;************************************************************************
; TaPRK IR-LINK-TRANSMITTER ROTARY ENCODER VERSION  2007-11-18
;************************************************************************
; WITH ROTARY ENCODER FOR SPEED
;************************************************************************
	LIST P = 16F628,  R = HEX		;Prosessortype, radix
	INCLUDE	"p16f628.inc"			;w,f,porta,portb etc. 
	ERRORLEVEL  -302 			;prevents some errors

        __CONFIG _HS_OSC & _LVP_OFF & _WDT_OFF & _PWRTE_ON & _BODEN_ON & _MCLRE_OFF 

;************************************************************************
; SCHEMATIC DIAGRAM
;************************************************************************
;
;	          		  +---+_+---+
;	GROUP1		PORTA.2 <-|1      18|-> PORTA.1	IR-LED act.high
;	GROUP2		PORTA.3 <-|2      17|-> PORTA.0	DATA_OUT
;	ENC_A		PORTA.4 ->|3      16|-- XTAL
;	ENC_B		PORTA.5 ->|4 PIC  15|-- XTAL
;			Vss(GND)--|5 16F  14|-- Vdd (+5V)
;	AddL/AddButton	PORTB.0 ->|6 628  13|<- PORTB.7	AddH/F4Sw
;	AddL/14/28Sw	PORTB.1 ->|7      12|<- PORTB.6	AddH/F3Sw
;	AddL/DirSw	PORTB.2 ->|8      11|<- PORTB.5	AddH/F2Sw
;	AddL/F0Sw	PORTB.3 ->|9      10|<- PORTB.4 AddH/F1Sw	
;		    	          +---------+
;
;			NOTE: Throttle ID now hard-coded!
;			     in #DEFINE section (PACK)!
;
;************************************************************************
; MAIN IDEA
;************************************************************************
;	This is based on Holger Klabunde's design, but is completely
;	rewritten in assembler.
;
;	Sender timing, carrier, packet format
;	=====================================
;	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
;
;	[2007-11-18] Changing of dir while speed off-zero will
;	cause Emergency Stop (ES). Also reducing speed too fast
;	will do the same. Moving the encoder CCV when speed
;	is already zero will now cause the throttle to send 
;	speed packets (speed zero).
;	Plan to add Emg.Stop button (move encoder gnd into either
;	GROUP and get two more inputs with ease!) NOT IMPLEMENTED!
;
;	[2007-01-23] Converted to use rotary encoder instead of 
;	potentometer. Also converted to work with 3 bit cab id.
;	NB: uses PIC16F628 now! Older version's pot and !MCLR
;	pins are used as encoder input, so it is easy to convert 
;	old throttles from pot to encoder use!
;
;	[2004-10-17] Converted the pot to have max.speed at 
;	low resistance -- i.e. _inverted_ the potentiometer!
;
;	[2003-11-16] Hard-coded throttle ID to get more functions
;	with least soldering task to get Antti's Roco
;	Nohab w. sound to play more tunes (horn!)
;
;	[2002-03-07] Error in number of "nop"s, in off-section:
;	had 1 too many. Also noted that (acc. to datasheet)
;	adding to TMR0 will clear prescaler contents, so always 
;	a bit late in timing! Hint: Use "MPLAB/Window/Stopwatch"!
;
;	This is loosely following Philips RC5 (Mancester code), exept:
;	Bit length now 832us instead of 1798us.
;	Only one start bit, and it is "0", only 8 data bits and
;	Added parity bit -> Total of 10 bits.
;
;	This is presumably similar to Lorell Joiner's
;	setup, done with hardwired UART some 10 years ago, (MR Jan 1990)
;	but instead of using 250 kHz carrier and on/off bits, I use the 
;	Bit formation similar to RC5 at 36...38 kHz carrier:
;
;	+++++                 +++++
;	|||||     =0          |||||    =1
;       +++++---+         +---+++++
;
;	Interval of packets needs to be somewhat random.
;	1 bit takes approx. 1 ms, one packet about 10 ms
;	1 sec => max. 100 packets
;	Sending now at 40ms + (10 * ID) interval:
;	ID 0...3 -> 40...70 ms interval.
;
;	Rotary encoder is sampled whenever the software is idle
;	waiting for TMR0 to overflow, and once in the main 
;	program. The encoder reading is not very efficient, but 
;	apparently there is no need to as at worst the reading
;	interval is about the length of one transmitter bit.
;	When the processor is waiting for the overflow flag
;	the encoder reading macro will firts check that there is
;	still ample time (TMR0 is less than F0h). It means that
;	there is still 16 x 8 instructions before overflow.
;	Encoder uses EX_ENC to compare previous reading and by
;	combining new and old one can determine if the knob was
;	turned up or down or not at all. Encoder steps are recorded
;	in ENCODER, and at change of value the MSB is tested and 
;	overflow and underflow corrected. This is then scaled to 
;	actual speed within main programme.
;	
;************************************************************************
; MACRO
;************************************************************************

can_read_enc MACRO

	;------------------------------------------------------
	; Testing TMR0 value, if adding 0Fh will cause overflow
	; this macro is skipped, else encoder is read
	;------------------------------------------------------

	movlw	b'00001111'	;Test if TMR0 is F0 or
	addwf	TMR0, w		;higer by adding 0F to TMR0
	skpnc			;and checking if we get overflow?
	goto	$+3		;yes, no encoder checking anymore
	call	read_encoder	;no, lets check the encoder
	goto	$-5		;
	ENDM

;************************************************************************
; VARIABLES
;************************************************************************

	CBLOCK H'20'

		Data1		;Data from IR-receiver
		Parity		;Parity
		bitcount	;bit counter
		potvalue	;pot position
		potbase		;pot start position (for auto null)
		ex_enc		;old encoder switces
		encoder		;encoder based counter value

		bcd		;BCD_to_bin
		temp		;BCD_to_bin

		e_stop

		speed
		ex_speed
		s_count

		addr
		ex_addr
		a_count

		func
		ex_func
		f_count

		payload

		PACK_ID
		TOGG_3
		TOGG_4
	ENDC
;************************************************************************
; STATICS
;************************************************************************


	#DEFINE DATA_OUT	PORTA, 0 	;Data out (if IR fails)
	#DEFINE IRLED		PORTA, 1 	;IR LED
	#DEFINE GROUP1		PORTA, 2 	;GROUP1, Address switch
	#DEFINE GROUP2		PORTA, 3 	;GROUP2, other switches
	#DEFINE ENC_A		PORTA, 4 	;IR ID High bit
	#DEFINE ENC_B		PORTA, 5 	;IR ID Low  bit

	#DEFINE BUTTON		PORTB, 0 	;Read address switches
	#DEFINE S_MODE		PORTB, 1 	;Address mode: 14/28 steps
	#DEFINE DirSw		PORTB, 2 	;Direction switch
	#DEFINE F0Sw		PORTB, 3 	;F0/FL switch
	#DEFINE F1Sw		PORTB, 4 	;F1    switch
	#DEFINE F2Sw		PORTB, 5 	;F2    switch
	#DEFINE F3Sw		PORTB, 6 	;F3    switch
	#DEFINE F4Sw		PORTB, 7 	;F4    switch

	#DEFINE HALFBIT		.203 		;= 255-52
	#DEFINE QUADBIT		.229		;= 255-26

	constant MAXSPEED	=.31	 	;max reading for pot

	#DEFINE CAB_ID		.1		;scale 0..7 (not 1..8!)
	#DEFINE INTERVAL	.40		;packet interval in ms
	
	;Pairs used:	Cab	interval 
	;		---	--------
	;		0	40	Done
	;		1	50	Done
	;		2	60	Done
	;		3	70	Done
	;		---	-------
	;		4	45
	;		5	55
	;		6	65
	;		7	75	
	;		---	-------

;************************************************************************
;RESTART/INT-START
;************************************************************************

	ORG     0		; Restart vector
	goto	main

	ORG	4		; INT vector
	retfie

;------------------------------------------------------------------------
; Initialize I/O ports, Interrupts, Timers etc
;------------------------------------------------------------------------
init


        BSF	STATUS,RP0	;BANK1
	BCF	STATUS, RP1	;
	movlw	b'11110000'	;Input -> I -> 1
	movwf	trisa		;Output-> O -> 0
	movlw	b'11111111'	;Input -> I -> 1
	movwf	trisb		;Output-> O -> 0
	CLRWDT			;
	bsf	STATUS, RP0	;BANK1
	BCF	STATUS, RP1	;
	movlw	b'00000010'	;Pullup=on, Prescaler= 1:8
	movwf	OPTION_REG	;
	bcf	STATUS, RP0	;BANK0
        MOVLW    7 		;PIC 16F628 Analog comparators:
        MOVWF    CMCON		;Comparators off, all pins digital I/O 

ramc	movlw	0x20		; 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

	movlw	b'00000000'	;initiate address byte
	movwf	addr
	movlw	b'11000000'	;initiate speed byte
	movwf	speed
	movlw	b'10000000'	;initiate func byte
	movwf	func
	return

read_encoder:
	;-------------------------------------------------------------
	; Ex encoder switch position is stored in ex_eng bits 2 and 3.
	; by shifting the ex_eng twice right and copying rotary encoder's
	; switches to bits 2 and 3 a four bit value is formed that will
	; reflect the ex state of the encoder and the present one.
	; Up and down branches will increment or decrement ENCODER
	; file and by testing MSB overflow is recognized 
	; (could have used carry, but only 7 bits are needed.
	;
	; As the rotary encoder advances four times at every "notch"
	; the two LSB are ignored when actually using the encoder value,
	; leaving five bits for speed!
	;-------------------------------------------------------------

	rrf	ex_enc, f	;
	rrf	ex_enc, w	;
	andlw	b'00000011'	;
	btfsc	enc_a		;
	iorlw	b'00000100'	;
	btfsc	enc_b		;
	iorlw	b'00001000'	;
	movwf	ex_enc		;
	addwf	PCL, f		;

				;-----------------------------------
				; new<-old:
				; 00<-10<-11<-01<-00 = UP
				; 00<-01<-11<-10<-00 = DOWN
				;-----------------------------------
	
	goto	speed_nop	; 00<-00 no change	
	goto	speed_down	; 00<-01 Down		
	goto	speed_up	; 00<-10 Up		
	goto	speed_err	; 00<-11 Error		

	goto	speed_up	; 01<-00 Up		
	goto	speed_nop	; 01<-01 No change	
	goto	speed_err	; 01<-10 Error		
	goto	speed_down	; 01<-11 Down		

	goto	speed_down	; 10<-00 Down		
	goto	speed_err	; 10<-01 Error		
	goto	speed_nop	; 10<-10 no change	
	goto	speed_up	; 10<-11 Up		

	goto	speed_err	; 11<-00 Error		
	goto	speed_up	; 11<-01 Up		
	goto	speed_down	; 11<-10 Down		
	goto	speed_nop	; 11<-11 No change	
	
speed_nop
	nop			; nop
	return			;

speed_up
	incf 	encoder, f	;increment speed	
	btfss	encoder, 7	;test for going too fast	
	return
	movlw	b'01111111'	;yes, replace encoder with 
	movwf	encoder		;max speed
	return
speed_down
	decf 	encoder, f	;decrement speed	
	btfss	encoder, 7	;test for going too slow 	
	return
	clrf	encoder		;yes, replace encoder with zero

	movfw	ex_speed	;Test ex_speed
	andlw	b'00001111'	;looking at speed bits
				;are they zero already
	skpnz			;(if so, there will be nothing sent)
	bsf	ex_speed, 1	;Yes - nudge up so that zero speed
	return			;will be sent if encoder was moved CCW
speed_err
	nop			;errors counter (if any!)
	return

;------------------------------------------------------------------------
; BCD to BIN [ from www.piclist.com (Scott Dattalo) ]
;------------------------------------------------------------------------

BCD_to_BIN 			;
	movwf	bcd		;
	rrf	bcd, W 
	andlw	b'01111000'	;W = tens*8 
	movwf	temp 
	clrc
	rrf	temp, F		;temp = tens*4 
	rrf	temp, F		;temp = tens*2 
	subwf	bcd, W		;W = tens*16 + ones - tens*8 
				;W = tens*8 + ones 
	addwf	temp, W		;W = tens*10 + ones 
	return

;------------------------------------------------------------------------
; Send BYTE Data to be sent in DATA1, number of bits to sed at BITCOUNT
;------------------------------------------------------------------------
send_byte

sb3	rlf	DATA1, F	;rotate through carry (MSB first) and 
	btfsc	STATUS, C	;in case of carry send 1 instead of 0
	goto	sb4		;carry=1
	call	Send0		;carry=0
	goto	sb5
sb4	call	Send1

sb5	decfsz	BITCOUNT, F	;all bits sent?
	goto sb3		;not yet, send more
	return

;------------------------------------------------------------------------
; Send 0 [###___] leaves TMR to half bit interval
;------------------------------------------------------------------------
send0
	bsf	DATA_OUT	;direct data out
s01	bsf	IRLED		;IR-LED on for 13 instr. cycles

	nop
	nop
	nop
	nop
	nop
	
	nop
	nop
	nop
	nop
	nop

	nop
	nop

	bcf	IRLED		;IR-LED off for 13 instr. cycles

	nop
	nop
	nop
	nop
	nop
	
	nop
	nop
	nop
	nop

	btfss	INTCON,	T0IF	;1/2 bit time gone?
	goto	s01		;not yet

	bcf	INTCON, T0IF	;clear overflow flag
	movlw	HALFBIT		;new timer base
	addwf	TMR0, f		;add to just overflowed timer

s02	bcf	DATA_OUT	;direct link

	can_read_enc		;Test if TMR0 < F0?
				;if so read the encoder

	btfss	INTCON,	T0IF	;1/2 bit time gone?
	goto	$-1		;not yet

	bcf	INTCON, T0IF	;clear overflow flag
	movlw	HALFBIT		;new timer base
	addwf	TMR0, f		;add to just overflowed timer

	return

;------------------------------------------------------------------------
; Send 1 [___###]
;------------------------------------------------------------------------

send1

	bcf	DATA_OUT	;direct link off

	can_read_enc		;Test if TMR0 < F0?
				;if so read the encoder
s11
	btfss	INTCON,	T0IF	;1/2 bit time gone?
	goto	$-1		;not yet

	incf 	PARITY, F	;parity++

	bcf	INTCON, T0IF	;clear overflow flag
	movlw	HALFBIT		;new timer base
	addwf	TMR0, f		;add to just overflowed timer
	bsf	DATA_OUT	;direct link on
s12	bsf	IRLED		;IR-LED on for 13 instr. cycles

	nop
	nop
	nop
	nop
	nop
	
	nop
	nop
	nop
	nop
	nop

	nop
	nop

	bcf	IRLED		;IR-LED off for 13 instr. cycles

	nop
	nop
	nop
	nop
	nop
	
	nop
	nop
	nop
	nop

	btfss	INTCON,	T0IF	;1/2 bit time gone?
	goto	s12		;not yet

	bcf	INTCON, T0IF	;clear overflow flag
	movlw	HALFBIT		;new timer base
	addwf	TMR0, f		;add to just overflowed timer
	bcf	DATA_OUT	;direct link off
	return

;------------------------------------------------------------------------
; 1ms delay
;------------------------------------------------------------------------

delay1ms
	bcf	INTCON, T0IF	;clear overflow flag
	movlw	.130		;new timer base
	addwf	TMR0, f		;add to timer

	can_read_enc		;Test if TMR0 < F0?
				;if so read the encoder

d11	btfss	INTCON,	T0IF	;1ms gone?
	goto	d11		;not yet

	return



;------------------------------------------------------------------------
; MAIN PROGRAMME
;------------------------------------------------------------------------
main
	call 	init		;intialize ports
m0

	tstf	TOGG_3		;test Toggle
	skpnz			;is it zero
	goto 	m0_1		;yes, leave it that way!	
	incfsz	TOGG_3, W	;no, Increment toggle 
	movwf	TOGG_3		;but not past the top
m0_1
	tstf	TOGG_4		;test Toggle
	skpnz			;is it zero
	goto 	m0_2		;yes, leave it that way!	
	incfsz	TOGG_4, W	;no, Increment toggle 
	movwf	TOGG_4		;but not past the top
m0_2

	movlw	b'00000000'	;modify new to resemble barebone
	movwf	addr		;IR address payload: 0AAAAAAA

	movlw	b'11000000'	;modify new to resemble barebone
	movwf	speed		;IR speed payload: 11DsSSSS

	movlw	b'10000000'	;modify new to resemble barebone
	movwf	func		;IR func payload: 10MFFFFF

	;----------------------------------------------------------------
	;First get the speed settings
	;----------------------------------------------------------------

	call	read_encoder	;read the encoder
				;(encoder values 0000-0000 -> 0111-1111)

	movfw	encoder		;get the encoder value
	sublw	b'01110000'	;subtract 28*4 to test if too high
	btfsc	status, c	;Did it go below zero c=0(too fast)?
	goto	m0_3		;no, continue
	movlw	b'01110000'	;replace with max so that while
	movwf	encoder		;turning knob too far cw the next step 
				;ccw will slow down

m0_3
	movfw	encoder		;get the encoder value
	movwf	potvalue	;move it to pot value and get rid
	rrf	potvalue, f	;of two bits
	rrf	potvalue, w	;of two bits
	andlw	b'00111111'	;and clear possible carbage from carry	
	skpz			;Well, was it zero then?
	addlw	.3		;no, add 3 to skip other zero
				;and emergency stop positions
				;-----------------------------------
	movwf	potvalue	;move result to potvalue
	sublw	MAXSPEED	;max-pot (now testing for speeding!)
	btfsc	status, c	;Did it go below zero c=0(too fast)?
	goto	read_addr	;no, continue
	movlw	MAXSPEED	;yes, replace w. MAXSPEED and
	movwf	potvalue	;move it to potvalue
				;potvalue: 0, 4..31

read_addr
	;----------------------------------------------------------------
	;Then check the addr_change button
	;----------------------------------------------------------------
	bcf	GROUP1		;now reading (grounding) other switches
	bsf	GROUP2		;not reading (releasing) address sw's
	nop
	nop
	btfsc	BUTTON		;Test if address selection button is down
	goto	read_sw		;not pressed (clear) goto switches

	tstf	potvalue	;Check the speed setting
	skpz			;it must be zero before changing address
	goto	read_sw		;not zero, goto switches

	bsf	GROUP1		;not reading (releasing) other switches
	bcf	GROUP2		;now reading (grounding) address sw's
	comf	portb, w	;read address switches

	bcf	GROUP1		;now reading (grounding) other switches
	bsf	GROUP2		;not reading (releasing) address sw's
	nop
	nop
	btfsc	BUTTON		;now read the switches, is the button still down
	goto	read_sw		;not pressed (clear) goto switches

	call	bcd_to_bin	;convert to binary address
	andlw	b'01111111'	;just to be sure...
	movwf	addr		;and save as new address
	movwf 	payload
;	movlw	.10		;repeat for address
;	movwf	a_count		;set as a dummy really...
	goto	send_packet	;and send it!

read_sw
	;----------------------------------------------------------------
	;Go to read other switches
	;----------------------------------------------------------------

	bcf	GROUP1		;now reading (grounding) other switches
	bsf	GROUP2		;not reading (releasing) address sw's
	nop
	nop

	;----------------------------------------------------------------
	;First check the dir switch and set/clear speed's dir bit
	;----------------------------------------------------------------
	
	btfss	DirSw		;Dir reverse (set) / forward (clear)
	bsf	speed, 5

	;----------------------------------------------------------------
	;Next check the F1..4 and set/clear func's F1..4 bits
	;----------------------------------------------------------------

	btfss	F1Sw		;F1 off (set) / on (clear)
	bsf	func, 0

	btfss	F2Sw		;F2 off (set) / on (clear)
	bsf	func, 1
	;----------------------------------------------------------------
	; Special Toggle action (like TMWDCC func-action)!
	;----------------------------------------------------------------


F3
	btfss	F3Sw		;F3 off (set) / on (clear)
	goto	F3_on		;Switch pulled: go for it!
				;Switch in center position:
F3_off
	movlw	.250		;
	addwf	TOGG_3, w	;Add 255-5 to Toggle to see
	skpnc			;skip if non carry (short duration)
	goto 	F3_off_long	;yes (toggle released after long time)

F3_off_short
	btfsc	ex_func, 2	;no (quick release) XOR the ex_function's
	bsf	func, 2		;resp. bit to new func byte
	clrf	Togg_3		;Toggle=> 0
	goto 	F4		;next switch

F3_off_long
	clrf	Togg_3		;Toggle=> 0
	goto 	F4		;next switch

F3_on
	tstf	Togg_3		;Test Toggle 
	skpnz			;is zero?
	goto	F3_on_now	;yes F3 just turned on

F3_on_before
	btfsc	ex_func, 2	;no (done before) Copy the ex_function's 
	bsf	func, 2		;resp.bit to new function byte
	goto	F4

F3_on_now
	incf	Togg_3, f	;Toggle to 1
	btfss	ex_func, 2	;XOR previous function status'
	bsf	func, 2		;resp.bit to new 

;---------
F4
	btfss	F4Sw		;F4 off (set) / on (clear)
	goto	F4_on		;Switch pulled: go for it!
				;Switch in center position:
F4_off
	movlw	.250		;
	addwf	TOGG_4, w	;Add 255-5 to Toggle to see
	skpnc			;skip if non carry (short duration)
	goto 	F4_off_long	;yes (toggle released after long time)

F4_off_short
	btfsc	ex_func, 3	;no (quick release) XOR the ex_function's
	bsf	func, 3		;resp. bit to new func byte
	clrf	Togg_4		;Toggle=> 0
	goto 	F5		;next switch

F4_off_long
	clrf	Togg_4		;Toggle=> 0
	goto 	F5		;next switch

F4_on
	tstf	Togg_4		;Test Toggle 
	skpnz			;is zero?
	goto	F4_on_now	;yes F4 just turned on

F4_on_before
	btfsc	ex_func, 3	;no (done before) Copy the ex_function's 
	bsf	func, 3		;resp.bit to new function byte
	goto	F5

F4_on_now
	incf	Togg_4, f	;Toggle to 1
	btfss	ex_func, 3	;XOR previous function status'
	bsf	func, 3		;resp.bit to new 


;---------
F5
;	btfss	F4Sw		;F4 off (set) / on (clear)
;	bsf	func, 3

	;----------------------------------------------------------------
	;Next check the mode switch and clear/set flag  bit in func byte,
	;set correct bit according to FL/F0func byte and handle speed
	;and functions:
	;----------------------------------------------------------------

	btfss	S_MODE		;Speed in 14 (set) / 28 (clear)
	goto	m_28
m_14
	;----------------------------------------------------------------
	; 14 step mode:
	; -------------
	;	Speed byte:	11DsSSSS  D    = Dir 1=Fwd, 0=Rev
	;				  s    = F0/FL,
	;				  S..S = Speed bits 3..0
	;	Func byte:	10M0FFFF  M    = 0 (14 step mode)
	;				  F..F = F4..1 
	;----------------------------------------------------------------

	bcf	func, 5		;speed_mode flag cleared (14 steps)
	bcf	speed, 4	;clear the little "s"
	btfss	F0Sw		;FL off (set) / on (clear)
	bsf	speed, 4

	rrf	potvalue,w	;get pot value, LSB to carry (discard!)
	andlw	0x0F		;clear top (just in case!)
	iorwf	speed, f	;
	goto	m1		;and done here!

m_28
	;----------------------------------------------------------------
	; 28 step mode:
	; -------------
	;	Speed byte:	11DsSSSS  D    = Dir 1=Fwd, 0=Rev
	;				  s    = speed bit 0
	;				  S..S = Speed bits 4..1
	;	Func byte:	10MFFFFF  M    = 1 (28 step mode)
	;		 		  F..F = F0,F4..F1 
	;----------------------------------------------------------------

	bsf	func, 5		;speed_mode flag set (28 steps)
	btfss	F0Sw		;FL off (set) / on (clear)
	bsf	func, 4
	bcf	speed, 4
	rrf	potvalue,w	;get pot value, LSB in carry
	skpnc			;was carry set
	bsf	speed, 4	;yes, set little "s"
	andlw	0x1F		;clear top (just in case!)
	iorwf	speed, f	;

m1

send_speed
	;----------------------------------------------------------------
	;Now, lets see if speed needs sending
	;----------------------------------------------------------------
	tstf	e_stop		;Do we have an emergency?
	skpz			;
	goto	es_on		;yes, lets act upon it!
	movfw	ex_speed	;Load old speed to w
	xorwf	speed, w	;and compare with latest one.
	btfsc	status, z	;Was it equal?
	goto	send_sp1	;yes, check for repeats!

	movfw	speed		;Test new speed:
	andlw	b'00001111'	;clear all but 4 speed bits
	skpz			;Is it zero
	goto	dir_swap	;no, go on to testing dir
	movfw	ex_speed	;yes, how about previous?
	andlw	b'00001100'	;was it over 3/14 (6/28)
	skpnz			
	goto	send_sp0	;no, go on
	movfw	speed		;make sure the staus will not 
	movwf	ex_speed	;stay on for ever
	movlw	.10
	movwf	e_stop		;set the e_state (10 repeats)
	goto	es_on		;and put the emg.stop out!

dir_swap
	movfw	ex_speed	;compare ex speed 
	xorwf	speed, w	;with new one
	andlw	b'00100000'	;has the direction been changed
	skpnz			;(note: speed non-zero if here!)
	goto	send_sp0	;no -- carry on as usual
	movfw	speed		;make sure the staus will not 
	movwf	ex_speed	;stay on for ever
	clrf	encoder		;and set speed to zero
	movlw	.10
	movwf	e_stop		;set the e_state (10 repeats)
	movwf	s_count		;and clear afterwards

es_on
	decf	e_stop, f	;reduce the e_stop counter
	movfw	speed
	andlw	b'11110000'	;get the FL and direction
	movwf	payload		;get this to payload
	bsf	payload, 0	;set bit 0 (emg stop!)	
	movlw	b'11000001'	;this is emergency packet
	goto	send_packet

send_sp0
	movlw	.10		;no, lets make sure
	movwf	s_count		;this is noticed
	movfw	speed		;get speed to w
	movwf	payload		;and prepare to send it
	movwf	ex_speed	;and make ex_speed equal to present
	goto	send_packet
	
send_sp1
	tstf	s_count		;test if repeats needs to be sent?
	skpnz
	goto	send_func	;no, check func next!
	decf	s_count,f	;yes, decrement repeat counter
	movfw	speed		;get speed and
	movwf	payload		;and prepare to send
	goto	send_packet	;go and send it!

send_func
	;----------------------------------------------------------------
	;Now, lets see if func needs sending
	;----------------------------------------------------------------

	movfw	ex_func		;Load old func to w
	xorwf	func, w		;and compare with latest one.
	btfsc	status, z	;Was it equal?
	goto	send_f1		;yes, how about repeats?

	movlw	.10		;no, lets make sure
	movwf	f_count		;this is noticed
	movfw	func		;get func to w
	movwf	payload		;and prepare to send it
	movwf	ex_func		;and make ex_func equal to present
	goto	send_packet

send_f1
	tstf	f_count		;test if repeats needs to be sent?
	skpnz
	goto	m0		;no, back to square one!
	decf	f_count, f	;yes, decrement repeat counter
	movfw	func		;get func packet and
	movwf	payload		;and prepare to send
	goto	send_packet	;go and send it!

send_packet
	;----------------------------------------------------------
	;send startbit
	;----------------------------------------------------------
	bcf	INTCON, T0IF	;clear overflow flag
	movlw	HALFBIT		;new timer base
	movwf	TMR0		;move initial timer base (first round!)

	call Send0		;send startbit (won't affect parity!)

	;----------------------------------------------------------
	;send cab number
	;----------------------------------------------------------

	movlw	cab_id		;PACK_ID is constant!
	movwf	DATA1		;save as data to be sent
	swapf	DATA1, f	;swap ends and shift left, so
	rlf	DATA1, f	;now three LSBs are three MSBs

	movlw	.3		;only 3 bits (NOTE LEFTMOST!)
	movwf	BITCOUNT	;

	call 	send_byte	;send it along!

	;----------------------------------------------------------
	;send payload
	;----------------------------------------------------------

	movfw	payload		;get the payload
	movwf	DATA1		;
	movlw	.8		;all 8 bits
	movwf	BITCOUNT	;

	call	send_byte		;send DATA1

	;----------------------------------------------------------
	;send parity
	;----------------------------------------------------------

	btfsc	Parity, 0	;in case Parity 1 send 1 instead of 0
	goto	m6		;Parity=1
	call	Send0		;Parity=0
	goto	m7
m6	call	Send1

	;----------------------------------------------------------
	;set packet interval
	;----------------------------------------------------------

m7	movlw	interval	;packet interval
	movwf	BITCOUNT	;bitcount counts ms now

m8	call 	delay1ms

	decfsz	BITCOUNT, F	;packet interval gone yet?
	goto 	m8		;not yet, wait another millisec!

	goto 	m0		;done, back to square one

	end

