;************************************************************************
; Soubry Henk wrote:													*
; "Following the example of Bob Blick's original propeler clock I made 	*
; my own version of this fancy clock and have re-written the code from	*
; scratch. 																*
; This 16f628 code is for the stationary part of the clock and will 	*
; drive the primary transformer coil, and use RC5 to switch the motor	*
; on and off (and adjust the speed)"									*
;																		*
; - Rewritten fog 16F886, extended to an alarm clock:					*
;	- 28 pin controller compatible with 18F2550 controller with USB		*
;	- Alarm timing (hour and minute with day of week and hour masking)	*
;	  40 on 16F886,														*
;	- Alarm with sound and relais drive output, turn on/off propeller,	*
;	- Push button wake up/go standby, automatic standby timer,			*
;	- Wake up in Run / Sleep - Deap sleep mode,							*
;	- Infra commands to switch on/off the relais with adjustable on time*
;	- Deap sleep mode - No power on coil for propellers with RTC,		*
;	- Date, Time, Alarm data and settings stored in PCF8583 RTC,		*
;	- DCF77 time synchronization,										*
;	- Automatic time synchronization to RTC's time,						*
;	- Error led to sign time, alarm data invalid (low battery indicator)*
;	- I2C bus @ 5V for handling other devices (LCD display),			*
;	- Push button to turn on/off relais, adjustable relais on time,		*
;	- Light, Temperature, Humidity and Air pressure measurement			* 
;	   with offset conpensation,										*
;	- Extended IR command set,											*
;	- RS232 channel to connect to PC,									*
;	- Propeller's clock synchronization using IR commands,				*
;	- Doubble buffered infra RC5 receiver								*
;																		*
;	- Fixed PR2 values .49, improuved time counting using TMR2 3.09		*
;																		*
;************************************************************************
;                                                        		       	*
;    Filename:	    base_886asm                                        	*
;    Date:          20/08/2002                                        	*
#define LastUpdate	"2009-12-12";										*
;																		*
#define	VersionMajor	0x03	;										*
#define	VersionMinor	0x09	;										*
;                                                                     	*
;  Based on:                                                           	*
;    Author:        Soubry Henk                                       	*
;    Company:       Soubry Software Service                           	*
;                                                                     	*
;  Rewritten - Extended                                                	*
;                                                                     	*
;************************************************************************
;                                                                    	*
;    Files required:                                                  	*
;           keys.asm                                                	*
;                                                                     	*
;************************************************************************
;                                                                     	*
;    Notes:                                                           	*
;    	Pin assignment                                                	*
;      		Port A            								       	  	*
;				RA0 = Light measurement					Analog			*
;				RA1 = Temperature measurement			Analog		 	*
;               RA2 = Humidity measurement				Analog        	*
;               RA3 = Pressure measurement				Analog		  	*
;               RA4 = Relais push button	use 10K pullup to pic's Vdd	*
;				RA5 = Sound push button		use 10K pullup to pic's Vdd	*
;				RA6.7 = 20MHz oscillator								*
;																		*
;      		Port B														*
;				RB0 = I2C SDA line			use 2K7 pullup to pic's Vdd	*
;				RB1	= I2C SCL line			use 2K7 pullup to pic's Vdd	*
;				RB2 = Wake up push button	use 10K pullup to pic's Vdd	*
;				RB3	= DCF77 active low inp. use 10K pullup to pic's Vdd	*
;				RB4 = Motor enable output								*
;				RB5 = Buzzer output										*
;				RB6 = Relais drive output								*
;				RB7 = Error LED output									*
;																		*
;      		Port C														*
;				RC0 = Not used output / Reserved for USB power sense	*
;				RC1	= Index Infra LED drive output						*
;				RC2 = Coil drive PWM output								*
;				RC3	= Not used output / Reserved for USB power capacitor*
;				RC4 = Not used output / Reserved for USB D-				*
;				RC5 = Not used output / Reserved for USB D+				*
;				RC6 = UART transmit output								*
;				RC7 = UART receive input								*
;                                                                     	*
;      		Port E														*
;				RE3 = RC5 infra input									*
;                                                                     	*
;************************************************************************
;																		*
;  RTC Ram layout														*
;	00	01	02	03	04	05	06	07	08	09	0A	0B	0C	0D	0E	0F		*
;	cmd	.1	sec	min	hou	day	mon	Alm	Alarm registers - can be used		*
;		.01				y10	wda	mod										*
;																		*
;	10	11	12	13	14	15	16	17	18	19	1A	1B	1C	1D	1E	1F		*
;	Yea	~Y	Ccp	Pr2	Ccp Pr2	AST	AST	HS	HS	Cen	Rel	Tmp	Hum	Pre	Mode	*
;			run	run	sl	sl	H	L	beg	end		ir	off	off	off			*
;																		*
;	20	21	22	23	24	25	26	27	28	29	2A	2B	2C	2D	2E	2F		*
;	-- Alarm 0  --	-- Alarm 1  --	-- Alarm 2  --	-- Alarm 3  --		*
;	WDa	Hou	Min	Md	WDa	Hou	Min	Md	WDa	Hou	Min	Md	WDa	Hou	Min	Md		*
;																		*
;	30	31	32	33	34	35	36	37	38	39	3A	3B	3C	3D	3E	3F		*
;	-- Alarm 4  --	-- Alarm 5  --	-- Alarm 6  --	-- Alarm 7  --		*
;	WDa	Hou	Min	Md	WDa	Hou	Min	Md	WDa	Hou	Min	Md	WDa	Hou	Min	Md		*
;																		*
;	40	41	42	43	44	45	46	47	48	49	4A	4B	4C	4D	4E	4F		*
;	-- Alarm 8  --	-- Alarm 9  --	-- Alarm 10 --	-- Alarm 11 --		*
;	WDa	Hou	Min	Md	WDa	Hou	Min	Md	WDa	Hou	Min	Md	WDa	Hou	Min	Md		*
;																		*
;	50	51	52	53	54	55	56	57	58	59	5A	5B	5C	5D	5E	5F		*
;	-- Alarm 12 --	-- Alarm 13 --	-- Alarm 14 --	-- Alarm 15 --		*
;	WDa	Hou	Min	Md	WDa	Hou	Min	Md	WDa	Hou	Min	Md	WDa	Hou	Min	Md		*
;																		*
;	60	61	62	63	64	65	66	67	68	69	6A	6B	6C	6D	6E	6F		*
;	-- Alarm 16 --	-- Alarm 17 --	-- Alarm 18 --	-- Alarm 19 --		*
;	WDa	Hou	Min	Md	WDa	Hou	Min	Md	WDa	Hou	Min	Md	WDa	Hou	Min	Md		*
;																		*
;	70	71	72	73	74	75	76	77	78	79	7A	7B	7C	7D	7E	7F		*
;	-- Alarm 20 --	-- Alarm 21 --	-- Alarm 22 --	-- Alarm 23 --		*
;	WDa	Hou	Min	Md	WDa	Hou	Min	Md	WDa	Hou	Min	Md	WDa	Hou	Min	Md		*
;																		*
;	80	81	82	83	84	85	86	87	88	89	8A	8B	8C	8D	8E	8F		*
;	-- Alarm 24 --	-- Alarm 25 --	-- Alarm 26 --	-- Alarm 27 --		*
;	WDa	Hou	Min	Md	WDa	Hou	Min	Md	WDa	Hou	Min	Md	WDa	Hou	Min	Md		*
;																		*
;	90	91	92	93	94	95	96	97	98	99	9A	9B	9C	9D	9E	9F		*
;	-- Alarm 28 --	-- Alarm 29 --	-- Alarm 30 --	-- Alarm 31 --		*
;	WDa	Hou	Min	Md	WDa	Hou	Min	Md	WDa	Hou	Min	Md	WDa	Hou	Min	Md		*
;																		*
;	A0	A1	A2	A3	A4	A5	A6	A7	A8	A9	AA	AB	AC	AD	AE	AF		*
;	-- Alarm 32 --	-- Alarm 33 --	-- Alarm 34 --	-- Alarm 35 --		*
;	WDa	Hou	Min	Md	WDa	Hou	Min	Md	WDa	Hou	Min	Md	WDa	Hou	Min	Md		*
;																		*
;	B0	B1	B2	B3	B4	B5	B6	B7	B8	B9	BA	BB	BC	BD	BE	BF		*
;	-- Alarm 36 --	-- Alarm 37 --	-- Alarm 38 --	-- Alarm 39 --		*
;	WDa	Hou	Min	Md	WDa	Hou	Min	Md	WDa	Hou	Min	Md	WDa	Hou	Min	Md		*
;																		*
;	C0	C1	C2	C3	C4	C5	C6	C7	C8	C9	CA	CB	CC	CD	CE	CF		*
;																		*
;	D0	D1	D2	D3	D4	D5	D6	D7	D8	D9	DA	DB	DC	DD	DE	DF		*
;																		*
;	E0	E1	E2	E3	E4	E5	E6	E7	E8	E9	EA	EB	EC	ED	EE	EF		*
;																		*
;	F0	F1	F2	F3	F4	F5	F6	F7	F8	F9	FA	FB	FC	FD	FE	FF		*
;																		*
;************************************************************************
;	Ir Remote control keys												*
;																		*
;	See keys.asm														*
;																		*
;************************************************************************

; Disabling error messages
	errorlevel -302			; Disable "Register in operand not in bank 0"
	errorlevel -306			; Disable "Crossing page boundary"


	ifdef	__16F886
		list	p=16f886			  ; 16F886 can be used
		#include <p16f886.inc>		  ; processor specific variable definitions
#define ProcType	"16F886"
EEPROM_SIZE	EQU	256
	endif

	ifndef	EEPROM_SIZE
		error	"Incompatible processor type selected"
	endif

	#include "keys.asm"

	ifdef __16F886
	__CONFIG _CONFIG1, _CP_OFF &_CPD_OFF & _WDT_OFF & _BOR_ON & _PWRTE_ON & _HS_OSC & _LVP_OFF & _IESO_OFF & _FCMEN_OFF & _MCLRE_OFF
	__CONFIG _CONFIG2, _WRT_OFF & _BOR40V
	endif

	__idlocs		0xB000 | (VersionMajor << 8) | (VersionMinor)


#define RC5AddrCheck			; Comment this line if RC5 Address checking not required

; Default mode settings at first power up
#define	AutoStandby					; Comment this line to disable auto standby
;#define	WakeUpRun				; Comment this line if wake up in sleep mode
#define	DeapSleeping				; Comment this line if coil has to be powered in sleep mode
;#define	TimeReInit				; Comment this line not to reinit time from RTC at midnight
;#define	EnableHourSign			; Comment this line to disable sound at hour change
;#define	SignMode				; Comment this line to disable as many beeps as hour (1..12)
;#define	PropSyncEnabled			; Comment this line to disable propeller time synchronization
#define	DCF77Enabled				; Comment this line to disable DCF77 synchronization

; Serial port Baud rate selection
;BaudRate	EQU	.2400			; Set the BaudRate of RS232 communication
;BaudRate	EQU	.4800			; Set the BaudRate of RS232 communication
BaudRate	EQU	.9600			; Set the BaudRate of RS232 communication
;BaudRate	EQU	.19200			; Set the BaudRate of RS232 communication
;BaudRate	EQU	.38400			; Set the BaudRate of RS232 communication

#define	RTC_ADDR		0xA0	; RTC's address with A0 pin grounded

#define	RTC_Control		0x00	; Control register
#define RTC_Tenms		0x01	; Address of 1/100 Seconds
;#define	RTC_Second	0x02	; Address of Second		- Sequential read/write, Constants not used
;#define	RTC_Minute	0x03	; Address of Minute
;#define	RTC_Hour	0x04	; Address of Hour     / AM-PM flag and mode
;#define	RTC_Day		0x05	; Address of Day      / 2 lsb of Year
;#define	RTC_Month	0x06	; Address of Week day / Month
;#define 	RTC_Timer	0x07	; Address of Timer controll register - Not used, timer disabled

								; RTC's alarm functions not used, data can be store in locations 0x08..0x0F
;						0x08	;
;						0x09	;
;						0x0B	;
;						0x0D	;
;						0x0E	;
;						0x0F	;

#define RTC_Year        0x10    ; Address of Year
#define RTC_YearNeg     0x11    ; Address of negated value of Year
#define	RTC_PWMData		0x12	; Address of PWM data
#define	RTC_AST			0x16	; Address of AutoStandbyTimer
#define	RTC_HourSnd		0x18	; Address of hour sound parameters
#define RTC_Century		0x1A	; Address of century
#define RTC_RelOnIr		0x1B	; Address of Relais on time for ir commands
#define	RTC_TempOffset	0x1C	; Address of temperature offset
;#define RTC_HumOffs	0x1D	; Address of humidity offset
;#define RTC_PresOffs	0x1E	; Address of pressure offset
#define	RTC_Mode		0x1F	; Address of mode
#define	RTC_AlarmData	0x20	; Address of alarm data (.40*4 bytes)


#define	PIC_ADDR		0x40	; PIC12F629's address
#define	PIC_Command		0x20	; Command register address

; Time setting commands for propeller clock

;        tg6543210
;  Addr  0 0mmmmmm : minute             setting
;  Addr  0 10hhhhh : hour               setting
;  Addr  0 11DDDDD : day                setting
;  Addr  1 000MMMM : month              setting
;  Addr  1 001yyyy : year low  nibble   setting
;  Addr  1 010YYYY : year high nibble   setting
;  Addr  1 011ffgg : flags setting
;							ff: flags4
;							gg: flags5
;  Addr  1 1uuffff : flags setting
;							uu:00 flags  low
;							uu:01 flags  high
;							uu:00 flags3 low
;							uu:01 flags3 high

; PWM settings for Sleep mode
;PR2Sleep	EQU	0x3D
CCPR1LSleep	EQU	0x0C

; PWM settings for Run mode
;PR2RUN		EQU	0x3D
CCPR1LRUN	EQU	0x28


F_OSC	EQU	.20000000			; Oscillator frequency in Hz
OSC		EQU	F_OSC/4

	ifndef BaudRate
		error "No BaudRate defined"
	endif
	if ( (BaudRate!=.2400) && (BaudRate!=.4800) && (BaudRate!=.9600) && (BaudRate!=.19200) && (BaudRate!=.38400) )
		error "Nonstandard BaudRate defined"
	endif

;***** VARIABLE DEFINITIONS

;Vars in shared memory. This memory is available from any bank

  cblock	0x070
	Scratch			; memory locations for general use
	Scratch2		;
	Scratch3		; Alarm index
	Scratch4
	BCD				; BCD routine temp var, I2C delay counter

	I2CSlaveAdr		; I2C slave address of current device
	I2CWordAdr		; I2C word  address of current transfer
	I2CBitCnt		; I2C bit   counter of data in/out routines
	I2CShiftReg		; I2C data  shift register

	flags			; State flags
	Mode			; Mode

; 1 more locations

	pclath_temp		; variable used for context saving

	w_temp			; variable used for context saving
	status_temp		; variable used for context saving
	fsr_temp		; variable used for context saving
  endc
	IF fsr_temp > 0x7F
		ERROR "To many variables used in Common RAM"
	ENDIF

  cblock	0x20
;Vars for time-keeping
  ;!! Keep variable order - Timecheck use indirect access to them v
	Second2			; 0..119 counting half seconds
	Minute			; 0.. 59
	Hour			; 0.. 23
	Day				; 1.. Dmon-1
	Month			; 1.. 12
	Year			; 0.. 99
	Century			; 0.. 99
  ;!! Keep variable order - Timecheck use indirect access to them ^

	DMon			; days in current Month + 1
	WDay			; Day of week 0..6

	SubSec_L		; Sub second timer
	SubSec_H

	SleepTimer		; Down counter in second, started at standby.

	StandbyTimerL	; Down counter for auto standby
	StandbyTimerH	;

	SoundCnt		; Down counter for alarm sound generation
	SwitchCnt		; Down counter for relais drive

	AutoStbyTimL	; Auto Standby time in seconds
	AutoStbyTimH	;

	PR2_Sleep		; PWM frequency for sleep mode
	PR2_Run			; PWM frequency for run   mode

	CCP1_Sleep		; PWM pulse width for sleep mode
	CCP1_Run		; PWM pulse width for run   mode

	RC5_flags		; RC5 decoding state flags
	RC5_Tmr			; RC5 time counter
	RC5_BitCnt		; RC5 decoders bit counter
	RC5_Addr		; Address field of RC5 message just received
	RC5_Cmd			; Command field of RC5 message just received
	RC5_Cmd2		; storage for previous cmd
	RC5_ShrA
	RC5_ShrC

	UartRxChNum		; Uart Rx fifo number of avaible chars
	UartRxChWp		; Uart Rx fifo write pointer
	UartRxChRp		; Uart Rx fifo read  pointer

	UartTxChNum		; Uart Tx fifo number of avaible chars
	UartTxChWp		; Uart Tx fifo write pointer
	UartTxChRp		; Uart Tx fifo read  pointer

	Rs232Cmd		; Last command code received from uart
	Rs232ParNum		; Number of paraneters of command
	Rs232Flags		; Command decoding state flags

	Rs232StrPtr		; 16 bit pointer to string to be sent
	Rs232StrPtrH
	Rs232Temp		; Temporary storage in UART routines
	Rs232Temp2		; Temporary storage in UART routines
	Rs232Fsr		; Save for FSR in UART routines
	Rs232Status		; Save for STATUS in UART routines

	PicFifoChNum	; Pic12F629 fifo number of avaible chars
	PicFifoWp		; Pic12F629 fifo write pointer
	PicFifoRp		; Pic12F629 fifo read  pointer

	HourSndBeg		;
	HourSndEnd

	RelOnIr			; Relais on time for ir and push button commands (minute)
	TempOffset
	HumidityOffset
	PressureOffset

	Light			; Light
	Humidity		; Humidity [%]
	Pressure		; Air pressure (Air Pressure [hPa] = (0x200 + Pressure) * 1.25 + 110
	Temperature		; Temperature [°C]

; DCF77 decoding
	DCF_bitcntr		; Bit counter 0 .. 59
	DCF_timer		; Timer using 10 ms time base
	DCF_flags		; DCF77 decoding sate flags
	DCF_20ms_cnt	; Counts 200uS interrupts to generate 20 ms time base - Power line nois reduction
	DCF_temp		; A variable for filtering
	DCF_SNum		; Number of succesfull synchronizations

; DCF77 decoding - Time	BCD encoding used
  ;!! Keep variable order - indirect access used to them v
	DCF_Minute		; 0 .. 59
	DCF_Hour		; 0 .. 23
	DCF_Day			; 1 .. 31
	DCF_Month		; Bit 7..3: Month	1 .. 12, bit 2..0: Wday 1..7
	DCF_Year		; 0 .. 99
  ;!! Keep variable order - indirect access used to them ^

	WuBtCnt			; Button counter for Wake Up/Go Sleep
	RyBtCnt			; Button counter for relais On/Off

	T2PostCnt		; TMR2 post counter - PWM uses 40 uS - Time counting requires 200uS 

; 10 more locations
	LastMinute		; Last minute processed by AlarmCheck
  endc
	IF LastMinute >= 0x70
		ERROR "To many variables used in Bank0"
	ENDIF

;Vars indirectly accessed are on Bank1
  cblock	0x0A0	; Alarm table - Indirectly accessed
	Alarm0WDay		; Bits 7: Global enable, 6..0: Enable on Day of week 7..1
	Alarm0Hour		; 0..23 or 32 for don't care, Bit 7,6 not used
	Alarm0Minute	; 0..59	; Bit 7,6 not used
	Alarm0Mode		; Bit 7: 0 - Alarm:
							; Bit 6: turn propeller on
							; Bit 5: turn propeller off
							; Bit 4: Enable sound
					; Bit 7: 1 - Relais switched on:
							; Bit 6..0: turn on time in minutes

	Alarm1:4
	Alarm2:4
	Alarm3:4
	Alarm4:4
	Alarm5:4
	Alarm6:4
	Alarm7:4
	Alarm8:4
	Alarm9:4
	Alarm10:4
	Alarm11:4
	Alarm12:4
	Alarm13:4
	Alarm14:4
	Alarm15:4
	Alarm16:4
	Alarm17:4
	Alarm18:4
	Alarm19:4

; No more locations
	; Not to use memory 0x0F0..0x0FF  -  it will overwrite 0x070..0x07F
  endc
	IF  Alarm19+3 >= 0xF0
		ERROR "To many variables used in Bank1"
	ENDIF

  cblock	0x110
					; More RAM space avaible: 16 for 16F886
  endc

  cblock	0x120	; Uart buffers
					; More RAM space avaible: 80 for 16F886
	PicFifo:	.32	; Fifo for PIC16F629 

	UartTxChar:	.32	; Uart Tx fifo

	UartRxChar:	.16	; Uart Rx fifo

; No more locations

 	; Not to use memory 0x170..0x17F  -  it will overwrite 0x070..0x07F
  endc

	IF  UartRxChar+.15 >= 0x170
		ERROR "To many variables used in Bank2"
	ENDIF

  cblock	0x190
					; More RAM space avaible: 16 for 16F886
  endc

;Vars indirectly accessed are on Bank3
  cblock	0x1A0	; Alarm table - Indirectly accessed
	Alarm20:4
	Alarm21:4
	Alarm22:4
	Alarm23:4
	Alarm24:4
	Alarm25:4
	Alarm26:4
	Alarm27:4
	Alarm28:4
	Alarm29:4
	Alarm30:4
	Alarm31:4
	Alarm32:4
	Alarm33:4
	Alarm34:4
	Alarm35:4
	Alarm36:4
	Alarm37:4
	Alarm38:4
	Alarm39:4

; No more locations
	; Not to use memory 0x1F0..0x1FF  -  it will overwrite 0x070..0x07F
  endc
	IF  Alarm39+3 >= 0x1F0
		ERROR "To many variables used in Bank3"
	ENDIF

;**********************************************************************
; Give meaningfull names to locations

; Common

; for the 16bit/8bit divide routine
DIV_HI			EQU		Scratch ; 16 bit Divident
DIV_LO			EQU		Scratch2; needed for 16 bit / 8 bit division
DIV_Q			EQU		Scratch3; Quotient
DIVISOR			EQU		Scratch4; Divisor

AD_state		EQU		CCPR2L	; A/D delay state
COPYB			EQU		CCPR2H	; Copy of PORTB

;**********************************************************************

; PORTA bits
;			EQU	0				; Light 	  measurement analogue channel
;			EQU	1				; Temperature measurement analogue channel
;			EQU	2				; Humidity	  measurement analogue channel
;			EQU	3				; Pressure	  measurement analogue channel
bRelButton	EQU	4				; Relais controll push button
bAlarmRes	EQU	5				; Alarm sound off push button
;			6..7				; Used for oscillator

; PORTB bits
bSDA		EQU	0				; I2C SDA line
bSCL		EQU	1				; I2C SCL line
bButton		EQU	2				; Power up push button
bDCF77inp	EQU	3				; DCF77 receiver input
bMotorOFF	EQU	4				; Motor controll output
bSoundOut	EQU	5				; Buzzer output
bRelais		EQU	6				; Relais drive output
bLED		EQU	7				; Error LED output

; PortC
bUSBPower	EQU	0				; USB power detect
bIndexLed	EQU	1				; Index LED output
bTrafo		EQU	2				; PWM controll of coil
bUSBCap		EQU	3				; USB filter
bUSBDN		EQU	4				; USB D-
bUSBDP		EQU	5				; USB D+
bTxD		EQU	6				; UART's TxD line
bRxD		EQU	7				; UART's RxD line

; PortE
bRC5inp		EQU	3				; IR receiver's output


; Flags
bStandBy	EQU	0				; Standby mode
bSleeping	EQU	1				; Sleep mode
bCoilPower	EQU	2				; High power on coil
bIndexOn	EQU	3				; Index LED on
bWuBtDown	EQU	4				; Wake up/ Go sleep button down - stabilized
bRyBtDown	EQU	5				; Relais On/ Off button down - stabilized
bNewTime	EQU	6				; Check the time
bTimeInv	EQU	7				; Time invalid

; RC5_flags
bRC5_WaitStart	EQU	0
bRC5_DataReady	EQU	1
bRC5_Idle		EQU	2
bRC5_prev_inp	EQU	bRC5inp		; Has to be on the same bit position as bRC5inp
bRC5_HalfBit	EQU	4
;				EQU	5
bRC5_ReSynced	EQU	6
;				EQU	7

; RS232Flags
bCmdExec		EQU	7			; Execution of a command is in progress
bTimeSet		EQU 6			; A date/time setting command was received

; Mode bits
bAutoStby		EQU	0			; Auto standby timer enable
bWakeRun		EQU	1			; Wake Run afther power up
bDeapSleep		EQU	2			; No coil drive in standby mode
bHourSign		EQU	3			; Sound at hour change
bHourSignMode	EQU	4			; Hour sign mode (One sound / as many as hour (1..12))
bPropTimSync	EQU	5			; Send time synchron ir messages to propeller
bDCFEnabled		EQU	6			; DCF77 synchronization enabled
bReinitTime		EQU	7			; Enable reinit time from RTC

; DCF77_Flags
bDCFParity		EQU		0		; Bit for calculating even parity
bDCFError		EQU		1		; Error in decoding
bDCFParityErr	EQU		2		; Parity error
bDCFBit			EQU		bDCF77inp; Last level read, has to be on same bit as on PORT
bDCFWaitSync	EQU		4		; Wait for DCF77 minute synchron
bDCFReady		EQU		5		; DCF time and date ready and valid
bDCFSummerTime	EQU		6		; CEST time used / Summer Daylight saving time
bDCFData		EQU		7		; Decoded data bit, rlf used to shift to C

;**********************************************************************
; PORTB

#define		SCL			PORTB,bSCL
#define		SDA			PORTB,bSDA

; RC5_flags
#define		RC5_WaitStart	RC5_flags,bRC5_WaitStart
#define		RC5_DataReady	RC5_flags,bRC5_DataReady
#define		RC5_prev_inp	RC5_flags,bRC5inp		; Has to be on the same bit position as bRC5inp
#define		RC5_Idle		RC5_flags,bRC5_Idle
#define		RC5_HalfBit		RC5_flags,bRC5_HalfBit
;							RC5_flags,5
#define		RC5_ReSynced	RC5_flags,bRC5_ReSynced
;							RC5_flags,7

; flags
#define 	StandBy		flags,bStandBy
#define		Sleeping	flags,bSleeping
#define		CoilPower	flags,bCoilPower
#define		IndexOn		flags,bIndexOn
#define		NewTime		flags,bNewTime
#define		TimeInv		flags,bTimeInv

; Mode
#define		AutoStby	Mode,bAutoStby
#define		WakeRun		Mode,bWakeRun
#define		DeapSleep	Mode,bDeapSleep
#define		HourSign	Mode,bHourSign
#define		HourSignMode	Mode,bHourSignMode
#define		ReinitTime	Mode,bReinitTime

;******************************************************************************
;	Define macro's for a Select - Case
;******************************************************************************
select_w	macro
sel_last	set 0                     ;setup variable only
         	endm
case     	macro   val
	        xorlw   val ^ sel_last
			btfsc	STATUS,Z
sel_last set val
         	endm

;**********************************************************************
		org     0x0000           	; processor reset vector
		movlw	(1<<bLED) | (1<<bMotorOFF);Turn off error led, motor
		movwf	PORTB				;
		movwf	COPYB
		goto    main            	; go to beginning of program

;**********************************************************************
		org     0x0004           	; interrupt vector location

		movwf	w_temp				; context saveing
		swapf	w_temp, f			; Save W to common RAM
		swapf	STATUS, w			; Get STATUS
		clrf 	STATUS				; select Bank0, IRP=0 for interrupt stuff
		movwf	status_temp			; Save STATUS
		movf	FSR,w				; Save FSR
		movwf	fsr_temp
		movf	PCLATH,w			; Needed only if more Pages used not only Page0
		movwf	pclath_temp
		clrf	PCLATH

;--------
;;INT_TMR0
;;
;;		btfss	INTCON,T0IF			; Test if a TMR0 interrupt occured
;;		goto	lTMR0EXIT
;;									; do the TMR0 stuff, we get here every 200uSec
;;
;;									; do the stuff, we get here every 200uSec
;;		movlw	.4					; Write to TMR0 disables it's increment for 2 cycles
;;		addwf	TMR0,f
;;		nop
;;		movlw	.4
;;		addwf	TMR0,f

INT_TMR2
		btfss	PIR1,TMR2IF			; Interrupt on TMR2? PWM uses 40uS period
		goto	INT_RB				; nope, goto RB port change interrupt

		decfsz	T2PostCnt,f
		goto	lTMR2EXIT
		movlw	.5
		movwf	T2PostCnt			; We get here every 200uSec

		btfsc	Second2,0			; Chopp alarm sound output
		goto	OffSound

;;
		movf	SoundCnt,f			; Counter == 0 ?
		btfsc	STATUS,Z
		goto	OffSound			; Yes - Turn off sound

		bsf		COPYB,bSoundOut		; Turn on sound output
		goto	UpdateSound

OffSound
		bcf		COPYB,bSoundOut		; Turn off sound output
UpdateSound
		call	ToPortB

CountSubSec

		incfsz	SubSec_L,f			; Increment 16-bit Sub Second counter
		goto	lTime_1				; stil counting
		incfsz	SubSec_H,f			;
		goto	lTime_1				; stil counting

		call	InitSubSecCnt

		incf	Second2,f			; Move time
		bsf		NewTime				; Sign new time for TimeCheck

		movlw	1<<bLED				; Toggle visible led if time read from RTC invalid
		btfsc	TimeInv
		call	XorToPortB
		btfsc	TimeInv				; If time valid
		goto	TestSec
		bsf		COPYB,bLED			; Turn off visible led
		call	ToPortB

TestSec
		btfsc	Second2,0			; Second passed
		goto	lTime_1

		movf	SoundCnt,f			; If SoundCnt != 0
		btfsc	STATUS,Z
		goto	lChkStby

		decf	SoundCnt,f			; Decrement sound counter

lChkStby
		btfss	StandBy				; In standby?
		goto	lTime_2				; no, count down StandbyTimer
		movf	SleepTimer,f		;
		btfsc	STATUS,Z			; SleepTimer = 0 ?
		goto	lTime_1				; yes, stop countdown
		decf	SleepTimer,f		; count down sleeptimer in seconds steps
		goto	lTime_1

lTime_2
		movf	StandbyTimerL,w		; If 16 bit StandbyTimer != 0
		iorwf	StandbyTimerH,w
		btfsc	STATUS,Z
		goto	lTime_1

		decf	StandbyTimerL,f		; Decrement it
		incf	StandbyTimerL,w
		btfss	STATUS,Z
		goto	lTime_1
		decf	StandbyTimerH,f

lTime_1
		movf	AD_state,f			; Decrement A/D state counter
		btfss	STATUS,Z
		decf	AD_state,f

; RC5 InfraRed Command Packet
;
;		Packet length: 24.899 ms, repeation time min.: 113.792 ms
;
;		Bit 1: 889uS - no pulses - TSOP output high, 889us - 32 pulses - TSOP output low
;		Bit 0: 889uS - 32 pulses - TSOP output low , 889us - no pulses - TSOP output high
;
;		 S  s   T   A4  A3  A2  A1  A0  C5  C4  C3  C2  C1  C0
;		|1 |s  |tg |a4 |a3 |a2 |a1 |a0 |c5 |c4 |c3 |c2 |c1 |c0 |
;
;		RC5  version s: second start bit		  : 1
;		RC5X version s: inverted bit 6 of command : !c6
;
;		tg: toggle bit: receving the same bit for repeated packet
;						receving opposite bit for a new command

lRC5_1								; start RC5 stuff here
		btfsc	RC5_DataReady
		goto	lRC5_Exit
		btfss	RC5_Idle
		goto	lRC5_Not_Idle		;
		decfsz	RC5_Tmr,f			;
		goto	lRC5_Exit			;
		btfsc	PORTE,bRC5inp		; test input
		bcf		RC5_Idle			; input = high, cancel Idle state
		incf	RC5_Tmr,f			; continue Idle state until input = high
		goto	lRC5_Exit			;

lRC5_Not_Idle
		btfss	RC5_WaitStart		;
		goto	lRC5_ReSync			;

lRC5WaitStart
		btfsc	PORTE,bRC5inp		; test input
		goto	lRC5_Exit			; no startbit
		bcf		RC5_WaitStart		; start received
		movlw	.13					; 13 bits to receive
		movwf	RC5_BitCnt			;
		clrf 	RC5_ShrA			;
		clrf	RC5_ShrC			;
		movlw	.6					;
		goto	lRC5_Reload			;

lRC5_ReSync							;
		movf	PORTE,w				;
		xorwf	RC5_flags,w			;
		andlw	1<<bRC5inp			;
		btfsc	STATUS,Z			;
		goto	lRC5_no_sync		;
		bsf		RC5_ReSynced		;
		xorwf	RC5_flags,f			; Save new input in RC5_flags
		movlw	.6					; re-sync the timer
		btfss	RC5_HalfBit			;
		movlw	.2					;
		movwf	RC5_Tmr				;

lRC5_no_sync
		btfsc	RC5_HalfBit			;
		goto	lRC5_2nd_Half		;

lRC5_1st_Half
		decfsz	RC5_Tmr,f			;
		goto	lRC5_Exit			;
		bcf		STATUS,C			;
		btfsc	PORTE,bRC5inp		;
		bsf		STATUS,C			; C = RC5inp
		rlf		RC5_ShrC,f			;
		rlf		RC5_ShrA,f			;
		bsf		RC5_HalfBit			; indicate that the first half bit is received
		bcf		RC5_ReSynced		;
		movlw	.4					;
		goto	lRC5_Reload

lRC5_2nd_Half
		btfsc	RC5_ReSynced		;
		goto	lReSyncOK			;
		decfsz	RC5_Tmr,f			;
		goto	lRC5_Exit			;

lRC5_Error
		movf	RC5_flags,w
		andlw	(1<<7) | (1<<5) | (1<<bRC5_DataReady)
		iorlw	(1<<bRC5_WaitStart) | (1<<bRC5_Idle)
		movwf	RC5_flags
		movlw	.128				;
lRC5_Reload
		movwf	RC5_Tmr				;
		goto	lRC5_Exit			;

lReSyncOK							; test second bit half
		bcf		RC5_HalfBit			;
		decfsz	RC5_BitCnt,f		;
		goto	lRC5_Exit			;
		rlf		RC5_ShrC,f			; Shift left to complete Addr
		rlf		RC5_ShrA,f			;
		rlf		RC5_ShrC,w			; RC5_Cmd remains unchanged
		rlf		RC5_ShrA,f			; Complete address
		bcf		RC5_ShrC,7			;
		btfss	RC5_ShrA,6			;
		bsf		RC5_ShrC,7			; Bit 7 of RC5_Cmd = Inv Bit6 in RC5_Addr
									; RC5_Addr and RC5_Cmd was cleared and shifted left 13+2 times, so C = 0
		btfsc	RC5_ShrA,5			;
		bsf		STATUS,C			; C = ToggleBit
		rrf		RC5_ShrC,w			; ToggleBit in bit 7 of RC5_Cmd
		movwf	RC5_Cmd
		movf	RC5_ShrA,w
		andlw	0x1F
		movwf	RC5_Addr
		bsf		RC5_DataReady		; Only lower 5 bits of RC5_Addr are valid

lRC5_Exit

lDCF77								; DCF77 decoding stuff
		movf	PORTB,w				; Digital filter of PORTB bit
		movwf	FSR

		btfss	FSR,bDCF77inp
		decf	DCF_temp,f
		btfsc	FSR,bDCF77inp
		incf	DCF_temp,f

		decfsz	DCF_20ms_cnt,f		; Time base for DCF77 decode
		goto	lTMR2EXIT
		movlw	.100				; .100 * .200 uS = .20 ms
		movwf	DCF_20ms_cnt

		btfsc	Mode,bDCFEnabled	; If disabled don't do anything
		call	lDCF77Dec			; DCF77 bitstream decoding

;;lTMR0EXIT
;;		bcf		INTCON,T0IF			; clear TMR0 interrupt flag before return

lTMR2EXIT
		bcf		PIR1,TMR2IF			; Clear TMR2 interrupt flag

;--------
INT_RB
;		btfss	INTCON,RBIF			; Test if a port change interrupt occured
;		goto	INT_UART			; nope, Int_Uart

;		bcf		INTCON,RBIF			; clear RB port change interrupt flag

;--------
INT_UART

		bsf		STATUS,IRP			; Buffers are on Bank2

		btfss	PIR1,RCIF			; Is it a receive interrupt
		goto	INT_UART_TX

		movf	UartRxChWp,w		; Put receive char to buffer if no error
		movwf	FSR
		movf	RCSTA,w				; Check for error
		andlw	(1<<FERR) | (1<<OERR)
		btfss	STATUS,Z
		goto	UART_ERR			; If error not to read char
		movf	RCREG,w				; Read character
		movwf	INDF				; Write it to buffer
		incf	FSR,w				; Move pointer in circular way
		andlw	0x0F
		iorlw	low(UartRxChar)
		movwf	UartRxChWp
		incf	UartRxChNum,f		; Sign one more char in buffer
		goto	INT_UART_TX

UART_ERR							; Receive error, reenable receive
		movf	RCREG,w				; Clear receive interrupt flag, drop character
		bcf		RCSTA,CREN			; Turn off receiver
		nop
		bsf		RCSTA,CREN			; Turn on  receiver

INT_UART_TX							; Is it a transmit interrupt
		btfss	PIR1,TXIF
		goto	INT_UART_EX

		movf	UartTxChNum,f		; Get next char from buffer if there is one
		btfsc	STATUS,Z
		goto	INT_TX_NOCHAR		; No more chars in buffer

		movf	UartTxChRp,w		; Get pointer to buffer
		movwf	FSR
		movf	INDF,w				; Get character from buffer
		movwf	TXREG				; Send it
		incf	FSR,w				; Move pointer
		andlw	0x1F				; in circular way
		iorlw	low(UartTxChar)
		movwf	UartTxChRp
		decfsz	UartTxChNum,f		; Sign one char read from buffer
		goto	INT_UART_EX			; Skip disabling transmit interrupt if more chars in buffer

INT_TX_NOCHAR						; No more chars to transmit
		bsf 	STATUS,RP0
		bcf		PIE1,TXIE			; Disable transmit int

INT_UART_EX
		clrf	STATUS				; Bank0, IRP=0

;--------
INT_EXIT
		movf	pclath_temp,w
		movwf	PCLATH				; Needed only in more Pages used not only Page0
		movf	fsr_temp,w			; Restore FSR
		movwf	FSR
		swapf	status_temp,w		; Restore context for main program
		movwf	STATUS				; This will also restore bank selection and IRP
		swapf	w_temp,w			; Restore W from common RAM
		retfie                  	; Return from interrupt

;**********************************************************************

div16X8Divisor100					; Divide by .100
		movlw	.100

div16X8Divisor						; Store divisor
		movwf	DIVISOR

div16X8								; DIV_HI and DIV_LO / DIVISOR.  result to DIV_Q
									; remainder in DIV_LO
									; does not deal with divide by 0 case
		clrf	DIV_Q
div_1
		movf	DIVISOR, W
		subwf	DIV_LO, F
		btfsc	STATUS, C			; If negative skip
		goto	div_2
div_borrow
		movlw	.1
		subwf	DIV_HI, F			; DIV_HI = DIV_HI - 1
		btfss	STATUS, C			; If no borrow occurred
		goto	div_done
div_2
		incf	DIV_Q, F
		goto	div_1
div_done
		movf	DIVISOR, W			; Re-add DIVISOR to DIV_LO to get
		addwf	DIV_LO, W			; remainder in DIV_LO
		movwf	DIV_HI				; Shift remainder to DIV_HI
		movf	DIV_Q,w				; Return with quotient in w
		return

;******************************************************************************
;	Check correct progress of sec, min, hour, day, day of week, month, year

TimeCheck
		movlw	Second2
		movwf	FSR
									; FSR -> Second2
		movlw	.120				; Check for second overflow
		call	CheckAndIncNext
									; FSR -> Minute
		movlw	.60					; Check for minute overflow
		call	CheckAndIncNext
									; FSR -> Hour
		movlw	.24					; Check for hour overflow
		call	CheckAndIncNext
									; FSR -> Day

		movlw	.32					; DMon = 32
		movwf	DMon
		movf	Month,w				;
		movwf	Scratch				; For months <8 odd  months have 31 days
		btfsc	Month,3
		incf	Scratch,f			; For months >7 even months have 31 days
		btfss	Scratch,0
		decf	DMon,f
		xorlw	.2					; Month = February ?
		btfss	STATUS,Z			;
		goto	lNotFeb2			; continue
		decf	DMon,f				; February has max 29 days
		movf	Year,w
		btfsc	STATUS,Z			; Year == 0 check Century instead
		movf	Century,w
		andlw	0x03
		btfss	STATUS,Z
		decf	DMon,f				; Year is not a LeapYear, dec DMon for Feb

lNotFeb2
		movf	DMon,w
		call	CheckAndIncNext		; Check for day overflow
		btfsc	STATUS,C        	; if day cleared, correct day
		incf	Day,f
									; FSR -> Month
		movlw	.13					; Check for month overflow
		call	CheckAndIncNext
		btfsc	STATUS,C 	    	; if month cleared, correct month
		incf	Month,f
									; FSR -> Year
		movlw	.100				;
		call	CheckAndIncNext
									; FSR -> Century
		movlw	.100				;
		subwf	Century,w			; Century < 100 ?
		btfsc	STATUS,C			;
		clrf	Century				;

		bcf		NewTime				; Clear new time flag
		btfss	Rs232Flags,bTimeSet	; If time was set by uart command
		return
		bcf		Rs232Flags,bTimeSet	; Clear time set flag
		goto	StoreTime			; Write new time and date to RTC

CheckAndIncNext
		subwf	INDF,w				; test INDF value to w
		btfsc	STATUS,C    	    ; if INDF < w then c=0 (borrow)
		movwf	INDF				; Reset value
		incf	FSR,f				; Move to next unit
		btfsc	STATUS,C    	    ; If reseted, increment next unit
		incf	INDF,f
		return						; C = 1, if carry was to next unit

;******************************************************************************
;	Check for Alarm conditions

AlarmCheck
		clrf	Scratch				; Get mask of daw of week
		incf	WDay,w				; Wday code is 0..6
		movwf	Scratch2
		bsf		STATUS,C			; Set C
Alarm_Wday
		rlf		Scratch,f			; Clears C
		decfsz	Scratch2,f
		goto	Alarm_Wday

Alarm_loop_init						; Scratch has now a 1 on bit number Wday
		movlw	Alarm0WDay			; Pointer to alarm table
		movwf	FSR

Alarm_loop
		btfss	INDF,7				; Check alarm enable flag
		goto	Alarm_dis			; Disabled

		movf	INDF,w				; Get alarm day of week flags
		andwf	Scratch,w			; Mask with actual day of week mask
		btfsc	STATUS,Z
		goto	Alarm_dis			; Not enabled for actual day of week

		incf	FSR,f				; Move pointer to alarm hour
		movf	INDF,w				; Get alarm hour
		andlw	0x1F
		xorwf	Hour,w				; Compare with actual hour
		movwf	Scratch2			; Store result

		btfsc	INDF,5				; If alarm hour >= 32, hour masked out from comparation
		clrf	Scratch2

		incf	FSR,f				; Move pointer to alarm minute
		movf	INDF,w				; Get alarm minute
		andlw	0x3F
		xorwf	Minute,w			; Compare with actual minute
		iorwf	Scratch2,w			; Combine with hour comp. result
		btfss	STATUS,Z
		goto	Alarm_dis			; Not Z, no alarm

		incf	FSR,f				; Move pointer to alarm minute
		btfsc	INDF,7				; Test for alarm mode
		goto	AlarmSwitch			; Goto if switch

		btfsc	INDF,6				; Test for propeller start
		call	NotStandbyPb		; Start up propeller
		btfsc	INDF,5				; Test for propeller stop
		call	ToStandby			; Stop propeller
		btfss	INDF,4				; Test for sound enabled
		goto	Alarm_dis

		movf	INDF,w
		andlw	0x0F
		btfsc	STATUS,Z
		movlw	.8					; Init sound counter
		movwf	SoundCnt
		goto	Alarm_dis

AlarmSwitch
		movf	INDF,w				; Get turn on time (minutes)
		andlw	0x7F
		movwf	SwitchCnt			; Set up counter
	bcf		INTCON,GIE
		btfss	STATUS,Z
		bsf		COPYB,bRelais		; Turn on  relais
		btfsc	STATUS,Z
		bcf		COPYB,bRelais		; Turn off relais
		call	ToPortB
	bsf		INTCON,GIE

Alarm_dis							; Move to next alarm setting
		bsf		FSR,0
		bsf		FSR,1
		incf	FSR,f
		movlw	0xF0				; Check for end of table
		xorwf	FSR,w
		btfss	STATUS,Z
		goto	Alarm_loop			; Loop for all alarm entries

		btfsc	STATUS,IRP			; Bank3 was used ?
		goto	Alarm_loop_ex		; End of alarm table
		bsf		STATUS,IRP			; Use Bank3
		goto	Alarm_loop_init
Alarm_loop_ex
		bcf		STATUS,IRP			; IRP = 0
		return

;******************************************************************************
;	Process RC5 commands

ProcessRC5
		movlw	'A'					; RC5 packet info will be sent
		call	UART_SEND
		movf	RC5_Addr,w			; Send address
		call	UART_SEND_BYTE
		movf	RC5_Cmd,w			; Send command
		call	UART_SEND_BYTE_CR

	ifdef	RC5AddrCheck
		movf	RC5_Addr,w			;
		xorlw	RemoteAddr			; test if RC5_Addr = RemoteAddr
		btfss	STATUS,Z			;
		goto	ProcessRC5Done		;
	endif

		movf	RC5_Cmd,w			; Get command code
		xorwf	RC5_Cmd2,f			; Compare with previous one
		btfsc	STATUS,Z			;
		goto	ProcessRC5Done		; Exit if the same code

		andlw	0x7F				; Mask toggle bit

		select_w
		case	WIDTH_DN			;
		  goto	DecWidth			; Decrement pulse width frequency
		case	WIDTH_UP			;
		  goto	IncWidth			; Increment pulse width frequency
;		case	PER_UP				;
;		  goto	DecFreq				; Decrement PWM frequency
;		case	PER_DN				;
;		  goto	IncFreq				; Increment PWM frequency
		case	POWUPCOIL			;
		  goto	PowerUpCoil			; Power up   coil
		case	POWDNCOIL			;
		  goto	PowerDownCoil		; Power down coil

		case	TINDEX
		  goto	ToggleIndex	 		; Toggle index LED
		case	ALM_SND
		  clrf	SoundCnt			; Alarm sound off
		case	REL_ON	 			;
		  goto	RelaisOn			; Turn relais on
		case	REL_OFF	 			;
		  goto	RelaisOff			; Turn relais off
		case	STANDBY				;
		  goto	ToggleStndBy		; StandBy
;		default
		call	ReloadASTimer		; Reload timer if valid command sent to clock

		goto	ProcessRC5Done		;

RelaisOn
		movf	RelOnIr,w			; Get turn on time
		movwf	SwitchCnt
	bcf		INTCON,GIE
		bsf		COPYB,bRelais
		call	ToPortB
	bsf		INTCON,GIE
		goto	ProcessRC5Done		;

RelaisOff							; Turn off relais output
		clrf	SwitchCnt
	bcf		INTCON,GIE
		bcf		COPYB,bRelais
		call	ToPortB
	bsf		INTCON,GIE
		goto	ProcessRC5Done		;

ToggleIndex							; Toggle index led
		movlw	1 << bIndexLed		;
		xorwf	PORTC,f
		movlw	1 << bIndexOn		; Toggle in flags too
		xorwf	flags,f
		goto	ProcessRC5Done		;

;IncFreq								; Increment PWM frequency - decrement PR2
;		bsf		STATUS,RP0			; Bank1
;		decf	PR2,f				;
;		goto	SetFreq

;DecFreq								; Decrement PWM frequency - increment PR2
;		bsf		STATUS,RP0			; Bank1
;		incf	PR2,f				;

;SetFreq								; Store frequency data in RTC
;		movlw	RTC_PWMData+1		; Use run addresses
;		btfsc	CoilPower			; Coil powered up?
;		addlw	0x02				; No - Use sleep addresses
;		call	SetWordAdr
;		movlw	PR2_Run				; Update in memory	use run variable
;		btfsc	CoilPower			; Coil powered up?
;		movlw	PR2_Sleep			; No - Use sleep variable
;		movwf	FSR
;		movf	PR2,w				; Get frequency
;		bcf		STATUS,RP0			; Bank0
;		goto	IndfToRTC			; Write to INDF and send on I2C

IncWidth							; Increment pulse width
		decf	CCPR1L,f
		goto	SetWidth

DecWidth							; Decrement pulse width
		incf	CCPR1L,f
SetWidth
		movlw	RTC_PWMData			; Use run address
		btfsc	CoilPower			; Coil powered up?
		addlw	0x02				; No - Use sleep addresses
		call	SetWordAdr
		movlw	CCP1_Run			; Update in memory	use run variable
		btfsc	CoilPower			; Coil powered up?
		movlw	CCP1_Sleep			; No - Use sleep variable
		movwf	FSR
		movf	CCPR1L,w			; Get pulse width

IndfToRTC							; Write to INDF and send on I2C
		movwf	INDF
		call	I2CByteWrite
		goto	ProcessRC5Done		;

PowerUpCoil							; High power drive to trafo coil
		call	InitPWMHighPower	;
		goto	ProcessRC5Done		;

PowerDownCoil						; Low power drive to trafo coil
		call	InitPWMLowPower		;
		goto	ProcessRC5Done		;

ToggleStndBy						; Toggle mode
		call	TgStandBy

ProcessRC5Done
		movf	RC5_Cmd,w			;
		movwf	RC5_Cmd2			; Store new command code
		bcf		RC5_DataReady		;
		return						;

;******************************************************************************
;	Init variables from RTC

InitData
		call	InitTime			; Get time from RTC
AlmInit
		movlw	Alarm0WDay			; Pointer to Alarm table
		movwf	FSR
AlmClear							; Clear all Alarm
		clrf	INDF
		incf	FSR,f
		movlw	0xF0
		xorwf	FSR,w
		btfss	STATUS,Z
		goto	AlmClear

		btfsc	STATUS,IRP			; Bank3 was used ?
		goto	AlmInitEx			; End of alarm table
		bsf		STATUS,IRP			; Use Bank3
		goto	AlmInit
AlmInitEx
		bcf		STATUS,IRP

		btfsc	TimeInv				; If time read from RTC is invalid
		return

		movlw	RTC_AlarmData		; Address of alarm data in RTC
		call	SetWordAdr

AlmLdInit
		movlw	Alarm0WDay			; Read Alarm table
		movwf	FSR					; Point to Alarm table
AlmLd
		call	I2CByteRead			; Read alarm data from RTC
		movwf	INDF
		incf	FSR,f
		movlw	0xF0
		xorwf	FSR,w
		btfss	STATUS,Z			; Loop for all alarm records
		goto	AlmLd

		btfsc	STATUS,IRP			; Bank3 was used ?
		goto	Alarm_loop_ex		; End of alarm table , set IRP = 0
		bsf		STATUS,IRP			; Use Bank3
		goto	AlmLdInit

;******************************************************************************
; PWM

; Low power

InitPWMLowPower
;;		movf	PR2_Sleep,w			; set frequency for sleep mode
		bsf		STATUS,RP0			; Bank1
;;		movwf	PR2					;
		btfsc	DeapSleep			; If deap sleep enabled
		bsf		TRISC,bTrafo		; Disable trafo FET
		btfss	DeapSleep			; If deap sleep disabled
		bcf		TRISC,bTrafo		; Enable  trafo FET
		bcf		STATUS,RP0			; Bank0
		movf	CCP1_Sleep,w		; Set dutycycle for sleep mode
		movwf	CCPR1L				;
		bcf		CoilPower
		return

; Toggle standby

TgStandBy
		btfss	StandBy				;
		goto	ToStandby

;--------
; Wake up from sleep / standby

NotStandbyPb
		bcf		PORTC,bIndexLed		; turn on index led
		bsf		IndexOn
		bcf		StandBy				; spin motor
		bcf		Sleeping			; stop sleeping
	bcf		INTCON,GIE
		bcf		COPYB,bMotorOFF		; startup MIC 2940A
		call	ToPortB
	bsf		INTCON,GIE

; High power

InitPWMHighPower
;;		movf	PR2_Run,w			; High power to trafo
		bsf 	STATUS,RP0			; Bank1
		bcf		TRISC,bTrafo		; Enable trafo FET
;;		movwf	PR2					; PR2 set for high power
		bcf 	STATUS,RP0			; Bank0
		movf	CCP1_Run,w			;
		movwf	CCPR1L				; CCPR1L = Run
		bsf		CoilPower

; Reload Auto standby timer

ReloadASTimer
		movf	AutoStbyTimH,w		; Count is in seconds
		movwf	StandbyTimerH
		movf	AutoStbyTimL,w
		movwf	StandbyTimerL
		return

;--------
; Go to standby

ToStandby							; Go to standby
		movlw	.5					;
		movwf	SleepTimer			; SleepTimer = 5 seconds

		bsf		PORTC,bIndexLed		; turn off index led
		bcf		IndexOn
		bsf		StandBy				; motor in standby
	bcf		INTCON,GIE
		bsf		COPYB,bMotorOFF		; shutdown MIC 2940A
		call	ToPortB
	bsf		INTCON,GIE

ClearASTimer
		clrf	StandbyTimerH
		clrf	StandbyTimerL
		return

;******************************************************************************
;		Read temperature measurement
;******************************************************************************

ReadAd
		movf	AD_state,w			; Get A/D state
		btfsc	STATUS,Z
		goto	ADReady				; If A/D state = 0 -> Read result
		btfsc	AD_state,3			; If A/D state < 8 -> Start A/D, A/D state = 0
		return

StartAD
		bsf		ADCON0,GO			; Start A/D conversion
		clrw
SetADState
		movwf	AD_state
		return

ADReady
		movf	ADRESH,w			; Get the 10 bit result
		movwf	DIV_HI
		bsf		STATUS,RP0			; Bank1
		movf	ADRESL,w
		movwf	DIV_LO
		bcf		STATUS,RP0			; Bank0

		btfsc	ADCON0,CHS1			; A/D channel 2 or 3 selected
		goto	AD_Ch23				;
		btfsc	ADCON0,CHS0			; A/D channel 1 selected
		goto	AD_Temperature		; Temperature measured

AD_Light							; A/D channel was 0 selected
		call	Div4				; Convert to 8 bits
		movwf	Light				; Store measured value

		goto	SelNextCh			; Next channel is 1 - Temperature

AD_Temperature
									; A/D res = (T+273.15)/100/5*1024	 0 °C ==> 560 = 512 + 48
									; T °C = (AD-560)/2
		call	Div2				; w=(AD-.512)/.2
		addlw	-.24				; add -48/2,
		addwf	TempOffset,w		; add correction
		movwf	Temperature			; Store temperature in °C (-26 ... 230)

		goto	SelNextCh			; Next channel is 2 - Humidity

AD_Ch23								; A/D channel 2 or 3 selected
		btfsc	ADCON0,CHS0
		goto	AD_Pressure

AD_Humidity							; A/D channel 2 selected
									; HIH 3610
									; Measured value   0% - 0.55637V - 113.83
									;                100% - 2.536  V - 518.86
									; HIH - 56k -+- 100k - GND

;		call	Div4				; Divide result by 4
;		addlw	-.114/.4

									; HIH 4000
									; Measured value   0% - 0.48449V -  99.22
									;                100% - 2.4348 V - 498.65
									; HIH - 47k -+- 100k - GND

		call	Div4				; Divide result by 4
		addlw	-.99/.4
		addwf	HumidityOffset,w
		movwf	Humidity			; Store humidity in %
		goto	SelNextCh			; Next channel is 4 - Pressure

AD_Pressure							; A/D channel 3 selected
									; MPXA6115A - 6k2 -+- 43k - GND
		addwf	PressureOffset,w
		movwf	Pressure			; Air Pressure = (0x200+Pressure)*1.25+.110
;		goto	SelNextCh			; Next channel is 0 - Light

SelNextCh
		movlw	(1<<CHS0)			; Select next AD channel
SelCh
		addwf	ADCON0,f			; Only channels 0..3
		bcf		ADCON0,CHS2

		movlw	0x0F
		goto	SetADState			; Reinit AD state counter

Div4								; Divide result by 4
		call	Div2
		movwf	DIV_LO

Div2								; Divide result by 2
		clrc
		rrf		DIV_HI,f
		rrf		DIV_LO,w
		return

;**********************************************************************
; Init sub second counter

InitSubSecCnt
		movlw	0x3C				; load counter SubSecond = 0x10000 - .2500 = 0xF63C
		movwf	SubSec_L			;
		movlw	0xF6				;
		movwf	SubSec_H			;
		return

;**********************************************************************
; Initialization

main
InitIO
;;;		movlw	(1<<bLED) | (1<<bMotorOFF);Turn off error led, motor
;;;		movwf	PORTB				;
;;;		movwf	COPYB				; Done at reset vector

		movlw	(1<<bIndexLed)		; Turn off index led
		movwf	PORTC

		bsf		STATUS,RP0			; Bank1
		movlw	0x84				; A/D right justified, VDD-GND references
		movwf	ADCON1

		movlw	0xFF				; Set PORTA 0..7 as input
		movwf	TRISA
									; I2C routines turn on bSCL and bSDA output if needed
		movlw	0xFF ^ ( (1<<bLED) | (1<<bRelais) | (1<<bSoundOut) | (1<<bMotorOFF) )
 		movwf	TRISB				; Disable trafo drive
		movlw	0xFF ^ ( (1<<bIndexLed) | (1<<bUSBPower) | (1<<bUSBCap) | (1<<bUSBDN) | (1<<bUSBDP) )
		movwf	TRISC

		clrf	PIE1				; dissable all possible interrupt flag
		movlw	b'10000001'			; set up timer0, prescaler(bit3)bypassed
		movwf	OPTION_REG			; send w to option.

		bsf		PIE1,TMR2IE			; Enable Peripheral interrupt from TMR2
		movlw	.49					; set frequency for 40uS interrupt
		movwf	PR2					;

		bsf		STATUS,RP1			; Bank3
		clrf	ANSELH
		movlw	0x0F
		movwf	ANSEL				; Use PORTA 3..0 pins analog 7..4 as digital I/O
									; A/D is off afther reset

		clrf	STATUS				; Bank0, IRP=0

;		movlw	0x0F
		movwf	AD_state			; Init A/D state counter

		clrf	DCF_SNum			; Clear counter of successfull synchronizations
		movlw	0x80
		movwf	DCF_temp
		movlw	.100				; .100 * .200 uS = .20 ms
		movwf	DCF_20ms_cnt
		clrf	DCF_flags
		bsf		DCF_flags,bDCFWaitSync; DCF is waiting for synchron
		clrf	DCF_Year
		clrf	DCF_Month
		clrf	DCF_Day
		clrf	DCF_Hour
		clrf	DCF_Minute

		movlw	0xff
		movwf	WuBtCnt
		movwf	RyBtCnt

		movlw	.5
		movwf	T2PostCnt
;		movlw	b'00000101'			;
		movwf	T2CON				; Timer2=ON, Prescaler = 1/4
		movlw	0x0C				; Set CCP in PWM mode
		movwf	CCP1CON				;

		movlw	0x81				; A/D on , Fosc/32, Ch 0
		movwf	ADCON0

		call	InitSubSecCnt

		clrf	SoundCnt			; Clear down counter for alarm sound
		clrf	SwitchCnt			; Clear down counter for relais controll

		clrf	Rs232Flags			; Clear uart's command decode flags
		clrf	RC5_flags			; clear flags
		clrf	RC5_Tmr				;
		bsf		RC5_WaitStart		; RC5 is waiting for startbit

		movlw	(1<<bStandBy)|(1<<bSleeping)
		movwf	flags				; Init flags: Sleeping

		call 	InitData			; Init data from RTC

		call	UART_INIT			; Init uart and it's buffers

; Low power

		call	InitPWMLowPower		; Init the low power PWM output to drive primary coil

		clrf	SleepTimer			; SleepTimer = 0 seconds
		call	ClearASTimer		; Clear auto standby timer

		clrf	PicFifoChNum		; Pic12F629 fifo number of avaible chars
		movlw	low(PicFifo)
		movwf	PicFifoWp			; Pic12F629 fifo write pointer
		movwf	PicFifoRp			; Pic12F629 fifo read  pointer

		btfsc	WakeRun				; Wake up in run mode
		call	NotStandbyPb		; Start in Active mode

;;		clrf	TMR0				; Restart timer

SendMessage
;;		movlw	(1<<GIE) | (1<<PEIE) | (1<<T0IE)
		movlw	(1<<GIE) | (1<<PEIE)
		movwf	INTCON 				; Enable global, extended peripheral and TMR0 interrupt

		call	SEND_MESSAGE		; Send message

;================================================================================
;	Main loop

MainLoop
		btfsc	RC5_DataReady		; Decode Command received from RC5 receiver
		call	ProcessRC5			;

		btfss	ADCON0,GO			; Test for A/D conversion ready
		call	ReadAd				; Read temperature

		call	UARTCmdDec			; Decode Command received from UART

;		movf	PicFifoChNum,f		; If data to send 
;		btfss	STATUS,Z
;		call	PIC_Send			; Try to send it

		bsf		PCLATH,3			; Page2
		movf	DCF_flags,w			; If DCF ready and not error and start of new frame
		andlw	(1 << bDCFReady) | (1 << bDCFParityErr) | (1 << bDCFError) | (1 << bDCFWaitSync)
		xorlw	(1 << bDCFReady)
		btfsc	STATUS,Z			; If DCF decoded data avaible and no error
		call	DCFCopy				; Copy time to clock's registers
		clrf	PCLATH				; Page0

		btfss	NewTime				; test new time flag
		goto	TestButtons

 		call	TimeCheck			; half second past, do TimeCheck
		bsf		PCLATH,3			; Page2
		call	CalcWDay			; Calculate day of week
		clrf	PCLATH				; Page0
		movwf	WDay

		movf	Second2,f
		btfss	STATUS,Z			; Minute passed
		goto	TestButtons

		movf	LastMinute,w
		xorwf	Minute,w			; Check this minute processed
		btfsc	STATUS,Z			; DCF77 synchronization can move time backward
		goto	TestButtons

		xorwf	LastMinute,f

		movf	SwitchCnt,f			; Check relais switch counter
		btfss	STATUS,Z
		decfsz	SwitchCnt,f			; Decrement timer
		goto	lAlmChk

	bcf		INTCON,GIE
		bcf		COPYB,bRelais		; Turn off relais
		call	ToPortB
	bsf		INTCON,GIE

lAlmChk
		call	AlarmCheck			; Check for alarm condition

ChkHourSnd
		movf	Minute,w
		btfss	STATUS,Z			; At hour change
		goto	TestButtons

		btfss	HourSign			; If hour sound enabled
		goto	CheckMidnight

		movf	HourSndBeg,w		; If afther begin hour
		subwf	Hour,w
		btfss	STATUS,C
		goto	CheckMidnight

		incf	Hour,w				; If before end hour
		subwf	HourSndEnd,w
		btfss	STATUS,C
		goto	CheckMidnight

		movf	SoundCnt,f			; If no alarm pending
		btfss	STATUS,Z
		goto	CheckMidnight

		movlw	1					; Set only one sound
		btfss	HourSignMode		; If hour mode
		goto	EnHourSound

		movlw	.12					; If hour >=12
		subwf	Hour,w				; W = Hour - 12
		btfss	STATUS,C
		movf	Hour,w
		btfsc	STATUS,Z			; If W ==0
		addlw	.12					; W = W+12

EnHourSound
		movwf	SoundCnt			; Set sound count

CheckMidnight
		movf	Hour,w				; At midnight
		btfss	STATUS,Z
		goto	TestButtons

		btfsc	ReinitTime			; If enabled
		call	InitTime			; Reinit time from RTC

TestButtons
		btfss	PORTA,bAlarmRes		; Alarm off button pressed
		clrf	SoundCnt

		movf	PORTB,w
		movwf	Scratch

		movlw	0xFF
		btfsc	Scratch,bButton		; Wake up button pressed
		movwf	WuBtCnt
		btfsc	Scratch,bButton		; Wake up button pressed
		goto	WuDone
		movf	WuBtCnt,f
		btfss	STATUS,Z
		decfsz	WuBtCnt,f
		goto	WuDone
		bsf		flags,bWuBtDown
WuDone

		movf	PORTA,w
		movwf	Scratch

		movlw	0xFF
		btfsc	Scratch,bRelButton	; Relais button pressed
		movwf	RyBtCnt
		btfsc	Scratch,bRelButton	; Relais button pressed
		goto	RyDone
		movf	RyBtCnt,f
		btfss	STATUS,Z
		decfsz	RyBtCnt,f
		goto	RyDone
		bsf		flags,bRyBtDown
RyDone

		btfss	flags,bWuBtDown		; Wake up button pressed
		goto	TestRyButton

		call	TgStandBy
		bcf		flags,bWuBtDown

TestRyButton
		btfss	flags,bRyBtDown		; Realis button pressed
		goto	CheckSleep

		bcf		flags,bRyBtDown
		movf	RelOnIr,w
		movf	SwitchCnt,f
		btfss	STATUS,Z
		clrw
	bcf		INTCON,GIE
		movwf	SwitchCnt			; Set time
		bcf		COPYB,bRelais
		movf	SwitchCnt,f
		btfss	STATUS,Z
		bsf		COPYB,bRelais
		call	ToPortB				; Switch on relais
	bsf		INTCON,GIE

CheckSleep
		btfsc	Sleeping			; yes, in standby: already sleeping?
		goto	MainLoop			; yes, sleeping, continue main loop

		btfsc	StandBy				; in standby?
		goto	CheckToSleep		; no, continue main loop

		movf	StandbyTimerH,w		; Check for StandbyTimer(16 bit)==0
		iorwf	StandbyTimerL,w
		btfss	STATUS,Z
		goto	MainLoop

		btfsc	AutoStby			; If AutoStandby enabled
		call	ToStandby			; Go to standby
		goto	MainLoop

CheckToSleep
		movf	SleepTimer,w		;
		btfss	STATUS,Z			; SleepTimer == 0
		goto	MainLoop			; no, continue main loop

		call	InitPWMLowPower		; Low power drive to trafo coil

		bsf		Sleeping			; Sleeping
		goto	MainLoop			;

;******************************************************************************
;	UART functions
;******************************************************************************

;******************************************************************************
; Command decoding

UARTCmdDec
		movlw	high(CmdParNum)
		movwf	PCLATH

		btfsc	Rs232Flags,bCmdExec	; If command execution in progress
		goto	GetParam			; Get parameters of command

GetCommand
		call	UART_RECEIVE		; Get the command character
		btfsc	STATUS,C			; Was there character avaible
		return						; Return if not
		addlw	-'`'				; Check the range '`', 'a'...'z'
		btfss	STATUS,C
		return
		movwf	Rs232Cmd			; Save code of command
		addlw	-(0x7F+1-'`')
		btfsc	STATUS,C
		return
		movf	Rs232Cmd,w			; Get code of command
		call	CmdParNum			; Get number of parameters
		movwf	Rs232ParNum
		bsf		Rs232Flags,bCmdExec	; Sign command execution in progress

GetParam
		movf	Rs232ParNum,w		; Are there enought parameters in buffer
		subwf	UartRxChNum,w
		btfss	STATUS,C
		return						; Return if not

CmdParOk
		movf	Rs232Cmd,w			; Get command code
		bcf		Rs232Flags,bCmdExec	; No command execution in progress

		goto	CmdExec				; Execute it and return to caller at the end of execution

;**********************************************************************
; Init uart

UART_INIT:
		clrf	UartRxChNum			; Init receive fifo
		movlw	low(UartRxChar)
		movwf	UartRxChWp
		movwf	UartRxChRp

		clrf	UartTxChNum			; Init transmit fifo
		movlw	low(UartTxChar)
		movwf	UartTxChWp
		movwf	UartTxChRp

		bsf 	STATUS,RP0			; Bank1

	if	BaudRate<.9600				; Set up Baud rate
		bcf		TXSTA,BRGH
		movlw	(F_OSC/.64/BaudRate)-1
	else
		bsf		TXSTA,BRGH
		movlw	(F_OSC/.16/BaudRate)-1
	endif

		movwf	SPBRG
		bsf		TXSTA,TXEN			; Enable transmission

		bsf		PIE1,RCIE			; Enable  receive interrupt
		bcf		PIE1,TXIE			; Disable transmit interrupt

		bcf 	STATUS,RP0			; Bank0

		bsf		RCSTA,SPEN			; Enable receive
		bsf		RCSTA,CREN

		return

;**********************************************************************
; Send a byte in BCD format with uart as two ASCII character
; Keeps IRP, RP1, RP0 bits of STATUS
; Keeps FSR

UART_SEND_BCD
		call	Conv2BCD

;**********************************************************************
; Send a byte with uart as two hex. ASCII character
; Keeps IRP, RP1, RP0 bits of STATUS
; Keeps FSR

UART_SEND_BYTE
		movwf	Scratch				; Save data to send
		swapf	Scratch,w			; Send high nibble first
		call	UART_SEND_NIBBLE
		movf	Scratch,w			; Send low  nibble

;**********************************************************************
; Send a nibble (lower 4 bit of W) with uart as a hex. ASCII character
; Keeps IRP, RP1, RP0 bits of STATUS
; Keeps FSR

UART_SEND_NIBBLE
		andlw	0x0F				; Keep only low nibble
		movwf	Rs232Temp2
		sublw	0x09
		clrw
		btfss	STATUS,C			; If nibble > 9 add 7, and use lower case character
		movlw	0x27
		addwf	Rs232Temp2,w
		addlw	0x30				; Convert to ACSII

;**********************************************************************
; Send a character (w), write it to uart send buffer
; Keeps IRP, RP1, RP0, DC, C bits of STATUS
; Keeps FSR

UART_SEND							; Sends char in w

		btfsc	UartTxChNum,5		; Test number of chars in buff
		goto	UART_SEND

		movwf	Rs232Temp			; Save character to send
		swapf	STATUS,w
		movwf	Rs232Status			; Save Status
		movf	FSR,w				; Save FSR
		movwf	Rs232Fsr

		bsf 	STATUS,RP0			; Bank1
		bcf		PIE1,TXIE			; Disable TX interrupt
		bcf 	STATUS,RP0			; Bank0

		bsf		STATUS,IRP			; Buffer in on Bank2

		movf	UartTxChWp,w		; Get write pointer
		movwf	FSR

		movf	Rs232Temp,w			; Get char to send
		movwf	INDF				; Store it in out buffer
		incf	FSR,w				; Move the pointer
		andlw	0x1F				; in circular way
		iorlw	low(UartTxChar)
		movwf	UartTxChWp
		incf	UartTxChNum,f		; Increment number of avaible characters

		bsf 	STATUS,RP0			; Bank1
		bsf		PIE1,TXIE			; Enable TX interrupt

UART_Exit
		bcf 	STATUS,RP0			; Bank0
		movf	Rs232Fsr,w			; Restore FSR
		movwf	FSR
		swapf	Rs232Status,w		; Restore STATUS
		movwf	STATUS				; Restore IRP, Bank selection
		movf	Rs232Temp,w			; Get char sent / just received
		return

;**********************************************************************
; Get a byte from receive buffer and convert it form BCD to bin
; Keeps IRP, RP1, RP0 bits of STATUS
; Keeps FSR

UART_REC_BCD
		call	UART_REC_BYTE
		goto	BcdToBin

;**********************************************************************
; Get a byte from receive buffer
; Keeps IRP, RP1, RP0 bits of STATUS
; Keeps FSR

UART_REC_BYTE
		clrf	Rs232Temp2			; Clear data to be read
		call	UART_REC_NIBBLE		; Receive high nibble
		movwf	Rs232Temp2
		swapf	Rs232Temp2,f		; Swap to high nibble

UART_REC_NIBBLE
		call	UART_RECEIVE
		btfsc	Rs232Temp,6			; Check for 'A'..'F' or 'a'..'f'
		addlw	-7
;		addlw	-0x30
		andlw	0x0F				; Keep low nibble
		addwf	Rs232Temp2,w
		return

;**********************************************************************
; Get a character from receive buffer
; Keeps IRP, RP1, RP0, DC, C bits of STATUS
; Keeps FSR

UART_RECEIVE						; Gets char into w, C == 1 if no char was in fifo

		bsf		STATUS,C			; Set no character received
		swapf	STATUS,w			; Save STATUS
		movwf	Rs232Status
		movf	FSR,w				; Save FSR
		movwf	Rs232Fsr

		bsf		STATUS,IRP			; Buffer in on Bank2

		bsf 	STATUS,RP0			; Bank1
		bcf		PIE1,RCIE			; Disable RC interrupt
		bcf 	STATUS,RP0			; Bank0

		clrf	Rs232Temp
		movf	UartRxChNum,w		; Check number of avaible chars
		btfsc	STATUS,Z
		goto	NO_REC_CHAR			; Jump if no character avaible

		movf	UartRxChRp,w		; Get read pointer
		movwf	FSR

		movf	INDF,w				; Read it from buffer
		movwf	Rs232Temp
		incf	FSR,w				; Move the pointer
		andlw	0x0F				; in circular way
		iorlw	low(UartRxChar)
		movwf	UartRxChRp
		decf	UartRxChNum,f		; Decrement number of avaible characters
		bcf		Rs232Status,C+4		; Valid character received - !Status was swapped!

NO_REC_CHAR
		bsf 	STATUS,RP0			; Bank1
		bsf		PIE1,RCIE			; Enable RC interrupt

		goto	UART_Exit			; Restore STATUS and FSR

;**********************************************************************
; Send init message

SEND_MESSAGE
		movlw	high(InitMsg)		; Init string pointer high part
		movwf	Rs232StrPtrH
		movlw	low(InitMsg)		; Init string pointer low  part

;**********************************************************************
; Send a string (high part of address must be in Rs232StrPtrH)

SEND_STRING
		movwf	Rs232StrPtr			; Save string pointer low  part
lString0
		call	MsgTabl				; Get next character
		movwf	Rs232Temp2			; Save it
		andlw	0x7F				; Mask bit7 off
		call	UART_SEND			; Send character
		btfss	Rs232Temp2,7		; Check for end of string mark
		goto	lString0			; Loop for all characters
		return

;******************************************************************************
;	I2C RTC functions
;******************************************************************************

;******************************************************************************
; Read the time from RTC

InitTime							; Init time from I2C RTC
		movlw	RTC_ADDR
		movwf	I2CSlaveAdr

		clrf	Second2
		movlw	RTC_Tenms			; Address of 1/100 Seconds
									; dpi = 0x01
		call	I2CByteReadStoreAddr; Read 1/100 seconds
		addlw	-0x50
		btfsc	STATUS,C
		bsf		Second2,0			; Set half seconds

		call	I2CByteRead			; Read seconds
		call	BcdToBin
		addwf	Second2,f
		addwf	Second2,f
									; I2CWordAdr = 0x03
		call	I2CByteRead			; Read minute
		call	BcdToBin
		movwf	Minute
									; I2CWordAdr = 0x04
		call	I2CByteRead			; Read hour
		call	BcdToBin3F			; Mask format and AM/PM
		movwf	Hour
									; I2CWordAdr = 0x05
		call	I2CByteRead			; Read day
		call	BcdToBin3F			; Mask Year bits
		movwf	Day
		swapf	Scratch,f
		rrf		Scratch,f
		rrf		Scratch,w
		movwf	Scratch2			; Save year bit 1..0
									; I2CWordAdr = 0x06
		call	I2CByteRead			; Read Month
		andlw	0x1F
		call	BcdToBin
		movwf	Month
									; I2CWordAdr = 0x07

		movlw	RTC_Year			; Address of Year
		call	I2CByteReadStoreAddr; Read year
									; I2CWordAdr = 0x11
		movwf	Year
		call	I2CByteRead			; Read year ^ 0xff
									; I2CWordAdr = 0x12

		xorlw	0xFF				; Complement read data
		xorwf	Year,w				; Has to be same as Year
		btfss	STATUS,Z
		goto	InitTimeDef			; Year not valid, init with default values

		call	I2CByteRead			; CCP1_Run
		movwf	CCP1_Run
									; I2CWordAdr = 0x13
		call	I2CByteRead			; PR2_Run
		movwf	PR2_Run
									; I2CWordAdr = 0x14
		call	I2CByteRead			; CCP1_Sleep
		movwf	CCP1_Sleep
									; I2CWordAdr = 0x15
		call	I2CByteRead			; PR2_Sleep
		movwf	PR2_Sleep
									; I2CWordAdr = 0x16
		call	I2CByteRead			; Auto Standby Time high
		movwf	AutoStbyTimH		;
									; I2CWordAdr = 0x17
		call	I2CByteRead			; Auto Standby Time  low
		movwf	AutoStbyTimL		;
									; I2CWordAdr = 0x18
		call	I2CByteRead			; Hour sound begin
		movwf	HourSndBeg			;
									; I2CWordAdr = 0x19
		call	I2CByteRead			; Hour sound end
		movwf	HourSndEnd			;
									; I2CWordAdr = 0x1A
		call	I2CByteRead			; Read Century
		movwf	Century
									; I2CWordAdr = 0x1B
		call	I2CByteRead			; Read Relais on time for ir commands
		movwf	RelOnIr
									; I2CWordAdr = 0x1C
		call	I2CByteRead			; Read temperature offset
		movwf	TempOffset
									; I2CWordAdr = 0x1D
		call	I2CByteRead			; Read humidity offset
		movwf	HumidityOffset
									; I2CWordAdr = 0x1E
		call	I2CByteRead			; Read pressure offset
		movwf	PressureOffset
									; I2CWordAdr = 0x1F
		call	I2CByteRead			; Mode
		movwf	Mode				;
									; I2CWordAdr = 0x20

		movf	Year,w				; Has the RTC incremented Year
		xorwf	Scratch2,w
		andlw	0x03
		btfsc	STATUS,Z
		return						; No, return

		incf	Year,f				; Yes, increment Year
		call	TimeCheck			; Will correct Year and Century

StoreYear
		movlw	RTC_Year			; Address of Year
		movwf	I2CWordAdr
		movf	Year,w				; Write Year
		call	I2CByteWrite
									; I2CWordAdr = 0x11
		comf	Year,w
		call	I2CByteWrite		; Write complement of Year
		movlw	RTC_Century			; Address of Century
		movwf	I2CWordAdr
		movf	Century,w			; Write Year
		goto	I2CByteWrite


;******************************************************************************
; Init time with default value: 2001-01-01 12:00:00, day of week: 1 ,set time invalid
; Init CCPR1L, RP2 for Run and Sleep mode with default values
; Init Auto Standby Timer with default value
; Init mode with default value
; Write default data to RTC

InitTimeDef
;;		clrf	Hour 				; May start from 00:00:00
		movlw	.12					; why do clocks always start
		movwf	Hour				; at 12:00 ?
;;
		clrf	Minute
        clrf	Second2
		movlw	.1
		movwf	Day
		clrf	WDay
		movwf	Month
		movwf	Year
		movlw	.20					; 2001.01.01 was monday
		movwf	Century

		bsf		TimeInv				; Sign time not valid

									; Write default data to RTC
		movlw	RTC_PWMData			; Set word address
		call	SetWordAdr			; Set RTC's slave address

									; PWM parameters
		movlw	CCPR1LRUN			; Set pulse width for run mode
		movwf	CCP1_Run			;
		call	I2CByteWrite		;
;;		movlw	PR2RUN				; Set frequency for run mode
		movlw	.49
		movwf	PR2_Run				;
		call	I2CByteWrite
		movlw	CCPR1LSleep			; Set pulse width for sleep mode
		movwf	CCP1_Sleep
		call	I2CByteWrite
;;		movlw	PR2Sleep			; set frequency for sleep mode
		movlw	.49
		movwf	PR2_Sleep			;
		call	I2CByteWrite

		movlw	high(.3600)			; Auto Standby time
		movwf	AutoStbyTimH		;
		call	I2CByteWrite
		movlw	low(.3600)			; Auto Standby Timer
		movwf	AutoStbyTimL		;
		call	I2CByteWrite

		movlw	.8
		movwf	HourSndBeg			; Hour sound begin hour
		call	I2CByteWrite

		movlw	.20
		movwf	HourSndEnd			; Hour sound end   hour
		call	I2CByteWrite

		movlw	.20
		movwf	Century				; Century
		call	I2CByteWrite

		movlw	0xFF				; Relais on time for ir commands
		movwf	RelOnIr
		call	I2CByteWrite

		movlw	-.2					; Temperature offset
		movwf	TempOffset
		call	I2CByteWrite

		clrw
		movwf	HumidityOffset
		call	I2CByteWrite

		clrw
		movwf	PressureOffset
		call	I2CByteWrite

;		movlw	RTC_Mode			; Mode
;		movwf	I2CWordAdr

ModeCode	set	0x00
	ifdef	AutoStandby
ModeCode	set	ModeCode | (1<<bAutoStby)
	endif
	ifdef	WakeUpRun
ModeCode	set	ModeCode | (1<<bWakeRun)
	endif
	ifdef	DeapSleeping
ModeCode	set ModeCode | (1<<bDeapSleep)
	endif
	ifdef	EnableHourSign
ModeCode	set	ModeCode | (1<<bHourSign)
	endif
	ifdef	SignMode
ModeCode	set	ModeCode | (1<<bHourSignMode)
	endif
	ifdef	TimeReInit
ModeCode	set ModeCode | (1<<bReinitTime)
	endif
	ifdef	DCF77Enabled
ModeCode	set ModeCode | (1<<bDCFEnabled)
	endif
	ifdef	PropSyncEnabled
ModeCode	set ModeCode | (1<<bPropTimSync)
	endif

		movlw	ModeCode			; Init Mode
		movwf	Mode
		call	I2CByteWrite

;- Clear alarm data in RTC
AlmClrRtc						; Clears alarm data and message in RTC
		movlw	RTC_AlarmData	; Address of alarm data in RTC
		movwf	FSR
		call	SetWordAdr		; Set RTC's slave address

AlmClrRtcLp
		clrw
		call	I2CByteWrite
		incfsz	FSR,f
		goto	AlmClrRtcLp
		return


;******************************************************************************
; Convert binary number to BCD

Conv2BCD							; Convert w to BCD (0 <= w <= 99)
		clrf	BCD					; Clear high nibble
l_bcd_1
		addlw	-.10				; Sub .10
		incf	BCD,f				; Inc high nibble
		btfsc	STATUS,C			; Loop if no carry
		goto	l_bcd_1
		addlw	.10					; Re add .10, C=1
		decf	BCD,f				; Correct high nibble
		swapf	BCD,f				; Swap to high part of byte
		addwf	BCD,w				; Add to low nibble, C=0
		return

;******************************************************************************
; Convert BCD number to binary - mask bit 7..6 off

BcdToBin3F							; Convert BCD to binary for Hour and Day
		andlw	0x3F

; Convert BCD number to binary

BcdToBin							; Convert BCD to binary
		movwf	BCD
		andlw	0x0F
		btfsc	BCD,4
		addlw	.10
		btfsc	BCD,5
		addlw	.20
		btfsc	BCD,6
		addlw	.40
		btfsc	BCD,7
		addlw	.80
		return

;******************************************************************************
; Writes the time to RTC

StoreTime
		call	SetSlaveAdr			; Set Slave address of RTC

		movlw	0x80				; Disable counting command
		call	SendRtcCmd
									; I2CWordAdr = 0x01
		clrw
		btfsc	Second2,0			; Store subsec
		addlw	0x50
		call	I2CBcdWrite
									; I2CWordAdr = 0x02

		clrc						; carry = 0
		rrf		Second2,w			; Store Second = (Seconds2 >> 1)
		call	I2CBcdWrite
									; I2CWordAdr = 0x03
		movf	Minute,w			; Store Minute
		call	I2CBcdWrite
									; I2CWordAdr = 0x04
		movf	Hour,w				; Store Hour
		call	I2CBcdWrite
									; I2CWordAdr = 0x05
		swapf	Year,w				; Store Day and Year bit 1..0
		movwf	Scratch
		rlf		Scratch,f
		rlf		Scratch,f
		movlw	0xC0
		andwf	Scratch,f
		movf	Day,w
		call	BCDiorWrite
									; I2CWordAdr = 0x06
		swapf	WDay,w				; Store Month and Wday
		movwf	Scratch
		rlf		Scratch,f
		movlw	0xE0
		andwf	Scratch,f
		movf	Month,w
		call	BCDiorWrite
									; I2CWordAdr = 0x07
		call	EnableCount
		bcf		TimeInv
		goto	StoreYear

BCDiorWrite
		call	Conv2BCD
		iorwf	Scratch,w
		goto	I2CByteWrite

; Send enable count command to RTC
EnableCount
		movlw	0x00				; Enable counting command

; Send command to RTC
SendRtcCmd
		clrf	I2CWordAdr
		goto	I2CByteWrite

;******************************************************************************
;	I2C low level functions
;******************************************************************************

; Temporary variables are in common Ram - Can be used from Bank of TRISB too
; START selects BANK1 to access TRISA   - STOP select BANK0 before return

; At reset SCL and SDA bits in PORTB are cleared

;******************************************************************************
; Reads a byte from RTC to Scratch, address is in w
; store address in I2CWordAdr, I2CWordAdr incremented afther execution

I2CByteReadStoreAddr
	movwf	I2CWordAdr				; Store address

; Reads a byte from RTC to Scratch, address is in I2CWordAdr
; I2CWordAdr incremented afther execution

I2CByteRead
	CALL 	START					; Generate Start
	MOVF	I2CSlaveAdr,w			; Get slave address for write
	CALL 	OUT_BYTE				; Send slave address byte + nack
	CALL 	OUT_BYTE_ADDR			; Send word  address byte + nack

	CALL 	START					; Generate repeted start
	INCF	I2CSlaveAdr,w			; Get slave address for read
	CALL 	OUT_BYTE				; Send byte + nack
	CALL	IN_BYTE					; Get the byte to Scratch + send nack

ToStop
	CALL 	STOP					; Generate stop condition
	incf	I2CWordAdr,f			; Increment word address
	movf	Scratch,W				; Return data just read
	bcf		STATUS,RP0				; Back to Bank 0
	return

;******************************************************************************
; Writes W to RTC in BCD format, address is in I2CWordAdr
; I2CWordAdr incremented afther execution

I2CBcdWrite
	call	Conv2BCD				; Convert w to BCD

; Writes W to RTC, address is in I2CWordAdr
; I2CWordAdr incremented afther execution

I2CByteWrite
	movwf	Scratch					; Save data to be written to RTC
	CALL 	START					; Generate Start
	MOVF	I2CSlaveAdr,w			; Get slave address for write
	CALL 	OUT_BYTE				; Send slave address byte + nack
	CALL 	OUT_BYTE_ADDR			; Send word  address byte + nack
	MOVF 	Scratch, W				; Get output data
	CALL 	OUT_BYTE				; Send data byte + nack
	goto	ToStop

;******************************************************************************
; Generate stop condition on I2C bus

STOP:								; SDA 0 -> 1 while SCL == 1
									; SCL must be LOW afther (N)ACK's CLOCK_PULSE
	CALL	LOW_SDA					; SDA -> 0 - NACK has done it
	CALL	HIGH_SCL				; SCL -> 1 and make 5us stop setup time

; Make SDA high by making it input

HIGH_SDA:							; high impedance by making SDA an input
	BSF 	SDA						; make SDA pin an input
	GOTO 	DELAY_5US				; SDA -> 1 and make 5us bus free time

;******************************************************************************
; Generate start / repeated start condition on I2C bus

START:								; SDA 1 -> 0 while SCL == 1, then SCL -> 0
	BSF 	STATUS, RP0				; Bank 1 - Access TRISA
	CALL 	HIGH_SDA				; SDA 0 -> 1 ; wait 5 us - For repeated start
	CALL 	HIGH_SCL				; SCL 0 -> 1 ; make 5 us Start setup time
	CALL 	LOW_SDA					; SDA 1 -> 0 ; make 5 us Start hold  time
	GOTO 	LOW_SCL					; SCL 1 -> 0 ; wait 5 us

;******************************************************************************
; Shift in a byte from I2C bus, clock out nack, store data to Scratch

IN_BYTE								; Read byte on i2c bus
	CALL 	HIGH_SDA				; Configure SDA as input
	movlw	.8
	movwf	I2CBitCnt
;	bsf		I2CBitCnt,3				; Load 8 to I2CBitCnt, OUT_BYTE cleared I2CBitCnt
IN_BIT
	CALL 	HIGH_SCL				; SCL -> 1 ; 5us wait
	BCF		STATUS,RP0				; Bank 0 to read PORTB
	BCF		STATUS,C				; clear carry
	BTFSC 	SDA						; test SDA bit
	BSF 	STATUS,C				; set carry if SDA == 1
	BSF		STATUS,RP0				; Bank 1 to control TRISA
	RLF 	Scratch,F				; Scratch = (Scratch << 1) | input bit
	CALL 	LOW_SCL					; SCL -> 0 ; 5us wait
	DECFSZ 	I2CBitCnt,F				; decrement bit counter
	GOTO 	IN_BIT
	GOTO	NACK

;******************************************************************************
; Shift out a byte to I2C bus, clock in (n)ack, get data from I2CWordAdr

OUT_BYTE_ADDR
	MOVF	I2CWordAdr,w			; output address to be read

; Shift out a byte to I2C bus, clock in (n)ack, data is in w

OUT_BYTE:							; send o_byte on I2C bus
	movwf	I2CShiftReg				; Store data to send
	MOVLW 	.8
	MOVWF 	I2CBitCnt				; Loop for 8 bits
OUT_BIT:
	BTFSC 	I2CShiftReg,7			; if  one, send a  one
	CALL 	HIGH_SDA				; SDA at logic one
	BTFSS 	I2CShiftReg,7			; if zero, send a zero
	CALL 	LOW_SDA					; SDA at logic zero
	CALL 	CLOCK_PULSE				; SCL -> 1 ; 5 us wait, SCL -> 0 ; 5 us wait
	RLF 	I2CShiftReg,F			; left shift, move mext bit to bit7
	DECFSZ 	I2CBitCnt,F				; decrement bit counter - Leaves with I2CBitCnt = 0
	GOTO 	OUT_BIT

;******************************************************************************
; Clock in/out (n)ack

NACK:								; bring SDA high and clock, SDA must be input
	CALL 	HIGH_SDA
	CALL	CLOCK_PULSE				; SCL -> 1 ; 5 us wait, SCL -> 0 ; 5 us wait

; Make SDA low by making it output

LOW_SDA:							; SDA -> 0 ; 5 us wait
	BCF 	SDA						; make SDA pin an output
	GOTO 	DELAY_5US

;******************************************************************************
; Generate clock pulse 			; SCL -> 1 ; 5 us wait, SCL -> 0 ; 5 us wait

CLOCK_PULSE:						; SCL momentarily to logic one
	CALL 	HIGH_SCL				; SCL -> 1 ; 5 us wait

; Make SCL low by making it output

LOW_SCL:							; SCL -> 0 ; 5 us wait
	BCF 	SCL						; make SCL pin an output
	GOTO	DELAY_5US

;******************************************************************************
; Make SCL high by making it input

HIGH_SCL:							; SCL -> 1 ; wait 5 us
	BSF 	SCL						; make SCL pin an input

; Delay 5uS @ 20MHz

DELAY_5US:							; provides nominal >5 us delay @20MHz
									; 1 instuction takes 200ns
	MOVLW	 .8						; 0.2 us
	MOVWF 	BCD						; 0.2 us
DELAY_1:							; Loop of 3 inst. time
	DECFSZ 	BCD, F					; 7*0.2+0.4 us
	GOTO 	DELAY_1					; 7*0.4 us
	RETURN							; Return 0.4 us

;******************************************************************************
; Command routines
;******************************************************************************

;******************************************************************************

UART_SEND_COMMAND
		movf	Rs232Cmd,w
		addlw	'@'					; Answare code in uppercase
		goto	UART_SEND

;******************************************************************************
; Send version

SendVer
		call	UART_SEND_COMMAND
		movlw	VersionMajor		; Send major version
		call	UART_SEND_BYTE
		movlw	'.'
		call	UART_SEND
		movlw	VersionMinor		; Send minor version
UART_SEND_BYTE_CR
		call	UART_SEND_BYTE		; Send a byte and a Cr Lf
SendCrLf
		movlw	high(CrLf)			; Send a Cr Lf sequence
		movwf	Rs232StrPtrH
		movlw	low(CrLf)
		goto	SEND_STRING

;******************************************************************************
; Clear seconds

ClrSec
		clrf	Second2				; Clear seconds
		goto	NewTim

;******************************************************************************
; Set Time

SetTime
		call	UART_REC_BCD		; Get hour
		movwf	Hour
		call	UART_REC_BCD		; Get minute
		movwf	Minute
		call	UART_REC_BCD		; Get second
		movwf	Second2
		addwf	Second2,f			; Doubble it
NewTim
		call	InitSubSecCnt
		bsf		Rs232Flags,bTimeSet	; Sign time has to be saved
		bsf		NewTime				; Set new time ready

;******************************************************************************
; Get Time

GetTime
		btfsc	NewTime
		call	TimeCheck
		call	UART_SEND_COMMAND
		movf	Hour,w				; Send hour
		call	UART_SEND_BCD
		movf	Minute,w			; Send minute
		call	UART_SEND_BCD
		clrc						; Get second
		rrf		Second2,w
		goto	UART_SEND_BCD_CR	; Send second

;******************************************************************************
; Set Date and day of week

SetDate
		call	UART_REC_BCD		; Get century
		movwf	Century
		call	UART_REC_BCD		; Get year
		movwf	Year
		call	UART_REC_BCD		; Get month
		addlw	0
		btfsc	STATUS,Z			; Correct 0 to 1
		addlw	1
		movwf	Month
		call	UART_REC_BCD		; Get day
		addlw	0
		btfsc	STATUS,Z			; Correct 0 to 1
		addlw	1
		movwf	Day
		call	UART_REC_BCD		; Get day of week
		bsf		PCLATH,3			; Page2
		call	CalcWDay			; Calculate day of week
		clrf	PCLATH
		movwf	WDay
		bsf		Rs232Flags,bTimeSet	; Sign time has to be saved
		bsf		NewTime				; Set new time ready

;******************************************************************************
; Get Date and day of week

GetDate
		btfsc	NewTime
		call	TimeCheck
		call	UART_SEND_COMMAND
		movf	Century,w
		call	UART_SEND_BCD		; Send century
		movf	Year,w
		call	UART_SEND_BCD		; Send year
		movf	Month,w
		call	UART_SEND_BCD		; Send month
		movf	Day,w
		call	UART_SEND_BCD		; Send day
		incf	WDay,w				; Convert 0..6 to 1..7
UART_SEND_BCD_CR
		call	UART_SEND_BCD		; Send day of week
		goto	SendCrLf

;******************************************************************************
; Init Alarm pointers (IRP:FSR and RTC)

AlarmPtr
		call	UART_REC_BCD		; Get alarm number
		movwf	FSR
		movlw	.40					; There are 40 alarm entries
		subwf	FSR,w				;
		movlw	.39					; If number > limit use last alarm entry
		btfsc	STATUS,C
		movwf	FSR
		movf	FSR,w
		movwf	Scratch3			; Store it
		addwf	FSR,f				; One entry has 4 locations
		rlf		FSR,f
		movf	FSR,w
		movwf	I2CWordAdr

		movlw	.4*.20				; Alarm entries >=20 are on Bank3
		subwf	FSR,w
		btfss	STATUS,C
		goto	PtrOk
		movwf	FSR					; Modify pointer
		bsf		STATUS,IRP			; Use Bank3

PtrOk
		movlw	Alarm0WDay
		addwf	FSR,f				; Init memory pointer

		movlw	RTC_AlarmData
		addwf	I2CWordAdr,w		; Init RTC address

SetWordAdr
		movwf	I2CWordAdr			; Save word address
SetSlaveAdr
		movlw	RTC_ADDR			; Init Slave address
		movwf	I2CSlaveAdr
		return

;******************************************************************************
; Set Alarm

SetAlarm
		call	AlarmPtr			; Get pointer to alarm table
		call	UART_REC_BYTE		; Get enable flags
		movwf	INDF				; Store it in memory
		call	I2CByteWrite		; Store it in RTC
		incf	FSR,f				; Move pointer
		call	UART_REC_BCD		; Get alarm hour
		movwf	INDF				; Store it in memory
		call	I2CByteWrite		; Store it in RTC
		incf	FSR,f
		call	UART_REC_BCD		; Get alarm minute
		movwf	INDF				; Store it in memory
		call	I2CByteWrite		; Store it in RTC
		incf	FSR,f
		call	UART_REC_BYTE		; Get alarm mode, duration
		movwf	INDF				; Store it in memory
		call	I2CByteWrite		; Store it in RTC

		bcf		FSR,0
		bcf		FSR,1				; Move pointer to beginning of entry
		goto	SendAlarm

;******************************************************************************
; Get Alarm

GetAlarm
		call	AlarmPtr			; Get pointer to alarm table
SendAlarm
		call	UART_SEND_COMMAND
		movf	Scratch3,w
		call	UART_SEND_BCD		; Send alarm number
		movf	INDF,w				; Get alarm enable flags
		call	UART_SEND_BYTE
		incf	FSR,f
		movf	INDF,w				; Get alarm hour
		call	UART_SEND_BCD
		incf	FSR,f
		movf	INDF,w				; Get alarm minute
		call	UART_SEND_BCD
		incf	FSR,f
		movf	INDF,w				; Get alarm mode, duration
CLR_IRP_SEND_B_CR
		bcf		STATUS,IRP			; IRP = 0
		goto	UART_SEND_BYTE_CR

;******************************************************************************
; Set PWM data

SetPWM
		movlw	RTC_PWMData			; Init RTC word address to PWM data
		call	SetWordAdr
		call	UART_REC_BYTE		; Get pulse width for run mode
		movwf	CCP1_Run
		call	I2CByteWrite		; Write to RTC
		call	UART_REC_BYTE		; Get period for run mode
		movwf	PR2_Run
		call	I2CByteWrite
		call	UART_REC_BYTE		; Get pulse width for sleep mode
		movwf	CCP1_Sleep
		call	I2CByteWrite
		call	UART_REC_BYTE		; Get period for sleep mode
		movwf	PR2_Sleep
		call	I2CByteWrite

		movf	CCP1_Run,w			; Copy new settings to CCPR1L and PR2
		btfss	CoilPower			; Coil powered up?
		movf	CCP1_Sleep,w		; No - Use sleep variable
		movwf	CCPR1L
;;		movf	PR2_Run,w			; Copy new settings to CCPR1L and PR2
;;		btfss	CoilPower			; Coil powered up?
;;		movf	PR2_Sleep,w			; No - Use sleep variable
;;		bsf		STATUS,RP0			; Bank1
;;		movwf	PR2
;;		bcf		STATUS,RP0			; Bank0


;******************************************************************************
; Get PWM data

GetPWM
		call	UART_SEND_COMMAND
		movf	CCP1_Run,w
		call	UART_SEND_BYTE		; Send pulse width for run mode
		movf	PR2_Run,w
		call	UART_SEND_BYTE		; Send period for run mode
		movf	CCP1_Sleep,w
		call	UART_SEND_BYTE		; Send pulse width for sleep mode
		movf	PR2_Sleep,w
		call	UART_SEND_BYTE		; Send period for sleep mode
		movf	CCPR1L,w
		call	UART_SEND_BYTE		; Send current pulse width
		bsf		STATUS,RP0
		movf	PR2,w
		bcf		STATUS,RP0
		goto	UART_SEND_BYTE_CR	; Send current periode

;******************************************************************************
; Set Auto Sleep Timer

SetAST
		movlw	RTC_AST
		call	SetWordAdr
		call	UART_REC_BYTE		; Get high byte of AST
		movwf	AutoStbyTimH
		call	I2CByteWrite
		call	UART_REC_BYTE		; Get low  byte of AST
		movwf	AutoStbyTimL
		call	I2CByteWrite

;******************************************************************************
; Get Auto Sleep Timer

GetAST
		call	UART_SEND_COMMAND
		movf	AutoStbyTimH,w		; Send high byte of AST
		call	UART_SEND_BYTE
		movf	AutoStbyTimL,w
		goto	UART_SEND_BYTE_CR	; Send low  byte of AST

;******************************************************************************
; Set Mode

SetMode
		movlw	RTC_Mode
		call	SetWordAdr
		call	UART_REC_BYTE		; Get mode
		movwf	Mode
		call	I2CByteWrite
		btfsc	StandBy
		call	InitPWMLowPower

;******************************************************************************
; Get Mode

GetMode
		call	UART_SEND_COMMAND
		movf	Mode,w
		goto	UART_SEND_BYTE_CR	; Send mode

;******************************************************************************
; Set relais state

SetRel
		call	UART_REC_BYTE		; Get relais controll
		andlw	1					; Keep lsb only
		movwf	Scratch
		call	UART_REC_BYTE		; Get duration
		btfss	Scratch,0
		goto	SetRel0

		movwf	SwitchCnt
	bcf		INTCON,GIE
		bsf		COPYB,bRelais		; Turn on relais output
		call	ToPortB
	bsf		INTCON,GIE
		goto	SetRel2

SetRel0
		clrf	SwitchCnt			; Clear counter
	bcf		INTCON,GIE
		bcf		COPYB,bRelais		; Turn off relais output
		call	ToPortB				; Copy it to PortB
	bsf		INTCON,GIE

SetRel2

;******************************************************************************
; Get relais state

GetRel
		call	UART_SEND_COMMAND
		clrw
		btfsc	PORTB,bRelais		; Get relais state
		addlw	1
		call	UART_SEND_BYTE		; Send it
		movf	SwitchCnt,w
		goto	UART_SEND_BYTE_CR	; Send remaining on time

;******************************************************************************
; Get number of alarms

GetAln
		call	UART_SEND_COMMAND
		movlw	.40					; There are .40 alarms
		call	UART_SEND_BCD
		movlw	RemoteAddr
		call	UART_SEND_BYTE		; Send RC5 address of clock
		movlw	0x86
		goto	UART_SEND_BYTE_CR	; Send processor type

;******************************************************************************
; Set hour sound parameters

SetHSnd
		movlw	RTC_HourSnd
		call	SetWordAdr

		call	UART_REC_BCD		; Get begin hour
		movwf	HourSndBeg
		call	I2CByteWrite

		call	UART_REC_BCD		; Get end   hour
		movwf	HourSndEnd
		call	I2CByteWrite

;******************************************************************************
; Get hour sound parameters

GetHSnd
		call	UART_SEND_COMMAND
		movf	HourSndBeg,w
		call	UART_SEND_BCD		; Send begin hour
		movf	HourSndEnd,w
		goto	UART_SEND_BCD_CR	; Send end   hour

;******************************************************************************
; Get / Set propeller state

SetProp
		call	UART_REC_BYTE		; Get controll info
		movwf	Scratch
		btfsc	Scratch,7			; If bit 7 set
		goto	SendProp			;  read flags only

		btfsc	Scratch,0			; Bit 0 set
		call	NotStandbyPb		;  start propeller
		btfss	Scratch,0			; Bit 0 cleared
		call	ToStandby			;  stop  propeller

SendProp
		call	UART_SEND_COMMAND
		movf	flags,w				; Send flags
		andlw	0xBF
		bsf		STATUS,RP0			; Change Time check needed flag to deep sleep
		btfsc	TRISC,bTrafo
		iorlw	0x40
		bcf		STATUS,RP0
		call	UART_SEND_BYTE
		movf	StandbyTimerH,w		; Send high byte of remaining run time
		call	UART_SEND_BYTE
		movf	StandbyTimerL,w
		goto	UART_SEND_BYTE_CR	; Send low  byte of remaining run time


;******************************************************************************
; Execute Rc5 command

XeqRc5
		call	UART_REC_BYTE		; Get address code
		andlw	0x1F				; Only 5 bit valid
		movwf	RC5_Addr
		call	UART_REC_BYTE		; Get command code
		movwf	RC5_Cmd
		bsf		RC5_DataReady		; Set address and command valid
		return						; Answare will be send in ProcessRC5


		call	UART_REC_BYTE		; Get address code
		andlw	0x1F				; Only 5 bit valid
		call	PICFifoWrite
		call	UART_REC_BYTE		; Get command code

PICFifoWrite

		movwf	Rs232Temp			; Save character to send
		swapf	STATUS,w
		movwf	Rs232Status			; Save Status
		movf	FSR,w				; Save FSR
		movwf	Rs232Fsr

		bsf		STATUS,IRP			; Buffer in on Bank2

		movf	PicFifoWp,w			; Get write pointer
		movwf	FSR

		movf	Rs232Temp,w			; Get char to send
		movwf	INDF				; Store it in out buffer
		incf	FSR,w				; Move the pointer
		andlw	0x1F				; in circular way
		iorlw	low(PicFifo)
		movwf	PicFifoWp
		incf	PicFifoChNum,f		; Increment number of avaible characters

Pic_Exit
		bcf 	STATUS,RP0			; Bank0
		movf	Rs232Fsr,w			; Restore FSR
		movwf	FSR
		swapf	Rs232Status,w		; Restore STATUS
		movwf	STATUS				; Restore IRP, Bank selection
		movf	Rs232Temp,w			; Get char sent / just received
		return

PIC_Send
		movlw	PIC_ADDR
		movwf	I2CSlaveAdr
		movlw	PIC_Command
		call	I2CByteReadStoreAddr
		xorlw	0xFF
		btfsc	STATUS,Z
		return
		call	PIC_RECEIVE
		btfsc	STATUS,C
		return
		goto	I2CByteWrite

PIC_RECEIVE							; Gets char into w, C == 1 if no char was in fifo
		bsf		STATUS,C			; Set no character received
		swapf	STATUS,w			; Save STATUS
		movwf	Rs232Status
		movf	FSR,w				; Save FSR
		movwf	Rs232Fsr

		bsf		STATUS,IRP			; Buffer in on Bank2

		clrf	Rs232Temp
		movf	PicFifoChNum,w		; Check number of avaible chars
		btfsc	STATUS,Z
		goto	NO_PIC_CHAR			; Jump if no character avaible

		movf	PicFifoRp,w			; Get read pointer
		movwf	FSR

		movf	INDF,w				; Read it from buffer
		movwf	Rs232Temp
		incf	FSR,w				; Move the pointer
		andlw	0x1F				; in circular way
		iorlw	low(PicFifo)
		movwf	PicFifoRp
		decf	PicFifoChNum,f		; Decrement number of avaible characters
		bcf		Rs232Status,C+4		; Valid character received - !Status was swapped!

NO_PIC_CHAR
		goto	Pic_Exit			; Restore STATUS and FSR


;******************************************************************************
; Init I2C slave and word address

InitI2CAdrs
		call	UART_REC_BYTE		; Get slave address
		andlw	0xFE				; Mask R/W bit off
		movwf	I2CSlaveAdr
		call	UART_REC_BYTE		; Get word address
		movwf	I2CWordAdr
		return

;******************************************************************************
; Set reg on I2C bus

SetI2C
		call	InitI2CAdrs
		call	UART_REC_BYTE		; Get data to be written
		call	I2CByteWrite		; Write it, increments I2CWordAdr
		decf	I2CWordAdr,f		; Correct it
		goto	SendI2CReg

;******************************************************************************
; Get reg on I2C bus

GetI2C
		call	InitI2CAdrs
SendI2CReg
		call	UART_SEND_COMMAND
		movf	I2CSlaveAdr,w
		call	UART_SEND_BYTE		; Send slave address
		movf	I2CWordAdr,w
		call	UART_SEND_BYTE		; Send word address
		call	I2CByteRead			; Read the data
		goto	UART_SEND_BYTE_CR	; Send it

;******************************************************************************
; Init FSR

InitFsr
		call	UART_REC_BYTE		; Get high part of address
		andlw	1
		movwf	Scratch
		bcf		STATUS,IRP
		btfsc	Scratch,0			; If on Bank2-3
		bsf		STATUS,IRP			; IRP=1
		call	UART_REC_BYTE		; Get low  part of address
		movwf	FSR
		return

;******************************************************************************
; Set internal reg

SetReg
		call	InitFsr				; Init FSR
		call	UART_REC_BYTE		; Get data
		movwf	INDF				; Write to reg
		goto	SendReg

;******************************************************************************
; Get internal reg

GetReg
		call	InitFsr				; Init FSR
SendReg
		call	UART_SEND_COMMAND
		movf	Scratch,w
		call	UART_SEND_BYTE		; Send high part of address
		movf	FSR,w
		call	UART_SEND_BYTE		; Send low  part of address
		movf	INDF,w				; Read reg
		goto	CLR_IRP_SEND_B_CR	; Send it

;******************************************************************************
; Set relais on time

SetRelIr
		call	UART_REC_BYTE		; Get control byte
		andlw	0x80
		movwf	Scratch3
		btfss	STATUS,Z
		goto	GetRelIr

		movlw	RTC_RelOnIr
		call	SetWordAdr
		call	UART_REC_BYTE		; Get relais on time
		movwf	RelOnIr
		call	I2CByteWrite		; Write it to RTC

GetRelIr
		call	UART_SEND_COMMAND
		movf	Scratch3,w
		call	UART_SEND_BYTE		; Send control byte
		movf	RelOnIr,w
		goto	UART_SEND_BYTE_CR	; Send relais on time

;******************************************************************************
; Clear alarm sound

SetAlmSnd
		call	UART_REC_BYTE		; Get control byte
		andlw	0x80
		movwf	Scratch3
		btfsc	Scratch3,7
		goto	GetALmSnd
		andlw	0x0F
		movwf	SoundCnt

GetALmSnd
		call	UART_SEND_COMMAND
		movf	Scratch3,w
		call	UART_SEND_BYTE		; Send control byte
		movf	SoundCnt,w
		goto	UART_SEND_BYTE_CR	; Send Sound counter

;******************************************************************************
; Get measurements

GetMeas
		call	UART_SEND_COMMAND
		movf	Light,w
		call	UART_SEND_BYTE		; Send Light
		movf	Temperature,w
		call	UART_SEND_BYTE		; Send Temperature
		movf	Humidity,w
		call	UART_SEND_BYTE		; Send Humidity

		movlw	2					; Converts measured pressure value to engineer value
		movwf	Scratch
		movwf	Scratch3
		movf	Pressure,w
		movwf	Scratch2
		movwf	Scratch4
		clrc
		rrf		Scratch,f
		rrf		Scratch2,f
		clrc
		rrf		Scratch,f
		rrf		Scratch2,w
		addwf	Scratch4,f
		btfsc	STATUS,C
		incf	Scratch3,f
		movlw	.110
		addwf	Scratch4,f
		btfsc	STATUS,C
		incf	Scratch3,f

		movf	Scratch3,w
		call	UART_SEND_BYTE		; Send Pressure high byte
		movf	Scratch4,w
		goto	UART_SEND_BYTE_CR	; Send Pressure low byte

;******************************************************************************
; Get DCF77 state

GetDCF
		call	UART_SEND_COMMAND
		movf	DCF_SNum,w			; Get number of successfull synchronizations
		call	UART_SEND_BYTE		; Send DCF77 state
		movlw	DCF_Year+1
		movwf	FSR
		call	UART_SEND_BYTE_DI	; Send DCF77 Year
		call	UART_SEND_BYTE_DI	; Send DCF77 Month

		decf	FSR,f
		movf	INDF,w				; Get DCF77 Day
		btfsc	DCF_flags,bDCFReady	; Copy status bits
		iorlw	1
		btfsc	DCF_flags,bDCFWaitSync
		iorlw	2
		call	UART_SEND_BYTE		; Send Day
		decf	FSR,f
		movf	INDF,w				; Get DCF77 Hour
		btfsc	DCF_flags,bDCFError	; Copy status bits
		iorlw	1
		btfsc	DCF_flags,bDCFParityErr
		iorlw	2
		call	UART_SEND_BYTE		; Send Hour
		decf	FSR,f
		movf	INDF,w				; Get DCF77 Minute
		btfsc	DCF_flags,bDCFSummerTime; Copy status bits
		iorlw	1
		goto	UART_SEND_BYTE_CR	; Send DCF77 Minute
									; DCF77 Seconds not transmitted

UART_SEND_BYTE_DI
		decf	FSR,f
		movf	INDF,w
		goto	UART_SEND_BYTE


;******************************************************************************
; Get/Set offsets

SetOffs
		movlw	RTC_TempOffset
		call	SetWordAdr

		call	UART_REC_BYTE		; Get control byte
		andlw	0xE0
		movwf	Scratch3
		call	UART_REC_BYTE		; Get temperature offset
		btfss	Scratch3,7
		movf	TempOffset,w
		movwf	TempOffset
		call	I2CByteWrite

		call	UART_REC_BYTE		; Get humidity offset
		btfss	Scratch3,6
		movf	HumidityOffset,w
		movwf	HumidityOffset
		call	I2CByteWrite

		call	UART_REC_BYTE		; Get pressure offset
		btfss	Scratch3,5
		movf	PressureOffset,w
		movwf	PressureOffset
		call	I2CByteWrite

;GetOffs
		call	UART_SEND_COMMAND
		movf	Scratch3,w
		call	UART_SEND_BYTE
		movf	TempOffset,w
		call	UART_SEND_BYTE		; Send temperature offset
		movf	HumidityOffset,w
		call	UART_SEND_BYTE		; Send humidity offset
		movf	PressureOffset,w
		goto	UART_SEND_BYTE_CR	; Send pressure offset


;******************************************************************************
;		DCF77 decoding
;******************************************************************************
;
;Encoding Scheme:
;----------------
;
;Encoding as follows: Pulse of 0.1s = 0, 0.2s = 1
;Numbers are encoded in BCD (binary coded decimal)
;
;Mark number(s)
;
;0				Minute, always 0 (0.1s)
;
;1-14			Reserved, always 0
;
;15				Antenna (0b normal antenna, 1b backup antenna)
;
;16				Time zone change announcement, 1 hour ahead (0b nothing, 1b change)
;
;17,18			Time zone, difference in hours against UTC (mark 18 is lsb)
;				(00b = +0h, 01b = +1h = CET, 10b = +2h = CEST, 11b = +3h)
;				In the case of transmission of UTC+1, mark 18 has a duration of 0.2s and mark 17 a duration of 0.1s.
;				If UTC+2 is being transmitted, this is reversed.
;
;19				Leap second announcement. (0b nothing, 1b change)
;				The leap second is encoded in this bit one hour prior to occurrence.
;
;20				Start bit for encoded time, always 1
;
;21-27			1, 2, 4, 8, 10, 20, 40 		minutes (mark 21 is lsb)
;
;28				P1 maintains even parity for marks 21-28
;
;29-34			1, 2, 4, 8, 10, 20			hours (mark 29 is lsb)
;
;35				P2 maintains even parity for marks 29-35
;
;36-41			1, 2, 4, 8, 10, 20			day in month (mark 36 is lsb)
;
;42-44			1, 2, 4						day in week  (mark 42 is lsb)
;
;45-49			1, 2, 4, 8, 10				month number (mark 45 is lsb)
;
;50-57			1, 2, 4, 8, 10, 20, 40, 80	year (without century) (mark 50 is lsb)
;
;58				P3 maintains even parity for marks 36-58.
;				There is no marktransmitted for the 59th second.
;
;59				Normally, this bit is not transmitted (space until bit 0,minute mark).
;				It is transmitted only when there is a leap second
;				(inserted twice per 3 years, last minute of June or December).
;
;
;Announcement bit for a leap second:
;-----------------------------------
;
;The DCF77 control unit is currently being modified so that in future an
;announcement bit for a leap second can be sent. It is expected that for
;the first time on 1st July 1985 the second mark No. 19 will be extended
;to a length of 0.2s for one hour prior to the introduction of a leap second.
;Intelligent receivers will then be able to recognize the
;discontinuity and maintain correct indicated time in spite of a 61s minute.

; Called from interrupt routine - Not to use any call because of stack linit

lDCF77Dec							; Start DCF77 decode
		incf	DCF_timer,f			; Increment 10ms timer
		btfsc	STATUS,Z			; Error if overflow
		goto	lDCFError

		clrw
		btfsc	DCF_temp,7
		movlw	1 << bDCFBit		; Get databit
		clrf	DCF_temp			; Reinit digital filter's counter
		bsf		DCF_temp,7
		xorwf	DCF_flags,w
		andlw	1 << bDCFBit		; Bit changed
		btfsc	STATUS,Z
		return						; No -> Exit

		xorwf	DCF_flags,f			; Store new bit in DCF_flags
		btfss	DCF_flags,bDCFWaitSync
		goto	lDCFSynced

lDCFNotSynced						; Not synchronized yet
		btfsc	DCF_flags,bDCFBit
		goto	lDCFClrTimer		; Amplitude is high, measure it's length

lDCFNotSync0						; Amplitude is low
		movlw	-.150/2
		addwf	DCF_timer,w			; High period was > 1500 ms
		btfss	STATUS,C
		goto	lDCFSyncWrong		; Too short - Middle of a minute - Exit

		addlw	-.50/2
		btfss	STATUS,C			; High period was > 2000 ms
		goto	lDCFSyncFound		; No - Sync period found

									; Too long
lDCFSyncWrong
		bcf		DCF_flags,bDCFReady	; Sync too long, clear data ready
		return

lDCFSyncFound
		movlw	0xFF ^ ((1 << bDCFWaitSync) | (1 << bDCFParityErr ) | (1 << bDCFParity) | (1 << bDCFError))
		andwf	DCF_flags,f			; Yes - Start, clear partity error and data ready flags and parity bit
		clrf	DCF_bitcntr			; Init bitcounter
		decf	DCF_bitcntr,f
		goto	lDCFSynced0

lDCFSynced
		btfsc	DCF_flags,bDCFBit	; Check new bit
		goto	lDCFSync1

lDCFSynced0
		movlw	-.60/2				; High period was > 600 ms
		addwf	DCF_timer,w
		btfss	STATUS,C
		goto	lDCFError			; No - Error

		incf	DCF_bitcntr,f		; Inc bit number

lDCFClrTimer
		clrf	DCF_timer			; Clear timer
		return

lDCFSync1
		movlw	-.30/2				; Low period was > 300 ms
		addwf	DCF_timer,w
		btfsc	STATUS,C
		goto	lDCFError			; Yes - Error

		movlw	-.15/2				; Low period was > 150 ms
		addwf	DCF_timer,w
		btfss	STATUS,C
		goto	lDCFSync1D0
		bsf		DCF_flags,bDCFData	; Set data bit
		goto	lDCFData

lDCFSync1D0
		movlw	-.6/2				; Low period was < 60 ms
		addwf	DCF_timer,w
		btfss	STATUS,C
		goto	lDCFError			; Yes - Error
		bcf		DCF_flags,bDCFData	; Clear data bit

lDCFData
		clrf	DCF_timer			; Clear timer
		bcf		DCF_flags,bDCFReady

		movlw	DCF_Year
		movwf	FSR					; FSR -> DCF_Year

		movlw	.58
		subwf	DCF_bitcntr,w
		btfsc	STATUS,Z
		goto	lDCFPar				; P3 parity bit - End of data
		addlw	.8					; >= .50
		btfsc	STATUS,C
		goto	lDCFShift			; Shift Year
		clrf	INDF				; Clear DCF_Year
		decf	FSR,f				; FSR -> DCF_Month
		addlw	.8					; >= .42
		btfsc	STATUS,C
		goto	lDCFShift			; Shift Month
		clrf	INDF				; Clear DCF_Month
		decf	FSR,f				; FSR -> DCF_Day
		addlw	.6					; >= .36
		btfsc	STATUS,C
		goto	lDCFShift			; Shift Day
		clrf	INDF				; Clear DCF_Day
		decf	FSR,f				; FSR -> DCF_Hour
		addlw	.1					; >= .35
		btfsc	STATUS,C
		goto	lDCFPar				; P2 parity bit - End of Hour
		addlw	.6					; >= .29
		btfsc	STATUS,C
		goto	lDCFShift			; Shift Hour
		clrf	INDF				; Clear DCF_Hour
		decf	FSR,f				; FSR -> DCF_Minute
		addlw	.1					; >= .28
		btfsc	STATUS,C
		goto	lDCFPar				; P1 parity bit - End of Minute
		addlw	.7					; >= .21
		btfsc	STATUS,C
		goto	lDCFShift			; Shift Minute
		clrf	INDF				; Clear DCF_Minute
		addlw	.1					; >= .20
		btfsc	STATUS,C
		goto	lDCFStart			; Start of time field - always 1
		addlw	.3					; == .17
		btfss	STATUS,Z
		return						; Don't care leading bits

lDCFSummer							; Winter / Summer time bit
		btfsc	DCF_flags,bDCFData
		bsf		DCF_flags,bDCFSummerTime
		btfss	DCF_flags,bDCFData
		bcf		DCF_flags,bDCFSummerTime
		return

lDCFShift
		rlf		DCF_flags,w			; Shift databit to C
		rrf		INDF,f				; Shift right register

		movlw	1 << bDCFParity
		btfsc	DCF_flags,bDCFData	;If data bit is set
		xorwf	DCF_flags,f			;   modify parity bit
		return


lDCFStart							; Start bit has to be 1
		btfss	DCF_flags,bDCFData
		goto	lDCFError
		return

lDCFPar
		movlw	1 << bDCFParity
		btfsc	DCF_flags,bDCFData	;If data bit is set
		xorwf	DCF_flags,f			;   modify parity bit

		btfsc	DCF_flags,bDCFParity
		goto	lDCFPerror			; Parity error

		movlw	.58
		xorwf	DCF_bitcntr,w
		btfsc	STATUS,Z			; Parity 3 field
		btfsc	DCF_flags,bDCFError	; If there was no error - the decoding is completed
		return

		incf	DCF_SNum,f			; Increment number of successfull synchronizations 8 bit only

		bsf		DCF_flags,bDCFReady	; Sign date and time ready and valid
		goto	lDCFNewSync

lDCFPerror
		bsf		DCF_flags,bDCFParityErr; parity error found
lDCFError
		bsf		DCF_flags,bDCFError	; Error in decoding
lDCFNewSync
		bsf		DCF_flags,bDCFWaitSync; Wait for new synchron
		return



;**********************************************************************
; PotrB write routines for I2C compatibility
; Use only these routines to copy CCPR1L to PORTB
; disable interrupts if called from other routines not from interrupt routine

XorToPortB
		xorwf	COPYB,f
ToPortB
		movf	COPYB,w
		movwf	PORTB
		return

;******************************************************************************
; String tables

InitMsg								; String tables (last character of string has bit7 set)
	dt	"Propeller clock"
CrLf
	retlw	0x0a
	retlw	0x8d					; Sign end of string - bit7 set

;******************************************************************************

	org	0x7B6

;******************************************************************************
; Jump tables

;******************************************************************************
; Return parameter count of a command

CmdParNum
	addwf	PCL,f
	retlw	.4		;'`'	0x60
	retlw	.4		;'a'	0x61
	retlw	.10		;'b'	0x62
	retlw	0		;'c'	0x63
	retlw	0		;'d'	0x64
	retlw	.6		;'e'	0x65
	retlw	.4		;'f'	0x66
	retlw	.2		;'g'	0x67
	retlw	0		;'h'	0x68
	retlw	.4		;'i'	0x69
	retlw	0		;'j'	0x6A
	retlw	.10		;'k'	0x6B
	retlw	.2		;'l'	0x6C
	retlw	.8		;'m'	0x6D
	retlw	0		;'n'	0x6E
	retlw	0		;'o'	0x6F
	retlw	0		;'p'	0x70
	retlw	.4		;'q'	0x71
	retlw	0		;'r'	0x72
	retlw	.6		;'s'	0x73
	retlw	0		;'t'	0x74
	retlw	.6		;'u'	0x75
	retlw	0		;'v'	0x76
	retlw	.2		;'w'	0x77
	retlw	.4		;'x'	0x78
	retlw	0		;'y'	0x79
	retlw	.4		;'z'	0x7A
	retlw	0		;'{'	0x7B
	retlw	0		;'|'	0x7C
	retlw	0		;'}'	0x7D
	retlw	.4		;'~'	0x7E
	retlw	.8		;''	0x7F

;******************************************************************************
; Go to execution routine of a command

CmdExec
	addwf	PCL,f			;	; Commands and parameters		; Answare
							;	; -- Time and date parameters transfered in BCD --
							;	; -- #YY, #MM, #DD, #hh, #mm, #ss, #nn, #hb, #he
			goto	SetRelIr;`	; Get / Set relais on time for ir commands
								;				'`' #Rc #Ro		; '@' #Ro
								;		Rc= Controll 0x80 for read time only
								;		Ro= Relais on time in minutes

								; Example: Send:'`8000'					Receive: '@80FF'


 			goto	XeqRc5	;a  ; Execute Rc5 command #aa #cc	; 'A' #aa #cc
								; On RC5 receive					Receive: 'Aaacc'
								;		aa= RC5 address code (5 bits)
								;		cc= RC5 command code - bit7 toggle bit

								; Example: Send:'a1d0c'				Receive: 'A1d0c'

			goto	SetDate	;b	; Set date 'b' #CC #YY #MM #DD #wd	; 'B' #CC #YY #MM #DD #wd
								;		YY= Year		00..99
								;		MM= Month 		01..12
								;		DD=	Day			01..(28,29,30,31)
								;		wd= Day of week 01..07

								; Example: Send:'b2009042007'		Receive: 'B2009042007'

 			goto	ClrSec	;c	; Clear seconds	'c'				; 'C' #hh #mm #ss
								;		hh=00..23, mm=00..59, ss=00

 								; Example: Send:'c'					Receive: 'C073000'

			goto	GetDate	;d	; Get date 'd' 					; 'D' #CC #YY #MM #DD #wd

								; Example: Send:'d'					Receive: 'B2009042007'

;;V;; For debugging only
			goto	SetI2C	;e	; Write reg on I2C 'e' #Sa #Wa #va; 'E' #Sa #Wa #va
								;		Sa= Slave address, Wa= Word address, Va=value

								; Example: Send:'ea00f20'			Receive: 'Ea00f20'

			goto	GetI2C	;f	; Read reg on I2C 'f' #Sa #Wa	; 'F' #Sa #Wa #va

								; Example: Send:'fa00f'				Receive: 'fa00f20'
;;^;; For debugging only

			goto	SetMode	;g	; Set mode 'g' #Mo				; 'G' #Mo
								;		Mo= Mode
								;	mode:	bit	0			; Auto standby timer enable
								;			bit	1			; Wake Run afther power up
								;			bit	2			; No coil drive in sleep mode
								;			bit	3			; Sound at hour change
								;			bit	4			; Hour sign mode (One sound / as many as hour (1..12))
								;			bit	5			; Send time synchron ir messages to propeller
								;			bit	6			; Enable DCF77 synchronization
								;			bit	7			; Enable reinit time from RTC at midnight

 								; Example: Send:'g01'				Receive: 'G01'

			goto	GetMode	;h	; Get mode 'h'					; 'H' #Mo
								;		Mo= Mode
								;			bit	0			; Auto standby timer enable
								;			bit	1			; Wake Run afther power up
								;			bit	2			; No coil drive in sleep mode
								;			bit	3			; Sound at hour change
								;			bit	4			; Hour sign mode (One sound / as many as hour (1..12))
								;			bit	5			; Send time synchron ir messages to propeller
								;			bit	6			; Enable DCF77 synchronization
								;			bit	7			; Enable reinit time from RTC at midnight

 								; Example: Send:'h'					Receive: 'H01'

 			goto	SetAST	;i	; Set AST 'i' #Ah #Al 			; 'I' #Ah #Al
								;			Ah:Al= 16 bit AutoStandby Time in seconds

 								; Example: Send:'i0E10'				Receive: 'I0e10'

 			goto	GetAST	;j	; Get AST 'j'  					; 'J' #Ah #Al
								;			Ah:Al= 16 bit AutoStandby Time in seconds

 								; Example: Send:'j'					Receive: 'J0e10'

			goto	SetAlarm;k	; Set alarm 'k'#nn #ff #hh #mm #uu; 'K' #nn #ff #hh #mm #uu
								;	 		nn=00..19, ff: bit7-enab; bit6..0-enable on weekday 7..1
								; 			hh=00..23, if hh==32 hour masked off from comparation
								;			mm=00..59,
								;			uu: 7: mode 0= Alarm , 6: Turn propeller on , 5: Turn propeller off , 4: Enable sound
								;			uu: 7: mode 1= Relais, 6..0= switch for (6..0) minutes; 0 minutes turns off relais

 								; Example: Send:'k01ff075000'		Receive: 'K01ff075000'
 								; Example: Send:'k01ff0750C0'		Receive: 'K01ff0750c0'

			goto	GetAlarm;l	; Get alarm 'l' #nn				; 'L' #nn #ff #hh #mm #uu
								;	 		nn=00..19, ff: bit7-enab; bit6..0-enable on weekday 7..1
								; 			hh=00..23, mm=00..59,
								;			uu: 7: mode 0= Alarm , 6: Turn propeller on , 5: Turn propeller off , 4: Enable sound
								;			uu: 7: mode 1= Relais, 6..0= switch for (6..0) minutes; 0 minutes turns off relais

 								; Example: Send:'l01'				Receive: 'L01ff075000'
 								; Example: Send:'l01'				Receive: 'L01ff0750c0'

 			goto	SetPWM	;m	; Set PWM 'm' #Cr #Pr #Cs #Ps	; 'M' #Cr #Pr #Cs #Ps #Cc #Pc
								;			Cr= CCPR1L setting for Run   mode
								;			Pr= PR2    setting for Run   mode
								;			Cs= CCPR1L setting for Sleep mode
								;			Ps= PR2    setting for Sleep mode
								;			Cc= current CCPR1L setting
								;			Pc= current PR2    setting

 								; Example: Send:'m283d0c3d'			Receive: 'M283d0c3d0c3d'

			goto	GetPWM	;n	; Get PWM 'n'  					; 'N' #Cr #Pr #Cs #Ps #Cc #Pc
								;			Cr= CCPR1L setting for Run   mode
								;			Pr= PR2    setting for Run   mode
								;			Cs= CCPR1L setting for Sleep mode
								;			Ps= PR2    setting for Sleep mode
								;			Cc= current CCPR1L setting
								;			Pc= current PR2    setting

 								; Example: Send:'n'					Receive: 'N283d0c3d0c3d'

 			goto	GetAln	;o	; Get number of alarms 'o' 		; 'O' #An #Ad #Pt
								;			An= Number of avaible alarms
								;			Ad= RC5 Address of clock
								;			Pt= Processor type  86 for 16F886
								;
								; Get number of alarms
								; Example: Send:'o'					Receive: 'O401d86'

		goto SEND_MESSAGE	;p	; Connect 'p'					; "Propeller clock"
 								; Example: Send:'p'					Receive: 'Propeller clock'

			goto	SetHSnd	;q	; Set hour sound 'q' #hb #he	; 'Q' #hb #he
								; 			hb= hour sound begin hour (bcd)
								; 			he= hour sound end   hour (bcd)

 								; Example: Send:'q0820'				Receive: 'Q0820'

			goto	GetHSnd	;r	; Get hour sound 'r'			; 'R' #hb #he
								; 			hb= hour sound begin hour (bcd)
								; 			he= hour sound end   hour (bcd)

 								; Example: Send:'r'					Receive: 'R0820'

			goto	SetTime	;s	; Set time 's' #hh #mm #ss		; 'S' #hh #mm #ss
								;		hh=00..23, mm=00..59, ss=00..59

 								; Example: Send:'s073005'			Receive: 'S073005'

			goto	GetTime	;t	; Get time 't' 					; 'T' #hh #mm #ss
								;		hh=00..23, mm=00..59, ss=00..59

 								; Example: Send:'t'					Receive: 'T073005'

;;V;; For debugging only
 			goto	SetReg	;u	; Set reg 'u' #rh #rl #vv		; 'U' #vv
								;		rh:rl=reg address, vv=value

 								; Example: Send:'u0110aa'			Receive: 'U0110aa'
;;^;; For debugging only

			goto	SendVer	;v	; Get version 'v'				; 'V' #ma '.' #mi

 								; Example: Send:'v'					Receive: 'V2.0d'

			goto	SetProp	;w	; Get/Set propeller state 'w' #wc; 'W' #ff #Rh #Rl
								;		wc=0x80 get state only
								;		wc=1 for Start
								;		wc=0 for Stop
								;		ff=flags
								;			bit	0:	in standby mode
								;			bit	1:	in sleep mode
								;			bit	2:	high power on coil
								;			bit	3:	index LED on
								;			bit	4:
								;			bit	5:
								;			bit	6:	in deep sleep mode
								;			bit	7:	time invalid
								;
								;		Rh:Rl: remaining run time in seconds

 								; Example: Send:'w01				Receive: 'W040e10'
 								; Example: Send:'w00				Receive: 'W050000'

								;  only read propeller state:
 								; Example: Send:'w80'				Receive: 'W430000'

 			goto	SetRel	;x	; Set relais 'x' #rr #vv		; 'X' #rr #vv
								;		rr=1 on, r=0 off, vv: on time in minutes

 								; Example: Send:'x0103				Receive: 'X0103'

 			goto	GetRel	;y	; Get relais 'y'				; 'Y' #rr #Rc
								;		rr=1 on, r=0 off, vv: on time in minutes

 								; Example: Send:'y0103'				Receive: 'Y0103'

;;V;; For debugging only
			goto	GetReg	;z	; Send reg 'z' #rh #rl			; 'Z' #vv
								;		rh:rl=reg address, vv=value

 								; Example: Send:'z0110'				Receive: 'Z0103aa'
;;^;; For debugging only

			goto	GetDCF	;{	; Get DCF variables '{'				; '[' #Ns #DY #DM #DD #Dh #Dm
								;		Ns= Number of succesfull synchronizations
								;		DY= bit 7..0: DCF year  (BCD)
								;		DM= bit 7..3: DCF month (BCD), bit 2..0 DCF day of week,
								;		DD= bit 7..2: DCF day   (BCD), bit 1: Wait for DCF77 minute synchron, bit 0: DCF time and date ready and valid
								;		Dh= bit 7..2: DCF hour  (BCD), bit 1: Error in decoding             , bit 0: Parity error
								;		Dm= bit 7..1: DCF minute(BCD). bit 0: Last time decoded used Summer time (CEST)

								; Example: Send:'{'						Receive: '[0009A7311234'


			goto	GetMeas	;|	; Send measures '|'					; '_'  #Lt #Tp #Fh #Ph #Pl
								;		Lt= Light
								;		Tp= Temperature
								;		Hy= Humidity
								;		Ph= Air pressure bit 9..8
								;		Pl= Air pressure bit 7..0

								; Example: Send:'|'						Receive: '_011A2002FD'

	return					;}	;

			goto	SetAlmSnd;~	; Set alarm sound	'~'	#Cb #Sc			; '^' #Cb #Sc
								;		Cb= 0x80 for clear alarm sound
								;		SC= Sound counter

								; Example: Send:'~80'					Receive: '^8000'

			goto	SetOffs;	; Get/Set offsets '' #Ct #To #Ho #Po	; '\' #Ct #To #Ho #Po 
								;		Cb= Controll
								;			bit 7: for set temperature offset
								;			bit 6: for set humidity    offset
								;			bit 5: for set pressure    offset
								;		To= Temperature offset
								;		Ho= Humidity offset
								;		Po= Pressure offset

	org		0x7F8

;******************************************************************************
; Get next character of a string

MsgTabl
		movf	Rs232StrPtrH,w		; Get string pointer high byte
		movwf	PCLATH				; Load it to PCLATH
		movf	Rs232StrPtr,w		; Get string pointer low  byte
		incfsz	Rs232StrPtr,f		; Increment pointer as
		goto	lString1
		incf	Rs232StrPtrH,f		; 16 bit number
lString1
		movwf	PCL					; Computed goto to string table
		return						; movwf	PCL cannot be the last instruction

;====== E N D   O F   2 K  P A G E ============================================

	org	0x0800

;******************************************************************************

JDNTabl
; 	(.153 * m + 2) div 5, Add 256 for last 3 in Scratch2:W
;	m	 0     1     2     3    4     5     6     7     8      9         10         11
	DT	.0  , .31 , .61 , .92 ,.122 ,.153 ,.184 ,.214 ,.245 ;;.256+.19 , .256+.50 , .256+.81
	addlw	low(.19-.49)		;  9
	addlw	low(.50-.80)		; 10
JDNTabl11
;	addlw	low(.81-$); 11
	addlw	low(.81-low(JDNTabl11-JDNTabl)); 11
	incf	Scratch2,f
	return

;******************************************************************************
;		DCF77 synchronizing - copy DCF's date and time to clock's variables
;******************************************************************************

DCFDayHour
		decf	FSR,f				; Move to next DCF data
		rrf		INDF,w				; Get data >> 1
		movwf	Scratch
		rrf		Scratch,w			; Get data >> 2
		andlw	0x3F				; Mask high bits off

BcdToBin_2K
		clrf	PCLATH				; Page0
		call	BcdToBin			; DCF77 uses BCD encoding
		bsf		PCLATH,3			; Page1
		return

DCFCopy
		movlw	DCF_Year			; Time variable are in Bank0, DCF are in Bank1
		movwf	FSR					; Indirect access to DCF time variables
									; FSR -> DCF_Year
		movf	INDF,w				; Get DCF Year
		call	BcdToBin_2K			; DCF77 uses BCD encoding
		xorwf	Year,w
		movwf	Scratch2			; Init change flag
		xorwf	Year,f
		decf	FSR,f				; FSR -> DCF_Month
		rrf		INDF,w				; Get DCF Month
		movwf	Scratch				; Shift month to bit0
		rrf		Scratch,f
		rrf		Scratch,w
		andlw	0x1F				; Keep month only
		call	BcdToBin_2K			; DCF77 uses BCD encoding
		xorwf	Month,w
		iorwf	Scratch2,f			; Modify change flag
		xorwf	Month,f
		call	DCFDayHour			; Get DCF Day
									; FSR -> DCF_Day
		xorwf	Day,w
		iorwf	Scratch2,f			; Modify change flag
		xorwf	Day,f
		call	DCFDayHour			; Get DCF Hour
									; FSR -> DCF_Hour
		xorwf	Hour,w
		iorwf	Scratch2,f			; Modify change flag
		xorwf	Hour,f
		decf	FSR,f				; FSR -> DCF_Minute
		rrf		INDF,w				; Get DCF Minute
		andlw	0x7F
		call	BcdToBin_2K			; DCF77 uses BCD encoding
		xorwf	Minute,w
		iorwf	Scratch2,f			; Modify change flag
		xorwf	Minute,f
		clrc
		rrf		Second2,w
		iorwf	Scratch2,f			; Modify change flag
		clrf	Second2				; Seconds are always 0

		bcf		DCF_flags,bDCFReady	; DCF data processed, Clear DCF data ready

		clrf	PCLATH				; Page0
		call	InitSubSecCnt		; Synchronize subsec counter
		bsf		PCLATH,3			; Page1

		bsf		Rs232Flags,bTimeSet	; Sign time has to be saved
		movf	Scratch2,f
		btfss	STATUS,Z
		bsf		flags,bNewTime		; Set new time ready if different time was received
		return

CalcWDay							; Calculates day of week
		clrf	Scratch
		clrf	Scratch2
		clrf	Scratch3
		movf	Day,w				; Day changes at 00:00
		movwf	Scratch4

;Year16bit							; Convert Centuty and Year to a 16 bit word in Rs232Temp:Rs232Status
		movf	Year,w
		movwf	Rs232Status
		clrf	Rs232Temp
		movf	Century,w
		movwf	BCD
		btfsc	STATUS,Z
		goto	ClearCy_2K
l_year16
		movlw	.100
		addwf	Rs232Status,f
		btfsc	STATUS,C
		incf	Rs232Temp,f
		decfsz	BCD,f
		goto	l_year16
ClearCy_2K
		clrc						; Rs232Temp:Rs232Status = .100 * Century + Year

JDN									; Returns Julian Day Number
									; Scratch .. Scratch3 cleard before call
									; For WDay and SDate calculation Scratch4 = Day
									; For JDN if Hour < .12 then (Day - 1) else Day

		movf	Month,w
		addlw	-.3
		movwf	BCD
		btfss	BCD,7
		goto	Dnum
		movlw	.12
		addwf	BCD,f
		bsf		STATUS,IRP			; IRP = a = (.14 - Month) div .12
Dnum								; BCD = m = Month + 12 * a - 3
		call	GetDn
		addwf	Scratch4,w			; Add the day
		movwf	Scratch3			; Scratch2:Scratch3 = day + (.153 * m + 2) div 5
									; C = 0
		btfsc	STATUS,IRP
		decfsz	Rs232Status,f
		goto	SetY
		decf	Rs232Temp,f			; Rs232Temp:Rs232Status = .100 * Century + Year - a
SetY
		rrf		Rs232Temp,w
		movwf	BCD
		rrf		Rs232Status,w
		movwf	Scratch4			; BCD:Scratch4 = (.100 * Century + Year - a) div 2

Mul365
		movlw	low(.365)
		addwf	Scratch3,f
		movlw	high(.365)
		call	ChkCy_2K
		addwf	Scratch2,f
		btfsc	STATUS,C
		incf	Scratch,f
		decfsz	Rs232Status,f
		goto	Mul365
		decf	Rs232Temp,f
		btfss	Rs232Temp,7
		goto	Mul365
									; Scratch:Scratch2:Scratch3 = day + ((.153 * m +2) div 5) + .356 * (.100 * Century + Year - a)
		movlw	0x1F
		addwf	Scratch3,f
		movlw	0x43
		call	ChkCy_2K
		addwf	Scratch2,f
		movlw	0x1A
		call	ChkCy_2K
		addwf	Scratch,f			; Scratch:Scratch2:Scratch3 = day + ((.153 * m +2) div 5) + .356 * (.100 * Century + Year - a) +
									; .365 * .4800 + (.4800 div 4) - (.4800 div .100) + (.4800 div 400) - .32045
									; C = 0
		rrf		BCD,f
		rrf		Scratch4,f			; BCD:Scratch4 = (.100 * Century + Year - a) div 4

		movf	Century,w			; W = (.100 * Century + Year) div .100 = Century
		btfss	STATUS,IRP
		goto	Ymod100
		movf	Year,f
		btfsc	STATUS,Z			; Correct W if Year = 0
		addlw	-1
Ymod100
		movwf	Rs232Status			; Rs232Status = W = (.100 * Century + Year - a) div .100
		subwf	Scratch4,f
		btfss	STATUS,C
		decf	BCD,f				; BCD:Scratch4 = (.100 * Century + Year - a) div 4 - (.100 * Century + Year - a) div .100
		rrf		Rs232Status,f
		rrf		Rs232Status,w
		andlw	0x3F				; W = (.100 * Century + Year - a) div .400
		addwf	Scratch4,w
		btfsc	STATUS,C
		incf	BCD,f
		addwf	Scratch3,f
		movf	BCD,w
		call	ChkCy_2K
		addwf	Scratch2,f
		btfsc	STATUS,C
		incf	Scratch,f			; Scratch:Scratch2:Scratch3 = (.100 * Century + Year - a) div 4 - (.100 * Century + Year - a) div .100 +  (.100 * Century + Year - a) div .400
		clrf	STATUS				; Clear IRP

FXD3216UBy700
		clrf	Rs232Fsr			; 256*JDN / 0x700
		clrf	Scratch4
		movlw	7
FXD3216U_StoreDivH
		movwf	I2CSlaveAdr			; At return W and Rs232Temp holds WDay (0 - Monday, 6 - Sunday)

;Inputs:
;   Dividend - Scratch:Scratch2:Scratch3:Scratch4 - Scratch is the most significant
;   Divisor  - I2CSlaveAddr:Rs232Fsr
;Temporary:
;   Counter  - BCD
;   Remainder- Rs232Temp:Rs232Status
;Output:
;   Quotient - Scratch:Scratch2:Scratch3:Scratch4
;

FXD3216U
		CLRF	Rs232Status			; Clear result
		CLRF	Rs232Temp
		MOVLW	.32
		MOVWF	BCD

LOOPU3216
		RLF		Scratch4,F
		RLF		Scratch3,F			;shift left divider to pass next bit to remainder
		RLF		Scratch2,F			;and shift in next bit of result
		RLF		Scratch,F

		RLF		Rs232Status,F		;shift carry into remainder
		RLF		Rs232Temp,F

		RLF		BCD,F				;save carry in counter

		MOVF	Rs232Fsr,W			;substract divisor from remainder
		SUBWF	Rs232Status,F
		MOVF	I2CSlaveAdr,W
		BTFSS	STATUS,C
		INCF	I2CSlaveAdr,W
		SUBWF	Rs232Temp,W			;keep that byte in W untill we make sure about borrow

        SKPNC						;if no borrow
		BSF		BCD,0				;set bit 0 of counter (saved carry)

		BTFSC	BCD,0				;if no borrow
		GOTO	UOK46LL				;jump

		MOVF	Rs232Fsr,W			;restore remainder if borrow
		ADDWF	Rs232Status,F
		MOVF	Rs232Temp,W			;read high byte of remainder to W
									;to not change it by next instruction
UOK46LL
		MOVWF	Rs232Temp			;store high byte of remainder
		CLRC						;copy bit 0 to carry
		RRF		BCD,F				;and restore counter
		DECFSZ	BCD,f				;decrement counter
		GOTO	LOOPU3216			;and repeat loop if not zero

		RLF		Scratch4,f			;shift in last bit of result
		RLF		Scratch3,F
		RLF		Scratch2,F
		RLF		Scratch,F
		RETURN

;******************************************************************************
; Get number of days for JDN

GetDn
		movlw	high(JDNTabl)
		movwf	PCLATH
		movf	BCD,w
		addlw	low(JDNTabl)
		movwf	PCL

ChkCy_2K
		btfsc	STATUS,C
		addlw	1
		return


; Deapest Stack 					; These processors have an 8 level stack
;	1	call	UARTCmdDec
;	2	call	TimeCheck
;	3	call	I2CByteWrite
;	4	CALL 	OUT_BYTE
;	5	CALL 	CLOCK_PULSE
;	6	CALL 	HIGH_SCL
;	7	Interrupt routine
;	8	one call from interrupt routine


;******************************************************************************
;		Define EEProm content
;******************************************************************************


		ORG		0x2100			; Start of message 1 in EEPROM
		de		"Propeller Clock Base ",LastUpdate," ",ProcType," V",VersionMajor+.48,".",((VersionMinor/.16)+.48),((VersionMinor%.16)+.48)


	END                     		; directive 'end of program'
