;**********************************************************************
;                                                                     *
;    Filename:      Decoder2.asm                                      *
;    Date:                                                            *
;    File Version:                                                    *
;                                                                     *
;    Author:        Ian Harding                                       *
;    Company:       (c) Electric Images, 2009                         *
;                   Permission is given for personal use only         * 
;                                                                     *
;**********************************************************************
;                                                                     *
;    Files required: P12F629.INC                                      *
;                                                                     *
;                                                                     *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Notes:                                                           *
;  Uses internal oscilator - should be 4MHz                           *
;                                                                     *
;    GP0: Serialised data out (ICSPclk)                               *
;    GP1: Confidence out to LED to gnd (ICSPdata)                     *
;    GP2: IR Detector 1 in, hi on active                              *
;    GP3: (MClr)                                                      *
;    GP4:                                                             *
;    GP5:                                                             *
;                                                                     *
;           start--v v--change                                        *
;                   _               _               _                 *
;     ||||||       | |-2-10 1 2 3 4| |-2-10 1 2 3 4| |    |||||       *
;     ||||||       | |             | |             | |    |||||       *
;     ||||||___.___| |_____________| |_____________| |__._|||||       *
;                         Car 4 - pulse is 48uS                       *
;                                                                     *
;                        change--v                                    *
;                   _____________   _____________   _._               *
;     ||||||       |  -2-10 1 2 3|4|  -2-10 1 2 3|4|   |  |||||       *
;     ||||||       |             | |             | |   |  |||||       *
;     ||||||___.___|             |_|             |_|   |__|||||       *
;                         Car 4 - pulse is 48uS-53uS                  *
;                                                                     *
;     Clearly time between rising edges is the critical item          *
;     Maximum cycle time for 6 cars, est 430uS                        *
;     Therefore use a T0 /4 prescaler, to give 12 units per pulse     *
;                                                                     *
;**********************************************************************

        radix   dec

;------------------------------------------------------------------------------
; PROCESSOR DECLARATION
;------------------------------------------------------------------------------

     LIST      P=12F629              ; list directive to define processor
     #INCLUDE <P12F629.INC>          ; processor specific variable definitions
        LIST    st=off


; --------------------------------
POS     equ     C       ; +ve STATUS after subtraction
SIGN    equ     7       ; True bit if negative value
;---------------------------------

;
; Branch if equal to destination
BEQ     MACRO   lDest
        btfsc   STATUS, Z
         goto   lDest
        ENDM

;
; Branch if not equal to destination
BNE     MACRO   lDest
        btfss   STATUS, Z
         goto   lDest
        ENDM
;------------------------------------------------------------------------------

#define _BANK1  bsf     STATUS, RP0
#define _BANK0  bcf     STATUS, RP0

;------------------------------------------------------------------------------
;
;
#define BITSIZE         11              ; number of TMR0 counts to a bitpulse
#define GOODREADS       (3 -1)          ; number of good reads reqd before send

;------------------------------------------------------------------------------
;
; CONFIGURATION WORD SETUP
;
; The 'CONFIG' directive is used to embed the configuration word within the 
; .asm file. The labels following the directive are located in the respective
; .inc file.  See the data sheet for additional information on configuration 
; word settings.
;
;------------------------------------------------------------------------------

    __CONFIG   _CP_OFF & _CPD_OFF & _BODEN_OFF & _MCLRE_ON & _WDT_OFF & _PWRTE_ON & _INTRC_OSC_NOCLKOUT ;_XT_OSC


;===================================
; IO Port defines
;
OUTb            equ     0               ; Serial out to other system (ICSPdata)
LED1b           equ     1               ; Set Hi to light (ICSPclk)
IR1b            equ     2               ; Input from IR1, lo on detect
;               equ     3               ; unused (MCLR)
;               equ     4               ; xtal
;               equ     5               ; xtal
#define LED1    GPIO, LED1b
#define OUT     GPIO, OUTb
#define IR1     GPIO, IR1b

;------------------------------------------------------------------------------
; VARIABLE DEFINITIONS
;------------------------------------------------------------------------------

_temp       res     1
cartime     res     1
carcount    res     1
car         res     1
carhold     res     1
carsent     res     1
count       res     1
halfway     res     1

;------------------------------------------------------------------------------
; EEPROM INITIALIZATION
;
; The 12F629 has 128 bytes of non-volatile EEPROM, starting at address 0x2100
; 
;------------------------------------------------------------------------------
;
;DATAEE    CODE  0x2100

;------------------------------------------------------------------------------
; OSCILLATOR CALIBRATION VALUE
;------------------------------------------------------------------------------

OSC       CODE    0x03FF

; Internal RC calibration value is placed at location 0x3FF by Microchip as
; a RETLW K instruction, where the K is a literal value to be loaded into
; the OSCCAL register.  

;------------------------------------------------------------------------------
; RESET VECTOR
;------------------------------------------------------------------------------

RESET_VECTOR  CODE      0x0000 ; processor reset vector
        goto    START          ; 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

; isr code can go here or be located as a call subroutine elsewhere

;        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
        retfie                ; return from interrupt

;------------------------------------------------------------------------------
; MAIN CODE STARTS
;------------------------------------------------------------------------------

MAIN_PROG     CODE

; Jump table for the various bit pulse times for cars
;   entry: timer value in W,
;   return: car # in W
CarCalc
        btfsc   cartime, 7
         retlw  0

        movf    cartime, W
        clrf    PCLATH
        addwf   PCL, f

car_table
    local i = 0
    local c = 1
    while i < (c +3) *BITSIZE -1
        dt      0
i       +=      1
    endw

    while c <= 6
car_val#v(i)            ; set the car values
      while i < (c +3) *BITSIZE +(BITSIZE /2)
        dt      c
i       +=      1
      endw
car_val#v(i)            ; set intercar gap
      while i < (c +1 +3) *BITSIZE -1
        dt      0
i       +=      1
      endw
c       +=      1
    endw

    while i < 128
        dt      0
i       +=      1
    endw


;------------------------------------------------------------------------------
; MAIN PROGRAM
;------------------------------------------------------------------------------

START
        _BANK0
        clrf    GPIO
        movlw   7
        movwf   CMCON

;------------------------------------------------------------------------------
; OSCCAL RESTORE (not required if internal OSC is not used)
;------------------------------------------------------------------------------

        errorlevel -302       ; no warnings about non-bank 0 registers
        call    0x3FF         ; retrieve factory calibration value
        banksel OSCCAL
        movwf   OSCCAL        ; update register with factory cal value 

;------------------------------------------------------------------------------

        movlw    (0 << NOT_GPPU) | (1 << INTEDG) | (0 << T0CS) | (1 << T0SE) | (0 << PSA) | 0x01
        movwf    OPTION_REG

        movlw    (1 << IR1b) | (0 << OUTb) | (0 << LED1b)
        movwf    TRISIO
        movwf   WPU
        errorlevel +302

        banksel INTCON
        clrf    INTCON
        movlw    (1 << OUTb) | (0 << LED1b)
        movwf    GPIO                ; set a 'space' state on output line, & LEDs off

        clrf    car

;------------------------------------------------------------------------------

; a long high implies that the car is going over the sensor, and its in darkness
long_silence
        movlw   GOODREADS
        movwf   carcount
        clrf    carsent
        clrf    carhold
        bcf     LED1

; wait for start pulse on inport (rising edge)
await_start
        clrf    TMR0

awaiting_start
        btfsc   TMR0, 7
         goto   long_silence

        btfss   IR1
         goto   awaiting_start                ; (while lo)
        btfss   IR1
         goto   awaiting_start                ; (while lo)
        clrf    TMR0
        btfss   IR1
         goto   awaiting_start                ; (while lo)

; start has occured, now await the changing edge - this defines the 'lane switch or not'
await_change
        btfsc   IR1
         goto   await_change
        btfsc   IR1
         goto   await_change
        btfsc   IR1
         goto   await_change

; edge has restored, now check the duration - this must be 9 or more (11 optimum) Timer cycles to be valid
        movf    TMR0, W
        movwf   halfway

        movlw   BITSIZE -3
        subwf   halfway, W
        btfss   STATUS, C
         goto   await_start       ; edge is too short, must be noise, try again

await_next_start
        btfsc   TMR0, 7           ; if timer over runs, then a long silence has occurred
         goto   long_silence

        btfss   IR1
         goto   await_next_start
        btfss   IR1
         goto   await_next_start
        btfss   IR1
         goto   await_next_start

; do calcs in here for car id
        movf    TMR0, W
        movwf   cartime
        clrf    TMR0

        movlw   BITSIZE -3
        addwf   halfway, W
        subwf   cartime, W
        btfss   STATUS, C
         goto   await_change       ; edge is too short, try again
        
        call    CarCalc

        btfsc   STATUS, Z               ; check for illegal value
         goto   await_change

car_send
        movwf   car
        movf    carhold, w              ; see if we've already got it before
        BNE     check_send

car_save
        movf    car, w                  ; first time or new decode, save for recheck
        movwf   carhold
        
        movlw   GOODREADS
        movwf   carcount
        goto    await_change

check_send
        movf    carhold, w
        xorwf   car, w                  ; second or later time, compare both
        BNE     car_save

        decfsz  carcount, f             ; decode must be the same for GOODREADS times
         goto   await_change

        movf    car, w                  ; see if we already sent this car id
        xorwf   carsent, w
        BEQ     await_change

;------------------------------------------------------------------------------
; All match, send the car number out

        bsf     LED1
        movf    car, w
        movwf   carsent

        movlw   0x30
        iorwf   car, f

        movlw   12
        movwf   count
        bcf     STATUS, C

tx_loop
        btfsc   STATUS, C
         goto   $ +4

        nop                             ; send a lo
        bcf     OUT
        goto    $ +3

        bsf     OUT                     ; send a hi
        goto    $ +1

        call    bit_delay               ; pause for the remainder of the bit time

        bsf     STATUS, C               ; set a stop bit, and rotate the value
        rrf     car, f
        decfsz  count, f                ; finish when all 11 bits sent
         goto   tx_loop

; await a suitable end point, then loop again
await_end
        btfsc   IR1
         goto   await_end
        btfsc   IR1
         goto   await_end
        btfsc   IR1
         goto   await_end
        goto    await_start

;------------------------------------------------------------------------------

; Delay of: 17.3 (57600bd); -15 cycles (for mainline code, inc call/return)
; for 4MHz crystal (1 MHz cycle)
bit_delay
        goto    $ +1
        retlw   0

        END                       ; 'end of program'