;**********************************************************************
;    Filename:        irsend.asm                                      *
;    Date:            2002-02-22                                      *
;    File Version:    1.0                                             *
;                                                                     *
;    Author:          Per Zander                                      *
;**********************************************************************
;    Files required:  p12c508a.inc                                    *
;********************************************************************** 
;
; Description:
;
; IR transmitter program for a model train recognition system.
; The transmitter sends an 8-bit code on GP0, and the same code,  
; but with inverted bit 7, on GP1.
;
; Each data sequence consists of one parity bit, followed by the 
; eight data bits, least significant bit first. The parity is such 
; that there is an odd number of '1's, including the parity bit 
; itself.
;
; The data is sent as 'LED off' pulses, which corresponds to high
; outputs on GP0 and GP1. A '0' or a '1' is coded by the length 
; of the pulses, where a '0' is 38 instruction cycles and a '1' is
; 102 instruction cycles. The 'LED on' time between the data bits
; are 38 instruction cycles, and the 'LED on' pause between two 
; consecutive data sequences is between 178 and 306 instruction cycles,
; depending on the value of bit 7 and the parity bit.
;
; The processor runs from its internal RC oscillator, which gives a
; nominal instruction length of 1 microsecond.
;
;**********************************************************************

;*---------- Device address, change for each unit. ----------*

my_addr EQU     0x0a                ; Decimal 10.

;*---------- Device select. ----------*

	  list      p=12c508a        ; List directive to define processor
	  #include <p12c508a.inc>    ; Processor specific variable definitions

;*---------- Configuration specification. ----------*

	  __CONFIG   _CP_OFF & _WDT_OFF & _MCLRE_ON & _IntRC_OSC                   

;*---------- Variable definitions. ----------*

addr    EQU     0x08               ; My address.
loopc   EQU     0x09               ; Counter variable in the wait loop. 
parity  EQU     0x0a               ; Parity bit (bit 0 in register).

;**********************************************************************
;* The program starts here after reset.
;**********************************************************************

;*---------- Skip Osc. cal. value if not UV erasable. ----------*

;       ORG     0x3FF             ; Processor reset vector.

;       movlw   0x38              ; Osc. cal. value.

;*---------- Real start of program. ----------*

        ORG     0x000             ; Coding begins here.

startofprog

        movwf   OSCCAL            ; Update register with factory cal value.  
        goto    init_code         ; Jump over a few words to enable
                                  ; reprogramming.
        ORG     0x008

;**********************************************
;*---------- Delay loop subroutine. ----------*
;**********************************************

;---------- Delays 4(W + 1) clock cycles. ----------*

wait_sub

        movwf   loopc

wait_loop

        nop
        decfsz  loopc, F
        goto    wait_loop
        retlw   0xff 

;************************************
;*---------- Get address. ----------*
;************************************

;---------- This allows for many address changes. ----------*
;---------- Replace the current 'movlw my_addr'   ----------*
;---------- with 'nop', and replace the last      ----------*
;---------- 'xorlw 0xff' with a 'movlw' with the  ----------*
;---------- new address.                          ----------*
 
        ORG     0x80

get_addr

        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff
        xorlw   0xff 
        movlw   my_addr
        goto    got_addr  
        
;******************************************
;*---------- Main program loop. ----------*
;******************************************

start_bit
       
;---------- Start bit. ----------*                
 
        clrf     GPIO            ; Turn on LED.   ; t0
        goto    get_addr         ; t1-t133

got_addr

        movwf   addr 
        movwf   parity           ; Parity calculation              
        rrf     parity, F
        addwf   parity, W            
        rrf     parity, F
        addwf   parity, W 
        rrf     parity, F
        addwf   parity, W            
        rrf     parity, F
        addwf   parity, W 
        rrf     parity, F
        addwf   parity, W            
        rrf     parity, F
        addwf   parity, W 
        rrf     parity, F
        addwf   parity, F       ; Bit 0 contains inverse of send parity.
        movlw   0x5             ; t150
        call    wait_sub        ; t151-t174 ; line 38

;---------- Parity bit. ----------*

parity_bit

        movlw   2
        btfsc   parity, 0
        movlw   1               ; t177

parity1
  
        movwf   GPIO            ; Turn off LED. ; t0
        movlw   0x0e                 
        call    wait_sub
        nop
        movlw   0xff      

parity2

        movwf   GPIO            ; Both led off
        movlw   0x08
        call    wait_sub          
        clrf     GPIO            ; Turn on LED. ; t0  
        movlw   0x08            ; t1
        call    wait_sub        ; t2-t37

;---------- Bit 0. ----------*

bit0

        movwf   GPIO            ; Turn off LED.
        movlw   0x07            ; Value in case of sending a '0'.     
        btfss   addr, 0         ; Test bit 0.
        goto    d0 
        movlw   0x17            ; Value in case of sending a '1'.     

d0

        nop                     ; t5  
        call    wait_sub        ; t6-t37 or t6-t101  
        clrf    GPIO            ; Turn on LED. ; t0  
        movlw   0x08            ; t1
        call    wait_sub        ; t2-t37

;---------- Bit 1. ----------*

bit1

        movwf   GPIO            ; Turn off LED.
        movlw   0x07            ; Value in case of sending a '0'.     
        btfss   addr, 1         ; Test bit 1.
        goto    d1 
        movlw   0x17            ; Value in case of sending a '1'.     

d1

        nop                     ; t5 
        call    wait_sub        ; t6-t37 or t6-t101  
        clrf    GPIO            ; Turn on LED. ; t0  
        movlw   0x08            ; t1
        call    wait_sub        ; t2-t37

;---------- Bit 2. ----------*

bit2

        movwf   GPIO            ; Turn off LED.
        movlw   0x07            ; Value in case of sending a '0'.     
        btfss   addr, 2         ; Test bit 2.
        goto    d2 
        movlw   0x17            ; Value in case of sending a '1'.     

d2

        nop                     ; t5 
        call    wait_sub        ; t6-t37 or t6-101  
        clrf     GPIO           ; Turn on LED. ; t0  
        movlw   0x08            ; t1
        call    wait_sub        ; t2-t37

;---------- Bit 3. ----------*

bit3

        movwf   GPIO            ; Turn off LED.
        movlw   0x07            ; Value in case of sending a '0'.     
        btfss   addr, 3         ; Test bit 3.
        goto    d3
        movlw   0x17            ; Value in case of sending a '1'.     

d3

        nop                     ; t5 
        call    wait_sub        ; t6-t37 or t6-t101
        clrf    GPIO            ; Turn on LED. ; t0  
        movlw   0x08            ; t1
        call    wait_sub        ; t2-t37
  
 
;---------- Bit 4. ----------*

bit4

        movwf   GPIO            ; Turn off LED.
        movlw   0x07            ; Value in case of sending a '0'.     
        btfss   addr, 4         ; Test bit 4.
        goto    d4 
        movlw   0x17            ; Value in case of sending a '1'.     

d4

        nop                     ; t5 
        call    wait_sub        ; t6-t37 or t6-t101
        clrf    GPIO            ; Turn on LED. ; t0  
        movlw   0x08            ; t1
        call    wait_sub        ; t2-t37
 
;---------- Bit 5. ----------*

bit5

        movwf   GPIO            ; Turn off LED.
        movlw   0x07            ; Value in case of sending a '0'.     
        btfss   addr, 5         ; Test bit 5.
        goto    d5 
        movlw   0x17            ; Value in case of sending a '1'.     

d5

        nop                     ; t5
        call    wait_sub        ; t6-t37 or t6-t101
        clrf     GPIO           ; Turn on LED. ; t0  
        movlw   0x08            ; t1
        call    wait_sub        ; t2-t37
   
;---------- Bit 6. ----------*

bit6

        movwf   GPIO            ; Turn off LED.
        movlw   0x07            ; Value in case of sending a '0'.     
        btfss   addr, 6         ; Test bit 6.
        goto    d6 
        movlw   0x17            ; Value in case of sending a '1'.     

d6

        nop                     ; t5 
        call    wait_sub        ; t6-t37 or t6-t101  
        clrf    GPIO            ; Turn on LED. ; t0  
        movlw   0x08            ; t1
        call    wait_sub        ; t2-t37

;---------- Bit 7. ----------*

bit7

        movwf   GPIO            ; Turn off LED.
        movlw   0xfc
        tris    GPIO            ; Set output port GP1 and GP0 to out.  
        movlw   0x06
        call    wait_sub
        nop
        movlw   2
        btfss   addr, 7
        movlw   1
        goto    last_bit 
 
last_bit

        movwf   GPIO
        movlw   0x0e                
        call    wait_sub        ; t8-t35 or t8-t99
        goto    start_bit       ; t36-t37 or t100-t101   
     
;*****************************************
;*---------- Initial settings. ----------*
;*****************************************
  
init_code

        movlw   0xc7             ; Internal timer clock, max prescaler.
        option 
        movlw   0xff 
        movwf   GPIO             ; Set output port, i.e. LED off.              
        movlw   0xfc             ; Set output port GP1 and GP0 to out. 
        tris    GPIO             
        goto    start_bit

endofprog

        END                       ; directive 'end of program'

