;**********************************************************************
;                                                                     *
;    Filename:	    wiresndr.asm                                      *
;    Date:          23 Nov 1999                                       *
;    File Version:  3                                                 *
;                                                                     *
;    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 sending telemetry     *
;           interface via asynchronous serial @ 5K baud.              *
;                                                                     *
;           'Wire' interface, asynchronous serial @ 5K baud           *
;           Port A 4 - Rx, 3 - Tx                                     *
;                                                                     *
;                                                                     *
;           Data nibbles are transmitted as individual bytes.  In     *
;           each transmitted byte the 'low' nibble gives the data     *
;           nibble's 'address', 0 - 15, and the 'high' nibble the     *
;           data nibble's data value.                                 *
;           This transmitter generates the data nibbles with address  *
;           values of 0 and 1 from the input byte value present on    *
;           it's input port (address 0 == input byte low nibble,      *
;           address 1 == high nibble).                                *
;           If this transmitter is an 'intermediary' in a 'data       *
;           stream' it listens for data from 'up stream'              *
;           transmitters.  This is then forwarded 'down stream' after *
;           having 2 (the number of data nibbles generated by this    *
;           transmitter) added to it's address.                       *
;           The forwarded data's addresses are examined and when      *
;           address 2 has been forwarded (which would have been sent  *
;           as address 0 by the immediately 'up stream' transmitter)  *
;           this node appends it's own data to the 'stream'.          *
;           On start up the transmitter enters a delay loop in which  *
;           it examines the state of it's Rx data bit.  If this       *
;           remains high throughout the loop the the node assumes it  *
;           is at the 'head' of the 'data stream'.  It then proceeds  *
;           to transmit it's data without waiting for data from any   *
;           'up stream' transmitter.                                  *
;                                                                     *
;**********************************************************************


	list      p=16C84
;**********************************************************************
; Include and configuration directives                                *
;**********************************************************************

#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'11111111' ; Initial port status, all bits set as input

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
INPORT		EQU     PORTB
LOWMASK		EQU     0x0F        ; Mask to isolate low 'nibble' of byte
HIGHMASK	EQU     0xF0        ; Mask to isolate high 'nibble' of byte


;**********************************************************************
; 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
intCount	; Free running interrupt counter for timing delays
telemData	; Telemetry data to be transmitted

		ENDC


;**********************************************************************
; Reset vector                                                        *
;**********************************************************************

		ORG     0x000             ; Processor reset vector
  		goto    Main              ; Jump to beginning of program


;**********************************************************************
; Interrupt vector                                                    *
;**********************************************************************

		ORG     0x004             ; Interrupt vector location
 		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

		decf    intCount,F        ; Decrement free running interrupt counter

#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    intCount          ; Set free running interrupt ...
		decf    intCount,F        ; ... counter to 0xFF
		clrf    telemData

		; Initialise interrupts
		movlw   RTCCINT
		movwf   TMR0              ; Load RTCC
		clrf    INTCON
		bsf	INTCON,T0IE       ; Enable RTCC interrupts
		bsf	INTCON,GIE        ; Enable interrupts

Startdelay	movf    intCount,F        ; Test free running interrupt counter
		btfss   STATUS,Z          ; Skip if it's reached zero ...
		goto    Startdelay        ; ... otherwise stay in delay loop

		decf    intCount,F        ; Set free running interrupt counter to 0xFF

Startloop	btfss   RXUPORT,RXUBIT    ; Skip if Rx data input is high ...
		goto    Rxloop            ; ... otherwise act as 'forwarding' node

		movf    intCount,F        ; Test free running interrupt counter
		btfss   STATUS,Z          ; Skip if it's reached zero ...
		goto    Startloop         ; ... otherwise stay in start loop

Sendloop	call    SendData          ; Become 'head' node, initiating data sending
		goto    Sendloop

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
		incf    telemData,F       ; Increment, twice, address part of data
		incf    telemData,F

		call    Txloop            ; Forward modified data on 'down stream'

		movf    telemData,W       ; Retrieve modified data
		andlw   LOWMASK           ; Isolate address part of data
		xorlw   2                 ; Test for address 2 (incremented from 0)
		btfsc   STATUS,Z          ; Skip if address is not 2 ...
		call    SendData          ; ... otherwise append own data to stream

		goto    Rxloop            ; Wait for more 'up stream' data to arrive


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

		return


SendData	movf    INPORT,W          ; Get input data
		andlw   HIGHMASK          ; Isolate high nibble
		movwf   telemData         ; Move to telemtry data register
		bsf     telemData,0       ; Set address part to 1
		call    Txloop            ; Send data 'down stream'

		swapf   INPORT,W          ; Get input data, swapping nibbles
		andlw   HIGHMASK          ; Isolate low nibble (of original input data)
		movwf   telemData         ; Move to telemtry data register
		goto    Txloop            ; Send data 'down stream'


		end                       ; directive 'end of program'

