	title	ace_1b.asm
	LIST P = 16C84,  R = HEX		;Prosessortype, radix
	INCLUDE	"p16c84.inc"			;w,f,porta,portb etc. 
	ERRORLEVEL -224, -302			;prevents error from
						;"tris"-command
        __CONFIG _PWRTE_ON & _HS_OSC & _WDT_OFF   

;************************************************************************
; SCHEMATIC DIAGRAM
;************************************************************************
;
;	          		  +---+_+---+
;  	    Col addr.C	PORTA.2 <-|1      18|-> PORTA.1 Col addr.B
;	    Col addr.D	PORTA.3 <-|2      17|-> PORTA.0	Col addr.A
;	    DCC OUT	PORTA.4 <-|3      16|-- XTAL
;	    RESET	    Vdd --|4 PIC  15|-- XTAL
;			Vss(GND)--|5 16C  14|-- Vdd (+5V)
;		ROW 1	PORTB.0 ->|6 84   13|-> PORTB.7	ROW 8 (W)
;		ROW 2	PORTB.1 <-|7      12|-> PORTB.6	ROW 7 (W)
;		ROW 3	PORTB.2 <-|8      11|-> PORTB.5	ROW 6
;		ROW 4	PORTB.3 <-|9      10|-> PORTB.4	ROW 5
;		    	          +---------+
;
;	          		  +---+_+---+
;  	                     ST  -|1      24|-  Vdd (+5V)
;	                     D1  -|2      23|-  Inh
;	                     D2  -|3      22|-  D4
;	                     S7  -|4      21|-  D3
;		             S6  -|5      20|-  S10
;		             S5  -|6 4515 19|-  S11
;		             S4  -|7      18|-  S8
;		             S3  -|8      17|-  S9
;		             S1  -|9      16|-  S14 (W)
;		             S2  -|10     15|-  S15 (W)
;		             S0  -|11     14|-  S12 (W)
;		       Vss(Gnd)  -|12     13|-  S13 (W)
;		    	          +---------+
;
;**********************************************************************************************
;	Original written by Mike Bolton:
;
;	This program is for an accessory only encoder. It scans a matrix of
;	on / off switches, each with series diodes and detects changes in the 
;	switch position. Accessory packets are sent to set one of each
;	output pair dependent on the switch position. Only one packet is sent
;	for each change. If there has been no change, an idle packet is sent.
;	A 4 to 16 line multiplexer is used to drive 16 columns. 8 rows are 
;	sensed by the PIC input lines. This gives a maximum of 128 switches.
;	Each set of four switches has a unique DCC address. Column 1 rows 1 to 4
;	are address 0, column 1 rows 5 to 8 are address 1 etc. allowing for upto
;	32 separate decoders, each with 4 output pairs.
;	When the encoder is first switched on, all switches are interrogated and
;	their positions complemented. This gives the impression that each has changed
;	so the encoder sends packets to all outputs to set them to the switch positions
;	This is essential for solenoid point motors as they can be in any position
;	at switch-on. There is a manual reset button which also sets all points
;	correctly in case any have stuck in the wrong position.
;	The present program only sends 'activate' packets. It assumes the decoder will
;	'time out' quickly as for solenoid drives. It may be modified for true on / off
;	actions for lights.
;
;	No aspects of the program are copyright and it may be freely used
;	copied, modified or distributed in whole or part. Acknowledgement of the original
;	author would be appreciated. 
;
;	Hardware schematics are also freely available from the author
;	email bolton@fs1.with.man.ac.uk   
;
;	03/05/02	Corrections and timimg changes
;                       Working with one decoder  04/05/02
;			Not tested with any more (I only have one!)
;**********************************************************************************************
;
; Original system has on-off switches, my attempt is to convert
; into (on)-off-(on) switches, first switch found off zero will will be sent
; until released. Must send some idles between packets and only
; idles if no switches are turned
;
; Original addressing scheme:
;
;		COL 1	COL2	COL3	...
;
;	ROW 1:	A0.1	A2.1	A4.1	...
;	ROW 2:	A0.2	A2.2	A4.2	...
;	ROW 3:	A0.3	A2.3	A4.3	...
;	ROW 4:	A0.4	A2.4	A4.4	...
;	ROW 5:	A1.1	A3.1	A5.1	...
;	ROW 6:	A1.2	A3.2	A5.2	...
;	ROW 7:	A1.3	A3.3	A5.3	...
;	ROW 8:	A1.4	A3.4	A5.4	...
;
;
; Revised scheme
;
;		COL 1	COL2	COL3	COL4	COL5	...	COL16
;
;	ROW 1:	A1.1+	A1.2+	A1.3+	A1.4+	A2.1+	...	A4.4+
;	ROW 2:	A1.1-	A1.2-	A1.3-	A1.4-	A2.1-	...	A4.4-
;	ROW 3:	A5.1+	A5.2+	A5.3+	A5.4+	A6.1+	...	A8.4+
;	ROW 4:	A5.1-	A5.2-	A5.3-	A5.4-	A6.1-	...	A8.4-
;	...
;
; Also added a possibility to change the address window, or base address
; of the decoders the system is to operate. the system will only operate 15
; decoders, the controls of decoder 16 are controlling the window.
; these buttons are replaced with jumpers, and at least one of them has
; to be in place to get other than idle packets out!
; Jumper positions correspond to R1:C1 decoder (DEC) or R1:C1 turnout (W):
;
;			COL13	COL14	COL15	COL16	
;			pin14	pin13	pin16	pin15	pin of 4515
;		------	-----	-----	-----	-----
;		ROW 7:	DEC 1	DEC 8	DEC16 	DEC24
;		pin12	(W1)	(W33)	(W65)	(W97)
;	
;		ROW 8:	DEC32	DEC40	DEC48	DEC56
;		pin13	(W129)	(W161)	(W193)	(W225)
;	
;		pin of
;		PIC
; ---------------------------------------------------------------------
;
; Accessory decoder packet format:
; ================================
;	PPPPPP 0 10AA-AAAA 0 1aaa-DCCX 0 EEEE-EEEE 1 PPP...
;	
;	Where:
;	------
;	P	= Preamble min. 14 ones
;	A	= Address LSB bits
;	a	= Address MSB bits complemented (0=>1, 1=>0)
;	D	= Data, w. turnouts must be 1 (lenz requires no resetting to 0)
;	C	= Turnout number within decoder
;	X	= which coil within turnout
;	E	= Error detection byte
;
;*********************************************************************

;
;	Registers used	predefined
;
;	working registers


	CBLOCK H'0C'

		temp		;temp
		spare		;spare
		colcnt		;column counter
		byte1		;first bute of packet
		byte2		;second byte of packet
		byte3		;third byte of packet (for future use)
		err1		;error byte
		bitcnt		;bit count in packet
		bytcnt		;in packet
		win_tmp		;used for calculating the address window
		window		;the turnout address window's origo
		row	
		in_use		;is the panel in use (non zero=yes)
		pktcnt		;number of packets
		pbitcnt		;preamble bit count
		rowcnt		;row counter
		bitnum		;sets bit in row (shift register)
		adrcnt		;address counter
		k_byte1 	;killer_byte1
		k_byte2 	;killer_byte2
		k_row 		;killer_row

		x_row		;tmporary row data

		table_1		;The table!
		table_2		;
		table_3		;
		table_4		;
		table_5		;
		table_6		;
		table_7		;
		table_8		;
		table_9		;
		table_A		;
		table_B		;
		table_C		;
		table_D		;
		table_E		;
		table_F		;
	ENDC

	#DEFINE DCC_OUT		porta,4 	;DCC signal out
	#DEFINE	PRE_BITS	.18		;Number of preamble bits
;*************************************************************************
;
	org		0
	goto	setup	;reset vector

	org	04	;interrupt vector
	retfie		;return from interrupt

;************************************************************************
;
;start of program. Sets up ports etc.


	org	10
	
setup
	movlw	b'11111111'	;RB.1..7=in
	tris	portb		;

	movlw	b'00000000'	;RA.0..4=out
	tris	porta		;

				;easy to recall:
				;Input -> I -> 1
				;Output-> O -> 0

	clrf	porta		;clear Port A (Shift reg output)
	clrf	portb		;Port B on (LED test)

	CLRWDT			;
	movlw	b'00010000'	;dcc_out set, row=0
	movwf	porta		;set out

	bsf	STATUS, RP0	;
	movlw	b'00001000'	;PullUp=on, int. clk, PreScaler on TMR0=1:1
	movwf	OPTION_REG	;
	bcf	STATUS, RP0	;

	clrf	colcnt		;
	clrf	window		;
	clrf	win_tmp		;
	clrf	row		;

	movlw	PRE_BITS	;we'll need predefined
	movwf	pbitcnt		;amount of preamblebits

;	end of setup

	goto	init		;

;----------------------------------------------------------------			 
; SYNC: Waits for TMR0, resets, loads new seed and returns
; Set DCC_OUT in calling code
;SYNC_1 for ones, SYNC_0 for zeros!
;----------------------------------------------------------------			 
	
sync_1	btfss	intcon, T0IF	;wait loop
	goto	$-1
	btfss	TMR0,2		;Jitter routine from
	goto	$+1		;Bob Ammerman [Piclist]
	btfsc	TMR0,0		;
	goto	$+1		;
	bcf	intcon, T0IF	;clear interrupt flag
	movlw	0xD2		;
	movwf	TMR0
	return

sync_0	btfss	intcon, T0IF	;wait loop
	goto	$-1
	btfss	TMR0,2		;Jitter routine from
	goto	$+1		;Bob Ammerman [Piclist]
	btfsc	TMR0,0		;
	goto	$+1		;
	bcf	intcon, T0IF
	movlw	0xE2		;reset TMR0
	movwf	TMR0
	return

;----------------------------------------------------------
;The turnout (or decoder!) base address is picked from here
;----------------------------------------------------------

getbase
	addwf	pcl,f		;and jump to return value
	retlw	.0		;0:
	retlw	.8		;1:
	retlw	.16		;2:
	retlw	.24		;3:
	retlw	.32		;4:
	retlw	.40		;5:
	retlw	.48		;6:
	retlw	.56		;7:
	retlw	.64		;8: (it should never get this far ;)

;******************************************************************
;
;	Initialise sequence
;	[This is original Bolton code!]
;----------------------------------------------------------------			 

init	movlw	.10
	movwf	pktcnt		;send 10 reset packets
	call	reset 
	movlw 	.10
	movwf	pktcnt		;send 10 reset packets
	call	idle
	clrf	row		;
	clrf	colcnt		;
	clrf	rowcnt		;
	clrf	in_use		;
	clrf	win_tmp		;
	clrf	window		;

scan	;-------------------------------------------------------
	; Here is the beginning of operations for each column
	; entrance DCC HIGH!
	;-------------------------------------------------------

	call	sync_1		;get sync (58 us) and then

	bcf	DCC_OUT		;output DOWN!
	decf	pbitcnt, f	;decrement preamble bit count at
				;falling edge of preamble byte

	comf	portb, w	;get row data
	movwf	row		;save in row

	;----------------------------------------------------------
	; For shifting the decoder base address (window)
	; we have to check the buttons/switches C12..15:R6..7! 
	; These will be handled here and cleared so as
	; to prevent the change-routine from halting
	; to these in case they are set. Win_tmp is used for 
	; searching the new base decoder number (returned in window
	; and added to base=0 decoder address) and also as
	; temp flag to set/clear in_use at end of col scan!
	;----------------------------------------------------------

	comf	colcnt, w	;get the column number and
	andlw	b'00001100'	;check if we are within
	skpz			;window columns (i.e Col:0..3)
	goto	scan2		;nope -- continue to scan2

	;-----------------------------------------------------
	; Now in possible column for base address shifting bits
	;-----------------------------------------------------

	movfw	row		;and now test the row for
	andlw	b'11000000'	;any window bits?
	skpnz			;are bits 6 or 7 set?
	goto	scan2		;no, continue as normal

				;Now we know that either bit 6 or 7
				;is set (only one "allowed") so it's
				;enough to test only the other
	;-----------------------------------------------------
	; Found base address shifting bits
	;-----------------------------------------------------

	movfw	colcnt		;yes, get the col again
	andlw	b'00000011'	;get the low bits only
	movwf	win_tmp		;and save it

	btfsc	row,7		;We'll test bit 7
	bsf	win_tmp, 2	;if set we'll set w_lookup bit 2

;	bcf	row, 6		;and clear both possible window bits
;	bcf	row, 7		;from row


	incf	win_tmp, f	;win_tmp is used also as flag
				;to tell that window was changed
				;we add one as it is possible that we found
				;jumper at C1,R1, i.e. zero!


scan2	call	sync_1
	bsf	DCC_OUT		;Output UP!
	;-----------------------------------------------------
	; Test if panel in use
	;-----------------------------------------------------
	
	tstf	in_use		;Check if the local panel is in use
	skpnz			;if 0 then skip row interpretations
	goto	scan4		;and go reading other columns

	;-----------------------------------------------------
	; Here if panel in use, lets test for buttons!
	;-----------------------------------------------------

	movlw	table_1		;get pointer to tables 1st item
	addwf	colcnt, w	;add column number to this
	movwf	FSR		;and point INDF to this table item

	movfw	INDF		;get the old row data (from table_n)
	movwf	x_row		;copy to safety
	movfw	row		;and replace table data
	movwf	INDF		;with new data (to table_n) and
	xorwf	x_row, w	;compaire it with the previous read
	andwf	row, f		;and check if new buttons or switches down.
				;So: x_row had old value copied from table and 
				;that is now xored with new value (to get 
				;changed bits) and this is anded with new value
				;to find out which changed bits have moved
				;from 0 -> 1. "row" has now these bits set!
	skpz			;any new buttons down (note: window bits not cleared!)?
	goto	change		;yes, out with it

	;-----------------------------------------------------
	; Here if panel in use, but column has no buttons down
	;-----------------------------------------------------

scan4	call	sync_1		;syncronize to 58us

	bcf	DCC_OUT	       	;output DOWN!
	decf	pbitcnt, f	;decrement preamble bit count at
				;falling edge of preamble byte

	;-----------------------------------------------------
	; Now at the end of this column, get to next column
	;-----------------------------------------------------

	incf	colcnt, w	;increment column
	andlw	B'00001111'	;clear the top nibble
	movwf	colcnt		;to prevent going over the top!

	skpz			;are we at the end of cols (last column)?
	goto 	scan6		;no, skip the end routine

	;-------------------------------------------------------------------
	; Here if this is the last column!
	;-------------------------------------------------------------------

	clrf	in_use		;if no window jumpers: not in use!
	tstf	win_tmp		;test the temp-file, in case we
	skpnz			;have found a window jumper?
	goto	scan6		;no, the panel is not in use

	;-----------------------------------------------------
	; If win_tmp is non zero then the panel is in use!
	;-----------------------------------------------------

	incf	in_use, f	;yes, we are in business
	decf	win_tmp, f	;decrement to get rid of the extra set for label!
	movfw	win_tmp		;get the w_lookup
	call	getbase		;make the lookup to find out window base
	movwf	window		;and move it in action!
	incf	window, f	;add one to get LENZ addressing;
				;W. LENZ the decoder numbers start from 1!
	clrf	win_tmp		;clear the win_tmp as it is used as a flag
				;during next round
	
scan6
	;-------------------------------------------------------------------
	; Here after all the column stuff is completed!
	;-------------------------------------------------------------------

;	movfw	porta,w		;get port a 
;	andlw	B'11110000'	;save DCC_OUT, discard address
;	iorwf	colcnt,w	;get new column address 
;	iorlw	B'00010000'	;keep dcc output
;	movwf	porta		;select new column
	movfw	colcnt		;get column count
	movwf	porta		;and put it out
				;(DCC signal is always down here!)
	call	sync_1		;syncronize to 58 us

	bsf	DCC_OUT	       	;output UP!

	incf	pktcnt,f	;one packet 
	call	idle		;to give delay
	goto	scan		;return to beginning of column scanning
				;with output HI
				
;============================================================
; END OF MAIN SCAN LOOP
;============================================================

change
	;-------------------------------------------------------
	; Here if new switches were closed
	; Will send all newly found switches, so all bits
	; may be set and must be sent before returning to scan!
	;-------------------------------------------------------
	; PPPPPP 0 10AA-AAAA 0 1aaa-DCCX 0 EEEE-EEEE 1
	;
	; Create packet from colcnt and rowcnt:	
	;
	;	colcnt low nibble => A1, A0, C1, C0
	;	rowcnt low nibble => A4, A3, A2, X
	;-------------------------------------------------------
	;Enter with output UP!
	;-------------------------------------------------------

	movlw	.8		;8 rows to search,
	movwf	x_row		;x_row now row's bit counter
	incf	x_row, f	;
	clrf	rowcnt		;row's bit pos denotes
	decf	rowcnt, f	;rowcnt value

	comf	colcnt, w	;get the column number and
	andlw	b'00001100'	;check if we are within
	skpz			;window columns (i.e Col:0..3)
	goto	c_loop		;nope -- continue to scan2

	decfsz	x_row, f	;Yep! decrement x_row so that the 
	decfsz	x_row, f	;window setting bits won't be noticed


c_loop	incf	rowcnt, f	;value converted to binary w.
	decfsz	x_row, f	;test if all rotated out
	goto	c0
	goto	scan4		;return to scan more columns
c0
	rrf	row, f		;rotate right throuh carry
	skpc			;if carry is not found
	goto 	c_loop		;we'll rotate more

	;---------------------------------------------------
	; Create accessory decoder packet data
	;---------------------------------------------------

	movlw	B'10000000'	;Byte 1: 10AA-AAAA
	movwf	byte1		;--------------------
	btfsc	colcnt, 2	;Test column bit 2 (A0)
	bsf	byte1,  0	;yes set A0
	btfsc	colcnt, 3	;Test column bit 3 (A1)
	bsf	byte1,  1	;yes set A1

	btfsc	rowcnt, 1	;Test row bit 1 (A2)
	bsf	byte1,  2	;yes set A2
	btfsc	rowcnt, 2	;Test row bit 2 (A3)
	bsf	byte1,  3	;yes set A3

	call	sync_1		;need to syncronize again

	bcf	DCC_OUT		;output DOWN
	decf	pbitcnt, f	;decrement preamble bit count at
				;falling edge of preamble byte

	movlw	B'11111000'	;Byte 2: 1111-1CCX
	movwf	byte2		;--------------------
	btfsc	colcnt, 0	;Test column bit 0 (C0)
	bsf	byte2,  1	;yes set C0
	btfsc	colcnt, 1	;Test column bit 1 (C1)
	bsf	byte2,  2	;yes, set C1
	btfss	rowcnt, 0	;Test row bit 0 (X) [inverted for SMJ]
	bsf	byte2,  0	;yes, set X

	;------------------------------------------------------
	; Now, as the window is added there is a possibility of 
	; messing the 2 MSB markers of byte1: if they are not 
	; '10' we'll fix em and adjust the byte2 inverted
	; address bits accordingly
	;------------------------------------------------------

	movfw	window		;get the window
	addwf	byte1, f	;and add it to byte1

	btfss	byte1, 6	;check if address gone over 63
	goto 	c2		;no, continue
	bcf	byte1, 6	;yes, clear "wrong" bit
	bcf	byte2, 4	;and set (clear) correct bit

c2	btfsc	byte1, 7	;check if addres overrun in byte1
	goto 	c3		;no, continue
	bsf	byte1, 7	;yes, correct by settng bit 7
	bcf	byte2, 5	;and set (clear) correct bit

c3	call	sync_1		;syncronize again

	bsf	DCC_OUT		;output UP!

	movfw	byte1		;---------------------------
	movwf	k_byte1		;make backups of byte1 and 2
	movfw	byte2		;to create the killer packet
	movwf	k_byte2		;Data bit = byte2, bit 3

	movlw	3		;total 3 bytes (E inclusive)
	movwf	bytcnt		;to bytecount
				;Recall: enter preamb w. output UP!
	call	preamb		;send preamble
	call	packet		;send the packet proper

	movlw	3		;and then send 2
	movwf	pktcnt		;idle packets to give
	call	idle		;time for decoder to operate

	;----------------------------------------------------------
	; We'll send second activating packet just to make sure
	;----------------------------------------------------------
	movfw	k_byte1		;yes still down! Let's send more
	movwf	byte1		;of those turnout activating
	movfw	k_byte2		;commands by using the
	movwf	byte2		;copies of previously calculated
	movlw	3		;byte1 and byte 2 copies!
	movwf	bytcnt		;set the bytecount (E inclusive)
	call	preamb		;send preamble
	call	packet		;and send the packet proper!

	movlw	3		;and then send 3
	movwf	pktcnt		;idle packets to give
	call	idle		;time for decoder to operate

	;-------------------------------------------------------------------
	; Sending killer!
	;-------------------------------------------------------------------
	bcf	k_byte2, 3	;modify the backup to create killer!
	movfw	k_byte1		;take the backups in use
	movwf	byte1		;for the packet sending
	movfw	k_byte2		;routine
	movwf	byte2		;and send the killer_packet
	movlw	3		;total 3 bytes (E inclusive)
	movwf	bytcnt		;to bytecount
	call	preamb		;send preamble
	call	packet		;send the killer packet proper

	movlw	3		;and then send 3
	movwf	pktcnt		;idle packets to give
	call	idle		;time for decoder to operate

	;-------------------------------------------------------------------
	; Sending second killer!
	;-------------------------------------------------------------------
	movfw	k_byte1		;take the backups in use
	movwf	byte1		;for the packet sending
	movfw	k_byte2		;routine
	movwf	byte2		;and send the killer_packet
	movlw	3		;total 3 bytes (E inclusive)
	movwf	bytcnt		;to bytecount
	call	preamb		;send preamble
	call	packet		;send the killer packet proper

	;------------------------------------------------------

	movlw	3		;and then send 2 idle packets
	movwf	pktcnt		;to give the decoder time to digest
	call	idle		;the new situation.

	goto 	c_loop		;and start looping again
				;NOTE: We will re-enter to the same column!

;*****************************************************
;
;	subroutines
;
;	[Mainly original Bolton code!]
	
;******************************************************
;
;	sends a complete reset packet
;	number of packets in pktcnt

reset	movlw	B'00000000'
	movwf	byte1
	movlw	B'00000000'
	movwf	byte2
	movlw	3
	movwf	bytcnt
	call	preamb
	call	packet
	decfsz	pktcnt,f
	goto	reset 
    	return 
;
;******************************************************
;
;	sends a complete idle packet
;	number of packets in pktcnt

idle	movlw	B'11111111'
	movwf	byte1
	movlw	B'00000000'
	movwf	byte2
	movlw	3
	movwf	bytcnt 
	call	preamb
	call	packet
	decfsz	pktcnt,f
	goto	idle
	return

;****************************************************************
;
;	main packet routine
;
;	sends a packet without preamble
;	data to be set in byte1 to byte3 etc
;	number of bytes in packet in bytcnt
;	routine works out the error byte itself
;	adds start bits 
;	must arrive with the DCC output high
;	When arriving here, TMR0 has seed for "one"!
;
;	preamble>|sep         >|
;	+---+   +---+--+      +---
;	|   |   |      |      |   ...
;	|   +---+      +--+---+
;
;	sync1   1   0  0  1   n
;
;	At sep.bit (0) the original seed is consumed
;	and then extra sync with special seed is run
;	before changing output.
;
;	At change of output the seed is always that of "one"
;
;	The same idea is used throughout the packet.
;-----------------------------------------------------------------

packet	movlw	byte1    	;point FSR to start of bytes
	movwf	FSR
	movf	bytcnt,w	;get no of bytes
	movwf	temp
	decf	temp,f
	decf	temp,f
	movf	INDF,w		;get 1st byte
	incf	FSR,f 
p1	xorwf	INDF,w		;work out error
	incf	FSR,f 
	decfsz	temp,f
	goto	p1 
	movwf	INDF		;error byte
	movlw	byte1 		;reset index
	movwf	FSR
	

ploopa	call	sync_0		;lets consume the "one"		
				;and insert seed for "zero"

	movlw	.9
	movwf	bitcnt		;set bitcount (8 bits)


	call	sync_1		;and consume the "zero"
				;and start with seed for "one"
	bcf	DCC_OUT		;output lo (first half of start bit complete)

;
;	second half of start bit
;
		 
ploop2	call	sync_0		;consume the "one" and insert
				;seed for "zero"
	
;
;	setup for a byte before end of start bit
;
;-----------------------------------------------------------
; BIT ROUTINES: enter with output LOW and with unknown seed
;-----------------------------------------------------------	

nxt1	decfsz	bitcnt,f	;last bit?
	goto	nxtbit		;no so next bit
	goto	nxtbyt		;yes so next byte


nxtbit	rlf	INDF,f		;roll the data
	skpc
	goto	zero		;wait for TMR0 then jump to 
				;a one or a zero

;-----------------------------------------------------------
;BIT IS ONE
;-----------------------------------------------------------
	call	sync_1		;sync to "one"
	bsf	DCC_OUT
	call 	sync_1		;sync to "one"
	bcf	DCC_OUT
	goto	nxt1

;-----------------------------------------------------------
; BIT IS ZERO
;-----------------------------------------------------------
zero	call	sync_1		;consume "zero" and seed to "one"
	bsf	DCC_OUT		;output HI
	call	sync_0		;consume "one" and
				;insert seed for "zero"
	call	sync_1		;consume "zero" load "one"
	bcf	DCC_OUT		;output LO
	call	sync_0		;
	goto 	nxt1	

;
;	get next byte
;
	
nxtbyt	incf	FSR,f
	movlw	.9
	movwf	bitcnt
	call	sync_1
nxtby1	bsf	DCC_OUT		;output up
	decfsz	bytcnt,f	;last byte	
	goto	ploopa		;start bit of next byte

	return			;no more bytes in packet


;*************************************************************
;
;sends a passive preamble of 14 cycles
;arrive with output hi
;leaves with output hi  (ready for packet)


preamb	call	sync_1		;syncronize to 58 us

pr1 	bcf	DCC_OUT		;output down
	decfsz	pbitcnt,f
	goto	pr2
	call	sync_1		;syncronize again
	bsf	DCC_OUT	      	;output up
	movlw	PRE_BITS	;get the pre-defined number of
	movwf	pbitcnt		;preamble bits as seed
	return            	;end of preamble

pr2	call	sync_1		;syncronize again to 58us
	bsf	DCC_OUT	       	;output up
	goto	preamb		;and again to beginning of preamb routine 

	end


