
#define x16F690

#ifdef x16F690
#include <p16F690.inc>
     __config (_INTRC_OSC_NOCLKOUT & _WDT_OFF & _PWRTE_OFF & _MCLRE_OFF & _CP_OFF & _BOR_OFF & _IESO_OFF & _FCMEN_OFF)
#endif


SER_IN			equ	PORTB
SER_IN_BIT		equ	5
RECV_STATUS_ERR	equ	0
LCD_DEVICE_ID	equ	b'00000010'

	cblock 0x20
	; LCD
	LOOKUP_TEMP
	LCD_WAIT_D1
	LCD_WAIT_D2
	; Receiver
	PULSE_UNIT
	PULSE_LEN
	DAT_H
	DAT_L
	COUNTER
	; PAR
	PAR
	PAR_TMP
	PAR_COUNTER
	endc

#ifdef TEST_SUBROUTINES
	cblock
	; Test
	DUMPLO
	DUMPHI
	PULSE0
	PULSE1
	PULSE2
	PULSE3
	PULSE4
	PULSE5
	PULSE6
	PULSE7
	endc
#endif

	org 0x00
	goto	Main
	org 0x04
	goto	Main

Main
	call	Init_PORTS
	call	Init_LCD
	call	LCD_Wait
	call	LCD_Wait
	call	LCD_Wait
	;goto	Test
	;goto	TestReceivePacket
	goto	ReceiveTextStream

#ifdef TEST_SUBROUTINES
Test
	btfsc	SER_IN,SER_IN_BIT
	goto	$-1
	call	GetPulse
	movwf	PULSE0
	call	GetPulse
	movwf	PULSE1
	call	GetPulse
	movwf	PULSE2
	call	GetPulse
	movwf	PULSE3
	call	GetPulse
	movwf	PULSE4
	call	GetPulse
	movwf	PULSE5
	call	GetPulse
	movwf	PULSE6
	call	GetPulse
	movwf	PULSE7
	movf	PULSE0,w
	call	DumpW
	movf	PULSE1,w
	call	DumpW
	movf	PULSE2,w
	call	DumpW
	movf	PULSE3,w
	call	DumpW
	movf	PULSE4,w
	call	DumpW
	movf	PULSE5,w
	call	DumpW
	movf	PULSE6,w
	call	DumpW
	movf	PULSE7,w
	call	DumpW
	sleep
	goto	$-1

TestReceivePacket
	call	ReceivePacket_Prepare
	call	ReceivePacket
	movf	DAT_H,w
	call	DumpW
	movf	DAT_L,w
	call	DumpW
	sleep
	goto	$-1
#endif

ReceiveTextStream
	call	ReceivePacket_Prepare
	call	ReceivePacket
	call	Check_PAR
	btfss	STATUS,Z
	goto	ReceiveTextStream	; invalid packet received
	call	Check_DeviceID
	btfss	STATUS,Z
	goto	ReceiveTextStream	; invalid Device ID
	rrf		DAT_H,w
	bsf		PORTB,7
	btfsc	STATUS,C
	bcf		PORTB,7
	movf	DAT_L,w
	movwf	PORTC
	call	LCD_PulseZ
	goto	ReceiveTextStream

ReceivePacket_Prepare
	clrf	DAT_H
	clrf	DAT_L
	movlw	0x10
	movwf	COUNTER
	return

ReceivePacket
	btfsc	SER_IN,SER_IN_BIT
	goto	$-1
	call	GetPulse
	movwf	PULSE_UNIT
ReceivePacket_0
	call	GetPulse
	subwf	PULSE_UNIT,w
	rlf		DAT_L,f
	rlf		DAT_H,f
	decf	COUNTER,f
	btfss	STATUS,Z
	goto	ReceivePacket_0
	movlw	0xFF
	xorwf	DAT_L,f
	xorwf	DAT_H,f
	return

Init_PORTS
	banksel	PORTC
	clrf	PORTC	;Lower all PORTC outputs
	clrf	PORTB
	banksel	ANSEL
	movlw	b'00000000'
	movwf	ANSEL	;All digital
	movwf	ANSELH	;All digital
	banksel	TRISC
	movlw	b'00000000'
	movwf	TRISC	;Port C - all output
	banksel	TRISB
	movlw	b'00111111'
	movwf	TRISB	;B7 & B6 - outputs
	banksel	PORTC
	return

Init_LCD
	call	LCD_Wait
	movlw	0x00
	movwf	PORTB
	movlw	b'00110000'
	movwf	PORTC
	call	LCD_PulseZ
	call	LCD_PulseZ
	call	LCD_PulseZ
	clrf	COUNTER
Init_LCD_0
	movf	COUNTER,w
	call	Init_LCD_Table
	movwf	PORTC
	call	LCD_PulseZ
	incf	COUNTER,f
	movlw	0x09
	subwf	COUNTER,w
	btfss	STATUS,Z
	goto	Init_LCD_0
	bsf		PORTB,7
	return
		
LCD_PulseZ
	nop
	nop
	nop
	bsf		PORTB,6
	nop
	nop
	nop
	bcf		PORTB,6
	call	LCD_Wait
	return

LCD_Wait
	movlw	0x01
	movwf	LCD_WAIT_D1
	movlw	0x08
	movwf	LCD_WAIT_D2
LCD_Wait_0
	decfsz	LCD_WAIT_D1, f
	goto	$+2
	decfsz	LCD_WAIT_D2, f
	goto	LCD_Wait_0
	return

GetPulse
	clrf	PULSE_LEN
	btfss	SER_IN,SER_IN_BIT
	goto	$-1
GetPulse_0
	incf	PULSE_LEN,f
	btfsc	STATUS,Z
	retlw	0x00
	btfsc	SER_IN,SER_IN_BIT
	goto	GetPulse_0
	movf	PULSE_LEN,w
	return

#ifdef TEST_SUBROUTINES
DumpW
	movwf	DUMPHI
	bcf		STATUS,C
	rrf		DUMPHI,f
	rrf		DUMPLO,f	
	bcf		STATUS,C
	rrf		DUMPHI,f
	rrf		DUMPLO,f	
	bcf		STATUS,C
	rrf		DUMPHI,f
	rrf		DUMPLO,f	
	bcf		STATUS,C
	rrf		DUMPHI,f
	rrf		DUMPLO,f
	bcf		STATUS,C	
	rrf		DUMPLO,f
	bcf		STATUS,C
	rrf		DUMPLO,f
	bcf		STATUS,C
	rrf		DUMPLO,f
	bcf		STATUS,C
	rrf		DUMPLO,f
	call	LCD_Wait
	movf	DUMPHI,w
	call	DumpHexLookup
	movwf	PORTC
	call	LCD_PulseZ
	call	LCD_Wait
	movf	DUMPLO,w
	call	DumpHexLookup
	movwf	PORTC
	call	LCD_PulseZ
	return
#endif

Stamp_PAR
	call	Generate_PAR
	rlf		DAT_H,f
	rlf		DAT_H,f
	rrf		PAR,f
	rrf		DAT_H,f
	rrf		PAR,f
	rrf		DAT_H,f
	return

Check_PAR	; if STATUS,Z is set, PAR is OK
	call	Generate_PAR
	bcf		STATUS,C
	rrf		PAR,f
	rrf		PAR,f
	rrf		PAR,f
	movlw	b'11000000'
	andwf	DAT_H,w
	subwf	PAR,w
	return

Generate_PAR
	clrf	PAR
	movlw	b'11000000'
	iorwf	DAT_H,w
	call	PAR_Byte
	movf	DAT_L,w
	call	PAR_Byte
	return

PAR_Byte
	movwf	PAR_TMP
	movlw	0x04
	movwf	PAR_COUNTER
PAR_Byte_0
	rlf		PAR_TMP,f
	btfss	STATUS,C
	goto	PAR_Byte_1
	movlw	b'00000010'
	xorwf	PAR,f
PAR_Byte_1
	rlf		PAR_TMP,f
	btfss	STATUS,C
	goto	PAR_Byte_2
	movlw	b'00000001'
	xorwf	PAR,f
PAR_Byte_2
	decf	PAR_COUNTER,f
	btfss	STATUS,Z
	goto	PAR_Byte_0
	return

Check_DeviceID
	movf	DAT_H,w
	andlw	b'00111110'
	sublw	b'00000010'
	return

	        org 0x101

#ifdef TEST_SUBROUTINES
DumpHexLookup
	movwf	LOOKUP_TEMP
	movlw	0x01
	movwf	PCLATH
	movf	LOOKUP_TEMP,w
	addwf	PCL,f
	retlw	b'00110000'		; 0
	retlw	b'00110001'		; 1
	retlw	b'00110010'		; 2
	retlw	b'00110011'		; 3
	retlw	b'00110100'		; 4
	retlw	b'00110101'		; 5
	retlw	b'00110110'		; 6
	retlw	b'00110111'		; 7
	retlw	b'00111000'		; 8
	retlw	b'00111001'		; 9
	retlw	b'01000001'		; A
	retlw	b'01000010'		; B
	retlw	b'01000011'		; C
	retlw	b'01000100'		; D
	retlw	b'01000101'		; E
	retlw	b'01000110'		; F
#endif

Init_LCD_Table
	movwf	LOOKUP_TEMP
	movlw	0x01
	movwf	PCLATH
	movf	LOOKUP_TEMP,w
	addwf	PCL,f
	retlw	b'00111000'
	retlw	b'00001000'
	retlw	b'00000001'
	retlw	b'00000110'
	retlw	b'00001101'
	retlw	b'00000010'
	retlw	b'10000000'
	retlw	b'00010100'
	retlw	b'10000000'
	
	END