//蛍光灯リモコン
//受信側プログラム
//製作者：KK
//2011/08/25
/*
※2011/09/23変更
・WDT追加
・ボリューム＋・−ボタン機能追加
*/

/*
市販テレビリモコンの制御
使用したコードはシャープ製テレビのもの
信号コード：040
*/

#include<12f675.h>
#fuses INTRC_IO,WDT,NOBROWNOUT,NOPROTECT,NOPUT,NOCPD
#use delay(clock=4000000)		//4MHz//

/*=====ポート定義=====*/
#byte RA=5

#bit	 EDGE_SIG=RA.0		//受信信号の出力
#bit ON_OFF_SIG=RA.1	//リレーON/OFF
#bit BZ=RA.4			//ブザー

/*=====定義文=====*/
#define	ALL_SIGNAL		8750	//１信号の時間(70ms)

//リーダ・信号時間
#define	READER			450		//リーダ時間(3.6ms)
#define	SIGNAL			150		//信号時間(1.2ms)

//マージンタイム作成用
#define	TIMER1_005MS	31		//TIMER1の0.05ms分カウント
#define	TIMER1_01MS	63		//TIMER1の0.1ms分カウント
#define	TIMER1_1MS	625		//TIMER1の1ms分カウント

//メーカーコード
#define	SHARP			0x1480000	//シャープ

//リモコンボタン
//放送切替ボタンはアナログテレビ用信号のため使用不可
#define	POWER			0x688b		//電源
#define	IN_CHANGE		0xc881		//入力切替
#define	DISPLAY			0xd880		//画面表示
#define	ONE				0x808d		//１
#define	TWO			0x4081		//２
#define	THREE			0xc089		//３
#define	FOUR			0x2087		//４
#define	FIVE			0xa08f		//５
#define	SIX				0x6083		//６
#define	SEVEN			0xe08b		//７
#define	EIGHT			0x1084		//８
#define	NINE			0x908c		//９
#define	TEN				0x5080		//１０
#define	ELEVEN			0xd088		//１１
#define	TWELVE			0x3086		//１２
#define	CH_PLUS		0x8885		//チャンネル＋
#define	CH_MINUS		0x4889		//チャンネル−
#define	VO_PLUS		0x288f		//ボリューム＋
#define	VO_MINUS		0xa887		//ボリューム−
#define	MUTE			0xe883		//ミュート

/*=====変数宣言=====*/
signed int mode=0,time=0,bz_sig=0;
unsigned long long read_data=0;
unsigned char edge_data=0;

/*=====メイン関数=====*/
void main(void){
	//ポート入出力設定
	set_tris_a(0b0100100);
	
	//8750	70ms
	//437	3.5ms
	//450	3.6ms
	//463	3.7ms
	//125	1ms
	//13	0.1ms
	//6		0.05ms
	
	/*
	H・Lレベルの時間
	1   1.2ms	150
	2   0.32ms	40
	*/
	
	//TIMER1設定
	setup_timer_1(T1_INTERNAL | T1_DIV_BY_8);
	set_timer1(0);
	
	//外部割り込み設定
	ext_int_edge(H_TO_L);	//立ち下がりエッジ検出
	
	//WDT設定
	setup_wdt(WDT_1152MS);	//WDT設定時間1.15s
	
	//割り込み許可
	enable_interrupts(INT_EXT);
	enable_interrupts(INT_TIMER1);
	enable_interrupts(GLOBAL);
	
	//初期化
	RA=0x00;
	
	//前回終了時照光ON/OFF状態呼び出し
	ON_OFF_SIG=READ_EEPROM(0);
	bz_sig=READ_EEPROM(1);
	
	//外部割り込み検出エッジ情報の保存
	edge_data = H_TO_L;
	
	while(TRUE){
		switch(mode){
			case 1:		//リーダー検出 約3.6ms
				if(!EDGE_SIG && (get_timer1() >= (READER-TIMER1_01MS) && get_timer1() <= (READER+TIMER1_01MS))){
					mode=2;			
				}
				if(get_timer1()>=ALL_SIGNAL){	//1信号分の時間が経過したら最初へ
					mode=0;
				}
				break;
			
			case 2:		//信号検出（49bit） Hレベル:1.2ms   Lレベル:0.32ms
			
				read_data=0;	//データの初期化
				
				//信号がLレベルの間待機
				while(!EDGE_SIG);
				
				//49bit分の信号抽出
				for(time=0;time<49;time++){
					set_timer1(0);	//タイマ１クリア
					
					while(EDGE_SIG && get_timer1() <= ALL_SIGNAL);		//信号Hレベルの時間測定
					
					read_data<<=1;		//データ左シフト
					
					//Hレベルが1.2msの信号だった場合、1を格納
					if(get_timer1() >= (SIGNAL-TIMER1_01MS) && get_timer1() <= (SIGNAL+TIMER1_01MS)){
						read_data |= 0x01;
					}
					
					while(!EDGE_SIG && get_timer1() <= ALL_SIGNAL);		//次の信号が来るまで待機。（Hレベルになるまで）
					
					if(get_timer1() > ALL_SIGNAL){	//１信号分（余裕持って70ms）経過してたらエラーとして抽出終了
						break;
					}	
				}
				read_data &= 0xFFFFFFF;
				
				//リレーON/OFFの変更
				if((read_data & 0xFFFF) == POWER){			//電源SW・・・蛍光灯ON/OFF切替
					ON_OFF_SIG=~ON_OFF_SIG;
					WRITE_EEPROM(0,ON_OFF_SIG);
				}
				else if((read_data & 0xFFFF) == VO_PLUS){	//音量調整＋・・・ブザー音ON
					bz_sig=1;
					WRITE_EEPROM(1,bz_sig);
				}
				else if((read_data & 0xFFFF) == VO_MINUS){	//音量調整−・・・ブザー音OFF
					bz_sig=0;
					WRITE_EEPROM(1,bz_sig);
				}
				else if((read_data & 0xFFFF) == MUTE){		//ミュート・・・ブザーON/OFF切替
					bz_sig=~bz_sig;
					WRITE_EEPROM(1,bz_sig);
				}	
				
				mode=0;
				break;
						
			default:		//待機状態
				set_timer1(0);	//TMR1=0
				break;
		}		
		restart_wdt();	//WDT再始動　1.15s以内に左記の関数を呼び出さないとリセットがかかる		
	}
}

/*=====割り込み処理=====*/
#INT_EXT
void ext(void){
	//立ち上がり・立ち下がりエッジの変更
	//立ち上がり・立ち下がり両方のエッジで割り込みを行う
	if(edge_data == H_TO_L){	//立ち下がり→立ち上がり
		ext_int_edge(L_TO_H);
		edge_data = L_TO_H;
		EDGE_SIG=0;
	}
	else{						//立ち上がり→立ち下がり
		ext_int_edge(H_TO_L);
		edge_data = H_TO_L;
		EDGE_SIG=1;
	}
	if(bz_sig){
		BZ=~BZ;
	}	
	
	if(!mode){
		mode=1;
	}	
}
