;*******************************************************************************
;                                                                              *
;    Filename:     main.asm                                                    *
;    Date:         2017/2/9                                                    *
;    File Version: v5                                                          *
;    Author:       yasuoki                                                     *
;    Description:  Fog & Day light control                                     *
;                                                                              *
;*******************************************************************************
	#include	"p16f648a.inc"
	__config	_LVP_OFF & _BOREN_OFF & _MCLRE_OFF & _HS_OSC & _PWRTE_OFF & _WDT_OFF & _CP_OFF & _CPD_OFF

; I/O Config
; RA
RA_FG_PWR	EQU		RA0		; fog light power
RA_DL_PWR	EQU		RA1		; day light power
RA_FG_SW1	EQU		RA2		; fog light sw mode1
RA_FG_SW2	EQU		RA3		; fog light sw mode2
RA_DL_SW1	EQU		RA4		; day light sw mode1
RA_DL_SW2	EQU		RA5		; day light sw mode2
; RB
RB_EX_SW	EQU		RB0		; extra mode sw
BIT_MK_PWR	EQU		RB4		; side marker voltage
BIT_LO_PWR	EQU		RB5		; low beam light voltage
BIT_HI_PWR	EQU		RB6		; high beam light voltage

; CONST
WKUP_DELAY_TIME			EQU	010H
SCAN_WAIT_TIME			EQU	001H
FLASH_INTERVAL_TIME		EQU 008H
DL_LOW_PWR				EQU 05fH
DL_MID_PWR				EQU 0BFH
DL_HIGH_PWR				EQU	0FFH
DL_FLUSH_PWR			EQU 001H
		
; WORK REGISTER
			IDATA	020H
TIMER_CNT0	RES		1
TIMER_CNT1	RES		1
WKUP_CNT	RES		1		; wake up timer
FG_PWR		RES		1		; fog light mode
FG_SW		RES		1		; fog light switch
FG_SCAN		RES		1		; fog light read status
FG_WCNT		RES		1		; fog light wait counter
DL_PWR		RES		1		; day light mode
DL_SW		RES		1		; day light read status
DL_SCAN		RES		1		; day light read status
DL_WCNT		RES		1		; day light wait counter
PS_CNT		RES		1		; passing timer
PS_STOP		RES		1		; passing stop
EX_MODE		RES		1		; extra mode
EX_SW		RES		1		; extra read status
EX_WCNT		RES		1		; extra wait counter
LIGHT_SW	RES		1		; car light sw
LIGHT_SCAN	RES		1		; car light scan
LIGHT_WCNT	RES		1		; car light wait counter
LIGHT_SW_MK	EQU		0
LIGHT_SW_LO	EQU		1
LIGHT_SW_HI	EQU		2

;*******************************************************************************
; Reset Vector
;*******************************************************************************

RES_VECT	CODE	0x0000			; processor reset vector
			GOTO	INIT			; go to beginning of program

;*******************************************************************************
; MAIN PROGRAM
;*******************************************************************************

MAIN_PROG	CODE				; let linker place main program

INIT	
		BSF		STATUS,RP0		; bank 1
		BCF		INTCON,GIE		; no intr
		MOVLW	b'00111100'		; RA0,1 output RA2,3,4,5 input
		MOVWF	TRISA
		MOVLW	b'01110001'		; RB0,4,5,6 input
		MOVWF	TRISB
		MOVLW	b'00000111'		; 07h
		MOVLW	h'ff'			; pwm PR2
		MOVWF	PR2				
		BCF		STATUS,RP0		; bank 0
		MOVWF	CMCON
		MOVLW	h'ff'
		MOVWF	CCPR1L			; pwm duty cycle 0
		MOVLW	b'00111100'		; pwm mode select, CCPR1L:2
		MOVWF	CCP1CON
		MOVLW	b'00000111'		; pwm timer2 on, pre scaler x16(11)
		MOVWF	T2CON
		
		CLRF	PORTA
		CLRF	PORTB
		CLRF	FG_PWR
		CLRF	FG_SW
		CLRF	FG_WCNT
		CLRF	DL_PWR
		CLRF	DL_SW
		CLRF	DL_WCNT
		CLRF	PS_CNT
		CLRF	PS_STOP
		CLRF	EX_SW
		CLRF	EX_WCNT
		CLRF	LIGHT_SW
		CLRF	LIGHT_WCNT
		MOVLW	WKUP_DELAY_TIME	; WKUP_CNT = WKUP_DELAY_TIME
		MOVWF	WKUP_CNT
		CLRF	TIMER_CNT0
		CLRF	TIMER_CNT1
MAIN_LOOP
READ_FG_SWITCH
		MOVF	FG_WCNT,W		; fog switch scan
		BTFSC	STATUS,Z		; fog wait timer == 0
		GOTO	SCAN_FG_SWITCH
		DECF	FG_WCNT,F		; fog wait--
		GOTO	READ_FG_END
SCAN_FG_SWITCH
		CLRF	FG_SCAN			; sw = 0
		BTFSC	PORTA,RA_FG_SW1	; if mode1 == on
		BSF		FG_SCAN,0		;	sw |= 1
		BTFSC	PORTA,RA_FG_SW2	; if mode2 == on
		BSF		FG_SCAN,1		;	sw |= 2
		MOVF	FG_SCAN,W		; if scan == sw
		SUBWF	FG_SW,W
		BTFSC	STATUS,Z
		GOTO	READ_FG_END
		MOVF	FG_SCAN,W		; sw = scan
		MOVWF	FG_SW			; 
		MOVLW	SCAN_WAIT_TIME	; wait = SCAN_WAIT_TIME
		MOVWF	FG_WCNT
READ_FG_END
		
READ_DL_SWITCH
		MOVF	DL_WCNT,W		; day switch scan
		BTFSC	STATUS,Z		; day wait timer == 0
		GOTO	SCAN_DL_SWITCH
		DECF	DL_WCNT,F		; day wait--
		GOTO	READ_DL_END
SCAN_DL_SWITCH
		CLRF	DL_SCAN			; scan = 0
		BTFSC	PORTA,RA_DL_SW1	; if mode1 == on
		BSF		DL_SCAN,0		;	scan |= 1
		BTFSC	PORTA,RA_DL_SW2	; if mode2 == on
		BSF		DL_SCAN,1		;	scan |= 2
		MOVF	DL_SCAN,W		; if scan == sw
		SUBWF	DL_SW,W
		BTFSC	STATUS,Z
		GOTO	READ_DL_END
		MOVF	DL_SCAN,W		; sw = scan
		MOVWF	DL_SW			;
		MOVLW	SCAN_WAIT_TIME	; wait = SCAN_WAIT_TIME
		MOVWF	DL_WCNT
READ_DL_END

READ_EX_SWITCH
		MOVF	EX_WCNT,W			; if wcnt == 0
		BTFSC	STATUS,Z			;	goto scan_switch
		GOTO	SCAN_EX_SWITCH		;
		DECF	EX_WCNT,F			; wait--
		GOTO	READ_EX_END			; goto read_end
SCAN_EX_SWITCH
		BTFSS	PORTB,RB_EX_SW		; if sw != on
		GOTO	SCAN_EX_SWITCH_OFF	;	goto scan_switch_off
SCAN_EX_SWITCH_ON
		BTFSC	EX_SW,0				; if mode == on
		GOTO	READ_EX_END			;	goto scan_mode_on
		; OFF -> ON
		BSF		EX_SW,0				; sw = 1
		MOVLW	SCAN_WAIT_TIME		; wcnt = SCAN_WAIT_TIME
		MOVWF	EX_WCNT
		GOTO	READ_EX_END			; got read_end
SCAN_EX_SWITCH_OFF
		BTFSS	EX_SW,0				; if mode != on
		GOTO	READ_EX_END			;	goto read_end
		; ON -> OFF
		BCF		EX_SW,0				; ex_sw = 0
		MOVLW	SCAN_WAIT_TIME		; wcnt = SCAN_WAIT_TIME
		MOVWF	EX_WCNT
		GOTO	READ_EX_END			; got read_end
READ_EX_END
		
READ_LGT_MODE
		MOVF	LIGHT_WCNT,W		; if wcnt == 0
		BTFSC	STATUS,Z			;	goto scan_switch
		GOTO	SCAN_LGT_SWITCH		;
		DECF	LIGHT_WCNT,F		; wait--
		GOTO	READ_LGT_END		; goto read_end
SCAN_LGT_SWITCH
		MOVLW	(1<<BIT_MK_PWR)|(1<<BIT_HI_PWR)|(1<<BIT_LO_PWR)
		ANDWF	PORTB,W				; scan = light pwr
		MOVWF	LIGHT_SCAN
		SUBWF	LIGHT_SW,W			; if scan != sw
		BTFSC	STATUS,Z			;	goto read_end
		GOTO	READ_LGT_END
		MOVF	LIGHT_SCAN,W
		MOVWF	LIGHT_SW			; sw = scan
		MOVLW	SCAN_WAIT_TIME		; 
		MOVWF	LIGHT_WCNT			; wait = SCAN_WAIT_TIME
		CLRF	WKUP_CNT
READ_LGT_END
		
SELECT_MODE
SELECT_DL_MODE
		CLRF	DL_PWR				; pwr = off
		BTFSC	EX_SW,0				; if ex != 0
		GOTO	SELECT_DL_EXTRA		;	goto extra
SELECT_DL_NORMAL
		BTFSC	DL_SW,0				; if sw == 1 (auto)
		GOTO	SELECT_DL_NORMAL_CH	;	goto normal check
		BTFSC	DL_SW,1				; if sw == 2 (extra)
		GOTO	SELECT_DL_NORMAL_CH	;	goto normal check
		GOTO	SELECT_DL_END		; goto end
		
SELECT_DL_EXTRA
		BTFSS	LIGHT_SW,BIT_HI_PWR	; if hight beam off
		GOTO	SELECT_DL_HI_OFF	;	goto no flush
		MOVF	PS_CNT,W			; if ps cnt != 0
		BTFSS	STATUS,Z			;	goto flush
		GOTO	SELECT_DL_FLUSH
		BTFSC	PS_STOP,0			; if ps stop
		GOTO	SELECT_DL_NO_FLUSH	;	goto no flush
		; passing mode on
		CLRF	TIMER_CNT1
		CLRF	TIMER_CNT0
		MOVLW	1					; cnt = 1
		MOVWF	PS_CNT				
		BSF		PS_STOP,0			; passing stop = 1
		GOTO	SELECT_DL_FLUSH
SELECT_DL_HI_OFF
		BCF		PS_STOP,0			; passing stop = 0
SELECT_DL_NO_FLUSH
		CLRF	PS_CNT
		BTFSC	DL_SW,0				; if sw == 1 (auto)
		GOTO	SELECT_DL_NORMAL_CH	;	goto normal check
		BTFSC	DL_SW,1				; if sw == 2 (extra)
		GOTO	SELECT_DL_EXTRA_CH	;	goto extra check
		GOTO	SELECT_DL_END		; goto end

SELECT_DL_NORMAL_CH
		BTFSC	LIGHT_SW,BIT_HI_PWR	; if hight beam on
		GOTO	SELECT_DL_END		;	goto end
		BTFSC	LIGHT_SW,BIT_LO_PWR	; if low beam on
		GOTO	SELECT_DL_END		;	goto end
		BTFSS	LIGHT_SW,BIT_MK_PWR	; if marker beam !on
		GOTO	SELECT_DL_MID		;	goto mid
		GOTO	SELECT_DL_LO		; goto low
		
SELECT_DL_EXTRA_CH
		GOTO	SELECT_DL_HI		;	goto hi
		
SELECT_DL_LO
		MOVLW	DL_LOW_PWR
		MOVWF	DL_PWR				; pwr = 1(low power)
		GOTO	SELECT_DL_END
SELECT_DL_MID
		MOVLW	DL_MID_PWR
		MOVWF	DL_PWR				; pwr = 2(mid power)
		GOTO	SELECT_DL_END
SELECT_DL_HI
		MOVLW	DL_HIGH_PWR
		MOVWF	DL_PWR				; pwr = 3(high power)
		GOTO	SELECT_DL_END
SELECT_DL_FLUSH
		MOVLW	DL_HIGH_PWR
		MOVWF	DL_PWR				; pwr = 3(high power)
		MOVLW	FLASH_INTERVAL_TIME	; if timer & FLASH_INTERVAL_TIME
		ANDWF	TIMER_CNT1,W		;	pwr = 0 (off)
		BTFSC	STATUS,Z
		GOTO	SELECT_DL_END
		MOVLW	DL_FLUSH_PWR
		MOVWF	DL_PWR				; pwr = 4(flush power)
SELECT_DL_END
	
SELECT_FG_MODE
		CLRF	FG_PWR				; pwr = off
		BTFSC	EX_SW,0				; if ex != 0
		GOTO	SELECT_FG_EXTRA		;	goto extra
SELECT_FG_NORMAL
		BTFSC	FG_SW,0				; if sw == 1 (auto)
		GOTO	SELECT_FG_NORMAL_ON	;	goto on
		BTFSC	FG_SW,1				; if sw == 2 (extra)
		GOTO	SELECT_FG_NORMAL_ON	;	goto on
		GOTO	SELECT_FG_END		; goto end
SELECT_FG_EXTRA
		BTFSC	FG_SW,0				; if sw == 1 (auto)
		GOTO	SELECT_FG_NORMAL_ON	;	goto on
		BTFSC	FG_SW,1				; if sw == 2 (extra)
		GOTO	SELECT_FG_EXTRA_ON	;	goto on
		GOTO	SELECT_FG_END		; goto end
SELECT_FG_NORMAL_ON		
		BTFSC	LIGHT_SW,BIT_HI_PWR	; if high beam
		BSF		FG_PWR,0			;	pwr = on
		GOTO	SELECT_FG_END		; goto end
SELECT_FG_EXTRA_ON
		BSF		FG_PWR,0			;	pwr = on
		GOTO	SELECT_FG_END
SELECT_FG_END

CNT_TIMER
		INCFSZ	TIMER_CNT0		; if timer_cnt0++ != 0
		GOTO	CNT_TMER_END
		INCFSZ	TIMER_CNT1		; if timer_cnt1++ != 0
		GOTO	CNT_TMER_END
		
		MOVF	WKUP_CNT,W		; if wkup_cnt != 0
		BTFSS	STATUS,Z		;	wkup_cnt--
		DECF	WKUP_CNT,F
		
		MOVF	PS_CNT,W		; if ps_cnt != 0
		BTFSS	STATUS,Z		;	ps_cnt--
		DECF	PS_CNT,F
CNT_TMER_END
		
CTRL_PWR
		MOVF	WKUP_CNT,W		; if wkup_cnt != 0
		BTFSS	STATUS,Z		;	goto CTRL_END
		GOTO	CTRL_END
		
CTRL_DL_PWR
		MOVF	DL_PWR,W
		BTFSC	STATUS,Z		; if day pwr == 0
		GOTO	CTRL_DL_OFF
CTRL_DL_ON
		BSF		PORTA,RA_DL_PWR	; day power on
		MOVF	DL_PWR,W
		MOVWF	CCPR1L			; set pwm duty
		GOTO	CTRL_DL_END
CTRL_DL_OFF
		BCF		PORTA,RA_DL_PWR	; day power off
CTRL_DL_END
		
CTRL_FG_PWR
		MOVF	FG_PWR,W
		BTFSC	STATUS,Z
		GOTO	CTRL_FG_OFF
CTRL_FG_ON
		BSF		PORTA,RA_FG_PWR
		GOTO	CTRL_FG_END
CTRL_FG_OFF
		BCF		PORTA,RA_FG_PWR
CTRL_FG_END
CTRL_END
		GOTO	MAIN_LOOP
		END
		