;************************************************************************
; 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!)
;
;       Raidekaavio      L1
;       ===========   /---<---- Raide 1
;                    /   L2 
;        ->------>--------<---- Raide 2
;        Te    Tu    \   L3 
;              Le     \---<---- Raide 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)
;		      L1Vi/TuVi PORTB.0 <-|6      13|<- PORTB.7	  Tulo
;		      L1Pu/TuPu PORTB.1 <-|7      12|-> PORTB.6	  L/!T
;		      L2Vi/LeVi PORTB.2 <-|8      11|-> PORTB.5	  L3Pu/TePu
;		      L2Pu/LePu PORTB.3 <-|9      10|-> PORTB.4	  L3Vi/TeVi
;			    	          +---------+
;
;************************ RAM *********************************************************

	CBLOCK H'0C'

		L1Vi_in		;Opastin Raide 1 Vihreä
		L1Vi_out	;Opastin Raide 1 Vihreä
		L1Pu_in		;Opastin Raide 1 Punainen
		L1Pu_out	;Opastin Raide 1 Punainen

		L2Vi_in		;Opastin Raide 2 Vihreä
		L2Vi_out	;Opastin Raide 2 Vihreä
		L2Pu_in		;Opastin Raide 2 Punainen
		L2Pu_out	;Opastin Raide 2 Punainen

		L3Vi_in		;Opastin Raide 3 Vihreä
		L3Vi_out	;Opastin Raide 3 Vihreä
		L3Pu_in		;Opastin Raide 3 Punainen
		L3Pu_out	;Opastin Raide 3 Punainen

		TuVi_in		;Tulo-opastin Vihreä
		TuVi_out	;Tulo-opastin Vihreä
		TuPu_in		;Tulo-opastin Punainen
		TuPu_out	;Tulo-opastin Punainen

		LeVi_in		;Lähtö-esiopastin Vihreä
		LeVi_out	;Lähtö-esiopastin Vihreä
		LeKe_in		;Lähtö-esiopastin keltainen
		LeKe_out	;Lähtö-esiopastin keltainen

		TeVi_in		;Tulo-esiopastin Vihreä
		TeVi_out	;Tulo-esiopastin Vihreä
		TeKe_in		;Tulo-esiopastin keltainen
		TeKe_out	;Tulo-esiopastin keltainen

		Apu		;apumuuttuja, bittietoa:
				;	0=Twin-T:n tila
				;	1=Lähtö/Tulo päällä
				;	2=Esiopastinvilkun tila
		Vilkku_ramppi	;Esiopastimen ramppi

		Ulos_tavu	;port b:n tuleva tila
		Ulos_bit	;mitä bittiä ylläolevasta säädetään
		Pwm_viive	;PWM:n venyttäjä
		Pwm_Loop_Count	;PWM-laskuri
           ENDC

	#DEFINE Tulo_Kytkin	PORTB, 7
	#DEFINE Lahto_Kytkin	PORTA, 0
	#DEFINE Seur_Lahto	PORTA, 1
	#DEFINE Vaihde1t3	PORTA, 2
	#DEFINE Vaihde2t3	PORTA, 3
	#DEFINE TwinT_in	PORTA, 4
 	#DEFINE TwinT_tila	Apu, 0
 	#DEFINE LT		Apu, 1
	#DEFINE Vilkku_tila	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!

Vilkku
	incfsz	Vilkku_ramppi,f ;kasvata vilkkuramppia, menikö ympäri
	goto 	Vilkku_paalle	;ei
Vilkku_pois
	bcf	Vilkku_tila	;kyllä, (ramppi=0) ->valo pois (clear)
	return
Vilkku_paalle
	btfsc	Vilkku_tila	;(ramppi 1..255) oliko valo pois (clear)
	return			;ei, jatketaan
	btfss	Vilkku_ramppi,7	;kyllä, onko rampin bitti 7 "1" (set)
	return			;ei    (ramppi = 0  ..127), ei muutoksia
	bsf	Vilkku_tila	;kyllä (ramppi = 128..255), valo päälle (set)
	movlw	0x0		;nolla akkuun ja 
	movwf	Vilkku_ramppi	;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	Vilkku_Ramppi	;
	return

;---------------------------------------------------------------
; KIRKASTA OPASTINLAMPPUA
;---------------------------------------------------------------
Kirkasta
	movwf	FSR		;op_in-rek w->Indirectiin
	incfsz	INDF, W		;kirkasta op_in ->w, ympäri?
	movwf	INDF		;ei, akusta op_in-rek:iin
				;
	call	Op_out		;kopioi op_in->op_out
	return

;---------------------------------------------------------------
; HIMMENNÄ OPASTINLAMPPUA
;---------------------------------------------------------------
Himmenna
	movwf	FSR		;op_in-rek w->Indirectiin
	movf	INDF, W		;kopioi akkuun,
	skpz			;oliko nolla
	decf	INDF, F		;ei, himmennä op_in-rek:iä
					;
	call	Op_out		;kopioi op_in->op_out
	return

;---------------------------------------------------------------
; OP_IN -> OP_OUT ACHTUNG: FSR pitää sis. oikean IN_rekisterin
;---------------------------------------------------------------
Op_out
	btfss	INDF, 7		;onko op_in ylätavu 1 (set)?
	goto	op_out_0	;ei ole, pidetään op_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 op_in->op_out
	andlw	0xF		;maskaa ylätavu pois
	call	Lookup		;muunna x3 -käyräksi
	movwf	INDF		;ja työnnö op_out:iin
	return
Op_out_0
	incf	FSR, f		;muut osoitus op_in->op_out
	movlw	0x0		;opastin pimeäksi
	movwf	INDF		;ja pimeä op_out:iin
	return

;-----------------------------------------------------------------------------
;Tarkista Twin-T
;-----------------------------------------------------------------------------
; jos lähtö ja tulo-opastin punaiset ->Twin-T pois
; jos juna -> Twin-T päälle
Tarkista_TwinT
	btfss	Lahto_kytkin	;onko Lahtökytkin seis (set=seis)
	goto 	Tarkista_juna	;ei, tarkista juna
	btfss	Tulo_kytkin	;onko Tulokytkin seis (set=seis)
	goto 	Tarkista_juna	;ei, tarkista juna
	bcf	TwinT_tila	;on Twin-T: ei junaa (clear)
	return
Tarkista_juna
	btfss	TwinT_in	;onko Twin-T (set=ei junaa)?
	bsf	TwinT_Tila	;on, Twin-T punaiseksi (set)
	return

;-----------------------------------------------------------------------------
;PWM-BIT-LOOP
;-----------------------------------------------------------------------------
Pwm_bit_loop
	bsf	Ulos_tavu, 0	;tämän lampun valo oletusarv. pois
	tstf	INDF		;onko tätä op_out:ia
	skpnz			;eihän vielä sammutettava (zero)?
	goto	Pwm_bit_seur	;ei vielä
	decf	INDF, f		;vähennetään
	bcf	Ulos_tavu, 0	;ja sytytetään lamppu
pwm_bit_seur
	rlf	Ulos_tavu, f
	incf	FSR, f		;indirect osoittamaan
	incf	FSR, f		;seur. op_out:iin
	decfsz	Ulos_bit, f	;joko viimeinen ulostulobitti?
	goto 	Pwm_bit_loop	;ei, takaisin
	return			;kyllä

;---------------------------------------------------------------
; Laske lähtöopastimet (L1..L3)
;---------------------------------------------------------------
Laske_lahto_opastimet
Op_L1 	;-------------------------------------------------------
	btfsc	TwinT_Tila	;Onko raide vapaa (clear)?
	goto	L1_seis		;ei, op->seis
	btfsc	Lahto_Kytkin	;Onko Lähtökytkin vi(clear)?
	goto 	L1_seis		;ei, op->seis

	btfss	Vaihde2t3	;Onko vaihteet raiteelle 2/3(set)?
	goto 	L1_seis		;on, op->seis
	btfsc	Vaihde1t3	;Onko vaihteet raiteelle 1/3(clear)?
	goto 	L1_seis		;ei, op->seis
L1_aja
	movlw	L1Vi_in
	call	Kirkasta
	movlw	L1Pu_in
	call	Himmenna
	goto	Op_L2
L1_seis
	movlw	L1Vi_in
	call	Himmenna
	movlw	L1Pu_in
	call	Kirkasta

Op_L2 	;-------------------------------------------------------
	btfsc	TwinT_Tila	;Onko raide vapaa (clear)?
	goto	L2_seis		;ei, op->seis
	btfsc	Lahto_Kytkin	;Onko Lähtökytkin vi(clear)?
	goto 	L2_seis		;ei, op->seis

	btfss	Vaihde1t3	;Onko vaihteet raiteelle 1/3(set)?
	goto 	L2_seis		;on, op->seis
	btfsc	Vaihde2t3	;Onko vaihteet raiteelle 2/3(clear)?
	goto 	L2_seis		;ei, op->seis
L2_aja
	movlw	L2Vi_in
	call	Kirkasta
	movlw	L2Pu_in
	call	Himmenna
	goto	Op_L3
L2_seis
	movlw	L2Vi_in
	call	Himmenna
	movlw	L2Pu_in
	call	Kirkasta

Op_L3 	;-------------------------------------------------------
	btfsc	TwinT_Tila	;Onko raide vapaa (clear)?
	goto	L3_seis		;ei, op->seis
	btfsc	Lahto_Kytkin	;Onko Lähtökytkin vi(clear)?
	goto 	L3_seis		;ei, op->seis

	btfss	Vaihde1t3	;Onko vaihteet raiteelle 1/3(set)?
	goto 	L3_seis		;ei, op->seis
	btfss	Vaihde2t3	;Onko vaihteet raiteelle 2/3(set)?
	goto 	L3_seis		;ei, op->seis
L3_aja
	movlw	L3Vi_in
	call	Kirkasta
	movlw	L3Pu_in
	call	Himmenna
	return
L3_seis
	movlw	L3Vi_in
	call	Himmenna
	movlw	L3Pu_in
	call	Kirkasta
	return

;---------------------------------------------------------------
; Laske tulo-opastin (Tu) ja esiopastimet
;---------------------------------------------------------------
Laske_tulo_opastimet
Op_Tu 	;-------------------------------------------------------
	btfsc	TwinT_Tila	;Onko raide vapaa (clear)?
	goto	Tu_seis		;ei, op->seis
	btfsc	Tulo_Kytkin	;Onko Tulokytkin vi(clear)?
	goto 	Tu_seis		;ei, op->seis

Tu_aja
	movlw	TuVi_in
	call	Kirkasta
	movlw	TuPu_in
	call	Himmenna
	goto	Op_Le
Tu_seis
	movlw	TuVi_in
	call	Himmenna
	movlw	TuPu_in
	call	Kirkasta

Op_Le 	;-------------------------------------------------------
	tstf	TuPu_in		;Testataan tulotolpan punaista
	skpz			;Onko edes häivähdys punaista (non-zero)
	goto	Le_pimea	;ei, esipoastin sammutetaan
	btfss	vilkku_tila	;onko eisop.vilkku päällä (set)
	goto	Le_pimea	;ei, esipoastin sammutetaan
	btfsc	Seur_Lahto	;onko seurLahto Vi(clear)
	goto	Le_odota_seis	;ei esipoastin keltaiseksi
Le_odota_aja
	movlw	LeVi_in
	call	Kirkasta
	movlw	LeKe_in
	call	Himmenna
	goto	Op_Te
Le_odota_seis
	movlw	LeVi_in
	call	Himmenna
	movlw	LeKe_in
	call	Kirkasta
	goto	Op_Te
Le_pimea
	movlw	LeVi_in
	call	Himmenna
	movlw	LeKe_in
	call	Himmenna

Op_Te 	;-------------------------------------------------------
	btfss	vilkku_tila	;onko eisop.vilkku päällä (set)
	goto	Te_pimea	;ei, esipoastin sammutetaan
	tstf	TuPu_in		;Testataan tulotolppaa häivädys punaista?
	skpz			;Onko edes häivädys punaista? (non-zero)
	goto	Te_odota_seis	;ei, esipoastin keltaiseksi
Te_odota_aja
	movlw	TeVi_in
	call	Kirkasta
	movlw	TeKe_in
	call	Himmenna
	return
Te_odota_seis
	movlw	TeVi_in
	call	Himmenna
	movlw	TeKe_in
	call	Kirkasta
	return
Te_pimea
	movlw	TeVi_in
	call	Himmenna
	movlw	TeKe_in
	call	Himmenna
	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	L1Vi_out	;Aletaan portin pienimmästä bitistä
	movwf	FSR		;ja pannaan indirect-pointteriksi
	movlw	B'01111111'	;Ulostulot oletusarvoisesti ylös(pimeä)
	movwf	Ulos_tavu	;
	movlw	.6		;kuinka monta bittiä kierretään
	movwf	Ulos_bit	;
	call	Pwm_bit_loop	;Ja pannaan ulostulon bitit Ulos_tavu:un
	rrf	Ulos_Tavu,f	;vikan kierron jälkeen pitää palauttaa
	bsf	Ulos_tavu,6	;valitaan lähtöopastimet
	movfw	Ulos_tavu	;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	TuVi_out	;Aletaan portin pienimmästä bitistä
	movwf	FSR		;ja pannaan indirect-pointteriksi
	movlw	B'00111111'	;Ulostulot oletusarvoisesti ylös(pimeä)
	movwf	Ulos_tavu	;
	movlw	.6		;kuinka monta bittiä kierretään
	movwf	Ulos_bit	;
	call	Pwm_bit_loop	;Ja pannaan ulostulon bitit Ulos_tavu:un
	rrf	Ulos_Tavu,f	;vikan kierron jälkeen pitää palauttaa
	bcf	Ulos_tavu,6	;valitaan tulo-opastin ja esiopastimet
	movfw	Ulos_tavu	;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_viive	;viivesilmukka
Viive_loop
	nop
	nop
	nop
	decfsz	pwm_viive, f	;Joko loopattu riittävästi
	goto Viive_loop		;ei
	return			;joo
	
;---------------------------------------------------------------
;MAIN
;---------------------------------------------------------------
Main
	call 	Init		;aseta portit TRIS etc....
Loop
	call	Tarkista_TwinT	;tarkista, onko junia

	call	Laske_lahto_opastimet
	call	Ulos_lahto_opastimet

	call	Laske_tulo_opastimet
	call	Ulos_tulo_opastimet

	call 	vilkku
	call	vilkku

	Goto	Loop

	END

