;The purpose of this code is to attempt to mimic the functionality of a V1 sensor by using Timer 1
;to measure the pulse width of both the high and low times.  These high and low times are then compared
;with the range of times allowed, and a hit is registered if enough match up.  The target pic is the
;16F628A with the internal clock.  A hit light is on PORTB,0 and the sensor inputs are on PORTB,3
;and PORTB,4. A sound output is on PORTB,1.
;
;The code itself is not terribly pretty, but it works.  It is going to be recieving a thorough
;overhall sometime in the near future (after I complete the thorough overhall of the gun code).
;
;This code is free for non-commercial use.  If you find any of it useful, please let me know.  I'd love
;to hear from you.  If you use any of the code in a project of your own, please give credit to me.
;I also wouldn't mind if you periodically came to check my website at http://wythelasertag.darkforces.biz
;
;Programmer: Erik Ritch
;Last modified: 4/20/04
;Known bugs: The timing parameters need to be adjusted.  Currently the sensor takes a hit from both Maxblast
;		and reset in addition to the regular hit frequency.
;
;Enjoy!
		list		p=16f628a
		__config		0x3f10
		radix		hex
		#include		<p16f628a.inc>
		cblock		0x20
		timeHI,timeLO,pulses,temp,temp1,temp2,temp3,temp4,temp5,frequency,tone_cycles,tones,between_pulse,hits_left,hitline
		endc
;
#define		_255_pulse_high	b'00000011'		;High byte of minimum time requirement (255 Hz) *Not actual value!
#define		_255_pulse_low	b'11110000'		;Low byte of the same
#define		_245_pulse_high	b'00100101'		;High byte of the maximum time requirement (245 Hz) *Not actual value!
#define		_245_pulse_low	b'11000011'		;Low byte of the same
#define		pulses_per_hit	d'10'	
#define		sensor_delay	d'2'
#define		hits_per_game	d'9'
;
		org		0x00
start		movlw		b'00000111'		;Turn off comparitors
		movwf		CMCON
		bsf		STATUS,RP0		;To bank 1
		movlw		b'00001100'		;PORTB,3 is an input, all others are outputs
		movwf		TRISB
		bcf		STATUS,RP0		;Back to bank 0
		bcf		PORTB,0
		bcf		PORTB,1
		movlw		pulses_per_hit
		movwf		pulses
		movlw		b'00000000'		;Timer 1 setup info, no prescaler, just use as a counter at Fosc/4
		movwf		T1CON		;Timer 1 is now off
		clrf		TMR1H
		clrf		TMR1L		;Clear the timer from any possible previous count
		movlw		sensor_delay
		movwf		between_pulse
startup		call		startup_tone	;Delay to allow circuit to stabilize, and to allert user to powerup
		movlw		hits_per_game
		movwf		hits_left
wait_for_pulse	btfss		PORTB,3		;Wait for PORTB,3 to go low.  Sensor holds it high when no light is coming in
		goto		line3
		btfsc		PORTB,2
		goto		wait_for_pulse	;Keep looping until sensor detects enough IR to go low
		bsf		hitline,0
		bsf		T1CON,0
		goto		wait_for_high
line3		bcf		hitline,0
		bsf		T1CON,0		;Turn on the timer
wait_for_high	movlw		d'4'
		btfss		hitline,0		;Now, we wait for the pin to go back high again
		addwf		PCL,f
		btfss		PORTB,2
		goto		wait_for_high	;Circle until it does
		call		store_time
		goto		check_x_245_1
		btfss		PORTB,3
		goto		wait_for_high
		call		store_time
;
;********************************************************************************************************************************
;This should work
;
;
;Now, we need to check that the 245Hz<time of this pulse<255Hz  We do this in two comparisons.  If the pulse is really short, we could miss something, but this probably won't be all that big a deal.  We'll see
		;********** 16 BIT			 Taken from http://massmind.org/techref/microchip/
		;if( X <= K )
check_x_245_1	movf 		timeHI,w
		sublw 		_245_pulse_high
 		skpc
 		goto 		false_start
		skpz
  		goto 		check_x_255_1
  		movf 		timeLO,w
  		sublw 		_245_pulse_low
 		skpc
		goto 		false_start
		goto		check_x_255_1
;If we get here, the pulse is greater than the 245Hz pulse.  We now need to check that x<255Hz.  Once more, taken from http://massmind.org/techref/microchip/
;if( K <= X )
check_x_255_1  	movlw 		_255_pulse_high
 		subwf 		timeHI,w
		skpc
		goto 		false_start
		skpz
		goto 		wait_for_low
		movlw 		_255_pulse_low
		subwf 		timeLO,w
		skpc
		goto 		false_start
		goto		wait_for_low
;
;
;End of working section
;********************************************************************************************************************************
;
;If we get here, the pulse is good, so we now need to wait for the line to go low again and time this interval
wait_for_low	movlw		d'4'
		btfss		hitline,0
		addwf		PCL,f
		btfsc		PORTB,2
		goto		wait_for_low
		call		store_time
		goto		check_x_245_2
		btfsc		PORTB,3		;So, now we wait for the pin to go low
		goto		wait_for_low	;Circle until it does
		call		store_time
;
;****************************************************************************************************************************
;This should work
;
;Now, we need to check to see if 245Hz<pulse length<255Hz.  Procedure is the same as above.
		;********** 16 BIT			 Taken from http://massmind.org/techref/microchip/
		;if( X <= K )
check_x_245_2	movfw 		timeHI
		sublw 		_245_pulse_high
		skpc
		goto 		false_start_2
		skpz
		goto 		check_x_255_2
		movfw 		timeLO
		sublw 		_245_pulse_low
		skpc
		goto 		false_start_2
		goto		check_x_255_2
;If we get here, the pulse is greater than the 245Hz pulse.  We now need to check that x<255Hz.  Once more, taken from http://massmind.org/techref/microchip/
;if( K <= X )
check_x_255_2  	movlw 		_255_pulse_high
		subwf 		timeHI,w
		skpc
		goto 		false_start_2
		skpz
		goto 		good_pulse
		movlw 		_255_pulse_low
		subwf 		timeLO,w
		skpc
		goto 		false_start_2
		goto		good_pulse
;
;
;End of working section
;***************************************************************************************************************************
;
;If we get here, the pulse is good and one entire waveform has been recieved.  We need to decrement the number of pulses needed to register a hit and then go back to waiting for the line to go high
good_pulse		decfsz		pulses,f		;Decrease the pulses counter
		goto		wait_for_high	;If it is not zero, go back and wait for the line to go high
		bsf		PORTB,0		;If it is zero, register a hit
		movlw		sensor_delay
		movwf		between_pulse
hit_delay		call		siren1		;And delay for the appropriate time
		decfsz		between_pulse,f
		goto		hit_delay
		bcf		PORTB,0
		decfsz		hits_left,f
		goto		wait_for_pulse
game_over		bsf		PORTB,0
		call		siren1
		goto		game_over
;If we end up here, the pulse was a false start.  Reset, and go back to the beginning.
false_start		bcf		T1CON,0		;Stop the timer
		clrf		TMR1H
		clrf		TMR1L		;Clear the timer
		movlw		pulses_per_hit
		movwf		pulses		;Reset the number of pulses needed to register a hit
		goto		wait_for_pulse
;
;If we end up here, the line is low, and the preceding high pulse wasn't of the right length.  So, we need to set things up
;to go again, and then wait for the line to go high again
;
false_start_2	bcf		T1CON,0
		clrf		TMR1H
		clrf		TMR1L
		movlw		pulses_per_hit
		movwf		pulses
wait_until_high	movlw		d'3'
		btfss		hitline,0
		addwf		PCL,f
		btfss		PORTB,2
		goto		wait_until_high
		goto		wait_for_pulse
		btfss		PORTB,3
		goto		wait_until_high
		goto		wait_for_pulse
;
;
;
store_time		bcf		T1CON,0		;Turn of Timer 1 for ease in reading.  The operation is not time sensitive enough to notice the couple of instructions this will throw things off
		movf		TMR1H,w		;Move the high byte of Timer 1 into working register for storage
		movwf		timeHI		;And store it in the register timeHI
		movf		TMR1L,w		;Move the high byte of Timer 1 into the working register in preparation for storing it
		movwf		timeLO		;And store it in the register timeLO
		clrf		TMR1H		;Clear the timer high byte
		clrf		TMR1L		;Clear the timer low byte
		bsf		T1CON,0		;And start the timer again.  Our count for the next pulse will be about 7 instructions out of aproximately 2000 off.  No big deal due to our tolerance
		return
;
delay0.1		clrf 		temp1		;Delay for about .1 seconds
		movlw		d'48'
		movwf 		temp2
set_temp3		movlw		d'3'
		movwf		temp3		
dec4		nop
		bsf		PORTB,1
		decfsz		temp1,f	
		goto 		dec4
		decfsz		temp3,f
		goto		dec4
		nop
		bcf		PORTB,1		
		decfsz		temp2,f	
		goto 		set_temp3			
		return
;		
startup_tone	movlw		0x0d
		movwf		temp1
		movwf		tone_cycles		;Number of cycles for each tone
		movlw		0x70		;Number of steps
		movwf		tones		;Holds number of steps
		movlw		0x99		;Determines the frequency
		movwf		frequency		;Holds the frequency
repeat3		movf		frequency,w
		movwf		temp		;Move frequency to temp5
on3		bsf		PORTB,1		;Turn the speaker on
		decfsz		temp,f		;Decrement temp5
		goto		on3		;And repeat until temp5=0
		movwf		temp		;Move the contents of temp4 back into temp 5
off3		bcf		PORTB,1		;Turn speaker off
		decfsz		temp,f		;Decrement temp5
		goto		off3		;And repeat until temp5=0
		decfsz		tone_cycles,f	;Now decrement temp2
		goto		repeat3		;And go back and repeat the same tone
		decf		frequency,f		;Increase the frequency (means fewer repeats)
		movf		temp1,w		;Move this same number to the working register
		movwf		tone_cycles		;And move the working register to the register determining the number of cycles for each tone
		decfsz		tones,f		;Decrease the number of steps remaining
		goto		repeat3		;Repeat with new tones
		return
;
;
;
siren1		movlw		0x01
		movwf		temp1
		movwf		tone_cycles		;Number of cycles for each tone
		movlw		0xa0		;Number of steps
		movwf		tones		;Holds number of steps
		movlw		0xff		;Determines the frequency
		movwf		frequency		;Holds the frequency
repeat		movf		frequency,w
		movwf		temp		;Move frequency to temp5
on		bsf		PORTB,1		;Turn the speaker on
		decfsz		temp,f		;Decrement temp5
		goto		on		;And repeat until temp5=0
		movwf		temp		;Move the contents of temp4 back into temp 5
off		bcf		PORTB,1		;Turn speaker off
		decfsz		temp,f		;Decrement temp5
		goto		off		;And repeat until temp5=0
		decfsz		tone_cycles,f	;Now decrement temp2
		goto		repeat		;And go back and repeat the same tone
		decf		frequency,f		;Increase the frequency (means fewer repeats)
		movf		temp1,w		;Move this same number to the working register
		movwf		tone_cycles		;And move the working register to the register determining the number of cycles for each tone
		decfsz		tones,f		;Decrease the number of steps remaining
		goto		repeat		;Repeat with new tones
siren2		movlw		0x00-0x02
		movwf		temp1
		movwf		tone_cycles		;Number of cycles for each tone
		movlw		0xa0		;Number of steps
		movwf		tones		;Holds number of steps
		movlw		0xff-0xa0		;Determines the frequency
		movwf		frequency		;Holds the frequency
repeat2		movf		frequency,w
		movwf		temp		;Move frequency to temp5
on2		bsf		PORTB,1		;Turn the speaker on
		decfsz		temp,f		;Decrement temp5
		goto		on2		;And repeat until temp5=0
		movwf		temp		;Move the contents of temp4 back into temp 5
off2		bcf		PORTB,1		;Turn speaker off
		decfsz		temp,f		;Decrement temp5
		goto		off2		;And repeat until temp5=0
		incfsz		tone_cycles,f	;Now decrement temp2
		goto		repeat2		;And go back and repeat the same tone
		incf		frequency,f		;Increase the frequency (means fewer repeats)
		movf		temp1,w		;Move this same number to the working register
		movwf		tone_cycles		;And move the working register to the register determining the number of cycles for each tone
		decfsz		tones,f		;Decrease the number of steps remaining
		goto		repeat2		;Repeat with new tones
		return
;
osc_sup		movlw		d'7'
		movwf		temp
dec5		decfsz		temp
		goto		dec5
		return
		end
