;**********************************************************************
;    Filename:        irdec.asm                                       *
;    Date:            2003-02-02                                      *
;    File Version:    1.0                                             *
;                                                                     *
;    Author:          Per Zander                                      *
;**********************************************************************
;    Files required:  p16c505.inc                                     *
;**********************************************************************
;    Description:
;
;    General
;
;    This program is an 8-channel decoder for 8-bit messages. There is 
;    a 9th channel for cascading of several decoder chips, and an output 
;    channel.
;
;    Pin usage
;
;    The inputs for the pulse coded messages are on pin RB0-RB3 and
;    RC0-RC3. The serial input channel is on pin RC5, and the output 
;    channel is on RC4.
;
;    Operating frequency
;
;    The chip operates on 20 MHz oscillator frequency.
;
;    Format of the message
;
;    Each message consists of one parity bit and 8 data bits, which are sent 
;    repeatedly. The parity bit is sent first, and then the data bits with 
;    least significant bit first. The bits are sent as low pulses, where the
;    data is coded by the length of the pulses. A '0' is nominally 38 us, and 
;    a '1' is nominally 102 us. The high periods between the data bits are
;    nominally 38 us. The high period between the last data bit and the parity
;    bit is nominally 178 us or longer.
;  
;    The parity is set such that there will be an odd number of '1's including
;    the parity bit itself.
;
;    The frequency of the sender is allowed to be 0.89 - 1.08 * nominal value.
;    This means that a '0' can be between 35 and 43 us, and a '1' can be
;    between 94 and 115 us.
;    
;    The ports are scanned concurrently. If a valid message is detected on
;    one port, it is queued for transmission. If the same message is 
;    received repeatedly on the same port, it will only be sent once every
;    second.
;
;    Transmission and forwarding of messages
;
;    When the messages are queued up, they are sent out as 3-byte serial
;    messages with 9.6 kbaud. They are sent with 8 bits, no parity, two
;    stop bits. The 3-byte message consists of:
;
;    byte 0:     Bit 0:   Idle/valid. Set to 0 for an idle message, 1 for a
;                         valid message.
;
;                Bit 7-1: Decoder ID. This is sent as 0 by the originating
;                         decoder, and is incremented by 1 by a decoder that
;                         forwards the message.
; 
;    byte 1:     Bit 2-0: Port number. PB0 = port 0 etc.
;
;                Bit 7-3: Reserved, sent as 0.
;
;    byte 2:              The actual message.
;
;    In idle messages, byte 1 and 2 are sent as 0xff.     
;
;    One message is sent or forwarded every 5.0 ms. If there is nothing to
;    send and nothing to forward, an idle message is sent. When several
;    decoders are cascaded, only the first one will ever generate idle
;    messages, and the number of units can be detected by the decoder ID
;    for the idle message.
;
;    The input and output serial channels are inverted, i.e. a '1' is low
;    and a '0' is high. The receiver (RC5) should have a pull-up to make
;    it possible to detect if there is an upstream decoder or not.                         
;**********************************************************************

;*---------- Device select. ----------*

	  list      p=16c505            ; List directive to define processor
	  #include <p16c505.inc>        ; Processor specific variable definitions

;*---------- Configuration specification. ----------*

	  __CONFIG   _CP_OFF & _WDT_OFF & _MCLRE_OFF & _HS_OSC 

;*---------- Port definitions. ----------*

port3_0 EQU     0x06              ; IR decoder port 3:0 are on RB3:0.
port7_4 EQU     0x07              ; IR decoder port 7:4 are on RC3:0.
serport EQU     0x07              ; Serial ports use RC5:4. 
txd     EQU     0x04              ; TxD is on RC4.
rxd     EQU     0x05              ; RxD is on RC5. 

;*---------- Variable definitions. ----------*

true_d  EQU     0x08              ; Data from inputs, one bit per channel. 
tmp     EQU     0x08              ; Re-used as temporary variable.
dav     EQU     0x09              ; Data valid, one bit per channel.
ch_nr   EQU     0x0a              ; Current channel number.
ch_data EQU     0x0b              ; Data value for current channel.
tr_time EQU     0x0c              ; Transmit time if first decoder in the chain.
tr_data EQU     0x0d              ; Transmit data.
bitcnt  EQU     0x0e              ; Bit counter for transmit data. 
flags   EQU     0x0f              ; Program flags.    
st_04   EQU     0x10              ; State variables for channel 0 and 4, and
                                  ; end pointer. Use bank 0, 1 and 2.
data_c0 EQU     0x10              ; Channel 0 data. Use bank 3.
data_04 EQU     0x11              ; Data out from channel 0 and 4. Use bank
                                  ; 0 and 1.
data_c1 EQU     0x11              ; Channel 1 data. Use bank 3.
bitc_04 EQU     0x12              ; Bitcounter for channel 0 and 4. Use bank
                                  ; 0 and 1.
data_c2 EQU     0x12              ; Channel 2 data. Use bank 3.
pard_04 EQU     0x13              ; Parity and temp data for channel 0 and 4.
                                  ; Use bank 0 and 1.   
data_c3 EQU     0x13              ; Channel 3 data. Use bank 3.
st_15   EQU     0x14              ; State variables for channel 1 and 5. 
                                  ; Use bank 0, 1 and 2.
data_c4 EQU     0x14              ; Channel 4 data. Use bank 3.
data_15 EQU     0x15              ; Data out from channel 1 and 5. Use bank
                                  ; 0 and 1.
data_c5 EQU     0x15              ; Channel 5 data. Use bank 3.
bitc_15 EQU     0x16              ; Bitcounter for channel 1 and 5. Use bank
                                  ; 0 and 1.
data_c6 EQU     0x16              ; Channel 6 data. Use bank 3.
pard_15 EQU     0x17              ; Parity and temp data for channel 1 and 5.
                                  ; Use bank 0 and 1.   
data_c7 EQU     0x17              ; Channel 7 data. Use bank 3.
st_26   EQU     0x18              ; State variables for channel 2 and 6. 
                                  ; Use bank 0, 1 and 2.
time_c0 EQU     0x18              ; Timeout for channel 0. Use bank 3.
data_26 EQU     0x19              ; Data out from channel 2 and 6. Use bank
                                  ; 0 and 1.
time_c1 EQU     0x19              ; Timeout for channel 1. Use bank 3.
bitc_26 EQU     0x1a              ; Bitcounter for channel 2 and 6. Use bank
                                  ; 0 and 1.
time_c2 EQU     0x1a              ; Timeout for channel 2. Use bank 3.
pard_26 EQU     0x1b              ; Parity and temp data for channel 2 and 6.
                                  ; Use bank 0 and 1.   
time_c3 EQU     0x1b              ; Timeout for channel 3. Use bank 3.
st_37   EQU     0x1c              ; State variables for channel 3 and 7.
                                  ; Use bank 0, 1 and 2.
time_c4 EQU     0x1c              ; Timeout for channel 4. Use bank 3.
data_37 EQU     0x1d              ; Data out from channel 3 and 7. Use bank
                                  ; 0 and 1.
time_c5 EQU     0x1d              ; Timeout for channel 5. Use bank 3.
bitc_37 EQU     0x1e              ; Bitcounter for channel 3 and 7. Use bank
                                  ; 0 and 1.
time_c6 EQU     0x1e              ; Timeout for channel 6. Use bank 3.
pard_37 EQU     0x1f              ; Parity and temp data for channel 3 and 7.
                                  ; Use bank 0 and 1.   
time_c7 EQU     0x1f              ; Timeout for channel 7. Use bank 3.
                                 
;*---------- Program flag definitions. ----------*

send    EQU     0                 ; Set if there is data to be sent.
first   EQU     1                 ; Set if this is the first decoder in the
                                  ; chain.
repeat  EQU     2                 ; Set if incoming serial data should be 
                                  ; repeated.
carry   EQU     3                 ; Carry flag when incrementing decoder ID.
dout    EQU     txd               ; This bit should match the TxD bit in
                                  ; serport. 

;*---------- Constant definitions. ----------*

timeout_interval  EQU   0xc9      ; Gives 0.998 s time out. 
send_time         EQU   0x38      ; Gives 4.992 ms send interval.
init_wait         EQU   0xfa      ; gives 0.503 s initial start up wait. 

;init_wait         EQU   0x01      ; Use this to speed up simulations.   

;**********************************************************************
;* The program starts here after reset.
;**********************************************************************

        ORG     0x3FF             ; Processor reset vector.

        movlw   0x38              ; Oscillator calibration value.

        ORG     0x000             ; Coding begins here.

startofprog

        movwf   OSCCAL            ; Update register with factory cal. value. 
        clrf    FSR               ; Ensure FSR register points to Bank 0.   
        bsf     STATUS, PA0       ; Select upper bank. 
        goto    init_code         ; Jump to initialization code.
                     
;**********************************************************************
;* Receiver subroutine, scans all 8 channels.
;**********************************************************************

rec_cycle

;-------- Read ports. ----------*        

        swapf   port7_4, W            
        andlw   0xf0              ; Channel 4-7 inputs on bit 4-7.
        movwf   true_d
        movf    port3_0, W
        andlw   0x0f              ; Channel 0-3 inputs on bit 0-3.
        iorwf   true_d, F

;---------- Start with channel 0. ----------*

        movlw   0x10
        movwf   FSR               ; Set bank 0, prepare for bank shift.
        movf    st_04, W          
        movwf   PCL               ; Jump to current state for channel 0.

;---------- Return from receiver. ----------*

rec_cyc_end                       ; Constantly stored in st_04 for bank 2.

        retlw   0

;-----------------------------------------------------*
;---------- Channel 0 and 4 receive states. ----------*
;-----------------------------------------------------*

;---------- Starting state. ----------*

start_rec_04

        btfss   dav, 0            ; Wait here if old data not sent yet. 
        movlw   wait_start_04
        btfsc   true_d, 0        
        movwf   st_04             ; Save new state.
        movlw   5     
        movwf   bitc_04           ; Set up start symbol min length.
        bsf     STATUS, PA0       ; Select upper program bank.   
        movf    st_15, W
        movwf   PCL               ; Jump to channel 1 or 5 states.

;---------- Wait for start symbol. ----------*

wait_start_04
     
        movlw   startsym_04
        decfsz  bitc_04, F
        movlw   wait_start_04     ; Stay here for start symbol length. 
        btfss   true_d, 0
        movlw   start_rec_04      ; Go back if start symbol too short.
        movwf   st_04             ; Save new state.
        bsf     STATUS, PA0       ; Select upper program bank.
        movf    st_15, W
        movwf   PCL               ; Jump to channel 1 or 5 states.

;---------- Wait for start symbol to end. ----------*

startsym_04

        btfss   true_d, 0
        movlw   rec_st1_04        ; Jump here when start symbol ends. 
        movwf   st_04             ; Save new state.
        clrf    pard_04
        movlw   0x0a
        movwf   bitc_04
        bsf     STATUS, PA0       ; Select upper program bank.
        movf    st_15, W
        movwf   PCL               ; Jump to channel 1 or 5 states.
       
;---------- Shift data register, and set data bit to 0. ----------*

rec_st1_04

        rrf     data_04, F
        bcf     data_04, 7        ; Set data bit to 0.
        movlw   rec_st2_04

epilog1_04

        btfsc   true_d, 0
        movlw   rec_bit_end_04    ; End of bit found.          
        movwf   st_04             ; Save new state. 
        bsf     STATUS, PA0       ; Select upper program bank.
        movf    st_15, W
        movwf   PCL               ; Jump to channel 1 or 5 states.

;---------- Wait. ----------*

rec_st2_04

        movlw   rec_st3_04
        goto    epilog1_04 

;---------- Set data bit, and toggle parity. --------;

rec_st3_04

        bsf     data_04, 7        ; Set data bit.
        incf    pard_04, F        ; Toggle parity.
        movlw   rec_st4_04        
        btfsc   true_d, 0         
        movlw   rec_bit_end_04    ; End of bit found.
        movwf   st_04             ; Save new state.
        bsf     STATUS, PA0       ; Select upper program bank.
        movf    st_15, W
        movwf   PCL               ; Jump to channel 1 or 5 states.

;---------- Wait. ----------*

rec_st4_04

        movlw   rec_st5_04
        goto    epilog1_04

;---------- Wait. ----------*

rec_st5_04

        movlw   start_rec_04      ; Restart if bit is too long.   
        goto    epilog1_04

;---------- Count down number of bits. ----------*

rec_bit_end_04

        decf    bitc_04, F
        nop
        movlw   rec_st6_04

epilog2_04

        btfss   true_d, 0
        movlw   rec_st1_04        ; Jump here if new symbol.
        movwf   st_04             ; Save new state.
        bsf     STATUS, PA0       ; Select upper program bank.
        movf    st_15, W
        movwf   PCL               ; Jump to channel 1 or 5 states.

;---------- Wait. ----------*

rec_st6_04

        movlw   rec_st7_04
        goto    epilog2_04

;---------- Check number of bits. ----------*

rec_st7_04

        decfsz  bitc_04, F        ; Check number of bits.
        bcf     pard_04, 0        ; Clear parity if error.
        movlw   rec_st8_04

epilog3_04

        btfss   true_d, 0
        
epilog4_04

        movlw   start_rec_04
        movwf   st_04             ; Save new state.
        bsf     STATUS, PA0       ; Select upper program bank.
        movf    st_15, W
        movwf   PCL               ; Jump to channel 1 or 5 states.

;---------- Wait. ----------*

rec_st8_04

        movlw   rec_st9_04
        goto    epilog3_04

;---------- Check parity. ----------*

rec_st9_04

        movlw   rec_dav_04
        btfss   pard_04, 0        ; Check parity. Should be set if correct.
        movlw   startsym_04       ; Restart without looking for start pulse.   
        btfss   true_d, 0
        movlw   start_rec_04
        movwf   st_04             ; Save new state.
        bsf     STATUS, PA0       ; Select upper program bank.
        movf    st_15, W
        movwf   PCL               ; Jump to channel 1 or 5 states.

;---------- Set data available. ----------*

rec_dav_04

        nop
        bsf     dav, 0
        goto    epilog4_04   

;---------- End of states for channel 0 and 4.  ----------*
;---------- States for the rest of the channels ----------*
;---------- are in the other program bank.      ----------*  

;**********************************************************
;* Short delay loop. Delays 4 cycles.
;**********************************************************

short_delay

        retlw   0

;**********************************************************
;* Delay loop. Delays 4 *(W + 1) cycles.
;**********************************************************

wait_delay

        movwf   tmp

wait_loop

        nop
        decfsz  tmp, F
        goto    wait_loop
        retlw   0   

;**********************************************************
;* One bit delay, with appropriate calls to 'rec_cycle'.
;**********************************************************

wait_one_bit

        call    rec_cycle
        movlw   0x07
        call    wait_delay
        call    rec_cycle
        movlw   0x07
        call    wait_delay
        call    rec_cycle
        movlw   0x07
        call    wait_delay
        call    rec_cycle
        movlw   0x02
        call    wait_delay
        nop
        retlw   0                 ; t111-t112         

;**********************************************************
;* Main. 
;**********************************************************

;*---------- Wait here for start bit or time to send.    ----------*
;*---------- Must be within the first 256 lines of code. ----------*

main_wait_start

        call    rec_cycle         ; t0-t96      
        btfsc   flags, send        
        goto    main_data_found   ; t98-t99   
        incf    ch_nr, F
        bcf     ch_nr, 3
        movf    ch_nr, W 
        addwf   PCL, F            ; Switch (ch_nr)... ; t102-t103
        goto    main_check_ch0    ; t104-t105
        goto    main_check_ch1
        goto    main_check_ch2
        goto    main_check_ch3
        goto    main_check_ch4
        goto    main_check_ch5
        goto    main_check_ch6
        goto    main_check_ch7  

;*---------- Check data available for channel 0. ----------*
 
main_check_ch0               ; This label must be <= 256 (<= 0x100)

        btfss   dav, 0
        goto    main_no_dav       ; t107-t108  
        bcf     dav, 0
        clrf    FSR
        movf    data_04, W
        movwf   ch_data
        bsf     FSR, 5
        bsf     FSR, 6            ; Select bank 3.
        xorwf   data_c0, W        ; Compare with previous data.
        decfsz  time_c0, W        ; Check if previous data timed out. 
        btfss   STATUS, Z         ; Skip if same data and not timed out.
        bsf     flags, send
        goto    main_check_start  ; t118-t119 

;*---------- Check data available for channel 1. ----------* 

main_check_ch1

        btfss   dav, 1
        goto    main_no_dav       ; t107-t108  
        bcf     dav, 1
        clrf    FSR
        movf    data_15, W
        movwf   ch_data
        bsf     FSR, 5
        bsf     FSR, 6            ; Select bank 3.
        xorwf   data_c1, W        ; Compare with previous data.
        decfsz  time_c1, W        ; Check if previous data timed out. 
        btfss   STATUS, Z         ; Skip if same data and not timed out.
        bsf     flags, send
        goto    main_check_start  ; t118-t119 

;*---------- Check data available for channel 2. ----------*

main_check_ch2

        btfss   dav, 2
        goto    main_no_dav       ; t107-t108  
        bcf     dav, 2
        clrf    FSR
        movf    data_26, W
        movwf   ch_data
        bsf     FSR, 5
        bsf     FSR, 6            ; Select bank 3.
        xorwf   data_c2, W        ; Compare with previous data.
        decfsz  time_c2, W        ; Check if previous data timed out. 
        btfss   STATUS, Z         ; Skip if same data and not timed out.
        bsf     flags, send
        goto    main_check_start  ; t118-t119

;*---------- Check data available for channel 3. ----------*

main_check_ch3

        btfss   dav, 3
        goto    main_no_dav       ; t107-t108  
        bcf     dav, 3
        clrf    FSR
        movf    data_37, W
        movwf   ch_data
        bsf     FSR, 5
        bsf     FSR, 6            ; Select bank 3.
        xorwf   data_c3, W        ; Compare with previous data.
        decfsz  time_c3, W        ; Check if previous data timed out. 
        btfss   STATUS, Z         ; Skip if same data and not timed out.
        bsf     flags, send
        goto    main_check_start  ; t118-t119 

;*---------- Check data available for channel 4. ----------*

main_check_ch4

        btfss   dav, 4
        goto    main_no_dav       ; t107-t108  
        bcf     dav, 4
        clrf    FSR
        bsf     FSR, 5 
        movf    data_04, W
        movwf   ch_data
        bsf     FSR, 6            ; Select bank 3.
        xorwf   data_c4, W        ; Compare with previous data.
        decfsz  time_c4, W        ; Check if previous data timed out. 
        btfss   STATUS, Z         ; Skip if same data and not timed out.
        bsf     flags, send
        goto    main_check_start  ; t118-t119

;*---------- Check data available for channel 5. ----------*

main_check_ch5

        btfss   dav, 5
        goto    main_no_dav       ; t107-t108  
        bcf     dav, 5
        clrf    FSR
        bsf     FSR, 5 
        movf    data_15, W
        movwf   ch_data
        bsf     FSR, 6            ; Select bank 3.
        xorwf   data_c5, W        ; Compare with previous data.
        decfsz  time_c5, W        ; Check if previous data timed out. 
        btfss   STATUS, Z         ; Skip if same data and not timed out.
        bsf     flags, send
        goto    main_check_start  ; t118-t119 

;*---------- Check data available for channel 6. ----------*

main_check_ch6

        btfss   dav, 6
        goto    main_no_dav       ; t107-t108  
        bcf     dav, 6
        clrf    FSR
        bsf     FSR, 5 
        movf    data_26, W
        movwf   ch_data
        bsf     FSR, 6            ; Select bank 3.
        xorwf   data_c6, W        ; Compare with previous data.
        decfsz  time_c6, W        ; Check if previous data timed out. 
        btfss   STATUS, Z         ; Skip if same data and not timed out.
        bsf     flags, send
        goto    main_check_start  ; t118-t119 ; 

;*---------- Check data available for channel 7. ----------*

main_check_ch7

        btfss   dav, 7
        goto    main_no_dav       ; t107-t108  
        bcf     dav, 7
        clrf    FSR
        bsf     FSR, 5 
        movf    data_37, W
        movwf   ch_data
        bsf     FSR, 6            ; Select bank 3.
        xorwf   data_c7, W        ; Compare with previous data.
        decfsz  time_c7, W        ; Check if previous data timed out. 
        btfss   STATUS, Z         ; Skip if same data and not timed out.
        bsf     flags, send
        goto    main_check_start  ; t118-t119 ; 

;*---------- Check for start bit or time to send. ----------*

main_data_found                   ; Channel with data was found before.

        movlw   1                 ; t100
        call    wait_delay        ; t101-t108
   
main_no_dav                       ; No channel has data.
                  
        movlw   1                 ; t109
        call    wait_delay        ; t110-t117
        goto    main_check_start  ; t118-t119
  
main_check_start                  ; Channel with data was found now.                   

        btfsc   serport, rxd      ; Check for start bit. ; t120
        decfsz  tr_time, F        ; Check for send time if first in chain.
        goto    main_wait_more    ; t122-123          
        nop                      
        call    short_delay       ; t124-t127 
        goto    main_start_send   ; t128-t129

main_wait_more

        call    short_delay       ; t124-t127 
        goto    main_wait_start   ; t128-t129
         
;*-----------------------------------*  
;*---------- Time to send. ----------*
;*-----------------------------------*

main_start_send
                
        call    rec_cycle         ; t0-t96
        movlw   0x06
        call    wait_delay
        nop 
        bsf     serport, txd      ; t127
        call    wait_one_bit      ; t128-t112
        bcf     flags, repeat     ; Assume we should send.
        bcf     flags, dout       ; Assume logical 1 = valid message.
        btfsc   flags, first      
        goto    always_send       ; We are first in the chain ; t116-t117 
        btfsc   flags, send
        goto    send_bit0_as_1    ; We are not first, but have data to send. 
        bsf     flags, repeat     ; We are not first, and have no data.                        
        btfsc   serport, rxd      ; t120
        bsf     flags, dout       ; repeat data in.
        nop
        nop 
        goto    send_bit0_out     ; t124-t125

always_send

        btfss   flags, send
        bsf     flags, dout       ; set logical 0 if we don't have data.
        goto    send_bit0         ; t120-t121
  
send_bit0_as_1

        btfss   serport, rxd      ; t120
        bsf     flags, repeat     ; Repeat data in if the data is valid.

send_bit0

        call    short_delay       ; t122-t125

send_bit0_out

        movf    flags, W
        movwf   serport           ; Moves flags, dout => serport, txd. ; t127 
        call    wait_one_bit      ; t128-t112
        btfsc   flags, repeat
        goto    main_repeat       ; t114-t115 
 
;*---------- Here we send our own data. ----------*

        movlw   0x80              ; Seven bits of 0 plus a stop bit.
        movwf   tr_data          
        movlw   0x09              ; Seven data bits and two stop bits.
        movwf   bitcnt            ; t118

send_id0
           
        call    short_delay       ; t119-t122
        bsf     flags, dout
        btfsc   tr_data, 0
        bcf     flags, dout
        movf    flags, W
        movwf   serport           ; t127
        call    wait_one_bit      ; t128-t112
        bsf     STATUS, C         ; Set stop bits.
        rrf     tr_data, F        ; Next bit.
        nop
        decfsz  bitcnt, F
        goto    send_id0          ; t117-t118     
        movlw   1               
        call    wait_delay        ; t119-t126  
        bsf     serport, txd      ; Send start bit.
        call    wait_one_bit      ; t128-t112
        movlw   0xff
        btfsc   flags, send
        movf    ch_nr, W 
        movwf   tr_data           ; Send channel number or 0xff 
        movlw   0x0a
        movwf   bitcnt            ; t118  
         
send_ch_nr 

        call    short_delay
        bsf     flags, dout
        btfsc   tr_data, 0
        bcf     flags, dout
        movf    flags, W
        movwf   serport           ; t127
        call    wait_one_bit      ; t128-t112
        bsf     STATUS, C         ; Set stop bits.
        rrf     tr_data, F        ; Next bit.
        nop
        decfsz  bitcnt, F
        goto    send_ch_nr        ; t117-t118
        movlw   1               
        call    wait_delay        ; t119-t126  
        bsf     serport, txd      ; Send start bit.
        call    wait_one_bit      ; t128-t112
        movlw   0x0a
        movwf   bitcnt            ; t114
        movf    ch_data, W 
        btfss   flags, send 
        goto    send_ff_data      ; t117-t118
        movwf   tr_data           ; Send channel data ; t118

send_ch_data 

        call    short_delay
        bsf     flags, dout
        btfsc   tr_data, 0
        bcf     flags, dout
        movf    flags, W
        movwf   serport           ; t127
        call    wait_one_bit      ; t128-t112
        bsf     STATUS, C         ; Set stop bits.
        rrf     tr_data, F        ; Next bit.
        nop
        decfsz  bitcnt, F
        goto    send_ch_data      ; t117-t118
        bcf     flags, send       ; Data sent now, take down flag.        
        movlw   (0x60 + data_c0)  ; t119
        addwf   ch_nr, W
        movwf   FSR               ; Point to saved data for selected channel.
        movf    ch_data, W
        movwf   INDF              ; Save data for later reference. 
        movlw   0x08
        addwf   FSR, F            ; Point to timeout for selected channel.  
        movlw   timeout_interval   
        movwf   INDF              ; Start timeout for detected channel. ; t127
        goto    main_after_send   ; t128-t129

send_ff_data 

        call    short_delay       ; t119-t122
        call    short_delay       ; t123-t126 
        bcf     serport, txd      ; Logical one ; t127     
        call    wait_one_bit      ; t128-t112
        nop
        nop
        nop
        decfsz  bitcnt, F
        goto    send_ff_data      ; t117-t118
        nop        
        movlw   1
        call    wait_delay
        goto    main_after_send   ; t128-t129

;*---------- Here we repeat received serial data. ----------*

main_repeat

        movlw   0x1f              ; Number of bits to repeat. ; t116
                                  ; 7 data + 2 stop + 1 start + 8 data + 
                                  ; 2 stop + 1 start + 8 data + 2 stop =
                                  ; 31 bits = 0x1f hex.
        movwf   bitcnt
        bsf     flags, carry      ; t118 

send_repeat
             
        bsf     flags, dout
        btfss   serport, rxd      ; t120 
        bcf     flags, dout  
        movf    flags, W
        btfsc   flags, carry
        comf    flags, W          ; Add carry.
        btfsc   flags, dout
        bcf     flags, carry      ; Clear carry out if data in is logical 0.
        movwf   serport           ; Send out data   ; t127
        call    wait_one_bit      ; t128-t112
        nop
        nop
        nop
        decfsz  bitcnt, F
        goto    send_repeat       ; t117-t118
        bcf     serport, txd      ; Recovery if data in was corrupt. 
        movlw   0x01
        call    wait_delay        ; t120-t127
        goto    main_after_send   ; t128-t129       

;*-----------------------------------*  
;*---------- After sending.----------*
;*-----------------------------------*

;*---------- Decrement channel timeouts. Remove dav ----------*
;*---------- if a repeated code is received.        ----------* 

main_after_send

        call    rec_cycle         ; t0-t96 
        bsf     FSR, 5
        bsf     FSR, 6            ; Select bank 3.
        decfsz  time_c0, W        ; Decrement timeouts for channel 0-5 
        decf    time_c0, F
        decfsz  time_c1, W
        decf    time_c1, F
        decfsz  time_c2, W
        decf    time_c2, F
        decfsz  time_c3, W
        decf    time_c3, F       
        decfsz  time_c4, W
        decf    time_c4, F
        decfsz  time_c5, W
        decf    time_c5, F        
        clrf    FSR               ; Remove repeated code for channel 0.
        movf    data_04, W
        bsf     FSR, 5
        bsf     FSR, 6
        xorwf   data_c0, W
        decfsz  time_c0, W
        btfss   STATUS, Z
        goto    keep_dav0
        bcf     dav, 0            ; t119 
        
keep_dav0

        clrf    FSR               ; Remove repeated code for channel 1.
        movf    data_15, W   
        bsf     FSR, 5
        bsf     FSR, 6 
        xorwf   data_c1, W
        decfsz  time_c1, W
        btfss   STATUS, Z
        goto    keep_dav1
        bcf     dav, 1            ; t128 
        
keep_dav1         
        
        nop
        call    rec_cycle         ; Time to call receiver ; t0-t96  
        clrf    FSR               ; Remove repeated code for channel 2.
        movf    data_26, W   
        bsf     FSR, 5
        bsf     FSR, 6
        xorwf   data_c2, W
        decfsz  time_c2, W
        btfss   STATUS, Z
        goto    keep_dav2
        bcf     dav, 2            ; t105 
      
keep_dav2         

        clrf    FSR               ; Remove repeated code for channel 3.
        movf    data_37, W   
        bsf     FSR, 5
        bsf     FSR, 6 
        xorwf   data_c3, W
        decfsz  time_c3, W
        btfss   STATUS, Z
        goto    keep_dav3
        bcf     dav, 3            ; t114 
        
keep_dav3         

        bcf     FSR, 6            ; Remove repeated code for channel 4.  
        movf    data_04, W
        bsf     FSR, 6   
        xorwf   data_c4, W        ; Half done.  
        bcf     flags, first      ; Check serial in here; t119       
        btfsc   serport, rxd      ; First in chain if rxd is high. ;t 120 
        bsf     flags, first      ; Serial in checked.
        decfsz  time_c4, W        ; Continue remove repeated code for ch. 4.
        btfss   STATUS, Z
        goto    keep_dav4         
        bcf     dav, 4            ; t125
   
keep_dav4   

        movlw   0x01              ; Remove repeated code for channel 5. 
        btfsc   flags, first
        movlw   send_time
        movwf   tr_time           ; t129
        call    rec_cycle         ; Time to call receiver. t0-t96
        clrf    FSR
        bsf     FSR, 5
        movf    data_15, W
        bsf     FSR, 6   
        xorwf   data_c5, W
        decfsz  time_c5, W
        btfss   STATUS, Z
        goto    keep_dav5    
        bcf     dav, 5            ; t105

keep_dav5   

        decfsz  time_c6, W        ; Decrement timeouts for channel 6-7.
        decf    time_c6, F
        decfsz  time_c7, W
        decf    time_c7, F        ; t109
        bcf     FSR, 6            ; Remove repeated code for channel 6.  
        movf    data_26, W
        bsf     FSR, 6   
        xorwf   data_c6, W
        decfsz  time_c6, W
        btfss   STATUS, Z
        goto    keep_dav6    
        bcf     dav, 6            ; t117

keep_dav6   

        bcf     FSR, 6            ; Remove repeated code for channel 7.
        movf    data_37, W
        bsf     FSR, 6   
        xorwf   data_c7, W
        decfsz  time_c7, W
        btfss   STATUS, Z
        goto    keep_dav7    
        bcf     dav, 7            ; t125
       
keep_dav7   

        nop
        nop       
        goto    main_wait_start   ; t128-t129

;**********************************************************************
;* Upper bank part of receiver subroutine.
;**********************************************************************

        ORG     0x200

;--------------------------------------*
;---------- Channel 1 and 5. ----------*
;--------------------------------------*

;---------- Starting state. ----------*

start_rec_15

        btfss   dav, 1            ; Wait here if old data not sent yet. 
        movlw   wait_start_15 
        btfsc   true_d, 1        
        movwf   st_15             ; Save new state.
        movlw   5     
        movwf   bitc_15           ; Set up start symbol min length.
        movf    st_26, W
        movwf   PCL               ; Jump to channel 2 or 6 states.

;---------- Wait for start symbol. ----------*

wait_start_15
     
        movlw   startsym_15
        decfsz  bitc_15, F
        movlw   wait_start_15     ; Stay here for start symbol length. 
        btfss   true_d, 1
        movlw   start_rec_15      ; Go back if start symbol too short.
        movwf   st_15             ; Save new state.
        movf    st_26, W
        movwf   PCL               ; Jump to channel 2 or 6 states.

;---------- Wait for start symbol to end. ----------*

startsym_15

        btfss   true_d, 1
        movlw   rec_st1_15        ; Jump here when start symbol ends. 
        movwf   st_15             ; Save new state.
        clrf    pard_15
        movlw   0x0a
        movwf   bitc_15
        movf    st_26, W
        movwf   PCL               ; Jump to channel 2 or 6 states.
       
;---------- Shift data register, and set data bit to 0. ----------*

rec_st1_15

        rrf     data_15, F
        bcf     data_15, 7        ; Set data bit to 0. 
        movlw   rec_st2_15

epilog1_15

        btfsc   true_d, 1
        movlw   rec_bit_end_15    ; End of bit found. 
        movwf   st_15             ; Save new state.  
        movf    st_26, W
        movwf   PCL               ; Jump to channel 2 or 6 states.

;---------- Wait. ----------*

rec_st2_15

        movlw   rec_st3_15
        goto    epilog1_15    

;---------- Set data bit, and toggle parity. ----------*

rec_st3_15

        bsf     data_15, 7        ; Set data bit.
        incf    pard_15, F        ; Toggle parity.
        movlw   rec_st4_15 
        btfsc   true_d, 1
        movlw   rec_bit_end_15    ; End of bit found.
        movwf   st_15             ; Save new state.
        movf    st_26, W
        movwf   PCL               ; Jump to channel 2 or 6 states.

;---------- Wait. ----------*

rec_st4_15

        movlw   rec_st5_15
        goto    epilog1_15    

;---------- Wait. ----------*

rec_st5_15

        movlw   start_rec_15      ; Restart if bit is too long.
        goto    epilog1_15    

;---------- Count down number of bits. ----------*

rec_bit_end_15

        decf    bitc_15, F
        nop   
        movlw   rec_st6_15

epilog2_15

        btfss   true_d, 1
        movlw   rec_st1_15        ; Jump here if new symbol.
        movwf   st_15             ; Save new state.
        movf    st_26, W
        movwf   PCL               ; Jump to channel 2 or 6 states.

;---------- Wait. ----------*

rec_st6_15

        movlw   rec_st7_15
        goto    epilog2_15

;---------- Check number of bits. ----------*

rec_st7_15

        decfsz  bitc_15, F        ; Check number of bits.
        bcf     pard_15, 0        ; Clear parity if error.   
        movlw   rec_st8_15

epilog3_15

        btfss   true_d, 1

epilog4_15

        movlw   start_rec_15
        movwf   st_15             ; Save new state. 
        movf    st_26, W
        movwf   PCL               ; Jump to channel 2 or 6 states.

;---------- Wait. ----------*

rec_st8_15
   
        movlw   rec_st9_15
        goto    epilog3_15

;---------- Check parity. ----------*

rec_st9_15

        movlw   rec_dav_15
        btfss   pard_15, 0        ; Check parity, Should be set if correct. 
        movlw   startsym_15       ; Restart without looking for start pulse.
        btfss   true_d, 1        
        movlw   start_rec_15   
        movwf   st_15             ; Save new state.
        movf    st_26, W
        movwf   PCL               ; Jump to channel 2 or 6 states.

;---------- Set data available. ----------*

rec_dav_15

        nop
        bsf     dav, 1
        goto    epilog4_15 

;--------------------------------------*
;---------- Channel 2 and 6. ----------*
;--------------------------------------*

;---------- Starting state. ----------*

start_rec_26

        btfss   dav, 2            ; Wait here if old data not sent yet. 
        movlw   wait_start_26
        btfsc   true_d, 2        
        movwf   st_26             ; Save new state.
        movlw   5     
        movwf   bitc_26           ; Set up start symbol min length.
        movf    st_37, W
        movwf   PCL               ; Jump to channel 3 or 7 states.

;---------- Wait for start symbol. ----------*

wait_start_26
     
        movlw   startsym_26
        decfsz  bitc_26, F
        movlw   wait_start_26     ; Stay here for start symbol length. 
        btfss   true_d, 2
        movlw   start_rec_26      ; Go back if start symbol too short.
        movwf   st_26             ; Save new state.
        movf    st_37, W
        movwf   PCL               ; Jump to channel 3 or 7 states.

;---------- Wait for start symbol to end. ----------*

startsym_26

        btfss   true_d, 2
        movlw   rec_st1_26        ; Jump here when start symbol ends. 
        movwf   st_26             ; Save new state.
        clrf    pard_26
        movlw   0x0a
        movwf    bitc_26
        movf    st_37, W
        movwf   PCL               ; Jump to channel 3 or 7 states.
       
;---------- Shift data register, and set data bit to 0. ----------*

rec_st1_26

        rrf     data_26, F
        bcf     data_26, 7        ; Set data bit to 0. 
        movlw   rec_st2_26

epilog1_26

        btfsc   true_d, 2
        movlw   rec_bit_end_26    ; End of bit found. 
        movwf   st_26             ; Save new state.  
        movf    st_37, W
        movwf   PCL               ; Jump to channel 3 or 7 states.

;---------- Wait. ----------*

rec_st2_26

        movlw   rec_st3_26
        goto    epilog1_26

;---------- Set data bit, and toggle parity. ----------*

rec_st3_26

        bsf     data_26, 7        ; Set data bit.
        incf    pard_26, F        ; Toggle parity.
        movlw   rec_st4_26 
        btfsc   true_d, 2
        movlw   rec_bit_end_26    ; End of bit found.
        movwf   st_26             ; Save new state.
        movf    st_37, W
        movwf   PCL               ; Jump to channel 3 or 7 states.

;---------- Wait. ----------*

rec_st4_26

        movlw   rec_st5_26
        goto    epilog1_26

;---------- Wait. ----------*

rec_st5_26

        movlw   start_rec_26      ; Restart if bit is too long. 
        goto    epilog1_26

;---------- Count down number of bits. ----------*

rec_bit_end_26

        decf    bitc_26, F
        nop
        movlw   rec_st6_26

epilog2_26

        btfss   true_d, 2
        movlw   rec_st1_26        ; Jump here if new symbol.
        movwf   st_26             ; Save new state.
        movf    st_37, W
        movwf   PCL               ; Jump to channel 3 or 7 states.

;---------- Wait. ----------*

rec_st6_26

        movlw   rec_st7_26
        goto    epilog2_26

;---------- Check number of bits. ----------*

rec_st7_26

        decfsz  bitc_26, F        ; Check number of bits.
        bcf     pard_26, 0        ; Clear parity if error. 
        movlw   rec_st8_26

epilog3_26

        btfss   true_d, 2

epilog4_26

        movlw   start_rec_26     
        movwf   st_26             ; Save new state.
        movf    st_37, W
        movwf   PCL               ; Jump to channel 3 or 7 states.

;---------- Wait. ----------*

rec_st8_26

        movlw   rec_st9_26
        goto    epilog3_26

;---------- Check polarity. ----------*

rec_st9_26

        movlw   rec_dav_26
        btfss   pard_26, 0        ; Check parity. Should be set if correct.
        movlw   startsym_26       ; Restart without looking for start pulse.
        btfss   true_d, 2
        movlw   start_rec_26 
        movwf   st_26             ; Save new state.
        movf    st_37, W
        movwf   PCL               ; Jump to channel 3 or 7 states.
   
;---------- Set data available. ----------*

rec_dav_26

        nop
        bsf     dav, 2
        goto    epilog4_26   

;--------------------------------------*
;---------- Channel 3 and 7. ----------*
;--------------------------------------*

;---------- Starting state. ----------*

start_rec_37

        btfss   dav, 3            ; Wait here if old data not sent yet. 
        movlw   wait_start_37
        btfsc   true_d, 3        
        movwf   st_37             ; Save new state.
        movlw   5     
        movwf   bitc_37           ; Set up start symbol min length.
        bcf     STATUS, PA0       ; Select lower program bank.
        rlf     FSR, F
        swapf   true_d, F
        swapf   dav, F   
        movf    st_04, W
        movwf   PCL               ; Jump to channel 4 or end states.

;---------- Wait for start symbol. ----------*

wait_start_37
     
        movlw   startsym_37
        decfsz  bitc_37, F
        movlw   wait_start_37     ; Stay here for start symbol length. 
        btfss   true_d, 3
        movlw   start_rec_37      ; Go back if start symbol too short.
        movwf   st_37             ; Save new state.
        bcf     STATUS, PA0       ; Select lower program bank.
        rlf     FSR, F
        swapf   true_d, F
        swapf   dav, F   
        movf    st_04, W
        movwf   PCL               ; Jump to channel 4 or end states.

;---------- Wait for start symbol to end. ----------*

startsym_37

        btfss   true_d, 3
        movlw   rec_st1_37        ; Jump here when start symbol ends. 
        movwf   st_37             ; Save new state.
        clrf    pard_37
        movlw   0x0a
        movwf    bitc_37
        bcf     STATUS, PA0       ; Select lower program bank.
        rlf     FSR, F
        swapf   true_d, F
        swapf   dav, F   
        movf    st_04, W
        movwf   PCL               ; Jump to channel 4 or end states.
       
;---------- Shift data register, and set data bit to 0. ----------*

rec_st1_37

        rrf     data_37, F
        bcf     data_37, 7        ; Set data bit to 0.
        movlw   rec_st2_37

epilog1_37

        btfsc   true_d, 3
        movlw   rec_bit_end_37    ; End of bit found. 
        movwf   st_37             ; Save new state 
        bcf     STATUS, PA0       ; Select lower program bank.
        rlf     FSR, F
        swapf   true_d, F
        swapf   dav, F   
        movf    st_04, W
        movwf   PCL               ; Jump to channel 4 or end states.

;---------- Wait. ----------*

rec_st2_37

        movlw   rec_st3_37
        goto    epilog1_37

;---------- Set data bit, and toggle parity. ----------;

rec_st3_37

        bsf     data_37, 7        ; Set data bit.
        incf    pard_37, F        ; Toggle parity.
        movlw   rec_st4_37 
        btfsc   true_d, 3
        movlw   rec_bit_end_37    ; End of bit found.
        movwf   st_37             ; Save new state.
        bcf     STATUS, PA0       ; Select lower program bank.
        rlf     FSR, F
        swapf   true_d, F
        swapf   dav, F   
        movf    st_04, W
        movwf   PCL               ; Jump to channel 4 or end states.

;---------- Wait. ----------*

rec_st4_37

        movlw   rec_st5_37
        goto    epilog1_37

;---------- Wait. ----------*

rec_st5_37

        movlw   start_rec_37      ; Restart if bit is too long.
        goto    epilog1_37

;---------- Count down number of bits. ----------*

rec_bit_end_37

        decf    bitc_37, F
        nop
        movlw   rec_st6_37

epilog2_37

        btfss   true_d, 3
        movlw   rec_st1_37        ; Jump here if new symbol.
        movwf   st_37             ; Save new state.
        bcf     STATUS, PA0       ; Select lower program bank.
        rlf     FSR, F
        swapf   true_d, F
        swapf   dav, F   
        movf    st_04, W
        movwf   PCL               ; Jump to channel 4 or end states.

;---------- Wait. ----------*

rec_st6_37

        movlw   rec_st7_37     
        goto    epilog2_37

;---------- Check number of bits. ----------*

rec_st7_37

        decfsz  bitc_37, F        ; Check number of bits.
        bcf     pard_37, 0        ; Clear parity if error.   
        movlw   rec_st8_37

epilog3_37

        btfss   true_d, 3

epilog4_37

        movlw   start_rec_37     
        movwf   st_37             ; Save new state.
        bcf     STATUS, PA0       ; Select lower program bank.
        rlf     FSR, F
        swapf   true_d, F
        swapf   dav, F   
        movf    st_04, W
        movwf   PCL               ; Jump to channel 4 or end states.

;---------- Wait. ----------*

rec_st8_37

        movlw   rec_st9_37     
        goto    epilog3_37

;---------- Set data available. ----------*

rec_dav_37

        nop
        bsf     dav, 3
        goto    epilog4_37 

;---------- Check parity. ----------*

rec_st9_37

        movlw   rec_dav_37
        btfss   pard_37, 0        ; Check parity. Should be set if correct.
        movlw   startsym_37       ; Restart without looking for start pulse.
        btfss   true_d, 3
        movlw   start_rec_37
        movwf   st_37             ; Save new state.
        bcf     STATUS, PA0       ; Select upper program bank.
        rlf     FSR, F
        swapf   true_d, F
        swapf   dav, F   
        movf    st_04, W
        movwf   PCL               ; Jump to channel 4 or end states.

;**********************************************************
;* Initialization code.
;**********************************************************

init_code

;-------- Initialize ports and timer. ----------*

        movlw   0xc7              ; Timer prescaler = 256.
        option
        clrf    serport           ; Set serial out to stop bit.
        movlw   0xef
        tris    serport           ; Enable serial port out.  
 
;---------- Initialize receive state variables. ----------*       

        movlw   start_rec_04
        movwf   st_04
        bsf     FSR, 5            ; Change to bank 1.
        movwf   st_04
        movlw   start_rec_15 
        movwf   st_15
        bcf     FSR, 5
        movwf   st_15
        movlw   start_rec_26
        movwf   st_26
        bsf     FSR, 5
        movwf   st_26
        movlw   start_rec_37
        movwf   st_37
        bcf     FSR, 5
        movwf   st_37
        bsf     FSR, 6            ; Change to bank 2.
        movlw   rec_cyc_end
        movwf   st_04

;---------- Initialize data registers. ----------*

        clrf    dav
        clrf    true_d   
        clrf    ch_nr
        clrf    flags  
        bsf     FSR, 5            ; Change to bank 3.
        movlw   0x01
        movwf   tr_time 
        movwf   time_c0 
        movwf   time_c1
        movwf   time_c2 
        movwf   time_c3 
        movwf   time_c4 
        movwf   time_c5 
        movwf   time_c6 
        movwf   time_c7 

;*---------- Check serial input, and wait 0.5 s if high. ----------*

init_delay_start

        movlw   0x0a
        movwf   tr_data        

init_delay_2  

        movlw   init_wait
        movwf   bitcnt


init_delay_3

        nop 
        movlw   0xc7
        movwf   tmp

init_delay_4

        btfss   serport, rxd
        goto    endofinit         ; Upstream decoder detected, start receive.     
        decfsz  tmp, F
        goto    init_delay_4                    
        decfsz  bitcnt, F
        goto    init_delay_3
        decfsz  tr_data, F
        goto    init_delay_2
        bsf     flags, first

endofinit

        bcf     STATUS, PA0       ; Jump to lower program bank.  
        goto    main_wait_start   ; This is the first decoder, start to send. 

endofprog

        END                       ; directive 'end of program'


























