;************************************************************************
; TaPRK IR-LINK-TRANSMITTER BUTTON VERSION
;************************************************************************

	LIST P = 16F84A,  R = HEX		;Prosessor type, radix
	INCLUDE	"p16f84A.inc"			;w,f,porta,portb etc. 
	ERRORLEVEL -224				;Prevent error message
						;from "tris"-command

        __CONFIG _PWRTE_OFF & _HS_OSC & _WDT_OFF;4MHz crystal   

;************************************************************************
; SCHEMATIC DIAGRAM
;************************************************************************

;	          		  +---+_+---+
;		N/C	PORTA.2 ->|1      18|<- PORTA.1 N/C
;		N/C	PORTA.3 ->|2      17|-> PORTA.0	IR-LED act.hi
;		N/C	PORTA.4 ->|3  PIC 16|-- XTAL (4MHz)
;		(+5V)	MCLR    --|4  16F 15|-- XTAL
;		(GND)	Vss     --|5  84A 14|-- Vdd (+5V)
;	ACCEL. SW	PORTB.0 ->|6      13|<- PORTB.7	N/C
;	BRAKE  SW	PORTB.1 ->|7      12|<- PORTB.6	N/C
;	DIR. BUTTON (R)	PORTB.2 ->|8      11|<- PORTB.5	N/C
;	F0/5 BUTTON (Y)	PORTB.3 ->|9      10|<- PORTB.4	F1 BUTTON (G)
;		    	          +---------+

;************************************************************************
; 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
;
;	[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, 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 50ms + (10 * address) interval:
;	Address 0...3 -> 40...70 ms interval.
;
;	NOTE: will stick to 4 bit resolution for now!

;************************************************************************
; VARIABLES
;************************************************************************

	CBLOCK H'0C'

		Data1		;Data from IR-receiver
		Parity		;Parity
		bitcount	;bit counter
		nulcount	;repeat packet counter
		potvalue	;pot position
		oldpot		;previous pot value
		count_0		;typematic counter
	ENDC
;************************************************************************
; STATICS
;************************************************************************


	#DEFINE IRLED		PORTA, 0 	;IR LED

	#DEFINE ACCEL_SW	PORTB, 0 	;!Faster
	#DEFINE BRAKE_SW	PORTB, 1 	;!Slower
	#DEFINE DIR_BUTTON	PORTB, 2 	;!Direction/Emg.Stop
	#DEFINE FL_BUTTON	PORTB, 3 	;!FL/F5
	#DEFINE F1_BUTTON	PORTB, 4 	;!F1

	#DEFINE ADDRLO		PORTB, 6 	;!Address, low bit
	#DEFINE ADDRHI		PORTB, 7 	;!Address, high bit

	#DEFINE HALFBIT		.203 		;= 255-52
	#DEFINE QUADBIT		.229		;= 255-26

	constant MAXSPEED	=.15	 	;max reading for pot
	
;************************************************************************
;RESTART/INT-START
;************************************************************************

	ORG     0		; Restart vector
	goto	main

	ORG	4		; INT vector
	retfie

;------------------------------------------------------------------------
; Initialize I/O ports, Interrupts, Timers etc
;------------------------------------------------------------------------
init
	movlw	b'00000010'	;RA0=out, RA1=in RA2:4=out
	tris	porta
	movlw	b'11111111'	;RB0..7=in
	tris	portb

	CLRWDT			;
	bsf	STATUS, RP0	;
	movlw	b'00000010'	;Pullup=on, Prescaler= 1:8
	movwf	OPTION_REG	;
	bcf	STATUS, RP0	;
	clrf	potvalue	;nopeus nollaan
	movlw	.10		;
	movwf	nulcount	;start by sending 10 packets
;------------------------------------------------------------------------
; Increment throttle's typematic counters
;------------------------------------------------------------------------
IncCounters
	tstf	count_0		;set zero flag from counter
	skpz			;skip if zero
	incf	count_0, f	;not yet -> increment
	return

;------------------------------------------------------------------------
; Send 0 [###___]
;------------------------------------------------------------------------
send0
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	btfss	INTCON,	T0IF	;1/2 bit time gone?
	goto	s02		;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
s11	btfss	INTCON,	T0IF	;1/2 bit time gone?
	goto	s11		;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

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

	return

;------------------------------------------------------------------------
;Read switch
;------------------------------------------------------------------------

read_sw
	tstf	potvalue	;check if speed
	skpnz			;is zero?
	goto	ad1		;yes, no need for emg.stop
	btfss	DIR_BUTTON	;no, check if button is pressed
	clrf	potvalue	;yes, speed -> 0
ad1
	btfsc	ACCEL_SW	;faster-bit cleared?
	goto	ad1s		;goto cab_1 slower
ad1f
	tstf	count_0		;check if typematic still on
	skpz			;skip if typematic clear
	return			;no, pass
	movlw	.240		;Typematic seed is now 200
	movwf	count_0		;start typematic
	incf	potvalue, f	;accelerate
	btfss	potvalue, 4	;going too fast
	return			;no, done with this
	movlw	0x0f		;top speed is 15
	movwf	potvalue	;and we settle for that!
	return			;done!

ad1s	btfsc	BRAKE_SW	;slower-bit cleared?
	goto	ad1nop		;goto cab_1 nop
	tstf	count_0		;check if typematic still on
	skpz			;skip if typematic clear
	return			;no, pass
	movlw	.240		;Typematic seed is now 200
	movwf	count_0		;start typematic
	tstf	potvalue	;accelerate
	skpz			;already standstill?
	decf	potvalue, f	;no, let's put on brakes
	return			;done!

ad1nop	clrf	count_0		;clear typematic counter
	return			;and done!
;------------------------------------------------------------------------
; 1ms delay
;------------------------------------------------------------------------

delay1ms
	bcf	INTCON, T0IF	;clear overflow flag
	movlw	.130		;new timer base
	addwf	TMR0, f		;add to timer

d11	btfss	INTCON,	T0IF	;1ms gone?
	goto	d11		;not yet

	return



;------------------------------------------------------------------------
; MAIN PROGRAMME
;------------------------------------------------------------------------
main
	call 	init		;intialize ports
m0
	call 	IncCounters	;

	call	read_sw		;read the accel/brake buttons (switch)
				;to potvalue

m1	comf	PORTB, w	;copy and invert inputs to w
	andlw	b'00111111'	;mask address bytes away to see
	skpz			;if any buttons pressed?
	goto 	m2		;yes, out with it!
	tstf	nulcount	;none! Test if all null packets sent?
	skpnz			;
	goto	m0		;yes, back to square one
	decf	nulcount, f	;no, decrement nul packet count
	goto	m2nul		;and send one!

m2	movlw	.3		;prepare to send X null packets
	movwf	nulcount	;in case no buttons pressed

m2nul
	;----------------------------------------------------------
	; prepare to send packet 	"AAWDSSSS"
	;				"AA"  =Address
	;				"W"   =0 speed+dir
	;				      =1 F buttons
	;				"D"   =direction button
	;				       or FL
	;				"SSSS"=Speed from potvalue
	;				       or F0...F4
	;				NO F-buttons yet!
	;----------------------------------------------------------
	;##### ERROR: BUTTONS not polled in oldvalues! ###########
	;----------------------------------------------------------
	clrf	DATA1		;clear byte to be sent

	btfss	ADDRHI		;Check for address hi bit
	bsf	DATA1, 7	;set resp. bit in data1 if grounded!

	btfss	ADDRLO		;Check for address lo bit
	bsf	DATA1, 6	;set resp. bit in data1 if grounded!

	btfss	DIR_BUTTON	;Check for direction button
	bsf	DATA1, 4	;set resp. bit in data1 if grounded!

	btfss	FL_BUTTON	;Check for FL button (simplified)
	bsf	DATA1, 4	;set dir. bit in data1 if grounded!

	btfss	F1_BUTTON	;Check for F1 button (simplified)
	bsf	DATA1, 4	;set dir. bit in data1 if grounded!

	movfw	potvalue	;copy pot value to w
	andlw	0x0F		;clear top bits just to be safe
	iorwf	data1, f	;and set resp. bits in data1

	;-------------------------------------------------------------

	call	IncCounters	;

	clrf	Parity		;clear Parity, 1's will increment

	movlw	.8		;all 8 bits
	movwf	BITCOUNT	;

	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!)

m3	rlf	DATA1, F	;rotate through carry (MSB first) and 
	btfsc	STATUS, C	;in case of carry send 1 instead of 0
	goto	m4		;carry=1
	call	Send0		;carry=0
	goto	m5
m4	call	Send1

m5	decfsz	BITCOUNT, F	;all bits sent?
	goto m3			;not yet, send more

	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

m7	movlw	.40		;count 40 ms
	movwf	BITCOUNT	;bitcount counts ms now

	btfss	ADDRHI		;Check for ADDRESS HI bit
	goto 	m7_		;not grounded, goto see lo bit
	movlw	.20		;was grounded, add 20 ms to loop
	addwf	BITCOUNT, f	;

m7_	btfss	ADDRLO		;Check for ADDRESS LO bit
	goto	m8		;not grounded, out with it!
	movlw	.10		;was grounded, add 10 ms to loop
	addwf	BITCOUNT, f	;
	

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

