;	list p=PIC16F628
#include <P16F628.INC>
;
; Mouse Tester ver 1.00
; (c) 2003 Sugihara Toshio.
; All rights reserved.

; PIC16F628
; Clock=4MHz 1Morder/s
; WDT=off
; PowerUpTimer=on
; Protect=off
; Oscllator=XT
; BrownOutDetect=on
; Low Voltage Program=off

; Memory for all banks
wtimer	equ	H'70'	;Dummy use 1 Wait timer and so on
dcount	equ	H'71'	;Dummy use 2 Wait timer and so on
sendbuf	equ	H'72'	;Sending buffer for PS/2.
bcount	equ	H'73'	;Bit counter

; Memory for bank 0
hexbuf	equ	H'20'	;Hex buf to send(1)
hexbuf2	equ	H'21'	;Hex buf to send(2)
moji		equ	H'22'	;Character to send
	;Mouse status data
x0		equ	H'23'	;Lower  X value
x1		equ	H'24'	;Higher X value
y0		equ	H'25'
y1		equ	H'26'
z0		equ	H'27'
z1		equ	H'28'
mdev		equ	H'29'	;Mouse device ID
btn		equ	H'2a'	;76543210
					;xxx54CRL
	;Mouse packet values
signs	equ	H'2b'
movx		equ	H'2c'
movy		equ	H'2d'
movz		equ	H'2e'
btn45	equ	H'2f'	;Only for button 4 and 5
					;Value is B'xxx54xxx'
	;For read verify
readc	equ	H'30'
	;Loop Count
lpa		equ	H'31'
	;Operation mode
modemk	equ	H'32'	;0=Mouse 1=Key
modemd	equ	H'33'	;マウスの場合で　N,L,R,C,4,5,X,Y,Z　の各文字を持つ
	;Key Repeat
keyrep	equ	H'34'

; Program starts from 0
; I/O setup
	org H'0'
	clrf INTCON	  ;Disable all interruption
	clrf STATUS	  ;Select bank 0
	movlw B'00111000' ;Choose bank 1
	movwf STATUS
	movlw B'00000111' ;TMR0 overflows 15.26Hz (1/256)
	movwf OPTION_REG	 ;Pull Up is on.
	bcf STATUS,RP0	;choose bank 0
	;モードを初期化（マウス、ノーマルとする）
	clrf modemk
	clrf modemd
	clrf keyrep		;Key Repeatのクリア
	
	;Mouse/Keyモードの入り口
mainloop
	call resetio		;Reset and LED=BLUE
	call initlcd		;Reset LCD
	;バージョン番号を表示 = 00
	movlw H'd4'
	call putrs0
	movlw A'0'
	call putrs1
	movlw A'1'
	call putrs1

	btfsc modemk,0	;If keymode,
	goto keymode		;then goto keymode.
					;Else, mousemode.
	;Mouseモード
	;マウスモードあることを表示(４行４桁から）
	movlw H'd7'
	call putrs0
	movlw A'M'
	call putrs1
	;マウスの初期化
	call resetmvalue		;マウスの状態量を初期化

	movlw H'94'	;debug LCDLine=3
	call putrs0	;debug

	;Wait for 256ms x 4
	movlw H'00'
	call wait1ms
	call wait1ms
	call wait1ms
	call wait1ms

	;Reset mouse for 3 times.
	movlw D'3'
	movwf lpa
resetmouse
	;Reset Mouse
	movlw H'ff'	;Send 0xff [RESET]
	call senddevrack
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror

	movlw A'R'	;debug send Reset and receive ack done.
	call putrs1	;debug

	;Wait for 256ms x 4
	;この間に H'aa'と H'00'を受けるとの説がある。
	movlw H'00'
	call wait1ms
	call wait1ms
	call wait1ms
	call wait1ms
	
	decfsz lpa,F
	goto resetmouse

	;Check Mouse ID
	movlw H'f2'
	call senddevrack
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror

	movlw H'00'
	call readdevthis	;Mouse device ID must be 0x00
	btfsc dcount,7
	goto ioerror
	clrf mdev		;Set ID as normal mouse now.

	;Check Mouse Device if it is 0x03
	movlw H'f3'
	call senddevrack
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror
	movlw H'c8'
	call senddevrack
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror

	movlw H'f3'
	call senddevrack
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror
	movlw H'64'
	call senddevrack
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror

	movlw H'f3'
	call senddevrack
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror
	movlw H'50'
	call senddevrack
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror

	;Read Mouse ID
	movlw H'f2'
	call senddevrack
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror

	call readdev
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror

	movf sendbuf,W	;Set value to W.
	xorlw H'03'
	btfss STATUS,Z	;ID==H'03'?
	goto chkms04		;No. Try next type.
					;Yes.
	movlw H'03'		
	movwf mdev		;device ID=H'03'

chkms04
	;Check Mouse Device if it is 0x04
	movlw H'f3'
	call senddevrack
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror
	movlw H'c8'
	call senddevrack
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror

	movlw H'f3'
	call senddevrack
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror
	movlw H'c8'
	call senddevrack
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror

	movlw H'f3'
	call senddevrack
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror
	movlw H'50'
	call senddevrack
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror

	;Read Mouse ID
	movlw H'f2'
	call senddevrack
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror

	call readdev
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror
	
	movf sendbuf,W	;Set value to W.
	xorlw H'04'
	btfss STATUS,Z	;ID==H'04'?
	goto chkmsdone	;No.
					;Yes.
	movlw H'04'		
	movwf mdev		;device ID=H'04'

chkmsdone
	movlw A'D'	;debug iD check done.
	call putrs1	;debug
	
	;Set Sample rate as default(=100)
	movlw H'f3'
	call senddevrack
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror
	movlw H'64'
	call senddevrack
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror

	;Set Remote mode
	movlw H'f0'	;Send 0xf0 [Set Remote Mode]
	call senddevrack
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror

	movlw A'M'	;debug reMote mode done. 
	call putrs1	;debug

;モードを変更した場合の入り口
mousemodechange
	;画面の枠を書く
	movlw H'80'	;Line1
	call putrs0	
	movlw A'X'
	call putrs1
	movlw A'='
	call putrs1
	movlw H'87'
	call putrs0	
	movlw A'Y'
	call putrs1
	movlw A'='
	call putrs1
	movlw H'8e'
	call putrs0	
	movlw A'Z'
	call putrs1
	movlw A'='
	call putrs1
	movlw H'ce'	;Line2
	call putrs0	
	movlw A'D'
	call putrs1
	movlw A'='
	call putrs1
	movf mdev,W
	call puthex
	;モード名を表示
	movlw H'd7'	;4行4列
	call putrs0	
	movlw A'M'
	call putrs1
	movlw A':'
	call putrs1
	call getmmodename
	call putrs1	

readmouse
	;Read motion from mouse.
	;Send [read data]
	movlw H'eb'
	call senddevrack
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror

	;Read 1st value[signs]
	call readdev
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror
	movf sendbuf,W
	movwf signs

	;Read 2nd value[movx]
	call readdev
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror
	movf sendbuf,W
	movwf movx

	;Read 3rd value[movy]
	call readdev
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror
	movf sendbuf,W
	movwf movy

	;Read 4th value if needed.
	clrf movz
	clrf btn45
	movlw H'03'
	xorwf mdev,W
	btfsc STATUS,Z	;If mouse is 0x03?
	goto readmP2		;Yes.
					;No.
	movlw H'04'
	xorwf mdev,W
	btfss STATUS,Z	;If mouse is 0x04?
	goto readmP0		;No. Normal mouse.
					;Yes.
readmP2
	;Mouse is 0x03 or 0x04.
	;Read 4th data.
	call readdev
	iorlw H'00'
	btfss STATUS,Z
	goto ioerror
	movf sendbuf,W
	movwf movz

	movf modemd,F
	btfss STATUS,Z		;If mode==0?
	goto showmxyzafter		;No. Not show.
						;Yes.
	;(debug) Show Read values
	movlw H'a0'	;debug
	call putrs0	;Line 3, 12
	movf signs,W
	call puthex
	movf movx,W
	call puthex
	movf movy,W
	call puthex
	movf movz,W
	call puthex	;Read value is directly displayed.
showmxyzafter	
	;If mouse is 0x04, button 45 exist.
	btfss mdev,2	;If mouse is 0x04?
	goto readmP3	;No. Read done.
				;Yes.
	;Set button 4,5
	btfsc movz,4	;set button 4
	bsf btn45,3
	btfsc movz,5	;set button 5
	bsf btn45,4
	;Adjust Values of movz as 0x03 mouse
	movlw B'00001111'
	andwf movz,F
	movlw B'11110000'
	btfsc movz,3		;bit3を符号ビットとみなして
	iorwf movz,F		;符号ビットをbit7まで延長する。
	goto readmP3
	
readmP0
	;Normal mouse
	movf modemd,F
	btfss STATUS,Z	;If modemd==0?
	goto readmP3		;No. Not show.
					;Yes.
	;(debug) Show Read values
	movlw H'a0'	;debug
	call putrs0	;Line 3, 12
	movf signs,W
	call puthex
	movf movx,W
	call puthex
	movf movy,W
	call puthex
	movlw A' '
	call putrs1
	movlw A' '
	call putrs1
readmP3
	;Mouse read done. Then evaluate these values.
	;Update mouse status values
	;Set button LRC. (4,5 are set as 0)
	movf signs,W
	andlw B'00000111'
	movwf btn
	
	btfss signs,6
	goto novfx
ovfx
	;X is overflowed
	incf x1,F
	movlw D'2'
	btfsc signs,4
	subwf x1,F
	goto chkovy
novfx
	;X is not overflowed
	btfsc signs,4
	decf x1,F
	movf movx,W
	addwf x0,F
	btfsc STATUS,C
	incf x1,F
chkovy
	btfss signs,7
	goto novfy
ovfy
	;Y is overflowed.
	incf y1,F
	movlw D'2'
	btfsc signs,5
	subwf y1,F
	goto chksgz
novfy
	;Y is not overflowed.
	btfsc signs,5
	decf y1,F
	movf movy,W
	addwf y0,F
	btfsc STATUS,C
	incf y1,F
chksgz
	;Change Z value
	btfsc movz,7
	decf z1,F
	movf movz,W
	addwf z0,F
	btfsc STATUS,C
	incf z1,F
	;Set button 4,5
	movf btn45,W
	iorwf btn,F
	;Mouse status change END.

	;Control LCD and LED
	;according to the operating mode.
	clrf dcount	;bit0 is for LED. 1=BLUE/0=RED
	movf modemd,W
	btfsc STATUS,Z		;modemd==0?
	goto displaynormal	;Yes.
						;No.
	sublw D'5'	;5 - modemd
	btfss STATUS,C	;modemd>5?
	goto mmodeact6	;Yes.
					;No. mode(1..5).
	;LRC45 mode.
	;Shift bits to make wtimer[Bit of (modemd-1)]=1
	movf modemd,W
	movwf bcount
	clrf wtimer
	bsf wtimer,0
mmodeB2	
	decf bcount,F
	btfsc STATUS,Z
	goto mmodeB3
	bcf STATUS,C
	rlf wtimer,F
	goto mmodeB2	
mmodeB3
	movf wtimer,W
	andwf btn,W
	btfsc STATUS,Z	;Btn pressed?
	bsf dcount,0		;No. BLUE.
					;Yes. RED
	goto mmodeactLED
mmodeact6
	;modemd>5
	;XYZmode
	movlw D'5'
	subwf modemd,W
	movwf bcount	;bcount = modemd - 5;
	decfsz bcount,F	;modemd==6?
	goto mmodeact7	;No.
					;Yes.
	;X axis mode
	movf movx,F
	btfss STATUS,Z	;movx is 0?
	goto mmodeactLED	;No. Moved.
					;Yes.
	movf signs,W
	andlw B'01010000'
	btfsc STATUS,Z	;signs for X is 0?
	bsf dcount,0		;Yes. X is not moving = BLUE
					;No. Moved.
	goto mmodeactLED
mmodeact7
	decfsz bcount,F	;modemd==7?
	goto modeact8	;No.
					;Yes.
	;Y axis mode
	movf movy,F
	btfss STATUS,Z	;movy==0?
	goto mmodeactLED	;No, moved.
					;Yes.
	movf signs,W
	andlw B'10100000'
	btfsc STATUS,Z	;signs of Y flags are all 0?
	bsf dcount,0		;Yes. Not moved = BLUE
					;No, moved.
	goto mmodeactLED
modeact8
	;modemd>= 8
	;This means mode is 8 and
	;Z axis mode.
	movf movz,F
	btfsc STATUS,Z	;movz==0?
	bsf dcount,0		;Yes. Not moved = BLUE
					;No, moved.
mmodeactLED
	btfss dcount,0
	goto mmodeactLED2;0 for RED
	bsf PORTB,7		;1 for BLUE
	goto mbtnwait
mmodeactLED2		
	bcf PORTB,7	;RED
	goto mbtnwait

;Display current x,y,z and button.
displaynormal		
	;X
	movlw H'82'
	call putrs0
	movf x1,W
	call puthex
	movf x0,W
	call puthex
	;Y
	movlw H'89'
	call putrs0
	movf y1,W
	call puthex
	movf y0,W
	call puthex
	;Z
	movlw H'90'
	call putrs0
	movf z1,W
	call puthex
	movf z0,W
	call puthex
	;Button
	movlw H'c0'
	call putrs0
	;Left
	movlw A'L'
	btfss btn,0
	movlw A' '
	call putrs1
	;Middle
	movlw A'C'
	btfss btn,2
	movlw A' '
	call putrs1
	;Right
	movlw A'R'
	btfss btn,1
	movlw A' '
	call putrs1
	;4
	movlw A'4'
	btfss btn,3
	movlw A' '
	call putrs1
	;5
	movlw A'5'
	btfss btn,4
	movlw A' '
	call putrs1

;Wait for button 
mbtnwait
	btfss PORTB,6	;Red(Replug) pushed?
	goto mainloop	;Yes. Return to mainloop
					;No.
	btfss PORTB,4	;Blue(M/K) pushed?
	goto mtokey		;Yes.
					;No.
	btfss PORTB,5	;Yellow(Mode change) pushed?
	goto myellow		;Yes.
	clrf keyrep		;No. Clear key repeat value.
	goto readmouse	;Do next read from the mouse. 
					;Yes.
	;Change mode in the mouse mode.
myellow
	incf keyrep,F
	decf keyrep,W
	btfsc STATUS,Z	;keyrep is 1?
	goto myinc		;Yes.
					;No.
	btfss keyrep,6	;keyrep >= 64?
	goto readmouse	;No. Read mouse again.
					;Yes.
	movf D'4'
	subwf keyrep,F
	;モードの更新
myinc	
	incf modemd,F
	movf modemd,W
	sublw D'8'		;8 - modemd
	btfss STATUS,C	;Is modemd>8 ?
	clrf modemd		;Yes.
					;No.
	call initlcd
	bsf PORTB,7	;LED = BLUE
	goto mousemodechange

;Change mode from mouse to key.
mtokey
	movlw D'1'
	movwf modemk	;Set Key mode.
	clrf modemd	;Set Normal mode.
	goto mainloop

;show I/O error in Mouse mode.
;Value in W register is displayed as Error NO.
ioerror
	bcf PORTB,7	;LED = RED
	call puterr	;Show ERROR NUM in W REG.
ioerror2
	btfss PORTB,6	;Red pushed?
	goto mainloop	;Yes. Return to mainloop
					;No.
	btfss PORTB,4	;Blue(M/K) pushed?
	goto mtokey		;Yes. Change to the Key mode.
	goto ioerror2	;No. Go back to the loop.


;Wait for LCD's operation done
;or wait for 64us.
;This routine assumes that ports
;for D4:D7 are inputs when calling.
lcdwait
	movlw D'4'	;Try up to 4 times
	movwf wtimer
lcdwait2
	clrf PORTA
	bsf PORTA,2	;R/W = Read
	bsf PORTA,1	;E = 1
	nop
	movf PORTB,W
	movwf dcount
	bcf PORTA,1	;E = 0
	nop
	bsf PORTA,1	;E = 1
	nop
	bcf PORTA,1	;E = 0
	clrf PORTA
	btfss dcount,7	;Is it busy?
	return			;No. busy is done			
					;Yes.
	decfsz wtimer,F	;Checked 4 times?
	goto lcdwait2	;No. try again.
	return			;Yes. Check is done.

	;Data is in W reg.
	;Send it to LCD as RS=0
putrs0
	movwf moji
	call lcdwait
	goto putrs02

	;Data is in W reg.
	;Send it to LCD as RS=1
putrs1
	movwf moji
	call lcdwait
	bsf PORTA,0
putrs02
	;From now send 1 byte to LCD
	bsf STATUS,RP0	;choose bank 1
	movlw B'01110000'
	movwf TRISB		;B3:B0 are output
	bcf STATUS,RP0	;choose bank 0
	;send upper 4bits
	swapf moji,W
	andlw B'00001111'
	btfsc PORTB,7
	iorlw B'10000000'
	movwf PORTB
	bsf PORTA,1	;E=1
	nop
	bcf PORTA,1	;E=0
	;send lower 4 bits
	movf moji,W
	andlw B'00001111'
	btfsc PORTB,7
	iorlw B'10000000'
	movwf PORTB
	bsf PORTA,1	;E=1
	nop
	bcf PORTA,1	;E=0
	;Set B3:B0 as input.
	bsf STATUS,RP0	;choose bank 1
	movlw B'01111111'
	movwf TRISB		;B7 is only output.
	bcf STATUS,RP0	;choose bank 0
	return	
	
	;Init LCD.
initlcd
	movlw D'200'		;Wait for about 20ms
	call wait100us
	clrf PORTA
	bsf STATUS,RP0	;choose bank 1
	movlw B'01110000'
	movwf TRISB		;B3:B0 are output
	bcf STATUS,RP0	;choose bank 0
	;send 1st line.
	movlw B'00000011'
	btfsc PORTB,7
	iorlw B'10000000'
	movwf PORTB
	bsf PORTA,1	;E=1
	nop
	bcf PORTA,1	;E=0
	;wait for 5.0ms
	movlw D'50'
	call wait100us
	;send 2nd line.
	bsf PORTA,1	;E=1
	nop
	bcf PORTA,1	;E=0
	;wait for about 100us
	movlw D'1'
	call wait100us
	;send 3rd line.
	bsf PORTA,1	;E=1
	nop
	bcf PORTA,1	;E=0
	;wait for about 100us
	movlw D'1'
	call wait100us
	;send 4th line
	bcf PORTB,0
	bsf PORTA,1	;E=1
	nop
	bcf PORTA,1	;E=0
	;wait for about 100us
	movlw D'1'
	call wait100us
	;Set B3:B0 as input.
	bsf STATUS,RP0	;choose bank 1
	movlw B'01111111'
	movwf TRISB		;B7 is only output.
	bcf STATUS,RP0	;choose bank 0
	;Function set
	movlw b'00101000'
	call putrs0
	movlw b'00001000'
	call putrs0
	movlw b'00000001'
	call putrs0
	movlw D'100'
	call wait100us
	movlw b'00000110'
	call putrs0
	movlw b'00001100'
	call putrs0
	return

;put number as HEX format
;Input is W register
puthex
	movwf hexbuf
	swapf hexbuf,W
	andlw H'0f'
	addlw A'0'	;Higher 4 bits as ASCII char
	movwf hexbuf2
	sublw A'9'
	btfsc STATUS,0
	goto puthexp1	;value <= '9'
					;value > '9'
	movlw D'39'
	addwf hexbuf2,F
puthexp1	
	movf hexbuf2,W
	call putrs1

	movf hexbuf,W
	andlw H'0f'
	addlw A'0'
	movwf hexbuf2
	sublw A'9'
	btfsc STATUS,0	;value > A'9'?
	goto puthexp2	;No.
	movlw D'39'		;Yes. So it must be from a to f.
	addwf hexbuf2,F
puthexp2
	movf hexbuf2,W
	call putrs1
	return

;Show error number
;error number is in W register.
;error number is displayed in HEX format.
;error number 0 makes error disappear.
puterr
	movwf hexbuf
	movlw H'dc'	;４行め８列へ移動
	call putrs0
	movf hexbuf,F
	btfsc STATUS,Z	;err number is 0 ? 
	goto puterr2		;Yes.
					;No.
	movlw A'E'
	call putrs1
	movlw A'R'
	call putrs1
	movlw A'R'
	call putrs1
	movlw A'O'
	call putrs1
	movlw A'R'
	call putrs1
	movf hexbuf,W
	goto puthex
puterr2
	;Show space 7 times
	movlw D'7'
	movwf hexbuf
puterr3
	movlw A' '
	call putrs1
	decfsz hexbuf,F
	goto puterr3
	return

	;Send 1 byte data for PS/2 device.
	;Writing data is in W register when calling.
	;1st, pull down CL for about 100us,
	;then make send mode, and send a byte.
	;If error occurs, return error in W reg.
	;If no error occurs, return 0 in W reg.
	;Error is
	;0x81 Unable to get clock for 20ms.
	;0x82 Clock stops while sending.
	;0x83 ACK error.
senddev
	movwf sendbuf

	;Wait for 200us
	movlw D'2'
	call wait100us

	clrf PORTA
	bsf STATUS,RP0	;choose bank 1
	bsf TRISA,3		;Release DA.
	bcf TRISA,4		;Pull down CL.
	;Wait for 200us
	movlw D'2'
	call wait100us
	bcf TRISA,3		;DA Down
	goto senddev2	;Wait for 3us
senddev2
	nop
	bsf TRISA,4		;CL Up
	;Wait for Clock down (MAX=20ms)
	bcf STATUS,RP0	;choose bank 0
	movlw D'16'
	movwf wtimer
	clrf dcount
senddev3
	btfss PORTA,4	;CL is down?
	goto senddev4	;Yes. 
					;No.
	decfsz dcount,F	
	goto senddev3	;Try again.
	decfsz wtimer,F
	goto senddev3
	call devrelease
	retlw H'81'		;Done 20ms
					;but clock did not appear.
	;Clock appears.
senddev4
	clrf dcount	;Parity counter
	clrf wtimer	;Wait timer
	movlw D'8'
	movwf bcount	;Count how many bits should be sent.
	;Clock is LO and send a bit.
senddev5
	;Set a DATA bit to send.
	bsf STATUS,RP0	;choose bank 1
	btfss sendbuf,0	;bit is 1?
	goto senddev6	;No.  It's 0.
					;Yes. It's 1.
	bsf TRISA,3	;Set as 1
	incf dcount,F;Increment parity counter.
	goto senddev7
senddev6
				;It's 0.
	bcf TRISA,3	;Set as 0
senddev7
	;Wait for clock Up and Down
	bcf STATUS,RP0	;choose bank 0
	clrf PORTA
	;Wait for UP
	movlw D'12'
	movwf wtimer
senddev8
	btfsc PORTA,4	
	goto senddev9
	decfsz wtimer,F
	goto senddev8
	call devrelease
	retlw H'82'
	
senddev9
	;Wait for DOWN
	movlw D'12'
	movwf wtimer
senddev10
	btfss PORTA,4
	goto senddev11
	decfsz wtimer,F
	goto senddev10
	call devrelease
	retlw H'82'
senddev11
	rrf sendbuf,F
	decfsz bcount,F
	goto senddev5
	;8 bits were sent or parity was sent or stop bit was sent.
	btfsc dcount,6	;Was stop bit sent?
	goto senddev13	;Yes.
					;No.

	btfsc dcount,7	;Was parity sent?
	goto senddev12	;Yes.
					;No.
	;Set parity
	bcf sendbuf,0
	btfss dcount,0
	bsf sendbuf,0
	incf bcount,F
	bsf dcount,7	;Parity is sent.
	goto senddev5
senddev12
	;Parity was sent.
	;Send stop bit.
	bsf sendbuf,0
	incf bcount,F
	bsf dcount,6	;Stop bit is sent.	
	goto senddev5
	
senddev13
	;Stop bit was sent.
	;Check ACK
	call devrelease
	btfsc PORTA,3
	retlw H'83'	;ACK ERROR
	;Wait for clock up.
	movlw D'12'
	movwf wtimer
senddev14
	btfsc PORTA,4
	goto senddev15
	decfsz wtimer,F
	goto senddev14
	retlw H'82'
senddev15
	;All done.
	retlw H'00'	;Done perfectly.


;Send value to the device and receive
;ACK(H'fa').
;If succeed, W register becomes H'00'
;If error occured, ErrorNo is in W reg.
;W=H'ff': Return value is not ACK
;W=other (not 0): I/O error NO. 
senddevrack
	;1st, Send data to the device.
	call senddev
	iorlw H'00'
	btfss STATUS,Z
	return			;If error occurs, return.
	;2nd, Read ACK from mouse device.
	call readdev
	iorlw H'00'
	btfss STATUS,Z
	return			;If error occurs, return.
	movf sendbuf,W
	xorlw H'fa'
	btfss STATUS,Z
	retlw H'ff'		;Return value is not ACK.
	retlw H'00'		;No error.
	
;read 1 byte from the device.
;Data comes from sendbuf
;If no error occurs, return 0 in W reg..
;If error occurs, Error NO is in W reg.
;0x91 Unable to get clock for 20 ms.
;0x92 Clock stops while reading.
;0x93 Parity error.
;0x94 Start/Stop bit error

readdev
	clrf PORTA
	call devrelease
	;Wait for clock down aboud 20ms
	movlw D'16'
	movwf dcount	;Wait timer 2nd level
	clrf wtimer	;Wait timer(set as 256)
readdev2
	btfss PORTA,4	;Is clock down?
	goto readdev3	;Yes.
					;No.
	decfsz wtimer,F
	goto readdev2
	decfsz dcount,F
	goto readdev2
	;Clock not found.
	retlw H'91'
readdev3
	;Read start bit.
	btfsc PORTA,3
	retlw H'94'	;Start bit error
	clrf dcount	;reset parity counter
	clrf bcount	;reset bit counter
	clrf sendbuf
readdevnext
	;Wait for UP
	movlw D'12'
	movwf wtimer
readdev4
	btfsc PORTA,4
	goto readdev5
	decfsz wtimer,F
	goto readdev4
	retlw H'92'	;Clock lost.
readdev5
	;Operation done check.
	movlw D'10'
	subwf bcount,W
	btfsc STATUS,Z	;Is bount==10?
	retlw H'00'		;Yes. Read operation is done.
					;No, read next bit.
	;Wait for down
	movlw D'12'
	movwf wtimer
readdev6
	btfss PORTA,4
	goto readdev7
	decfsz wtimer,F
	goto readdev6
	retlw H'92'	;Clock lost.	
readdev7
	btfsc bcount,3	;If already read >= 8bits
	goto readdev9	;Yes
					;No.
	rrf sendbuf,F
	bcf sendbuf,7
	btfss PORTA,3	;If data is 0?
	goto readdev10	;Yes.
					;No.
	bsf sendbuf,7	;value=1
	incf dcount,F	;increment parity counter
	goto readdev10
readdev9
	;Already read >=8 bits.
	btfsc bcount,0
	goto readdev9b	;stop bit
					;parity bit 	
	btfsc PORTA,3
	incf dcount,F	;add parity bit to parity counter.
	btfss dcount,0	;Is parity OK?
	retlw H'93'		;No. Error!
					;Yes.
	goto readdev10
readdev9b
	;stop bit
	btfss PORTA,3	;Stop bit OK?
	retlw H'94'		;No. Error!
					;Yes.
readdev10
	;Read 1 bit is done.
	incf bcount,F
	goto readdevnext

;Read from device
;and if value is equal to W register,
;return with dcount=0.
;If value is not equal to Wregister,
;return with dcount=0xff
;If error occured,
;return with dcount=0xfe
;Return Wreg is 0x00:Succeed 0xff:Not Equal Other:I/O Error value.
readdevthis
	movwf readc	;Save value to check
	call readdev
	iorlw H'00'
	btfss STATUS,Z
	goto readdevioe	;I/O Error 
	clrf dcount
	movf sendbuf,W
	xorwf readc,W
	btfss STATUS,Z
	goto readdevneq
	retlw H'00'
readdevneq
	decf dcount,F	;Not equal to readc
	retlw H'ff'
readdevioe
	clrf dcount
	decf dcount,F
	decf dcount,F
	return 
	
;Release PS/2 device
devrelease
	bsf STATUS,RP0	;choose bank 1
	movlw B'11111000'
	movwf TRISA
	bcf STATUS,RP0	;choose bank 0
	clrf PORTA
	return

;Reset values of status of mouse
;Mouse packets are not cleared.
resetmvalue
	clrf x0
	clrf x1
	clrf y0
	clrf y1
	clrf z0
	clrf z1
	clrf mdev
	clrf btn
	return

;Reset I/O
;バンク０が選ばれていることを前提とする。
;バンク０が選ばれた状態で戻る。
;BLUE LED becomes ON.
resetio
	clrf PORTA
	movlw B'10000000'
	movwf PORTB		;Initial values are 0
	movlw H'07'
	movwf CMCON	;Comparater is not used.
	bsf STATUS,RP0	;choose bank 1
	movlw B'11111000';A2:A0 are output.
	movwf TRISA
	movlw B'01111111' ;B7 is output.
	movwf TRISB
	clrf VRCON		;Voltage Reference is not used.
	bcf STATUS,RP0	;choose bank 0
	clrf PORTA		;Stop charging
	movlw B'10000000'
	movwf PORTB		;Blue LED becomes ON.
	return
		
	;Wait for about W reg * 100 us
	;Return with W=0
wait100us
	movwf wtimer
wxms3
	movlw D'32'
	movwf dcount
wxms2
	decfsz dcount,F
	goto wxms2

	decfsz wtimer,F
	goto wxms3
	retlw H'00'

wait1ms
	movwf wtimer
w1ms3
	movlw D'200'
	movwf dcount
w1ms2
	goto w1ms4
w1ms4
	decfsz dcount,F
	goto w1ms2
	decfsz wtimer,F
	goto w1ms3	
	retlw H'00'

;;;;;;;;;;;;;;;;;;;;;;;;;;;

	;キーボードを扱う部分。
	;まだ全く実装されていません。
keymode
	;キーモードであることを表示(４行４桁から）
	movlw H'd7'
	call putrs0
	movlw A'K'
	call putrs1
	;実装されていないので赤信号
	bcf PORTB,7
	;1秒強待つ
	movlw H'00'
	call wait1ms
	call wait1ms
	call wait1ms
	call wait1ms
	;青ボタンを待つ
keywaitblue
	btfsc PORTB,4
	goto keywaitblue
	;マウスモード、ノーマルに設定
	clrf modemk
	clrf modemd
	goto mainloop

	org	H'700' ;Address is from 1792 (Final 256bytes)
	
	;Read modename of mouse mode.
	;Selector is in modemd.
	;Return value (name) is in W register.
getmmodename
	movlw B'00000111'
	movwf PCLATH
	movf modemd,W
	andlw B'00001111'		;Limit value from 0 to 15
	addwf PCL,F
	retlw A'N'	;0: Normal
	retlw A'L'	;1: Left button
	retlw A'R'	;2: Right button
	retlw A'C'	;3: Center button
	retlw A'4'	;4: 4th button
	retlw A'5'	;5: 5th button
	retlw A'X'	;6: X axis
	retlw A'Y'	;7: Y axis
	retlw A'Z'	;8: Z axis
	retlw A'?'	;9; (Error)
	retlw A'?'	;a
	retlw A'?'	;b
	retlw A'?'	;c
	retlw A'?'	;d
	retlw A'?'	;e
	retlw A'?'	;f
	end
	
	
