#include "app.h"

/****************************************************************************
 *	赤外線通信サポート
 ****************************************************************************/

#define CPUCLK		24000000		/* CPUクロック */
#define IRFREQ		   37900		/* 赤外線キャリア周波数 */
#define IRCNT		(CPUCLK / IRFREQ)	/* 16bitタイマ5設定値(赤外線キャリア生成用) */
#define USEC(u)		((u) * 24 >> 4)		/* マイクロ秒→16bitタイマ3カウント(θ/16で駆動) */

void
ir_init()
{
	/* 赤外線受光モジュールの電源をONにします。
	 * * P34(Vcc)とGNDの間にあるコンデンサの影響で、P34を1にしてもP34ラインがすぐにHiレベルに上がりません。
	 *   幸い、入出力ポートのI/Oを読み込むと、入出力方向の設定に関らず現在のポート電圧レベルが取得できます。
	 *   P34を1に設定した後、P34の電圧レベルが本当にHiレベルになるまで、空ループで待つことにします。
	 * * しかしこれだけでは不十分です。
	 *   デジタル的にはHiでも、赤外線受光モジュールへの電源供給レベルとしてはまだ低い可能性があります。
	 *   赤外線受光モジュールの出力(K52)はアクティブLowなので、通常は1が出力されています。
	 *   また、実験によると、電源が供給されていないときは0が出力されているようです。
	 *   （赤外線受光モジュールをOFFにしていると、K52ラインに電流が流れてるってこと...？）
	 *   そこで、赤外線受光モジュールの電源をONにした後、出力が1になるまで、空ループで待つことにします。
	 * ↓変更
	 * * 『USB電源での駆動時に、赤外線受光部の近くに物（指など）がある』と、赤外線を受信していなくても、
	 *   赤外線受光モジュールからの出力が頻繁に0(=赤外線受信あり)になってしまうようです。(^^;謎だ〜！)
	 *   こんな状況で安定待ちをしてもあまり意味がないので、赤外線受光モジュールの安定待ちはやめました。
	 *   不安定な受信データは、受信処理のところで弾くことにします。
	 *   （なお、電池での駆動時は、上記のような症状は起こりません。USB電源からのノイズなのでしょうか？）
	 */
	bP3_P3D_P34D = 1;
	while(!bP3_P3D_P34D) { /* 電源安定待ち */ }
	/* 赤外線受光モジュールの安定待ちは行いません */

	/* 16bitタイマ5をキャリア生成用に設定します。
	 * * bP2_CFP2_CFP27=1(P27=クロック出力)かつbT16_CTL5_PTM5=0(クロック出力なし)に設定すると、
	 *   P27の出力レベルはbT16_CTL5_OUTINV5の設定に従ったインアクティブレベルとなります。
	 *   今回はbT16_CTL5_OUTINV5=1(出力反転)としたので、上記の設定ではHiが出力されます。
	 * * こうしておけば、bT16_CTL5_PTM5を0⇔1に切り替えるだけで、LED消灯⇔点滅(37.9KHz)を切り替えられます。
	 *   bT16_CTL5_OUTINV5=1(出力反転)とした理由は、bT16_CTL5_PTM5=0時にP27=Hi(LED消灯)とするためなのです。
	 */
	pT16_CTL5 = 0x10;		/* タイマ停止(OUTINV) */
	bCLKCTL_T16_5_P16TON5 = 0;	/* プリスケーラ停止 */
	bCLKCTL_T16_5_P16TS5 = 0;	/* 1/θ */
	bCLKCTL_T16_5_P16TON5 = 1;	/* プリスケーラ起動 */
	pT16_CR5A = IRCNT / 2 - 1;	/* クロック立ち下がりタイミング設定(注:OUTINV) */
	pT16_CR5B = IRCNT     - 1;	/* クロック立ち上がりタイミング設定(注:OUTINV) */
	pT16_CTL5 = 0x13;		/* タイマ起動(OUTINV|PRESET|PRUN) ※まだPTMはセットしません */
	bP2_CFP2_CFP27 = 1;		/* P27=16bitタイマ5クロック出力 */

	/* 16bitタイマ3をビットクロック生成用に設定します。 */
	pT16_CTL3 = 0x00;		/* タイマ停止 */
	bCLKCTL_T16_3_P16TON3 = 0;	/* プリスケーラ停止 */
	bCLKCTL_T16_3_P16TS3 = 3;	/* 1/16(=1.5MHz) */
	bCLKCTL_T16_3_P16TON3 = 1;	/* プリスケーラ起動 */
	pT16_CR3A = 0xffff;		/* (関係ありません) */
	pT16_CR3B = 0xffff;		/* 0〜0xffffでループ */
	pT16_CTL3 = 0x03;		/* タイマ起動(PRESET|PRUN) */
}

void
ir_free()
{
	/* 赤外線受光モジュールの電源をOFFにします。 */
	bP3_P3D_P34D = 0;

	/* 16bitタイマ5を停止します。 */
	pT16_CTL5 = 0x00;		/* タイマ停止 */
	bCLKCTL_T16_5_P16TON5 = 0;	/* プリスケーラ停止 */
	bP2_CFP2_CFP27 = 0;		/* P27=出力ポート */
	bP2_P2D_P27D = 1;		/* LED消灯 */

	/* 16bitタイマ3を停止します。 */
	pT16_CTL3 = 0x00;		/* タイマ停止 */
	bCLKCTL_T16_3_P16TON3 = 0;	/* プリスケーラ停止 */
}

/****************************************************************************
 *	テストプログラム
 ****************************************************************************/

unsigned char vbuff[DISP_X * DISP_Y];

int ON = 500;
int OFF = 1500;

void send();
void recv();

int
main()
{
	int joy;

	pceLCDDispStop();
	pceLCDSetBuffer(vbuff);
	pceAppSetProcPeriod(10);
	pceLCDDispStart();

	ir_init();

	for(;;) {
		yield();

		joy = pcePadGet();
		if(joy & TRG_SELECT) break;

		if(joy & TRG_A) send();
		if(joy & TRG_B) recv();

		if((joy & TRG_LF) && 100 < ON) ON -= 50;
		if((joy & TRG_RI) && ON < 100000) ON += 50;
		if((joy & TRG_DN) && 100 < OFF) OFF -= 50;
		if((joy & TRG_UP) && OFF < 100000) OFF += 50;

		memset(vbuff, 0, sizeof vbuff);
		pceFontSetPos(0, 0);
		pceFontPrintf("ON =%4d\nOFF=%4d", ON, OFF);
		pceLCDTrans();
	}

	ir_free();

	return 0;
}


void
send()
{
	int n, T0, T1;
	int u_on = USEC(ON);
	int u_off = USEC(OFF);

	memset(vbuff, 0, sizeof vbuff);
	pceFontSetPos(0, 0);
	pceFontPrintf("send");
	pceLCDTrans();

DI;
	n = 0;
	T1 = pT16_TC3;
	while(!(pcePadGetDirect() & PAD_SELECT)) {
		bT16_CTL5_PTM5 = 1;
		T0 = T1; do { T1 = pT16_TC3; } while(((T1 - T0) & 0xffff) < u_on);
		bT16_CTL5_PTM5 = 0;
		T0 = T1; do { T1 = pT16_TC3; } while(((T1 - T0) & 0xffff) < u_off);
		n++;
	}
EI;

	memset(vbuff, 0, sizeof vbuff);
	pceFontSetPos(0, 0);
	pceFontPrintf("%d", n);
	pceLCDTrans();

	yield();
	for(;;) {
		yield();
		if(pcePadGet() & TRG_SELECT) break;
	}
}

void
recv()
{
	int na, nb, T0, T1, dT, prev, cur;
	unsigned a, b;

	memset(vbuff, 0, sizeof vbuff);
	pceFontSetPos(0, 0);
	pceFontPrintf("recv");
	pceLCDTrans();

DI;
	na = 0, nb = 0;
	a = 0, b = 0;
	do {
		T0 = pT16_TC3;
		prev = bK5_K5D_K52D;
	} while(prev && !(pcePadGetDirect() & PAD_SELECT));
	while(!(pcePadGetDirect() & PAD_SELECT)) {
		cur = bK5_K5D_K52D;
		if(prev == cur) continue;
		T1 = pT16_TC3;
		dT = (T1 - T0) & 0xffff;
		T0 = T1;
		if(cur) { /* 点灯→消灯 */
			a += dT;
			na++;
		} else {  /* 消灯→点灯 */
			b += dT;
			nb++;
		}
		prev = cur;
	}
EI;

	memset(vbuff, 0, sizeof vbuff);
	pceFontSetPos(0, 0);
	pceFontPrintf("%d:%d\n%d/%d", na, nb, a * 16 / 24 / na, b * 16 / 24 / nb);
	pceLCDTrans();

	yield();
	for(;;) {
		yield();
		if(pcePadGet() & TRG_SELECT) break;
	}
}


