;------------------------------------------------------------------------------
; timer_remocon.asm	タイマーリモコン
;------------------------------------------------------------------------------
; バージョン履歴
; 2014-02-03 Ver.0.15 Ver.0.12で削除したアラーム個別ONフラグを復活させた。DP-1Hに状態表示させている。
;		      メモリ初期化ルーチンで全アラームONフラグも初期化するようにした。
;		      赤外線送信ルーチンで3回同じデータを送信するようにした。
; 2014-01-18 Ver.0.14 基板レイアウトに合わせてLEDの配線と表示ルーチンを変更。
; 2014-01-16 Ver.0.13 キーリピートを付けた
; 2014-01-14 Ver.0.12 個々のアラームの有効化フラグを廃止し、赤外線データの有無で有効化した。DP点灯パターンの見直し。赤外線バッファのサイズを152バイトに拡張
; 2014-01-13 Ver.0.11 完成、LEDの照射角がシビアだが今晩テストで使ってみる。
; 2014-01-12 Ver.0.10 赤外線送信ルーチンが完成、照明をコントロールできるようになった。
; 2014-01-12 Ver.0.09 赤外線受信ルーチンを作成、エアコンのデータは164bitあって記録できないことが判明
; 2014-01-03 Ver.0.08 赤外線送受信、アラーム鳴動以外のルーチンが完成。
; 2014-01-02 Ver.0.07 EEPROM,I2CROM初期化ルーチン作成。
;		      i2csspif内で行っていたSSPIFのクリアをSEN,RSEN,PEN,ACKEN,送信前に持ってきた。(SSPIFのクリア前に割り込みが起きると無限ループしてしまう、丸1日ハマった)
; 2014-01-01 Ver.0.06 アラームの番号選択を実装。
; 2014-12-31 Ver.0.05 時計セットモード実装。キー入力はワンショットのみ受け付けるようにした。
; 2014-12-29 Ver.0.04 メインループの流れと表示ルーチンを刷新。変数割り当てを見直した。
;		      とりあえず時計がまともに動くように戻した。
; 2014-12-27 Ver.0.03 内蔵EEPROMアクセスルーチンを作成
; 2014-12-26 Ver.0.02 時間表示ルーチン作成、時計として機能するようになった
; 2014-12-25 Ver.0.01 LED表示ルーチンを作成
; 2014-12-23 Ver.0.00 TIMER1,CCP1を使って時計のコアを作成。
;
;------------------------------------------------------------------------------
; IRP,RP1,RP0を切り替える所で◆ RP=をコメントに置く
; PCLATHを切り替えるところで■ PCLATHをコメントに置く
;------------------------------------------------------------------------------
;------------------------------------------------------------------------------
; デバイス	PIC16F873A
; 動作周波数	4MHz
;------------------------------------------------------------------------------
	LIST		P=PIC16F873A,R=DEC,N=0
	INCLUDE		"P16F873A.INC"
	ERRORLEVEL	0,-302,-306,-307
	__CONFIG	0x3F71
;------------------------------------------------------------------------------
; 変数宣言
;------------------------------------------------------------------------------
W_		EQU	0x20		; 割り込みの退避用
W__		EQU	0xA0		; 16F873はBank0とBank1が共通でないため、両方のページを予約する必要がある。
STATUS_		EQU	0x21
PCLATH_		EQU	0x22
FSR_		EQU	0x23

HOUR		EQU	0x24		; 時計カウンタ
MINUTE		EQU	0x25
SECOND		EQU	0x26
MODE		EQU	0x27

ALARM_NUMBER	EQU	0x28		; アラーム呼び出し、保存用
ALARM_HOUR	EQU	0x29
ALARM_MINUTE	EQU	0x2A
ALARM_SIZE	EQU	0x2B

DISP_HOUR	EQU	0x2C		; 数値型から文字型に変換する時用
DISP_MINUTE	EQU	0x2D

CHAR_10H	EQU	0x2E		; ASCII文字列を入れてパターンを呼び出す
CHAR_1H		EQU	0x2F		; 0x80以上を入れるとDPを点灯させる
CHAR_10M	EQU	0x30
CHAR_1M		EQU	0x31
LED_PORTC	EQU	0x32

I2CADRH		EQU	0x33
I2CADRL		EQU	0x34
I2CDATA		EQU	0x35
DATAPTR		EQU	0x36
DATASIZE	EQU	0x37

EEADRH_		EQU	0x38		; プログラムEEPROMのテーブルリード用
EEADR_		EQU	0x39
EEDATA_		EQU	0x3A

STRING		EQU	0x3B		; 文字列呼び出し用表番号
KEY		EQU	0x3C		; 入力キービットマップ
REPEAT_COUNT	EQU	0x3D

DIV1		EQU	0x3E		; DIV1 = DIV1 / DIV2
DIV2		EQU	0x3F		; 非破壊
MODULO		EQU	0x40		; MODULO = DIV1 % DIV2
MUL1		EQU	DIV1		; DIV2,1 = DIV1 * DIV3
MUL2		EQU	DIV2
MUL3		EQU	MODULO

FLAG		EQU	0x41

TMP00		EQU	0x42
TMP01		EQU	0x43
TMP02		EQU	STRING
TMP05		EQU	0x44
TMP06		EQU	0x45
TMP07		EQU	0x46

					; 赤外線データ展開領域
; 16F873と16F876ではデータレジスタのマッピングが異なるので注意すること。
IRDATA1		EQU	0x47		; 47-7F(57)+A1-FF(95)=152バイト
IRDATA2		EQU	0xA1		; 最大12.75ms*2のリーダー(6)+最大6.375ms*2のデータ*48bit(96)+最大121.125msのパディング(37)
MAX_SIZE	EQU	0x100+0x80-IRDATA1-IRDATA2

;------------------------------------------------------------------------------
; 定数・フラグ宣言
;------------------------------------------------------------------------------
ALARM_ALLON	EQU	0		; FLAG-0 全アラームの一括ONフラグ
MINUTE_INCR	EQU	1		; FLAG-1 割り込み処理で分がインクリメントされたことを示す。リセットはメインルーチンで行う。
DPSET		EQU	2		; FLAG-2 DPを点灯する文字の一時記憶用
RELEASE		EQU	3		; FLAG-3 キーをリリースするまで0を返すようにする
DIRTY		EQU	4		; FLAG-4 設定が変更されているので保存しないといけない
PAGE_OVER	EQU	5		; FLAG-5 IRDATA1からIRDATA2に切り替わったことを示すフラグ
;空
ALARM_ON	EQU	7		; FLAG-7 アラームの個別ONフラグ

KEY_0		EQU	0		; 押されているキーのフラグ
KEY_1		EQU	1
KEY_2		EQU	2
KEY_3		EQU	3
IR_IN		EQU	4
IR_OUT		EQU	5

CL		EQU	0		; モード表記
MN_AL		EQU	1
MN_AS		EQU	2
MN_IR		EQU	3	
MN_CS		EQU	4
MN_EE		EQU	5
AL		EQU	6
AS		EQU	7
AS2		EQU	8
IR		EQU	9
IR2		EQU	10
CS		EQU	11
EE		EQU	12

REFRESH_RATE	EQU	25		; 空ループの時のリフレッシュレート調整用
KEY_REPEAT	EQU	25		; 空ループを何回実行するとキーリピート状態にするか

;------------------------------------------------------------------------------
; EEPROMアドレス
;------------------------------------------------------------------------------
EE_ALARM_ALLON	EQU	0x70
I2C_ALARM_TIME	EQU	HIGH 0x4B00	; アラームの時刻とフラグを格納するスタートアドレス

;------------------------------------------------------------------------------
; 電源ON
;------------------------------------------------------------------------------
	ORG	0
	GOTO	POWER_ON

;------------------------------------------------------------------------------
; 割り込み処理
;------------------------------------------------------------------------------
	ORG	4			; 割り込みベクタ
					; ◆ RP=不明
	MOVWF	W_			; Wセーブ(W_かW__のどちらに書かれるかは不明)
	SWAPF	STATUS,W		; STATUSセーブ
	CLRF	STATUS			; ◆ RP=0
	MOVWF	STATUS_
	MOVF	PCLATH,W		; PCLATHセーブ
	MOVWF	PCLATH_
	MOVF	FSR,W			; FSRセーブ
	MOVWF	FSR_

	BCF	PIR1,CCP1IF		; 割り込みフラグをリセット
	INCF	SECOND,F		; 0.5秒ごとのCCP1割り込みをカウントする
	MOVLW	120
	SUBWF	SECOND,W
	BTFSS	STATUS,Z
	GOTO	INTRETURN
	
	CLRF	SECOND			; 1分
	BSF	FLAG,MINUTE_INCR	; 分がインクリメントされたらフラグをセットし、
	INCF	MINUTE,F		; メインルーチン内でアラーム処理をしてからフラグをリセットする。
	MOVLW	60
	SUBWF	MINUTE,W
	BTFSS	STATUS,Z
	GOTO	INTRETURN
	
	CLRF	MINUTE			; 1時間
	INCF	HOUR,F
	MOVLW	24
	SUBWF	HOUR,W
	BTFSS	STATUS,Z
	GOTO	INTRETURN
	
	CLRF	HOUR			; 1日

INTRETURN
	MOVF	FSR_,W			; FSRリストア
	MOVWF	FSR
	MOVF	PCLATH_,W		; PCLATHリストア
	MOVWF	PCLATH
	SWAPF	STATUS_,W		; STATUSリストア
	MOVWF	STATUS			; ◆ 不明なRPが復元される
	SWAPF	W_,F			; Wリストア
	SWAPF	W_,W
	RETFIE

;------------------------------------------------------------------------------
; 電源投入時の初期化
;------------------------------------------------------------------------------
POWER_ON
	CLRF	PORTA
	CLRF	PORTB
	CLRF	PORTC
	CLRF	TMR1H
	CLRF	TMR1L

	MOVLW	HIGH 0xF424		; CCP1を使って0.5秒の割り込みを発生させる
	MOVWF	CCPR1H			; Fosc / 8 / 2 = 62500 = 0xF424
	MOVLW	LOW  0xF424		; 		10倍速 = 186A
	MOVWF	CCPR1L
	MOVLW	B'00001011'		; コンペアモード、スペシャルイベントトリガ
	MOVWF	CCP1CON
	MOVLW	B'00101000'		; SSP=I2C
	MOVWF	SSPCON

	BSF	STATUS,RP0		; ◆ RP=1
	MOVLW	B'00000110'		; RAをデジタル入力として使用
	MOVWF	ADCON1
	MOVLW	B'00011111'		; RA5:/IR点灯出力, RA4:IRセンサ入力, RA3-0:スイッチ入力
	MOVWF	TRISA
	CLRF	TRISB			; RB7-0:LEDセグメント出力
	MOVLW	B'00011110'		; RC7-5:LED桁出力, RC4-3:I2C入力, RC2-1:未使用 RC-0:LED桁出力
	MOVWF	TRISC
	BSF	PIE1,CCP1IE		; CCP1割り込み有効
	CLRF	SSPCON2			; I2C初期化
	MOVLW	2			; 4,000,000/(4*(2+1))=333KHz
	MOVWF	SSPADD

	BCF	STATUS,RP0		; ◆ RP=0
	MOVLW	EE_ALARM_ALLON		; 変数初期値読み込み
	CALL	eeread
	MOVWF	FLAG

	MOVLW	B'00110001'		; プリスケーラ1:8、TIMER1スタート
	MOVWF	T1CON
	
	MOVLW	B'11000000'		; GIE=1,PEIE=1
	MOVWF	INTCON

	CLRF	HOUR
	CLRF	MINUTE
	CLRF	SECOND
	CLRF	MODE
	MOVLW	KEY_REPEAT
	MOVWF	REPEAT_COUNT

;------------------------------------------------------------------------------
; メインループ
;------------------------------------------------------------------------------
MAINLOOP
	MOVF	MODE,W			; CLモードの時は時計を表示させる
	BTFSC	STATUS,Z
	GOTO	MAINLOOP_CLOCK

	SUBLW	CS			; CSモードの時も時計を表示させる
	BTFSC	STATUS,Z
MAINLOOP_CLOCK
	CALL	clock_to_ascii
MAINLOOP_DISPLAY
	CALL	key_prepare		; キー入力準備
	CALL	display			; LED表示+キーチャタリングウエイト
	CALL	getkey			; キー入力
	
	BTFSC	FLAG,MINUTE_INCR	; 1分フラグが立っていない場合、アラームルーチンは実行する必要はない
	CALL	proc_alarm
MAINLOOP_KEY
	MOVF	KEY,W			; キーが押されている場合は、モード別キー処理を実行
	BTFSS	STATUS,Z
	CALL	proc_key
	GOTO	MAINLOOP

;------------------------------------------------------------------------------
; 時計レジスタからASCII文字列を作る
;
; time_to_asciiのdiv8でTMP07を使う
;------------------------------------------------------------------------------
clock_to_ascii
	MOVF	HOUR,W
	MOVWF	DISP_HOUR
	MOVF	MINUTE,W
	MOVWF	DISP_MINUTE
	CALL	time_to_ascii

	BTFSC	SECOND,0		; 1tickの時はDP処理を行わない
	RETURN

	MOVLW	CHAR_1H			; ポインタを使ってbit7を立てる桁を選択する
	MOVWF	FSR

	MOVLW	60			; 秒は60tick以上?
	SUBWF	SECOND,W
	BTFSC	STATUS,C
	GOTO	DP_HIGH
DP_LOW
	INCF	FSR,F			; 一桁下げる
	MOVLW	30			; 秒は30tick以上?
	SUBWF	SECOND,W
	BTFSS	STATUS,C
	INCF	FSR,F
	GOTO	DP_PROC
DP_HIGH
	MOVLW	90			; 秒は90tick以上?
	SUBWF	SECOND,W
	BTFSC	STATUS,C
	DECF	FSR,F
DP_PROC
	BSF	INDF,7
	RETURN

;------------------------------------------------------------------------------
; 数値型レジスタからASCII文字列を作る
;
; div8でTMP07を使う
;------------------------------------------------------------------------------
time_to_ascii
	MOVF	DISP_HOUR,W		; 時の上下の桁を分ける
	MOVWF	DIV1
	MOVLW	10
	MOVWF	DIV2
	CALL	div8
	MOVF	DIV1,W
	BTFSC	STATUS,Z		; 上位が0の場合は10(スペース)に置き換える
	MOVLW	10
	ADDLW	'0'			; ASCII変換
	MOVWF	CHAR_10H
	MOVF	MODULO,W
	ADDLW	'0'
	MOVWF	CHAR_1H
	
	MOVF	DISP_MINUTE,W
	MOVWF	DIV1
	MOVLW	10
	MOVWF	DIV2
	CALL	div8
	MOVF	DIV1,W
	ADDLW	'0'
	MOVWF	CHAR_10M
	MOVF	MODULO,W
	ADDLW	'0'
	MOVWF	CHAR_1M
	RETURN
;------------------------------------------------------------------------------
; ASCII文字列を表示させる
;
; waitでTMP06,07を使う
; get_patternでtmp07を使う
;------------------------------------------------------------------------------
display
	BTFSC	FLAG,DIRTY		; DIRTY状態ならば最下位LEDのDPを点灯させる。
	BSF	CHAR_1M,7

;		B'012    3'
	MOVLW	B'00010001'		; パターン取得、表示
	MOVWF	LED_PORTC
	MOVLW	CHAR_10H
	MOVWF	FSR
DISPLAY_LOOP
	MOVF	INDF,W
	CALL	get_pattern
	MOVWF	PORTB
	MOVF	LED_PORTC,W
	MOVWF	PORTC
	MOVLW	REFRESH_RATE
	CALL	wait
	
	INCF	FSR,F
	BCF	STATUS,C		; 次の桁へ
	RLF	LED_PORTC,F
	CLRF	PORTB
	CLRF	PORTC
	BTFSS	STATUS,C		; LED_PORTCの点灯ビットがあふれたら表示ループ終了
	GOTO	DISPLAY_LOOP
	RETURN

;------------------------------------------------------------------------------
; EEPROMからアラームデータを読み取り、出力する
;------------------------------------------------------------------------------
proc_alarm
	BCF	FLAG,MINUTE_INCR	; 1分フラグをクリア
	BTFSS	FLAG,ALARM_ALLON	; 全アラームがOFFの時はアラームルーチンを実行しない
	RETURN

	MOVLW	CL			; CLモード以外ではアラームを実行しない
	SUBWF	MODE,W
	BTFSS	STATUS,Z
	RETURN

	CLRF	ALARM_NUMBER
PROC_ALARM_LOOP
	MOVF	ALARM_NUMBER,W		; 各アラームのIRサイズをチェック
	CALL	eeread
	BTFSC	STATUS,Z		; データが無いなら次のアラームへ
	GOTO	PROC_ALARM_NEXT

	MOVLW	I2C_ALARM_TIME		; 各アラームの時刻をチェック
	MOVWF	I2CADRH
	BCF	STATUS,C
	RLF	ALARM_NUMBER,W
	MOVWF	I2CADRL
	MOVLW	ALARM_HOUR
	MOVWF	DATAPTR
	MOVLW	2
	MOVWF	DATASIZE
	CALL	i2cpread

	RLF	ALARM_HOUR,W
	BTFSS	STATUS,C
	GOTO	PROC_ALARM_NEXT		; アラーム個別ONフラグが立っていない場合は、次のアラームへ
	BCF	ALARM_HOUR,ALARM_ON
	MOVF	ALARM_HOUR,W
	SUBWF	HOUR,W
	BTFSS	STATUS,Z
	GOTO	PROC_ALARM_NEXT
	MOVF	ALARM_MINUTE,W
	SUBWF	MINUTE,W
	BTFSS	STATUS,Z
	GOTO	PROC_ALARM_NEXT

	CALL	load_ir			; 送信実行
	CALL	transmit_ir
PROC_ALARM_NEXT
	INCF	ALARM_NUMBER,F
	MOVLW	100
	SUBWF	ALARM_NUMBER,W
	BTFSS	STATUS,Z
	GOTO	PROC_ALARM_LOOP
	RETURN

;------------------------------------------------------------------------------
; モード別のキー処理へ分岐
; Mode |Key0   Key1   Key2   Key3
; -----+--------------------------
; AL   |---    Enable ---    Back
; AS   |AS2    +10    +1     Back
; AS2  |Enable H+     M+     Back
; IR   |IR2    +10    +1     Back
; IR2  |Test   IR Rec Delete Back
; IRRec|---    ----   ---    Back
; CS   |H+     M+     Sec=0  Back
; EE   |---    Format ---    Back
;------------------------------------------------------------------------------
proc_key
	BSF	FLAG,RELEASE
	MOVLW	HIGH $
	MOVWF	PCLATH
	MOVF	MODE,W
	ADDWF	PCL,F
	GOTO	BRANCH_CL
	GOTO	BRANCH_MN_AL
	GOTO	BRANCH_MN_AS
	GOTO	BRANCH_MN_IR
	GOTO	BRANCH_MN_CS
	GOTO	BRANCH_MN_EE
	GOTO	BRANCH_AL
	GOTO	BRANCH_AS
	GOTO	BRANCH_AS2
	GOTO	BRANCH_IR
	GOTO	BRANCH_IR2
	GOTO	BRANCH_CS
	GOTO	BRANCH_EE
;------------------------------------------------------------------------------
BRANCH_CL				; 時計モード
	BTFSC	KEY,0
	GOTO	MENU_AL			; -> MN_AL Mode
	RETURN
;------------------------------------------------------------------------------
BRANCH_MN_AL				; MN_AL Mode
	BTFSC	KEY,0
	GOTO	ENTER_MODE_AL		; -> AL Mode
	BTFSC	KEY,1
	NOP				; 未割当
	BTFSC	KEY,2
	GOTO	MENU_AS			; -> MN_AS Mode
	BTFSC	KEY,3
	GOTO	LEAVE_MENU		; -> CL Mode
	RETURN
;------------------------------------------------------------------------------
BRANCH_MN_AS				; MN_AS Mode
	BTFSC	KEY,0
	GOTO	ENTER_MODE_AS		; -> AS Mode
	BTFSC	KEY,1
	GOTO	MENU_AL			; -> MN_AL Mode
	BTFSC	KEY,2
	GOTO	MENU_IR			; -> MN_IR Mode
	BTFSC	KEY,3
	GOTO	LEAVE_MENU		; -> CL Mode
	RETURN
;------------------------------------------------------------------------------
BRANCH_MN_IR				; MN_IR Mode
	BTFSC	KEY,0
	GOTO	ENTER_MODE_IR		; -> IR Mode
	BTFSC	KEY,1
	GOTO	MENU_AS			; -> MN_AS Mode
	BTFSC	KEY,2
	GOTO	MENU_CS			; -> MN_CS Mode
	BTFSC	KEY,3
	GOTO	LEAVE_MENU		; -> CL Mode
	RETURN
;------------------------------------------------------------------------------
BRANCH_MN_CS				; MN_CS Mode
	BTFSC	KEY,0
	GOTO	ENTER_MODE_CS		; -> CS Mode
	BTFSC	KEY,1
	GOTO	MENU_IR			; -> MN_IR Mode
	BTFSC	KEY,2
	GOTO	MENU_EE			; -> MN_EE Mode
	BTFSC	KEY,3
	GOTO	LEAVE_MENU		; -> CL Mode
	RETURN
;------------------------------------------------------------------------------
BRANCH_MN_EE				; MN_EE Mode
	BTFSC	KEY,0
	GOTO	ENTER_MODE_EE		; -> EE Mode
	BTFSC	KEY,1
	GOTO	MENU_CS			; -> MN_CS Mode
	BTFSC	KEY,2
	NOP				; 未割当
	BTFSC	KEY,3
	GOTO	LEAVE_MENU		; -> CL Mode
	RETURN
;------------------------------------------------------------------------------
BRANCH_AL				; AL Mode:全アラームフラグ操作
	BTFSC	KEY,0
	NOP				; 未割当
	BTFSC	KEY,1
	GOTO	PROC_ALARM_ALLON	; 機能キー
	BTFSC	KEY,2
	NOP				; 未割当
	BTFSC	KEY,3
	GOTO	LEAVE_MODE_AL		; -> MN_AL Mode
	RETURN
;------------------------------------------------------------------------------
BRANCH_AS				; AS Mode:アラーム番号選択
	BTFSC	KEY,0
	GOTO	ENTER_MODE_AS2		; -> AS2 Mode
	BTFSC	KEY,1
	GOTO	PROC_ALARM_10		; 機能キー
	BTFSC	KEY,2
	GOTO	PROC_ALARM_1		; 機能キー
	BTFSC	KEY,3
	GOTO	LEAVE_MODE_AS		; -> MN_AS Mode
	RETURN
;------------------------------------------------------------------------------
BRANCH_AS2				; AS2 Mode:アラーム時刻設定
	BTFSC	KEY,0
	GOTO	PROC_ALARM_OFF		; 機能キー
	BTFSC	KEY,1
	GOTO	PROC_ALARM_HOUR		; 機能キー
	BTFSC	KEY,2
	GOTO	PROC_ALARM_MINUTE	; 機能キー
	BTFSC	KEY,3
	GOTO	LEAVE_MODE_AS2		; -> AS Mode
	RETURN
;------------------------------------------------------------------------------
BRANCH_IR				; IR Mode:赤外線データ番号選択
	BTFSC	KEY,0
	GOTO	ENTER_MODE_IR2		; -> IR2 Mode
	BTFSC	KEY,1
	GOTO	PROC_ALARM_10		; 機能キー (流用)
	BTFSC	KEY,2
	GOTO	PROC_ALARM_1		; 機能キー (流用)
	BTFSC	KEY,3
	GOTO	LEAVE_MODE_IR		; -> MN_IR Mode
	RETURN
;------------------------------------------------------------------------------
BRANCH_IR2				; IR2 Mode:赤外線データ設定
	BTFSC	KEY,0
	GOTO	PROC_IR_TEST		; 機能キー
	BTFSC	KEY,1
	GOTO	PROC_IR_RECORD		; 機能キー
	BTFSC	KEY,2
	GOTO	PROC_IR_DELETE		; 機能キー
	BTFSC	KEY,3
	GOTO	LEAVE_MODE_IR2		; -> IR Mode
	RETURN
;------------------------------------------------------------------------------
BRANCH_CS				; CS Mode:時計設定
	BTFSC	KEY,0
	GOTO	PROC_CLOCK_HOUR		; 機能キー
	BTFSC	KEY,1
	GOTO	PROC_CLOCK_MINUTE	; 機能キー
	BTFSC	KEY,2
	GOTO	PROC_CLOCK_ZERO		; 機能キー
	BTFSC	KEY,3
	GOTO	LEAVE_MODE_CS		; -> MN_CS Mode
	RETURN
;------------------------------------------------------------------------------
BRANCH_EE				; EE Mode:EEPROM初期化
	BTFSC	KEY,0
	NOP				; 未割当
	BTFSC	KEY,1
	GOTO	PROC_FORMAT		; 機能キー
	BTFSC	KEY,2
	NOP				; 未割当
	BTFSC	KEY,3
	GOTO	LEAVE_MODE_EE		; -> MN_EE Mode
	RETURN

;------------------------------------------------------------------------------
; メニュー遷移
;------------------------------------------------------------------------------
LEAVE_MENU				; Mode CLに戻る
	MOVLW	CL
	MOVWF	MODE
	RETURN

MENU_AL
	MOVLW	MN_AL
	MOVWF	MODE
	MOVLW	0			; AL (メニュー文字列)
	GOTO	MENU_COMMON

MENU_AS
	MOVLW	MN_AS
	MOVWF	MODE
	MOVLW	1			; AS
	GOTO	MENU_COMMON

MENU_IR
	MOVLW	MN_IR
	MOVWF	MODE
	MOVLW	2			; IR
	GOTO	MENU_COMMON

MENU_CS
	MOVLW	MN_CS
	MOVWF	MODE
	MOVLW	3			; CS
	GOTO	MENU_COMMON

MENU_EE
	MOVLW	MN_EE
	MOVWF	MODE
	MOVLW	4			; EE
MENU_COMMON
	MOVWF	STRING
	CALL	getstr
	RETURN

;------------------------------------------------------------------------------
; Mode AL アラームフラグ切り替え
;------------------------------------------------------------------------------
ENTER_MODE_AL			; モード移行後
	MOVLW	AL
	MOVWF	MODE
	BCF	FLAG,DIRTY		; 未編集状態にする
DISPLAY_ALARMFLAG			; フラグ状態表示
	MOVLW	5			; A.OFFの文字列
	BTFSC	FLAG,ALARM_ALLON	; フラグがONの時は
	MOVLW	6			;   A.ONの文字列
	MOVWF	STRING
	CALL	getstr
	RETURN

PROC_ALARM_ALLON		; フラグ切り替え処理
	MOVLW	B'00000001'		; ALARM_ALLONフラグビットだけ反転させる
	XORWF	FLAG,F
	BSF	FLAG,DIRTY
	GOTO	DISPLAY_ALARMFLAG	; フラグ状態表示へ

LEAVE_MODE_AL			; メニューに戻る
	MOVLW	EE_ALARM_ALLON		; EEPROM保存先アドレス
	MOVWF	EEADR_
	MOVLW	B'00000001'		; FLAG-ALARM_ALLONを抽出
	ANDWF	FLAG,W
	BTFSC	FLAG,DIRTY		; DIRTY状態の場合にEEPROMへ書き込む
	CALL	eewrite
	BCF	FLAG,DIRTY
	GOTO	MENU_AL

;------------------------------------------------------------------------------
; Mode AS アラーム番号選択
;------------------------------------------------------------------------------
ENTER_MODE_AS			; モード移行後
	MOVLW	AS
	MOVWF	MODE
	CLRF	ALARM_NUMBER
DISPLAY_ALARM_NUMBER			; アラーム番号の表示
	MOVF	ALARM_NUMBER,W
	MOVWF	DISP_MINUTE
	CALL	time_to_ascii

	MOVLW	AS
	SUBWF	MODE,W
	MOVLW	'A'			; Mode ASの時は"A-"を頭に付ける
	BTFSS	STATUS,Z
	MOVLW	'I'			; 違うときは"I-"を頭に付ける
	MOVWF	CHAR_10H

	MOVLW	';'
	MOVWF	CHAR_1H

	MOVLW	I2C_ALARM_TIME		; アラーム個別ONフラグがある時はDP-1Hを点灯
	MOVWF	I2CADRH
	BCF	STATUS,C
	RLF	ALARM_NUMBER,W
	MOVWF	I2CADRL
	CALL	i2cread
	RLF	I2CDATA,W
	BTFSC	STATUS,C
	BSF	CHAR_1H,7

	MOVF	ALARM_NUMBER,W		; 赤外線データがある時はDP-10Hを点灯
	CALL	eeread
	BTFSS	STATUS,Z
	BSF	CHAR_10H,7
	RETURN

PROC_ALARM_10			; アラーム番号10の位インクリメント
	MOVF	ALARM_NUMBER,W		; 数値を10と1の位に分けて、
	MOVWF	DIV1
	MOVLW	10
	MOVWF	DIV2
	CALL	div8
	MOVF	MODULO,W		; 1の位を保存しておく
	MOVWF	TMP00

	INCF	DIV1,F			; 10の位をインクリメント
	MOVLW	10			; 結果が10になったら0にリセット
	SUBWF	DIV1,W
	BTFSC	STATUS,Z
	CLRF	DIV1
PROC_ALARM_10_COMPLEX
	MOVF	DIV1,W			; インクリメント後元に戻す
	MOVWF	MUL1
	MOVLW	10			; 10で割られている10の位を×10
	MOVWF	MUL3
	CALL	mul8
	MOVF	MUL1,W
	ADDWF	TMP00,W			; 保存しておいた1の位を足す
	MOVWF	ALARM_NUMBER
	GOTO	DISPLAY_ALARM_NUMBER
	
PROC_ALARM_1			; アラーム番号1の位インクリメント
	MOVF	ALARM_NUMBER,W		; 数値を10と1の位に分けて、
	MOVWF	DIV1
	MOVLW	10
	MOVWF	DIV2
	CALL	div8
					; 10で割られている10の位はそのままにしておく
	INCF	MODULO,F		; 1の位をインクリメント
	MOVLW	10			; 結果が10になったら0にリセット
	SUBWF	MODULO,W
	BTFSC	STATUS,Z
	CLRF	MODULO
	MOVF	MODULO,W		; 1の位を保存しておく
	MOVWF	TMP00
	GOTO	PROC_ALARM_10_COMPLEX

LEAVE_MODE_AS			; メニューに戻る
	GOTO	MENU_AS

;------------------------------------------------------------------------------
; Mode AS2 アラーム時刻設定
;------------------------------------------------------------------------------
ENTER_MODE_AS2			; モード移行後
	MOVLW	AS2
	MOVWF	MODE
	CALL	load_alarm		; アラーム時刻をEEPROMからロード
DISPLAY_ALARM_TIME			; アラーム時刻の表示
	BTFSS	FLAG,ALARM_ON		; アラームがOFFの時は"OFF"を表示させる
	GOTO	DISPLAY_ALARM_OFF
	MOVF	ALARM_HOUR,W
	MOVWF	DISP_HOUR
	MOVF	ALARM_MINUTE,W
	MOVWF	DISP_MINUTE
	CALL	time_to_ascii
DISPLAY_ALARM_FLAG			; 編集状態をDPで表示(AS2,IR2共用)
	BTFSC	FLAG,ALARM_ON		; アラーム個別フラグがONの時はDP-1Hを点灯
	BSF	CHAR_1H,7
	
	MOVF	ALARM_SIZE,W		; 赤外線データがある時はDP-10Hを点灯
	BTFSS	STATUS,Z
	BSF	CHAR_10H,7
	RETURN

DISPLAY_ALARM_OFF
	MOVLW	8			; OFFの文字列
	MOVWF	STRING
	CALL	getstr
	GOTO	DISPLAY_ALARM_FLAG

PROC_ALARM_HOUR			; 時インクリメント
	BTFSS	FLAG,ALARM_ON		; アラームがOFFの時はアラームをONにする
	GOTO	PROC_ALARM_ON
	INCF	ALARM_HOUR,F
	MOVLW	24
	SUBWF	ALARM_HOUR,W
	BTFSC	STATUS,Z
	CLRF	ALARM_HOUR
	BSF	FLAG,DIRTY
	GOTO	DISPLAY_ALARM_TIME	; 時刻表示
	
PROC_ALARM_MINUTE		; 分インクリメント
	BTFSS	FLAG,ALARM_ON		; アラームがOFFの時はアラームをONにする
	GOTO	PROC_ALARM_ON
	INCF	ALARM_MINUTE,F
	MOVLW	60
	SUBWF	ALARM_MINUTE,W
	BTFSC	STATUS,Z
	CLRF	ALARM_MINUTE
	BSF	FLAG,DIRTY
	GOTO	DISPLAY_ALARM_TIME	; 時刻表示
	
PROC_ALARM_ON			; アラーム個別フラグを切り替える
	BSF	FLAG,ALARM_ON
	BSF	FLAG,DIRTY
	GOTO	DISPLAY_ALARM_TIME	; 時刻表示
	
PROC_ALARM_OFF			; アラーム個別フラグを切り替える
	BCF	FLAG,ALARM_ON
	BSF	FLAG,DIRTY
	GOTO	DISPLAY_ALARM_TIME	; 時刻表示
	
LEAVE_MODE_AS2			; アラーム番号選択に戻る
	CALL	save_alarm		; DIRTYの場合は保存する、フラグは勝手にクリアされる
	MOVLW	AS
	MOVWF	MODE
	GOTO	DISPLAY_ALARM_NUMBER	; アラーム番号を維持して戻る

;------------------------------------------------------------------------------
; Mode IR 赤外線番号選択
;------------------------------------------------------------------------------
ENTER_MODE_IR			; モード移行後
	MOVLW	IR
	MOVWF	MODE
	CLRF	ALARM_NUMBER
	GOTO	DISPLAY_ALARM_NUMBER	; 番号表示と選択画面はアラーム選択を流用する

LEAVE_MODE_IR			; メニューに戻る
	GOTO	MENU_IR

;------------------------------------------------------------------------------
; Mode IR2 赤外線データの読み込み・テスト
;------------------------------------------------------------------------------
ENTER_MODE_IR2			; モード移行後
	MOVLW	IR2
	MOVWF	MODE
	CALL	load_ir			; IRデータをロード
DISPLAY_IR_SIZE				; IRサイズ表示
	MOVF	ALARM_SIZE,W	
	MOVWF	DIV1
	MOVLW	100
	MOVWF	DIV2
	CALL	div8
	MOVF	DIV1,W
	MOVWF	DISP_HOUR
	MOVF	MODULO,W
	MOVWF	DISP_MINUTE
	CALL	time_to_ascii
	GOTO	DISPLAY_ALARM_FLAG	; 編集状態をDPで表示

PROC_IR_TEST			; テスト送信
	CALL	transmit_ir
	RETURN

PROC_IR_RECORD			; 記録
	CALL	recieve_ir		; DIRTYはサブルーチン内でセットされる
	GOTO	DISPLAY_IR_SIZE		; IRサイズ表示

PROC_IR_DELETE			; IRデータ削除
	CLRF	ALARM_SIZE
	BSF	FLAG,DIRTY
	GOTO	DISPLAY_IR_SIZE		; IRサイズ表示

LEAVE_MODE_IR2			; 赤外線番号選択に戻る
	CALL	save_ir			; DIRTYの場合は保存する
	MOVLW	IR
	MOVWF	MODE
	GOTO	DISPLAY_ALARM_NUMBER	; 赤外線番号を維持して戻る
	
;------------------------------------------------------------------------------
; Mode CS 時刻設定
;------------------------------------------------------------------------------
ENTER_MODE_CS			; モード移行後
	MOVLW	CS
	MOVWF	MODE
	RETURN

PROC_CLOCK_HOUR			; 1時間プラス
	INCF	HOUR,W
	MOVWF	TMP00
	SUBLW	24			; 1回転チェック
	BTFSC	STATUS,Z
	CLRF	TMP00
	MOVF	TMP00,W
	MOVWF	HOUR
	RETURN

PROC_CLOCK_MINUTE		; 1分プラス
	CLRF	TMR1L			; 秒もリセットする
	CLRF	TMR1H
	CLRF	SECOND
	INCF	MINUTE,W
	MOVWF	TMP00
	SUBLW	60			; 1回転チェック
	BTFSC	STATUS,Z
	CLRF	TMP00
	MOVF	TMP00,W
	MOVWF	MINUTE
	RETURN

PROC_CLOCK_ZERO			; 分と秒をリセット
	CLRF	TMR1L
	CLRF	TMR1H
	CLRF	SECOND
	CLRF	MINUTE
	RETURN

LEAVE_MODE_CS				; メニューに戻る
	GOTO	MENU_CS

;------------------------------------------------------------------------------
; Mode EE EEPROM初期化
;------------------------------------------------------------------------------
ENTER_MODE_EE			; モード移行後
	MOVLW	EE
	MOVWF	MODE
	MOVLW	7		; メッセージ表示
	GOTO	MENU_COMMON

PROC_FORMAT
	BSF	FLAG,ALARM_ALLON	; 全アラームON
	MOVLW	EE_ALARM_ALLON
	MOVWF	EEADR_
	MOVLW	B'00000001'
	CALL	eewrite

	MOVLW	IRDATA2			; I2CROMを初期化するためのパターンを用意
	MOVWF	FSR
	MOVLW	66
	MOVWF	TMP00
PROC_FORMAT_INIT_BUFFER
	MOVLW	65			; 65以上の時は00(時刻用)、未満の時はFF(データ用)
	SUBWF	TMP00,W
	MOVLW	0xFF
	BTFSC	STATUS,C
	CLRW
	MOVWF	INDF
	INCF	FSR,F
	DECFSZ	TMP00,F
	GOTO	PROC_FORMAT_INIT_BUFFER

	CLRF	DISP_MINUTE		; DISP_MINUTEをアドレスカウンタに使用する
	MOVLW	100
	MOVWF	TMP00
PROC_FORMAT_LOOP
	CALL	time_to_ascii		; アドレス表示
	MOVLW	'E'
	MOVWF	CHAR_10H
	MOVLW	';'
	MOVWF	CHAR_1H
	CALL	display

	MOVLW	I2C_ALARM_TIME		; アラーム時刻
	MOVWF	I2CADRH
	BCF	STATUS,C
	RLF	DISP_MINUTE,W		; 2バイトごとのアドレスを計算
	MOVWF	I2CADRL
	MOVLW	2
	MOVWF	DATASIZE
	MOVLW	IRDATA2
	MOVWF	DATAPTR
	CALL	i2cpwrite

	MOVF	DISP_MINUTE,W		; アラームサイズ
	MOVWF	EEADR_
	CLRW
	CALL	eewrite

	MOVF	DISP_MINUTE,W		; IRデータ
	MOVWF	MUL1			; 192バイトごとのアドレスを計算
	MOVLW	192			; データはページ境界をまたぐことはできないので、
	MOVWF	MUL3			; 実データがMAX_SIZEバイトでも、ページ書き込みは192バイトで行う。
	CALL	mul8

	MOVF	MUL2,W			; 0〜63バイト
	MOVWF	I2CADRH
	MOVF	MUL1,W
	MOVWF	I2CADRL
	MOVLW	64
	MOVWF	DATASIZE
	MOVLW	IRDATA2+1
	MOVWF	DATAPTR
	CALL	i2cpwrite

	MOVLW	64			; 64〜127バイト
	ADDWF	I2CADRL,F
	BTFSC	STATUS,C
	INCF	I2CADRH,F
	MOVLW	IRDATA2+2
	MOVWF	DATAPTR
	CALL	i2cpwrite

	MOVLW	64			; 128〜191バイト
	ADDWF	I2CADRL,F
	BTFSC	STATUS,C
	INCF	I2CADRH,F
	MOVLW	IRDATA2+1
	MOVWF	DATAPTR
	CALL	i2cpwrite

	INCF	DISP_MINUTE,F
	DECFSZ	TMP00,F
	GOTO	PROC_FORMAT_LOOP			
	GOTO	ENTER_MODE_EE		; EE Modeへ戻る

LEAVE_MODE_EE				; メニューへ戻る
	GOTO	MENU_EE

;------------------------------------------------------------------------------
; アラームデータ、赤外線データセーブ、ロードルーチン
;
;  load_alarm	アラーム時刻・アラーム個別ONフラグ・赤外線サイズ(参照用)をロード
;  save_alarm	アラーム時刻・アラーム個別ONフラグをセーブ
;  load_ir	赤外線データ・赤外線サイズ・アラーム個別ONフラグ(参照用)をロード
;  save_ir	赤外線データ・赤外線サイズをセーブ
;
;  アラーム時刻はI2CROMに保存する時、アラーム個別ONフラグを重畳して保存する。
;  アラーム時刻をI2CROMから読み出す時、アラーム個別ONフラグを除去してFLAG-ALARM_ONを立てる。
;  それぞれALARM_NUMBERをセットしてから呼び出すこと
;------------------------------------------------------------------------------
load_alarm
	MOVLW	I2C_ALARM_TIME		; アラーム時刻をI2CROMから取得
	MOVWF	I2CADRH
	BCF	STATUS,C
	RLF	ALARM_NUMBER,W
	MOVWF	I2CADRL			; 時と分を取得
	MOVLW	ALARM_HOUR
	MOVWF	DATAPTR
	MOVLW	2
	MOVWF	DATASIZE
	CALL	i2cpread

	BCF	FLAG,ALARM_ON
	RLF	ALARM_HOUR,W		; アラーム個別ONフラグがOFFの時はフラグビット落とし処理を省略
	BTFSS	STATUS,C
	GOTO	LOAD_ALARM2
	BCF	ALARM_HOUR,ALARM_ON	; フラグビットを落とす代わりにフラグレジスタをONにする
	BSF	FLAG,ALARM_ON
LOAD_ALARM2
	MOVF	ALARM_NUMBER,W		; IRサイズをEEPROMから取得
	CALL	eeread
	MOVWF	ALARM_SIZE

	BCF	FLAG,DIRTY
	RETURN

save_alarm
	BTFSS	FLAG,DIRTY		; DIRTY状態でなければ書き込まない
	RETURN

	BTFSC	FLAG,ALARM_ON		; アラーム個別ONフラグをアラーム時刻と重畳させる
	BSF	ALARM_HOUR,ALARM_ON
	MOVLW	I2C_ALARM_TIME		; アラーム時刻をI2CROMに保存
	MOVWF	I2CADRH
	BCF	STATUS,C
	RLF	ALARM_NUMBER,W
	MOVWF	I2CADRL
	MOVLW	ALARM_HOUR		; 時と分を保存
	MOVWF	DATAPTR
	MOVLW	2
	MOVWF	DATASIZE
	CALL	i2cpwrite

	BCF	FLAG,DIRTY
	RETURN

load_ir
	MOVF	ALARM_NUMBER,W		; IRサイズをEEPROMから取得
	CALL	eeread
	MOVWF	ALARM_SIZE

	BCF	FLAG,DIRTY
	BTFSC	STATUS,Z		; サイズが0の時は取得しない
	RETURN

	BCF	FLAG,ALARM_ON
	MOVLW	I2C_ALARM_TIME		; アラーム個別ONをロード
	MOVWF	I2CADRH
	BCF	STATUS,C
	RLF	ALARM_NUMBER,W
	MOVWF	I2CADRL
	CALL	i2cread
	RLF	I2CDATA,W
	BTFSC	STATUS,C
	BSF	FLAG,ALARM_ON

	BCF	FLAG,PAGE_OVER
	MOVF	ALARM_NUMBER,W		; スタートアドレスを計算
	MOVWF	MUL1
	MOVLW	192
	MOVWF	MUL3
	CALL	mul8
	MOVF	MUL2,W
	MOVWF	I2CADRH
	MOVF	MUL1,W
	MOVWF	I2CADRL
	
	MOVLW	IRDATA1			; データバッファの初期ポインタを設定
	MOVWF	DATAPTR
	MOVF	ALARM_SIZE,W
	MOVWF	TMP00			; ロードする残りのバイト数
LOADIR_LOOP
	MOVLW	64			; ロードするページあたりのバイト数を計算
	SUBWF	TMP00,W
	MOVF	TMP00,W
	BTFSC	STATUS,C
	MOVLW	64			; 64バイト以上の場合は64固定
	MOVWF	DATASIZE
	CALL	i2cpread		; 読み出し

	MOVLW	64			; I2Cポインタを移動
	ADDWF	I2CADRL,F
	BTFSC	STATUS,C
	INCF	I2CADRH,F
	
	MOVF	DATASIZE,W		; データポインタをインクリメント
	ADDWF	DATAPTR,F
	BTFSC	FLAG,PAGE_OVER		; IRDATA1からIRDATA2へのページ切り替えが発生したとき1度だけDATAPTRを書き換えるようにする
	GOTO	LOADIR_LOOPNEXT
	MOVLW	0x80
	SUBWF	DATAPTR,W
	BTFSS	STATUS,C
	GOTO	LOADIR_LOOPNEXT
	BSF	FLAG,PAGE_OVER		; ページ切り替えが発生した時
	MOVLW	0x80			; 0x80からIRDATA2にアドレスを飛ばす
	SUBWF	DATAPTR,W
	ADDLW	IRDATA2
	MOVWF	DATAPTR

LOADIR_LOOPNEXT
	MOVF	DATASIZE,W
	SUBWF	TMP00,F
	BTFSS	STATUS,Z		; 残りのバイト数が0になるまでループ
	GOTO	LOADIR_LOOP
	RETURN

save_ir					; IRデータをALARM_NUMBERに保存
	BTFSS	FLAG,DIRTY		; DIRTY状態でなければ保存しない
	RETURN
	BCF	FLAG,DIRTY

	MOVF	ALARM_NUMBER,W		; IRサイズをEEPROMに保存
	MOVWF	EEADR_
	MOVF	ALARM_SIZE,W
	CALL	eewrite

	MOVF	ALARM_SIZE,W		; サイズが0の時はデータを保存しない
	BTFSC	STATUS,Z
	RETURN

	BCF	FLAG,PAGE_OVER
	MOVF	ALARM_NUMBER,W		; スタートアドレスを計算
	MOVWF	MUL1
	MOVLW	192
	MOVWF	MUL3
	CALL	mul8
	MOVF	MUL2,W
	MOVWF	I2CADRH
	MOVF	MUL1,W
	MOVWF	I2CADRL
	
	MOVLW	IRDATA1			; データバッファの初期ポインタを設定
	MOVWF	DATAPTR
	MOVF	ALARM_SIZE,W
	MOVWF	TMP00			; セーブする残りのバイト数
SAVEIR_LOOP
	MOVLW	64			; セーブするページあたりのバイト数を計算
	SUBWF	TMP00,W
	MOVF	TMP00,W
	BTFSC	STATUS,C
	MOVLW	64			; 64バイト以上の場合は64固定
	MOVWF	DATASIZE
	CALL	i2cpwrite		; 書き込み

	MOVLW	64			; I2Cポインタを移動
	ADDWF	I2CADRL,F
	BTFSC	STATUS,C
	INCF	I2CADRH,F
	
	MOVF	DATASIZE,W		; データポインタをインクリメント
	ADDWF	DATAPTR,F
	BTFSC	FLAG,PAGE_OVER		; IRDATA1からIRDATA2へのページ切り替えが発生したとき1度だけDATAPTRを書き換えるようにする
	GOTO	SAVEIR_LOOPNEXT
	MOVLW	0x80
	SUBWF	DATAPTR,W
	BTFSS	STATUS,C
	GOTO	SAVEIR_LOOPNEXT
	BSF	FLAG,PAGE_OVER		; ページ切り替えが発生した時
	MOVLW	0x80			; 0x80からIRDATA2にアドレスを飛ばす
	SUBWF	DATAPTR,W
	ADDLW	IRDATA2
	MOVWF	DATAPTR

SAVEIR_LOOPNEXT
	MOVF	DATASIZE,W
	SUBWF	TMP00,F
	BTFSS	STATUS,Z		; 残りのバイト数が0になるまでループ
	GOTO	SAVEIR_LOOP
	RETURN

;------------------------------------------------------------------------------
; 赤外線送受信ルーチン
;  recieve_ir	赤外線データを受信する、サンプリング周期は26サイクル(38,462Hz)
;  transmit_ir  赤外線データを送信する
;------------------------------------------------------------------------------
recieve_ir
	MOVLW	IRDATA1
	MOVWF	FSR
	CLRF	TMP00			; サイズカウンタ
	BSF	FLAG,RELEASE		; 受信キャンセル後にキー検出が行われないようにする
RECIEVE_PRE_LOOP
	BTFSS	PORTA,IR_IN		; 入力あり(負論理)まで待機
	GOTO	FIRST_RECIEVE		; 初期ビットは最小5、最大9サイクル遅れる
	BTFSC	PORTA,KEY_3
	GOTO	RECIEVE_PRE_LOOP
	RETURN				; キー3が押されたら(負論理)受信をキャンセルする
FIRST_RECIEVE
	BCF	INTCON,GIE		; タイミングが狂わないように割り込みを禁止する
	CLRF	INDF			; 初期ビットの初期化用
RECIEVE
	SWAPF	PORTA,W			; IRセンサ(bit0)とサイズカウンタのbit0を比較
	XORWF	TMP00,W			; 同じならZが立つ
	ANDLW	1
	BTFSS	STATUS,Z
	GOTO	RECIEVE_NEXT_BIT 	; 違うなら次のビットへ
	INCFSZ	INDF,W
	GOTO	RECIEVE_NORMAL_WAIT

	INCF	TMP00,F			; ロングビットでキャリーオーバーした時
	MOVLW	MAX_SIZE		; 空のビットを追加して、2度ポインタ移動
	SUBWF	TMP00,W			; バッファサイズいっぱいまで読み込んだ?
	BTFSC	STATUS,Z
	GOTO	TRUNCATE		; 強制的に読み込み終了、リターン前処理
	INCF	FSR,F			; バッファポインタインクリメント
	MOVLW	0x80			; バッファ境界をまたいだ?
	SUBWF	FSR,W
	MOVLW	IRDATA2			; またいだ場合はIRDATA2へ移動
	BTFSC	STATUS,Z
	MOVWF	FSR
	CLRF	INDF

	INCF	TMP00,F
	MOVLW	MAX_SIZE
	SUBWF	TMP00,W			; バッファサイズいっぱいまで読み込んだ?
	BTFSC	STATUS,Z
	GOTO	TRUNCATE		; 強制的に読み込み終了、リターン前処理
	INCF	FSR,F			; バッファポインタインクリメント
	MOVLW	0x80			; バッファ境界をまたいだ?
	SUBWF	FSR,W
	MOVLW	IRDATA2			; またいだ場合はIRDATA2へ移動
	BTFSC	STATUS,Z
	MOVWF	FSR
	CLRF	INDF

	INCF	INDF,F
	GOTO	RECIEVE

RECIEVE_NEXT_BIT			; 次のビットへポインタ移動
	INCF	TMP00,F
	MOVLW	MAX_SIZE
	SUBWF	TMP00,W			; バッファサイズいっぱいまで読み込んだ?
	BTFSC	STATUS,Z
	GOTO	TRUNCATE		; 強制的に読み込み終了、リターン前処理

	INCF	FSR,F			; バッファポインタインクリメント
	MOVLW	0x80			; バッファ境界をまたいだ?
	SUBWF	FSR,W
	MOVLW	IRDATA2			; またいだ場合はIRDATA2へ移動
	BTFSC	STATUS,Z
	MOVWF	FSR
	CLRF	INDF

	INCF	INDF,F
	GOTO	$+1
	GOTO	$+1
	NOP
	GOTO	RECIEVE

RECIEVE_NORMAL_WAIT			; 一番短いルートのウエイト
	MOVWF	INDF
	NOP
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	GOTO	RECIEVE

TRUNCATE				; 末尾についている不要な0のビットを削除
	BSF	INTCON,GIE
	BSF	FLAG,DIRTY
	MOVLW	MAX_SIZE
	MOVWF	ALARM_SIZE
	MOVLW	0xFE
	MOVWF	FSR
TRUNCATE_LOOP
	MOVF	INDF,W			; 最後の1のビット幅が0ならば、最後の0のビットもカットする
	BTFSS	STATUS,Z
	RETURN				; リターンポイント
	DECF	ALARM_SIZE,F
	DECF	ALARM_SIZE,F
	CALL	TRUNCATE_MOVE_POINTER	
	CALL	TRUNCATE_MOVE_POINTER	
	GOTO	TRUNCATE_LOOP

TRUNCATE_MOVE_POINTER
	DECF	FSR,F			; バッファ境界を処理する
	MOVLW	IRDATA2-1
	SUBWF	FSR,W
	MOVLW	0x7F
	BTFSC	STATUS,Z
	MOVWF	FSR
	RETURN


transmit_ir
	BCF	PORTA,IR_OUT		; 念のため
	MOVF	ALARM_SIZE,W		; サイズが0の時は送信しない
	BTFSC	STATUS,Z
	RETURN

	MOVLW	3
	MOVWF	TMP02
TRANSMIT_3TIMES
	MOVF	ALARM_SIZE,W
	MOVWF	TMP00			; 送信バイト数カウンタ

	MOVLW	IRDATA1
	MOVWF	FSR
TRANSMIT_LOOP
	MOVLW	B'00100000'		; LED点灯状態を反転
	XORWF	PORTA,F
TRANSMIT_NOCHENGE
	MOVF	INDF,W			; ビット幅カウンタをロード
	MOVWF	TMP01
TRANSMIT_BIT_WAIT
	DECFSZ	TMP01,F
	GOTO	TRANSMIT_NORMAL_WAIT

	INCF	FSR,F			; バッファポインタインクリメント
	MOVLW	0x80			; バッファ境界をまたいだ?
	SUBWF	FSR,W
	MOVLW	IRDATA2			; またいだ場合はIRDATA2へ移動
	BTFSC	STATUS,Z
	MOVWF	FSR

	MOVF	INDF,W
	BTFSS	STATUS,Z
	GOTO	TRANSMIT_NEXT_WAIT
	INCF	FSR,F			; バッファポインタインクリメント
	MOVLW	0x80			; バッファ境界をまたいだ?
	SUBWF	FSR,W
	MOVLW	IRDATA2			; またいだ場合はIRDATA2へ移動
	BTFSC	STATUS,Z
	MOVWF	FSR
	DECFSZ	TMP00,F
	GOTO	TRANSMIT_NEXT_LONGBIT
	GOTO	TRANSMIT_RETURN
TRANSMIT_NEXT_WAIT
	GOTO	$+1	
	GOTO	$+1	
	GOTO	$+1
	NOP
	DECFSZ	TMP00,F
	GOTO	TRANSMIT_LOOP
TRANSMIT_RETURN
	BCF	PORTA,IR_OUT
	CALL	wait_100ms
	DECFSZ	TMP02,F
	GOTO	TRANSMIT_3TIMES
	RETURN

TRANSMIT_NEXT_LONGBIT			; ロングビットの時はLEDの状態を維持する
	NOP
	DECFSZ	TMP00,F
	GOTO	TRANSMIT_NOCHENGE
	GOTO	TRANSMIT_RETURN

TRANSMIT_NORMAL_WAIT
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	GOTO	$+1
	NOP
	GOTO	TRANSMIT_BIT_WAIT

;------------------------------------------------------------------------------
; キー取得ルーチン
;  チャタリング防止のため、keyprepareで仮取得してしばらく経ってからgetkeyで本取得する
;  チャタリングと判断すればKEY=0となる
;  FLAG-RELEASEを立てた状態でgetkeyを呼ぶと、実際のKEY=0になるまでKEY=0を返す
;   キーがリリースされるとFLAG-RELEASEがOFFになり、新たなキーを読み込めるようになる。
;------------------------------------------------------------------------------
key_prepare
	COMF	PORTA,W			; キーはプルアップされているので、反転取得する。
	ANDLW	0x0F
	MOVWF	KEY
	RETURN

getkey
	COMF	PORTA,W
	ANDLW	0x0F
	SUBWF	KEY,W			; 前回の読み込みと異なるならゼロフラグが立たないので
	BTFSS	STATUS,Z		; 読み込んだキーを無効=0として反映する
	CLRF	KEY

	BTFSC	FLAG,RELEASE		; キーリリース処理が不要な場合はリターン
	GOTO	PROC_RELEASE
	MOVLW	KEY_REPEAT
	MOVWF	REPEAT_COUNT
	RETURN

PROC_RELEASE
	MOVF	KEY,W
	BTFSC	STATUS,Z
	GOTO	NO_KEY
					; キーが押されている状態
	DECFSZ	REPEAT_COUNT,F
	GOTO	NO_REPEAT
	MOVLW	KEY_REPEAT		; リピートタイマーが満了したら
	MOVWF	REPEAT_COUNT		; 回数をリセットしてキーを返す
	RETURN	

NO_KEY					; キーが押されていない場合
	MOVLW	KEY_REPEAT
	MOVWF	REPEAT_COUNT
	BCF	FLAG,RELEASE
NO_REPEAT				; リピートタイマーを満了していない
	CLRF	KEY
	RETURN

;------------------------------------------------------------------------------
; 文字列をプログラムメモリから取得し、CHAR_10H〜CHAR_1Mに入れる
;
;  TMP07を使う
;------------------------------------------------------------------------------
getstr
	MOVLW	CHAR_10H		; LEDメモリの場所
	MOVWF	FSR
	MOVLW	4			; 4文字ループ
	MOVWF	TMP07
	RLF	STRING,F		; 文字列番号から実際のアドレスに変換
	RLF	STRING,W
	ANDLW	0xFC
	BSF	STATUS,RP1		; ◆ RP=2
	ADDLW	LOW STRSTART
	MOVWF	EEADR
	MOVLW	HIGH STRSTART
	MOVWF	EEADRH
GETSTRLOOP
	BSF	STATUS,RP1		; ◆ RP=2
	BSF	STATUS,RP0		; ◆ RP=3
	BSF	EECON1,EEPGD
	BSF	EECON1,RD
	NOP
	NOP
	BCF	STATUS,RP0		; ◆ RP=2
	INCF	EEADR,F
	MOVF	EEDATA,W
	MOVWF	INDF
	INCF	FSR,F
	BCF	STATUS,RP1		; ◆ RP=0
	DECFSZ	TMP07,F
	GOTO	GETSTRLOOP
	RETURN	

;------------------------------------------------------------------------------
; EEPROMアクセスルーチン
;  eeread	内蔵EEPROMのアドレスWから読み出してデータをWに入れる
;  eewrite	データWを内蔵EEPROMのアドレスEEADR_へ書き込む
;------------------------------------------------------------------------------
eeread
	BSF	STATUS,RP1		; ◆ RP=2
	MOVWF	EEADR
	BSF	STATUS,RP0		; ◆ RP=3
	BCF	EECON1,EEPGD		; データEEPROMを選択
	BSF	EECON1,RD		; 読み出し
	BCF	STATUS,RP0		; ◆ RP=2
	MOVF	EEDATA,W
	BCF	STATUS,RP1		; ◆ RP=0
	RETURN

eewrite
	BSF	STATUS,RP1		; ◆ RP=2
	MOVWF	EEDATA
	BCF	STATUS,RP1		; ◆ RP=0
	MOVF	EEADR_,W
	BSF	STATUS,RP1		; ◆ RP=2
	MOVWF	EEADR
	BSF	STATUS,RP0		; ◆ RP=3
	BCF	EECON1,EEPGD		; データEEPROMを選択
	BCF	INTCON,GIE		; 割り込み禁止
	BSF	EECON1,WREN
	MOVLW	0x55			; 書き込みパターン
	MOVWF	EECON2
	MOVLW	0xAA
	MOVWF	EECON2
	BSF	EECON1,WR		; 書き込み
	BSF	INTCON,GIE		; 割り込み許可
EEWRITEPOLL
	BTFSC	EECON1,WR		; 書き込みが終わるまでループ
	GOTO	EEWRITEPOLL
	BCF	EECON1,WREN		; 書き込み保護
	BCF	STATUS,RP1		; ◆ RP=1
	BCF	STATUS,RP0		; ◆ RP=0
	RETURN

;------------------------------------------------------------------------------
; I2C EEPROMアクセスルーチン群
;  i2cpread	I2CADRH,I2CADRLからDATAPTRへDATASIZEバイト読み出す(最大64バイト)
;  i2cpwrite	DATAPTRからDATASIZEバイトをI2CADRH,I2CADRLへ書き込む(最大64バイト)
;  i2cread	I2CADRH,I2CADRLからI2CDATAへ読み出す
;  i2cwrite	I2CDATAをI2CADRH,I2CADRLへ書き込む
;
;  TMP07を使う
;------------------------------------------------------------------------------
i2csspif				; I2Cコマンド終了待ち
	BCF	STATUS,RP0		; ◆ RP=0		
	BTFSS	PIR1,SSPIF		; SSPIFポーリング
	GOTO	i2csspif
	RETURN

i2cstart				; スタートコンディション送信
	BCF	STATUS,RP0		; ◆ RP=0		
	BCF	PIR1,SSPIF		; SSPIFリセット
	BSF	STATUS,RP0		; ◆ RP=1
	BSF	SSPCON2,SEN
	GOTO	i2csspif

i2crestart				; 再スタートコンディション送信
	BCF	STATUS,RP0		; ◆ RP=0		
	BCF	PIR1,SSPIF		; SSPIFリセット
	BSF	STATUS,RP0		; ◆ RP=1
	BSF	SSPCON2,RSEN
	GOTO	i2csspif

i2cstop					; ストップコンディション送信
	BCF	STATUS,RP0		; ◆ RP=0		
	BCF	PIR1,SSPIF		; SSPIFリセット
	BSF	STATUS,RP0		; ◆ RP=1
	BSF	SSPCON2,PEN
	GOTO	i2csspif

i2cack					; アクノリッジビット送信
	BCF	STATUS,RP0		; ◆ RP=0		
	BCF	PIR1,SSPIF		; SSPIFリセット
	BSF	STATUS,RP0		; ◆ RP=1
	BSF	SSPCON2,ACKEN
	GOTO	i2csspif

i2caddr					; EEPROMアドレス送信
	CALL	i2cstart
	BCF	PIR1,SSPIF		; SSPIFリセット
	MOVLW	B'10100000'		; EEPROMデバイスアドレス
	MOVWF	SSPBUF
	CALL	i2csspif		; 送信待ち
	BSF	STATUS,RP0		; ◆ RP=1
	BTFSS	SSPCON2,ACKSTAT
	GOTO	I2CADDR1		; EEPROMが反応した
	CALL	i2cstop			; 反応しない(=書き込み中)は再送信 ◆ RP=0
	GOTO	i2caddr
I2CADDR1
	BCF	STATUS,RP0		; ◆ RP=0
	BCF	PIR1,SSPIF		; SSPIFリセット
	MOVF	I2CADRH,W		; 上位アドレス送信
	MOVWF	SSPBUF
	CALL	i2csspif		; アドレス書き込み時にACK検査をクリアしているので検査省略

	BCF	PIR1,SSPIF		; SSPIFリセット
	MOVF	I2CADRL,W		; 下位アドレス送信
	MOVWF	SSPBUF
	CALL	i2csspif
	RETURN

i2cread					; EEPROMからデータの読み出し
	CALL	i2caddr
	CALL	i2crestart		; データ方向切り替えのため再スタート
	BCF	PIR1,SSPIF		; SSPIFリセット
	MOVLW	B'10100001'		; 読みこみモードへ突入
	MOVWF	SSPBUF
	CALL	i2csspif
	BSF	STATUS,RP0		; ◆ RP=1
	BSF	SSPCON2,RCEN		; 読みこみ開始
I2CREADPOLL
	BTFSS	SSPSTAT,BF		; 読み込み中?
	GOTO	I2CREADPOLL
	BCF	STATUS,RP0		; ◆ RP=0
	MOVF	SSPBUF,W		; データをI2CDATAへ入れる
	MOVWF	I2CDATA
	CALL	i2cstop
	RETURN

i2cwrite				; EEPROMにデータの書き込み
	CALL	i2caddr
	BCF	PIR1,SSPIF		; SSPIFリセット
	MOVF	I2CDATA,W
	MOVWF	SSPBUF
	CALL	i2csspif
	CALL	i2cstop
	RETURN

i2cpread				; EEPROM 64バイトページ読み込み
	CALL	i2caddr
	CALL	i2crestart		; データ方向切り替えのため再スタート
	BCF	PIR1,SSPIF		; SSPIFリセット
	MOVLW	B'10100001'		; 読みこみモードへ突入
	MOVWF	SSPBUF
	CALL	i2csspif

	MOVF	DATAPTR,W		; データの格納先
	MOVWF	FSR
	MOVF	DATASIZE,W		; 取得サイズ
	MOVWF	TMP07
I2CPREADLOOP
	BSF	STATUS,RP0		; ◆ RP=1
	BSF	SSPCON2,RCEN		; 読みこみ開始
I2CPREADPOLL
	BTFSS	SSPSTAT,BF		; 読み込み中?
	GOTO	I2CPREADPOLL
	BCF	STATUS,RP0		; ◆ RP=0
	MOVF	SSPBUF,W		; データをデータバッファへ間接入力
	MOVWF	INDF

	INCF	FSR,F

	MOVLW	0x80			; ポインタが0x80になったら次のデータバッファのポインタへ飛ばす
	SUBWF	FSR,W
	MOVLW	IRDATA2
	BTFSC	STATUS,Z
	MOVWF	FSR

	DECF	TMP07,F
	BTFSC	STATUS,Z		; 64回ループしたら(Z=0)
	GOTO	I2CPREADEND		; リターン
	CALL	i2cack
	GOTO	I2CPREADLOOP
I2CPREADEND
	CALL	i2cstop
	RETURN

i2cpwrite				; EEPROM 64バイトページ書き込み
	CALL	i2caddr

	MOVF	DATAPTR,W		; データの読み出し位置
	MOVWF	FSR
	MOVF	DATASIZE,W		; 書き込みサイズ
	MOVWF	TMP07
I2CPWRITELOOP
	BCF	PIR1,SSPIF		; SSPIFリセット
	MOVF	INDF,W
	MOVWF	SSPBUF
	CALL	i2csspif

	INCF	FSR,F
	MOVLW	0x80			; ポインタが0x80になったら次のデータバッファのポインタへ飛ばす
	SUBWF	FSR,W
	MOVLW	IRDATA2
	BTFSC	STATUS,Z
	MOVWF	FSR
	DECFSZ	TMP07,F
	GOTO	I2CPWRITELOOP

	CALL	i2cstop
	RETURN

;------------------------------------------------------------------------------
; 掛け算 8bit * 8bit = 16bit
;	http://elm-chan.org/docs/avrlib/mul08.txt
; 引数		
;	MUL1		掛けられる数
; 	MUL3		掛ける数
;
; 戻り値
;	MUL2 		積上位
;	MUL1		積下位
;
; 使用変数
;	TMP07		ループカウンタ
;------------------------------------------------------------------------------
mul8
	CLRF	MUL2			; sub	var11,var11
	BCF	STATUS,C
	MOVLW	9			; ldi	lc,9
	MOVWF	TMP07
MUL8LOOP
	BTFSS	STATUS,C		; brcc	PC+2
	GOTO	MUL8LOOP2
	MOVF	MUL3,W			; add	var11,var20
	ADDWF	MUL2,F
MUL8LOOP2
	RRF	MUL2,F			; ror	var11
	RRF	MUL1,F			; ror	var10
	DECFSZ	TMP07,F			; dec	lc
	GOTO	MUL8LOOP		; brne	PC-5
	RETURN				; ret

;------------------------------------------------------------------------------
; 割り算 8bit / 8bit = 商8bit + 剰余8bit
;	http://elm-chan.org/docs/avrlib/div08.txt
; 引数		
;	DIV1		割られる数(破壊)
; 	DIV2		割る数(非破壊)
;
; 戻り値
;	DIV1		商  -> 10の桁として使う
;	MODULO 		剰余-> 1の桁として使う
;
; 使用変数
;	TMP07		ループカウンタ
;------------------------------------------------------------------------------
div8
	CLRF	MODULO			; clr	mod
	MOVLW	8			; ldi	tmp07,8
	MOVWF	TMP07
DIV8LOOP
	BCF	STATUS,C		; lsl	div1
	RLF	DIV1,F
	RLF	MODULO,F		; rol	modulo
	MOVF	DIV2,W			; cp	modulo,div2
	SUBWF	MODULO,W
	BTFSS	STATUS,C		; brcs	DIV8NEXTLOOP
	GOTO	DIV8NEXTLOOP
	INCF	DIV1,F			; inc	div1
	MOVF	DIV2,W			; sub	modulo,div2
	SUBWF	MODULO,F
DIV8NEXTLOOP
	DECFSZ	TMP07,F			; dec	tmp07
	GOTO	DIV8LOOP		; brne	PC-7
	RETURN				; ret

;------------------------------------------------------------------------------
; ウエイトルーチン
;  TMP06〜07を使う
;------------------------------------------------------------------------------
wait_100ms
	MOVLW	10
	MOVWF	TMP05
wait_100ms_1
	MOVLW	100
	CALL	wait
	DECFSZ	TMP05,F
	GOTO	wait_100ms_1
	RETURN

wait					; 100usウエイト@1MHz
	MOVWF	TMP06			; Wにループ回数をセット後CALL
wait1
	MOVLW	31
	MOVWF	TMP07
wait2
	DECFSZ	TMP07,F
	GOTO	wait2
	DECFSZ	TMP06,F
	GOTO	wait1
	RETURN

;------------------------------------------------------------------------------
; LED表示用 メッセージ文字列
;  STRINGに文字列番号を入れてgetstrを呼ぶと、この表の文字列がCHAR_10H〜CHAR_1Mに入る
;------------------------------------------------------------------------------
STRSTART	ORG	0x07A0
					; 文字列番号
	DW	'A','L',':',':'		; 0 AL
	DW	'A','S',':',':'		; 1 AS
	DW	'I','R',':',':'		; 2 IR
	DW	'C','S',':',':'		; 3 CS
	DW	'E','E',':',':'		; 4 EE

	DW	'A'+0x80,'O','F','F'	; 5 A.OFF
	DW	'A'+0x80,'O','N',':'	; 6 A.On

	DW	'E'+0x80,'C','L','R'	; 7 E.CLr
	DW	':','O','F','F'		; 8  OFF

;------------------------------------------------------------------------------
; LED表示用 文字パターン取得
;  WにASCIIコードを入れて呼ぶとWにパターンが入って戻る
;  Wが0x80以上の場合は、DPを付けたパターンを返す
;
;  TMP07を使う
;------------------------------------------------------------------------------
get_pattern
	MOVWF	TMP07
	BCF	FLAG,DPSET
	BTFSC	TMP07,7
	BSF	FLAG,DPSET
	MOVLW	0x7F
	ANDWF	TMP07,F
	CALL	PATTERN_TABLE
	BTFSC	FLAG,DPSET
	IORLW	B'00001000'
	RETURN
PATTERN_TABLE
	MOVLW	HIGH $
	MOVWF	PCLATH		; ■ PCLATH
	MOVLW	0x30
	SUBWF	TMP07,W
	ADDWF	PCL,F
;		 aaa
;		f   b
;		 ggg
;		e   c
;		 ddd  .
;
;		B'abec.fdg'
	RETLW	B'11110110'	; 0
	RETLW	B'01010000'	; 1
	RETLW	B'11100011'	; 2
	RETLW	B'11010011'	; 3
	RETLW	B'01010101'	; 4
	RETLW	B'10010111'	; 5
	RETLW	B'10110111'	; 6
	RETLW	B'11010100'	; 7
	RETLW	B'11110111'	; 8
	RETLW	B'11010111'	; 9
	RETLW	0          	; : => ' '
	RETLW	B'00000001'	; ; => -
	RETLW	B'00000010'	; < => _
	RETLW	B'00000011'	; =
	RETLW	0          	; >
	RETLW	0          	; ?
	RETLW	0          	; @
	RETLW	B'11110101'	; A
	RETLW	B'00110111'	; b
	RETLW	B'10100110'	; C
	RETLW	B'01110011'	; d
	RETLW	B'10100111'	; E
	RETLW	B'10100101'	; F
	RETLW	B'10110110'	; G
	RETLW	B'01110101'	; H
	RETLW	B'01010000'	; I
	RETLW	B'01110010'	; J
	RETLW	0          	; K
	RETLW	B'00100110'	; L
	RETLW	0          	; M
	RETLW	B'00110001'	; n
	RETLW	B'11110110'	; O
	RETLW	B'11100101'	; P
	RETLW	0          	; Q
	RETLW	B'00100001'	; r
	RETLW	B'10010111'	; S
	RETLW	B'00100111'	; t
	RETLW	B'01110110'	; U
	RETLW	0          	; V
	RETLW	0          	; W
	RETLW	0          	; X
	RETLW	B'01010111'	; y
	RETLW	0          	; Z

;------------------------------------------------------------------------------
; EEPROMデータ
;------------------------------------------------------------------------------
	ORG	0x2100
	DE	0,0,0,0,0,0,0,0,0,0
	DE	0,0,0,0,0,0,0,0,0,0
	DE	0,0,0,0,0,0,0,0,0,0
	DE	0,0,0,0,0,0,0,0,0,0
	DE	0,0,0,0,0,0,0,0,0,0
	DE	0,0,0,0,0,0,0,0,0,0
	DE	0,0,0,0,0,0,0,0,0,0
	DE	0,0,0,0,0,0,0,0,0,0
	DE	0,0,0,0,0,0,0,0,0,0
	DE	0,0,0,0,0,0,0,0,0,0

	ORG	0x2100+EE_ALARM_ALLON
	DE	0x01

	END