;**********************************************************************
;                                                                     *
;    Filename:	    wirercvr.asm                                      *
;    Date:          23 Nov 1999                                       *
;    File Version:  2                                                 *
;                                                                     *
;    Author:        Chris White (whitecf@bcs.org.uk)                  *
;    Company:       Monitor Computing Services Ltd.                   *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Copyright (C) 1999  Monitor Computing Services Ltd.              *
;                                                                     *
;    This program is free software; you can redistribute it and/or    *
;    modify it under the terms of the GNU General Public License      *
;    as published by the Free Software Foundation; either version 2   *
;    of the License, or any later version.                            *
;                                                                     *
;    This program is distributed in the hope that it will be useful,  *
;    but WITHOUT ANY WARRANTY; without even the implied warranty of   *
;    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    *
;    GNU General Public License for more details.                     *
;                                                                     *
;    You should have received a copy of the GNU General Public        *
;    License (http://www.gnu.org/copyleft/gpl.html) along with this   *
;    program; if not, write to:                                       *
;       The Free Software Foundation Inc.,                            *
;       59 Temple Place - Suite 330,                                  *
;       Boston, MA  02111-1307,                                       *
;       USA.                                                          *
;                                                                     *
;**********************************************************************
;                                                                     *
;    Notes: Bod test program excersising simple receiving telemetry   *
;           interface via asynchronous serial @ 5K baud.              *
;                                                                     *
;           'Wire' interface, asynchronous serial @ 5K baud           *
;           Port A 4 - Rx, 3 - Tx                                     *
;                                                                     *
;                                                                     *
;           Data nibbles are received as individual bytes.  In each   *
;           received byte the 'low' nibble gives the data nibble's    *
;           'address', 0 - 15, and the 'high' nibble the data         *
;           nibble's data value.                                               *
;           This receiver takes the data nibbles with address values  *
;           of 0 and 1 and combines their data values to form a       *
;           single output byte (address 0 == output byte low nibble,  *
;           address 1 == output byte high nibble).  Addresses other   *
;           than 0 and 1 indicate data for nodes further 'down' the   *
;           'data stream' and are forwarded after having 2 (the       *
;           number of data nibbles used by this receiver) subtracted  *
;           from their address.                                       *
;           As a guard against corruption any data nibble must be     *
;           received twice in succession with the same value before   *
;           it is used to modify the output byte value.               *
;                                                                     *
;**********************************************************************


;**********************************************************************
; Include and configuration directives                                *
;**********************************************************************

	list      p=16C84

#include <c:\pic\mplab\inc\p16C84.inc>

	__CONFIG   _CP_OFF & _WDT_OFF & _PWRTE_ON & _XT_OSC

; '__CONFIG' directive is used to embed configuration data within .asm file.
; The lables following the directive are located in the respective .inc file.
; See respective data sheet for additional information on configuration word.

#include <c:\projects\picsrl\asyn_srl.inc>


;**********************************************************************
; Constant definitions                                                *
;**********************************************************************

PORTASTATUS	EQU     B'00000000' ; Initial port status, all bits set as output
PORTBSTATUS	EQU     B'00000000' ; Initial port status, all bits set as output

RTCCINT		EQU     158         ; 1Mhz / 100 (adjusted for RTCC write inhibit) = 10Khz

INT5KBIT	EQU     2           ; Interrupts per serial bit @ 5K baud
INT5KINI	EQU     3           ; Interrupts per initial Rx serial bit @ 5K (start bit)
INT2K5BIT	EQU     4           ; Interrupts per serial bit @ 2K5 baud
INT2K5INI	EQU     6           ; Interrupts per initial Rx serial bit @ 2K5 (start bit)

INTMILLI	EQU     10          ; Interrupts per millisecond

CLKPORT		EQU     PORTA       ; Clock tick output port
CLKBIT		EQU     2           ; Clock tick output on Port A bit 2

; 'Up' interface constants
RXUFLAG		EQU     0           ; 'Up' receive byte buffer 'loaded' status bit
RXUERR		EQU     1           ; 'Up' receive error status bit
RXUBREAK	EQU     2           ; 'Up' received 'break' status bit
TXUFLAG		EQU     3           ; 'Up' transmit byte buffer 'clear' status bit
TXUTRIS		EQU     TRISA       ; 'Up' side Tx port direction register
TXUPORT		EQU     PORTA       ; 'Up' side Tx port data register
TXUBIT		EQU     3           ; Tx on Port A bit 3
RXUTRIS		EQU     TRISA       ; 'Up' side Rx port direction register
RXUPORT		EQU     PORTA       ; 'Up' side Rx port data register
RXUBIT		EQU     4           ; Rx on Port A bit 4

; Telemetry constants
OUTPORT		EQU     PORTB
LOWMASK		EQU     0x0F        ; Mask to isolate low 'nibble' of byte
HIGHMASK	EQU     0xF0        ; Mask to isolate high 'nibble' of byte
ADDRMASK	EQU     0x0E        ; Mask to identify data not for this 'node'


;**********************************************************************
; Variable definitions                                                *
;**********************************************************************

		CBLOCK  0x0C

; Status and accumulator storage registers
pclath_isr	; PCLATH register store during ISR
w_isr		; 'w' register, accumulator, store during ISR
status_isr	; status register store during ISR

; Interface registers
serStatus	; Serial I/F status flags

; 'Up' side interface registers
serURxTmr	; Interrupt counter for serial bit timing
serURxReg	; Data shift register
serURxByt	; Data byte buffer
serURxBitCnt	; Bit down counter
serUTxTmr	; Interrupt counter for serial bit timing
serUTxReg	; Data shift register
serUTxByt	; Data byte buffer
serUTxBitCnt	; Bit down counter

; Telemetry registers
telemData       ; Received telemtry data for forwarding or outputting
last0Low        ; Last received data for byte 0 low nibble
last0High       ; Last received data for byte 0 high nibble
outData         ; Output data value

		ENDC


;**********************************************************************
; Reset vector                                                        *
;**********************************************************************

		ORG     0x000             ; Processor reset vector
BootVector	goto    Main              ; Jump to beginning of program


;**********************************************************************
; Interrupt vector                                                    *
;**********************************************************************

		ORG     0x004             ; Interrupt vector location
IsrVector	goto    BeginISR          ; Jump to interrupt service routine


;**********************************************************************
; Link and interface routine macro invocations                        *
;**********************************************************************

EnableRxU	EnableRx  RXUTRIS, RXUPORT, RXUBIT
		return


InitRxU		InitRx  serURxTmr, serStatus, RXUFLAG, RXUERR, RXUBREAK
		return


SrvcRxU		ServiceRx serURxTmr, RXUPORT, RXUBIT, serURxBitCnt, INT5KINI, serStatus, RXUERR, RXUBREAK, serURxReg, serURxByt, RXUFLAG, INT5KBIT


EnableTxU	EnableTx  TXUTRIS, TXUPORT, TXUBIT
		return


InitTxU		InitTx  serUTxTmr, serStatus, TXUFLAG
		return


SrvcTxU		ServiceTx serUTxTmr, serStatus, serUTxByt, serUTxReg, TXUFLAG, serUTxBitCnt, INT5KBIT, TXUPORT, TXUBIT, 0, 0


LinkURx
SerURx		SerialRx serStatus, RXUFLAG, serURxByt


LinkUTx
SerUTx		SerialTx serStatus, TXUFLAG, serUTxByt


;**********************************************************************
; Interrupt service routine (ISR) code                                *
;**********************************************************************

BeginISR	movwf   w_isr             ; Save off current W register contents
		movf	STATUS,W          ; Move status register into W register
		movwf	status_isr        ; save off contents of STATUS register
		movf	PCLATH,W          ; Move PCLATH register into W register
		movwf	pclath_isr        ; save off contents of PCLATH register

		btfss   INTCON,T0IF       ; Skip if RTCC interrupt flag is set ...
		goto    EndISR            ; ... otherwise jump to end of service routine

		BANKSEL TMR0              ; Ensure register page 0 is selected
#ifdef CLKPORT
		bcf     CLKPORT,CLKBIT    ; Set clock outData low
#endif
		bcf     INTCON,T0IF       ; Clear the RTCC interrupt bitflag

		movlw   RTCCINT
		addwf   TMR0,F            ; Reload RTCC

		call    SrvcRxU           ; Perform up interface Rx service
		call    SrvcTxU           ; Perform up interface Tx service

#ifdef CLKPORT
		bsf     CLKPORT,CLKBIT    ; Set clock outData high
#endif

EndISR		movf    pclath_isr,W      ; Retrieve copy of PCLATH register
		movwf	PCLATH            ; Restore pre-isr PCLATH register contents
		movf    status_isr,W      ; Retrieve copy of STATUS register
		movwf	STATUS            ; Restore pre-isr STATUS register contents
		swapf   w_isr,F
		swapf   w_isr,W           ; Restore pre-isr W register contents

		retfie                    ; Return from interrupt


;**********************************************************************
; Main program code                                                   *
;**********************************************************************

Main		clrf    PORTA             ; Clear I/O ports
		clrf    PORTB

		BANKSEL OPTION_REG        ; Select register page 1

		movlw   PORTASTATUS       ; Program I/O port bit directions
		movwf   TRISA
		movlw   PORTBSTATUS
		movwf   TRISB

		clrf    OPTION_REG
		bsf     OPTION_REG,NOT_RBPU
		bsf     OPTION_REG,INTEDG
		bsf     OPTION_REG,PSA

		BANKSEL TMR0              ; Select register page 0

		movlw   PORTASTATUS       ; For Port A need to write one to each bit ...
		movwf   PORTA             ; ... being used for input

		; Initialise variables

		; Initialise serial link
		SerInit    serStatus, serUTxTmr, serUTxReg, serUTxByt, serUTxBitCnt, serURxTmr, serURxReg, serURxByt, serURxBitCnt
		call    EnableRxU
		call    InitRxU
		call    EnableTxU
		call    InitTxU

		clrf    telemData
		clrf    last0Low
		clrf    last0High
		clrf    outData

		; Initialise interrupts
		movlw   RTCCINT
		movwf   TMR0              ; Load RTCC
		clrf    INTCON
		bsf	INTCON,T0IE       ; Enable RTCC interrupts
		bsf	INTCON,GIE        ; Enable interrupts

Rxloop		call    LinkURx           ; Check for data from 'up stream' node
		btfss   STATUS,Z          ; Skip if data received ...
		goto    Rxloop            ; ... otherwise keep waiting

		movwf   telemData         ; Save received telemetry data

		andlw   ADDRMASK          ; Isolate address part of received data
		btfss   STATUS,Z          ; Skip if address is 0 or 1 ...
		goto    ForwardData       ; ... otherwise forward data on 'down stream'

		btfsc   telemData,0       ; Skip address is 0 ...
		goto    GotHigh           ; ... otherwise received high nibble data

GotLow		movf    telemData,W       ; Retrieve received data
		xorwf   last0Low,W        ; Compare with last received low nibble data
		btfsc   STATUS,Z          ; Skip, and ignore, if values different ...
		goto    SetLow            ; ... otherwise set output low nibble value

		movf    telemData,W       ; Retrieve received data and ...
		movwf   last0Low          ; ... save as last received low nibble data
		goto    Rxloop

SetLow		swapf   telemData,W       ; Get received data part into low nibble ...
		andlw   LOWMASK           ; ... and isolate low nibble ...
		movwf   telemData         ; ... then store isolated low nibble value
		movf    outData,W         ; Get current output data ...
		andlw   HIGHMASK          ; ... and isolate high nibble value
		goto    SetOutput

GotHigh		movf    telemData,W       ; Retrieve received data
		xorwf   last0High,W       ; Compare with last received high nibble data
		btfsc   STATUS,Z          ; Skip, and ignore, if values different ...
		goto    SetHigh           ; ... otherwise set output high nibble value

		movf    telemData,W       ; Retrieve received data and ...
		movwf   last0High         ; ... save as last received high nibble data
		goto    Rxloop

SetHigh		movf    telemData,W       ; Get received data part into high nibble ...
		andlw   HIGHMASK          ; ... and isolate high nibble ...
		movwf   telemData         ; ... then store isolated high nibble value
		movf    outData,W         ; Get current output data ...
		andlw   LOWMASK           ; ... and isolate low nibble value

SetOutput	iorwf   telemData,W       ; Combine current and new nibble values ...
		movwf   outData           ; ... save as current output data ...
		movwf   OUTPORT           ; ... and output value

		goto    Rxloop            ; Wait for more data from 'up stream' node

ForwardData	decf    telemData,F       ; Decrement, twice, address part of data
		decf    telemData,F

Txloop		movf    telemData,W       ; Get telemetry data ...
		movwf   FSR               ; ... into FSR in order to transmit
		call    LinkUTx           ; Attempt to transmit telemetry data
		btfss   STATUS,Z          ; Skip if data sent ...
		goto    Txloop            ; ... otherwise keep trying to transmit

		goto    Rxloop            ; Wait for more data from 'up stream' node


		end                       ; directive 'end of program'

