; Test application for the relay board
;
;   Copyright 2014 Greg Stein
;
;   Licensed under the Apache License, Version 2.0 (the "License");
;   you may not use this file except in compliance with the License.
;   You may obtain a copy of the License at
;
;       http://www.apache.org/licenses/LICENSE-2.0
;
;   Unless required by applicable law or agreed to in writing, software
;   distributed under the License is distributed on an "AS IS" BASIS,
;   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
;   See the License for the specific language governing permissions and
;   limitations under the License.
;
;
; Simply rotates through the various relays, keeping two on at a time.
;

        list p = 16f688
        include p16f688.inc
        include ../include/handy.inc
        errorlevel  -302        ; suppress banksel warning (302) from listing

        __config DEFAULT_CONFIG


; If the Makefile says we're active LOW, then roll with that. Otherwise, we
; will use active HIGH by default.
 ifndef ACTIVE_LOW
  constant ACTIVE_HIGH = 1
 endif

relay_ON: macro PORT, WHICH
 ifdef ACTIVE_LOW
        bcf     PORT, WHICH
 else
        bsf     PORT, WHICH
 endif
        endm
relay_OFF: macro PORT, WHICH
 ifdef ACTIVE_LOW
        bsf     PORT, WHICH
 else
        bcf     PORT, WHICH
 endif
        endm


DELAY_COUNT equ 0x20


.reset: org  0x0000

        bank0

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

        ; Latch "disabled" to all outputs: RA0/1/2/./4/5 and RC0/1/2/3
 ifdef ACTIVE_HIGH
        clrf    PORTA
        clrf    PORTC
 else
        movlw   0x37
        iorwf   PORTA, F
        movlw   0x0f
        iorwf   PORTC, F
 endif

        bank1s

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

        ; With an 8 MHz clock, an instruction cycle is 0.5 µs. We want to
        ; target 2.5 second delays (each relay remains engaged for 5s).
        ; This corresponds to 5M instruction cycles.
        ;
        ; Timer 0 wraps at 256 instructions. Setting the prescaler to 1:256
        ; will wrap at 65536 instructions (32.8 ms).
        movlw   0x87            ; pull-ups disabled, T0CS to internal
                                ;   instruction clock (timer mode), prescaler
                                ;   assigned to Timer 0, rate set at 1:256.
        movwf   OPTION_REG

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

        ; And set the tristates to ensure the pins are all OUTPUTS.
        clrf    TRISA

        movlw   0x30
        andwf   TRISC, F

        bank0s

cycle_start:
        relay_ON  PORTC, 2
        call      delay
        relay_OFF PORTA, 4
        call      delay
        relay_ON  PORTC, 1
        call      delay
        relay_OFF PORTC, 2
        call      delay
        relay_ON  PORTC, 0
        call      delay
        relay_OFF PORTC, 1
        call      delay
        relay_ON  PORTA, 2
        call      delay
        relay_OFF PORTC, 0
        call      delay
        relay_ON  PORTA, 1
        call      delay
        relay_OFF PORTA, 2
        call      delay
        relay_ON  PORTA, 0
        call      delay
        relay_OFF PORTA, 1
        call      delay
        relay_ON  PORTA, 5
        call      delay
        relay_OFF PORTA, 0
        call      delay
        relay_ON  PORTA, 4
        call      delay
        relay_OFF PORTA, 5
        call      delay

        goto    cycle_start

; Wait 64 rounds of TMR0 overflows (each at 32.8ms). Total: 2.1 seconds.
delay:
        clrf    DELAY_COUNT
        clrf    TMR0

loop:
        ; Wait for TMR0 to overflow
        btfss   INTCON, T0IF
        goto    loop

        ; Clear the overflow indicator
        bcf     INTCON, T0IF

        ; 64 cycles. Wait for bit5 to get SET.
        incf    DELAY_COUNT, F
        btfss   DELAY_COUNT, 5
        goto    loop

        return


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