; Primary application for the control board in the wall "switches"
;
; ### license
;
; ### docco
;
; WRITE-TO and READ-FROM operations are supported.
;
; OPCODE values are defined as:
;   ### todo
;
; PINS:
;   A0 - HOUSE SDA
;   A1 - HOUSE SCL
;   A2 - MPR IRQ (Local #0 only)
;   A3 - ICSP
;   A4 - LOCAL SCL
;   A5 - LOCAL SDA
;   C0 - TMP36 (AN4) (optional)
;   C1 - LED CLK (Local #0 only)
;   C2 - LED DAT (Local #0 only)
;   C3 - Local I2C accelator ENABLE (Local #0 only)
;   C4 - TX (to ePIR) (optional)
;   C5 - RX (from ePIR) (optional)
;

        list p = 16f688
        include p16f688.inc
        include ../include/handy.inc

        constant USING_I2C_SLAVE = 1
        include ../include/i2c.inc

        __config DEFAULT_CONFIG

; i2c.inc only has the no-prefix entrypoints. Define the prefixed forms.
 extern HOUSE_I2C_S_listen
 extern HOUSE_I2C_S_detect_START
 extern HOUSE_I2C_S_saw_START
 extern HOUSE_I2C_S_read
 extern HOUSE_I2C_S_read_stretch
 extern HOUSE_I2C_S_end_stretch
 extern HOUSE_I2C_S_write

 extern HOUSE_I2C_skip_unknown

 extern LOCAL_I2C_S_listen
 extern LOCAL_I2C_S_detect_START
 extern LOCAL_I2C_S_saw_START
 extern LOCAL_I2C_S_read
 extern LOCAL_I2C_S_read_stretch
 extern LOCAL_I2C_S_end_stretch
 extern LOCAL_I2C_S_write

 extern LOCAL_I2C_skip_unknown

; Support functions in mpr.asm
 extern mpr_initall
 extern mpr_check


; Pin definitions
 constant HOUSE_SCL = 1         ; PORTA
 constant HOUSE_SDA = 0         ; PORTA

 constant LOCAL_SCL = 4         ; PORTA
 constant LOCAL_SDA = 5         ; PORTA

 constant MPR_IRQ = 2           ; PORTA

 constant LED_DATIN = 1         ; PORTC
 constant LED_CLKIN = 2         ; PORTC

 constant ACCEL_ENABLE = 3      ; PORTC


        ; Define this module's variables
.gpr0   udata

; The OPCODE sent in a WRITE-TO request on the I2C bus.
OPCODE  res     1

; Configuration mask
 global CONFIG_MASK
CONFIG_MASK res 1
        ; Bit 0 : only LOCAL0 on this chain
        ; Bit 1 : only LOCAL0/1 are present
        ; Bit 2 : only LOCAL0/1/2 are present. (LOW: LOCAL3 is also present)
        ; Bit 3..7 : future



.reset: org  0x0000
        goto main


.main:  code                    ; relocatable
main:

        bank0

        ; Disable comparators. We're going to use all RA* as INPUTS/OUTPUTS.
        movlw   0x07
        movwf   CMCON0

        ; ### latch any OUTPUTS

        bank1s

        ; Switch to running at 8 Mhz
        movlw   0x70
        iorwf   OSCCON, F

        ; Ensure AN* are configured as DIGITAL pins.
        clrf    ANSEL

        ; ### leave all tristates as INPUTS (HIGH-Z) for now

        ; Get some configuration information
        read_eeprom EE_CONFIG_MASK
        movwf   CONFIG_MASK

        bank0s

        ; ### need to set up the I2C slave module

 ifdef IS_LOCAL0
        ; Initialize all the MPR121 devices on our LOCAL network
        call    mpr_initall
 endif

busy_loop:
        ; Both I2C busses are IDLE. Any SDA transition is a START condition,
        ; so we don't really need to test SCL. Just need to start reading
        ; fast enough.

        ; Check if either SDA has transitioned LOW (while SCL remains HIGH).
        ; t(HD;STA) is 4.0 µs minimum, then SCL will transition LOW and hold
        ; for t(LOW) of 4.7 µs until SCL then transitions HIGH to deliver
        ; the first bit. That gives us 17 instructions to see SCL LOW, then
        ; watch for the transition edge.

        ; NOTE: HOUSE-SDA might be managed by the Arduino, so the above
        ;       timings are strict. We will test HOUSE_SDA "often" to ensure
        ;       we never miss a START. LOCAL-SDA is from another '688, and
        ;       we will specifically code a stretch of the t(HD;STA) time.

        ; MPR and IR are much more lax on timing.

 ifndef IS_LOCAL0
        ; LOCAL1/2/3 act as Slave nodes on the LOCAL bus.

        ; Is LOCAL-SDA still HIGH?
        btfss   PORTA, LOCAL_SDA
        goto    local_activity

 else
        ; LOCAL0 needs to look at HOUSE-SDA and the MPR interrupts.

        ; Is HOUSE-SDA still HIGH?
        btfss   PORTA, HOUSE_SDA
        ; HOUSE-SDA just transitioned LOW.
        goto    house_activity

        ; Did the MPR121 IRQ get tripped LOW? Only LOCAL0 should handle
        ; MPR events.
        ; NOTE: downstream nodes will also pull this LOW for IR events.
        btfss   PORTA, MPR_IRQ
        goto    MPR_activity

        ; Test HOUSE-SDA again.
        btfss   PORTA, HOUSE_SDA
        goto    house_activity
 endif

        ; All nodes may have an IR module connected to them.
        ;
        ; LOCAL0 will send HOUSE an event. LOCAL1/2/3 will signal LOW on
        ; the MPR interrupt pin.

        ; Has data arrived from the IR module?
        btfsc   PIR1, RCIF
        ; Nothing from IR. Keep checking.
        goto    busy_loop

        ; FALLTHRU

IR_activity:
        ; ### do something
        goto    busy_loop


 ifdef IS_LOCAL0
house_activity:
        call    HOUSE_I2C_S_saw_START
        bz      busy_loop
        bc      house_read_from

        call    HOUSE_I2C_S_read_stretch
        movwf   OPCODE

        goto    busy_loop

house_read_from:
        ; ### do something
        goto    busy_loop

 endif                          ; IS_LOCAL0


 ifdef IS_LOCAL0
MPR_activity:
        movlw   I2C_READ_FROM(I2C_MPR0)
        call    mpr_check
        bz      done_mpr

        btfsc   CONFIG_MASK, 0
        ; Only LOCAL0 in this chain. Stop testing MPRs.
        goto    check_IR

        movlw   I2C_READ_FROM(I2C_MPR1)
        call    mpr_check
        bz      done_mpr

        btfsc   CONFIG_MASK, 1
        ; Only LOCAL0/LOCAL1 in this chain. Stop testing MPRs.
        goto    check_IR

        movlw   I2C_READ_FROM(I2C_MPR2)
        call    mpr_check
        bz      done_mpr

        btfsc   CONFIG_MASK, 2
        ; Only LOCAL0/LOCAL1/LOCAL2 in this chain. Stop testing MPRs.
        goto    check_IR

        movlw   I2C_READ_FROM(I2C_MPR3)
        call    mpr_check
        bz      done_mpr

check_IR:
        ; None of the MPRs were triggered. Thus, one of LOCAL1..LOCAL3
        ; pulled the signal line LOW, indicating an IR event.

        ; ### which nodes are connected to IR? consult CONFIG_MASK.
        ; ### talk to those slaves to see what is going on

done_mpr:
        ; ### nothing more to do?
        goto    busy_loop

 endif                          ; IS_LOCAL0


 ifndef IS_LOCAL0
local_activity:
        ; ### do something
        goto    busy_loop

 endif                          ; ! IS_LOCAL0 (aka LOCAL1/2/3)


; stupid assemblers don't realize EOF means *end*
        end
