/*	
 *	clipir.c
 *
 *	愒奜慄捠怣 (24/48MHz椉懳墳)
 *
 *	CLiP - Common Library for P/ECE
 *	Copyright (C) 2001-2005 Naoyuki Sawa
 *
 *	* Sat Mar 05 15:53:00 JST 2005 Naoyuki Sawa
 *	- 嶌惉奐巒丅
 *	* Tue Nov 27 12:03:36 JST 2007 Naoyuki Sawa
 *	- TxBit()撪偺丄儕乕僟偲僩儗乕儔偺敪岝僷僞乕儞偵娭偡傞僐儊儞僩傪掶惓偟傑偟偨丅
 *	  娫堘偭偰偄偨偺偼僐儊儞僩偩偗偱丄僾儘僌儔儉偼惓偟偐偭偨偺偱丄曄峏偁傝傑偣傫丅
 */
#include "clip.h"

/****************************************************************************
 *	
 ****************************************************************************/

/* - 斃憲攇廃攇悢傪寛傔傞16價僢僩僞僀儅5偺掕悢
 *
 *	僾儕僗働乕儔偐傜16bit僞僀儅5傊偺弌椡僋儘僢僋 = 24MHz
 *	愒奜慄捠怣偺斃憲攇廃攇悢 = 37.9KHz (庴岝晹偺巇條偱偡)
 *	24MHz / 38KHz = 633.245... -> 633
 */
#define IRCNT	(633)

#define IRBC1	(12)	/* 1(敪岝)->0(徚岝) 帪娫 = (1/37.9K)[sec]亊 IRBC1                */
#define IRBC2	(8)	/* 0(徚岝)->1(敪岝) 帪娫 = (1/37.9K)[sec]亊(IRBC1+IRBC2亊{0..3}) */

typedef struct _IR {
	int stat;		/* 0 = 掆巭拞, 1 = 捠怣拞 */
	//
	unsigned char* data;	/* 憲怣帪: 師偺憲怣僨乕僞撉傒弌偟埵抲 */
				/* 庴怣帪: 師偺庴怣僨乕僞彂偒崬傒埵抲 */
	int len;		/* 憲怣帪: 憲怣僨乕僞憤僶僀僩悢(屌掕) */
				/* 庴怣帪: 庴怣僨乕僞憤僶僀僩悢(屌掕) */
	int pos;		/* 憲怣帪: 憲怣嵪傒僶僀僩悢 */
				/* 庴怣帪: 庴怣嵪傒僶僀僩悢 */
	//
	int tcnt;		/* 憲怣帪: 0(徚岝)<->1(敪岝) 帪娫偺僇僂儞僩僟僂儞 */
				/* 庴怣帪: 慜夞偺16bit僞僀儅5僇僂儞僞僨乕僞傪曐懚 */
	int bcnt;		/* 憲怣帪: 僷儖僗僇僂儞僩傾僢僾 */
				/* 庴怣帪: 僷儖僗僇僂儞僩傾僢僾 */
	int dat;		/* 憲怣帪: 憲怣拞偺堦帪僨乕僞 */
				/* 庴怣帪: 庴怣拞偺堦帪僨乕僞 */
	//
	void (*callback)();	/* 捠怣姰椆帪偵屇傃弌偡僐乕儖僶僢僋 (NULL: 柍偟) */
} IR;
static IR _ir;
static int mode = 1;	/* P/ECE Kernel愒奜慄捠怣偲偺屳姺 (0 = 旕屳姺, 1 = 屳姺) */

/****************************************************************************
 *	
 ****************************************************************************/

static void _irt_isr() __attribute__((unused));
static int  TxBit();
static void _irr_isr() __attribute__((unused));
static void RxBit(unsigned n);

/* - P/ECE Kernel偺愒奜慄捠怣偼丄憲怣僨乕僞傪偦偺傑傑僄儞僐乕僪偣偢偵丄
 *   側偤偐丄CRC32僥乕僽儖偺抣偲偺Xor傪庢偭偰偐傜僄儞僐乕僪偟偰偄傑偡丅
 *   偙偆偡傞偙偲偵傛偭偰丄偳偺傛偆側岠壥偑偁傞偺偐棟夝偱偒偰偄傑偣傫丅丅丅
 * - 屳姺儌乕僪(mode=1)偱偼丄CRC32僥乕僽儖偺抣偲偺Xor傪庢偭偰偐傜僄儞僐乕僪偟傑偡丅
 *   CRC32僥乕僽儖偺抣偼丄CRC32僥乕僽儖傪帩偨偢偵丄枅夞寁嶼偱媮傔傞偙偲偵偟傑偟偨丅
 * - 旕屳姺儌乕僪(mode=0)偱偼丄憲怣僨乕僞傪偦偺傑傑僄儞僐乕僪偟傑偡丅
 */
static int
crctable_entry(unsigned c)
{
#define POLY	((1<<(31-26))|	\
		 (1<<(31-23))|	\
		 (1<<(31-22))|	\
		 (1<<(31-16))|	\
		 (1<<(31-12))|	\
		 (1<<(31-11))|	\
		 (1<<(31-10))|	\
		 (1<<(31- 8))|	\
		 (1<<(31- 7))|	\
		 (1<<(31- 5))|	\
		 (1<<(31- 4))|	\
		 (1<<(31- 2))|	\
		 (1<<(31- 1))|	\
		 (1<<(31- 0)))

	int i = 8;
	do {
		if(c & 1) {
			c = (c >> 1) ^ POLY;
		} else {
			c = (c >> 1);
		}
	} while(--i);
	return c;
}

/****************************************************************************
 *	
 ****************************************************************************/

void
ir_mode(int _mode_)
{
	/* 捠怣拞偵愝掕傪曄峏偟偰偼偄偗傑偣傫丅 */
	if(ir_stat()) {
		DIE();
	}

	/* 捠怣僼僅乕儅僢僩傪奿擺偟傑偡丅 */
	mode = _mode_;
}

void
ir_stop()
{
	IR* const ir = &_ir;

ENTER_CS;

	/* IR峔\憿懱僋儕傾丅(昁梫!!) */
	memset(ir, 0, sizeof(IR));

	/*** P27愝掕 (愒奜慄弌椡) ***/

	/* P27 I/O惂屼 = 弌椡 */
	bP2_IOC2_IOC27 = 1; /* 仛屌掕仛 */

	/* P27擖弌椡寭梡億乕僩僨乕僞 = 1 (徚岝) */
	bP2_P2D_P27D = 1; /* 仛屌掕仛 */

	/* P27婡擻\慖戰 = P27 (徚岝) */
	bP2_CFP2_CFP27 = 0;

	/*** P34愝掕 (愒奜慄擖椡僷儚乕) ***/

	/* P34婡擻\慖戰 = P34 */
	bP3_CFP3_CFP34 = 0; /* 仛屌掕仛 */

	/* P34 I/O惂屼 = 弌椡 */
	bP3_IOC3_IOC34 = 1; /* 仛屌掕仛 */

	/* P34擖弌椡寭梡億乕僩僨乕僞 = 0 (Off) */
	bP3_P3D_P34D = 0;

	/*** 16bit僞僀儅5僾儕僗働乕儔愝掕 ***/

	/* 16bit僞僀儅5僋儘僢僋惂屼 = Off */
	bCLKCTL_T16_5_P16TON5 = 0;

	/*** 16bit僞僀儅5愝掕 ***/

	/* 16bit僞僀儅5僋儘僢僋弌椡惂屼 = Off丄Stop */
	pT16_CTL5 = 0;

	/*** 16bit僞僀儅5妱傝崬傒愝掕 ***/

	/* 16bit僞僀儅5僐儞儁傾A妱傝崬傒 = 嬛巭 */
	bINT_E16T45_E16TC5 = 0;

	/*** 億乕僩擖椡2妱傝崬傒愝掕 ***/

	/* 億乕僩擖椡2妱傝崬傒 = 嬛巭 */
	bINT_EK01_EP03_EP2 = 0;

LEAVE_CS;
}

int
ir_stat()
{
	IR* const ir = &_ir;

	return ir->stat;
}

/****************************************************************************
 *	憲怣張棟
 ****************************************************************************/

void
ir_send(const void* data, int len, void (*callback)())
{
	IR* const ir = &_ir;

	/* 1僶僀僩枹枮偺捠怣偼晄壜偱偡丅
	 * (ir->len > 0 偱偁傞偙偲偵埶懚偟偨僐乕僨傿儞僌傪偟偰偄傑偡丅)
	 */
	if(len <= 0) {
		DIE();
	}

ENTER_CS;

	/* 傑偢丄妋幚偵掆巭偟傑偡丅 */
	ir_stop();

	///* IR峔\憿懱僋儕傾丅 */
	//memset(ir, 0, sizeof(IR));
	//仺ir_stop()偱僋儕傾嵪傒偱偡丅

	ir->stat = 1;
	ir->callback = callback;
	ir->data = (unsigned char*)data;
	ir->len = len;
	ir->pos = -1; /* 儕乕僟憲怣 */
	ir->tcnt = 1; /* 弶夞偼偡偖偵敪岝奐巒 */

	/*** P27愝掕 (愒奜慄弌椡) ***/

	//仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛
	//仛廳梫!!婋尟!!廳梫!!婋尟!!廳梫!!婋尟!!廳梫!!婋尟!!廳梫!!婋尟!!廳梫!!婋尟!!廳梫仛
	//仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛
	//仛 - P27弌椡 = 1 偲偡傞偲丄P27婡擻\慖戰 = P27 偲偟偨偲偒偵徚岝偟傑偡丅         仛
	//仛 - P27弌椡 = 0 偲偡傞偲丄P27婡擻\慖戰 = P27 偲偟偨偲偒偵揰摂偟偨傑傑偵側傝丄 仛
	//仛   揹棳偑棳傟偡偓偰婋尟偱偡偺偱丄愨懳偵 P27 = 0 偲偟偰偼偄偗傑偣傫丅        仛
	//仛 - 愒奜慄LED偼丄僞僀儅偵傛傞乽揰柵乿傑偨偼乽徚岝乿偺偄偢傟偐偺忬懺偲偟丄    仛
	//仛   揰摂偟偨傑傑偺忬懺偵偟偰偼偄偗傑偣傫丅                                   仛
	//仛 - 廬偭偰丄P27 I/O惂屼丄P27擖弌椡寭梡億乕僩僨乕僞嫟偵1屌掕偱巊梡偟傑偡丅    仛
	//仛   曄壔偝偣傞偺偼丄P27婡擻\慖戰 = P27/TM5 偺傒偱偡丅                         仛
	//仛 - P27婡擻\慖戰 = TM5 偺忬懺偱丄岆偭偨儗僕僗僞憖嶌偵傛傝僞僀儅偑掆巭偡傞偲丄 仛
	//仛   愒奜慄LED偑揰摂偟偨傑傑偵側傝丄P27 = 0 偲摨條偵婋尟偱偡丅                仛
	//仛 - 愒奜慄弌椡拞偼丄愨懳偵僞僀儅傪掆巭偟側偄傛偆丄廩暘偵拲堄偟偰偔偩偝偄丅   仛
	//仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛仛

	///* P27 I/O惂屼 = 弌椡 */
	//bP2_IOC2_IOC27 = 1; /* 仛屌掕仛 */
	//仺ir_stop()偵偰愝掕嵪傒偱偡丅

	///* P27擖弌椡寭梡億乕僩僨乕僞 = 1 (徚岝) */
	//bP2_P2D_P27D = 1; /* 仛屌掕仛 */
	//仺ir_stop()偵偰愝掕嵪傒偱偡丅

	/* P27婡擻\慖戰 = P27 (徚岝) */
	bP2_CFP2_CFP27 = 0;

	/*** 16bit僞僀儅5僾儕僗働乕儔愝掕 ***/

	/* 16bit僞僀儅5僋儘僢僋暘廃斾慖戰 = 兤/1 or 兤/2 */
	if(bP0_P0D_P07D) { /* P07 = 1 (24MHz) */
		bCLKCTL_T16_5_P16TS5 = 0; /* 兤/1 */
	} else {           /* P07 = 0 (48MHz) */
		bCLKCTL_T16_5_P16TS5 = 1; /* 兤/2 */
	}

	/* 16bit僞僀儅5僋儘僢僋惂屼 = On */
	bCLKCTL_T16_5_P16TON5 = 1;

	/*** 16bit僞僀儅5愝掕 ***/

	/* 16bit僞僀儅5僐儞儁傾僨乕僞A */
	pT16_CR5A = IRCNT / 2 - 1;

	/* 16bit僞僀儅5僐儞儁傾僨乕僞B */
	pT16_CR5B = IRCNT - 1;

	/* 16bit僞僀儅5僋儘僢僋弌椡惂屼 = On丄儕僙僢僩丄Run */
	pT16_CTL5 = 7;

	/*** 16bit僞僀儅5妱傝崬傒愝掕 ***/

	/* 16bit僞僀儅5妱傝崬傒儗儀儖 = 7 (嵟崅) */
	bINT_P16T45_P16T5 = 7;

	/* 16bit僞僀儅5僐儞儁傾A妱傝崬傒 = 嫋壜 */
	bINT_E16T45_E16TC5 = 1;

	/* 妱傝崬傒僒乕價僗儖乕僠儞傪僀儞僗僩乕儖偟傑偡丅 */
	{
		extern void irt_isr();
		pceVectorSetTrap(TRAP_16TC5, irt_isr);
	}

LEAVE_CS;
}

asm("
	.code
	.align	1
irt_isr:
	pushn	%r15
	ld.w	%r0, %alr
	ld.w	%r1, %ahr
	pushn	%r1
	call	_irt_isr
	popn	%r1
	ld.w	%ahr, %r1
	ld.w	%alr, %r0
	popn	%r15
	reti
");

static void
_irt_isr()
{
	IR* const ir = &_ir;

	/* 16bit僞僀儅5僐儞儁傾A妱傝崬傒梫場僼儔僌僋儕傾丅 */
	bINT_F16T45_F16TC5 = 0;

	/* 0(徚岝)->1(敪岝) 傑偨偼 1(敪岝)->0(徚岝) 帪娫偑僞僀儉傾僂僩偟偨傜... */
	if(!--ir->tcnt) {

		/* 敪岝拞側傜偽... */
		if(bP2_CFP2_CFP27) {

			/* P27婡擻\慖戰 = P27 (徚岝) */
			bP2_CFP2_CFP27 = 0;

			/* 0(徚岝)->1(敪岝) 帪娫傪庢摼丅 */
			ir->tcnt = TxBit();

		/* 徚岝拞側傜偽... */
		} else {

			/* P27婡擻\慖戰 = TM5 (敪岝) */
			bP2_CFP2_CFP27 = 1;

			/* 1(敪岝)->0(徚岝) 帪娫(屌掕)丅 */
			ir->tcnt = IRBC1;
		}
	}
}

static int
TxBit()
{
	IR* const ir = &_ir;
	//
	void (*callback)();
	int retv;

	/* 僷儖僗僇僂儞僩傾僢僾丅 */
	ir->bcnt++;

	/*** 儕乕僟憲怣 ***/

	/* 儕乕僟憲怣拞側傜偽... */
	if(ir->pos < 0) {

		///* 傑偩16僷儖僗惗惉偟偰偄側偗傟偽... */
		//伀 * Tue Nov 27 12:03:36 JST 2007 Naoyuki Sawa
		//伀 - 儕乕僟偼16僷儖僗偱偼側偔丄15僷儖僗偺娫堘偄偱偟偨丅
		//伀   ir->bcnt偑0偐傜奐巒偟偰丄僾儕僀儞僋儕儊儞僩丄16枹枮偲偄偆忦審偩偐傜偱偡丅
		//伀   娫堘偭偰偄偨偺偼僐儊儞僩偩偗偱丄僾儘僌儔儉偼偙偺傑傑偱惓偟偄偱偡丅
		//伀   P/ECE Kernel傕摨偠巇條偱偡丅
		//伀 - 僼儗乕儉愭摢晹暘偺丄儕乕僟敪岝僷僞乕儞偼丄埲壓偺偲偍傝偱偡丅
		//伀
		//伀	丂劕劒劒劒劖丂丂丂丂丂丂丂丂丂劕劒劒劒劖丂丂丂丂丂丂丂丂丂劕丂乧丂劖丂丂丂丂丂丂丂丂丂劕劒劒劒劖丂丂丂丂丂丂丂丂丂劕劒劒劒劖丂丂丂丂丂
		//伀	劒劗丂丂丂劘劒劒劒劒劒劒劒劒劒劗丂丂丂劘劒劒劒劒劒劒劒劒劒劗丂丂丂劘劒劒劒劒劒劒劒劒劒劗丂丂丂劘劒劒劒劒劒劒劒劒劒劗丂丂丂劘劒劒劒丂乧
		//伀	掆劆IRBC1 劆仼IRBC1+IRBC2*4 仺劆IRBC1 劆仼IRBC1+IRBC2*4 仺劆丂丂丂劆仼IRBC1+IRBC2*4 仺劆IRBC1 劆仼IRBC1+IRBC2*4 仺劆IRBC1 劆丂丂丂丂丂
		//伀	巭劆仼劅劅劅 1僷儖僗栚劅劅劅仺劆仼劅劅劅 2僷儖僗栚劅劅劅仺劆丂丂丂劅14僷儖僗栚劅劅劅仺劆仼劅劅劅15僷儖僗栚劅劅劅仺劆丂丂丂丂丂丂丂丂丂
		//伀	忬劆仼劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅儕乕僟劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅仺劆仼僨乕僞杮懱劅丂乧
		//伀	懺劆仼劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅僼儗乕儉劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅丂乧
		//伀
		/* 傑偩15僷儖僗惗惉偟偰偄側偗傟偽... */
		if(ir->bcnt < 16) {

			/* 儕乕僟憲怣拞偺 0(徚岝)->1(敪岝) 帪娫丅 */
			retv = IRBC1 + IRBC2 * 4;

			return retv;
		}

		///* 16僷儖僗惗惉偟偨傜丄僨乕僞憲怣傊堏峴丅 */
		//伀 * Tue Nov 27 12:03:36 JST 2007 Naoyuki Sawa
		//伀 - 儕乕僟偼16僷儖僗偱偼側偔丄15僷儖僗偺娫堘偄偱偟偨丅
		//伀   忋偺僐儊儞僩傪嶲徠偟偰偔偩偝偄丅
		/* 15僷儖僗惗惉偟偨傜丄僨乕僞憲怣傊堏峴丅 */
		ir->pos = 0;
		//ir->bcnt = 4;
		//仺婛偵 ir->bcnt=16 側偺偱晄梫偱偡丅

		/* FALLTHRU */
	}

	/*** 僨乕僞憲怣 ***/

	/* 4僷儖僗憲怣嵪傒(傑偨偼儕乕僟憲怣捈屻)側傜偽... */
	if(ir->bcnt >= 4) {

		/* 傑偩憲怣僨乕僞偑桳傟偽... */
		if(ir->pos < ir->len) {

			/* 憲怣僨乕僞撉傒弌偟丅 */
			ir->pos++; /* crctable_entry(0)偼巊傢側偄巇條 */
			if(mode) { /* 1: 屳姺儌乕僪 */
				ir->dat = *ir->data++ ^ (unsigned char)crctable_entry(ir->pos);
			} else {   /* 0: 旕屳姺儌乕僪 */
				ir->dat = *ir->data++;
			}
			ir->bcnt = 0;

		/* 傕偆憲怣僨乕僞偑柍偗傟偽... */
		} else {

			/* - 嵟屻偺僨乕僞偺屻偵丄8僷儖僗偺僩儗乕儔傪憲怣偟偰丄憲怣廔椆偟傑偡丅
			 *   憲怣僨乕僞僶僀僩悢偑丄庴怣梫媮僨乕僞僶僀僩悢傛傝傕抁偄応崌偵丄
			 *   RxBit偑僨乕僞廔抂傪専弌偟偰丄庴怣張棟傪拞抐偡傞偨傔偵棙梡偟傑偡丅
			 *   憲怣僨乕僞僶僀僩悢偲庴怣梫媮僨乕僞僶僀僩悢偑摍偟偄応崌丄傑偨偼丄
			 *   憲怣僨乕僞僶僀僩悢偺曽偑戝偒偄応崌偵偼丄僩儗乕儔偼柍堄枴偱偡丅
			 * - 旕屳姺儌乕僪偱偼丄憲庴怣僶僀僩悢偑昁偢堦抳偟偰偄傞傕偺偲壖掕偟偰丄
			 *   僩儗乕儔傪憲怣偣偢丄捈偪偵憲怣張棟傪廔椆偟傑偡丅
			 */
			if((!mode) ||             /* 0: 旕屳姺儌乕僪 or  */
			   (ir->bcnt >= 4 + 8)) { /* 僩儗乕儔憲怣姰椆    */
				callback = ir->callback; /* ir_stop()偱僋儕傾偝傟傞偐傜 */
				ir_stop();
				if(callback) {
					callback();
				}
				return 0;
			}

			///* 僩儗乕儔偺 0(徚岝)->1(敪岝) 帪娫丅
			// * - 杮摉偼丄P/ECE Kernel偺愒奜慄捠怣偺僩儗乕儔偼丄
			// *	(徚岝)-[抁]->(敪岝)-[挿]->(徚岝)->[挿]->(敪岝)-[挿]->徚岝
			// *   偲偄偆僷僞乕儞偱偡丅杮儌僕儏乕儖偺僩儗乕儔偼丄
			// *	(徚岝)-[抁]->(敪岝)-[挿]->(徚岝)->[抁]->(敪岝)-[挿]->徚岝
			// *   偲偄偆僷僞乕儞偱偁傝丄偙傟偼儕乕僟偲摨偠偱偡丅
			// *   尩枾偵偼P/ECE Kernel偲摨偠偱偼側偄偺偱偡偑丄栤戣偁傝傑偣傫丅
			// *   P/ECE Kernel偺庴怣張棟偼丄偁傞敪岝偐傜師偺敪岝傑偱偺帪娫偑挿偄偙偲偩偗傪尒偰
			// *   僩儗乕儔傪専弌偡傞偺偱丄抁丒挿丒挿丒挿偺僷僞乕儞偵偼摿偵堄枴偑柍偄偐傜偱偡丅
			// */
			//伀 * Tue Nov 27 12:03:36 JST 2007 Naoyuki Sawa
			//伀 - 忋偺僐儊儞僩偵彂偄偨丄僩儗乕儔敪岝僷僞乕儞偼岆傝偱偟偨丅
			//伀   惓偟偔偼丄埲壓偵掶惓偟偨僐儊儞僩偺偲偍傝偱偡丅
			//伀 - 僼儗乕儉枛旜偺丄僩儗乕儔敪岝僷僞乕儞偼丄埲壓偺偲偍傝偱偡丅
			//伀
			//伀	[P/ECE Kernel]
			//伀	丂丂丂丂丂丂丂丂丂劕劒劒劒劖丂丂丂丂丂丂丂丂丂劕劒劒劒劖丂丂丂劕劒劒劒劖丂丂丂丂丂丂丂丂丂劕劒劒劒劖丂丂丂劕劒劒劒劖丂丂丂丂丂丂丂丂丂劕劒劒劒劖丂丂丂劕劒劒劒劖丂丂丂丂丂丂丂丂丂劕劒劒劒劖丂丂丂劕劒劒劒劖丂
			//伀	乧丂劒劒劒劒劒劒劒劗丂丂丂劘劒劒劒劒劒劒劒劒劒劗丂丂丂劘劒劒劒劗丂丂丂劘劒劒劒劒劒劒劒劒劒劗丂丂丂劘劒劒劒劗丂丂丂劘劒劒劒劒劒劒劒劒劒劗丂丂丂劘劒劒劒劗丂丂丂劘劒劒劒劒劒劒劒劒劒劗丂丂丂劘劒劒劒劗丂丂丂劘劒
			//伀	丂丂丂丂丂丂丂丂丂劆IRBC1 劆仼IRBC1+IRBC2*4 仺劆IRBC1 劆IRBC1 劆IRBC1 劆仼IRBC1+IRBC2*4 仺劆IRBC1 劆IRBC1 劆IRBC1 劆仼IRBC1+IRBC2*4 仺劆IRBC1 劆IRBC1 劆IRBC1 劆仼IRBC1+IRBC2*4 仺劆IRBC1 劆IRBC1 劆IRBC1 劆掆
			//伀	丂丂丂丂丂丂丂丂丂劆仼劅劅劅 1僷儖僗栚劅劅劅仺劆仼 2僷儖僗栚仺劆仼劅劅劅 3僷儖僗栚劅劅劅仺劆仼 4僷儖僗栚仺劆仼劅劅劅 5僷儖僗栚劅劅劅仺劆仼 6僷儖僗栚仺劆仼劅劅劅 7僷儖僗栚劅劅劅仺劆仼 8僷儖僗栚仺劆丂丂丂劆巭
			//伀	乧丂劅僨乕僞杮懱仺劆仼劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅僩儗乕儔劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅仺劆忬
			//伀	乧丂劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅僼儗乕儉劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅仺劆懺
			//伀	
			//伀	[杮儌僕儏乕儖]
			//伀	丂丂丂丂丂丂丂丂丂劕劒劒劒劖丂丂丂丂丂丂丂丂丂劕劒劒劒劖丂丂丂丂丂丂丂丂丂劕丂乧丂劖丂丂丂丂丂丂丂丂丂劕劒劒劒劖丂丂丂丂丂丂丂丂丂劕劒劒劒劖丂
			//伀	乧丂劒劒劒劒劒劒劒劗丂丂丂劘劒劒劒劒劒劒劒劒劒劗丂丂丂劘劒劒劒劒劒劒劒劒劒劗丂丂丂劘劒劒劒劒劒劒劒劒劒劗丂丂丂劘劒劒劒劒劒劒劒劒劒劗丂丂丂劘劒
			//伀	丂丂丂丂丂丂丂丂丂劆IRBC1 劆仼IRBC1+IRBC2*4 仺劆IRBC1 劆仼IRBC1+IRBC2*4 仺劆丂丂丂劆仼IRBC1+IRBC2*4 仺劆IRBC1 劆仼IRBC1+IRBC2*4 仺劆IRBC1 劆掆
			//伀	丂丂丂丂丂丂丂丂丂劆仼劅劅劅 1僷儖僗栚劅劅劅仺劆仼劅劅劅 2僷儖僗栚劅劅劅仺劆丂丂丂劅 7僷儖僗栚劅劅劅仺劆仼劅劅劅 8僷儖僗栚劅劅劅仺劆丂丂丂劆巭
			//伀	乧丂劅僨乕僞杮懱仺劆仼劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅僩儗乕儔劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅仺劆忬
			//伀	乧丂劅劅劅劅劅劅劅劆仼劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅僼儗乕儉劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅劅仺劆懺
			//伀
			/* 僩儗乕儔偺 0(徚岝)->1(敪岝) 帪娫丅
			 * - 杮摉偼丄P/ECE Kernel偺愒奜慄捠怣偺僩儗乕儔偼丄
			 *	(敪岝)-[抁]->(徚岝)-[挿]->(敪岝)->[抁]->(徚岝)-[抁]->(敪岝)
			 *   偲偄偆僷僞乕儞偱偡丅杮儌僕儏乕儖偺僩儗乕儔偼丄
			 *	(敪岝)-[抁]->(徚岝)-[挿]->(敪岝)->[抁]->(徚岝)-[挿]->(敪岝)
			 *   偲偄偆僷僞乕儞偱偁傝丄偙傟偼儕乕僟偲摨偠偱偡丅
			 *   尩枾偵偼P/ECE Kernel偲摨偠偱偼側偄偺偱偡偑丄栤戣偁傝傑偣傫丅
			 *   P/ECE Kernel偺庴怣張棟偼丄乽(敪岝)-[抁]->(徚岝)-[挿]->(敪岝)乿傪敪尒偟偨帪揰偱丄僩儗乕儔偲敾抐偟偰丄庴怣張棟傪懪偪愗傝傑偡丅
			 *   椉幰偲傕愭摢晹暘偺乽(敪岝)-[抁]->(徚岝)-[挿]->(敪岝)乿偼嫟捠側偺偱丄偦傟埲崀偺敪岝僷僞乕儞偑堘偭偰偄偰傕塭嬁偑柍偄偐傜偱偡丅
			 * - 側偤丄P/ECE Kernel偺僩儗乕儔偼丄堄枴偺柍偄乽(敪岝)->[抁]->(徚岝)-[抁]->(敪岝)乿偲偄偆敪岝僷僞乕儞傪娷傫偱偄傞偺偐晄柧偱偡丅
			 */
			retv = IRBC1 + IRBC2 * 4;

			return retv;
		}
	}

	/* 僨乕僞憲怣拞偺 0(徚岝)->1(敪岝) 帪娫丅 */
	retv = IRBC1 + IRBC2 * (ir->dat & 3);
	ir->dat >>= 2;

	return retv;
}

/****************************************************************************
 *	庴怣張棟
 ****************************************************************************/

void
ir_recv(void* data, int len, void (*callback)())
{
	IR* const ir = &_ir;

	/* 1僶僀僩枹枮偺捠怣偼晄壜偱偡丅
	 * (ir->len > 0 偱偁傞偙偲偵埶懚偟偨僐乕僨傿儞僌傪偟偰偄傑偡丅)
	 */
	if(len <= 0) {
		DIE();
	}

ENTER_CS;

	/* 傑偢丄妋幚偵掆巭偟傑偡丅 */
	ir_stop();

	///* IR峔\憿懱僋儕傾丅 */
	//memset(ir, 0, sizeof(IR));
	//仺ir_stop()偱僋儕傾嵪傒偱偡丅

	ir->stat = 1;
	ir->callback = callback;
	ir->data = (unsigned char*)data;
	ir->len = len;
	ir->pos = -1; /* 儕乕僟庴怣 */
	ir->tcnt = 0; /* 16bit僞僀儅5僇僂儞僩僨乕僞弶婜抣 */

	/*** P34愝掕 (愒奜慄擖椡僷儚乕) ***/

	///* P34婡擻\慖戰 = P34 */
	//bP3_CFP3_CFP34 = 0; /* 仛屌掕仛 */
	//仺ir_stop()偵偰愝掕嵪傒偱偡丅

	///* P34 I/O惂屼 = 弌椡 */
	//bP3_IOC3_IOC34 = 1; /* 仛屌掕仛 */
	//仺ir_stop()偵偰愝掕嵪傒偱偡丅

	/* P34擖弌椡寭梡億乕僩僨乕僞 = 1 (On) */
	bP3_P3D_P34D = 1;

	/*** 16bit僞僀儅5僾儕僗働乕儔愝掕 ***/

	/* - 16bit僞僀儅偺僾儕僗働乕儔愝掕偵偼兤/32偑柍偄偨傔偵丄
	 *   僾儕僗働乕儔愝掕偵傛偭偰24MHz/48MHz偺嵎傪媧廂偱偒傑偣傫丅
	 * - 巇曽偑柍偄偺偱丄僇僂儞僩僨乕僞傪撉傒弌偟偨屻偵丄
	 *   48MHz偺応崌偼憹暘傪1/2偟偰丄24MHz偵崌傢偣傞偙偲偵偟傑偡丅
	 */

	/* 16bit僞僀儅5僋儘僢僋暘廃斾慖戰 = 兤/16 */
	bCLKCTL_T16_5_P16TS5 = 3;

	/* 16bit僞僀儅5僋儘僢僋惂屼 = On */
	bCLKCTL_T16_5_P16TON5 = 1;

	/*** 16bit僞僀儅5愝掕 ***/

	/* 16bit僞僀儅5僐儞儁傾僨乕僞A */
	pT16_CR5A = -1;

	/* 16bit僞僀儅5僐儞儁傾僨乕僞B */
	pT16_CR5B = -1;

	/* 16bit僞僀儅5僋儘僢僋弌椡惂屼 = Off丄儕僙僢僩丄Run */
	pT16_CTL5 = 3;

	/*** 億乕僩擖椡2愝掕 ***/

	/* K52婡擻\慖戰 = K52 */
	bK5_CFK5_CFK52 = 0;

	/* FPT2妱傝崬傒擖椡億乕僩慖戰 = K52 */
	bPINTSEL_SPT03_SPT2 = 1;

	/* FPT2擖椡嬌惈慖戰 = High儗儀儖丄傑偨偼丄棫偪忋偑傝僄僢僕 */
	bPINTPOL_SPPT_SPP2 = 1;

	/* FPT2僄僢僕/儗儀儖慖戰 = 僄僢僕 */
	bPINTEL_SEPT_SEPT2 = 1;

	/*** 億乕僩擖椡2妱傝崬傒愝掕 ***/

	/* 億乕僩擖椡2妱傝崬傒儗儀儖 = 7 (嵟崅) */
	bINT_PP23L_PP2L = 7;

	/* 億乕僩擖椡2妱傝崬傒 = 嫋壜 */
	bINT_EK01_EP03_EP2 = 1;

	/* 妱傝崬傒僒乕價僗儖乕僠儞傪僀儞僗僩乕儖偟傑偡丅 */
	{
		extern void irr_isr();
		pceVectorSetTrap(TRAP_P2, irr_isr);
	}

LEAVE_CS;
}

asm("
	.code
	.align	1
irr_isr:
	pushn	%r15
	ld.w	%r0, %alr
	ld.w	%r1, %ahr
	pushn	%r1
	call	_irr_isr
	popn	%r1
	ld.w	%ahr, %r1
	ld.w	%alr, %r0
	popn	%r15
	reti
");

static void
_irr_isr()
{
	IR* const ir = &_ir;
	//
	int a;
	int n;

	/* 億乕僩擖椡2妱傝崬傒梫場僼儔僌僋儕傾丅 */
	bINT_FK01_FP03_FP2 = 0;

	/* 慜夞偺敪岝専弌偐傜偺宱夁帪娫傪媮傔傑偡丅 */
	a = pT16_TC5;
	n = (unsigned short)(a - ir->tcnt);
	if(!bP0_P0D_P07D) { /* P07 = 0 (48MHz) */
		n >>= 1;
	}
	ir->tcnt = a;

	/* 敪岝娫妘偐傜丄庴怣僨乕僞傪僨僐乕僪偟傑偡丅 */
	RxBit(n);
}

static void
RxBit(unsigned n)
{
	IR* const ir = &_ir;
	//
	void (*callback)();

	/* 敪岝娫妘傪丄2bit庴怣僨乕僞偵曄姺偟傑偡丅 */
	n -= (IRCNT * (IRBC1 * 2 - IRBC2 / 2)) / 16;
	n /= (IRCNT *              IRBC2     ) / 16;

	/* 2bit庴怣僨乕僞傪丄堦帪僨乕僞偵儅乕僕偟傑偡丅
	 * 儕乕僟僷儖僗偺応崌偼丄僟儈乕張棟偲側傝傑偡丅
	 */
	ir->dat >>= 2;
	ir->dat |= (n & 3) << 6;

	/* 僷儖僗僇僂儞僩傾僢僾丅 */
	ir->bcnt++;

	/*** 儕乕僟庴怣 ***/

	/* 儕乕僟庴怣拞側傜偽... */
	if(ir->pos < 0) {

		/* 儕乕僟偺僷儖僗娫妘偱側偗傟偽... */
		if(n != 4) {

			/* 僨乕僞僷儖僗偲偟偰桳岠側娫妘偱丄偐偮丄
			 * 儕乕僟偺僷儖僗傪彮側偔偲傕8僷儖僗埲忋庴怣偟偰偄偨傜...
			 * (憲怣懁偼儕乕僟傪16僷儖僗憲怣偡傞偺偱丄偦偺敿暘埲忋)
			 */
			if((n < 4) && (ir->bcnt >= 8)) {
				/* 僨乕僞庴怣傊堏峴偟傑偡丅 */
				ir->pos = 0;
				/* 婛偵偄傑丄桳岠側僨乕僞偺1僷儖僗(=2bit)傪庴怣嵪傒偱偡丅 */
				ir->bcnt = 1;
			} else {
				/* 晄惓側僷儖僗傪庴怣偟偨偺偱丄儕乕僟傪嵟弶偐傜懸偪傑偡丅 */
				ir->bcnt = 0;
			}
		}

		return;
	}

	/*** 僨乕僞庴怣 ***/

	/* 晄惓側僷儖僗丄傑偨偼丄僩儗乕儔傪庴怣偟偨傜丄庴怣張棟傪拞抐偟傑偡丅 */
	if(n >= 4) {
		callback = ir->callback; /* ir_stop()偱僋儕傾偝傟傞偐傜 */
		ir_stop();
		if(callback) {
			callback();
		}
		return;
	}

	/* 4僷儖僗庴怣嵪傒側傜偽... */
	if(ir->bcnt >= 4) {

		/* 庴怣僨乕僞傪奿擺偟傑偡丅 */
		ir->pos++; /* crctable_entry(0)偼巊傢側偄巇條 */
		if(mode) { /* 1: 屳姺儌乕僪 */
			*ir->data++ = ir->dat ^ (unsigned char)crctable_entry(ir->pos);
		} else {   /* 0: 旕屳姺儌乕僪 */
			*ir->data++ = ir->dat;
		}
		ir->bcnt = 0;

		/* 庴怣僶僢僼傽偑偄偭傁偄偵側偭偨傜丄庴怣張棟傪廔椆偟傑偡丅 */
		if(ir->pos >= ir->len) {
			callback = ir->callback; /* ir_stop()偱僋儕傾偝傟傞偐傜 */
			ir_stop();
			if(callback) {
				callback();
			}
			return;
		}
	}
}

