;******************************************************************************
;                                                                             *
;    Filename:      SwarmiRx.asm                                              *
;    Date:          4/9/12                                                    *
;    File Version:  0.1                                                       *
;                                                                             *
;    Author:        Mike "Merser" Seiler                                      *
;                                                                             *
;******************************************************************************
;                                                                             *
;    Files required: P12F683.INC                                              *
;                                                                             *
;******************************************************************************
;                                                                             *
;    Notes:                                                                   *
;                                                                             *
;******************************************************************************

	list      P=12F683              	; list directive to define processor
    #include <P12F683.INC>          	; processor specific variable definitions

    __config   _FCMEN_ON & _IESO_OFF & _CP_OFF & _CPD_OFF & _BOD_OFF & _MCLRE_OFF & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT 

	errorlevel	-302					; ignores warnings about bank select bits
;------------------------------------------------------------------------------
; VARIABLE DEFINITIONS
;------------------------------------------------------------------------------

INT_VAR     udata_shr      
W_TEMP      RES     1             ; variable used for context saving 
STATUS_TEMP RES     1             ; variable used for context saving
Rx_STATUS	RES		1			  ; keeps track of whether we are triggering by falling or rising edge
resultH		RES		1			  ; 8 msb for comparing captured signal
resultL		RES		1			  ; 8 lsb for comparing captured signal
bit			RES		1			  ; counter for each bit of message sent
cmd			RES		1			  ; holds the actual 8 bit value to be sent

	#define		falling		b'00000100'	; constant to set type of edge in capture mode
	#define		rising		b'00000101'
	#define		fe_dt		0			; falling edge detected
	#define		re_dt		1			; rising edge detected
	#define		st_dt		2			; start detected

;------------------------------------------------------------------------------
; RESET VECTOR
;------------------------------------------------------------------------------

RESET_VECTOR  CODE    0x0000  			; processor reset vector
        goto    init         			; go to beginning of program

;------------------------------------------------------------------------------
; INTERRUPT SERVICE ROUTINE
;------------------------------------------------------------------------------

INT_VECTOR    CODE    0x0004  			; interrupt vector location
        movwf   W_TEMP        			; save off current W register contents
        movf    STATUS,w      			; move status register into W register
        movwf   STATUS_TEMP   			; save off contents of STATUS register
		bcf		INTCON,GIE				; disable interrupts for the length of the isr
		bcf		PIR1,CCP1IF				; clear the capture flag
		btfss	Rx_STATUS,fe_dt			; check if it was a falling edge capture
		goto	pulse_Start
		btfsc	Rx_STATUS,re_dt			; check if it was a rising edge capture
		goto	pulse_Start

pulse_End
		bcf		Rx_STATUS,fe_dt			; we've found the end of the pulse	
		bsf		Rx_STATUS,re_dt
		movlw	falling					; reset to look for beginning of next pulse
		movwf	CCP1CON					
		goto	$+5

pulse_Start
		bsf		Rx_STATUS,fe_dt			; start of new pulse
		bcf		Rx_STATUS,re_dt
		movlw	rising					; reset to look for end of this pulse
		movwf	CCP1CON

		movf   	STATUS_TEMP,w 			; retrieve copy of STATUS register
        movwf   STATUS        			; restore pre-isr STATUS register contents
        swapf   W_TEMP,f
        swapf   W_TEMP,w      			; restore pre-isr W register contents
        bsf		INTCON,GIE				; renable interrupts
		clrf	TMR1L					; zero timer1
		clrf	TMR1H
		retfie                			; return from interrupt

;------------------------------------------------------------------------------
; MAIN PROGRAM
;------------------------------------------------------------------------------

MAIN_PROG     CODE

init
		bsf		STATUS,RP0				; select bank 1
		clrf	ANSEL					; make all pins digital
		movlw	b'00000100'				; make GPIO2 input and rest of pins output
		movwf	TRISIO					; except GPIO3 which can only be an input
		bsf		PIE1,CCP1IE				; enable interrupt for captured edge
		bcf		STATUS,RP0				; go back to bank 0
		clrf	GPIO					; clear the i/o port
		movlw	b'00000111'				; turn the comparator off - unfortunately a lot of peripherals
		movwf	CMCON0					; are on by default which can cause i/o not to function as intended
		bcf		T1CON,TMR1CS			; set timer 1 clock source to internal osc
		bsf		T1CON,TMR1ON			; turn timer1 on
		movlw	falling					; set type of edge to trigger interrupt
		movwf	CCP1CON
		movlw	(1<<PEIE | 1<<GIE)		; turn on interrupts
		movwf	INTCON
		
receive.wait
		btfss	Rx_STATUS,fe_dt			; has a falling edge been detected?
		goto	$-1						; no loop
		btfss	Rx_STATUS,re_dt			; yes look for raising edge
		goto	$-1						; no loop
		call	compare.pulse			; compare contents in CCPR1H-L if between 2300 and 2500
		btfss	Rx_STATUS,st_dt			; is it a start condition ?
		call	err_receive				; no goto error receive
		goto	receive.wait
compare.pulse							; test if received pulse is between 2300 and 2500
		movf	CCPR1L,w				; microseconds in length
		movwf	resultL
		movf	CCPR1H,w
		movwf	resultH
		movlw	b'11111100'				; first check if the pulse is not shorter than 2300 usec
		subwf	resultL,w
		movlw	b'00001000'
		btfss	STATUS,C
		addlw	.1
		subwf	resultH,w
		btfss	STATUS,C
		goto	err_receive				; pulse was shorter than allowed 2300 usec for a start condition abort
		movlw	b'11000110'				; now check if the pulse is not longer than 2500 usec
		subwf	resultL,w
		movlw	b'00001001'
		btfss	STATUS,C
		addlw	.1
		subwf	resultH,w
		btfss	STATUS,C
		goto	receive.message			; ok we have a start condition start receiving command
		goto	err_receive				; pulse was longer than 2500 usec abort receive
receive.message							
		movlw	.9						; load a counter so we only look for 8 bits
		movwf	bit						; the reason we load nine is we immediately decrement in the loop
command.loop
		decfsz	bit,f
		goto	$+2
		goto	set.dir					; if we arrive here we have all 8 bits and now need to act on command
		btfss	Rx_STATUS,fe_dt			; has a falling edge been detected?
		goto	$-1						; no loop
		btfss	Rx_STATUS,re_dt			; yes look for raising edge
		goto	$-1						; no loop
		movf	CCPR1L,w				; move the length of our capture to the working register
		movwf	resultL
		movf	CCPR1H,w
		movwf	resultH
		movlw	b'11110100'				; is the length of the capture shorter than 500 usec
		subwf	resultL,w
		movlw	b'00000001'
		btfss	STATUS,C
		addlw	.1
		subwf	resultH,w
		btfss	STATUS,C
		goto	err_receive				; yes abort receive, bad data
		movlw	b'10111100'				; is the pulse longer than 700 usec? 
		subwf	resultL,w
		movlw	b'00000010'
		btfss	STATUS,C
		addlw	.1
		subwf	resultH,w
		btfss	STATUS,C
		goto	receive.zero			; no it's between 500 and 700 usec so we got a zero
		movlw	b'01001100'				; the pulse was either too short or too long for a zero
		subwf	resultL,w				; so check if it's a one
		movlw	b'00000100'				; is the pulse shorter than 1100 usec
		btfss	STATUS,C
		addlw	.1
		subwf	resultH,w
		btfss	STATUS,C
		goto	err_receive				; yes so bad data, abort receive
		movlw	b'00010100'				; is the pulse longer than 1300 usec
		subwf	resultL,w
		movlw	b'00000101'
		btfss	STATUS,C
		addlw	.1
		subwf	resultH,w
		btfss	STATUS,C
		goto	receive.one				; pulse was between 1100 and 1300 usec so it's a one
		goto	err_receive				; yes abort

receive.zero
		rlf		cmd,f					; rotate file one bit to the left
		goto	command.loop
receive.one
		rlf		cmd,f					; rotate file one bit to the left
		bsf		cmd,0					; and set bit zero
		goto	command.loop
err_receive			
		goto	receive.wait			; abort receive
set.dir
		movlw	.76						; check if we received an ascii L for left
		subwf	cmd,w
		btfsc	STATUS,Z
		call	turn.left				; yes turn left
		movlw	.82						; check if we received an ascii R for right
		subwf	cmd,w
		btfsc	STATUS,Z
		call	turn.right				; yes turn right
		movlw	.70						; check if we received an ascii F for forward
		subwf	cmd,w
		btfsc	STATUS,Z
		call	go.forward				; yes go turn both motors on
		movlw	.83						; check if we received an ascii S for stop
		subwf	cmd,w
		btfsc	STATUS,Z
		call	stop					; yes stop
		goto	receive.wait			; go back to start and wait for next command

;---------------------------------------------------------------------------------------------------
;  Set port pins for motor steering and stopping
;---------------------------------------------------------------------------------------------------

turn.left
		bcf		GPIO,1
		bsf		GPIO,0
		return		
turn.right
		bcf		GPIO,0
		bsf		GPIO,1
        return
go.forward
		bsf		GPIO,0
		bsf		GPIO,1
		return
stop
		bcf		GPIO,0
		bcf		GPIO,1
		return
        END                       		; if you get to here ask Telefox why

