	processor	16F874A
	title	"bc1a_2.asm	Issue 	1 Rev c	1/04/02"  
;**********************************************************************************************
;
;	bc1a is a rewritten version of dcc8g to use a 16F874 or 16F877
;	This gives essentially a 'single chip' command station with
;	integrated booster
;
;	Clock speed now 16MHz (plenty of time for expansion)
;	Handset voltages converted by on chip ADC
;	No external serial data MUX needed
;	Chip has USART available for computer linking (not implemented yet)
;	and RS485 interface for X bus etc. (no software)
;	Loads of extra memory for expansion / future upgrades
;
;
;	This program is for a  NMRA standard DCC 'Command Station'
;	Written by Mike Bolton,  (May 1999 - initial veresion)
;	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 and PCB layout are also freely available from the author
;	email bolton@fs1.with.man.ac.uk)  
;
;	The objective of this command station was to duplicate the ease and
;	operability of a conventional analog system while maintaining the 
;	advantages of DCC. Keeping the cost low and using standard parts were
;	also criteria. The system uses up to eight handsets giving a maximum of
;	eight locos at the same time. Each handset has a potentiometer for speed control
;	two, low cost thumbwheel switches for loco address selection (00 to 99), an on/off
;	switch for direction, four function pushbuttons (simple normally open PBs), an 
;	optional handset deactivate switch (same as unplugging the handset), and 
;	two jumpers (or switches) to select the speed mode. Again optional if only one 
;	speed mode is required. Switching off a handset (or unplugging it) sends an emergency
;	stop packet to its loco.
;
;	Speed modes are 14 step, 28 step or 128 step. In 28 step mode,
;	intermediate steps are filled in by adding a step on a 1 in 2 packet
;	basis to create effectively 56 step control. This intermediate step mode can be selected
;	by a jumper on PORTD,2. If D2 is lo, mode is standard 28 step. If hi (tied to D3), then
;	the intermediate step mode is selected. (there are jumper pads on the PCB for this)
;	Not all 28 step mode decoders were happy with the alternating packets, notably the Lenz
;	LE130 feedback decoder. In 14 step mode, bit 4 controls F0(FL).
;
;	Different handsets can be in different modes and modes can be changed whilst running.
;	
;	There is an address 00 analog function available on any one handset. This allows
;	control of a conventional (non DCC) loco by the 'stretched zeros' method. Not 
;	advised for ironless rotor motors (Escap, Faulhaber, Minimotor etc). In analog mode, the 
;	waveform is similar to a conventional PWM controller with a PRF of about 40Hz. This gives
;	excellent slow speed control but is a bit noisy.
;
;	The hardware is based on a PIC 16F874 microcontroller chip with 8 channel
;	8 bit ADC. The speed information is sampled from the potentiometer voltage on each 
;	handset by the ADC. Function and address information is read serially from the handsets 
;	using a clock signal from the PIC. A 5 wire connection to the handsets is required.
; 
;	The program continually scans all handsets for information in rotation.  The
;	handset info. is read and 'parsed' during the packet preamble. If there is no 
;	handset on that channel or the address is 00, then an idle packet is sent. Function
;	packets are sent every 4th speed packet. 
;
;	On startup, all handsets are deactivated until or unless the speed control is at
;	zero. This avoids locos starting unexpectedly. Also, when a new address is dialled
;	on the thumbwheels, it will not become valid until the speed is turned to zero.
;	The 'old' loco remains under control until stopped, then the new one will start if
;	the address is available. If not, there is an audible alarm.  To change locos, select
;	address of new loco. Turn speed to zero. Current loco stops and new loco is selected 
;	if not in use otherwise alarm sounds, new loco is not selected and old one deselected.
;
;	System allows for upto 4 consists, each of upto 4 locos. Advanced consisting is
;	not used. The primary address of each loco in a consist is stored in EEPROM. 
;	If a consist address is selected (90 to 93), the speed and direction info. is sent
;	in successive packets to each loco in that consist. It is possible to have the same 
;	loco in more than one consist. Once in a consist, function data but not speed data 
;	can be sent to individual locos. Function data cannot be sent to all locos
;	in a consist from the 'consist' handset. 
;
;	A consist is selected as if it was an individual loco by dialling in the consist
;	address and turning the speed to zero. It is possible to use addresses 90 to 93 
;	for individual locos but only those addresses can be used for consists.
;
;	To set a loco into a consist, that loco must be 'active'. Hold in the consist button 
;	and then press a function button and release. Then release the consist button.
;	To 'de-consist' repeat the process. The addresses of the locos in each consist are 
;	stored in EEPROM so will be remembered when the system is powered off. F0 sets the 
;	loco on that handset to consist 90, F1 to 91 etc. If you have forgotten which locos
;	are in a consist, you can clear it by activating address 00 and putting this into the
;	consist. It will clear one loco at a time on a first in, first out basis. To completely
;	clear a consist, repeat with 00 four times. You cannot have an analog (00) loco in a 
;	consist.
;
;	The function buttons have a toggle action. Press for on, press again for off.
;
;	Zero stretching for analog control has 64 step resolution. A lookup table is used
;	to create a set of 16 straight line approximations for the non-linear curve.
;	This gives approximate correspondence between the speed setting and the mean DC level.
;
;	The system output is a 5v logic level DCC bit stream. 
;	The 16F874 provides anti phase drives for booster MOSFETs with a variable delay between 
;	switching. An input senses overload and  shuts down the drives. There is a timed retry
;	and an audible alarm.
;
;	Summary
; 
;	8 channel 'command station' 
;	8 channel 8 bit ADC
;	17 bit serial data input per channel
;	14, 28 and 128 speed steps 
;	8 bit BCD address select (00 to 99 used)
;	4 function pushbuttons
;	1 consist set pushbutton
;	1 switch for direction
;	2 mode switches (4 modes)
;	analog speed on address zero
;	integrated booster drive
;	
;	
;	Filename	bc1a_2.asm	 uses 16F874/20
;
;	Date	3/12/00
;	Working with bc1a pcb. No serial interfaces yet
;	14/6/01  Mods for overload delay
;	01/04/02 Mod to remove speed step 1
;						
;				
;	Program methodology.				
;				
;			
;	All time intervals are derived by polling the real time clock (RTCC)	
;	overflow flag. No interrupts or timing loops are used. This gives simple
;	but precise timing control and allows changes and mods. to be made without
;	affecting the timing. This method entails breaking the program up into sections
;	which take a relatively short time to execute - less than 58 microsecs. 
;	At the end of each section, the w register is loaded with a jump value pointing
;	to the next section to be executed. The RTCC is polled for overflow, reset and a
;	programmed jump is executed via the main 'goto' table. 	The exception to this
;	is in the zero and stretched zero bits where the polling is internal to the 
;	routine and does not use the main jump table. The alarm sounds if an address is selected 
;	on one handset that is is use by another and the speed is turned to the
;	zero position. Turning the speed off zero will silence the alarm as will selecting a
;	valid address. Each bit in 'alarm'corresponds to one channel. The bit is set or cleared
;	depending on the alarm state for that handset. Any bit set will sound the alarm. 		 
;				
;				
;	Programming
;
;	HS  	on
;	WDT	off
;	RST	on
;	debug 	disabled
;
	__CONFIG	h'3F72' ; PUTimer on, WDT off, HS clock, no debug
;			
;**********************************************************************************************
;
;	Registers used	predefined
;

	include	"P16F874A.inc"	;registers file

	CBLOCK	0x0020		;start of data block in RAM

;
;	working registers
;
	fcount		;function counter
	conbit		;consist bit register
	adrtmp		;temp for address
	temp		;general temp reg
	byte1		;first byte of packet
	byte2		;second byte of packet
	byte3		;third byte of packet (error on 3 byte packets)
	err1		;error byte
	count0		;counter 0 (number of packets)
	count1		;counter 1
	bytcnt		;byte counter in packet
	bitcnt		;bit counter in a byte
	count4		;counter 4
	alarm		;flag for alarm
	temp2		;another temp
	chcnt		;channel counter 
	zcount		;zeros counter
	adcset		;setup data for adc
	adcdat		;data from ADC (7 bit)
	chdata		;channel data (function and mode)
	curadr		;current loco address
	curfun		;current functions
	funflgs		;flag for function change - not used
	count		;local counter
	tcount		;count in adc setup / read





	FSRtmp		;temp for FSR
	consis		;flag tor consist setup
	mask		;used in consist direction
	loopt		;special temp in loop routine
	strch		;temp for stretch value
	div		;used in stretch
	used		;non zero if address in use
	ftoggl		;toggle for functions
	chadr		;channel address from handset
	temp1		;another temp
	alarmc		;alarm counter (shift register)
	


	locos		;loco addresses against channel
			
	loco1a		
	loco2a	
	loco3a	
	loco4a	
	loco5a	
	loco6a	
	loco7a	
	functs		;functions against channel
	func1a	
	func2a	
	func3a	
	func4a	
	func5a	
	func6a	
	func7a	


	cons00		;first loco in consist 90	
	cons01	
	cons02	
	cons03	
	cons10		;first loco in consist 91
	cons11	
	cons12	
	cons13	
	cons20		;first loco in consist 92
	cons21	
	cons22	
	cons23	
	cons30		;first loco in consist 93
	cons31	
	cons32	
	cons33

	ENDC	

;	bits used		predefined

zbit	equ	2	;STATUS zero bit
carry	equ	0	;carry bit

;RP0   equ    	5	;page bit	

rd      equ    	0	;read bit for eeprom
wr      equ    	1	;write bit for eeprom
wren    equ    	2	;write enable
f       equ    	1
w       equ    	0
dcc	equ	7	;dcc output bit
alrm	equ	1	;alarm output
clk	equ	6	;handset clock
ph1	equ	2	;H bridge phase 1
ph2	equ	3	;H bridge phase 2
overld	equ	4	;overcurrent sense input
alrovr	equ	0	;overload alarm



;
;
;	end of definitions
;**************************************************************************
;
;	start of program
;
;*************************************************************************
;
	org	0
	goto	setup	;reset vector
	org	4
	goto	setup	;in case of interrupt
;
;
;************************************************************************
;
; Sets up ports etc.

	
setup	bsf	STATUS,RP0	;set to page 1
	movlw	B'00000001'	;set up TMR0 (divide by 4)
	movwf	OPTION_REG
	movlw	B'00111111'	;set port a 
				;low 5 lines of A/D (0 to 3) + O/L detect + A/D 4
				;sequence of channels is reversed
				;bit 0 is input 8 etc
	movwf	TRISA
	movlw	B'0000111'	;set up port e 
				;high 3 lines of A/D (5 to 7)
	movwf	TRISE

	movlw	B'11111111'	;set port b to inputs
	movwf	TRISB		;handset data inputs

	movlw	B'10100000'	;set port c 
				
	movwf	TRISC		;bit 0,1  alarms
				;bit 2,3 H bridge drivers
				;bit 4 CTS out
				;bit 5 RTS in
				;bit 6 TX dat
				;bit 7 RX dat
				
	movlw	B'00001100'	;set port D 
				;bit 0  not used
				;bit 1  not used
				;bit 2  and 3 mode select 
				;bit 4  not RXE  (RS485)
				;bit 5      TXE  (RS485)
				;bit 6  HS clock
				;bit 7  DCC out
	movwf	TRISD

	clrf	ADCON1		;set ADC control	

	bcf	STATUS,RP0	;back to page 0

	movlw	B'00000000'	;drives off (modify later)
	movwf	PORTC
	movlw	B'10011011'	;set port d (d7 is DCC out)
				;d6 is serial clock
				;
	movwf	PORTD
	movlw	B'00100001'	;timer 1 setup, prescale 1/4
	movwf	T1CON
	clrf	chcnt
	movlw	.16		;clear tables
	movwf	count0
	movlw	locos
	movwf	FSR
clear	clrf	INDF
	incf	FSR,f
	decfsz	count0,f
	goto	clear
	movlw	.16		;read consist table
	movwf	count0
	movlw	cons00		;start of consist table
	movwf	FSR
	clrf	temp1		;start of eeprom 
ldcon	movf	temp1,w
	bsf	STATUS,RP1	;page 2
	movwf	EEADR
	call	eeread		;get consist info from eeprom
	movwf	INDF		;put in RAM stack

	incf	FSR,f
	incf	temp1,f
	decfsz	count0,f
	goto	ldcon
	
	call	brdown		;set output to zero
	clrf	alarmc		;counter for alarm
	clrf	alarm     	;alarm bit register
	clrf	consis		;consist setup flag
	clrf	fcount		;counter for function packets
	clrf	conbit		;bits show which handsets 
	clrf	strch		;stretch value
	movlw	.29		;goto initialise
	


;
;	end of setup
;
;	main jump table	

main	bcf	INTCON,2	;clear RTCC flag
main1	addwf	PCL,f
;
;	start of main goto table
;
	goto	p2          	;0      packet routine
	goto	one1		;1
	goto	zero1		;2
	goto	zero2		;3
	goto	one2		;4
	goto	nxtby1		;5 
	goto	setup		;6	dummy
	goto	setup		;7
	goto	setup		;8
	goto	adcclk		;9	in ADC setup
	goto	adcck2		;10
	goto	adcck3		;11 
	goto	adc2		;12
	goto	chr2		;13		
	goto	bcdout		;14	finish getting channel data
	goto	nchng1		;15	at end of function setup
	goto	chrex2		;16
        goto	nexld1		;17     in conchk

        
        goto	lid2		;18     idle 2 half cycles
        goto	lid1		;19     idle 3 half cycles
        goto	spdo1		;20	before speed packet
	goto	not0a		;21	part of loco
	goto	chngz		;22	part of loco 		
	goto	chngy		;23	part of loco
	goto	nexlu1		;24	in conchk
		
	goto	inv1            ;25	inval first

	goto	inv2		;26	inval second cycle 
	goto	loc1		;27	extra in loco
	goto	noz		;28	nozero
	goto	init       	;29	initialise
	goto	init1       	;30	second part of initialise
	goto	kill1		;31	kill old loco
	goto	kill2		;32	next stage of kill
	goto	nexld2		;33
	goto	nexlu2		;34
	goto	setc1		;35	in consist setup
	goto	setc2		;36	in consist setup
;
;******************************************************************
;
;	consist button convert
;
conbut	addwf	PCL,f		;add button no. to pc
	retlw	0		;0 is invalid combination
	retlw	1		;returns with address +1
	retlw	5
	retlw	0
	retlw	9
	retlw	0
	retlw	0
	retlw	0
	retlw	.13
;
;	timing loop. Waits for RTCC, resets and jumps
	
loop	btfss	INTCON,2	;wait loop
	goto	loop
	movwf	loopt		;save w
	movlw	0xC8		;reset TMR0. Adjust value for one bit period
	movwf	TMR0
	movf	loopt,w		;recover w
	goto	main
;
;******************************************************************
;
;	initialisation on startup
;
init	bsf	PORTD,dcc	;output hi		
	movlw	B'00000111'	;set initial channel count
	movwf	chcnt

	movlw	0xC8		;timing value for 58 usec.
	movwf	TMR0
	movlw	.30		;init1
	goto	loop

init1	call	brup		;output hi     
	movlw	.20
	movwf	count0		;20 reset packets 
	call 	reset
	movlw	.20 
	movwf	count0		;20 idle packets
	call	idle 
                   
;*******************************************************************        
;
;	main continuous scan and send routine
;
;
scan	bcf	INTCON,GIE	;just in case
	movf	alarm,f		;test alarm
	btfsc	STATUS,zbit
	goto	alarm1
	bsf	PORTC,alrm	;alarm on
	goto	scan1
alarm1	bcf	PORTC,alrm	;alarm off
scan1	incf	chcnt,w		;next channel
	andlw	B'00000111'	;eight channels only
	movwf	chcnt
	call	rolbit		;sets rolling bit for channel		
	call	adcgo		;set up adc 
	call	adcrd		;read adc 
	call	chread		;get channel data
				
	call	setfun		;sets up functions
		
	call	loco		;check for valid loco or consist
				;and send packet(s)
		
main3	movf	chcnt,w		;send function packet
	andlw	B'00000011'	;every 4th channel
	btfsc	STATUS,zbit
	call	sndchg		;send function 
	
main2	goto	scan	


;******************************************************
;
;	subroutines
;
;******************************************************
;
;	sends a complete reset packet
;
reset	
	clrf	byte1
	clrf	byte2
	
	movlw	3
	movwf	bytcnt
	call	preamb
	call	packet
	decfsz	count0,f
	goto	reset 
    	return 
;
;	sends a complete idle packet
;
    
idle	movlw	.10
	call	lidle1		;idle packet with preamble
	decfsz	count0,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 and handles any stretches
;	must arrive with the DCC output high
;
;			 
packet	movlw	1		;add preamble
	call	addpre
	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 INDF
	movwf	FSR
	
	

		
ploop	btfss	INTCON,2  	;wait for RTCC
	goto	ploop 
        movlw	0xD8		;sets non stretched zero for 100 usec. *
	movwf	TMR0
	bcf	INTCON,2

	incf	zcount,f	;increment zeros counter
	btfss	strch,7		;check direction of DC
    	call	strtch		;nonlinear stretch of first half

    
	
	movlw	.9
	movwf	bitcnt		;set bitcount (8 bits)
	movlw	0		;wait for RTCC in main loop
	goto	loop		;jump to p2
p2	call	brdown		;output lo (first half of start bit complete)
;
;	second half of start bit
;
		 
ploop2	btfss	INTCON,2
	goto	ploop2 
	movlw	0xD7		;reset  TMR0 *
	movwf	TMR0 
	bcf	INTCON,2

   	btfsc	strch,7		;check direction of DC	
	call	strtch


	
;
;	setup for a byte
;
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
	btfss	STATUS,carry
	goto	zero		;wait for RTCC then jump to 
				;a one or a zero

	movlw	1		;one1
	goto	loop
;
;	bit is a zero
;
zero	movlw	2		;zero1
	goto	loop
	
zero1	call	brup		;output up 

z1	btfss	INTCON,2  	;miss a count as it is a zero
	goto	z1
	movlw	0xD7		;reset TMR0 *
	movwf	TMR0		;value to make zero = 100usec.
	bcf	INTCON,2
	incf	zcount,f	;increment zeros counter
	btfss	strch,7		;check direction of DC
	call	strtch
	movlw	3 		;wait again then goto zero2
	goto	loop
	
zero2  	call	brdown		;output down (end of first half)
;
;	second half of a zero
;
    	
z2	btfss	INTCON,2  	;miss a count
	goto	z2
	movlw	0xD7		;reset TMR0 *
	movwf	TMR0
	bcf	INTCON,2
	btfsc	strch,7		;check direction of DC
	call	strtch
	
z3	goto	nxt1
;
;	bit is a one	
;

one1	call	brup		;output up
	movlw	4      		;one2
	goto	loop 
;
;	second half of a one
; 
one2	call	brdown   	;output down 
	goto	nxt1
;
;	get next byte
;
	
nxtbyt	incf	FSR,f
	movlw	.9
	movwf	bitcnt
	movlw	5 		;nxtby1
	goto	loop
nxtby1	call	brup		;output up
	decfsz	bytcnt,f	;last byte	
	goto	ploop		;start bit of next byte

	return			;no more bytes in packet

;************************************************************
;
;	nonlinear stretch routine
;	uses lookup table in eeprom to give 16 linear
;	segment approximation for stretch curve
;	also for each speed step (0 to 127) it stretches
;	progressively more zeros.
;	If stretch value is zero then no stretch
;	Note. Bit 7 of strch is the DC direction bit.
;
strtch	btfsc	zcount,6	;if counter = 64 then reset
	clrf	zcount
	movf	strch,w		;get DC speed value
	andlw	B'01111111'	;mask direction
	subwf	zcount,w	;stretch this zero?
	btfsc	STATUS,carry
	goto	strend
	movf	zcount,w	;get cycle number
	movwf	div		;ready to divide by 4
	rrf	div,f
	rrf	div,w
	andlw	B'00001111'	;mask any carries
	addlw	.48		;table starts at 48
	bsf	STATUS,RP1	;page 2
	movwf	EEADR
	call	eeread
	movwf	div		;use div again as loop counter
loopy	call 	dely		;delay loop
	decfsz	div,f
	goto	loopy 
	movlw	0xF5		;reset  TMR0 *
	movwf	TMR0 
	bcf	INTCON,2

strend	return

dely	movlw	.110		;seems OK
	movwf	temp
dely1	decfsz	temp,f
	goto	dely1
	return
;************************************************************
;
;	MOSFET bridge switching routines
;	Sets delay between phases
;	Generates logic DCC output
;	Uses timer 1 for overload delay
;	set at 64K usec for now. (65.5 millisec)

brup	call	over		;test for overload
	

	bcf	PORTC,ph2	;phase 2 off
	bsf	PORTD,dcc	;dcc output up
	nop			;delay for switching
	nop			;250ns per nop
	nop
	nop
	nop
	nop
	nop
	nop 
	;nop
	;nop
	bsf	PORTC,ph1	;phase 1 on
		
	return

brdown	call	over		;test for overload
	

	bcf	PORTC,ph1	;phase 1 off
	bcf	PORTD,dcc	;dcc output down
	nop			;delay for switching
	nop			;250ns per nop
	nop
	nop
	nop
	nop
	nop
	nop
	;nop
	;nop
	bsf	PORTC,ph2	;phase 2 on
	return

over	btfss	PORTA,overld	;overload is low
	goto	over1
	clrf	TMR1H		;reset overload timer
	clrf	TMR1L
	return

over1	btfsc	PIR1,0		;time out?
	goto	overtm
	return

overtm	bcf	PORTC,ph1	;turn off bridge
	bcf	PORTC,ph2
	bsf	PORTC,alrovr	;alarm on
	clrf	temp
	clrf	temp1
over3	call	dely1		;delay
	call	dely1
	call	dely1
	call	dely1
	call	dely1 
	call	dely1
	call	dely1
	call	dely1
	call	dely1
	call	dely1
	decfsz	temp1,f
	goto	over3
	bcf	PORTC,alrovr	;alarm off
	bcf	PIR1,0		;clear timer flag
over2	return			;try again
	

;*************************************************************
;
;sends a passive preamble of 10 cycles
;arrive with output hi
;leaves with output hi  (ready for packet)


preamb	movlw	.10		;10 preamb cycles
	call	addpre
	return
	

	
;**************************************************************
;
;	set up ADC and start conversion
;
;	
;
adcgo	movlw	9
	goto	loop
adcclk	call	brdown		;output lo
	movf	chcnt,w		;get channel count
	sublw	7		;reverse sequence
	movwf	adcset
	rlf	adcset,f
	rlf	adcset,f
	rlf	adcset,w
	andlw	B'00111000'	;mask unwanted bits
	iorlw	B'10000001'	;set up for ADC
	movwf	ADCON0		;set channel for sample
	movlw 	.10
	goto	loop
adcck2	call	brup		;output up
	bsf	ADCON0,2	;start A to D
    	movlw	.11    
    	goto	loop		;allow for AD conversion
adcck3	call	brdown		;output down
	return 			
	

;
;	get data from ADC   
;
adcrd	btfsc	ADCON0,2	;conversion complete?
	goto	adcrd
	movf	ADRESH,w	;get answer
	movwf	adcdat
	rrf	adcdat,f	;7 bits only
	bcf	adcdat,7
	movlw	1		;check for speed 1
	subwf	adcdat,w
	movlw	2
	btfsc	STATUS,zbit
	movwf	adcdat
	movlw	.12
	goto	loop
adc2	call	brup		;output up
	return			;ADC read complete

;
;	read channel settings.  two data bits for each half of
;	preamble cycle
;
chread	clrf	temp1		;temp store for data byte
	
	movlw	2
	movwf	bytcnt		;two bytes (16 bits of data)
chrr1	movlw	2
	movwf	count0
	
chrr	movlw	4
	movwf	count4		;bits per half output
	
chrd2	bsf	PORTD,clk	;clock down
	nop
	nop			;delay here for 16MHz clock
	nop
	call	pad25
	movf	alarmc,w	;rolling bit 
	andwf	PORTB,w		;read data
	btfsc	STATUS,zbit	;bit hi or lo
	goto	dat0
	bsf	STATUS,carry
	goto	roldat
dat0	bcf	STATUS,carry
roldat	bcf	PORTD,clk	;clock up 
	nop
	nop
	call	pad30		;more delay
	rlf	temp1,f		;bit 7 = no handset if 1
				;bit 5 and 6 = 0 mode 0
				;bit 6 = 1 mode 2
				;bit 5 = 1 mode 1
				;bits 5 and 6 = 1 mode 3
				;bit 4 = fwd / rev
				;functions lo nibble
	decfsz	count4,f
	goto	chrd2		;next bit of 4
	decfsz	count0,f		
	goto	opdown
	
	movlw	.16		;chrex2
	goto 	loop


opdown 	movlw	.13		;goto chr2
	goto	loop
chr2	call	brdown   	;output down
	goto	chrr

secbyt	movf	temp1,w		;store channel data
	movwf	chdata
	goto	chrr1

chrex2	call	brup		;output up
	decfsz	bytcnt,f	;last byte?
	goto	secbyt
	movf	temp1,w		;finished getting channel data
	movwf	curadr  	;store channel data	
	
			
hndtst	btfss	chdata,7	;any handset?
	goto	bcdcon		;yes
	goto	notbcd		;don't do BCD conversion

pad25	nop			;add 2.5 usec
	nop
	nop
	nop
	nop
	nop
	return

pad30	nop			;add 3 usec
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	return
	
;	converts BCD address from thumbwheels
;	uses jump table	for speed

bcdcon	comf	curadr,f	;recover address and complement
	movf	curadr,w
	movwf	temp1        	;BCD to binary 
	swapf	temp1,f			
	movlw	B'00001111'	;mask 
	andwf	curadr,f        ;has low nibble
	andwf	temp1,f         ;has hi nibble
	movlw	.10		;start bcd conversion
bcdlp	movf	temp1,f
	btfsc	STATUS,zbit
	goto	bcdfin
	addwf	curadr,f	;add 10
	decf	temp1,f
	goto	bcdlp

;	sets bit in alarm counter
;	works like a shift register
;	bit moves along with each channel count
;

rolbit	movf	chcnt,f		;roll the alarm counter bit
	btfss	STATUS,zbit	;is it channel 0
	goto	aroll0
	bsf	STATUS,carry	;set carry
	rlf	alarmc,f	;roll in a one
	goto	aroll1
aroll0	bcf	STATUS,carry	;clear carry
	rlf	alarmc,f	;roll bit along	
aroll1	return


bcdfin	;bsf	PORTD,clk	;read consist switch

	movf	alarmc,w
	andwf	PORTB,w
	btfss	STATUS,zbit	;test bit (0 = consist)
	goto	conoff
	movf	alarmc,w	;get handset counter
	andwf	conbit,w	;test for zero
	btfsc	STATUS,zbit
	bsf	consis,4
	goto	conout
conoff	movf	alarmc,w	;toggle consist set off
	andwf	conbit,w
	btfsc	STATUS,zbit
	goto	conout
	comf	alarmc,w	
	andwf	alarm,f 	;clear alarm
	andwf	conbit,f	;clear consist flag

conout	;bcf	PORTD,clk	;clock up
	movlw	.14		;bcdout
	goto	loop
bcdout	call	brdown		;output down
	return

notbcd	clrf	curadr		;invalid address
	goto	bcdfin

;
;	
;
;
;	set up function byte
;	checks if there has been a change
;	sets / clears toggle action
;
setfun	comf	chdata,w	;hi is off on receipt
	movwf	curfun		;current functions (lo nibble)

	btfsc	consis,4	;is it a consist set up
	goto	nchng2		;yes so leave alone
	movf	alarmc,w	;check consist toggle
	andwf	conbit,w
	btfss	STATUS,zbit
	goto	nchng2

	
	movlw	functs		;point to function table
	addwf	chcnt,w		;offset by channel
	movwf	FSR
	movlw	B'00100000'	;counter for 28 step mode
	addwf	INDF,f
	movlw	B'00001111'	;toggle action for functions
	andwf	curfun,w
	btfss	STATUS,zbit	;are all buttons released?
	goto	fchnge		;yes so set toggle
	bsf	INDF,4		;toggle is bit 4
	goto	nchng2

fchnge	btfsc	INDF,4		;toggle set?
	goto	fchng1
	goto	nchng2

				
fchng1	movlw	B'00001111'	;mask functions
	andwf	curfun,w	;get new functions to change
	xorwf	INDF,f		;change funct. bit	
	bcf	INDF,4		;clear toggle


nchng2	movlw	.15		;wait for RTCC
	goto	loop
nchng1	call	brup		;output up
	return


;
;	checks loco address for in use
;	a valid address has the top bit set
;
loco	movlw	locos		;get table start
	addwf	chcnt,w		;add channel count
	movwf	FSR		;set indirection
	btfss	chdata,7	;handset off?
	goto	okadr      	;no so continue
	comf	alarmc,w	;handset off so no alarm on this channel
	andwf	alarm,f
	btfss	INDF,7		;old address valid?
	goto	lidle5		;no so idle
	bcf	INDF,7		;set address to invalid
	movf	INDF,w		;get old address
	goto	estop		;handset now off so stop
				;loco that was assigned to it
				;and set to invalid
;
;	address is OK to check
;
				
	

okadr	bsf	curadr,7	;set valid bit on new one	
	movf	curadr,w	;get new address to w
	subwf	INDF,w		;is it same as old one?
	btfss	STATUS,zbit	;skip if same
	goto	new1		;new address different
	btfss	consis,4	;test for consist setup
	goto	nocons		;no consist button
        goto	setcon		;set / unset consist

	
	
nocons	goto	speed		;put out speed packet to same address
new1	movf	adcdat,f	;is speed zero?
	btfsc	STATUS,zbit
	goto	change		;yes so change?
	comf	alarmc,w	;speed not zero so no alarm on this channel
	andwf	alarm,f
	btfss	INDF,7		;old address valid? 
	goto	lidle5		;old one was not and speed not zero so idle
	
				;old one was valid and speed not zero
	comf	alarmc,w	;clear alarm bit
	andwf	alarm,f

	movf	INDF,w		;get old address
	movwf	curadr
	goto	speed		;send speed packet to old address

;
;	speed is zero so see if address is in use
;	interleaved with sending preamble bits
;	if there is a match, the 'used' flag is set
;
change	clrf	used    	;clear flag for address in use
	movlw	locos		;reset FSR
	movwf	FSR
	movlw	2               ;loop 2 channels	
	movwf	count0
chng1	movf	curadr,w	;get new address
	subwf	INDF,w
	btfsc	STATUS,zbit	;same?
	incf	used,f
	incf	FSR,f
	decfsz	count0,f
	goto	chng1		

	movlw	.22
	goto	loop
	
	
chngz	call	brdown	        ;output down 
	movlw	4           	;loop another 4
	movwf	count0		

chng2	movf	curadr,w	;get new address
	subwf	INDF,w
	btfsc	STATUS,zbit	;same?
	incf	used,f
	incf	FSR,f
	decfsz	count0,f
	goto	chng2		
	movlw	.23
		
	goto	loop        	;wait for timer
chngy	call	brup		;output up
	movlw	2           	;loop another 2
	movwf	count0		

chng3	movf	curadr,w	;get new address
	subwf	INDF,w
	btfsc	STATUS,zbit	;same?
	incf	used,f
	incf	FSR,f
	decfsz	count0,f
	goto	chng3		

	movf	used,f		;test used flag
	btfss	STATUS,zbit
	goto	kill	    	;address in use so kill old loco
	movlw	.27		;wait for RTCC
	goto	loop
loc1	call	brdown		;output down
	movlw	locos		;OK so put new address
	movwf	FSR		;in loco table
	movf	chcnt,w
	addwf	FSR,f       	;now check if old address was 00
	btfss	INDF,7		;is address valid
	goto	nozero		;not valid so don't reset 
	movf	INDF,w		;test for zero
	andlw	B'01111111'
	btfss	STATUS,zbit
	goto	nozero		;not zero
	clrf	strch		;was zero so reset stretch

nozero 	comf	alarmc,w	;clear alarm bit
	andwf	alarm,f
			
;mod to ensure old loco stops
 
loc3	movlw   .28		;noz
	goto	loop
noz	call	brup		;output up
	
	
	call	activ		;if new is a consist, activate
	movf	curadr,w 	;swap old and new addresses
	movwf	temp1		;save 
	movf	INDF,w         
	movwf	curadr
	movf	temp1,w
	movwf	INDF
	btfss	curadr,7	;was old one valid
	goto	lidle5 
	clrf	adcdat     	;make sure old address is off	
	call	deact		;if old was a consist, then deactivate
	goto	speed

activ	bcf	curadr,7	;clear valid flag
	movlw	.90		;sets consist active flag for speed check
	subwf	curadr,w
	btfsc	STATUS,zbit	;no match
	bsf	consis,0	;flag for consist 90
	movlw	.91		
	subwf	curadr,w
	btfsc	STATUS,zbit	;no match
	bsf	consis,1	;flag for consist 91
	movlw	.92		
	subwf	curadr,w
	btfsc	STATUS,zbit	;no match
	bsf	consis,2	;flag for consist 92
	movlw	.93		
	subwf	curadr,w
	btfsc	STATUS,zbit	;no match
	bsf	consis,3	;flag for consist 93 
	bsf	curadr,7	;restore valid flag
	return

deact	bcf	curadr,7	;clear valid flag
	movlw	.90		;clears consist active flag 
	subwf	curadr,w
	btfsc	STATUS,zbit	;no match
	bcf	consis,0	;flag for consist 90
	movlw	.91		
	subwf	curadr,w
	btfsc	STATUS,zbit	;no match
	bcf	consis,1	;flag for consist 91
	movlw	.92		
	subwf	curadr,w
	btfsc	STATUS,zbit	;no match
	bcf	consis,2	;flag for consist 92
	movlw	.93		
	subwf	curadr,w
	btfsc	STATUS,zbit	;no match
	bcf	consis,3	;flag for consist 93
	return
;
;	address in use so stop old loco and set hansdet address to invalid
;	also set alarm 
;
kill	movlw	.31
	goto	loop
kill1	call	brup		;output up
	movlw	locos		;get old address
	movwf	FSR		;in loco table
	movf	chcnt,w
	addwf	FSR,f       	;now check if old address was 00
	movf	INDF,w		;test for zero
	andlw	B'01111111'
	btfss	STATUS,zbit

	goto	kzero		;not zero
	clrf	strch		;was zero so reset stretch

kzero	movf	alarmc,w	;set alarm register 
	iorwf	alarm,f
			
	movlw	.32
	goto	loop
kill2	call	brdown		;output down
	btfsc	INDF,7
	goto	kill3		;is old address valid?
	movlw	5               ;5 extra preambles
	goto	lidle1		;no so idle
kill3   bcf	INDF,7		;set invalid
	movf	INDF,w		;get old address
	movwf	curadr
	call	deact		;if a consist, deactivate
	clrf	adcdat		;stop
	incf	adcdat,f	;em stop
	goto	speed
;
;
;	sends an idle packet without preamble
;
				
 
	
lidle3	movlw	B'11111111'	;set idle bytes
	movwf	byte1
	movlw	B'00000000'
	movwf	byte2
	movlw	3
	movwf	bytcnt
	call	packet
	goto	spdo2		;check for part of consist
		
lidle5	movlw	5
	
lidle1 	call	addpre 		;add preamble cycles
	goto	lidle3
	
;
;	subroutine to add extra preamble cycles
;	number of extras in w
;	arrives with output hi
;	leaves with output hi
;
			
addpre	movwf	count1		;extra preamble cycles
addpr1	movlw	.19		
	goto	loop
lid1	call	brdown     	;output down
	movlw	.18
	goto	loop
lid2 	call	brup		;output up 
	decfsz	count1,f
	goto	addpr1
	return

;
;	sends a speed packet
;	checks on speed mode and sets accordingly
;	mode for a consist is that of the consist handset
;	cannot mix modes within a consist
;	checks for address zero and sets stretches
;	arrives with output high
;	exits to packet with output high
	
	
speed	bcf	curadr,7	;clear valid flag
	
	movf	curadr,f	;is address zero?
	btfss	STATUS,zbit
	goto	not0		;no

	
	movf	adcdat,w	;put adc data into stretch
	movwf	strch
	rrf	strch,f		;64 steps for DC
	btfss	chdata,4	;check direction bit
	goto	fwd0
	bsf	strch,7		;set direction bit (1 = reverse)
	goto	speedy
fwd0	bcf	strch,7
speedy	movlw	3		;3 extra preambles
	goto	lidle5        	;put out idle packet (address 00)
	
not0	goto	conchk		;is it a consist 
speedz	movf	curadr,f	;consist address is zero (no loco)
	btfsc	STATUS,zbit
	goto	speedy
	movlw	.21		
	goto	loop		;wait for RTCC
	
not0a	call	brdown		;output down	
	movlw	B'01100000'  	;test for current speed mode
	andwf	chdata,w
	movwf	temp1
	btfsc	STATUS,zbit
	goto	spd3		;mode 0 is 128 for now 
	movlw	B'01100000'
	subwf	temp1,w
	btfsc	STATUS,zbit
	goto	spd3		;128 step speed mode
	
	btfss	temp1,5
	goto	spd2         	;28 step mode

	goto	spd1         	;14 step mode
	

;	set up speed bytes
;
;	spd3 is 128 step mode
;
spd3	movf	curadr,w	;get address
	movwf	byte1 
	bcf	byte1,7		;clear valid flag
	movlw	B'00111111'	;128 bit speed
	movwf	byte2
	movf	adcdat,w
	movwf	byte3
	btfsc	chdata,4
	goto	revset
fwdset	bsf	byte3,7		;forward
	goto	errset
revset	bcf	byte3,7		;reverse
			
errset	movlw	4
	movwf	bytcnt
	goto	spdout      	;send speed packet


;
;	spd2 is 28 step mode
;
		
spd2	movf	curadr,w	;get address
	movwf	byte1
	bcf	byte1,7		;remove valid bit
	clrf	byte2		;clear speed byte
	decf	adcdat,w	;em stop?
	btfsc	STATUS,zbit
	goto	spd2e
	movlw	B'00000011'	;save last two bits
	andwf	adcdat,w
	movwf	div		;reuse div
	movf	adcdat,w	;save adcdat
	movwf	adcset		;reuse adcset as temp
	rrf	adcset,f        ;reduce speed to 4 bits
	rrf	adcset,f
	movlw	B'00011111'	
	andwf	adcset,f	;mask
	movlw	2
	subwf	adcset,w
	btfss	STATUS,carry	;2 or more?
	goto	nonout
	movlw	functs		;point to function table 
	addwf	chcnt,w		;add channel
	movwf	FSR		;indirection
	swapf	INDF,w
	movwf	temp
	rrf	temp,w
	andlw	B'00000011'	;mask except count
	subwf	div,w
	btfss	STATUS,carry	;count > div
	goto	nojit
	btfsc	STATUS,zbit	;count = div
	goto	nojit
	btfss	PORTD,2		;no jitter mode?
	goto	nojit
	movlw	B'00011111'	;is it step 28 already
	andwf	adcset,f	;mask
	subwf	adcset,w
	btfss	STATUS,zbit
		
	incf	adcset,f	;add 1



nojit	rrf	adcset,w        ;in 28 step mode
	btfsc	STATUS,carry
	bsf	byte2,4
	iorwf	byte2,f		;set speed
	
	
	
	
spd2f	call	dirsub		;set direction
	goto	spdout

nonout	clrf	adcset		;stop 
	goto	nojit
		
spd2e	movf	adcdat,w	;em stop
	movwf	byte2
	goto	spd2f

;
;	spd1 is 14 step mode. FO bit is set
;

spd1	movf	curadr,w	;get address
	movwf	byte1
        bcf	byte1,7
	decf	adcdat,w	;em stop?
	btfsc	STATUS,zbit
	goto	spd1e
	rrf	adcdat,f	;set for 14 steps only
	rrf	adcdat,f        ;reduce speed to 4 bits
	rrf	adcdat,w
	movwf	byte2		;set speed

	bcf	byte2,4		;F0 bit
	movlw	functs		;point to function table 
	addwf	chcnt,w		;add channel
	movwf	FSR		;Indirection
	btfsc	INDF,0		;test F0 bit
	bsf	byte2,4		;F0 on 
spd1f	call	dirsub		;set direction
	

spdout	movlw	.20
	goto	loop
spdo1	call	brup		;output up
	call	packet		;send speed packet
spdo2	btfss	consis,6	;a consist
	return 
	btfss	consis,7
	goto	lstcn1
	movlw	5
	call	addpre		;add 5 preamble cycles
	goto	nxtloc		;next in consist

spd1e	movf	adcdat,w
	movwf	byte2
	goto	spd1f

lstcn1	bcf	consis,6	;last in consist
	return

dirsub	btfsc	chdata,4	;check direction
	goto	revse1
fwdse1	bsf	byte2,5		;forward
	goto	errse1
revse1	bcf	byte2,5		;reverse
	
errse1	bcf	byte2,7
	bsf	byte2,6		;speed packet
	
	movlw	3
	movwf	bytcnt
	return

confn1	btfss	chdata,4	;direction in consist
	goto	revse1
	goto	fwdse1 




;	sends a stop to current loco
;
estop	movwf	curadr		;old address
	clrf	adcdat		;speed to zero
	incf	adcdat,f	;em stop
	call	deact		;deactivate if a consist
	

	
;*********************************
;
;	set up consist
;	loco address in curadr
;	consist number is function button
;	
;
setcon	movf	curfun,w	;get function button
	andlw	B'00001111'
	movwf	temp
	btfsc	STATUS,zbit	;no button?
	goto	noput
	movlw	.9		;too high?
	subwf	temp,w
	btfsc	STATUS,carry
	goto	noput 
	movf	temp,w
	call	conbut		;converts button number to address
	btfsc	STATUS,zbit	;invalid combination? (only one button
				;allowed)
	goto	noput
	movwf	temp		;for consist address
 
	movlw	.35             ;wait
	goto	loop
setc1	call	brdown		;output down
	decf	temp,f		;less 1
		                                              	
lookup	clrf	temp1
        clrf	temp2
	clrf	count4
	movf	curadr,w	;get handset address
	movwf	adrtmp
	bcf	adrtmp,7	;clear valid bit
	incf	count4,f	;1 in count 4
	movf	temp,w
	addlw	cons00		;start of consist block
	movwf	FSR
looku1	movf	INDF,w		;get loco
	btfsc	STATUS,zbit	;blank?
	goto	setblk		
looku2	andlw	B'01111111'	;mask direction bit
	subwf	adrtmp,w	;same?
	btfsc	STATUS,zbit	;no
	goto	looku3
	movf	adrtmp,f	;is address 00?
	btfss	STATUS,zbit	
	goto	again		;no
looku3	movf	count4,w
	movwf	temp2		;number that matches	
		
again	incf	count4,f
	incf	FSR,f
	movlw	5
	subwf	count4,w
	btfss	STATUS,zbit
	goto	looku1
	goto	check 
	
setblk	movf	count4,w
	movwf	temp1		;number that is a blank
	goto	again
	
check	movlw	4     		;set FSR back to block start
	subwf	FSR,f

	movf	temp2,w         ;was there a match?
	btfsc	STATUS,zbit
	goto	check1  	;no
	decf	temp2,w		;get which one
	addwf	FSR,f
	goto	clrout		;clear loco

check1	movf	temp1,w
	btfsc	STATUS,zbit	;was there a blank
	goto	noput	
	decf	temp1,w
	addwf	FSR,f
putin	movf	adrtmp,w	;get address
	movwf	INDF		;put in block
	btfsc	chdata,4	;direction for consist
	bsf	INDF,7		;top bit of address is direction

	movf	INDF,w
	bsf	STATUS,RP1	;page 2
	movwf	EEDATA
	bcf	STATUS,RP1
putcon	movlw	cons00          ;get eeprom address
	subwf	FSR,w		;get block offset
	bsf	STATUS,RP1	;page 2
	movwf	EEADR
	bcf	STATUS,RP1 
	movlw	.36
	call	loop		;wait
setc2	call	brup		;output up
	
	bsf	STATUS,RP0	;page 3
	bsf	STATUS,RP1
	bcf	EECON1,EEPGD
	bsf	EECON1,wren
	
	call	eewrit		;write loco to eeprom
				;end of write
	movf	alarmc,w	;set toggle
	iorwf	conbit,f
	iorwf	alarm,f		;set alarm for acknowledge
noput	bcf	consis,4
	movlw	4
	call	addpre		;add 4 preambles

	goto	speed

clrout	clrf	INDF
	bsf	STATUS,RP1
	clrf	EEDATA
	bcf	STATUS,RP1
	goto	putcon		;clear table entry

;******************************************************
;
;	check if address is a consist and if so
;	send speed packets to all in the consist
;	else send speed packet as normal
;
			
conchk	movlw	.90		;consist address?
	subwf	curadr,w	;90 or higher
	btfss	STATUS,carry
	goto	notcon		;not a consist
	sublw	.3
	btfss	STATUS,carry	
	goto	notcon		;not a consist
	bsf	consis,7	;is a consist
	bsf	consis,6
	movf	chdata,w	;save chdata
	movwf	mask
	movlw	.90
	subwf	curadr,f	;consist block address starts at 0
	bcf	STATUS,carry
	rlf	curadr,f
	rlf	curadr,f	;multiply by 4
	movlw	cons00		;start of table
	addwf	curadr,w
	movwf	temp2		;set index
conck1	movlw	.4		;4 locos per consist
	movwf	count4		;4 in count4
loadu1	movf	temp2,w
	movwf	FSR
	movf	INDF,w		;get table entry
	btfss	STATUS,zbit	;is it blank
	goto	spdin		;send packet to loco
	decfsz	count4,f	;block end?
	goto	nxtloc
	goto	lstloc		;last in consist
nxtloc	incf	temp2,f
	goto	loadu1		;next in block
spdin	movwf	curadr		;loco address to curadr
	movf	mask,w		;recover original chdata

	btfss	curadr,7	;consist direction		
	goto	norev		;not reverse
	xorlw	B'00010000'	;direction for consist
norev	movwf	chdata		;set for this loco
	bcf	curadr,7	;clear direction bit
	movlw	4
	call	addpre		;4 extra preamble cycles
	goto	speedz
	
lstloc	bcf	consis,7	;last of consist
	goto	spdin				
;********************************************
;
;	checks if loco is in an active consist and if so
;	does not send speed packet. As a loco may be in
;	more than one consist which may or not be active, 
;	this is a bit messy.
;
notcon	clrf	used
	movlw	cons00
	movwf	FSR

nexloc	movlw	.17
	goto	loop
nexld1  call	brdown		;output down
	call	conloc
	sublw	0
	btfsc	STATUS,zbit
	goto	nexlo1		;no match in consist 90
	btfsc	consis,0	;consist active?
	incf	used,f
nexlo1	movlw	.24
        goto	loop
nexlu1	call	brup		;output up
	movlw	2
	call	addpre		;add 2 preamble cycles
	incf	FSR,f
	call	conloc
	sublw	0
	btfsc	STATUS,zbit
	goto	nexlo2		;no match in consist 91
	btfsc	consis,1	;consist active?
	incf	used,f
nexlo2	movlw	.33
        goto	loop
nexld2  call	brdown		;output down
	incf	FSR,f
	call	conloc 
	sublw	0
	btfsc	STATUS,zbit
	goto	nexlo3		;no match in consist 92
	btfsc	consis,2	;consist active?
	incf	used,f
nexlo3	movlw	.34
        goto	loop
nexlu2	call	brup		;output up
	incf	FSR,f
	call	conloc 
	sublw	0
	btfsc	STATUS,zbit
	goto	nexlo4		;no match in consist 93
	btfsc	consis,3	;consist active?
	incf	used,f
nexlo4	movf	used,f		;not zero if in a consist?
	btfsc	STATUS,zbit
	goto	speedz		;send speed packet to loco
	movlw	4		;4 extra cycles
	goto	lidle1		;send an idle instead

conloc	movlw	4
	movwf	count
conlo1	movf	INDF,w		;get loco
	andlw	B'01111111'	;mask direction
	subwf	curadr,w
	btfsc	STATUS,zbit	;not in a consist
	retlw	1		;match
	decfsz	count,f
	goto	conlo2
	retlw	0		;no match
conlo2	incf	FSR,f
	goto	conlo1
	
	
;********************************************
;	sends a function packet if required
;
		
sndchg	incf	fcount,w	;increment function counter
	andlw	B'00000111'	;eight channels
	movwf	fcount
	movf	fcount,f	;is fcount zero
	btfss	STATUS,zbit
	goto	getfun
	movlw	1
	movwf	count0
	call	idle		;was zero so add an idle packet
getfun	movlw	locos		;loco table
	addwf	fcount,w	;add offset
	movwf	FSR
	btfss	INDF,7		;invalid address?
	goto	inval		;don't send a function
	
	movf	INDF,w		;get address
	movwf	byte1
	bcf	byte1,7		;clear valid flag
	movf	byte1,f		;is address zero?
	btfsc	STATUS,zbit
	goto	inval		;yes so dont send function
	
	movlw	functs		;start of function stack
	addwf	fcount,w	;offset
	movwf	FSR		;set pointer
	

	movf	INDF,w		;get function
	andlw	B'00001111'	;mask mode bits	
	movwf	byte2
	rrf	byte2,f		;mod for f0
	
	btfsc	STATUS,carry	;F0 was zero
	bsf	byte2,4		;set F0
		
	
	bsf	byte2,7		;set for function group 1
	
	movlw	3
	movwf	bytcnt
	call	preamb        	;preamble
	call	packet        	;send function packet
	return
	
inval 	movlw	.25	    	;no function packet
	goto	loop            ;but needs an extra
                              	;preamble cycle to make up time
inv1	call	brdown		;output down
	movlw	8
	addwf	FSR,f		;point to function
	movlw	B'11100000'
	andwf	INDF,f		;clear any old function data
	movlw	.26
	goto	loop
inv2	call	brup		;output up		
	return
	
;		

;	eeprom write subroutine. Write EEDATA into EEADR
;	does not wait for write complete as this would interfere
;	with the DCC bit stream timing.
;	can only write every 8th packet anyway.

eewrit	bcf	INTCON,GIE
	movlw   0x55
        movwf   EECON2
        movlw   0xAA
        movwf   EECON2
        bsf     EECON1,wr
	nop
        bcf     EECON1,wren
        bcf     STATUS,RP0
	bcf	STATUS,RP1	;page 0
        return

eeread	bsf	STATUS,RP0	;page 3
	bcf	EECON1,EEPGD
	bsf	EECON1,rd	;set read bit
	bcf	STATUS,RP0	;back to page 2
	movf	EEDATA,w	;get data
	bcf	STATUS,RP1	;page 0
last	return



;************************************************
;
;	clear consist EEPROM space
;
	org	0x2100
	de	0
	de	0
	de	0
	de	0
	de	0
	de	0
	de	0
	de	0
	de	0
	de	0
	de	0
	de	0
	de	0
	de	0
	de	0
	de	0
	
;	lookup table for speed curve in EEPROM
;	not finalised yet
;
	org	0x2130 
	de	.7
	de	.8
	de	.9
	de	.10
	de	.12
	de	.14
	de	.16
	de	.19
	de	.24
	de	.29
	de	.37
	de	.48
	de	.65
	de	.93
	de	.145
	de	.255
		

	
	
	end

	
