list    P=PIC16F690
#include "P16F690.inc"
 __config (_CP_OFF & _WDT_OFF & _PWRTE_ON & _HS_OSC)

#define RFIDdebug


; constants and mask definitions

; variable definitions
RFIDMachineState    equ       0x20
RFIDByteCounter     equ       0x21
RFIDNibbleIndicator equ       0x22
RFID_Read           equ       0x23
RFIDNewData         equ       0x24
TimeoutCounter		equ		  0x26

#define SPI_Header 0xB9
#define SPI_End    0x9B
SPI_Index           equ       0x25

#define SPI_RequestPort PORTC
#define SPI_RequestBit 3

ASCII_Byte          equ       0x2E
Hex_Nibble          equ       0x2F

RFIDChecksum        equ       0x30
;MSB to LSB from RFID reader
RFID_ByteArray      equ       0x31


#define   DebugPort PORTC
DebugBit  equ       0
DebugLED  equ       2

; bit definitions

; program start
          org 0
          goto Main
          org 5

;RFID State switch
RFIDStateSwitch:
          addwf     PCL,f
          goto      RFIDState_Message   ;case 0
          goto      RFIDState_Data      ;case 1
          goto      RFIDState_End       ;case 2


;-----------------------------------------------------------;
; Main - initialization of ports and configuration          ;
;-----------------------------------------------------------;
Main:
;General Initialization
          ;Clear ANSEL registers
          banksel   ANSEL
          clrf      ANSEL
          clrf      ANSELH

          ;Set Outputs before initialization
          banksel   PORTA
          clrf      PORTA
          clrf      PORTB
          clrf      PORTC

          banksel   DebugPort
          bsf       DebugPort,DebugLED

          ;Set TRIS registers
          banksel   TRISA
          bsf       TRISB,5   ;RX input
          bcf       TRISB,7   ;TX output

          bsf       TRISC,DebugBit
          bcf       TRISC,DebugLED

		  bcf		SPI_RequestPort,SPI_RequestBit
          bcf       TRISC,SPI_RequestBit   ;SPI Request Line
          bsf       TRISB,6   ;SCK input
          bsf       TRISB,4   ;SDI input
          bcf       TRISC,7   ;SDO output
          bsf       TRISC,6   ;SS input

          ;secret master mode
;          bcf       TRISB,6   ;SCK output//input
;          bsf       TRISB,4   ;SDI input
;          bcf       TRISC,7   ;SDO output
;          bcf       TRISC,6   ;SS output //input


;;Initialize SPI
          banksel   SPI_Index
          movlw     0x04
          movwf     SPI_Index
          banksel   SSPBUF
          movlw     0xA5
          movwf     SSPBUF

          banksel   SSPCON
          movlw     b'00110100'
                    ; xx1xxxxx    Enables SPI
                    ; xxx1xxxx    CKP - clock idles high
                    ; xxxx0100    SPI slave with SS enabled
          movwf     SSPCON
          banksel   SSPSTAT
          clrf      SSPSTAT
                    ; 0xxxxxxx    Required for slave mode
                    ; x0xxxxxx    CKE - Data transmitted on rising edge of SCK

;Initialize EUSART
          ;set baud rate to 9600: 20MHz/16/(129+1)
          banksel   SPBRG
          movlw     d'129'
          movwf     SPBRG
          banksel   TXSTA
          bsf       TXSTA,BRGH
          ;asynch:
          banksel   TXSTA
          bcf       TXSTA,SYNC
          banksel   RCSTA
          bsf       RCSTA,SPEN
          ;transmission and reception enable
          banksel   TXSTA
          bsf       TXSTA,TXEN
          banksel   RCSTA
          bsf       RCSTA,CREN

;Initialize Timer
          banksel   PIR1
          bcf       PIR1,TMR2IF

          banksel   PR2
          movlw     d'255'
          movwf     PR2

          call      TimerReset

          banksel   T2CON
          movlw     b'01111111'   ;1:16 pre and post scaler, timer on
		  movwf     T2CON


;State machine initialization
          pagesel   RFIDReset
          call      RFIDReset ;Call UARTReset Function

;Event Checker Loop:
LoopStart:
LoopContinue:
          ;check for received message on EUSART
          banksel   PIR1
          btfsc     PIR1,RCIF    ;check if new UART message
          call      RFIDReceive  ;call UART Received function if so

          ;check for new serial transmission
          banksel   SSPSTAT
          btfsc     SSPSTAT,BF   ;check for new serial transmission
          call      SPIUpdate    ;call update function to load next byte

          ;update timer, check for timeout
          banksel   PIR1
          btfss     PIR1,TMR2IF  ;check to see if timer 2 rolled over
          goto      LoopContinue

          ;update timer
          banksel   PIR1
          bcf       PIR1,TMR2IF  ;clear timer overflow flag
          banksel   TimeoutCounter
          decfsz    TimeoutCounter ;decrease counter by 1 tick
          goto      LoopContinue

          ; TIMEOUT:
          call      TimerReset ;reset state timer
          call      RFIDReset  ;reset state machine on timeout
          goto      LoopContinue

; Reset Timeout Counter
TimerReset:
          banksel   TimeoutCounter
          movlw     0x76           ;one second timer
          movwf     TimeoutCounter ;reset counter
          return

; Update SPI transmission
SPIUpdate:
          call      TimerReset   ;reset timeout counter

          ;Clear flag
          banksel   PIR1
          movf      PIR1,W
          banksel   SSPBUF
          movf      SSPBUF,W

          banksel   SPI_Index
          decfsz    SPI_Index,f    ;decrement index
          goto      SPINewByte     ;load next byte

          ;if index hit 0, end SPI transmission
          banksel   SPI_RequestPort
          bcf       SPI_RequestPort,SPI_RequestBit  ;clear ready to send bit
          movlw     SPI_End
          movwf     SSPBUF     ;store end byte in register, just to clear it

          ;reset index
          movlw     0x05
          banksel   SPI_Index
          movwf     SPI_Index

          return

; Load next byte for SPI transmission
SPINewByte:
          movlw     RFID_ByteArray      ;access array of rfid bytes
          banksel   SPI_Index
          addwf     SPI_Index,W         ;index array on counter
          movwf     FSR                 ;store target index

          banksel   SSPBUF
          movf      INDF,W
          movwf     SSPBUF    			;load next byte

          return


;UART Reset Function
RFIDReset:
          ;Set UARTMachineState to WaitingForMessage state
          banksel   RFIDMachineState
          clrf      RFIDMachineState

          ;Initialize Byte Counter to 6
          banksel   RFIDByteCounter
          movlw     d'6'
          movwf     RFIDByteCounter

          ;Initialize RFIDNibbleIndicator to High
          banksel   RFIDNibbleIndicator
          movlw     0xFF
          movwf     RFIDNibbleIndicator

          ;clear checksum
          banksel   RFIDChecksum
          clrf      RFIDChecksum

          return

;UART Receive function:
RFIDReceive:
          call      TimerReset          ;reset timeout counter

          ;Read byte from receive register, store as RFID_Read
          banksel   RCREG
          movf      RCREG,W
          banksel   RFID_Read
          movwf     RFID_Read

          ;Switch on UARTMachineState
          banksel   RFIDMachineState
          pageselw  RFIDStateSwitch
          movf      RFIDMachineState,W
          goto      RFIDStateSwitch

;State: WaitingForMessage
RFIDState_Message:
          banksel   RFID_Read
          movf      RFID_Read,W
          ;if RFID_Read is 0x02
          xorlw     0x02
          btfss     STATUS,Z
          goto      RFIDReset           ;if not 02, reset and exit
          call      RFIDReset           ;if 02, reset and continue

          ;clear new rfid flag
          banksel   RFIDNewData
          bcf       RFIDNewData,0

          banksel   RFIDMachineState
          incf      RFIDMachineState,f  ;set state to waiting for data

          return    ;return to loop


;State: WaitingForData
RFIDState_Data
          banksel   RFID_Read
          movf      RFID_Read,W
          call      ASCIItoHex          ;Call ASCIItoHex function on RFID_READ

          banksel   RFIDNibbleIndicator
          btfsc     RFIDNibbleIndicator,0      ;If NibbleIndicator is High
          swapf     Hex_Nibble,f               ;make nibble MSB.  Using SWAPF, whatup!?

          ;Add Nibble to RFID_Byte(RFIDByteCounter)
          movlw     RFID_ByteArray      ;access array of rfid bytes
          banksel   RFIDByteCounter
          addwf     RFIDByteCounter,W   ;index array on byte counter
          movwf     FSR                 ;store target index

          banksel   RFIDNibbleIndicator
          btfsc     RFIDNibbleIndicator,0       ;If NibbleIndicator is high, new byte
          clrf      INDF                        ;clear indexed byte

          banksel   Hex_Nibble
          movf      Hex_Nibble,W        ;load nibble to add to indexed byte
          addwf     INDF,f              ;add nibble to byte

          ;Swap RFIDNibbleIndicator
          banksel   RFIDNibbleIndicator
          comf      RFIDNibbleIndicator,f

          ;If RFIDNibbleIndicator is high, prepare for new byte
          btfss     RFIDNibbleIndicator,0
          return                        ;return to loop otherwise

#ifdef RFIDdebug
          ;output to UART if byte index is 2, 3, or 4 for checkoff
          movf      RFIDByteCounter,W
          sublw     0x02
          btfsc     STATUS,Z
          goto      Output

          movf      RFIDByteCounter,W
          sublw     0x03
          btfsc     STATUS,Z
          goto      Output

          movf      RFIDByteCounter,W
          sublw     0x04
          btfsc     STATUS,Z
          goto      Output

          goto      Continue

Output:
          banksel   RFIDChecksum
          movf      INDF,w              ;load recent completed byte to w
          btfsc     PIR1,TXIF
          movwf     TXREG
#endif

Continue:
          banksel   RFIDChecksum
          movf      INDF,w              ;load recent completed byte to w

          xorwf     RFIDChecksum,f      ;bitwise add byte to checksum
          banksel   RFIDByteCounter
          decfsz    RFIDByteCounter,f   ;decrement byte counter
          return                        ;return to loop if not 0

          ;if byte counter reached 0, we finished with checksum
          ;check checksum:
          banksel   RFIDChecksum
          movf      RFIDChecksum,f      ;if checksum is 0, then Z=1
          btfss     STATUS,Z
          goto      RFIDReset           ;if bad checksum, bail on transfer, return to loop
          banksel   RFIDMachineState
          incf      RFIDMachineState,f  ;set state to waiting for end byte
          return    ;return to loop

;State:: Waiting for End
RFIDState_End:
          ;check if RFID_Read is 0x03
          banksel   RFID_Read
          movf      RFID_Read,W
          xorlw     03

          btfss     STATUS,Z            ;if not
          goto      RFIDReset           ;exit loop, reset state to waiting for message
                                        ;otherwise
          banksel   RFIDNewData
          bsf       RFIDNewData,0       ;set new data flag

          banksel   SSPBUF
          movlw     SPI_Header
          movwf     SSPBUF    ;put header in buffer

          banksel   SPI_Index
          movlw     0x05
          movwf     SPI_Index ;start counter at 3

          banksel   SPI_RequestPort
          bsf       SPI_RequestPort,SPI_RequestBit        ;indicate ready to send

          ;turn on debug led
          banksel   DebugPort
          bsf       DebugPort,DebugLED

          goto      RFIDReset ;exit loop, reset state to waiting for message



; Convert ASCII byte to Hex nibble
ASCIItoHex:
          banksel   ASCII_Byte
          movwf     ASCII_Byte
          ;if ascii byte > 40, add 9
          sublw     0x40
          movlw     0
          btfss     STATUS,C
          movlw     9
          addwf     ASCII_Byte,W
          ;get lower nibble
          andlw     0x0F
          banksel   Hex_Nibble
          movwf     Hex_Nibble
          return


          end