; -----------------------------------------------------------------------
; Laser safety controller
    #include <p12f629.inc>

; -----------------------------------------------------------------------
; Configuration bits
	__CONFIG _INTRC_OSC_NOCLKOUT & _WDT_ON & _PWRTE_ON & _MCLRE_ON & _BODEN_ON & _CP_OFF & _CPD_OFF

	RADIX DEC

; -----------------------------------------------------------------------
; Pinout
;
; GP0 - Comparator reference (analog comparator)
; GP1 - Voltage monitoring input (analog comparator)
; GP2 - 1kHz pilot tone (schmitt trigger digital input)
; GP3 - MCLR/Vpp (for ICSP)
; GP4 - Disable output to laser driver (digital)
; GP5 - Relay activation output (digital)

; -----------------------------------------------------------------------
; Variables declaration
VAR	UDATA_SHR
CNT	RES	1
d1	RES	1
d2	RES	1
d3	RES	1

; -----------------------------------------------------------------------
; reset vector
STARTUP CODE 0x000
	goto	start

#define PILOT GPIO,2

ALLOFF	MACRO
	movlw	b'010000'
	movwf	GPIO
	ENDM

DISABLE	MACRO
	movlw	b'110000'
	movwf	GPIO
	ENDM

ENABLE	MACRO
	movlw	b'100000'
	movwf	GPIO
	ENDM

#define LEEWAY 10
#define HALFCYCLE 122

; interrupt vector
INT_VECTOR CODE 0x004
	ALLOFF
	goto	pwrchk
	; Yeah I totally pwn the stack here. Like I care.

; relocatable code
PROG CODE

start
	ALLOFF
	bsf	STATUS, RP0
	call	0x3ff
	movwf	OSCCAL
	movlw	b'001111'
	movwf	TRISIO
	movlw	(1<<NOT_GPPU) | (0<<PSA) | (1<<PS0)
	movwf	OPTION_REG
	bsf	PIE1, CMIE

	bcf	STATUS, RP0
	clrf	INTCON
	clrwdt
	movlw	(1<<CINV) | (b'010'<<CM0)
	movwf	CMCON
	bsf	INTCON, PEIE

pwrchk:
	bcf	INTCON, GIE
	ALLOFF
	clrwdt
	btfss	CMCON, COUT
	goto	pwrchk

	bcf	PIR1, CMIF
	bsf	INTCON, GIE
	; from here on, interrupts are engaged and will trigger an ALLOFF if power dies

	; double check, I don't trust Microchip
	btfss	CMCON, COUT
	goto	pwrchk

	call	Delay_1s

	; looks like power is stable

invalid:
	clrf	CNT
loopa:
	; look for a rising edge
	DISABLE
	clrwdt
	btfsc	PILOT
	goto	loopa
loopb:
	clrwdt
	btfss	PILOT
	goto	loopb

valid:
	; reset timer
	clrf	TMR0
hi:
	movlw	HALFCYCLE - LEEWAY
	subwf	TMR0,W
	btfsc	STATUS,C
	goto	wlo
	btfss	PILOT
	goto	invalid
	goto	hi
	

wlo:
	movlw	HALFCYCLE + LEEWAY
	subwf	TMR0,W
	btfsc	STATUS,C
	goto	invalid
	btfsc	PILOT
	goto	wlo
	
	clrf	TMR0
lo:
	movlw	HALFCYCLE - LEEWAY
	subwf	TMR0,W
	btfsc	STATUS,C
	goto	whi
	btfsc	PILOT
	goto	invalid
	goto	lo

whi:
	movlw	HALFCYCLE + LEEWAY
	subwf	TMR0,W
	btfsc	STATUS,C
	goto	invalid
	btfss	PILOT
	goto	whi

	incfsz	CNT,F
	goto	off
	decf	CNT,F
	clrwdt
	ENABLE
	goto	valid
off:
	clrwdt
	DISABLE
	goto	valid

Delay_4ms
			;3993 cycles
	movlw	0x1E
	movwf	d1
	movlw	0x04
	movwf	d2
Delay_4ms_0
	decfsz	d1, f
	goto	$+2
	decfsz	d2, f
	goto	Delay_4ms_0

			;3 cycles
	goto	$+1
	nop

			;4 cycles (including call)
	return

Delay_1s
	clrf	d3
Delay_1s_0
	clrwdt
	ALLOFF
	call	Delay_4ms
	decfsz	d3, f
	goto	Delay_1s_0
	return

END

