;; servo-decoder.asm  (c) Ben Levitt 2006-2007
;;
;; A pic10f220 programmed with this code will listen to servo signals
;; on GPIO3, and send a 250ms pulse on GPIO0 whenever the servo signal
;; switches from above-center to below-center, or back.
;;
;; I use it to electronically trigger a digital video camera's 
;; start-recording/stop-recording button.
;;
;; I connect GPIO0 to the shutter button connection through a 1kOhm
;; resistor.
;;
;; I compile using the open assembler gpasm.


#include <p10f220.inc>

	__config (_IOFSCS_8MHZ & _WDT_OFF & _MCPU_OFF & _MCLRE_OFF & _CP_OFF)

	;; Variable
	cblock	0x10
		Length			; how long high?
		State			; 0=middle, 1=low, 2=high
		DelayCounter:3	; counters for Delay subroutines
	endc

	org 	0x00

Start
	call	Init10f220

	clrf	GPIO		; ShutterTrigger off, Vars to 0
	clrf	Length
	clrf	State
	
	call	Delay250	; Wait a second for power to stabilize
	call	Delay250
	call	Delay250
	call	Delay250

Main
	call	GetPulseLength

	btfsc	State,0		; if State=1 goto AlreadyLow
	goto	AlreadyLow

	btfsc	State,1		; if State=2 goto AlreadyHigh
	goto	AlreadyHigh

	btfss	Length,7	; if Length is low -> DoLow
	goto	DoLow

	btfsc	Length,7	; if Length is high -> DoHigh
	goto	DoHigh

	goto	Main

AlreadyLow
	btfsc	Length,7	; if Length is high -> DoMiddle
	goto	DoMiddle
	goto	Main

AlreadyHigh
	btfss	Length,7	; if Length is low -> DoMiddle
	goto	DoMiddle
	goto	Main

DoLow
	bsf		State,0		; Set State to 1 (Low)
	bsf		GPIO,0		; Set GPIO0 (ShutterTrigger) on
	call	Delay250
	bcf		GPIO,0		; Set GPIO0 (ShutterTrigger) off
	goto	Main

DoHigh
	bsf		State,1		; Set State to 2 (High)
	bsf		GPIO,0		; Set GPIO1 (ShutterTrigger) on
	call	Delay250
	bcf		GPIO,0		; Set GPIO1 (ShutterTrigger) off
	goto	Main

DoMiddle
	clrf	State		; Set State to 0/Middle	
	clrf	GPIO		; Set ShutterTrigger off
	goto	Main


;; Chip Initialization Routine
Init10f220
	movwf	OSCCAL		; load factory osccal value at start-up
	bcf		OSCCAL,0	; do NOT output osc/4 on GP2

	clrf	ADCON0		; Disable A2D module

	movlw	b'00000000' ; All GPIO pins off on power-up
	movwf	GPIO		; load port latches

	movlw	b'00001100' ; GP2,GP3 = input, rest outputs
	tris	GPIO		; set I/O directions

	movlw	b'11110000'	; wake-up on pin change disabled, weak pull-ups off
	option				; Timer0 clock select on GP2 internal write to OPTION_REG
	retlw	0


;; Handy Delay Routines
Delay250				; preload 2 into W for a 250ms delay
	movlw	2
Delay
	movwf   DelayCounter; pre-load W & enter at Delay2 for different delays
	movlw   D'232'		; (250ms per 2 in W on entry at 8MHZ)
	movwf   DelayCounter+1
	movlw   D'255'
	movwf   DelayCounter+2
Dloop
	nop							; 1
	decfsz  DelayCounter+2,f	; 1
	goto	$-2					; 2/1
	decfsz  DelayCounter+1,f	; 1
	goto	$-4					; 2/1
	decfsz  DelayCounter,f		; 1
	goto	$-6					; 2/1
	retlw   0					; 2


;; Wait for a pulse on GPIO3, store the duration of the pulse in Length
GetPulseLength
	btfss	GPIO,3		; wait here until GPIO3 is low
	goto	$-1

	btfss	GPIO,3		; wait here until GPIO3 is high
	goto	$-1

	clrf	Length
LengthLoop				; 12 cycles per loop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	nop
	incf	Length,F
	btfsc	GPIO,3		; wait here until GPIO3 is low
	goto	LengthLoop
	retlw	0


	end
