;************************************************************************
; TaPRK IR-LINK-RECEIVER
;************************************************************************

	LIST P = 16F84A,  R = HEX		;Prosessortype, radix
	INCLUDE	"p16f84A.inc"			;w,f,porta,portb etc. 
	ERRORLEVEL -224, -302			;prevents error from
						;"tris"-command
        __CONFIG _PWRTE_ON & _HS_OSC & _WDT_OFF   

;************************************************************************
; SCHEMATIC DIAGRAM
;************************************************************************

;	          		  +---+_+---+
;		N/C	PORTA.2 ->|1      18|<- PORTA.1 N/C
;		N/C	PORTA.3 ->|2      17|<- PORTA.0	TSOP1738 act.lo
;			PORTA.4 ->|3      16|-- XTAL
;			    Vdd --|4      15|-- XTAL
;			Vss(GND)--|5      14|-- Vdd (+5V)
;	Strobe_MUX	PORTB.0 <-|6      13|-> PORTB.7	LED1
;	Strobe_Disp	PORTB.1 <-|7      12|-> PORTB.6	N/C
;	Comm.Ser.data	PORTB.2 <-|8      11|-> PORTB.5	N/C
;	Comm.Ser.clock	PORTB.3 <-|9      10|-> PORTB.4	N/C
;		    	          +---------+

;************************************************************************
; MAIN IDEA
;************************************************************************
;
;	This is based on Holger Klabunde's design, but is completely
;	rewritten in assembler.
;
;	Timing
;	======
;	26us cycle of IR-LED on/off gives 38,5kHz
;	16 cycles for 1/2 bit -> 16 x 26us= 416 us
;	Prescaler of 1:8 makes TMR0 advance every 8us (@4MHz crystal)
;	1/2 bit needs 416/8 = 52 ticks of TMR0
;	1/4 bit needs  52/2 = 26 ticks of TMR0
;
;	This is loosely following Philips RC5, exept:
;
;	-- Bit length 2 X 416us!
;	-- Only one start bit, and it is "0"
;	-- Only 8 data bits
;	-- Added parity bit
;	-- Total of 10 bits
;
;	This is presumably the same as Lorell Joiner's
;	setup, done with hardwired UART some 10 years ago, but instead
;	of using 250 kHz carrier and on/off bits, I use the 
;	Bit formation same as RC5 at 36...38 kHz carrier:
;
;	+---+                 +---+
;	|   |     =0          |   |    =1
;       +   +---+         +---+   +
;
;	TSOP1738 receiver module inverts the above
;
;	Serial output to 7-segment display and C-MOS switches
;	4094 serial-in-parallel-out will be used. Two branches, one
;	for controllers (PC-Joystick through C-MOS switches) and the
;	other for speed step (hex-) display. Both branches may use
;	common data and clock, strobe sent only to correct branch.
;
;	I'll use 4066 to connect a set of trimmers to replace
;	joystick pot.
;
;	Functions (F0 and F1) will be added later!
;
;	==============================================================
;	5-PIN STEREO DIN DISP. UNIT 
;	--------------------------------------------------------------
;		1 CK	 Orange  [Biltema
;		4 GND	 Green	  keyboard
;		2 DATA	 Blue	  extension
;		5 +5V	 White	  cord
;		3 STROBE Black	  colours]

;	==============================================================
;	3.5mm STEREO IR-MODULE CONNECTOR 
;	--------------------------------------------------------------
;		Tip	Data
;		Ring	+
;		Sleeve	GND

;	==============================================================
;	RESISTOR NETWORK VALUES (eq.47K pot)
;	--------------------------------------------------------------
;		1	2K9
;		2	6K
;		4	11K9
;		8	23K5
;	--------------------------------------------------------------
;	4094 switch on-resistance 250R/switch, so all cable throttles
;	will be equipped with a 1K resistor in addition to pot to
;	compensate as this will not go to 0 ohms. Will also change
;	cable throttles to have max. speed at min resistance in case
;	of power failure in this setup! [NB: resistance values above
;	are thoise we used, our 47K pots were in fact approx 43K5
;	potentiometers, therefore the odd figures!]
;
;	Throttle number 0 now has working functions! Single press
;	of F0 or F1 will produce correct pattern and keeping the
;	button down will keep the functions last dir-button press
;	down.
;
;	If speed is zero then speed will be advanced to step one
;	and it will return to last used speed after function procedure
;	(zero if speed was zero before pressing of F-button)
;	This is still quick and dirty. We'll polish the code and
;	make it operate other controllers as well
;
;************************************************************************
; VARIABLES
;************************************************************************

	CBLOCK H'0C'

		Data1		;Data from IR-receiver
		Data2		;waiting for conversion to 7-seg...
		Parity		;Parity
		Err		;error flag from ReadBit
		bitcount	;bit counter

		count_gp	;freewheeling counter
		blink		;blink on/off
		f_served	;number of cab whose f's are to be served

		last_0		;cab 0 last received command
		speed_0		;cab 0 speed (4 bits)
		func_0		;cab 0 functions
		chann_0		;cab 0 channel (msb hi: unfinished)

		last_1		;cab 0 last received command
		speed_1		;cab 0 speed (4 bits)
		func_1		;cab 0 functions
		chann_1		;cab 0 channel (msb hi: unfinished)

		last_2		;cab 0 last received command
		speed_2		;cab 0 speed (4 bits)
		func_2		;cab 0 functions
		chann_2		;cab 0 channel (msb hi: unfinished)

		last_3		;cab 0 last received command
		speed_3		;cab 0 speed (4 bits)
		func_3		;cab 0 functions
		chann_3		;cab 0 channel (msb hi: unfinished)

	ENDC

;************************************************************************
; STATICS
;************************************************************************

	#DEFINE TSOP		PORTA, 0 	;IR receiver
	#DEFINE M_STROBE	PORTB, 1 	;MUX Strobe
	#DEFINE S_STROBE	PORTB, 0 	;7-SEG Strobe
	#DEFINE S_DATA		PORTB, 2 	;7-SEG Data
	#DEFINE S_CLOCK		PORTB, 3 	;7-SEG Clock
	#DEFINE	LED1		PORTB, 7	;Pilot light
	#DEFINE HALFBIT		.203 		;= 255-52
	#DEFINE QUADBIT		.229		;= 255-26

;************************************************************************
;RESTART/INT-START
;************************************************************************

	ORG     0		; Restart vector
	goto	main

	ORG	4		; INT vector
	retfie

;------------------------------------------------------------------------
; Initialize I/O ports, Interrupts, Timers etc
;------------------------------------------------------------------------
init

	movlw	b'00000000'	;RB0..7=out
	tris	portb		;
	movlw	b'00011111'	;RA0..4=in
	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			;
	bsf	STATUS, RP0	;
	movlw	b'00000010'	;Pullup=on, Prescaler= 1:8
	movwf	OPTION_REG	;
	bcf	STATUS, RP0	;

ramc	movlw	0x0c		; start of 16F84 ram
	movwf	fsr
ramc1	clrf	indf		; clear indirect location
	incf	fsr, f		; next location
	btfss	fsr, 7		; cleans up to 0x7f
	goto	ramc1		; [From J.Niinikoski]

ramdone
	movfw	DATA1		;clear w

	call disp_speed		;Show speed w. 7-seg display
	call mux_speed		;Drive mux to operate speed network

	return


;------------------------------------------------------------------------
; Increment cab's typematic counters
;------------------------------------------------------------------------


IncCounters
	tstf	count_gp	;set zero flag from counter
	skpz			;skip if zero
	goto	gpnz		;non-zero
	goto	gpz		;zero
gpnz
	bsf	LED1		;pilot off
	incf	count_gp, f	;not yet -> increment
	return			;[21/4-2002]
gpz
	bcf	LED1		;pilot on
	incf	blink, f	;change blink (choose bit to follow
				;for different rates!)
	call func		;
	return			;

;------------------------------------------------------------------------
; Read whole bit, set/clear error reset TMR0, count parity
;------------------------------------------------------------------------

ReadBit
	movlw	0xFF		;Set error state,
	movwf	ERR		;will be cleared if bit correctly read

rb1	btfss	INTCON, T0IF	;wait for timer to overflow
	goto 	rb1		;not yet

	movlw	HALFBIT		;new timer base
	addwf	TMR0, f		;add to just overflowed timer
	bcf	INTCON, T0IF	;clear overflow flag

	call	IncCounters	;increment countgp at each INTCON T0IF

	btfsc	TSOP		;test 1st halfbit state
	goto 	read1		;was high -> beginning of "1"

read0	btfss	INTCON, T0IF	;wait for timer to overflow
	goto 	read0		;not yet

	movlw	HALFBIT		;new timer base
	addwf	TMR0, f		;add to just overflowed timer
	bcf	INTCON, T0IF	;clear overflow flag

	call	IncCounters	;increment countgp at each INTCON T0IF

	btfss	TSOP		;test 2nd halfbit, must be high (set)
	return			;was not, error, return

	bcf	STATUS, C	;have read a "0"
	rlf	DATA1, f	;move it into DATA1
	clrf	ERR		;clear error state
	return

read1	btfss	INTCON, T0IF	;wait for timer to overflow
	goto 	read1		;not yet

	movlw	HALFBIT		;new timer base
	addwf	TMR0, f		;add to just overflowed timer
	bcf	INTCON, T0IF	;clear overflow flag

	call	IncCounters	;increment countgp at each INTCON T0IF

	btfsc	TSOP		;test 2nd halfbit, must be low (clear)
	return			;was not, error, return

	bsf	STATUS, C	;have read a "1"
	rlf	DATA1, f	;move it into DATA1
	incf	Parity, f	;add 1 to parity
	clrf	ERR		;clear error state
	return

;---------------------------------------------------------------
;Lookup-table for 7-seg display, uses 4094 shift registers
;---------------------------------------------------------------

Lookup
	andlw	0x0F		;clear top to prevent going past
	addwf	pcl,f		;
	retlw	b'00011000'	; 0
	retlw	b'01111011'	; 1
	retlw	b'00101100'	; 2
	retlw	b'00101001'	; 3	 77777
	retlw	b'01001011'	; 4	6     8
	retlw	b'10001001'	; 5	6     8
	retlw	b'10001000'	; 6	6     8
	retlw	b'00111011'	; 7      55555
	retlw	b'00001000'	; 8	1     3
	retlw	b'00001001'	; 9	1     3
	retlw	b'00001010'	; A	1     3  44
	retlw	b'11001000'	; b	 22222   44
	retlw	b'10011100'	; C
	retlw	b'01101000'	; d
	retlw	b'10001100'	; E
	retlw	b'10001110'	; F
	retlw	b'11101111'	; -

;---------------------------------------------------------------
;Lookup-table for cab to be served for functions
;---------------------------------------------------------------

lookup_last
	addwf	pcl,f		;
	retlw	last_0		; point to cab 0's last cmd
	retlw	last_1		; point to cab 1's last cmd
	retlw	last_2		; point to cab 2's last cmd
	retlw	last_3		; point to cab 3's last cmd

;------------------------------------------------------------
; MUX out SPEED
;------------------------------------------------------------
mux_speed
	movf	speed_1, w	;speed_x to w
	btfsc	chann_1, 7	;Check for unfinished ch selection
		movlw	.0	;under construction: no output
	call 	so_byte		;and shift out byte

	movf	speed_0, w	;speed_x to w
	btfsc	chann_0, 7	;Check for unfinished ch selection
		movlw	.0	;under construction: no output
	call 	so_byte		;and shift out byte

	bsf	M_STROBE	;strobe out
	nop			;wait for slow C-MOS
	bcf	M_STROBE	;

	return

;-------------------------------------------------------------------------
; DISPALY SPEED
;-------------------------------------------------------------------------
; New development at cab 0:
;	if chann_0 = 0 then only dash is displayed as cab is
;	effectively disconnected!
;	While choosing a channel, the dp will be lit if the candidate
;	channel equals the presently active one
;
;	cab 1 has old ch routine,
;	cabs 2 and 3 have yet nothing (well -- they have the 'dash')!
;
;	Must make this also "modular" (through FSR, like functions)
;-------------------------------------------------------------------------

Disp_speed
d3	movlw	b'11101111'	;light (clear) 'dash' only!
	call 	so_byte		;and shift out byte
d2	movlw	b'11101111'	;light (clear) 'dash' only!
	call 	so_byte		;and shift out byte

d1	btfsc	chann_1, 7	;test if unfinished channel sel?
	goto	d_ch1		;yes, what's the score?
	movf	speed_1, w	;no, speed_x to w
	andlw	0xF		;clear top nibble
	call	lookup		;convert to 7-segment
	btfsc	speed_1, 4	;Check for direction button
	andlw	b'11110111'	;light (clear) 'dp' if set!
	call 	so_byte		;and shift out byte
	goto 	d0		;next
d_ch1
	movf	chann_1, w	;channel: chann_x to w
	andlw	0xF		;clear top nibble
	btfss	last_1, 5	;ordinary speed packet received?
	movlw	b'11101111'	;yes, dash out!
	btfsc	blink, 2	;Check for blink phase
	movlw	0xFF		;turn off in case
	call 	so_byte		;and shift out byte


d0	btfsc	chann_0, 7	;test if unfinished channel sel?
	goto	d_ch0		;yes, what's the score?
	tstf	chann_0		;test channel
	skpnz			;is there a channel
	goto 	d0_null		;no, the throttle is disconnected!
	movf	speed_0, w	;yes, speed_x to w
	andlw	0xF		;clear top nibble
	call	lookup		;convert to 7-segment
	btfsc	speed_0, 4	;Check for direction button
	andlw	b'11110111'	;light (clear) 'dp' if set!
	call 	so_byte		;and shift out byte
	goto 	ds		;strobe out

d0_null
	movlw	b'11101111'	;light (clear) 'dash'only!
	call 	so_byte		;and shift out byte
	goto 	ds		;strobe out

d_ch0
	movfw	chann_0		;load current channel to accumulator,
	andlw	0x0F		;clear the flag bit and
	xorwf	last_0, w	;subtract last_0 to test equality
	skpnz			;well, was it equal?
	goto	d_ch0_eq	;yes, show the dp
	movfw	last_0		;no, lets get the candidate
	call	lookup		;convert to 7-segment
	btfsc	blink, 2	;Check for blink phase
	movlw	0xFF		;turn off in case
	call 	so_byte		;and shift out byte
	goto 	ds		;strobe out
d_ch0_eq
	movfw	last_0		;equal, lets get the candidate
	call	lookup		;convert to 7-segment
	andlw	b'11110111'	;light (clear) 'dp'!
	btfsc	blink, 2	;Check for blink phase
	movlw	0xFF		;turn off in case
	call 	so_byte		;and shift out byte
	goto 	ds		;strobe out
	
ds
	bsf	S_STROBE	;strobe out
	nop			;wait for slow C-MOS
	bcf	S_STROBE	;

	return


;-----------------------------------------------------------------------
;shift out one byte from w (uses DATA1 and BITCOUNT)
;-----------------------------------------------------------------------

so_byte
	movwf	DATA1		;and put out for shifting

	movlw	.8		;all 8 bits
	movwf	BITCOUNT	;

sob1	rlf	DATA1, F	;rotate through carry (MSB first) and 
	btfsc	STATUS, C	;in case of carry shift out 1 
	goto	so1		;carry=1
so0				;carry=0

	bcf	S_DATA		;data  lo
	bsf	S_CLOCK		;clock hi
	nop			;wait for slow C-MOS
	bcf	S_CLOCK		;clock lo

	goto	sob2
so1

	bsf	S_DATA		;data  hi
	bsf	S_CLOCK		;clock hi
	nop			;wait for slow C-MOS
	bcf	S_CLOCK		;clock lo

sob2	decfsz	BITCOUNT, F	;all bits sent?
	goto 	sob1		;not yet, shift out more
	return			;yes, this byte shifted out
	

;-----------------------------------------------------------------------
;Function action (now works with all cabs!)
;
;	This is rather complicated, but the idea is that
;	FSR contains the address of last_x of the cab in question.
;	To manipulate and test also speed_x and func_x FSR
;	needs to be incremented and decremented.
;	When jump to another spot is made the comment
;	at label row will tell what register the FSR is pointing
;	at the moment of entry
;-----------------------------------------------------------------------
func

	incf	count_gp, f	;count_gp to non-zero!

	;---------------------------------------------------------------
	; Move the FSR to point next cabs particulars
	;---------------------------------------------------------------
	incf	f_served, w	;point to next cabs particulars
	movwf	f_served	;return updated valued
	btfsc	f_served, 2	;gone past 4?
	goto	fdisp		;yes, display what we got
	call	lookup_last	;no, get address of last_x of this cab
	movwf	FSR		;and set this to indirect pointer

f0				;--- FSR: last_x -------------------
	incf	FSR, f		;FSR: last_x -> speed_x
	incf	FSR, f		;FSR: speed_x-> func_x
	
	tstf	INDF		;let's see cab x's func_x status?
	skpz			;Do we have fun?
	goto	f0yes		;Yes, let's process the fun!

				;no, let's sync last speed w. last cmd
	decf	FSR, f		;FSR: func_x ->speed_x
	decf	FSR, f		;FSR: speed_x->last_x

	movfw	INDF		;move last command (non func!) to w
	andlw	0x1f		;clear 3 top bits

	incf	FSR, f		;FSR: last_x -> speed_x
	movwf	INDF		;move to speed_0
	return			;and finish for now

f0yes				;--- FSR: func_x -------------------
				;so, func_x was non zero!
	decf	FSR, f		;FSR: func_x -> speed_x
	tstf	INDF		;Let's see cab has speed?
	skpz			;Do we have speed?
	goto	f0act		;yes, let's have some more activity

	incf	INDF, f		;no, lets add some speed
	return			;and finish for now

f0act				;--- FSR: speed_x -----------------
				;Now we have speed and fun is non-zero
	btfss	INDF, 4		;Is dir on?
	goto 	f0setdir	;no, go and put it on

				;yes [speed<>0; func<>0; dir=1]
	incf	FSR, f		;FSR: speed_x-> func_x
	decfsz	INDF, w		;Test if func_x is one [1->0?]
	goto	f0diroff	;No, proceed to put dir off etc....
				;yes  [speed<>0; func=1; dir=1]
	decf	FSR, f		;FSR: func_x ->speed_x
	decf	FSR, f		;FSR: speed_x->last_x

	btfsc	INDF, 5		;Test if last_x has a F-command B5=1
	return			;yes, lets keep the dir as "1"
				;no, lets clear dir and dec. func
	incf	FSR, f		;FSR: last_x -> speed_x
	incf	FSR, f		;FSR: speed_x-> func_x

f0diroff			;--- FSR: func_x -------------------
	decf	FSR, f		;FSR: func_x ->speed_x
	bcf	INDF, 4		;yes, put it off
	incf	FSR, f		;FSR: speed_x-> func_x
	decf	INDF, f		;and decrement fun contents
	return			;and go to to see if next has fun

f0setdir			;--- FSR: speed_x ------------------
	bsf	INDF, 4		;set the dir of this cab
	return			;and finnish for now

fdisp				;--- FSR: whatever ;) --------------
	call disp_speed		;Show speed w. 7-seg display
	call mux_speed		;Drive mux to operate speed network
	movlw	0xff		;lets make sure next entry to f gets zero
	movwf	f_served	;as f_served goes over top
	return
	
;------------------------------------------------------------------------
; MAIN PROGRAMME
;------------------------------------------------------------------------
main
	call 	init		;intialize ports
m1
	btfss	TSOP		;wait for beginning of the broadcast
	goto 	m2		;found, start interpreting

	btfss	INTCON, T0IF	;has timer overflowed
	goto 	m1		;not yet

	movlw	HALFBIT		;new timer base
	addwf	TMR0, f		;add to just overflowed timer
	bcf	INTCON, T0IF	;clear overflow flag

	call	IncCounters	;increment countgp at each INTCON T0IF

;	tstf	count_gp	;set zero flag from counter
;	skpz			;skip if zero
;	goto 	m1		;wait for broadcast
m2
	movlw	QUADBIT		;advance 1/4 bit to hit middle of
	movwf	TMR0		;1st half-bit of start-bit ("0")
	bcf	INTCON, T0IF	;just in case: clear Timer overflow flag

	call	ReadBit		;read whole start-bit
	btfsc	ERR, 0		;if error, return to square one
	goto 	m1		;

	btfsc	DATA1, 0	;last read bit (LSB of DATA1) must
	goto 	m1		;be "0" as it was the start bit

	movlw	8		;read 8 bits
	movwf	BITCOUNT
	clrf	DATA1		;clear read DATA1
	clrf	Parity		;clear parity

m3	call 	ReadBit		;read whole DATA1 bit
	btfsc	ERR, 0		;if error, return to square one
	goto 	m1		;

	decfsz	BITCOUNT, f	;All DATA1 bits read?
	goto	m3		;not yet, read more

	movfw	DATA1		;all DATA1 read
	movwf	DATA2		;move to safety

	call	ReadBit		;read parity bit
	btfsc	ERR, 0		;if error, return to square one
	goto 	m1		;

	btfsc	Parity, 0	;Parity must now be clear
	goto	m1		;if not return to square one
	bcf	PORTA, 2

ad
;-----------------------------------------------------------------------
;ADDRESS TESTING

	btfss	DATA2, 7	;test for address MSB
	goto	adlo		;address=0/1
	goto	adhi		;address=2/3

adlo
	btfss	DATA2, 6	;test for address LSB
	goto	ad0		;address=0
	goto	ad1		;address=1

adhi
	btfss	DATA2, 6	;test for address LSB
	goto	ad2		;address=2
	goto	ad3		;address=3
;----------------------------------------------------------------
; Handling of incoming data packets
; ---------------------------------
;	[not yet reality, but soon...]
;	The handling of incoming data depends on present status
;	of the receiver:
;
;		- pending Functions handling and
;		- pending Channel selection handling
;
;	In case there are pending Functions handling (func_x <> 0)
;	all incoming packets are just copied to last_x
;	so that the speed of the loco after dir-flashing sequence
;	may be received during flashing (does not adjust speed during
;	flashing yet). The functions handler is called by the
;	count_gp updating routine (flashes the dir button and
;	decrements func_x.
;
;	In case the channel selection is still pending (MSB of
;	chann_x is high, no ordinary speed packets are taken in at all!
;	The exception is if incoming speed packet has speed=0. That
;	will cause copying of last channel commands channel from
;	last_x to chann_x and terminates channel selection (MSB low).
;
;	in case the received packet is a functions packet, the
;	function number is extracted (lower nibble) and placed in
;	func_x and the received byte as is goes to last_x
;	(further speed packets will also go to last_x so that
;	when the functions handilng nears completion the last_x
;	is tested in case the transmitter still has the funtion button
;	pressed, thus resulting contunued dir-button down. This
;	is carried in "count_gp" triggered routine!
;
;	In case the packet is a channel selection packet, the MSB
;	of chann_x is taken high (as a flag) and packet copied to last_x.
;	The channel of chann_x is kept as is, so that the display routine
;	can display dp in case the previuous setting is selected
;	(in case one got "accidentally" into channel selection this
;	provides a way to undo -- yet one must find the channel that
;	lights the dp first!). The speed_x will be kept cleared while
;	MSB of chann_x is high!
;
;	When the transmitter ceases sending channel packets, it will
;	send speed packets, but the chann_x MSB will remain high!
;	Incoming speed packets will be discarded as mentioned above
;	(last_x contains the next channel number!) until a speed=0 packet
;	is received, and then last_x info will be used to fill func_x.
;
;	Presently it seems that starting a channel selection during
;	pending functions will just extend the last dir-button.
;
;	I'm wish, that in case a used channel is displayed while
;	browsing the new candidate, the display should show "r" like
;	reserved!
;
;	So: only in case chann_x MSB is high and non-zero speed packet is
;	received, it will be discarded, else it is copied to last_x
;
;	ATTENTION: DEVELOPMENT ONLY AT cab 0!
;	Cab 1 has previous version!
;	Cabs 2 and 3 don't work at all!
;	Must make this also "modular" (through FSR, like functions)
;--------------------------------------------------------------------------	

ad0
	tstf	func_0		;Test Functions:
	skpz			;Any functions pending?
	goto	fun_on		;yes, go for it

fun_off				;no, so fun is off
	btfsc	chann_0, 7	;Any channel selection pending?
	goto 	ch_on		;yes, go for it!

all_off				;no, all are off!
	btfss	data2, 5	;Test if speed packet coming?
	goto	all_off_sp_in	;yes, go for it!
	btfss	data2, 4	;no, lets see if func packet coming?
	goto	all_off_fun_in	;yes, go for it!

all_off_ch_in			;no, so this must be channel-stuff
	bsf	chann_0, 7	;set pending ch flag hi!
	movfw	data2		;Load incoming into accumulator,
	andlw	0x0F		;clear top nibble,
	movwf	last_0		;and move as next ch candidate
	goto	m4		;and quit!

fun_on
	movfw	DATA2		;copy new packet to accumulator
	movwf	last_0		;and on to last command
	goto	m4		;and quit!

ch_on
	btfss	data2, 5	;received a speed packet?
	goto	ch_on_sp_in	;yes, go for it
	btfss	data2, 4	;no, is it a function packet?
	goto	m4		;yes, not interested due to pending...

ch_on_ch_in			;Channel pending, got a new ch packet
	movfw	data2		;As it's another channel candidate, we'll
	andlw	0x0F		;clear top to expose proposed ch number
	movwf	last_0		;and make it available at last_0
	goto	m4		;and quit!

ch_on_sp_in			;Channel pending, received a speed packet
	movfw	data2		;no, lets see, if it's speed=0 packet
	andlw	0x0F		;by clearing top  and
	skpz			;so, is it zero?
	goto 	m4		;no, waste it!
	movfw	last_0		;yes, so channel candidate at last_0
	movwf	chann_0		;is new channel (and ch-flag becomes cleared too!)
	goto	m4		;and quit!
	
all_off_sp_in			;no pending stuff, got a speed packet
	movfw	DATA2		;Move DATA to w
	movwf	last_0		;new last command
	andlw	0x1f		;clear only 3 top bits
	movwf	speed_0		;move to speed_0
	goto	m4		;and quit!

all_off_fun_in			;no pending stuff, got a function packet
	movfw	DATA2		;Let's see which F-button pressed
	andlw	b'00001111'	;by masking out top nibble
	movwf	func_0		;and make it to cab's next function,
	goto	m4		;and quit!

;----------------------------------------------------------------------;
; OLD ad0			                                       ;
	movfw	last_0		;load last command to accumulator
	subwf	DATA2, w	;subtract DATA2 from last command
	skpnz			;skip if non-zero
	goto	m4		;nothing new, goto m4
	movfw	DATA2		;DATA2 to accumulator
	movwf	last_0		;accumulator to last command
	tstf	func_0		;Test if F-stuff pending,
	skpz			;and forget this packet
	goto 	m4		;and pass

	btfsc	DATA2, 5	;test for Speed/Function bit
	goto 	ad0f		;set (1): cab1 F-stuff
	movfw	DATA2		;clear: move DATA to w
	andlw	0x1f		;clear 3 top bits
	movwf	speed_0		;move to speed_0
	tstf	speed_0		;is speed 0
	skpnz
	bcf	chann_0, 7	;yes no pending channel!
	goto	m4
ad0f
	btfsc	DATA2, 4	;test if it's a channel select packet?
	goto 	ad0ch		;yes, let's save it
	movfw	DATA2		;no,let's see which F-button pressed
	andlw	b'00001111'	;by masking out top nibble
	movwf	func_0		;and make it to cab x's function,
	goto	m4		;and so done here
ad0ch
	movfw	DATA2		;no,let's see which channel proposed
	andlw	b'00001111'	;by masking out top nibble
	iorlw	b'10000000'	;this is pending stuff (msb=1)
	movwf	chann_0		;and make it to cab x's function,
	goto	m4		;and so done here
;				                                      ;
;---------------------------------------------------------------------;


ad1
	btfsc	DATA2, 5	;test for Speed/Function bit
	goto 	m4		;set (1) no F-stuff handler yet, skip
	movfw	DATA2		;move DATA to w
	andlw	0x1f		;clear 3 top bits
	movwf	speed_1		;move to speed_1
	goto	m4

;-------------------------------------------------------------------
ad2
;-------------------------------------------------------------------
ad3
	goto m4

m4
	call disp_speed		;Show speed w. 7-seg display
	call mux_speed		;Drive mux to operate speed network

	goto 	m1
	end

