;***************************************************************************
;   lights.asm           Scale LED Lighting System
;***************************************************************************
;            Bruce Abbott   bhabbott@paradise.net.nz 
;
;        for Microchip PIC 12C508, 12C509, 12F629 or 12F675.
;
;============================= Description =================================
;
; =============================================================================
;                             Summary of Changes
;
; 2005/03/15 V0.0 - Created from RXDecode.asm 
; 2005/03/19 V0.1 - Reduced strobe flash time
; 2005/05/20 V0.2 - Changed strobe flash sequence again!
;
; -----------------------------------------------------------------------------

#DEFINE	TIME 4		; number of servo pulses per strobe state

#DEFINE version  "0.2"

;#DEFINE __12C508	; enable if processor not specified elsewhere 
;#DEFINE __12F675	; MPLAB users should use menu <Configure/Select Device> 

;#DEFINE NO_OSCCAL 	; enable if OSCCAL value was erased!


	ifdef	  __12C508
	PROCESSOR PIC12C508
        INCLUDE   <P12C508.inc>
	__CONFIG  _MCLRE_OFF&_CP_OFF&_WDT_ON&_IntRC_OSC	
	else
        PROCESSOR PIC12F675
        INCLUDE   <P12F675.inc>
	__CONFIG  _MCLRE_OFF&_CP_OFF&_WDT_ON&_BODEN_ON&_INTRC_OSC_NOCLKOUT
	endif

        radix     dec

	errorlevel 0,-305,-302


; Bit definitions for the GPIO register and the TRIS register

#DEFINE STRB1	 0    ; pin 7   strobe light #1 (switched) WHITE
#DEFINE STRB2	 1    ; pin 6   strobe light #2 (not switched) RED
#DEFINE NAV	 2    ; pin 5   navigation lights (switched) RED/GREEN
#DEFINE SERVO	 3    ; pin 4   servo pulse input
#DEFINE AUX1	 4    ; pin 3   auxilary output 1 
#DEFINE AUX2	 5    ; pin 2   auxilary output 2 

#DEFINE TrisBits (1<<SERVO)


; Bits to be set with the OPTION instruction
;   No wake up
;   No weak pullups
;   Timer 0 source internal
;   Prescaler to Watchdog, divide by 16 (~270mS).
;
#DEFINE OptionBits B'11011100'


;=========================================================================
; Macro for generating short time delays
;
NO_OP           MACRO   count
NO_OP_COUNT     SET     count
                WHILE   NO_OP_COUNT>1
		goto	$+1		; 2 clocks
NO_OP_COUNT     SET     NO_OP_COUNT-2
                ENDW
		IF	NO_OP_COUNT
		nop			; 1 clock
		ENDIF
                ENDM

;===========================================================================
; Macro to create offsets for variables in RAM
;
		ifdef	__12C508
ByteAddr	SET	7
		else
ByteAddr	SET	32		; user RAM starts here
		endif

BYTE            MACRO     ByteName
ByteName        EQU       ByteAddr
ByteAddr	SET       ByteAddr+1
                ENDM

; ==========================================================================
;                 RAM Variable Definitions  
;
        BYTE	Flags		; various boolean flags            

        BYTE	ServoCount	; servo pulse length. 1~255 = 0.01~2.55mS  

	BYTE	Timer		; delay timer for strobes

	BYTE	Strobe1		; strobe 1 sequencer
	BYTE	Strobe2		; strobe 2 sequencer
				
	BYTE	Temp1
	BYTE	Temp2



; flag values
;
#DEFINE WATCH		0	; Watchdog timeout
#DEFINE	STROBE1		1	; strobe 1 is on	
#DEFINE	STROBE2		2	; strobe 2 is on
#DEFINE	SWITCH		4	; switch is on (controlled by servo input)


;****************************************************************************
;                                Code
;
	ORG	0
	goto	ColdStart

;-------------------------- version string ----------------------------------

	org	8		
	ifdef	__12C508
	dt	"RYANL508"
	endif
	ifdef	__12F629	
	dt	"RYANL629"
	endif
	ifdef	__12F675	
	dt	"RYANL675"
	endif
	dt	"--V"
	dt	version
	dt	"--"

;============================================================================

ColdStart:		
	bcf	Flags,WATCH
	btfss	STATUS,NOT_TO		; copy Watchdog timeout flag
	bsf	Flags,WATCH

; get oscillator calibration value and use it to fine-tune clock frequency.
; 12C508/9 has value in W at startup, 12F629/75 gets it from RETLW at 0x3ff.

	ifdef	__12C508
	ifdef	NO_OSCCAL		
	movlw	0x90			; replace with value for your PIC!
	endif
	movwf	OSCCAL			; set oscillator calibration 
	else 
	bsf	STATUS,RP0		; register bank 1 (12F629/75) 
	call	0x3ff			; get OSCCAL value
	movwf	OSCCAL			; set oscillator calibration 
        bcf	STATUS, RP0		; register bank 0 
        endif

; ==========================================================================
; Moves the prescaler from tmr0 to the watchdog without accidental resets.
;
	clrwdt                    
	clrf      TMR0            
	movlw     OptionBits | 7  
        option                    
        clrwdt
        movlw     OptionBits
        option
        clrwdt
                      
	ifdef	__12C508
	clrwdt                    
	clrf    TMR0            
	movlw   OptionBits | 7  
        option                    
        clrwdt
        movlw   OptionBits
        option
        clrwdt
	else
        clrwdt                    
	clrf    TMR0        
	bsf	STATUS,RP0	; register bank 1 (12F629/75)
        movlw	OptionBits | 7
	movwf	OPTION_REG
        clrwdt
        movlw   OptionBits
        movwf	OPTION_REG
	bcf	STATUS,RP0	; register bank 0
        clrwdt
	endif

;========================================================================
; initialise I/O registers 

	ifdef	__12C508
        clrf	GPIO			; all outputs low
        movlw	TrisBits
        TRIS    GPIO			; set I/O pin directions
	else
        clrf	GPIO			; all outputs low
	bsf	STATUS,RP0		; register bank 1 (12F629/75)
        movlw	TrisBits
        movwf	TRISIO			; set I/O pin directions
	ifdef	ANSEL
	clrf	ANSEL			; disable analog inputs (12F675)
	endif
	bcf	STATUS,RP0		; register bank 0
	ifdef	CMCON
	movlw	b'00000111'		      
        movwf	CMCON			; Comparator off
	endif
	endif

; CPU specific stuff done, now we can start the main program!

        goto	Main		
							                               
SeqStrobe1:	
		ifdef	PCLATH
		clrf	PCLATH
		endif
		movf	Strobe1,w
		addwf	PCL
		retlw	b'00000001'
		retlw	b'00000000'
		retlw	b'00000001'
		retlw	b'00000000'
		retlw	b'00000001'
		retlw	b'00000000'
		retlw	b'00000001'
		retlw	b'00000000'
		retlw	b'00000000'
		retlw	b'00000000'
		retlw	b'00000000'
		retlw	b'00000000'
		retlw	b'00000000'
		retlw	b'00000000'
		retlw	b'00000000'
		retlw	b'00000000'
		retlw	b'00000000'
		retlw	b'00000000'
		retlw	b'00000000'
		retlw	b'10000000'

SeqStrobe2:	
		ifdef	PCLATH
		clrf	PCLATH
		endif
		movf	Strobe2,w
		addwf	PCL
		retlw	b'00000000'
		retlw	b'00000000'
		retlw	b'00000000'
		retlw	b'00000000'
		retlw	b'00000000'
		retlw	b'00000000'
		retlw	b'00000000'
		retlw	b'00000000'
		retlw	b'00000001'
		retlw	b'00000000'
		retlw	b'00000001'
		retlw	b'00000000'
		retlw	b'00000001'
		retlw	b'00000000'
		retlw	b'00000000'
		retlw	b'00000000'
		retlw	b'10000000'

;-------------------------------------------------------------------------------
;                    Millisecond Delay Timer 
;-------------------------------------------------------------------------------
; Input: W = number of milliseconds to wait (max 256mS)
;

dx1k:		movwf	Temp1
_dx1k1:		movlw	(1000-5)/5
		movwf	Temp2
_dx1k2:		clrwdt			; avoid watchdog timeout
		nop
		decfsz	Temp2		; wait 1mS
		goto	_dx1k2
		decfsz	Temp1		
		goto	_dx1k1
		retlw	0


;*******************************************************************************
;				   Main
;*******************************************************************************		


Main:		btfsc	Flags,WATCH	; did the watchdog timeout ?
        	goto    MainLoop	; oops! try to keep going ...

		clrf	Flags		; clear all flags

		movlw	250		; wait 500mS for power to stabilise 
		call	dx1k		
		movlw	250
		call	dx1k

		movlw	TIME
		movwf	Timer

		clrf	Strobe1
		clrf	Strobe2

MainLoop:	clrwdt			; avoid watchdog timeout
		btfsc	GPIO,SERVO	; wait for no servo pulse
		goto	MainLoop
waitpulse:	clrwdt			; avoid watchdog timeout
		btfss	GPIO,SERVO	; wait for start of servo pulse
		goto	waitpulse

		clrf	ServoCount
measure:	incf	ServoCount	;1    count * 10uS
		skpnz			;2
		goto	ServoError	;3    >2.55mS ?
		clrwdt			; 4   avoid watchdog timeout
		NO_OP	3		;5~7				
		btfsc	GPIO,SERVO	;8    servo pulse finished ?
		goto	measure		;9,10 no, continue measuring

		movlw	150
		subwf	ServoCount,w	; less than 1.5mS ? 
		bcf	Flags,SWITCH	; assume no
		skpc
		bsf	Flags,SWITCH	; yes

		decfsz	Timer
		goto	MainLoop	; time for next change?
		movlw	TIME
		movwf	Timer

		call	SeqStrobe1	; get Strobe 1 state
		movwf	Temp1
		incf	Strobe1		; next state
		btfsc	Temp1,7		; end of sequence ?
		clrf	Strobe1		; restart sequence
		bcf	Flags,STROBE1
		btfsc	Temp1,0		; strobe 1 to be on ?
		bsf	Flags,STROBE1

		call	SeqStrobe2	; get Strobe2 state
		movwf	Temp1
		incf	Strobe2		; next state
		btfsc	Temp1,7		; end of sequence ?
		clrf	Strobe2		; restart sequence
		bcf	Flags,STROBE2
		btfsc	Temp1,0		; strobe 2 to be on ?
		bsf	Flags,STROBE2

		btfsc	Flags,SWITCH	; switch on ?
		goto	switch_on

switch_off:	bcf	GPIO,NAV	; no, turn off NAV lights
		bcf	GPIO,STRB1	;     turn of strobe 1
		goto	switch_done

switch_on:	bsf	GPIO,NAV	; yes, turn on NAV lights

		btfss	Flags,STROBE1	; flash strobe 1
		bcf	GPIO,STRB1
		btfsc	Flags,STROBE1
		bsf	GPIO,STRB1

switch_done:	btfss	Flags,STROBE2	; flash strobe 2
		bcf	GPIO,STRB2
		btfsc	Flags,STROBE2
		bsf	GPIO,STRB2

ServoError:
done:		goto	MainLoop
		





;---------- Oscillator Calibration Subroutine (12F629/75 only) --------------

		ifdef	__12F675
		org	0x3ff
		retlw	0x90	; replace with oscal value for your PIC!
		endif

		END


