	list b=4
;************************************************************************
; 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. I used a bit more powerfull version of PIC cpu and added 	*
; these features:														*
;  - the clock keeps time AND DATE and Day of week     					*
;  - can display analogue hands or digital time and mixed mode where	*
;    time is displayed as analogue hands and digital date				*
;  - setting the time/date or switch mode is done by RC5 remote control	*
;  - possibility to display a message programmed in ROM or EEPROM		*
;                                                                 		*
;************************************************************************
;                                                               		*
;    Filename:	    prop_bright.asm										*
;					dd/mm/yyyy	                                    	*
;    StartDate:     02/12/2001                                        	*
;    LastUpdate:    20/12/2011											*
#define	VersionMajor	0x04	;										*
#define	VersionMinor	0x53	;										*
;#define	DebugI2C	; comment this line to compile release version	*
;                                                                     	*
;  Based on:                                                         	*
;    Author:        Soubry Henk                                       	*
;    Company:       Soubry Software Service                           	*
;                                                                     	*
;	PCB: by Patexati, Schematic and Software by Hp41C					*
;			 form www.hobbielectronika.hu								*
;                                                                     	*
;  Ported to 16F886 and extended with:				             		*
;                                                                     	*
;	 Hardware can be used with 28 pin 18Fxxxx controllers				*
;    Modified to drive more 26 LEDs: 6 + 3 + 3 inner LEDs				*
;    Separate (may be different colour) led for ticks, second hand		*
;	 8 dot heigh characters												*
;	 Displays day of week (1 = Monday), century, age of Moon			*
;	 Day of week and age of Moon are calculated from Julian Day Number	*
;    Name of weekdays on 16 languages (see Daynames.asm)				*
;	 Selectable date formats: (CC)YY-MM-DD or DD-MM-(CC)YY				*
;    12/24 hour digital/analogue display mode							*
;	 All digital display can use Binary Coded Decimal format			*
;	 Individualy controllable analogue hands							*
;	 Dot/arc second hand, bar/dot minute and hour hand option			*
;	 Doubble/single tick at 12'o clock and 0'o clock in 24 hour format	*
;	 III, VI, IX, XII signs on analogue clock in 12 hour mode			*
;	 Temperature measurement displaied with day of week					*
;	 PWM brightness controll with night and daytime settings			*
;	 Brightness setting with +/-1 and +/-16								*
;	 Light measurement for automatic brightness controll				*
;	 Rotation speed displaied with brightness settings					*
;		Brightness: ll m dd c nn										*
;		ll : Light limit in hexadecimal									*
;			 Brightness step size:	1		16							*
;		 m : Brightness mode:											*
;				night always :		n		N							*
;				daily always :		d		D							*
;				timed		 :		t		T							*
;				light based	 :		l		L							*
;		dd : Daily brightness in hexadecimal							*
;		 c : Currently used brigthness 									*
;				night		 :		>									*
;				daytime		 :		<									*
;		nn : Night brightness in hexadecimal							*
;	 Two scrolling message with adjustable speed						*
;	 Scrolling display with												*
;		date, time, name of weekday, temperature, age of Moon			*
;	 Static picture display - 32 picture can be stored					*
;		00 		: Zodiac ring with actual symbol at top					*
;		01 		: "Propeller Clock" 									*
;		02 - 0F : User pictures											*
;		10 - 1F : Slideshow	picture										*
;	 Slide show option with pictures 16..31: plays Towers of Hanoi		*
;	 Analog time with inner leds can be displaied during scrolling and	*
;	    static picture 													*
;	 Store time and settings in a PCF8583 I2C RTC						*
;	 4 / 8 favorite display setting can be stored in RTC,				*
;		and restore later (4 set option to reduce command count)		*
;		( Store / Restore command have to be consecutive codes,			*
;		 the least significant 2/3 bits of commands used as index)		*
;  Options:																*
;	 Calibration pin can be used to select motor rotation direction		*
;		pull up/down with 10k resistor									*
;	 Light controll for higher/lower code meas darker					*
;                                                                     	*
;************************************************************************
;                                                                    	*
;    Files required: CharGen.asm                                      	*
;                    Keys.asm  	                                      	*
;                    DayNames.asm                                      	*
;                    Zodiac.asm                                      	*
;                                                                     	*
;************************************************************************
;                                                                     	*
;    Notes:                                                           	*
;    	Pin assignment                                                	*
;      		Port A                                             			*
;				0 = Light measurement		A/D channel analogue 		*
;       		1 = Calibration output - Rot dir input at reset			*
;											H =	Counter Clock Wise		*
;											L = Clock Wise				*
;											use 4k7-10k pull up/down 	*
;       		2 = Analog Led group 0	inner			output			*
;       		3 = Analog Led group 1					output			*
;       		4 = Analog Led group 2					output			*
;       		5 = Analog Led group 3	outer			output			*
;			  6.7 = 20MHZ Oscillator 					inputs			*
;                                                                     	*
;      		Port B 														*
;				0 = Index		use 10k pull up to Vdd	input			*
;               1..7 = Display led's (1=inner, 7=outer)	output			*
;                                                                     	*
;      		Port C 														*
;				0 = Inner display led (because RB0 - INT is index)		*
;               1 = Analogue ticks led					output			*
;               2 = CCP1 PWM brightness controll 		output			*
;               3 = I2C SCL		use 2k7 pull up to Vdd	must be input	*
;               4 = I2C SDA 	use 2k7 pull up to Vdd	must be input	*
;               5 = Data receive 	not used yet		input			*
;               6 = Second hand led						output			*
;               7 = Outer led							output			*
;                                                                     	*
;      		Port E 														*
;				3 = IR receiver: Attention at ICSP		input			*
;                                                                     	*
;************************************************************************
;																		*
;  RTC Ram layout														*
;	00		01		02		03		04		05		06		07			*
;	Cmd		1/10	Sec		Minute	Hour	Day		Month	Timer		*
;			1/100							Year1.0	Wday	10Day/Day	*
;			sec												not used	*
;																		*
;	08		09		0A		0B		0C		0D		0E		0F			*
;	A	L	A	R	M		R	E	G	I	S	T	E	R	S			*
;						Not used										*
;																		*
;	10		11		12		13		14		15		16		17			*
;	Year	~Year	Century	Flags	Disp	Scroll	Flags3	Flags4		*
;									offs	sp Lang						*
;																		*
;	18		19		1A		1B		1C		1D		1E		1F			*
;	Bright	Flags5	Scroll	Pict	Bright	Bright	Bright	Light		*
;	step			flags			mode	Daytime	Night	level		*
;																		*
;	20		21		22		23		24		25		26		27			*
;					Display settings set #0								*
;																		*
;	ind		f5		f		f3		f4		LgSs	Pn		scfl		*
;																		*
;	28		29		2A		2B		2C		2D		2E		2F			*
;					Display settings set #1								*
;																		*
;	30		31		32		33		34		35		36		37			*
;					Display settings set #2								*
;																		*
;	38		39		3A		3B		3C		3D		3E		3F			*
;					Display settings set #3								*
;																		*
;	40		41		42		43		44		45		46		47			*
;					Display settings set #4								*
;																		*
;	48		49		4A		4B		4C		4D		4E		4F			*
;					Display settings set #5								*
;																		*
;	50		51		52		53		54		55		56		57			*
;					Display settings set #6								*
;																		*
;	58		59		5A		5B		5C		5D		5E		5F			*
;					Display settings set #7								*
;																		*
;	60		..		..		..		..		..		..		FF			*
;						Not used										*
;																		*
;************************************************************************
;	Ir Remote control keys												*
;																		*
;	See keys.asm and keys.txt											*
;																		*
; Afther time setting Toggle Outer Led command stores time to RTC		*
;************************************************************************

	errorlevel	-302
	errorlevel	-306

;***** VARIABLE DEFINITIONS

;#define MotorDirFromCalibration	; un-comment this line if get motor direction from calibration pin
#define	MotorCounterClockWise	; un-comment this line if motor is running counter clockwise
;#define ReversTextScroll		; un-comment this line if your text must scroll from left to right (e.g. Hebrew)
;#define SlashedZero			; comment this line to use normal zero
;#define RC5AddrCheck			; comment this line if RC5 Address checking not required
;#define	GreatherMeansDarker		; comment this line if least code means darker
;#define	Use4SavingOnly			; un-comment this line if 4 setting sets to use only

#define UseAnalog24Mode			; Comment this line if not to use analog 24 hour mode
#define SeparateHandHandling	; Comment this line to handle analog hands together
#define UseLightLimitSetting	; Comment this line if light limit setting not required by RC5 commands
#define	UseBrightModeSetting	; Comment this line if bright mode setting not required by RC5 commands
#define	UseBrightStepSetting	; Comment this line if bright step setting not required by RC5 commands
#define	UseZodiacRing
#define	UseAgeOfMoon
#define DISPLAYOFFSET	0x37	; Initial Display Offset for the hardware (display memory address) !!!
#define TEMPR_OFFSET	0x00	; Teperature offset

	list	p=16f886            ; list directive to define processor
	#include <p16f886.inc>      ; processor specific variable definitions

	#include "CharGen.asm"
	#include "my_keys.asm"
;	#include "Keys_URC.asm"
;	#include "keys_URC22B_modositott.asm"
	#include "DayNames.asm"
;	#include "Zodiac_DV.asm"
	#include "Zodiac.asm"

	__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

	__idlocs		0xA000 | (VersionMajor << 8) | (VersionMinor)

;F_OSC	EQU	.20000000			; Oscillator frequency in Hz

;***** RTC VARIABLE DEFINITIONS

RTC_ADDR	EQU	0xA0			; Address of RTC A0 - 0
;RTC_ADDR	EQU	0xA2			; Address of RTC A0 - 1

;#define	RTC_Control	0x00	; Control register
#define RTC_Tenms		0x01	; Address of 1/100 Seconds
#define	RTC_Second		0x02	; Address of Second
;#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_Year        0x10    ; Address of Year
#define RTC_YearNeg     0x11    ; Address of negated value of Year
#define RTC_century		0x12	; Address of century
#define	RTC_flags		0x13	; Address of flags
#define	RTC_disp_off	0x14	; Address of DispOffset
#define RTC_ScrollSp	0x15	; Address of Scroll speed and language
#define	RTC_flags3		0x16	; Address of flags3
#define	RTC_flags4		0x17	; Address of flags4
#define	RTC_BrightStep	0x18	; Address of Brightness step size
#define	RTC_flags5		0x19	; Address of flags5
#define	RTC_Scrollflags	0x1A	; Address of Scroll flags
#define	RTC_PictNum		0x1B	; Address of Picture number
#define	RTC_BrightMode	0x1C	; Address of Brightness mode
#define	RTC_BrightDay	0x1D	; Address of Brightness Daytime
#define	RTC_BrightNight	0x1E	; Address of Brightness Night
#define	RTC_LightLimit	0x1F	; Address of Light level
#define	RTC_SettingSets	0x20	; Address of saved setting sets 8 sets with 8 bytes each
;					0x60..0xFF	; Not used

;MCP9800_ADDR	EQU		0x90	; MCP9800A0T	I2C address is 0
MCP9800_ADDR	EQU		0x96	; MCP9800A3T	I2C address is 3
;MCP9800_ADDR	EQU		0x9A	; MCP9800A5T	I2C address is 5

;Display 	Low byte	High byte
;DispI		0x020		0x120	; 2*40 bytes from 0x20 -> 0x48 and 0x120 -> 0x148
;DispII		0x0A0		0x1A0	; 2*80 bytes from 0xA0 -> 0xF0 and 0x1A0 -> 0x1F0

; Common memory 0x070-0x07F, 0x0F0-0x0FF, 0x170-0x17F, 0x1F0-0x1FF

;Vars in shared memory. This memory is accessable from any bank
  cblock	0x70
	Scratch						; memory locations for general use
	Scratch2					;
	Scratch3					;
	Scratch4					;
	Scratch5
	Scratch6

;Vars for building display-content
	BCD							; Binary coded decimal
	BCD_High					;   high part
	digitindex					; Index digit to display
	dotindex					; Index dot   to display
	tdd							; Temporary display data
	tddH						;   high part

	flags						; Digital display flags
	flags2						; System  flags

	RC5_flags					; RC5 receiver state bits

; No more location
	w_temp						; variable used for context saving
LastCommon:
  endc

	IF LastCommon > 0x80
		ERROR "To many variables used in Common area"
	ENDIF

  cblock	0x70-.11
;Vars for time-keeping
  ;!! Keep variable order - indirect access used to access 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
	WDay						; Day of week 0..6 - displayed as 1..7 : Monday is 1
	Tempr						; Temperature
	Language					; Language and scroll speed
	PictNum						; 32 pictures: Pict0 is Zodiac ring, Pict1: "Propeller Clock",
  ;!! Keep variable order - indirect access used to access them ^
LastTime:
  endc
	IF LastTime > 0x70
		ERROR "To many variables used in Time area"
	ENDIF

;Vars for display timing routines and interrupts
  cblock	0x20
    DispI: .40					; Display data 0..39
	PeriodCnt_H					; 16 bit counter counts number of TMR0 interrupt
	PeriodCnt_L					; between index-pulses (one revolution)

  ;!! Keep variable order - indirect access used to them v
	StorePCnt1_H				; first  16 bit storage for PeriodeCounter
	StorePCnt1_L				;
	StorePCnt2_H				; second 16 bit storage for PeriodeCounter
	StorePCnt2_L				;
  ;!! Keep variable order - indirect access used to them ^

	SubSec_H					; 16 bit sub-second counter
	SubSec_L					; there are 2500 sub-seconds in 1/2 second

	PixelWidth					; Pixel-width = number of TMR0 interrupts in one ON pixel
	PixelOff					; 8 bit down-counter to time PixelWidth

	NewPixelWidth				; Pixel-width calculated by main programm

	PixelPitch_L				; PixelPitch =  8 bit number of interrupts between two pixel
	PixelPitch_F				; Fraction of PixelPitch needed for accuracy and to avoid jitter

	NewPPitch_L					; New pixel pitch calculated by main programm, will be
	NewPPitch_F					; copied to PixelPitch by interrupt routine

	NextPixel_H					; Next pixel @ PeriodCnt = NextPixel
	NextPixel_L					;
	NextPixel_F					;

	RoundedNext_L				; RoundedNext = Round(NextPixel)
	RoundedNext_H				;

	DispOffset					; Display offset compared to indexpulse

	TmrScroll					; Count Down timer for scroll delay

	dpi							; 0..119 display index for main program

	flags3						; Analogue display flags
	flags4

	iFSR						; Display buffer memory pointer used by interrupt routine

	DMon						; Days in current Month + 1
	TickPos						; Position of tick on analog clock

	Scratch7
; No more location

LastBank0:
  endc

	IF LastBank0 > Second2
		ERROR "To many variables used in Bank 0"
	ENDIF

; start a new block of vars in bank1
  cblock	0xA0
	DispII:	.80					; Display data 40..119
; No more location
  endc

; start a new block of vars in bank2

  cblock	0x110				; Bank 2 - 16 bytes
; 16 more location
  endc

  cblock	0x120				; Bank 2 - 80 bytes
	DispIHigh:	.40				; Display high data 0..39

	ch_slidecnt					; Slidshow timing counter

;	ch_dot_point_H				; pointer the the current dot# in a character			- BCD_High
;	ch_dot_point_L				; points the the chargenerator table					- BCD
;	ch_dot_index				; index of dot# in a char								- dotindex
;	ch_blanking					; counter for blanking the display when scrolling text	- EEADRH

	ch_flags					; Scroll flags	- Used by ScrollText
	ch_flags_RC5				; Scroll flags	- Set by RC5 receiver

	AD_state					; A/D delay state

	Light						; External light
	BrightMode					; Brightness controll mode
	LightLimit					; External light limit
	BrightDay					; Brightness value for daytime
	BrightNight					; Brightness value for night
	BrightStep					; Step size for limit and brightness settings

;Vars for RC5 decoding
	RC5_Tmr						; Time counter
	RC5_BitCnt					; Bit  counter
	RC5_Addr					; Received address
	RC5_Cmd						; Received command code
	RC5_Cmd2					; storage for previous cmd

	RotBuffer_L					; Rotation count buffer
	RotBuffer_H
	Rotation_L					; Rotation count for display routine
	Rotation_H					;

; 7 more location
	pclath_temp					; variable used for context saving
	fsr_temp					; variable used for context saving
	status_temp					; variable used for context saving
LastBank2:
  endc

	IF LastBank2 >= (Second2+0x100)
		ERROR "To many variables used in Bank 2"
	ENDIF

  cblock	(Second2+0x100)
  ; Second2_sc must be at address 0x100 + Second2
  ;!! Keep variable order - indirect access used to access them v
	Second2_sc					; 0..119 counting half seconds
	Minute_sc					; 0.. 59
	Hour_sc						; 0.. 23
	Day_sc						; 1.. Dmon-1
	Month_sc					; 1.. 12
	Year_sc						; 0.. 99
	Century_sc					; 0.. 99
	WDay_sc						; Day of week 0..6 - displayed as 1..7 : Monday is 1
	Tempr_sc					; Temperature
	Language_sc					; A copy of language code during scrolling
	PictNum_sc
  ;!! Keep variable order - indirect access used to access them ^

; No more location
  endc

	IF  RC5_Cmd2>= 0x170
		ERROR "To many variables used in Bank 2"
	ENDIF

; start a new block of vars in bank3
  cblock	0x190				; Bank 3 - 16 bytes
; 16 more location
  endc

  cblock	0x1A0				; Bank 3 - 80 bytes
	DispIIHigh:	.80				; Display high data 40..119
; No more location
  endc

;**********************************************************************
; Give meaningfull names to locations

; 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

ch_dot_index	EQU	dotindex
ch_blanking		EQU	EEADRH

Scratch8		EQU	CCPR2L
Scratch9		EQU	CCPR2H

;**********************************************************************
; define Port bits

;;; Bank 0

; Port A
bLightCh		EQU	0			; bit 2 analogue input	Light
bCalibration	EQU	1			; Square wave output 2.5 kHz / Motor dir input at reset - 10k pull up/down
bAnalogL0		EQU	2			; Analog led goup 0
bAnalogL1		EQU	3			; Analog led goup 1
bAnalogL2		EQU	4			; Analog led goup 2
bAnalogL3		EQU	5			; Analog led goup 3
;								; bit 6..7 used for oscillator

; Port B
bIndexPuls		EQU	0
;								; bit 7..1 used for pixel data output
bHourLED		EQU	6
bMinLED			EQU	7

; Port C
bPixel0			EQU	0			; Lsb of pixel data
bTicksLED		EQU	1			; Analog tick led
bBrightPWM		EQU	2			; PWM brightness controll output
bSCL			EQU	3			; used by MSSI
bSDA			EQU	4			; used by MSSI
bData			EQU	5			; Data receiver input
bSecLED			EQU	6			; Analog second led
bOuterLED		EQU	7			; Outer led

; Port E
bRC5inp			EQU	3			; RC5 infra receiver input, active low

; TMR1L, TMR1H	used to count rotation speed

; T1CON
bMotorDirCC		EQU	1			; Direction of motor rotation  -  Read at reset from PORTC,bCalibration
bTimeSet		EQU 2			; Time setting commands were received
bNewRot			EQU	4			; New rotation count available
bPStorage		EQU	5			; Rotation time measurement buffer select
bRotAvailable	EQU	6			; A rotation measurement done afther power on
;				EQU	7

; CCP1CON						; Brightness controll
;				EQU	0			; Used by 18F886 extended CCP modul
;				EQU	1
;bPWMmode0		EQU	2			; PWM mode set Mode b00xx1100
;bPWMmode1		EQU	3			;
;				EQU	4			; Can be used to store data
;				EQU	5			; Can be used to store data
;					6			; Not implemented on normal CCP module.  Used by 18F886 extended CCP modul
;					7			; Not implemented on normal CCP module.  Used by 18F886 extended CCP modul

; CCPR1H						; Used by PWM hardware
Brightness		EQU	CCPR1L		; Stores actual Brightness code for PWM

; CCP2CON						; Not used
;				EQU	0			; Used by 18F886 normal CCP modul
;				EQU	1			;
;				EQU	2			; PWM mode set Mode --xx0000
;				EQU	3			;
;				EQU	4			; Can be used to store data
;				EQU	5			; Can be used to store data
;					7..6		; Not implemented on normal CCP module

; define flags3 bits			; Analogue Display flags
bShow36912		EQU	0			; Show  / hide drawing III, VI, IX, XII around the clock
bSecMode		EQU	1			; Dot   / Arc second  hand
bMinMode		EQU	2			; Dot   / Bar minute  hand
bHourMode		EQU	3			; Dot   / Bar hour    hand
bShowSecHand	EQU	4			; Show  / hide second hand
bShowMinHand	EQU	5			; Show  / hide minute hand
bShowHourHand	EQU	6			; Show  / hide hour   hand
bAnalMode24h	EQU	7			; 24    / 12 hour mode

; define flags4	bits			; More analogue display flags
bAnalogClk		EQU	0			; Show analog clock using inner led groups
bShowTicks		EQU	4			; Show   / hide ticks
bSTick12		EQU	5			; Single / double tick at 12'o clock

;;; Common

; define flag bits				; Digital Display flags
bShowOuter		EQU	0			; Show / hide outer ring
bShowDayName	EQU	1			; Show   day's name instead day of week, temperature, age of Moon
bDisp12Mode		EQU	2			; 12   / 24 hour mode
bDateFormat		EQU	3			; Use YYYY-MM-DD / DD-MM-YYYY or YY-MM-DD / DD-MM-YY date format
bShowWDay		EQU	4			; Show / hide day of week, temperature, age of Moon
bShowDTime		EQU	5			; Show / hide digital time
bShowDDate		EQU	6			; Show / hide digital date
bShowCentury	EQU	7			; Show / hide century

; define flag2 bits				; System flags
bDspEnabled		EQU	0			; Blank the display - motor slow or not stabilized
bNewPCnt		EQU	1			; New pitch calculated
bNewTime		EQU	2			; New time calculated
bNewPPitch		EQU	3			; New pitch measured
bText			EQU	4			; Text on display
bScrollOn		EQU	5			; Scrolling text on display
bDemo			EQU	6			; Demo mode active
bTimeInv		EQU	7			; Time invalid

; RC5 flags
bRC5_WaitStart	EQU	0
bRC5_DataReady	EQU	1
bRC5_HalfBit	EQU	2
bRC5_prev_inp	EQU	bRC5inp		; Has to be on same bit as bRC5inp on PORT
bRC5_Idle		EQU	4
bRC5_ReSynced	EQU	5
								; Interrupt routine keeps the values of these bits
								; Not RC5 related bits, but must be in common ram
bBCDMode		EQU	6			; Binary display mode
bUseBinFont		EQU	7			; Numerical character to display in Binary mode

	if (bRC5_prev_inp==bRC5_WaitStart) | (bRC5_prev_inp==bRC5_DataReady) | (bRC5_prev_inp==bRC5_Idle) | (bRC5_prev_inp==bRC5_HalfBit)
		error "RC5 input configuration error"
	endif
	if (bRC5_prev_inp==bRC5_ReSynced) | (bRC5_prev_inp==bBCDMode) | (bRC5_prev_inp==bUseBinFont)
		error "RC5 input configuration error"
	endif

;;; Bank2

; BrightMode					; Brightness controll
bBrMode0		EQU	0			; Brightness mode 0
bBrMode1		EQU	1			; Brightness mode 1
;				EQU	2			; Not used yet
;				EQU	3			; Not used yet
bNight			EQU	4			; Use night setting
bDark			EQU	5			; Light measure reading was dark
;				EQU	6			; Not used yet
;				EQU	7			; Not used yet

; define ch_flags_RC5
bScrollDateTime		EQU	0		; Date, time, day name, temperature, language in scrolling text
bAlternateScroll	EQU	1		;
;						2..3	; Not used
;						4		; Reserved
;						5		; Not used
;						6		; Reserved for copy of bDemo
;						7		; Not used

; define ch_flags
;bScrollDateTime	EQU	0		; Copied form ch_flags_RC5
;bAlternateScroll	EQU	1		; Copied form ch_flags_RC5
;						2..3	; Not used
bDateToScroll		EQU	4
;						5		; Not used
bDemo_sc			EQU	bDemo	; A copy of demo mode flag, bDemo in flags2 may change during scroll
;						7		; Not used

	if (bScrollDateTime==bDemo)
		error "Ch_flags configuration error"
	endif

;******************************************************************************
;	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

;******************************************************************************
;	Define EEPROM content for initial message
;******************************************************************************

	ORG     0x2100				; Start of EEPROM page 0
		de	"===> This SMD version of Bob Blick's Propeller Clock was built with "
		de	"16F886"
		de	", PCF8583 RTC, light and temperature sensors ",0x83,0x84," <==="
		de	0x00,0x00

	ORG     0x2180				; Start of EEPROM page 1
		de	"===> Uses 26 leds, 8 dot high characters,"
		de	" 16 bit wide display memory, advanced graphics,"
		de	" measures rotation speed "
		de	"Ver."	,VersionMajor | 0x30 ,".", ((VersionMinor>>4) & 0x0F) | 0x30, ((VersionMinor) & 0x0F) | 0x30, " <==="
		de	0x00,0x00

;**********************************************************************
		ORG     0x0000          ; Processor reset vector
		movlw	high(main)
		movwf	PCLATH
		clrf	PORTA
		goto    main            ; Go to beginning of program

;**********************************************************************
		ORG     0x0004          ; Interrupt vector location

		movwf	w_temp			; Context saveing
		swapf	w_temp,f
		swapf	STATUS,w		; Save STATUS
		bcf		STATUS,RP0
		bsf		STATUS,RP1		; Context saving variables are on Bank2
		movwf	status_temp
		swapf	PCLATH,w		; Save PCLATH
		movwf	pclath_temp		; Needed only if >2K program memory used
		movf	FSR,w			; context saving
		movwf	fsr_temp		;

		clrf	PCLATH			; Interrup routine is on Page0
		clrf	STATUS			; select Bank0 & IRP=0 for interrupt stuff

;**********************************************************************

INT_RB0
		btfss	INTCON,INTF		; Interrupt on RB0?
		goto	INT_TMR0		; nope, TMR0 is next

;----------	RB0 interrupt ! == Index Sensor

		movlw	StorePCnt1_H	; Get the address of storage to use
		btfss	T1CON,bPStorage
		movlw	StorePCnt2_H
		movwf	FSR
		movf	PeriodCnt_H,w	; Save Period counter
		movwf	INDF
		incf	FSR,f
		movf	PeriodCnt_L,w	;
		movwf	INDF
		movlw	(1 << bPStorage); Switch to next storage
		xorwf	T1CON,f

;StoreDone:
		bsf		flags2,bNewPCnt	; Signal new stored PeriodCount to main program
		clrf	PeriodCnt_H		; PeriodCnt = 0
		clrf	PeriodCnt_L		;
		clrf	NextPixel_H		; Next_Pixel = 0 (thus now)
		clrf	NextPixel_L		;
		clrf	NextPixel_F		;
		clrf	RoundedNext_L	; RoundedNext = 0
		clrf	RoundedNext_H	;
		clrf	PixelOff		; display next pixel no matter what.
		movf 	DispOffset,w	; iFSR = DispOffset
		movwf	iFSR			;
		btfss	flags2,bNewPPitch; Is there a new value calculated by main prg?
		goto	lINT_RB0		; no, continue
		movf	NewPPitch_L,w	; PixelPitch = NewPPitch
		movwf	PixelPitch_L	;
		movf	NewPPitch_F,w	;
		movwf	PixelPitch_F	;
		movf	NewPixelWidth,w
		movwf	PixelWidth		; PixelWidth = NewPixelWidth
		bcf		flags2,bNewPPitch;

lINT_RB0
		movlw	0xff			;
		movwf	TMR0			; Force TMR0 to 0xFF

		incfsz	TMR1L,f
		goto	INT_RB0_2
		incf	TMR1H,f

INT_RB0_2
		bcf		INTCON,INTF		; Clear RB0 interrupt flag
		goto	lDisp_1			; Do display routine but skip Period increment

;-------- Timer 0 interrupt
INT_TMR0
		btfss	INTCON,T0IF		; Test if a TMR0 interrupt occured
		goto	INT_TMR2		; nope, TMR2 is next

		bsf		TMR0,7			; TMR0 = TMR0 + 128 => Test to double TMR0 speed

		incfsz	PeriodCnt_L,f	; Increment 16-bit period counter
		goto	lDisp_1			;
		incfsz	PeriodCnt_H,f	;
		goto	lDisp_1			; If overflow in MSB period counter = speed to low

		bcf		flags2,bDspEnabled
		bcf		PORTC,bOuterLED	; Other bit of PortA, PortB bits and PortC 0 will be cleared by lDisp_1

lDisp_1
		bcf		INTCON,T0IF		; clear TMR0 interrupt flag before return

		movf	RoundedNext_L,w	; PeriodCnt = RoundedNextPixel ?
		xorwf	PeriodCnt_L,w	;
		btfss	STATUS,Z		;
		goto	lPixelOn		; no, check if there is a pixel on
		movf	RoundedNext_H,w	;
		xorwf	PeriodCnt_H,w	;
		btfss	STATUS,Z		;
		goto	lPixelOn		; no,  check if there is a pixel on
								; yes, display next pixel data

		movf	iFSR,w			; Load new memory pointer to FSR
		movwf	FSR
		bsf		STATUS,IRP		; Point to high data

		movlw	0x00			; Blank the display if rotation too slow
		btfsc	flags2,bDspEnabled
		movf	INDF,w			; Get display high data

		movwf	iFSR			; iFSR copied to FSR, high display data temporary stored in iFSR

		xorwf	PORTA,w			; Update only led output bits
		andlw	(1 << bAnalogL0) | (1 << bAnalogL1) | (1 << bAnalogL2) | (1 << bAnalogL3)
		xorwf	PORTA,f

		movlw	(1 << bSecLED) | (1 << bTicksLED)
		andwf	iFSR,f

		bcf		STATUS,IRP		; Point to low data
		movlw	0x00
		btfsc	flags2,bDspEnabled
		movf	INDF,w			; Get display data

		movwf	PORTB			; PortB = DisplayData(index)

		andlw	(1 << bPixel0)
		iorwf	iFSR,w
		xorwf	PORTC,w
		andlw	(1 << bSecLED) | (1 << bTicksLED) | (1 << bPixel0)
		xorwf	PORTC,f			; Dispatch bits to PORTC

	ifdef	MotorDirFromCalibration
		btfsc	T1CON,bMotorDirCC; Get direction of motor rotation
		call	CheckDecrementFSR; decrement FSR, check correct progress of display memory pointer
		btfss	T1CON,bMotorDirCC; Get direction of motor rotation
		call	CheckIncrementFSR; increment FSR, check correct progress of display memory pointer
	else

	  ifdef MotorCounterClockWise
		call	CheckDecrementFSR; decrement FSR, check correct progress of display memory pointer
	  else
		call	CheckIncrementFSR; increment FSR, check correct progress of display memory pointer
	  endif
	endif
		movwf	iFSR			; Store it in i(nterrupt)FSR

		movf	PixelPitch_F,w 	; NextPixel = NextPixel + PixelPitch
		addwf	NextPixel_F,f	;
		btfss	STATUS,C		;
		goto	no_overflow		;

		incf	NextPixel_L,f	; Fraction overflow, add 1 to Low byte
		btfsc	STATUS,Z		;
		incf	NextPixel_H,f	; low byte roll-over, add 1 to High byte

no_overflow:
		movf	PixelPitch_L,w	;
		addwf	NextPixel_L,f	;
		btfsc	STATUS,C		;
		incf	NextPixel_H,f	; low byte overflow, add 1 to High byte

		movf	NextPixel_L,w	; RoundedNext = NextPixel
		movwf	RoundedNext_L	;
		movf	NextPixel_H,w	;
		movwf	RoundedNext_H	;
		btfss	NextPixel_F,7	; If NextPixel_Fraction >= 128 then
		goto	NotRoundUp		;
		incf	RoundedNext_L,f	; Rounding up
		btfsc	STATUS,Z		;
		incf	RoundedNext_H,f	;
NotRoundUp:
		movf	PixelWidth,w	;
		movwf	PixelOff		; PixelOff = PixelWidth
		goto	lDispDone		;

lPixelOn
		movf	PixelOff,w		; Is there a pixel on?
		btfss	STATUS,Z		; If PixelOff = 0 not to decrement
		decfsz	PixelOff,f		; Pixels are on, countdown
		goto	lDispDone		;

		clrf	PORTB			; Turn off display LED's
		movlw	~ ( (1 << bAnalogL0) | (1 << bAnalogL1) | (1 << bAnalogL2) | (1 << bAnalogL3) )
		andwf	PORTA,f
		movlw	~ ( (1 << bSecLED) | (1 << bTicksLED) | (1 << bPixel0) )
		andwf	PORTC,f

lDispDone
								; Check for high priority interrupts
		btfsc	INTCON,INTF		; interrupt on RB0?
		goto	INT_RB0
		btfsc	INTCON,T0IF		; interrupt on TMR0?
		goto	INT_TMR0

;-------- Timer 2 interrupt
INT_TMR2
		btfss	PIR1,TMR2IF		; interrupt on TMR2?
		goto	INT_EXIT		; nope, interrupt is done!

		bcf		PIR1,TMR2IF		; clear TMR2 interrupt flag
								; do the TMR2 stuff, we get here every 200uSec

		movlw   (1 << bCalibration); toggle PORTA bit, use scope or freq counter
		xorwf	PORTA,f			; to calibrate to 2.5 kHz

								; Text-scroll timer
		movf	TmrScroll,f		; TmrScroll == 0 ?
		btfss	STATUS,Z		;
		decf	TmrScroll,f		; no, TmrScroll --

								; real time sub-second counter
		incfsz	SubSec_L,f		; Increment 16-bit Sub Second counter
		goto	lTime_1			; stil counting
		incfsz	SubSec_H,f		;
		goto	lTime_1			; stil counting

		incf	Second2,f		; 1/2 second has passed
		bsf		flags2,bNewTime	; Sign time need checking

		call	InitSubSecCnt	; reload counter SubSecond = 0x10000 - .2500 = 0xF63C
								; returns 0
		btfsc	flags2,bDspEnabled; Displaying disabled
		movlw	(1 << bOuterLED); Toggle outerled if time invalid
		btfsc	flags2,bTimeInv
		xorwf	PORTC,f			; Outer led on PORTC

		movf	Second2,w		; Minute passed
		xorlw	.120
		btfss	STATUS,Z
		goto	lTime_1			; No, goto RC5 task

		movf	TMR1L,w			; Read rotation from Timer1
		bsf		STATUS,RP1		; Bank2
		movwf	RotBuffer_L		; Store it
		bcf		STATUS,RP1		; Bank0
		movf	TMR1H,w
		bsf		STATUS,RP1		; Bank2
		movwf	RotBuffer_H		; in RotBuffer_L & RotBuffer_H
		bcf		STATUS,RP1		; Bank0

		clrf	TMR1H			; Reset Timer 1
		clrf	TMR1L

		bsf		T1CON,bNewRot	; Sign new rotation data available

lTime_1
		bsf		STATUS,RP1		; Bank2
		movf	AD_state,f
		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_Stuff						; Start RC5 stuff here
		movlw	PORTE			; As on Bank2 use indirect access to PORTE
		movwf	FSR

		btfsc	RC5_flags,bRC5_DataReady;
		goto	lRC5_Exit		;
		btfss	RC5_flags,bRC5_Idle;
		goto	lRC5_Not_Idle	;
		decfsz	RC5_Tmr,f		;
		goto	lRC5_Exit		;
		btfsc	INDF,bRC5inp	; Test input
		bcf		RC5_flags,bRC5_Idle; input = high, cancel Idle state
		incf	RC5_Tmr,f		; continue Idle state until input = high
		goto	lRC5_Exit		;

lRC5_Not_Idle
		btfss	RC5_flags,bRC5_WaitStart;
		goto	lRC5_ReSync		;

lRC5WaitStart
		btfsc	INDF,bRC5inp	; Test input from PORTA
		goto	lRC5_Exit		; No startbit

		bcf		RC5_flags,bRC5_WaitStart; Start received
		clrf 	RC5_Addr		;
		movlw	4				; Receiving 13 bits shift this bit to bit 7 of RC5_Addr
		movwf	RC5_Cmd
		movlw	.6				;
		goto	lRC5_Reload		;

lRC5_ReSync						;
		movf	INDF,w			; Read PORTA
		xorwf	RC5_flags,w		;
		andlw	(1 << bRC5inp)	;
		btfsc	STATUS,Z		;
		goto	lRC5_no_sync	;
		bsf		RC5_flags,bRC5_ReSynced;

		xorwf	RC5_flags,f		; Modify stored input bit

		movlw	.6				; Re-sync the timer
		btfss	RC5_flags,bRC5_HalfBit;
		movlw	.2				;
		movwf	RC5_Tmr			;

lRC5_no_sync
		btfsc	RC5_flags,bRC5_HalfBit;
		goto	lRC5_2nd_Half	;

lRC5_1st_Half
		decfsz	RC5_Tmr,f		;
		goto	lRC5_Exit		;
		bcf		STATUS,C		;
		btfsc	INDF,bRC5inp	; Test PORTA,bRC5inp
		bsf		STATUS,C		; C = RC5inp
		rlf		RC5_Cmd,f		;
		rlf		RC5_Addr,f		;
		bsf		RC5_flags,bRC5_HalfBit; indicate that the first half bit is received
		bcf		RC5_flags,bRC5_ReSynced;
		movlw	.4				; reload timer
		goto	lRC5_Reload

lRC5_2nd_Half
		btfsc	RC5_flags,bRC5_ReSynced;
		goto	lReSyncOK		;
		decfsz	RC5_Tmr,f		;
		goto	lRC5_Exit		;

;lRC5_Error
		movf	RC5_flags,w		; Clear RC5 status bits but keep binary mode flags
		andlw	(1 << bUseBinFont) | (1 << bBCDMode) | (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_flags,bRC5_HalfBit;
		btfss	RC5_Addr,7
		goto	lRC5_Exit		;
		rlf		RC5_Cmd,f		; Shift left to complete Addr
		rlf		RC5_Addr,f		;
		rlf		RC5_Cmd,w		; RC5_Cmd remains unchanged
		rlf		RC5_Addr,f		; Complete address
		bcf		RC5_Cmd,7		;
		btfss	RC5_Addr,6		;
		bsf		RC5_Cmd,7		; Bit 7 of RC5_Cmd = Inv Bit6 of RC5_Addr
								; RC5_ShrA and RC5_Cmd was cleared and shifted left 13+2 times, so C = 0
		btfsc	RC5_Addr,5		;
		bsf		STATUS,C		; C = ToggleBit
		rrf		RC5_Cmd,f		; ToggleBit in bit 7 of RC5_Cmd
		movf	RC5_Addr,w
IrAddr0
		xorlw	RemoteAddr		; If RC5_Addr = RemoteAddr
	ifdef	RC5AddrCheck
		andlw	0x1F			; Only 5 bits to test
	else
		andlw	0x00
	endif
		btfsc	STATUS,Z		;
		bsf		RC5_flags,bRC5_DataReady; Sign new command received
lRC5_Exit
								; Bank 2 active
;		clrf	STATUS			; Bank 0

;-------- Exit form interrupt service rutine
INT_EXIT
		bsf		STATUS,RP1		; Bank 2 Context saving variables are on Bank2 except w_temp in Common
		movf	fsr_temp,w		; Context recall
		movwf	FSR				;
		swapf	pclath_temp,w	; Needed only if >2K program memory used
		movwf	PCLATH
		swapf	status_temp, w	; restore context for main program
		movwf	STATUS			;  this will also restore bank selection
		swapf	w_temp, w
		retfie                  ; return from interrupt

;******************************************************************************
;	Init sub second counter	--	SubSecond = 0x10000 - 2500 = 0xF63C

InitSubSecCnt
		movlw	0x3C			; load counter SubSecond = 0x10000 - 2500 = 0xF63C
		movwf	SubSec_L		;
		movlw	0xF6			;
		movwf	SubSec_H		;
		retlw	0				; W cleared on return

;**********************************************************************

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

;**********************************************************************
; Calculate pixel pitch

CalcPixelPitch					; That is a hard one. We have to divide by 120 !!!
								; PixelPitch = PeriodCnt / 120
		btfsc	flags2,bNewPPitch
		return

		movf 	StorePCnt1_H,w	; Check if two period counters
		movwf	DIV_LO			;
		xorwf	StorePCnt2_H,w	; are the same. If not, don't
		btfss	STATUS,Z		; calculate new pixelpitch because
		goto	CalcDone		; the rotation speed was not stable
		movf	StorePCnt1_L,w	;
		xorwf	StorePCnt2_L,w	;
		btfss	STATUS,Z		;
		goto	CalcDone		;

		clrf	DIV_HI			; Divider = 00:StorePCnt1_H

		movlw	.120			; Init divisor
		call 	div16X8Divisor
		movf	StorePCnt1_L,w	;
		movwf	DIV_LO			;

		call	div16X8			; Divider = Remainder:StorePCnt1_L
		movwf	NewPPitch_L		;
		clrf	DIV_LO			;

		call	div16X8			; Divider = Remainder:00
		movwf	NewPPitch_F		;

		clrc					; Start calculation for pixel width
		rrf		NewPPitch_L,w	;
		movwf	NewPixelWidth	; W = PixelWidth = NewPPitch_L * 4 / 8
		clrc
		rrf		NewPixelWidth,f	; PixelWidth = NewPPitch_L * 2 / 8
		clrc
		rrf		NewPixelWidth,f	; PixelWidth = NewPPitch_L * 1 / 8
		addwf	NewPixelWidth,f	; PixelWidth = NewPPitch_L * 5 / 8

		bsf		flags2,bDspEnabled; If bDspEnabled int. routine clears PORTA,bOuterLED
		call	SetOuterLed		; Set Port for Outerled equal to flags OuterLED bit

NotON:
		bsf		flags2,bNewPPitch; Signal new Pitch value to interrupt routine

CalcDone:
		bcf		flags2,bNewPCnt	; clear flag
		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			; Decrement for february as well
		xorlw	.2				; Month = February ?
		btfss	STATUS,Z		;
		goto	lNotFeb			; 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
		btfsc	STATUS,Z
		decf	DMon,f			; Year is not a LeapYear, dec DMon for Feb

lNotFeb
		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
CheckYear
		movlw	.100			; FSR has to be set to Year
		call	CheckAndIncNext
								; FSR -> Century
		movlw	.100			;
		subwf	Century,w		; Century < 100 ?
		btfsc	STATUS,C		;
		clrf	Century			;

		bcf		flags2,bNewTime	; Clear new time flag
		return

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

;******************************************************************************
;	Routines to display Time and Date
;******************************************************************************

;-------- Update Display memory with name of day

LoadBCDDayname
		call	DayAddress
		movf	digitindex,w	; Read names backward
		sublw	.9
		call	AddBCD16
		movlw	high(DayNames)	; Add address of table
		call	CharPattern		; Get next character
		clrf	PCLATH			; Page 0

ConvToInternalNotBin
		bcf		RC5_flags,bUseBinFont; Not numeric character

ConvToInternal					; Converts ascii character to internal address
		addlw	-' '			; Convert ascii code to inernal
ConvToAddress
		clrc
		movwf	BCD				; Save internal code
		clrf	BCD_High
		btfsc	BCD,7
		clrf	BCD				; If code was > 0x9F - use space instead
		rlf		BCD,f			; Multiply by 6
		rlf		BCD,w
		call	RlfAddBCD16
		movf	BCD,w
		return					; Store new code

DayAddress
		movf	Language,w		; Get Language code
		andlw	0x0F
		movwf	Scratch2		; Store language code
		call	ConvToAddress	; Multiply by 6
		addwf	Scratch2,w		; Add once more - Multiply by 7
		addwf	WDay,w			; Add day of week

Mult10
		movwf	BCD				; Multiply by 10
		clrf	BCD_High		; result is 16 bit wide
		addwf	BCD,f			; C = 0
		movf	BCD,w
		rlf		BCD,f
		rlf		BCD_High,f
		rlf		BCD,f
RlfAddBCD16
		rlf		BCD_High,f
AddBCD16						; Add w to BDC_High:BCD
		addwf	BCD,f
		btfsc	STATUS,C
		incf	BCD_High,f
		return

CharPatternTab
		bsf		PCLATH,3		; Page1
		btfsc	RC5_flags,bUseBinFont; Is this char a numeric char in bin mode
		goto	CharPatternBin_2K; Use binary table
CharTable
		movlw	high(CharTab)
CharPattern						; If calls out from lower 2K, afther call PCLATH has to be set to 0
		addwf	BCD_High,w		; Get high byte
GetXII
		movwf	PCLATH			; Store it in PCLATH
		movf	BCD,w			; Get low byte
		movwf	PCL				; Get next character

;=======================================================
; No execution passes here

;-------- Update Display memory with Digital Time Display

DTime
		movf	dpi,f			;
		btfss	STATUS,Z		;
		goto	l_DTime_1		; display index > 0

		clrf	digitindex		; display index = 0
		clrf	dotindex		; Load start parameters for digit displaying

l_DTime_1
		movlw	.60				;
		subwf	dpi,w			;
		btfsc	STATUS,C		;
		return					; display index >= 60

		movf	dotindex,w		;
		btfss	STATUS,Z		;
		goto	l_DTime_3

		movlw	.6
		addwf	dotindex,f		; C = 0
		bcf		RC5_flags,bUseBinFont

		btfsc	flags,bShowDTime
		call	LoadBCDTime		; dotindex = 0, load new digit

		btfss	flags,bShowDTime
		call	LoadBCDTest		; dotindex = 0, load new digit

l_DTime_3
		decfsz	dotindex,f		;
		goto	l_DTime_2

l_DTime_Gap
		incf	digitindex,f	; Select next digit
		return					; To get a gap between digits

l_DTime_2
		call	CharPatternTab	; Get the dot pattern for this column
		clrf	PCLATH			; Page0

IorToTdd
		iorwf	tdd,f			; Load pixed data to temp disp data

IncBCD16
		movlw	1
		goto	AddBCD16

;-------- Update Display memory with Digital Date Display

DDate
		movlw	.60
		subwf	dpi,w			;
		btfss	STATUS,C		;
		return					; display index < 60
		btfss	STATUS,Z		;
		goto	l_DDate_1		; display index > 60

		clrf	digitindex		; display index = 60
		clrf	dotindex		; Load start parameters for digit displaying

l_DDate_1
		movf	dotindex,w		; dotindex = 0, load new digit
		btfss	STATUS,Z		;
		goto	l_DDate_11

		movlw	.6
		addwf	dotindex,f		; C = 0
		bcf		RC5_flags,bUseBinFont

		movf	flags,w			; If no date or day of week to display - Brightness display
		andlw	(1 << bShowDDate) | (1 << bShowWDay)
		btfss	STATUS,Z
		goto	l_DDate_7

		call	LoadBCDBright
		goto	l_DDate_10

l_DDate_7
		xorlw	(1 << bShowDDate) | (1 << bShowWDay)
		btfsc	STATUS,Z
		goto	l_DDate_8		; If both date and day of week - alternate them

		btfss	flags,bShowWDay
		goto	l_DDate_9

		call	LoadBCDWDay
		goto	l_DDate_10

l_DDate_8
		btfss	Second2,3
		call	LoadBCDWDay		; Day of week to display
		btfsc	Second2,3
l_DDate_9
		call	LoadBCDDate		; Date to display

l_DDate_10
		movlw	.4				; Read dot patterns backward
		call	AddBCD16

l_DDate_11
		decfsz	dotindex,f		;
		goto	l_DDate_2		; dotindex < 6, display data
		goto	l_DTime_Gap		; To get a gap between digits

l_DDate_2
		call	CharPatternTab	; get the dot pattern for this column
		clrf	PCLATH			; Page0

l_Date_3
		movwf	Scratch2		; Flip the dot pattern
		clrf	Scratch			; Clear bit 8
		movlw	7				; Characters are 7 bit height
l_Date_4
		rrf		Scratch2,f		; Rotate (right) next bit to   C
		rlf		Scratch,f		; Rotate (left ) next bit from C
		addlw	-1				;
		btfss	STATUS,Z		; Loop for 7 dots
		goto	l_Date_4
		movf	Scratch,w		; Get flipped dot pattern

		iorwf	tdd,f			; Load pixed data to temp disp data

		movlw	0xFF			; Move table pointer backward
		call	AddBCD16
		addwf	BCD_High,f
		return

;-------- Update Display memory with Hands

Hands
		movlw	.30				; difference in offset for hands and digital display
		subwf	dpi,w			; scratch4 = dpi - 30
		btfss	STATUS,C		; if scratch4 < 0 then
		addlw	.120			;    scratch4 = scratch4 + 120
		movwf	Scratch4		;

		movf	Second2,w		;
		andlw	0xFE			; filter out 1/2 second

		subwf	Scratch4,w
	ifdef	SeparateHandHandling
		btfss	flags3,bShowSecHand; Second hand disabled
	else
		btfss	flags3,bShowHourHand; Hour hand disabled
	endif
		goto	MinuteHand

		btfss	flags4,bAnalogClk
		goto	ArcSecHand

		btfsc	STATUS,Z
		call	SetAllInner		; Turn on all inner leds
		goto	MinuteHand

ArcSecHand						; Draw arc if Scratch4<= (Second2 and 0xFE)
		btfss	flags3,bSecMode	; Set C if dot second hand mode
		bsf		STATUS,C
		btfss	STATUS,C
		bsf		tddH,bSecLED	; Sec led - second hand
SecHand
		btfsc	STATUS,Z		;
		bsf		tddH,bSecLED	; Sec led - second hand

MinuteHand
		movlw	.60
		subwf	Second2,w		; Set C if Second2 >= .60
		rlf		Minute,w		; Clears C, because Minute < .60
		movwf	Scratch			; Scratch = Minute * 2

		xorwf	Scratch4,w		;
		btfsc	STATUS,Z
	ifdef	SeparateHandHandling
		btfss	flags3,bShowMinHand; Minute hand disabled
	else
		btfss	flags3,bShowHourHand; Hour hand disabled
	endif
		goto	HourHand

		btfss	flags4,bAnalogClk
		goto	NormMinHand

		movlw	(1 << bAnalogL0) | (1 << bAnalogL1) | (1 << bAnalogL2)
		iorwf	tddH,f
		goto	HourHand

NormMinHand
		btfsc	flags3,bMinMode	;
		goto	DotMinHand

		call	SetAllInner		; Turn on all inner leds
		movlw	B'00001111'		;
		iorwf	tdd,f			; Turn on minute hand
		goto	HourHand

DotMinHand
		bsf		tdd,bMinLED		; Turn on minute dot

HourHand
		btfss	flags3,bShowHourHand; Hour hand disabled
		return

		call	CalcHourHand

	ifdef	UseAnalog24Mode
		btfsc	flags3,bAnalMode24h; In 24 hour mode
		rrf		Scratch2,f		;  divide by 2
	endif

l_120
		subwf	Scratch2,f		;
		btfsc	STATUS,C		; result > 0 ?
		goto	l_120
		addwf	Scratch2,w		; result was negative, re-add 120 and load it in w

		xorwf	Scratch4,w		;
		btfss	STATUS,Z
		return

		movlw	(1 << bAnalogL0) | (1 << bAnalogL1)
		btfsc	flags4,bAnalogClk
		goto	IorTotddH

		btfss	flags3,bHourMode
		goto	SetAllInner		; Turn on all inner leds
		bsf		tdd,bHourLED
		return

SetAllInner
		movlw	(1 << bAnalogL0) | (1 << bAnalogL1) | (1 << bAnalogL2)| (1 << bAnalogL3)
IorTotddH
		iorwf	tddH,f
		return

CalcHourHand
		bcf		STATUS,C
		rlf		Hour,w			; Get hour, last instruction modified C was "rlf Minute,w" and cleared C
		movwf	Scratch2		; Scratch2 = hour * 2
		rlf		Scratch2,f		; Scratch2 = hour * 4
		rlf		Scratch2,f		; Scratch2 = hour * 8
		addwf	Scratch2,f		; Scratch2 = hour * 10

		movlw	.12				;
l_hour_div12					; Divide (2 * minute) by 12
		subwf	Scratch,f		;
		btfss	STATUS,C		;
		goto	l_div12_done	;
		incf	Scratch2,f		; advance hour a bit
		goto	l_hour_div12	;

l_div12_done					; C=0
		retlw	.120			; Scratch2 = (10 * Hour) + (2 * Minute / 12)

;-------- Get character for Digital Date Display

LoadBCDDate						; load BCD with date digits
		movlw	high(DateTable0)
		movwf	PCLATH
		movf	digitindex,w	;
		addwf	digitindex,w	;
		btfss	flags,bShowCentury
		addlw	DF_YYMMDD-DF_YYYYMMDD
		btfsc	flags,bDateFormat
		addlw	DF_DDMMYYYY-DF_YYYYMMDD

DateTable0
		addwf	PCL,f			;

; DateFormat: YYYY-MM-DD
DF_YYYYMMDD
;0--
		movf	Day,w			; Day     1 digit
		goto	l_convert		;
;1--
		movf	Day,w			; Day    10 digit
		goto	l_convert_swap	;
;2--
		movlw	'-'				; '-'
		goto	l_char_clr		;
;3--
		movf	Month,w			; Month   1 digit
		goto	l_convert		;
;4--
		movf	Month,w			; Month  10 digit
		goto	l_convert_swap	;
;5--
		movlw	'-'				; '-'
		goto	l_char_clr		;
;6--
		movf	Year,w			; Year    1 digit
		goto	l_convert		;
;7--
		movf	Year,w			; Year   10 digit
		goto	l_convert_swap
;8--
		movf	Century,w		; Year  100 digit
		goto	l_convert		;
;9--
		movf	Century,w		; Year 1000 digit
		goto	l_convert_swap

;  DateFormat: DD-MM-YYYY
DF_DDMMYYYY
;10--
		movf	Year,w			; Year    1 digit
		goto	l_convert		;
;11--
		movf	Year,w			; Year   10 digit
		goto	l_convert_swap	;
;12--
		movf	Century,w		; Year  100 digit
		goto	l_convert		;
;13--
		movf	Century,w		; Year 1000 digit
		goto	l_convert_swap	;
;14--
		movlw	'-'				; '-'
		goto	l_char_clr		;
;15--
		movf	Month,w			; Month   1 digit
		goto	l_convert		;
;16--
		movf	Month,w			; Month  10 digit
		goto	l_convert_swap	;
;17--
		movlw	'-'				; '-'
		goto	l_char_clr		;
;18--
		movf	Day,w			; Day     1 digit
		goto	l_convert		;
;19--
		movf	Day,w			; Day    10 digit
		goto	l_convert_swap

; DateFormat: YY-MM-DD
DF_YYMMDD
;20--
		movlw	' '				; ' '
		goto	l_char_clr		;
;21--
		movf	Day,w			; Day     1 digit
		goto	l_convert		;
;22--
		movf	Day,w			; Day    10 digit
		goto	l_convert_swap	;
;23--
		movlw	'-'				; '-'
		goto	l_char_clr		;
;24--
		movf	Month,w			; Month   1 digit
		goto	l_convert		;
;25--
		movf	Month,w			; Month  10 digit
		goto	l_convert_swap	;
;26--
		movlw	'-'				; '-'
		goto	l_char_clr		;
;27--
		movf	Year,w			; Year    1 digit
		goto	l_convert		;
;28--
		movf	Year,w			; Year   10 digit
		goto	l_convert_swap
;29--
		movlw	' '				; ' '
		goto	l_char_clr		;

;  DateFormat: DD-MM-YY
DF_DDMMYY
;30--
		movlw	' '				; ' '
		goto	l_char_clr		;
;31--
		movf	Year,w			; Year    1 digit
		goto	l_convert		;
;32--
		movf	Year,w			; Year   10 digit
		goto	l_convert_swap	;
;33--
		movlw	'-'				; '-'
		goto	l_char_clr		;
;34--
		movf	Month,w			; Month   1 digit
		goto	l_convert		;
;35--
		movf	Month,w			; Month  10 digit
		goto	l_convert_swap	;
;36--
		movlw	'-'				; '-'
		goto	l_char_clr		;
;37--
		movf	Day,w			; Day     1 digit
		goto	l_convert		;
;38--
		movf	Day,w			; Day    10 digit
		goto	l_convert_swap
;39--
		goto	l_Space			;

DateTable1

	IF high(DateTable0) != high(DateTable1)
		ERROR "Date jump table page error"
        ENDIF

;-------- Get character for Digital Time Display

LoadBCDTime						; load BCD with time digits
		movf	Hour,w
		btfss	flags,bDisp12Mode; 24 hour mode
		goto	lBCDHour
		addlw	-.12			; Prepare to 12 hour mode
		btfss	STATUS,C		; If hour > .12: add -.12
		movf	Hour,w			; Reload hour if hour < 12
		btfsc	STATUS,Z
		addlw	.12				; Correct 0 to 12
lBCDHour
		movwf	BCD
		movlw	high(TimeTable0)
		movwf	PCLATH
		movf	digitindex,w	;
		addwf	digitindex,w	; Clears C

TimeTable0
		addwf	PCL,f			;
;0--
		movf	Hour,w			; PM indicator
		goto	l_PM			;
;1--
		movf	BCD,w			; Hour   10 digit or PM indicator
		goto	l_leading_swap_PM;
;2--
		movf	BCD,w			; Hour    1 digit
		goto	l_convert		;
;3--
		movlw	':'				; ':'
		goto	l_char_clr		;
;4--
		movf	Minute,w		; Minute 10 digit
		goto	l_convert_swap	;
;5--
		movf	Minute,w		; Minute  1 digit
		goto	l_convert		;
;6--
		movlw	':'				; ':'
		goto	l_char_clr		;
;7--
		rrf		Second2,w		; Second 10 digit
		goto	l_convert_swap	;
;8--
		rrf		Second2,w		; Second  1 digit
		goto	l_convert		;
;9--
		goto	l_Space			;

TimeTable1

	IF high(TimeTable0) != high(TimeTable1)
		ERROR "Time jump table page error"
    ENDIF

;-------- Get character for Temperature and day of week Display

LoadBCDWDay
		btfsc	flags,bShowDayName
		goto	LoadBCDDayname

LoadBCDTemp
		movf	STATUS,w		; Save Bank selection
		movwf	BCD
		clrf	STATUS			; Bank 0 for MoonSymbol
		bsf		PCLATH,3		; Page 3
		bsf		PCLATH,4
		call	MoonSymbol		; Calculate Moon symbol
;		clrf	PCTALH			; Next instructions clear 4..3 of PCLATH
		movwf	Scratch2
		movf	BCD,w			; Restore bank selection
		movwf	STATUS
		movlw	high(TempTable0)
		movwf	PCLATH			; Page 0
		movf	digitindex,w	;
		addwf	digitindex,w	; Clears C

TempTable0
		addwf	PCL,f			;
	ifdef	UseAgeOfMoon
;0--
		movf	Scratch4,w		; Moon    1 digit
		goto	l_convert		;
;1--
		movf	Scratch4,w		; Moon   10 digit
		goto	l_leading_swap	;
;2--
		movf	Scratch2,w		; Moon symbol
		goto	l_char_clr		;
;3--
		movlw	' '				; ' '
		goto	l_char_clr		;
;4--
		incf	WDay,w			; Day of week
		goto	l_convert_sc	;
;5--
		movlw	' '				; ' '
		goto	l_char_clr		;
;6--
		movlw	0x95			; 'C'
		goto	l_char_clr		;
;7--
		movf	Tempr,w			; Temperature  1
		goto	l_convert		;
;8--
		movf	Tempr,w			; Temperature 10
		goto	l_leading_swap	;
;9--
		goto	l_Space			; ' '
	else
;0--
		movlw	' '				; ' '
		goto	l_char_clr		;
;1--
		movlw	' '				; ' '
		goto	l_char_clr		;
;2--
		movlw	' '				; ' '
		goto	l_char_clr		;
;3--
		movlw	' '				; ' '
		goto	l_char_clr		;
;4--
		incf	WDay,w			; Day of week
		goto	l_convert_sc	;
;5--
		movlw	' '				; ' '
		goto	l_char_clr		;
;6--
		movlw	0x95			; 'C'
		goto	l_char_clr		;
;7--
		movf	Tempr,w			; Temperature  1
		goto	l_convert		;
;8--
		movf	Tempr,w			; Temperature 10
		goto	l_leading_swap	;
;9--
		goto	l_Space			; ' '
	endif

TempTable1

	IF high(TempTable0) != high(TempTable1)
		ERROR "Temp jump table page error"
    ENDIF

;-------- Get character for rotation measurement Display

LoadBCDTest						; load BCD with test digits
		call	Word2Bcd5
		movlw	high(TestTable0+1)
		movwf	PCLATH
		movf	digitindex,w	;
		addwf	digitindex,w	;

TestTable0
		addwf	PCL,f			;
;0--
		movlw	' '				; ' '
		goto	l_char_clr		;
;1--
		movf	Scratch3,w		; Rotation digit  10000
		goto	l_BCD			;
;2--
		swapf	Scratch2,w		; Rotation digit   1000
		goto	l_BCD			;
;3--
		movf	Scratch2,w		; Rotation digit    100
		goto	l_BCD			;
;4--
		swapf	Scratch,w		; Rotation digit     10
		goto	l_BCD			;
;5--
		movf	Scratch,w		; Rotation digit      1
		goto	l_BCD			;
;6--
		movlw	'R'				; 'R'
		goto	l_char_clr		;
;7--
		movlw	'/'				; '/'
		goto	l_char_clr		;
;8--
		movlw	'm'				; 'm'
		goto	l_char_clr		;
;9--
		goto	l_Space			;

TestTable1

	IF high(TestTable0) != high(TestTable1)
		ERROR "Test jump table page error"
        ENDIF

l_Dark
		andlw	1				; Get current setting sign
		addlw	BrightSet-BrightCodes
		goto	l_Bm2

l_BrMode
		andlw	3
		btfsc	BrightStep,4	; If step size .16, use uppercase letters
		addlw	4
l_Bm2
		addlw	low(BrightCodes); Get character form table
		movwf	BCD
		movlw	high(BrightCodes)
		call	GetXII
		clrf	PCLATH			; Page0

l_char_clr
		bcf		RC5_flags,bUseBinFont; Not to use binary characters
l_char
		btfsc	flags2,bScrollOn; Leave with Bank2 selected if scrolling
		return
		bcf		STATUS,RP1		; Bank 0 --- For entry from DrawTest
		goto	ConvToInternal	; Convert to internal code

l_leading_swap_PM
		call	l_convert_swap	; Convert to BCD and swapp
		movf	Scratch2,f
		btfss	STATUS,Z		; If not 0 - display the number
		return
		goto	l_pm_ap			; Check for pm

l_leading_swap
		call	l_convert_swap	; Convert to BCD and swapp
		movf	Scratch2,f		; Remove leading 0
		btfsc	STATUS,Z
		goto	l_Space
		return

l_PM
		addlw	4				; Display pm indicator
		andlw	0xF0
		btfsc	flags,bDisp12Mode
		btfsc	STATUS,Z		; If not 0, display number
		goto	l_Space
l_pm_ap
		movlw	.12				; Check for pm
		subwf	Hour,w
		btfss	STATUS,C		;
		goto	l_Space
		movlw	"'"				; If pm display apstroph
		goto	l_char_clr		; Not to use binary font

l_hex
		andlw	0x0F			; Use low nibble only
		movwf	BCD
		sublw	0x09
		movlw	'0'+0x07		; Convert hex codes to A..F
		btfsc	STATUS,C		; If nibble > 9 add 7, and use upper case character
l_char_add0
		movlw	'0'				; Convert to character code
		addwf	BCD,w
		goto	l_char

l_convert_swap
		call	Conv2BCD		; Convert to BCD
l_BCD_swap
		movwf	BCD				; Swap nibbles
		swapf	BCD,w			;
		goto	l_BCD

l_convert_sc					; Blanks data for scroll routines
		btfsc	flags2,bScrollOn
		goto	l_Space

l_convert
		call	Conv2BCD		; Convert to BCD
l_BCD
		andlw	0x0F			; Use low nibble
		movwf	Scratch2		; Store it in Scratch2 for leading 0 test
		movwf	BCD				;
		sublw	9
		btfss	STATUS,C		; Check for decimal character (A..F converted to space)
		goto	l_Space
		btfsc	RC5_flags,bBCDMode; Test for binary mode
		bsf		RC5_flags,bUseBinFont
		goto	l_char_add0		; Convert to character code, C=0

;-------- Get character for Brightness information Display

LoadBCDBright					; load BCD with Brightness information
		movlw	high(BrightTable0)
		movwf	PCLATH
		movf	digitindex,w	;
		addwf	digitindex,w	;
		bsf		STATUS,RP1		; Bank2

BrightTable0
		addwf	PCL,f			;
;0--
l_Space
		movlw	' '				; ' '
		goto	l_char_clr		;
;1--
		movf	BrightNight,w	; Night brightness low  digit
		goto	l_hex			;
;2--
		swapf	BrightNight,w	; Night brightness high digit
		goto	l_hex			;
;3--
		swapf	BrightMode,w	; Current bright setting
		goto	l_Dark			;
;4--
		movf	BrightDay,w		; Daytime brightness low  digit
		goto	l_hex			;
;5--
		swapf	BrightDay,w		; Daytime brightness high digit
		goto	l_hex			;
;6--
		movf	BrightMode,w	; Bright mode
		goto	l_BrMode		;
;7--
		movf	LightLimit,w	; Light limit low digit
		goto	l_hex			;
;8--
		swapf	LightLimit,w	; Light limit high digit
		goto	l_hex			;
;9--
		goto	l_Space			;

BrightTable1

	IF high(BrightTable0) != high(BrightTable1)
		ERROR "Bright jump table page error"
        ENDIF

;--------
Conv2BCD						; Convert w to BCD (0 <= w <= 99)
		clrf	Scratch2		; Clear high nibble
l_bcd_1
		addlw	-.10			; Sub .10
		incf	Scratch2,f		; Inc high nibble
		btfsc	STATUS,C		; Loop if no carry
		goto	l_bcd_1
		addlw	.10				; Re add .10, C=1
		decf	Scratch2,f		; Correct high nibble
		swapf	Scratch2,f		; Swap to high part of byte
		addwf	Scratch2,w		; Add to low nibble, C=0
		return

;-------- Update Display memory with Time Ticks every 5 minutes

Ticks
		movf	dpi,w
		xorwf	TickPos,w
		btfss	STATUS,Z		; At a tick position
		return

		bsf		tddH,bTicksLED	; Turn on analogue tick Leds

		btfsc	flags4,bSTick12
		goto	Ticks10			; If single tick at 12 always add .10

		movf	TickPos,w		; Dpi=30 at 12 o clock
TicksCikl
		xorlw	.20
		btfsc	STATUS,Z		; Draw " at 12, ' at other
		goto	Ticks9
		xorlw	.20^.29
		btfsc	STATUS,Z
		goto	Ticks2
		xorlw	.29^.31
		btfsc	STATUS,Z
		goto	Ticks9

		btfss	flags3,bAnalMode24h; If analogue hands operate in 24 hour mode
		goto	Ticks10

		xorlw	.31
		addlw	-.60
		btfsc	STATUS,C
		goto	TicksCikl

Ticks10
		movlw	.1
Ticks9
		addlw	.7				; W = 0 if jump to here
Ticks2
		addlw	.2				; W = 0 if jump to here
		addwf	TickPos,f
		return

;-------- Update Display memory with XII   III  VI  IX around the clock

Draw36912
		movlw	(1 << bShowDDate) | (1 << bShowDTime) | (1 << bShowWDay)
		andwf	flags,w
		btfss	flags3,bAnalMode24h; Hide if analogue hands operate in 24 hour mode
		btfss	STATUS,Z		; Hide if digital displaing on
		return

		movf	dpi,f
		btfss	STATUS,Z
		goto	l_Draw_0

		movlw	5
		movwf	dotindex
		movlw	(IX-XII)+low(XII)+2
		movwf	BCD

l_Draw_0
		btfss	dotindex,3
		goto	l_Draw_2
		movf	dpi,w			;
		xorlw	.27				; Are we at XII
		btfsc	STATUS,Z		;
		goto	l_Start_XII		; Start draw it
		xorlw	.27^.58			; Are we at III
		btfsc	STATUS,Z
		goto	l_Start_III		; Start draw it
		xorlw	.58^.88			; Are we at VI
		btfsc	STATUS,Z		;
		goto	l_Start_VI		; Start draw it
		xorlw	.88^.118		; Are we at IX
		btfss	STATUS,Z		;
		goto	l_Draw_1		; No, continue drawing

l_Start_IX						; Calculate index of char
		movlw	IX-VI
l_Start_VI
		addlw	VI-III			; W = 0 if jump to here
l_Start_III
		addlw	III-XII			; W = 0 if jump to here
l_Start_XII
		addlw	low(XII)
		movwf	BCD				; Store table offset, W = 0 if jump to here
		clrf	dotindex		; Start counting dots
l_Draw_1
		btfsc	dotindex,3
		return					; No more dots to draw

l_Draw_2
		incf	dotindex,f		; Move to next dot
		movlw	high(XII)
		call	GetXII			; get the dot pattern for this column
		clrf	PCLATH
		goto	IorToTdd		; Ior to display data, move pointer

;******************************************************************************
;	Processing of RC5 command's, called by main program if a command is received
;******************************************************************************

ProcessRC5
		bsf		STATUS,RP1		; Bank2

		movf	RC5_Cmd,w		;
		xorwf	RC5_Cmd2,f		;
		btfsc	STATUS,Z		;
		goto	ProcessRC5Done	; Process command only once, at least toggle bit changes for a new command

		andlw	0x7F			;

IrCmdTab
		select_w				; Bank2

		case	TScrollMode		;
		  goto	ToggleScrollMode; Toggle scroll mode

								; Brightness setting commands
		case	BRIGHT_UP		;
		  goto	BrightnessUp	; Brightness up
		case	BRIGHT_DN		;
		  goto	BrightnessDown	; Brightness down
	ifdef	UseBrightModeSetting
		case	BRIGHT_MD		;
		  goto	BrightnessMode	; Brightness mode
	endif
	ifdef	UseLightLimitSetting
		case	LIGHTLIM_UP		;
		  goto	LightLimitUp	; Light limit up
		case	LIGHTLIM_DN		;
		  goto	LightLimitDown	; Light limit down
	endif
	ifdef	UseBrightStepSetting
		case	BRIGHT_ST
		  goto	ToggleBrightStep; Toggle Brightness step size
	endif

		bcf		STATUS,RP1		; Bank0

								; Time setting commands
		case	SEC_CL			;
		  goto	ClrSecond		; Adjust time : Clear Seconds
		case	SEC_UP			;
		  goto	IncSecond		; Adjust time : Increment Seconds
		case	SEC_DN			;
		  goto	DecSecond		; Adjust time : Decrement Seconds
		case	MIN_UP			;
		  goto	IncMinute		; Adjust time : Increment Minutes
		case	MIN_DN			;
		  goto	DecMinute		; Adjust time : Decrement Minutes
		case	HOUR_UP			;
		  goto	IncHour			; Adjust time : Increment Hours
		case	HOUR_DN			;
		  goto	DecHour			; Adjust time : Decrement Hours
		case	DAY_UP			;
		  goto	IncDay			; Adjust Date : Increment Days
		case	DAY_DN			;
		  goto	DecDay			; Adjust Date : Decrement Days
		case	MON_UP			;
		  goto	IncMonth		; Adjust Date : Increment Month
		case	MON_DN			;
		  goto	DecMonth		; Adjust Date : Decrement Month
		case	YEAR_UP			;
		  goto	IncYear			; Adjust Date : Increment Year
		case	YEAR_DN
		  goto	DecYear			; Adjust Date : Decrement Year
		case	CENT_UP			;
		  goto	IncCentury		; Adjust Date : Increment Century
		case	CENT_DN
		  goto	DecCentury		; Adjust Date : Decrement Century


								; Offset setting commands
		case	INDEX_UP		;
		  goto	DecDispOffset	; Adjust index sensor Offset, rotate display left
		case	INDEX_DN		;
		  goto	IncDispOffset	; Adjust index sensor Offset, rotate display right

								; Mode setting commands
		case	TOuterLine 		;
		  goto	ToggleOuterLed	; Outer Line
		case	DigitalMode		;
		  goto	ChgDigitMode	; Change digital display mode
		case	TWDayName		;
		  goto	ToggleName		; Toggle day name display and digit display mode
		case	TBinMode		;
		  goto	ToggleBinMode	; Toggle binay mode
		case	AnalogueMode	;
		  goto	ChgAnalogMode	; Change analogue display mode
		case	AnalogueHands	;
		  goto	ChgAnalogHands	; Change analogue hand options
		case	AnalogClk		;
		  goto	TgAnalogClk		; Analog Clock on inner led goups
		case	TTicks			;
		  goto	ToggleTicks		; Toggle Ticks mode

		case	DemoM			;
		  goto	ToggleDemo		; Demo Mode
		case	TextMode		;
		  goto	ToggleText		; Scrolling Text Mode
		case	TStaticText		;
		  goto	ToggleStaticText; Static Text Mode

		case	SET_SP			;
		  goto	SetScrollSp		; Set Scrolling speed up
		case	SET_SP			;
		  goto	SetScrollSpDown	; Set Scrolling speed down

		case	TLANGUAGE		;
		  goto	SetLanguage		; Set Language
		case	TPICT			;
		  goto	SetPictNum		; Set Picture number
		case	TPICTDN			;
		  goto	SetPictNumDown	; Set Picture number
		case	TSlideShow		;
		  goto	ToggleSlideShow	; Toggle slide show mode
IrCmdTabEnd

		bsf		PCLATH,3
		xorlw	TSlideShow
	ifdef	Use4SavingOnly
		addlw	-(SAVE0 & 0x03)
		movwf	Scratch
		andlw	0x03
		movwf	tddH
		movf	Scratch,w
		andlw	0x7C			; Mask toggle bit and set number off
		xorlw	SAVE0 & (~0x03)
	else
		addlw	-(SAVE0 & 0x07)
		movwf	Scratch
		andlw	0x07
		movwf	tddH
		movf	Scratch,w
		andlw	0x78			; Mask toggle bit and set number off
		xorlw	SAVE0 & (~0x07)
	endif
		btfsc	STATUS,Z
		goto	SaveSettings_2K
		movf	Scratch,w
	ifdef	Use4SavingOnly
		addlw	(SAVE0 & 0x03)-(RESTORE0 & 0x03)
		movwf	Scratch
		andlw	0x03
		movwf	tddH
		movf	Scratch,w
		andlw	0x7C			; Mask toggle bit and set number off
		xorlw	RESTORE0 & (~0x03)
	else
		addlw	(SAVE0 & 0x07)-(RESTORE0 & 0x07)
		movwf	Scratch
		andlw	0x07
		movwf	tddH
		movf	Scratch,w
		andlw	0x78			; Mask toggle bit and set number off
		xorlw	RESTORE0 & (~0x07)
	endif
		btfsc	STATUS,Z
		goto	RestoreSettings_2K

		clrf	PCLATH
		goto	ProcessRC5Done	; Default

; ----- Bank 2 ----- Bank 2 ----; Bank 2 active on entry

ToggleScrollMode				; Set Scroll mode - Bank2 active
		incf	ch_flags_RC5,w
		andlw	0x03
		movwf	ch_flags_RC5
		movwf	Scratch
		movlw	RTC_Scrollflags

ScratchToRTC					; Writes Scratch to RTC at address 'w'
		clrf	STATUS			; Bank0, IRP=0
		call	SetRTCWordAddr	; Set word address
		movf	Scratch,w		; Get data
		goto	WriteToRtc		; Switch to Bank0, sets IRP 0

ToggleBrightStep
		movlw	0x11
		xorwf	BrightStep,f	; Toggle step 1 - 16
		movf	BrightStep,w
		movwf	Scratch
		movlw	RTC_BrightStep	; Store it in RTC
		goto	ScratchToRTC

BrightnessMode
		incf	BrightMode,w	;
		andlw	0x33			; Keep bNight and bDark bits
		movwf	BrightMode
		movwf	Scratch
		movlw	RTC_BrightMode	; Get address in RTC
		goto	ScratchToRTC

BrightnessDown
		comf	BrightStep,w	; Get -step
		addlw	1
		goto	SetBrightness

BrightnessUp
		movf	BrightStep,w	; Get step
SetBrightness
		movwf	Scratch
		movlw	low(BrightDay)	; Get address in memory
		movwf	FSR
		btfsc	BrightMode,bNight
		incf	FSR,f
		movf	Scratch,w		; Modify brightness
		bsf		STATUS,IRP
		addwf	INDF,f
		movf	INDF,w
		movwf	Scratch			; Store new brigthness
		movlw	RTC_BrightDay	; Get address in RTC
		btfsc	BrightMode,bNight
		addlw	1
		goto	ScratchToRTC	; Write Scratch to RTC at address 'w'

LightLimitDown
		comf	BrightStep,w	; Get -step
		addlw	1
		goto	SetLightLimit

LightLimitUp
		movf	BrightStep,w	; Get step
SetLightLimit
		addwf	LightLimit,f	; Modify light limit
		movf	LightLimit,w
		movwf	Scratch
		movlw	RTC_LightLimit
		goto	ScratchToRTC	; Store it in RTC

; ----- Bank 0 ----- Bank 0 ----; Bank 0 active on entry

SetPictNumDown
		movlw	RTC_PictNum
		call	SetRTCWordAddr
		decf	PictNum,w
		xorwf	PictNum,w
		andlw	0x1f			; Only 32 pictures - Keeps bit 7
		xorwf	PictNum,f
		goto	RefreshPictNum

SetPictNum
		movlw	RTC_PictNum
		call	SetRTCWordAddr
		incf	PictNum,f
		bcf		PictNum,5		; Only 32 pictures - Keeps bit 7

RefreshPictNum
		movf	PictNum,w
		call	I2CByteWrite
		goto	UpdatePict

ToggleSlideShow
		movlw	0x80			; Toggles bit 7 of PictNum
		xorwf	PictNum,f
		goto	ProcessRC5Done

SetScrollSpDown
		movlw	RTC_ScrollSp	; Address of scrolling speed in RTC
		call	SetRTCWordAddr
		movlw	0x10
		goto	ModScrollSp

SetScrollSp
		movlw	RTC_ScrollSp	; Address of scrolling speed in RTC
		call	SetRTCWordAddr
		movlw	0xF0			; Set scrolling speed

ModScrollSp
		addwf	Language,f
		goto	LanguageToRtc	;

SetLanguage						; Set language
		movlw	RTC_ScrollSp
		call	SetRTCWordAddr
		incf	Language,w
		xorwf	Language,w
		andlw	0x0F			; Only 16 language
		xorwf	Language,f
LanguageToRtc
		movf	Language,w
		goto	WriteToRtc		;

ToggleBinMode					; Toggle BCD display mode
		movlw	RTC_flags5
		call	SetRTCWordAddr
		movlw	(1 << bBCDMode)
		xorwf	RC5_flags,f
		andwf	RC5_flags,w
		goto	WriteToRtc		;

ToggleName
		movlw	(1 << bShowDayName);
		addwf	flags,w
		xorwf	flags,w
		andlw	(1 << bDateFormat) | (1 << bDisp12Mode) | (1 << bShowDayName)
		goto	XorToFlags

ToggleOuterLed
		btfsc	T1CON,bTimeSet	; If time modified
		call	StoreTime		; Write it into RTC
		bcf		T1CON,bTimeSet	; Clear modification flag
		movlw	(1 << bShowOuter);

XorToFlags
		xorwf	flags,f			;

FlagsToRTC						; Save flags settings to RTC ram
		movlw	RTC_flags		; Address Flags
		call	SetRTCWordAddr
		movf	flags,w
WriteToRtc
		clrf	STATUS			; Bank0, IRP=0
		call	I2CByteWrite
		goto	ProcessRC5Done	;

ChgDigitMode					; Change digital clock mode
		movlw	(1 << bShowWDay)
		addwf	flags,f
		goto	FlagsToRTC		;

ChgAnalogHands					; Enable / disable analog hands
	ifdef	SeparateHandHandling
		movlw	(1 << bShowSecHand);
	else
		movlw	(1 << bShowHourHand);
	endif
		addwf	flags3,f
		goto	Flags3ToRTC

ChgAnalogMode					; Change analog hand mode (dot/hand)
		movlw	(1 << bShow36912);
		addwf	flags3,w
		xorwf	flags3,w
		andlw	(1 << bHourMode) | (1 << bMinMode) | (1 << bSecMode) | (1 << bShow36912)

XorToFlags3
		xorwf	flags3,f

Flags3ToRTC						; Save flags3 settings to RTC ram
		movlw	RTC_flags3		; Address Flags3
		call	SetRTCWordAddr
		movf	flags3,w
		goto	WriteToRtc		;

TgAnalogClk						; Toggle Analogue clock mode with inner led goups
		movlw	(1 << bAnalogClk)

XorToFlags4
		xorwf	flags4,f

Flags4ToRtc						; Save flags4 settings to RTC ram
		movlw	RTC_flags4
		call	SetRTCWordAddr
		movf	flags4,w
		goto	WriteToRtc		;

ToggleTicks						; Change tick mode
		movlw	(1 << bShowTicks)
		addwf	flags4,f
		goto	Flags4ToRtc		;

IncDispOffset					; Inc display offset
		incf	DispOffset,w	;
		call 	CheckIncrement 	;
		goto	SetDispOffset

DecDispOffset					; Dec display offset
		decf	DispOffset,w	;
		call 	CheckDecrement	;

SetDispOffset					; Save flags settings to RTC ram
		movwf	DispOffset		;
		movlw	RTC_disp_off	; Address DispOffset
		call	SetRTCWordAddr
		movf	DispOffset,w	;
		goto	WriteToRtc		;

IncSecond
		incf	Second2,f		; Inc seconds
		incf	Second2,f		;
		movlw	.120			;
		subwf	Second2,w		;
		btfsc	STATUS,C		;
ClrSecond						; Clear seconds
		clrf	Second2			;
ClrSubSec
		call	InitSubSecCnt
		goto	TimeSetRC5Done	;

DecSecond
		movlw	.2				; Dec seconds
		subwf	Second2,f		;
		movlw	.120			;
		btfss	STATUS,C		;
		addwf	Second2,f		;
		goto	ClrSubSec		;

IncMinute
		incf	Minute,f		; Inc minute
		movlw	.60				;
		xorwf	Minute,w		;
		btfsc	STATUS,Z		;
StoreMinute
		movwf	Minute			;
		goto	TimeSetRC5Done

DecMinute
		decf	Minute,f		; Dec minute
		btfss	Minute,7
		goto	TimeSetRC5Done	;
		movlw	.59
		goto	StoreMinute

IncHour
		incf	Hour,f			; Inc hour
		movlw	.24				;
		xorwf	Hour,w			;
		btfsc	STATUS,Z		;
StoreHour
		movwf	Hour			;
		goto	TimeSetRC5Done	;

DecHour
		decf	Hour,f			; Dec hour
		btfss	Hour,7
		goto	TimeSetRC5Done	;
		movlw	.23
		goto	StoreHour

IncDay
		decf	DMon,w			; Inc day
		xorwf	Day,w			;
        btfsc	STATUS,Z		;
		clrf	Day				;
		incf	Day,f			;
		goto	TimeSetRC5Done	;

DecDay
		decfsz	Day,f			; Dec day
		goto	TimeSetRC5Done	;
		decf	DMon,w			;
		movwf	Day				;
		goto	TimeSetRC5Done	;

IncMonth
		movlw	.12				; Inc month
		xorwf	Month,w			;
		btfsc	STATUS,Z		;
StoreMonth
		movwf	Month			;
		incf	Month,f			;
		goto	TimeSetRC5Done	;

DecMonth
		decfsz	Month,f			; Dec month
		goto	TimeSetRC5Done	;
		movlw	.11				;
		goto	StoreMonth		;

IncYear							; Increment year -> TimeCheck will correct
		incf	Year,f
		goto	TimeSetRC5Done	;

DecYear							; Dec year
		decf	Year,f
		movlw	.99				;
		btfss	Year,7
		goto	TimeSetRC5Done	;
		movwf	Year

DecCentury						; Decrement century -> TimeCheck will correct
		decf	Century,f
		goto	TimeSetRC5Done	;

IncCentury						; Increment century -> TimeCheck will correct
		incf	Century,f

TimeSetRC5Done
		bcf		flags2,bTimeInv
		bsf		flags2,bNewTime	; force display update
		bsf		T1CON,bTimeSet	;

ProcessRC5Done
		bsf		STATUS,RP1		; Bank2
		movf	RC5_Cmd,w		;
		movwf	RC5_Cmd2		;
		bcf		STATUS,RP1		; Bank0
		bcf		RC5_flags,bRC5_DataReady;

SetOuterLed
		btfss	flags2,bDspEnabled; Displaying disabled
		goto	OuterLedOff
		btfsc	flags,bShowOuter;
		bsf		PORTC,bOuterLED	;
		btfss	flags,bShowOuter;
OuterLedOff
		bcf		PORTC,bOuterLED	;
		return					;

ToggleStaticText				; Static text
		bcf		flags2,bScrollOn; Scrolling OFF
		movlw	(1 << bText)	; toggle Text flag
		xorwf	flags2,f		;

UpdatePict
		btfsc	flags2,bText
		call	PrintDisp		; Print static message
		goto	ProcessRC5Done	;

ToggleText
		call	TextON_OFF		; Scrolling Text mode
		goto	ProcessRC5Done	;

ToggleDemo
		movlw	(1 << bDemo)	;
		xorwf	flags2,f		;
		goto	ProcessRC5Done	;

;******************************************************************************
; Display mode routines

DemoMode						; In demo mode change clock/text when Second2 is 0
		movf	Second2,f		; Test for Second==0
		btfss	STATUS,Z		;
		return

TextON_OFF						; Toggle text mode
		bcf		flags2,bScrollOn; Scrolling OFF
		movlw	(1 << bText)	; toggle Text flag
		xorwf	flags2,f		;
		btfss	flags2,bText	; test Text flag
		return					;
		bsf		flags2,bScrollOn; Scrolling ON

ClearDisplay					; Clear display memory
		call	InitEEData		; Selects Bank2
		bsf		PCLATH,3
		bsf		PCLATH,4		; Page3
		goto	ClearDisplay_6K

;******************************************************************************
;	Read temperature measurement
;******************************************************************************

ReadAd
		bsf		STATUS,RP1		; Bank2
		movf	AD_state,w		; Get A/D state
		movwf	Scratch
		bcf		STATUS,RP1		; Bank0
		btfsc	STATUS,Z
		goto	ADReady			; If A/D state = 0 -> Read result
		btfsc	Scratch,3		; If A/D state < 8 -> Start A/D, A/D state = 15
		return

StartAD
		bsf		ADCON0,GO		; Start A/D conversion
		clrw

SetADState
		bsf		STATUS,RP1		; Bank2
		movwf	AD_state
RetBank0
		clrf	STATUS
		return

ADReady
		movf	ADRESH,w		; Get upper 8 bits of result

AD_Light
		bsf		STATUS,RP1		; Bank2
		movwf	Light			; Store measured value
		bcf		BrightMode,bDark; Clear lighting state
		subwf	LightLimit,w	; Compare to limit

	ifdef	GreatherMeansDarker
		btfss	STATUS,C
	else
		btfsc	STATUS,C
	endif
		bsf		BrightMode,bDark; Dark

		movlw	0x0F
		goto	SetADState

;******************************************************************************
;	Main program
;******************************************************************************

MainLoop
		btfsc	RC5_flags,bRC5_DataReady; RC5_flags is in common area
		call	ProcessRC5		; Process RC5 commands if available

		movf	TmrScroll,f		; Test for Scroll timer
		btfss	STATUS,Z		;
		goto	NoScrolling		;
		movf	Language,w		; Get Scrolling speed
		iorlw	0x0F			; Speeds are 0x0F, 0x1F, ..., 0xEF, 0xFF
		movwf	TmrScroll		; Reinit scrolling timer

		btfsc	flags2,bScrollOn;
		call	ScrollText		;

		btfss	flags2,bText
		goto	NoScrolling		;

		btfsc	PictNum,7		; Slideshow
		call	SlideShow

NoScrolling
		btfsc	flags2,bNewPCnt	; Test Period counter flag
		call	CalcPixelPitch  ; Calculate new pixel pitch

		btfss	ADCON0,GO		; Test for A/D conversion ready
		call	ReadAd			; Read temperature

		btfss	T1CON,bNewRot	; Rotation measurement finished
		goto	CheckNewTime

		bsf		STATUS,RP1		; Bank1
		movf	RotBuffer_L,w	; Copy new rotation count
		movwf	Rotation_L
		movf	RotBuffer_H,w
		movwf	Rotation_H
		bcf		STATUS,RP1		; Bank0
		bcf		T1CON,bNewRot
		bsf		T1CON,bRotAvailable; Sign rotation data available

CheckNewTime
		btfss	flags2,bNewTime	; test new time flag
		goto  	BrightControl	;
								; Half second past. Do timecheck and if text=off, also a display update.
		call	TimeCheck		; Correct date and time
		bsf		PCLATH,3
		bsf		PCLATH,4		; Page3
		call	CalcWDay		; Calculate day of week
		clrf	PCLATH			; Page0
		movwf	WDay

		movlw	MCP9800_ADDR	; Read temperature, most significant byte only
		movwf	dpi
		clrf	tddH			; Select temperature register
		call	I2CByteRead		; Read MCP9800 temperature sensor
		addlw	TEMPR_OFFSET
		movwf	Tempr			; In 9 bit mode Tempr always positive

TestDemo
		btfsc	flags2,bDemo	; Check for demo mode
		call	DemoMode		;

		btfss	flags2,bText	; Test Image flag
		goto  	ReDrawClock		;

		call	DrawInnerHands
		goto	BrightControl

ReDrawClock						; Start display memory update
		clrf	dpi				; dpi = 0
		clrf	TickPos			; Keep index for 5 min timeticks
		movlw	0x20			; Start of display memory

lUpdateDisplay
		movwf	FSR
		clrf	tdd				; Clear temporary display data / patterns iored to tddH:tdd
		clrf	tddH

		btfsc	flags,bShowDTime;
		call	DTime			; Display digital Time

		movf	flags,w
		andlw	(1 << bShowDDate) | (1 << bShowWDay)
		btfss	STATUS,Z
		call	DDate			; Display digital Date

		call	Hands			; Analogue clock's hands

		btfsc	flags4,bShowTicks;
		call	Ticks			; Analogue clock's ticks

		btfsc	flags3,bShow36912;
		call	Draw36912		; XII, III, VI, IX around the clock

		movf	flags,w			; Check for show rotation speed and brightness...
		andlw	(1 << bShowDDate) | (1 << bShowDTime) | (1 << bShowWDay)
		btfss	STATUS,Z
		goto	StoreTdd
		movf	flags3,w
		andlw	(1 << bShowHourHand) | (1 << bShowMinHand) | (1 << bShowSecHand) | (1 << bShow36912)
		btfss	STATUS,Z
		goto	StoreTdd

		call	DTime			; Display Rotation
		call	DDate			; Display Brightness

StoreTdd
		movf	tdd,w			; Store data in
		movwf	INDF			; display memory
		bsf		STATUS,IRP		; Ind will use Bank 2 & 3
		movf	tddH,w			; Store high data
		movwf	INDF			; high display memory
		bcf		STATUS,IRP		; Ind will use Bank 0 & 1

		incf	dpi,f			; Check for end of buffer
		movlw	.120			;
		xorwf	dpi,w			;
		btfsc	STATUS,Z		;
		goto  	BrightControl	; Leave if end of buffer
		call	CheckIncrementFSR; Move pointer
		goto	lUpdateDisplay	; Loop for all positions

BrightControl
		movlw	Hour
		movwf	FSR
		bsf		STATUS,RP1		; Bank2
		btfss	BrightMode,0	; Test for static controll
		goto	SetStatic

		btfsc	BrightMode,1	; Check for mode
		goto	AutoPwm

		bsf		BrightMode,bNight; Timed controll
		movlw	.8
		subwf	INDF,w
		btfsc	STATUS,C
		bcf		BrightMode,bNight

		movlw	.20
		subwf	INDF,w
		btfsc	STATUS,C
SetNight
		bsf		BrightMode,bNight; Use night setting
SetBr
		movf	BrightDay,w
		btfsc	BrightMode,bNight
		movf	BrightNight,w
		clrf	STATUS			; Bank0
		movwf	Brightness		; Write to actual brightness in CCPR1L
		goto	MainLoop

SetStatic						; Static controll
		btfss	BrightMode,1	; Test for night setting to be used
		goto	SetDay
		goto	SetNight

AutoPwm							; Light measurement based controll
		btfsc	BrightMode,bDark; Test for light intensity > limit
		goto	SetNight
SetDay
		bcf		BrightMode,bNight; Use daily setting
		goto	SetBr

;******************************************************************************
;	Text display functions
;******************************************************************************

InitEEData
		bsf		STATUS,RP1		; Bank2
		movlw	' '
		movwf	EEDATA			; Prepare for first character
		movlw	0x80
		andwf	EEADR,f			; Start of message
		return

;******************************************************************************
;	Scrolling function

ScrollText
		bsf		STATUS,RP1		; Bank2

      	movf	ch_dot_index,w	;
		btfss	STATUS,Z		; dot_index == 0 ?
		goto	Scroll_0

		movf	ch_blanking,w	; Blanking at the end of message
		btfsc	STATUS,Z		;
		goto	Scroll_read_ee	; More message characters to display
		decfsz	ch_blanking,f	;
		goto	Scroll_2		; Insert one more " "

		call	InitEEData		; Selects Bank2
		xorwf	EEADR,f			; Change message

		movf	ch_flags_RC5,w	; Copy ch_flags, but keep bDemo_sc
		xorwf	ch_flags,w
		andlw	0x03
		xorwf	ch_flags,f

		btfss	ch_flags,bDemo_sc; in demo mode?
		goto	Scroll_read_ee	; re-read char
;;++
		btfss	ch_flags,bAlternateScroll
		goto	TextON_OFF		; At end of line, turn text off!

		movlw	0x80
		btfsc	ch_flags,bDateToScroll
		xorwf	EEADR,f

		movlw	1 << bDateToScroll
		xorwf	ch_flags,f
;;++
;		bcf		STATUS,RP1		; Bank0 / TextON_OFF may called with Bank2 selected
		goto	TextON_OFF		; At end of line, turn text off!

Scroll_read_ee
		movf	EEDATA,w
		btfss	STATUS,Z		; If Z, end of message
		goto	Scroll_1		;

		movlw	0x0F			; Insert 15 " " at end of string to clear display
		movwf	ch_blanking		;

Scroll_2
		movlw	" "				; w = " "

Scroll_1
		call	ConvToInternalNotBin
		movlw	6
		movwf	ch_dot_index	; Reinit dot counter

Scroll_0
		call	CharTable
		clrf	PCLATH			; Call / Goto in first 2K
		movwf	Scratch			;
		call	IncBCD16		; Move index of character table

	ifdef ReversTextScroll
		movlw	0xE4			; Start at begin of 7 o'clock character
	else
		movlw	0xBF			; Start at end   of 5 o'clock character
	endif
		movwf	FSR				;

ScrollLoop
		movf	INDF,w			; Get current display data = Previous_INDF
		xorwf	Scratch,w		; W = (Previous_INDF ^ Scratch)
		xorwf	INDF,f			; INDF = (Previous_INDF ^ Scratch) ^ Previous_INDF = Scratch
		xorwf	Scratch,f		; Scratch = (Previous_INDF ^ Scratch) ^ Scratch = Previous_INDF

	ifdef ReversTextScroll
		call	CheckIncrementFSR; Move pointer
		movwf	FSR				;
		xorlw	0xC0			; Check end of 5 o'clock character
	else
		call	CheckDecrementFSR; Move pointer
		movwf	FSR				;
		xorlw	0xE3			; Check begin of 7 o'clock character
	endif

		btfss 	STATUS,Z		; FSR = 0xE4 ? (or 0xC0)
		goto	ScrollLoop		;

		decfsz	ch_dot_index,f
		goto	RetBank0
;;--
;;		btfss	ch_flags,bDemo_sc; Use the copy of demo mode flag
;;		btfss	ch_flags,bScrollDateTime
;;		goto	EPROM_READ
;;--
;;++
		btfss	ch_flags,bDateToScroll
		goto	EPROM_READ
;;++

GetNextTimeChar
								; Char index is in EEADR called with Bank2
		movf	EEADR,w			; Get address
		andlw	0x7F
		movwf	digitindex		; Check for start of message
		btfsc	STATUS,Z
		call	CopyTime		; Copy date, time, temperature, Language,...
		movf	digitindex,w
		call	Conv2BCD		; A part of message has 10 characters
		movwf	BCD				; Get table number from high nibble of BCD
		andlw	0x0F
		movwf	digitindex		; Store index

		btfsc	BCD,6			; If table number >=4 end of message
		goto	ScrEnd

		btfsc	BCD,5			; Table 2 and 3
		goto	ScrDayTemp

		btfsc	BCD,4			; Table 1 is Time
		goto	ScrTime

ScrDate							; Table 0 is Date
		sublw	9				; Reverse index
		movwf	digitindex
		call	LoadBCDDate		; Get next char of date
		goto	ScrExit

ScrTime
		call	LoadBCDTime		; Get next char ot time
		goto	ScrExit

ScrDayTemp
		btfss	BCD,4
		goto	ScrDay

ScrTemp							; Table 3 is temperature
		sublw	9				; Reverse index
		movwf	digitindex
		call	LoadBCDTemp		; Get next char on age of Moon and temperature
		goto	ScrExit

ScrDay							; Table 2 is name of day
		bcf		RC5_flags,bUseBinFont

		movf	Language_sc,w	; Get language code

		call	DayAddress

		movf	digitindex,w	; Add digitindex
		call	AddBCD16
		movlw	high(DayNames)	; Add address of table
		call	CharPattern		; Get next character
		clrf	PCLATH			; Use page 0
		goto	ScrExit

ScrEnd
		clrw					; End of message

ScrExit
		movwf	EEDATA			; Store new character
		goto	IncEEAdr

EPROM_READ
		bsf		STATUS,RP0		; Bank3
		bsf		EECON1,RD		; Read character from EEProm
		bcf		STATUS,RP0		; Bank2
IncEEAdr
		movf	ch_blanking,f
		btfsc	STATUS,Z
		incf	EEADR,f			; Inc address for next read
		goto	RetBank0

; Problem of scrolling message with data in it:
; While scrolling the message, data can change - so a part of old data mixed with outher part of new data may be scrolled
; To avoid this date, time, temperature, language code copied to a buffer
; To use the original routines written for the clock, the buffer is on same address but on an other bank.
; Real time data are on Bank0 - buffered are on Bank2

CopyTime
		movlw	Second2			; Copy from Second2 to Language
		movwf	FSR
		movlw	Language+1-Second2
		movwf	BCD
CopyLoop
		movf	INDF,w			; Get data from Bank0
		bsf		STATUS,IRP
		movwf	INDF			; Write it to Bank2
		bcf		STATUS,IRP
		incf	FSR,f
		decfsz	BCD,f
		goto	CopyLoop
		return

;******************************************************************************
;	Static picture functions

SlideShow						; Slide show
		bsf		STATUS,RP1		; Bank2
		decfsz	ch_slidecnt,f	; Counter = 0
		goto	RetBank0		; No, return and select Bank0

		bsf		ch_slidecnt,7	; Speed up scrolling

		movf	PictNum_sc,w	; Get picture number
		incf	PictNum_sc,f
		andlw	0x0F
		iorlw	0x10
		bcf		STATUS,RP1		; Bank0
		goto	DispPict

PrintDisp						; Show a picture
		call	ClearDisplay	; Clear display content Clear EEADR, reutrns with Bank0
		movf	PictNum,w
		andlw	0x1F
	ifdef	UseZodiacRing
		btfsc	STATUS,Z
		goto	DispZodiac		; Pict0 is Zodiac ring
	endif

DispPict						; Draw the picture
		movwf	Scratch
		clrf	BCD_High		; Copy pictnum to BCD_High
		clrf	BCD				; Convert picnum to memory address

DispPictMull					; Pictures use 120 bytes
		addlw	0
		btfsc	STATUS,Z
		goto	DispPictMull0
		movlw	.120
		call	AddBCD16
		decfsz	Scratch,f
		goto	DispPictMull
DispPictMull0
		movlw	0xD1			; Start at 6'o clock
		goto	DispPict0

DispZodiac						; Draw Zodiac ring - current symbol at top
		clrf	BCD_High
		decf	Month,w			; Get month
		movwf	Scratch			; Store as symbol munber
		addlw	low(ZodiacDay)	; Look for change day
		movwf	BCD
		movlw	high(ZodiacDay)
		call	CharPattern		; Get day of change
		clrf	PCLATH			; Use page 0

		subwf	Day,w			; If Day >= Change day  - inc symbol number
		btfsc	STATUS,C
		incf	Scratch,f
		movlw	.12				; Modulo 12
		xorwf	Scratch,w
		btfss	STATUS,Z
		movf	Scratch,w
		call	Mult10			; A symbol has 10 bytes
		movlw	0x20+.25		; Start at top-5

DispPict0
		movwf	Scratch2
		movwf	FSR				; Store start address

DispPict1
		movlw	high(Pict00)
		call	CharPattern		; Get next data
		clrf	PCLATH			; Use page 0

		movwf	INDF			; Store in buffer
		call	IncBCD16		; Move memory pointer

		movf	BCD,w
		xorlw	.120
		iorwf	PictNum,w
		btfsc	STATUS,Z
		clrf	BCD				; Clear pict pointer if >=120 for Zodiac ring

		call 	CheckIncrementFSR; Move pointer
		movwf	FSR				;
		xorwf	Scratch2,w		; Check for end of buffer
		btfss	STATUS,Z
		goto	DispPict1

DrawInnerHands
		bsf		STATUS,IRP		; IRP = 1
		clrf	dpi				; dpi = 0
		movlw	0x20			; Start of display memory

InnerHandsLoop
		movwf	FSR
		clrf	tddH
		btfss	flags4,bAnalogClk
		goto	S_Store

		movlw	.30				; difference in offset for hands and digital display
		subwf	dpi,w			; scratch4 = dpi - 30
		btfss	STATUS,C		; if scratch4 < 0 then
		addlw	.120			;    scratch4 = scratch4 + 120
		movwf	Scratch4		;

		movf	Second2,w		;
		andlw	0xFE			; filter out 1/2 second
		xorwf	Scratch4,w		;
		btfsc	STATUS,Z
		call	SetAllInner		; Turn on all inner leds

		movlw	.60
		subwf	Second2,w		; Set C if Second2 >= .60
		rlf		Minute,w		; Clears C, because Minute < .60
		movwf	Scratch			; Scratch = Minute * 2

		xorwf	Scratch4,w		;
		movlw	(1 << bAnalogL0) | (1 << bAnalogL1) | (1 << bAnalogL2)
		btfsc	STATUS,Z
		iorwf	tddH,f

		call	CalcHourHand

S_120
		subwf	Scratch2,f		;
		btfsc	STATUS,C		; result > 0 ?
		goto	S_120
		addwf	Scratch2,w		; result was negative, re-add 120 and load it in w

		xorwf	Scratch4,w		;
		movlw	(1 << bAnalogL0) | (1 << bAnalogL1)
		btfsc	STATUS,Z
		iorwf	tddH,f

S_Store
		movf	tddH,w
		movwf	INDF
		incf	dpi,f
		movlw	.120			;
		xorwf	dpi,w			;
		btfsc	STATUS,Z		;
		goto	RetBank0		; Leave if end of buffer, IRP = 0
		call	CheckIncrementFSR; Move pointer
		goto	InnerHandsLoop	; Loop for all positions

;******************************************************************************
;	Some general functions
;******************************************************************************

;- check correct decrement of Display memory pointer
CheckDecrementFSR
		decf	FSR,w
CheckDecrement
		xorlw	0x1F			;
		btfsc	STATUS,Z		;
		movlw	0xEF ^ 0x1F		;
		xorlw	0x9F ^ 0x1F		;
		btfsc	STATUS,Z		;
		movlw	0x47 ^ 0x9F		;
		xorlw	0x9F			;
		return					;

;- check correct increment of Display memory pointer
CheckIncrementFSR
		incf	FSR,w
CheckIncrement
		xorlw	0x48			;
		btfsc	STATUS,Z		;
		movlw	0xA0 ^ 0x48		;
		xorlw	0xF0 ^ 0x48		;
		btfsc	STATUS,Z		;
		movlw	0x20 ^ 0xF0		;
		xorlw	0xF0			;
		return					;

;******************************************************************************
;	I2C RTC functions
;******************************************************************************

SetRTCWordAddr
		movwf	tddH			; Save word address

SetRTCSlaveAddr
		movlw	RTC_ADDR		; Get slave address of RTC
		movwf	dpi				; Save slave address
		return

InitTime						; Init time from I2C RTC
		movlw	RTC_Tenms		; Address of 1/100 Seconds
		call	SetRTCWordAddr
								; tddH = 0x01
		clrf	Second2
		call	I2CByteRead		; Read seconds
		addlw	-0x50			; C = 1 if ms >= .50 (BCD codeing read from RTC)
		rlf		Second2,f		; Set half seconds
								; tddH = 0x02

		call	InitSubSecCnt	; Reload counter SubSecond = 0x10000 - .2500 = 0xF63C, returns 0x00

		call	I2CByteRead		; Read seconds (BCD)
		call	BcdToBin
		addwf	Second2,f
		addwf	Second2,f
								; tddH = 0x03

		call	I2CByteRead		; Read minute (BCD)
		call	BcdToBin
		movwf	Minute
								; tddH = 0x04

		call	I2CByteRead		; Read hour (BCD)
		call	BcdToBin3F		; Mask format and AM/PM
		movwf	Hour
								; tddH = 0x05

		call	I2CByteRead		; Read day (BCD)
		call	BcdToBin3F
		movwf	Day
		swapf	tdd,f
		rrf		tdd,f
		rrf		tdd,w
		andlw	0x03
		movwf	Scratch6		; Save year bit 1..0
								; tddH = 0x06

		call	I2CByteRead		; Read Month (BCD)
		andlw	0x1F
		call	BcdToBin
		movwf	Month
								; tddH = 0x07

		movlw	RTC_Year		; Address of Year
		call	I2CByteReadSetAddr; Read year
		movwf	Year
		andlw	0x03
		movwf	Scratch5
								; tddH = 0x11

		call	I2CByteRead		; Read year ^ 0xff
		xorlw	0xFF
		xorwf	Year,w
								; tddH = 0x12

		btfss	STATUS,Z
		goto	InitTimeDef		; Year not valid, init with default values

		call	I2CByteRead		; Read Century
		movwf	Century
								; tddH = 0x13

		call	I2CByteRead		; Read flags
		movwf	flags
								; tddH = 0x14

		call	I2CByteRead		; Read DispOffset
		movwf	DispOffset
		call	ValidateOffs
								; tddH = 0x15

		call	I2CByteRead		; Read Scroll speed and Language
		movwf	Language
								; tddH = 0x16

		call	I2CByteRead		; Read flags3
		movwf	flags3
								; tddH = 0x17

		call	I2CByteRead		; Read flags4
		movwf	flags4
								; tddH = 0x18

		call	I2CByteRead		; Read Brightstep
		andlw	0x01
		btfsc	STATUS,Z
		iorlw	0x10
		bsf		STATUS,RP1		; Bank2
		movwf	BrightStep
								; tddH = 0x19

;		bcf		STATUS,RP1		; Bank0
		call	I2CByteRead		; Read flags5
		andlw	(1 << bBCDMode)
		iorwf	RC5_flags,f
								; tddH = 0x1A

		call	I2CByteRead		; Read ch_flags
		bsf		STATUS,RP1		; Bank2
		andlw	0x03
		movwf	ch_flags_RC5
;		bcf		STATUS,RP1		; Bank0
								; tddH = 0x1B

		call	I2CByteRead		; Read PictNum
		andlw	0x1F
		movwf	PictNum
								; tddH = 0x1C

		call	I2CByteRead		; Read Bright mode
		andlw	3
		bsf		STATUS,RP1		; Bank2
		movwf	BrightMode
								; tddH = 0x1D

		call	I2CByteRead		; Read Bright Daytime
		bsf		STATUS,RP1		; Bank2
		movwf	BrightDay
;		bcf		STATUS,RP1		; Bank0
								; tddH = 0x1E

		call	I2CByteRead		; Read Bright Night
		bsf		STATUS,RP1		; Bank2
		movwf	BrightNight
;		bcf		STATUS,RP1		; Bank0
								; tddH = 0x1F

		call	I2CByteRead		; Read Light limit
		bsf		STATUS,RP1		; Bank2
		movwf	LightLimit
								; tddH = 0x20

		bcf		STATUS,RP1		; Bank0

		movf	Scratch5,w		; Has the RTC increment Year
		subwf	Scratch6,w		; W = (RTC_Year % 4) - (Year % 4)
		movwf	Scratch6
		btfsc	Scratch6,7
		addlw	4
		andlw	7
		bcf		Scratch6,0		; No correction was made
		btfss	STATUS,Z
		bsf		Scratch6,0		; Correction was made
		addwf	Year,f			; Yes, increment Year

		movlw	Year			; Prepare to check Year and Century
		movwf	FSR
		call	CheckYear		; Will correct year and century for leap year
		call	TimeCheck		; Will correct date and time
		btfss	Scratch6,0		; If correction was made, save date to RTC
		return

		movlw	0x80			; Disable counting command
		call	SendRtcCmd
		goto	StoreDate

StoreTime
		call	SetRTCSlaveAddr	;
		movlw	0x80			; Disable counting command
		call	SendRtcCmd
								; tddH = 0x01

		clrw
		btfsc	Second2,0		; Store subsec
		addlw	0x50
		call	I2CBcdWrite
								; tddH = 0x02

		bcf		STATUS,C		; Store Second
		rrf		Second2,w
		call	I2CBcdWrite
								; tddH = 0x03

		movf	Minute,w		; Store Minute
		call	I2CBcdWrite
								; tddH = 0x04

		movf	Hour,w			; Store Hour
		call	I2CBcdWrite
								; tddH = 0x05
StoreDate
		movlw	RTC_Day			; Address of Day
		call	SetRTCWordAddr
								; tddH = 0x05
		movf	Day,w
		call	Conv2BCD
		btfsc	Year,0			; Store Day and Year bit 1..0
		iorlw	0x40
		btfsc	Year,1
		iorlw	0x80
		call	I2CByteWrite
								; tddH = 0x06

		movf	Month,w
		call	I2CBcdWrite
								; tddH = 0x07

		movlw	0x00			; Enable counting command
		call	SendRtcCmd
								; tddH = 0x01
		movlw	RTC_Year		; Address Year
		movwf	tddH
								; tddH = 0x10
		movf	Year,w
		call	I2CByteWrite
								; tddH = 0x11
		comf	Year,w
		call	I2CByteWrite
								; tddH = 0x12
		movf	Century,w
		goto	I2CByteWrite

ValidateOffs
		movlw	0x20
		subwf	DispOffset,w
		btfss	STATUS,C
		goto	DifDispOffs
		movlw	0xF0
		subwf	DispOffset,w
		btfsc	STATUS,C
		goto	DifDispOffs
		movlw	0xA0
		subwf	DispOffset,w
		btfsc	STATUS,C
		return
		movlw	0x48
		subwf	DispOffset,w
		btfss	STATUS,C
		return
DifDispOffs
		movlw	DISPLAYOFFSET
		movwf	DispOffset
		return

InitTimeDef
		movlw	.12				; Why do clocks always start
		movwf	Hour			;  at 12:00 ?
		clrf	Minute
        clrf	Second2
		movlw	.1
		movwf	Day
;		clrf	WDay			; 01-01-2001 was monday
		movwf	Month
		movwf	Year
		movlw	.20
		movwf	Century

		bsf		flags2,bTimeInv

		movlw	RTC_flags
		movwf	tddH
								; tddH = 0x13

;;1		movlw	(1 << bShowDTime) | (1 << bShowDDate) | (1 << bShowOuter) | (1 << bShowDayName) | (1<<bShowWDay)
		movlw	(1 << bShowDTime) | (1 << bShowDDate) | (1 << bShowOuter) | (1 << bShowWDay)
		movwf	flags			; Init flags
		call	I2CByteWrite	; Store it in RTC
								; tddH = 0x14

								; Display offset
		movlw	DISPLAYOFFSET	; Initial Display Offset for the hardware
		movwf	DispOffset		;
		call	I2CByteWrite	; Store it in RTC
								; tddH = 0x15

		movlw	0xF0			; Scroll speed and Language
		movwf	Language
		call	I2CByteWrite	; Store it in RTC
								; tddH = 0x16

		movlw	(1 << bShowHourHand) | (1 << bShowMinHand) | (1 << bShowSecHand)
		movwf	flags3			; Init flags3
		call	I2CByteWrite	; Store it in RTC
								; tddH = 0x17

		movlw	(1 << bShowTicks)
		movwf	flags4			; Init flags4
		call	I2CByteWrite	; Store it in RTC
								; tddH = 0x18

		movlw	1
		bsf		STATUS,RP1		; Bank2
		movwf	BrightStep		; Init BrightStep
		call	I2CByteWrite	; Store it in RTC
								; tddH = 0x19
		movlw	0
;		iorwf	RC5_flags,f		; Init flags5
		call	I2CByteWrite	; Store it in RTC
								; tddH = 0x1A
;		movlw	0
		bsf		STATUS,RP1		; Bank2
		movwf	ch_flags_RC5	; Init scroll flags
;		bcf		STATUS,RP1		; Bank0
		call	I2CByteWrite	; Store it in RTC
								; tddH = 0x1B

;		movlw	0x0				; Pict number
		movwf	PictNum
		call	I2CByteWrite	; Store it in RTC
								; tddH = 0x1C

		movlw	0x03			; Brightness mode
		bsf		STATUS,RP1		; Bank2
		movwf	BrightMode
		call	I2CByteWrite	; Store it in RTC
								; tddH = 0x1D

		movlw	0xF0			; Brightness for daytime
		bsf		STATUS,RP1		; Bank2
		movwf	BrightDay
;		bcf		STATUS,RP1		; Bank0
		call	I2CByteWrite	; Store it in RTC
								; tddH = 0x1E

		movlw	0x20			; Brightness night
		bsf		STATUS,RP1		; Bank2
		movwf	BrightNight
;		bcf		STATUS,RP1		; Bank0
		call	I2CByteWrite	; Store it in RTC
								; tddH = 0x1F

		movlw	0x80			; External light level
		bsf		STATUS,RP1		; Bank2
		movwf	LightLimit
		call	I2CByteWrite	; Store it in RTC

		clrf	FSR
InitSaveSets
		movf	FSR,w			; Initialize the 8 stored settings
		movwf	tddH
		bsf		PCLATH,3		; Pape2
		call	StoreSettings_2K; Clears PCLATH
		incf	FSR,f
		btfss	FSR,3
		goto	InitSaveSets	; Loop for 8 setting sets
		return

BcdToBin3F
		andlw	0x3F
BcdToBin						; Uses only numbers < 60
		movwf	Scratch2
		andlw	0x0F
		btfsc	Scratch2,4
		addlw	.10
		btfsc	Scratch2,5
		addlw	.20
		btfsc	Scratch2,6
		addlw	.40
;		btfsc	Scratch2,7
;		addlw	.80
		return

SendRtcCmd
		clrf	tddH			; tddH = 0x00
		goto	I2CByteWrite

;*****************************************************************

; Only dpi, tdd and tddH used in MSSP I2C routines.
; Not to call them from ReDrawClock cycle

;*******************Start bit subroutine**************************
;           This routine generates a Start condition
;           (high-to-low transition of SDA while SCL
;           is still high.
;*****************************************************************
I2CBSTART
		bcf		STATUS,RP1		; Bank0 but keep IRP
		bcf		STATUS,RP0
	    bcf     PIR1,SSPIF		; Clear SSP interrupt flag
	    bsf     STATUS,RP0		; Select Bank1
	    bsf     SSPCON2,SEN		; Generate Start condition
		goto	I2Cbstop_wait0

;*******************Restart bit subroutine**************************
;           This routine generates a Repeated Start
;           condition (high-to-low transition of SDA
;           while SCL is still high.
;*****************************************************************
;I2CBRESTART
;	    bcf     PIR1,SSPIF		; Clear SSP interrupt flag
;	    bsf     STATUS,RP0		; Select Bank1
;	    bsf     SSPCON2,RSEN	; Generate Restart condition
;		goto	I2Cbstop_wait0

;*******************Data transmit subroutine**********************
;           This routine transmits the byte of data
;           stored in w to the I2C serial
;           device.
;*****************************************************************

I2CTXSlaveReadAddr
		movf	dpi,w			; Load control byte for write
		andlw   0xFE			; Can be removed if all addresses are even

I2CTX
	    bcf		PIR1,SSPIF		; Clear SSP interrupt flag
    	movwf	SSPBUF			; Write byte out to device

		goto	I2Cbstop_wait0	; Wait for oparation completed

;*******************Byte read test subroutine*********************
;           This routine tests the byte read feature
;           of the I2C serial device.  It will read
;           1 byte of data at address I2CAddress from the device.
;*****************************************************************

I2CByteReadSetAddr
		movwf	tddH			; Store word address

I2CByteRead						; Returns data just read from RTC, increments word address
		call	I2CBSTART		; Generate Start condition

    	call    I2CTXSlaveReadAddr; Send control byte to device

		movf	tddH,w			; Get address
    	call    I2CTX			; Send address to device

;    	call    I2CBRESTART		; Generate Restart condition
	    bcf     PIR1,SSPIF		; Clear SSP interrupt flag
	    bsf     STATUS,RP0		; Select Bank1
	    bsf     SSPCON2,RSEN	; Generate Restart condition
		call	I2Cbstop_wait0
								; Send control byte
		movf	dpi,w			; Load control byte for read
		iorlw	0x01			; incf dpi,w can be used instead
    	call    I2CTX			; Send control byte to device

								; Read data byte
    	bcf     PIR1,SSPIF		; Clear SSP interrupt flag
    	bsf     STATUS,RP0		; Select Bank1
    	bsf     SSPCON2,ACKDT	; Select to send NO ACK bit
    	bsf     SSPCON2,RCEN	; Initiate reception of byte

		call	I2Cbstop_wait0	; Wait for oparation completed

    	movf    SSPBUF,W		; Copy byte to WREG

    	bcf     PIR1,SSPIF		; Clear SSP interrupt flag
    	bsf     STATUS,RP0		; Select Bank1
    	bsf     SSPCON2,ACKEN	; Generate ACK/NO ACK bit

		call	I2Cbstop_wait0	; Wait for oparation completed

		movwf	tdd				; Save data

;*******************Stop bit subroutine***************************
;           This routine generates a Stop condition
;           (low-to-high transition of SDA while SCL
;           is still high.
;*****************************************************************
I2CBSTOP
		incf	tddH,f			; Increment word address

	    bcf     PIR1,SSPIF		; Clear SSP interrupt flag
	    bsf     STATUS,RP0		; Select Bank1
	    bsf     SSPCON2,PEN		; Generate Stop condition
I2Cbstop_wait0
	    bcf     STATUS,RP0		; Select Bank0
bstop_wait
	    btfss   PIR1,SSPIF		; Check if operation completed
	ifdef	DebugI2C
		return
	else
	    goto    bstop_wait		; If not, keep checking
	endif
    	return

;*******************Byte write test subroutine********************
;           This routine tests the byte write feature
;           of the I2C serial device.
;*****************************************************************

I2CBcdWrite
		call	Conv2BCD		; Convert to BCD

I2CByteWrite					; Returns data written to device, increments word address
		movwf	tdd				; Store data

	    call    I2CBSTART		; Generate Start condition

    	call    I2CTXSlaveReadAddr; Send control byte to device

		movf	tddH,w			; Get address
	    call    I2CTX

		movf	tdd,w			; Get data
    	call    I2CTX			; Send data byte to device

	   	goto    I2CBSTOP		; Generate Stop condition

;******************************************************************************
;	Base conversion function for rotation displaying
;******************************************************************************

Word2Bcd5
		movlw	0xff			; Blank display
		movwf	Scratch
		movwf	Scratch2
		movwf	Scratch3
		btfss	T1CON,bRotAvailable; If available convert and remove leading 0s
		return

		clrf	Scratch7
		bsf		STATUS,RP1		; Bank2
		movf	Rotation_H,w	; Convert binary rotation count to Scratch6:Scartch5
		movwf	Scratch6
		movf	Rotation_L,w
		bcf		STATUS,RP1		; Bank0
		movwf	Scratch5
		call	BIN2BCD24

Leading0
		clrf	Scratch6		; Remove first 3 leading 0s
		movf	Scratch3,w
		andlw	0x0F
		iorwf	Scratch6,f
		movlw	0x0F
		btfsc	STATUS,Z
		iorwf	Scratch3,f
		movf	Scratch2,w
		andlw	0xF0
		iorwf	Scratch6,f
		movlw	0xF0
		btfsc	STATUS,Z
		iorwf	Scratch2,f
		movf	Scratch2,w
		andlw	0x0F
		iorwf	Scratch6,f
		movlw	0x0F
		btfsc	STATUS,Z
		iorwf	Scratch2,f
		return

; Convert 24 bit binary number in Scratch7:Scratch6:Scartch5
; to a 32 bit packed BCD number in Scratch4:Scratch3:Scratch2:Scratch
; FSR save to Scratch8, Scratch9 used for loop counter

BIN2BCD24						; 24 bit binary to BCD converter
		movf	FSR,w			; FSR saved to Scratch6
		movwf	Scratch8

		movlw   .24
        movwf   Scratch9
		clrf	Scratch
		clrf	Scratch2
		clrf	Scratch3
		clrf	Scratch4
		clrc
        goto    BIN2BC2

BIN2L
		movlw	Scratch
		movwf	FSR
BCDADJ
		movlw	0x33
		addwf	INDF,F
		btfsc	INDF,3
		andlw	0xF0
		btfsc	INDF,7
		andlw	0x0F
		subwf	INDF,F
		incf	FSR,F
		btfss	FSR,2
		goto	BCDADJ

BIN2BC2
		rlf		Scratch5,F		; Shift Low   byte
		rlf		Scratch6,F		; Shift High  byte
		rlf     Scratch7,F		; Shift Upper byte
		rlf 	Scratch,F		; Shift BCD   bytes
		rlf     Scratch2,F
		rlf     Scratch3,F
		rlf     Scratch4,F		; Since Scratch4 was cleared, C = 0
		decfsz  Scratch9,F
		goto    BIN2L
		movf	Scratch8,w		; Restore FSR
		movwf	FSR
		return

;******************************************************************************

	org	0x0C84

CharPatternBin_2K				; Binary font is simple
		movf	dotindex,w
		xorlw	0x03			; If dotidex != 3
		btfss	STATUS,Z
		retlw	0				; Return 0
		movf	BCD,w
		addlw	-(0x60)			; Else return (BCD-0x60) / 6
		clrf	Scratch
lBin1_2K
		addlw	-6
		incf	Scratch,f
		btfsc	STATUS,C
		goto	lBin1_2K
		decf	Scratch,w
		return

;******************************************************************************

SaveSettings_2K
		call	StoreSettings_2K; Save current setting
		goto	ProcessRC5Done	; Return trough ProcessRC5Done on Page0

StoreSettings_2K
		call	GetSettingAddr_2K; Get address on stored set
		movf	tddH,w			; Write index
		call	I2CByteWrite
		movlw	(1 << bBCDMode)
		andwf	RC5_flags,w		; Store flags5
		iorlw	0x05			; Add validation code
		call	I2CByteWrite
		movf	flags,w			; Store flags
		call	I2CByteWrite
		movf	flags3,w		; Store flags3
		call	I2CByteWrite
		movf	flags4,w		; Store flags4
		call	I2CByteWrite
		movf	Language,w		; Store language and scroll speed
		call	I2CByteWrite
		movf	PictNum,w		; Store picture number
		call	I2CByteWrite
		bsf		STATUS,RP1		; Bank2
		movf	ch_flags_RC5,w	; Store scroll flags
		goto	I2CByteWrite

RestoreSettings_2K
		call	GetSettingAddr_2K; Get address on stored set
		movf	tddH,w
		movwf	FSR
		call	I2CByteRead		; Read index
		xorwf	FSR,w
		btfss	STATUS,Z
		goto	ProcessRC5Done	; Return if not equal
		call	I2CByteRead		; Read flags5
		andlw	0x1F
		xorlw	0x05
		btfss	STATUS,Z		; Check for valid data
		goto	ProcessRC5Done	;
		btfsc	tdd,bBCDMode	; Modify RC5_flags
		bsf		RC5_flags,bBCDMode
		btfss	tdd,bBCDMode
		bcf		RC5_flags,bBCDMode
		call	I2CByteRead
		movwf	flags			; Get flags
		call	I2CByteRead
		movwf	flags3			; Get flags3
		call	I2CByteRead
		movwf	flags4			; Get flags4
		call	I2CByteRead
		movwf	Language		; Get language and scroll speed
		call	I2CByteRead
		andlw	0x1F
		movwf	PictNum			; Get picture number
		call	I2CByteRead
		andlw	0x03
		bsf		STATUS,RP1		; Bank2
		movwf	ch_flags_RC5	; Store scroll flags
		clrf	STATUS
		goto	ProcessRC5Done	; Return trough ProcessRC5Done on Page0

GetSettingAddr_2K
		clrf	PCLATH			; Page0
		swapf	tddH,f			; Multiply by 8
		rrf		tddH,w
		andlw	0x38
		addlw	RTC_SettingSets	; Add stert address
		goto	SetRTCWordAddr	; Return trough SetRTCWordAddr on Page0

;******************************************************************************

	org	0x1F00

;******************************************************************************
;	Calculating Day of week using Julian Day Number mod 7 method
;******************************************************************************

CalcWDay						; Calculates day of week
		call	JulianDay00

FXD3216UBy700
		clrf	Scratch6		; .256 * JDN / 0x700
		clrf	Scratch4
		movlw	7

FXD3216U_StoreDivH
		movwf	Scratch5		; At return W holds WDay (0 - Monday, 6 - Sunday)

;Inputs:
;   Dividend - Scratch:Scratch2:Scratch3:Scratch4 - Scratch is the most significant
;   Divisor  - Scratch5:Scratch6
;Temporary:
;   Counter  - Scratch7
;   Remainder- Scratch9:Scratch8
;Output:
;   Quotient - Scratch:Scratch2:Scratch3:Scratch4
;

FXD3216U						; Call with Bank2 selected
		clrf	Scratch8		; Clear result
		clrf	Scratch9
		movlw	.32
		movwf	Scratch7

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		Scratch8,F		; Shift carry into remainder
		rlf		Scratch9,F

		rlf		Scratch7,F		; Save carry in counter

		movf	Scratch6,W		; Substract divisor from remainder
		subwf	Scratch8,F
		movf	Scratch5,W
		btfss	STATUS,C
		incf	Scratch5,W
		subwf	Scratch9,W		; Keep that byte in W untill we make sure about borrow

		btfsc	STATUS,C
		bsf		Scratch7,0		; Set bit 0 of counter (saved carry)

		btfsc	Scratch7,0		; If no borrow
		goto	UOK46LL			; jump

		movf	Scratch6,W		; Restore remainder if borrow
		addwf	Scratch8,F
		movf	Scratch9,W		; Read high byte of remainder to W
								; not to change it by next instruction
UOK46LL
		movwf	Scratch9		; Store high byte of remainder
		bcf		STATUS,C		; Copy bit 0 to carry
		rrf		Scratch7,F		;  and restore counter
		decfsz	Scratch7,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					; Day of week and Moon phase calculation use remainder only

ChkCy_6K
		btfsc	STATUS,C		; Take care of C
		addlw	1
		return

JulianDay00
		clrf	Scratch
		clrf	Scratch2
		clrf	Scratch3
		movf	Day,w			; Day changes at 00:00
		movwf	Scratch4

Year16bit						; Convert Century and Year to a 16 bit word in Scratch6:Scratch5
		movf	Year,w
		movwf	Scratch5
		clrf	Scratch6
		movf	Century,w
		movwf	Scratch7
		btfsc	STATUS,Z
		goto	JDN
l_year16
		movlw	.100
		addwf	Scratch5,f
		btfsc	STATUS,C
		incf	Scratch6,f
		decfsz	Scratch7,f
		goto	l_year16

JDN								; Returns Julian Day Number
								; Scratch .. Scratch3 cleared before call
								; For WDay calculation Scratch4 = Day

		movf	Month,w
		addlw	-.3
		movwf	Scratch7
		btfss	Scratch7,7
		goto	Dnum
		movlw	.12
		addwf	Scratch7,f
		bsf		STATUS,IRP		; IRP = a = (.14 - Month) div .12
Dnum							; dpi = m = Month + 12 * a - 3
		call	GetDn
		bsf		PCLATH,3
		bsf		PCLATH,4		; Page 3
		addwf	Scratch4,w		; Add the day
		movwf	Scratch3		; Scratch2:Scratch3 = day + (.153 * m + 2) div 5
								; C = 0
		btfsc	STATUS,IRP
		decfsz	Scratch5,f
		goto	SetY
		decf	Scratch6,f		; Scratch6:Scratch5 = .100 * Century + Year - a
SetY
		rrf		Scratch6,w
		movwf	Scratch7
		rrf		Scratch5,w
		movwf	Scratch4		; Scratch7:Scratch4 = (.100 * Century + Year - a) div 2

Mul365
		movlw	low(.365)
		addwf	Scratch3,f
		movlw	high(.365)
		call	ChkCy_6K
		addwf	Scratch2,f
		btfsc	STATUS,C
		incf	Scratch,f
		decfsz	Scratch5,f
		goto	Mul365
		decf	Scratch6,f
		btfss	Scratch6,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_6K
		addwf	Scratch2,f
		movlw	0x1A
		call	ChkCy_6K
		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		Scratch7,f
		rrf		Scratch4,f		; Scratch7: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	Scratch5		; Scratch5 = W = (.100 * Century + Year - a) div .100
		subwf	Scratch4,f
		btfss	STATUS,C
		decf	Scratch7,f		; Scratch7:Scratch4 = (.100 * Century + Year - a) div 4 - (.100 * Century + Year - a) div .100
		rrf		Scratch5,f
		rrf		Scratch5,w
		andlw	0x3F			; W = (.100 * Century + Year - a) div .400
		addwf	Scratch4,w
		btfsc	STATUS,C
		incf	Scratch7,f		; There will not be an overflow
		addwf	Scratch3,f
		movf	Scratch7,w
		call	ChkCy_6K		; There will not be an overflow
		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			; Bank0, Clear IRP
		return

;******************************************************************************
; Get number of days for JDN

GetDn
		movlw	high(JDNTabl)
		movwf	PCLATH
		movf	Scratch7,w
		addlw	low(JDNTabl)
		movwf	PCL

;******************************************************************************

MoonSymbol
		call	JulianDay00		; Calculate phase of Moon
		clrf	Scratch4
		movlw	low(.7560)
		movwf	Scratch6
		movlw	high(.7560)
		call	FXD3216U_StoreDivH; At return W holds phase of moon (.0 .. .29)
		addlw	.17				; add .17 days modulo 29
		movwf	Scratch4
		movlw	.29
		subwf	Scratch4,w
		btfsc	STATUS,C
		movwf	Scratch4		; At return Scratch4 holds phase of moon (.0 .. .29)

		addlw	-.24
		btfsc	STATUS,C
		movlw	'('				; W holds Moon symbol
		addlw	.8
		btfsc	STATUS,C
		retlw	0x87
		addlw	.1
		btfsc	STATUS,C
		retlw	0x86
		addlw	.8
		btfsc	STATUS,C
		retlw	0x85
		retlw	')'

;******************************************************************************

main
;		clrf	PORTA			; Done at RESET
		clrf	PORTB			; PortA, PortB, PortC cleared at reset vector
		clrf	PORTC			; all LED OFF

	ifdef	MotorDirFromCalibration
		btfsc	PORTA,bCalibration; Read Calibration input
		bsf		T1CON,bMotorDirCC; Set direction of motor rotation
	endif

		bsf		STATUS,RP0		; Bank1

		clrf	ADCON1			; PORTA 5..1 bits are digital I/O, 0 is analog, A/D left justified

		movlw	~ ((1 << bAnalogL0) | (1 << bAnalogL1) | (1 << bAnalogL2) | (1 << bAnalogL3) | (1 << bCalibration))
		movwf	TRISA			; Set 5,4,3,2,1 as output, 7,6,0  input
		movlw	(1 << bIndexPuls)
 		movwf	TRISB			; Set 7..1 as output, 0 as input
		movlw	~ ((1 << bSecLED) | (1 << bBrightPWM) | (1 << bOuterLED) | (1 << bTicksLED) | (1 << bPixel0))
		movwf	TRISC			; Set 7..6, 2..0 as output, 5,4,3  input			;

	    clrf    SSPSTAT			; Disable SMBus inputs
    	bsf     SSPSTAT,SMP		; Disable slew rate control
	    movlw   0x31			; Divide FOSC/4 by .50
    	movwf   SSPADD			; Setup 100 kHz I2C clock
	    clrf    SSPCON2			; Clear control bits

;		clrf	PIE1			; dissable all possible peripheral interrupt enable
		movlw	b'10011000'		; set up timer. prescaler(bit3)bypassed, Int on falling Edge RB0
		movwf	OPTION_REG		;
		movlw	.249			; TMR2 period=250 PR2=249
		movwf	PR2				;
		bsf		PIE1,TMR2IE		; enable Peripheral interrupt from TMR2

		bsf		STATUS,RP1		; Bank3
		clrf	EECON1			; Clear EECON - Data EEProm access select

		movlw	0x01			; Only RA0  analogue
		movwf	ANSEL
		clrf	ANSELH

		bcf		STATUS,RP0		; Bank2

		movlw	0x0F
		movwf	AD_state		; Init ADC state counter

		clrf	Light
		clrf	EEADR			; Start of message

		clrf	PictNum_sc		; No slideshow, pict 0 selected

		clrf	RC5_flags		; clear RC5_flags
		bsf		RC5_flags,bRC5_WaitStart; RC5 is waiting for startbit
		clrf	RC5_Tmr			;

		bcf		STATUS,RP1		; Bank0

		movlw	0x0C			; PWM mode bit 1..0 are don't care: can be used for data storage
		movwf	CCP1CON

		clrf	TMR1H			; Init rotation measurement counter
		clrf	TMR1L

		movlw	b'00101000'
		movwf	SSPCON			; Enable SSP, select I2C Master mode

		movlw	0x81			; A/D on , Fosc/32, Ch 0
		movwf	ADCON0

		clrf	PixelWidth		;
		clrf	PixelOff		;

		clrf	PCLATH			; Page0 preload - Runs on Page3 but calls routines on Page0

		clrf	flags2			; clear flags2 - holds TimeInv set by InitTime

		call	InitTime		; Init time counter variables and Display flags

		movf	DispOffset,w	; Init display memory pointer
		movwf	iFSR


		call 	ClearDisplay	; clear display content

		clrf	INTCON			; clear and dissable all possible interrupt flag
		clrf	PIR1			; clear all pripheral interrupt flag
		clrf	PIR2

		movlw	b'00000101'		; TMR2=ON, Prescaler = 1/4,  Postscaler = 1
		movwf	T2CON			;

		clrf	TMR0			; start timer

		movlw	(1 << T0IE) | (1 << INTE) | (1 << PEIE) | (1 << GIE)
		movwf	INTCON

		goto	MainLoop		; Jumps to MainLoop on Page0

;******************************************************************************

ClearDisplay_6K
		movlw	.120
		movwf	ch_dot_index
		movlw	0x20			; Set FSR to 0x20
		movwf	ch_slidecnt		; Init slide show counter
cldisp_6K
		movwf	FSR				;
		clrf	INDF			; clear display memory
		bsf		STATUS,IRP
		clrf	INDF			; clear display high memory
		bcf		STATUS,IRP
		clrf	PCLATH
		call	CheckIncrementFSR; Increment and test pointer
		bsf		PCLATH,3
		bsf		PCLATH,4		; Page3
		decfsz	ch_dot_index,f	; Loop for .120 positions
		goto	cldisp_6K		; Loop clears ch_dot_index

      	clrf	ch_blanking		; init stuff needed for Text Scroll function

		movf	ch_flags_RC5,w
		andlw	0x03
		movwf	ch_flags		; Copy ch_flags

		btfsc	flags2,bDemo	; Copy demo mode flag
		bsf		ch_flags,bDemo_sc
;;++
		btfsc	flags2,bDemo
		goto	RetBank0_6K

		btfsc	ch_flags,bScrollDateTime
		bsf		ch_flags,bDateToScroll
;;++
RetBank0_6K
		clrf	PCLATH
		clrf	STATUS			; Bank0
		return


;******************************************************************************
; Pointers for configurator

		org		0x1FF9
		dw		0x103
		dw		(VersionMajor << 8) | VersionMinor
		dw		0x00
		dw		IrAddr0
		dw		0x00
		dw		IrCmdTab
		dw		IrCmdTabEnd

;******************************************************************************

	ifdef DebugI2C
		messg	"Don't program this compilation to chip, I2C rutines are debug verisons"
	endif

	END
