 TITLE  "wRX2.asm"          	; weather station controller
 List P=12F683, R=DEC
 INCLUDE "p12F683.inc"

SCL	EQU 4			; Clock line setup
SDA	EQU 5			; Data line setup
RFHI 	EQU 0			; high pulse state timeout bit
RFLO 	EQU 1			; low pulse state timeout bit
VERR 	EQU 2			; pulse width verification error bit
VTOL	EQU 8			; pulse width tolerance
ZERR	EQU 3			; zero gap tolerance
OERR	EQU 4			; one gap tolerance
TFACT	EQU 16			; receive timing factor (value*3+2 usec)
PLEN	EQU 2			; min pulse length (value*5 usec)

; data segment
 CBLOCK 0x20                   
 del, err, temp, temp2 	 	; local variables 
 dataIO, i, cnt		
 gapTime, refTime
 prev0, prev1	
 ENDC

; code segment
 __CONFIG _BOD_ON & _CPD_OFF & _CP_OFF & _MCLRE_OFF & _PWRTE_ON & _WDT_OFF & _INTOSCIO

  ORG 0	                    	; start program at the beginning of mem
	bcf	STATUS, RP0     ; switch to BANK 0
	clrf	GPIO		; initialize GPIO
	movlw	0x13		; COUT on pin 5 (GPIO2)
	movwf	CMCON0		; setup the comparator
	clrf	ADCON0		; ADC OFF
  	bsf    	STATUS, RP0    	; change to BANK 1
	movlw	0xA7		; comparator reference  (A7=1.46V, A6=1.25V)
	movwf	VRCON ^ 0x80	; setup voltage reference
	movlw	2
	movwf	ANSEL ^ 0x80 	; enable GP1 as analog input
	movlw	b'00111011'
	movwf	TRISIO ^ 0x80	; enable GP<2> for input
  	bcf    	STATUS, RP0    	; back to BANK 0

loop				; main loop
	btfss	CMCON0, COUT	; wait for pulse
	 goto	$-1					

	call	getPulse	; timing the first pulse
	sublw	PLEN		; w = PLEN - pulse_len
	btfsc	STATUS, C
	 goto loop		; ignore short impulse

	call	getByte		; receive a byte in WREG

	btfsc	err, RFHI	; error control for debugging
	 goto	err1
	btfsc	err, RFLO
	 goto	err2
	btfsc	err, ZERR
	 goto 	err4
	btfsc	err, OERR
	 goto 	err5
;	btfsc	err, VERR
;	 goto	err3
	
send	
	call	writeLCD	; display the byte in WREG
	goto	loop
err1	
 	movlw	'H'		; pulse timeout error
	goto	send
err2	
	movlw	'L'		; gap timeout error
	goto	send
err3	
	movlw	'T'		; gap tolerance error		
	goto	send
err4
	movlw	'Z'		; zero tolerance error
	goto 	send					
err5
	movlw	'O'		; one tolerance error
	goto 	send


; get 10-pulse data byte	
getByte	
 	clrf	prev0		; clear validity bytes
	clrf	prev1
	clrf	err
	call	getGap		; get reference time
	btfsc	err, RFLO	; data ok?
	 goto 	errReturn	; NO - error exit
	movwf	refTime		; store reference time
	movlw	8
	movwf	cnt		; set bit counter
	clrf	dataIO		; receiving data

nextBit
	rlf	dataIO, f
	call	getGap
	movwf	gapTime		; save for validity check.
	btfsc	err, RFLO	; pulse stuck low?
	 goto	errReturn	; YES - return
	btfsc	err, RFHI       ; pulse stuck high?
	 goto	errReturn	; YES - return
	subwf	refTime, w	; > or < than ref ?
	btfss	STATUS, C	
	 goto	one		; proceed with receiving a 1

zero	
	bcf	dataIO, 0	; insert a 0 into receiving data
	movf	prev0, w
	btfsc	STATUS, Z	; got a 0 already?
	 goto	zback		; NO
	call	validate
	btfss	STATUS, C
	 bsf	err, ZERR
	goto	more
zback	
	movf	gapTime, w
	movwf	prev0		; store for next time
	goto	more		; get next bit		

one	
	bsf	dataIO, 0	; insert a 1 into receiving data
	movf	prev1, w
	btfsc	STATUS, Z	; got a 1 already?
	 goto	oback		; NO
	call	validate
	btfss	STATUS, C
	 bsf	err, OERR
	goto	more
oback	
 	movf	gapTime, w	; store one's duration
	movwf	prev1

more	
	decfsz	cnt, f
	 goto	nextBit
	movf	dataIO, w

errReturn	
	return

getPulse			; return pulse width in W
	clrf	temp2		; pulse/gap width counter
	incf	temp2, f	; pulse was already high for some time
	btfss	CMCON0, COUT	; pulse still high?
	 goto 	returnLen	; no - return its length
	incfsz	temp2, f	; pulse stuck on high
	 goto	$-3	
	bsf	err, RFHI	; report an error

returnLen	
	movf	temp2, w
	return

getGap				; return the gap width in W	
	bcf	err, RFLO	; clear all errors
	bcf	err, RFHI

	clrf	temp		; gap measuring loop
g1	movlw	TFACT		; short timing delay
	movwf	del		; for 3*TFACT+2 usec (50usec)
	decfsz	del, f
	 goto	$-1

	btfsc	CMCON0, COUT	; still low?
	 goto	g2		; NO - return time
	incfsz	temp, f
	 goto	g1		; keep timing the gap
	bsf	err, RFLO	; timeout on gap
	return

g2	call 	getPulse
	sublw	PLEN
	btfsc	STATUS, C
	 goto	g1		; ignore short pulse and keep timing gap

	movf	temp, w
	return

validate			; check the received gap tolerance
	movwf	temp		; last bit's time
	movf	gapTime, w	; this bit's time
	subwf	temp, f		; get the difference (last - this)
	btfss	temp, 7		; negative?
	 goto	$+4		; NO

	movf	temp, w		; YES - negate it
	sublw	0
	movwf	temp		; temp = -temp for negative values

	movf	temp, w
	sublw	VTOL		; error tollerance
	return

; code from here down is only needed for a debugging with LCD
writeLCD			; write byte in W to the LCD line
	movwf	dataIO
	movlw	b'001111'
	andwf	GPIO, f
	movlw	0x85		; setup FSR to point to TRISIO
	movwf	FSR
	bsf	INDF, SCL	; make sure that clock is high
	movlw	8
	movwf	cnt		; bits counter

w_loop
	btfss	GPIO, SCL	; wait for release of the clock line
	 goto	$-1

	bcf	INDF, SCL	; set clock low
	rlf	dataIO, f	; get the rightmost data bit
	btfss	STATUS, C
	 bcf	INDF, SDA
	btfsc	STATUS, C
	 bsf	INDF, SDA	; now the data bit is on the line
	goto	$+1		; short delay
	bsf	INDF, SCL	; raise clock up

	movlw	6		; a 20 usec delay
	addlw	-1
	btfss	STATUS, Z
	 goto	$-2

	decfsz	cnt, f
	 goto	w_loop		; repeat this 8 times
	return

 end
