;************************************************************************
; TaPRK IR-LINK-TRANSMITTER POT 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
;************************************************************************

;	          		  +---+_+---+
;	ADDR LOW	PORTA.2 ->|1      18|<- PORTA.1 BUTTON act.low
;	ADDR HIGH	PORTA.3 ->|2      17|-> PORTA.0	IR-LED act.high
;	POT&CAP		PORTA.4 <>|3      16|-- XTAL
;			    Vdd --|4      15|-- XTAL
;			Vss(GND)--|5      14|-- Vdd (+5V)
;	SPEED LED 0	PORTB.0 <-|6      13|-> PORTB.7	
;	SPEED LED 1	PORTB.1 <-|7      12|-> PORTB.6	
;	SPEED LED 2	PORTB.2 <-|8      11|-> PORTB.5	
;	SPEED LED 3	PORTB.3 <-|9      10|-> PORTB.4	
;		    	          +---------+

;************************************************************************
; 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.
;
;	Reading the pot
;	===============	
;	Reading pot values in much the same way as PC-compatible's
;	joystick port!
;
;	1)	Make PORTA.4 output and discharge Cap through port.
;	2)	Make PORTA.4 input (schmitt!) and wait for going high
;	3)	Send number of loop counts it took to go high
;
;	More about PC-joystick port, see:
;	http://www.epanorama.net/documents/joystick/pc_joystick.html
;
;	Datasheet states max. capacitance to be connected
;	to any 16F84-port as 50 pF.
;
;	Time constant: T(63%)=RC close to schmitt trip level
;
;	Connecting Cap from PORTA.4 to gnd, and Pot through
;	22k resistor from Vhi to PORTA.4
;
;	Looping through counter takes approx 4 inst.cycles (4us)
;	so min. time (count 1) should be about 4us,
;	and max. time (count 255) about 1ms.
;
;	  0->  4us / 33pF = 121 Kohm
;	 15-> 60us / 33pF =   2 Mohm
;	255->  1ms / 33pF =  30 Mohm
;	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
	ENDC
;************************************************************************
; STATICS
;************************************************************************


	#DEFINE IRLED		PORTA, 0 	;IR LED
	#DEFINE BUTTON		PORTA, 1 	;DIR-button
	#DEFINE ADDRLO		PORTA, 2 	;Address, low bit
	#DEFINE ADDRHI		PORTA, 3 	;Address, high bit
	#DEFINE POT		PORTA, 4 	;potentiometer

	#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'00011110'	;RA0  =out 	IR-LED,
				;RA1  =in  	BUTTON,
				;RA2:3=in	ADDRESS,
				;RA4  =in	CAP&POT
	tris	porta
	movlw	b'00000000'	;RB0..7=out (TEST LEDS!)
	tris	portb

	CLRWDT			;
	bsf	STATUS, RP0	;
	movlw	b'10000010'	;Pullup=off, Prescaler= 1:8
	movwf	OPTION_REG	;
	bcf	STATUS, RP0	;
	clrf	nulcount	;clear null packet counter
	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 pot
;------------------------------------------------------------------------
read_pot
	bsf	STATUS, RP0	;Select Bank1 and
	bcf	TRISA, 4	;choose RA4 -> output
	bcf	STATUS, RP0	;Select Bank0 

	bcf	POT		;discharge cap by grounding
	nop			;RA4 and keep it down
	nop			;for a while in case of
	nop			;current limiting resistor

	clrf	potvalue	;clear previous pot position
	bsf	STATUS, RP0	;Select Bank1 and choose
	bsf	TRISA, 4	;RA4 -> input for reading cap
	bcf	STATUS, RP0	;Select Bank0 
	nop

test_pot
	btfsc	POT		;test if cap charged
	return			;yes, done!
	incf	potvalue, f	;no, increment counter
	goto	test_pot	;and test again
	return

;------------------------------------------------------------------------
; 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	read_pot	;read the pot value
				;to potvalue
	movlw	MAXSPEED	;get FF-max_speed to w
	sublw	.255		;255-MAXSPEED to w 
	addwf	potvalue, w	;and add pot value to this.
	btfss	status, c	;Did it go over the top (too fast)?
	goto	m1		;no, proceed
	movlw	maxspeed	;yes, put maxspeed
	movwf	potvalue	;to potvalue	

m1
;#####################################################################
;#TO CREATE MORE TRAFFIC TO TEST COLLISIONS => JUMP TO m2
;	goto 	m2
;#####################################################################
	movfw	oldpot		;load old pot value to w
	xorwf	potvalue, w	;and compare with present value.
	btfss	status, z	;Was it equal?
	goto	m2ne		;no, send it!

	btfss	BUTTON		;Check for direction button
	goto	m2ne		;pressed (clear), send it!

m2eq	tstf	nulcount	;Equal! Test if all repeat 
	skpnz			;packets are already sent?
	goto	m0		;yes, back to square one
	decf	nulcount, f	;no, decrement nul packet count
	goto	m2		;and send one!

m2ne	movfw	potvalue	;yes, copy present pot value
	movwf	oldpot		;to old pot.

	movlw	.10		;prepare to send it x times
	movwf	nulcount	;in case not immediately noticed

m2
	;----------------------------------------------------------
	; 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:	BUTTON 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	BUTTON		;Check for direction button
	bsf	DATA1, 4	;set resp. 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

	comf	DATA1, w	;invert outgoing data and
	movwf	PORTB		;send to LEDs as well!
	;-------------------------------------------------------------

	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

