;************************************************************************
; Opastinhässäkkä							;
;************************************************************************

	LIST P = 16F84A,  R = HEX		;Prosessorityyppi, radix
	INCLUDE	"p16f84A.inc"			;w,f,porta,portb yms. 
	ERRORLEVEL -224				;Estää virheilmoituksen 
						;"tris"-komennosta
        __CONFIG _PWRTE_OFF & _HS_OSC & _WDT_OFF   
	
;	Poltto Tait-polttokoneella 16C84:nä, muista: PWRTE kääntyy!
;	Xtal 4 MHz => 1 us/cycle (HS/LS-oskillaattorin raja on 32kHz!)
;
;       Layout            St1
;       ======        /---<---- Track 1
;                    /   St2 
;        ->------>--------<---- Track 2
;       AdvHm   Hm   \   St3 
;              AdvSt  \---<---- Track 3
;
;				          +---+_+---+
;		Vaihde:Raide1/3	PORTA.2 ->|1      18|<- PORTA.1	 Lähtö2("jatkoyhteys")
;		Vaihde:Raide2/3	PORTA.3 ->|2      17|<- PORTA.0	 Lähtö1
;			 Twin-T	PORTA.4 ->|3      16|-- XTAL
;		  		    Vdd --|4      15|-- XTAL
;				Vss(GND)--|5      14|-- Vdd (+5V)
;		     St1_G/Hm_G PORTB.0 <-|6      13|<- PORTB.7	  Home
;		     St1_R/Hm_R PORTB.1 <-|7      12|-> PORTB.6	  Starter/!Home
;		  St2_G/AdvSt_G PORTB.2 <-|8      11|-> PORTB.5	  St3_R/AdvHm_R
;		  St2_R/AdvSt_R PORTB.3 <-|9      10|-> PORTB.4	  St3_G/AdvHm_G
;			    	          +---------+
;
;************************ RAM *********************************************************

	CBLOCK H'0C'

		St1_G_in	;Opastin Raide 1 Vihreä
		St1_G_out	;Opastin Raide 1 Vihreä
		St1_R_in	;Opastin Raide 1 Punainen
		St1_R_out	;Opastin Raide 1 Punainen

		St2_G_in	;Opastin Raide 2 Vihreä
		St2_G_out	;Opastin Raide 2 Vihreä
		St2_R_in	;Opastin Raide 2 Punainen
		St2_R_out	;Opastin Raide 2 Punainen

		St3_G_in	;Opastin Raide 3 Vihreä
		St3_G_out	;Opastin Raide 3 Vihreä
		St3_R_in	;Opastin Raide 3 Punainen
		St3_R_out	;Opastin Raide 3 Punainen

		Hm_G_in		;Tulo-opastin Vihreä
		Hm_G_out	;Tulo-opastin Vihreä
		Hm_R_in		;Tulo-opastin Punainen
		Hm_R_out	;Tulo-opastin Punainen

		AdvSt_G_in	;Lähtö-esiopastin Vihreä
		AdvSt_G_out	;Lähtö-esiopastin Vihreä
		AdvSt_Y_in	;Lähtö-esiopastin keltainen
		AdvSt_Y_out	;Lähtö-esiopastin keltainen

		AdvHm_G_in	;Tulo-esiopastin Vihreä
		AdvHm_G_out	;Tulo-esiopastin Vihreä
		AdvHm_Y_in	;Tulo-esiopastin keltainen
		AdvHm_Y_out	;Tulo-esiopastin keltainen

		Apu		;apumuuttuja, bittietoa:
				;	0=Twin-T:n tila
				;	1=Lähtö/Tulo päällä
				;	2=Esiopastinvilkun tila
		Flasher_ramp	;Esiopastimen ramppi

		Out_byte	;port b:n tuleva tila
		Out_bit		;mitä bittiä ylläolevasta säädetään
		PWM_delay	;PWM:n venyttäjä
		PWM_Loop_Count	;PWM-laskuri
           ENDC

	#DEFINE Home_sw		PORTB, 7
	#DEFINE Starter_sw	PORTA, 0
	#DEFINE next_Starter	PORTA, 1
	#DEFINE Turnout1or3	PORTA, 2
	#DEFINE Turnout2or3	PORTA, 3
	#DEFINE TwinT_in	PORTA, 4
 	#DEFINE TwinT_status	Apu, 0
 	#DEFINE LT		Apu, 1
	#DEFINE Flasher_status	Apu, 2
	#DEFINE	Ulos		PORTB
;************************************************************************
;RESTART/INT-START
;************************************************************************

	ORG     0		; Restart vector
	goto	main

	ORG	4		; INT vector
	retfie


;---------------------------------------------------------------
; vilkun ohjaus 1/3 POIS 2/3 PÄÄLLÄ
;---------------------------------------------------------------
;	kasvata ramppia:
;	jos ramppi =0 -> valo pois!
;	jos ramppi >127 ja valo on pois -> valo päälle, ramppi nollaan!

Flasher
	incfsz	Flasher_ramp,f ;kasvata Flasherramppia, menikö ympäri
	goto 	Flasher_on	;ei
Flasher_off
	bcf	Flasher_status	;kyllä, (ramppi=0) ->valo pois (clear)
	return
Flasher_on
	btfsc	Flasher_status	;(ramppi 1..255) oliko valo pois (clear)
	return			;ei, jatketaan
	btfss	Flasher_ramp,7	;kyllä, onko rampin bitti 7 "1" (set)
	return			;ei    (ramppi = 0  ..127), ei muutoksia
	bsf	Flasher_status	;kyllä (ramppi = 128..255), valo päälle (set)
	movlw	0x0		;nolla akkuun ja 
	movwf	Flasher_ramp	;nollataan sillä vikkkuramppi
	return

;---------------------------------------------------------------
;Lookup-taulu (jäljittelee x^3-käyrää, 0..0x0F -> 0..0x20)
;---------------------------------------------------------------
Lookup
	addwf pcl,f
	retlw	.0
	retlw	.0
	retlw	.0
	retlw	.0
	retlw	.1
	retlw	.1
	retlw	.2
	retlw	.3
	retlw	.5
	retlw	.7
	retlw	.9
	retlw	.13
	retlw	.16
	retlw	.21
	retlw	.26
	retlw	.32

;---------------------------------------------------------------
init
;---------------------------------------------------------------
; I/O portit kuntoon

	movlw	b'10000000'	;RB7=sisään, RB0..6=ulos
	tris	portb
	movlw	b'00011111'	;RA0..4=sisään
	tris	porta

	movlw	.0		;Port A lähdöt nollille
	movwf	porta		;
	movlw	0x00		;Port B ledit päälle
	movwf	portb		;

	movlw	0x00		;esiopastinvilkun tila on 0
	movwf	Flasher_ramp	;
	return

;---------------------------------------------------------------
; Brighten OPASTINLAMPPUA
;---------------------------------------------------------------
Brighten
	movwf	FSR		;op_in-rek w->Indirectiin
	incfsz	INDF, W		;Brighten Sg_in ->w, ympäri?
	movwf	INDF		;ei, akusta Sg_in-rek:iin
				;
	call	Sg_out		;kopioi Sg_in->Sg_out
	return

;---------------------------------------------------------------
; HIMMENNÄ OPASTINLAMPPUA
;---------------------------------------------------------------
Dimm
	movwf	FSR		;Sg_in-rek w->Indirectiin
	movf	INDF, W		;kopioi akkuun,
	skpz			;oliko nolla
	decf	INDF, F		;ei, himmennä Sg_in-rek:iä
					;
	call	Sg_out		;kopioi Sg_in->Sg_out
	return

;---------------------------------------------------------------
; Sg_IN -> Sg_OUT ACHTUNG: FSR pitää sis. oikean IN_rekisterin
;---------------------------------------------------------------
Sg_out
	btfss	INDF, 7		;onko Sg_in ylätavu 1 (set)?
	goto	Sg_out_0	;ei ole, pidetään Sg_out pimeänä
	rlf	INDF, f		;yläbitti pois
	swapf	INDF, W		;swappaa ylä-alatavut, akkuun
	rrf	INDF, f		;yläbitti takaisin
	incf	FSR, f		;muut osoitus Sg_in->Sg_out
	andlw	0xF		;maskaa ylätavu pois
	call	Lookup		;muunna x3 -käyräksi
	movwf	INDF		;ja työnnö Sg_out:iin
	return
Sg_out_0
	incf	FSR, f		;muut osoitus Sg_in->Sg_out
	movlw	0x0		;opastin pimeäksi
	movwf	INDF		;ja pimeä Sg_out:iin
	return

;-----------------------------------------------------------------------------
;Tarkista Twin-T
;-----------------------------------------------------------------------------
; jos lähtö ja tulo-opastin punaiset ->Twin-T pois
; jos juna -> Twin-T päälle
Check_TwinT
	btfss	Starter_sw	;onko Lahtökytkin seis (set=seis)
	goto 	Check_train	;ei, tarkista juna
	btfss	Home_sw		;onko Tulokytkin seis (set=seis)
	goto 	Check_train	;ei, tarkista juna
	bcf	TwinT_status	;on Twin-T: ei junaa (clear)
	return
Check_train
	btfss	TwinT_in	;onko Twin-T (set=ei junaa)?
	bsf	TwinT_status	;on, Twin-T punaiseksi (set)
	return

;-----------------------------------------------------------------------------
;PWM-BIT-LOOP
;-----------------------------------------------------------------------------
PWM_bit_loop
	bsf	Out_byte, 0	;tämän lampun valo oletusarv. pois
	tstf	INDF		;onko tätä Sg_out:ia
	skpnz			;eihän vielä sammutettava (zero)?
	goto	PWM_bit_next	;ei vielä
	decf	INDF, f		;vähennetään
	bcf	Out_byte, 0	;ja sytytetään lamppu
PWM_bit_next
	rlf	Out_byte, f
	incf	FSR, f		;indirect osoittamaan
	incf	FSR, f		;seur. Sg_out:iin
	decfsz	Out_bit, f	;joko viimeinen ulostulobitti?
	goto 	PWM_bit_loop	;ei, takaisin
	return			;kyllä

;---------------------------------------------------------------
; Laske lähtöopastimet (L1..L3)
;---------------------------------------------------------------
Laske_lahto_opastimet
Sg_St1 	;-------------------------------------------------------
	btfsc	TwinT_status	;Onko raide vapaa (clear)?
	goto	St1_halt		;ei, op->seis
	btfsc	Starter_sw	;Onko Lähtökytkin vi(clear)?
	goto 	St1_halt		;ei, op->seis

	btfss	Turnout2or3	;Onko vaihteet raiteelle 2/3(set)?
	goto 	St1_halt		;on, op->seis
	btfsc	Turnout1or3	;Onko vaihteet raiteelle 1/3(clear)?
	goto 	St1_halt		;ei, op->seis
St1_drive
	movlw	St1_G_in
	call	Brighten
	movlw	St1_R_in
	call	Dimm
	goto	Sg_St2
St1_halt
	movlw	St1_G_in
	call	Dimm
	movlw	St1_R_in
	call	Brighten

Sg_St2 	;-------------------------------------------------------
	btfsc	TwinT_status	;Onko raide vapaa (clear)?
	goto	St2_halt		;ei, op->seis
	btfsc	Starter_sw	;Onko Lähtökytkin vi(clear)?
	goto 	St2_halt		;ei, op->seis

	btfss	Turnout1or3	;Onko vaihteet raiteelle 1/3(set)?
	goto 	St2_halt		;on, op->seis
	btfsc	Turnout2or3	;Onko vaihteet raiteelle 2/3(clear)?
	goto 	St2_halt		;ei, op->seis
St2_drive
	movlw	St2_G_in
	call	Brighten
	movlw	St2_R_in
	call	Dimm
	goto	Sg_St3
St2_halt
	movlw	St2_G_in
	call	Dimm
	movlw	St2_R_in
	call	Brighten

Sg_St3 	;-------------------------------------------------------
	btfsc	TwinT_status	;Onko raide vapaa (clear)?
	goto	St3_halt		;ei, op->seis
	btfsc	Starter_sw	;Onko Lähtökytkin vi(clear)?
	goto 	St3_halt		;ei, op->seis

	btfsc	Turnout1or3	;Onko vaihteet raiteelle 1/3(set)? ##
	goto 	St3_halt		;ei, op->seis
	btfsc	Turnout2or3	;Onko vaihteet raiteelle 2/3(set)? ##
	goto 	St3_halt		;ei, op->seis
St3_drive
	movlw	St3_G_in
	call	Brighten
	movlw	St3_R_in
	call	Dimm
	return
St3_halt
	movlw	St3_G_in
	call	Dimm
	movlw	St3_R_in
	call	Brighten
	return

;---------------------------------------------------------------
; Laske tulo-opastin (Tu) ja esiopastimet
;---------------------------------------------------------------
Laske_tulo_opastimet
Sg_Hm 	;-------------------------------------------------------
	btfsc	TwinT_status	;Onko raide vapaa (clear)?
	goto	Hm_halt		;ei, op->seis
	btfsc	Home_sw	;Onko Tulokytkin vi(clear)?
	goto 	Hm_halt		;ei, op->seis

Hm_drive
	movlw	Hm_G_in
	call	Brighten
	movlw	Hm_R_in
	call	Dimm
	goto	Sg_AdvSt
Hm_halt
	movlw	Hm_G_in
	call	Dimm
	movlw	Hm_R_in
	call	Brighten

Sg_AdvSt	;-------------------------------------------------------
	tstf	Hm_R_in		;Testataan tulotolpan punaista
	skpz			;Onko edes häivähdys punaista (non-zero)
	goto	AdvSt_dark	;ei, esipoastin sammutetaan
	btfss	Flasher_status	;onko eisop.Flasher päällä (set)
	goto	AdvSt_dark	;ei, esipoastin sammutetaan
	btfsc	next_Starter	;onko seurLahto Vi(clear)
	goto	AdvSt_next_halt	;ei esipoastin keltaiseksi
AdvSt_next_drive
	movlw	AdvSt_G_in
	call	Brighten
	movlw	AdvSt_Y_in
	call	Dimm
	goto	Sg_Te
AdvSt_next_halt
	movlw	AdvSt_G_in
	call	Dimm
	movlw	AdvSt_Y_in
	call	Brighten
	goto	Sg_Te
AdvSt_dark
	movlw	AdvSt_G_in
	call	Dimm
	movlw	AdvSt_Y_in
	call	Dimm

Sg_Te 	;-------------------------------------------------------
	btfss	Flasher_status	;onko eisop.Flasher päällä (set)
	goto	AdvHm_dark	;ei, esipoastin sammutetaan
	tstf	Hm_R_in		;Testataan tulotolppaa häivädys punaista?
	skpz			;Onko edes häivädys punaista? (non-zero)
	goto	Te_odota_halt	;ei, esipoastin keltaiseksi
Te_odota_drive
	movlw	AdvHm_G_in
	call	Brighten
	movlw	AdvHm_Y_in
	call	Dimm
	return
Te_odota_halt
	movlw	AdvHm_G_in
	call	Dimm
	movlw	AdvHm_Y_in
	call	Brighten
	return
AdvHm_dark
	movlw	AdvHm_G_in
	call	Dimm
	movlw	AdvHm_Y_in
	call	Dimm
	return

;---------------------------------------------------------------
; Ohjataan ulostulot lähtö-opastimille Bit 6=1
;---------------------------------------------------------------
Ulos_lahto_opastimet
	movlw	B'01111111'	;Ulostulot oletusarvoisesti ylös(pimeä)
	movwf	Ulos		;Ulostulot pimeäksi
	movlw	0x21
	movwf	PWM_Loop_Count
Out_byte1
	movlw	St1_G_out	;Aletaan portin pienimmästä bitistä
	movwf	FSR		;ja pannaan indirect-pointteriksi
	movlw	B'01111111'	;Ulostulot oletusarvoisesti ylös(pimeä)
	movwf	Out_byte	;
	movlw	.6		;kuinka monta bittiä kierretään
	movwf	Out_bit	;
	call	PWM_bit_loop	;Ja pannaan ulostulon bitit Out_byte:un
	rrf	Out_byte,f	;vikan kierron jälkeen pitää palauttaa
	bsf	Out_byte,6	;valitaan lähtöopastimet
	movfw	Out_byte	;ulostulotavu akkuun ja
	movwf	Ulos		;ja ulostuloon
	call 	Viive
	decfsz	PWM_Loop_Count,f
	goto 	Out_byte1
	movlw	B'00111111'	;Ulostulot oletusarvoisesti ylös(pimeä)
	movwf	Ulos		;odottamaan tulo-opastimia (op-ampille aikaa)
	return

;---------------------------------------------------------------
; Ohjataan ulostulot Tulo- ja esiopastimille (Bit 6=0)
;---------------------------------------------------------------
Ulos_tulo_opastimet
	movlw	B'00111111'	;Ulostulot oletusarvoisesti ylös(pimeä)
	movwf	Ulos		;Ulostulot pimeäksi
	movlw	0x21
	movwf	PWM_Loop_Count
Out_byte2
	movlw	Hm_G_out	;Aletaan portin pienimmästä bitistä
	movwf	FSR		;ja pannaan indirect-pointteriksi
	movlw	B'00111111'	;Ulostulot oletusarvoisesti ylös(pimeä)
	movwf	Out_byte	;
	movlw	.6		;kuinka monta bittiä kierretään
	movwf	Out_bit	;
	call	PWM_bit_loop	;Ja pannaan ulostulon bitit Out_byte:un
	rrf	Out_byte,f	;vikan kierron jälkeen pitää palauttaa
	bcf	Out_byte,6	;valitaan tulo-opastin ja esiopastimet
	movfw	Out_byte	;ulostulotavu akkuun ja
	movwf	Ulos		;ja ulostuloon
	call 	Viive
	decfsz	PWM_Loop_Count,f
	goto 	Out_byte2
	movlw	B'01111111'	;Ulostulot oletusarvoisesti ylös(pimeä)
	movwf	Ulos		;odottamaan lähtö-opastimia (op-ampille aikaa)
	return

;---------------------------------------------------------------
;VIIVESILMUKKA
;---------------------------------------------------------------
Viive
	movlw	0x01		;kierrosmäärä ##### oli 0xFF
	movwf 	PWM_delay	;viivesilmukka
Delay_loop
	nop
	nop
	nop
	decfsz	PWM_delay, f	;Joko loopattu riittävästi
	goto Delay_loop		;ei
	return			;joo
	
;---------------------------------------------------------------
;MAIN
;---------------------------------------------------------------
Main
	call 	Init		;aseta portit TRIS etc....
Loop
	call	Check_TwinT	;tarkista, onko junia

	call	Laske_lahto_opastimet
	call	Laske_lahto_opastimet
	call	Ulos_lahto_opastimet

	call	Laske_tulo_opastimet
	call	Laske_tulo_opastimet
	call	Ulos_tulo_opastimet

	call 	Flasher
	call	Flasher

	Goto	Loop

	END

