;************************************************************************
; 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 analog hands or digital time and mixed mode where	*
;    time is displayed as analog 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.asm                                        	*
;    StartDate:     02/12/2001                                        	*
;    LastUpdate:    09/09/2009						*
;    File Version:  2.16                                       	   	*
;                                                                     	*
;    Author:        Soubry Henk                                       	*
;    Company:       Soubry Software Service                           	*
;                                                                     	*
;    Ported to 16F648A	16F88						*
;	 Displays day of week, century					*
;    Name of weekdays on 16 languages					*
;	 Selectable date formats ((CC)YY-MM-DD / DD-MM-(CC)YY)		*
;	 Rotation speed measurement					*
;	 Two scrolling message with adjustable speed			*
;	 Static text display						*
;    12/24 hour digital/analog display mode				*
;	 All digital display can be done in Binary Coded Decimal	*
;	 Individualy controllable analog hands				*
;	 Dot/arc second hand, bar/dot minute hand option		*
;	 Doubble/single tick at 12'o clock				*
;	 Store time and settings in a PCF8583 I2C RTC			*
;	 Calibration pin can be used to select rotation direction	*
;                                                                     	*
;************************************************************************
;                                                                    	*
;    Files required: CharGen648.asm                                    	*
;                    Keys648.asm                                      	*
;                    DayNames648.asm                                   	*
;                                                                     	*
;************************************************************************
;                                                                     	*
;    Notes:                                                           	*
;    	Pin assignment                                                	*
;    Notes:                                                           	*
;    	Pin assignment                                                	*
;      		Port A                                             	*
;		0 = inner display led (because RB0 is index)		*
;               1 = analog outer led				   	*
;               2 = I2C SCL	use 2k pull up resistor to PIC's Vdd    *
;               3 = OSC Calibration output @ 2.5kHz                    	*
;		4 = I2C SDA	use 2k pull up resistor to PIC's Vdd	*
;               5 = Ir receiver              Input only pin            	*
;		6..7 = Quartz oscillator				*
;                  RA6 can be freed up using ext oscillator		*
;      		Port B 							*
;		0 = index                                     	       	*
;               1..6 = Display leds (1=inner, 6=outer)                	*
;               7 = analog inner leds	  				*
;                                                                     	*
;************************************************************************
;									*
;  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	speed*
;									*
;	18		19		1A		1B		1C		1D		1E		1F	*
;	Lang.	Flags5							*
;									*
;************************************************************************
;	Ir Remote control keys						*
;									*
;	See keys.asm and keys.txt					*
;									*
; Afther time setting Toggle Outer Led command stores time to RTC	*
;************************************************************************


	ifdef	__16F648A
		list	p=16f648A            	; 16F648A can be used
		#include <p16f648A.inc>       	; processor specific variable definitions
EEPROM_SIZE	EQU	256
	endif
	ifdef	__16F88
		list	p=16f88			; 16F88 can be used
		#include <p16f88.inc>		; processor specific variable definitions
		#define	T0IE	TMR0IE
		#define	T0IF	TMR0IF
		#define	_MCLRE_OFF	_MCLR_OFF
EEPROM_SIZE	EQU	256
	endif

	#include "CharGen648.asm"
	#include "Keys648.asm"
	#include "DayNames648.asm"

	ifdef	__16F88
		__CONFIG _CONFIG1, _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _HS_OSC & _MCLRE_OFF & _LVP_OFF
		__CONFIG _CONFIG2, _IESO_OFF & _FCMEN_OFF 
	else
		__CONFIG _CP_OFF & _WDT_OFF & _BODEN_ON & _PWRTE_ON & _HS_OSC & _MCLRE_OFF & _LVP_OFF
	endif

#define	VersionMajor	0x02
#define	VersionMinor	0x16

	__idlocs		0xA000 | (VersionMajor << 8) | (VersionMinor)

F_OSC	EQU	.20000000	; Oscillator frequency in Hz
OSC	EQU	F_OSC/4

; Settings for Baud 2400	;
;BAUDH	EQU	0		; Use 64 divider
;BAUD	EQU	.2400		; Baud rate of serial line

; Settings for Baud 9600	;
;BAUDH	EQU	1		; Use 16 divider
BAUD	EQU	.9600		; Baud rate of serial line

RTC_ADDR	EQU	0xA0	; Address of RTC

;***** VARIABLE DEFINITIONS

#define RC5IntOnRA5			; un-comment this line if RC5 input is on RA2
#define	MotorCounterClockWise		; un-comment this line if motor is running counter clockwise
;#define MotorDirFromCalibration	; un-comment this line if get motor direction from calibration pin
;#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 on time/date display
#define RC5AddrCheck			; comment this line if RC5 Address checking not required
#define UsePCF8583RTC			; comment this line if No PCF8583 RTC used

#define DISPLAYOFFSET	0x37	; Initial Display Offset for the hardware (display memory address) !!!

;#define	RTC_Control	0x00	; Control register
#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
#define		RTC_flags3	0x16	; Address of flags3
#define		RTC_flags4	0x17	; Address of flags4
#define		RTC_Language	0x18	; Address of Language
#define		RTC_flags5	0x19	; Address of flags5


;Display memory	Low byte	
;DispI		0x020		; 2*40 bytes from 0x20 -> 0x48
;DispII		0x0A0		; 2*80 bytes from 0xA0 -> 0xF0

; Common memory 0x070-0x07F, 0x0F0-0x0FF, 0x170-0x17F, 0x1F0-0x1FF

;Vars in shared memory. This memory is available from any bank
  cblock	0x70
	Scratch		; memory locations for general use
	Scratch2	;
	Scratch3	;
	Scratch4	;

;Vars for building display-content
	BCD		; Binary coded decimal
	BCD_High	;   high part
	digitindex	; index digit to display
	dotindex	; index dot to display
	dpi		; 0..119 display index for main program
	tdd		; temporary display data
	I2CWordAddr	; 

	flags		; Digital  display flags - more bits in flags5:5..4
	flags2		; System  flags
	flags3		; Analogue display flags - more bits in CCP1CON:5..4

	iFSR		; copy of FSR used by interrupt routine
	w_temp		; variable used for context saving
  endc

;Vars for display timing routines and interrupts
  cblock	0x20
    DispI: .40		; Display data 0..39
	PeriodCnt_H	; 16 bit counter counts number of 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 interrupts in one ON pixel
	PixelOff	; 8 bit down-counter to time PixelWidth

	PixelPitch_H	; PixelPitch = 16 bit number of interrupts between two pixel
	PixelPitch_L	;
	PixelPitch_F	; Fraction of PixelPitch needed for accuracy and to avoid jitter

	NewPPitch_H	; New pixel pitch calculated by main programm, will be
	NewPPitch_L	; copied to PixelPithc by interrupt routine
	NewPPitch_F	;

	NextPixel_H	; Next pixel @ PeriodCnt = NextPixel
	NextPixel_L	;
	NextPixel_F	;
	RoundedNext_L	; RoundedNext = Round(NextPixel)
	RoundedNext_H	;

	DispOffset	; Display offset compared to indexpuls

	TmrScroll	; Count Down timer for scroll delay

;Vars for time-keeping
  ;!! Keep variable order - Timecheck use indirect access to them v
	Second2		; 0..119 counting half seconds
	Minute		; 0.. 59
	Hour		; 0.. 23
	Day		; 1.. Dmon-1
	Month		; 1.. 12
	Year		; 0.. 99
	Century		; 0.. 99
  ;!! Keep variable order - Timecheck use indirect access to them ^

	DMon		; days in current Month + 1
	WDay		; Day of week 0..6 - displayed as 1..7 : Monday is 1 

	Language
	flags5

;Vars for RC5 decoding
	RC5_flags	;
	RC5_Tmr		;
	RC5_BitCnt	;
	RC5_Addr	;
	RC5_Cmd		;
	RC5_Cmd2	; storage for previous cmd
  endc

	IF RC5_Cmd2 >= 0x70
		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
  endc

; start a new block of vars in bank2

  cblock	0x120	; Bank 2 - 16F648A 80 bytes

	ch_dot_point_H	; pointer the the current dot# in a character
	ch_dot_point_L	; points the the chargenerator table
	ch_dot_index	; index of dot# in a char, 0..5
	ch_flags	; char flags
	ch_blanking	; counter for blanking the display when scrolling text

	rotation_L	; Rotation count
	rotation_H

	rot_bcd:5	; Rotation in BCD 1/min

	pclath_temp	; variable used for context saving
	fsr_temp	; variable used for context saving
	status_temp	; variable used for context saving
  endc
	IF status_temp >= 0x160
		ERROR "To many variables used in Bank 2"
	ENDIF


;**********************************************************************
; give meaningfull names to the scratch 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

;**********************************************************************
; define Port bits
; Port A
bPixel0		EQU	0
bOuterLED	EQU	1
bCalibration	EQU	3

  ifdef	UsePCF8583RTC
bSCL		EQU	2
bSDA		EQU	4
  endif

  ifdef	RC5IntOnRA5
bRC5inp		EQU	5
  else
bRC5inp		EQU	2
  endif

  ifdef UsePCF8583RTC
	if ((bOuterLED>5) || (bCalibration>5) || (bSCL>5) || (bSDA>5) || (bRC5inp>5))
	  error "RA6, RA7 pins are used for quartz oscillator"
	endif
  else
	if ((bOuterLED>5) || (bCalibration>5) || (bRC5inp>5))
	  error "RA6, RA7 pins are used for quartz oscillator"
	endif
  endif

  ifdef UsePCF8583RTC
	if ((bOuterLED==5) || (bCalibration==5) || (bSCL==5) || (bSDA==5))
	  error "RA5 in an input only pin"
	endif
  else
	if ((bOuterLED==5) || (bCalibration==5))
	  error "RA5 in an input only pin"
	endif
  endif

	if ((bOuterLED==4) || (bCalibration==4))
	  messg "RA4 in an open drain output pin - pull-up resistor required"
	endif

	ifdef	UsePCF8583RTC
		if ((bOuterLED==bSCL) || (bCalibration==bSCL) || (bPixel0==bSCL) || (bSDA==bSCL) || (bRC5inp==bSCL) || (bSCL>4))
			error "PORTA configuration error : bSCL"
		endif
		if ((bOuterLED==bSDA) || (bCalibration==bSDA) || (bPixel0==bSDA) || (bSDA==bSCL) || (bRC5inp==bSDA) || (bSDA>4))
			error "PORTA configuration error : bSDA"
		endif
	endif

;PortB
bIndexPuls	EQU	0		; Index pulse interrupt request
bMinLED		EQU	4		;
bSecLED		EQU	5		; Second hand's LED
bTickLED	EQU	6		; Analogue clock's Ticks LED
bInnerLED	EQU	7		; Analogue hand's inner 9 LEDs

	if (bIndexPuls!=0)
	  error "Index puls has to be the RB0/External interrupt pin"
	endif

	if ( (bIndexPuls==bSecLED)   || (bTickLED==bSecLED)  || (bInnerLED==bSecLED) )
	  error "PORTB configuration error : bSecLED"
	endif

	if ( (bIndexPuls==bTickLED)  || (bSecLED==bTickLED)  || (bInnerLED==bTickLED) )
	  error "PORTB configuration error : bTickLED"
	endif

	if ( (bIndexPuls==bInnerLED) || (bSecLED==bInnerLED) || (bTickLED==bInnerLED) )
	  error "PORTB configuration error : bInnerLED"
	endif


; TMR1L, TMR1H	used to count rotation speed

; T1CON
bMotorDirCC	EQU	1	; Direction of motor rotation  -  Read at reset from PORTC,bCalibration
bRC5_TimeSet 	EQU 	2	; Time setting commands were received
bNewRot		EQU	4	; New rotation count avaible
bPStorage	EQU	5	; Rotation time measurement buffer select

; CCP1CON			; More analog  display flags
bSTick12	EQU	4	; Single / double tick at 12'o clock
;		EQU	5

; flags5			; More digital display flags
bBinMode	EQU	4	; Binary display mode
;		EQU	5

; CCPR1L			; Stores a copy of PORTC - needed only for sw I2C
; CCPR1H			; Stores Scrolling speed

; 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, humidity
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, humidity - Show always date
bShowDTime	EQU	5	; Show / hide digital time
bShowDDate	EQU	6	; Show / hide digital date
bShowCentury	EQU	7	; Show / hide century

; define flag3 bits		; Analog Display flags
;bShow36912	EQU	0	; Show / hide drawing III, VI, IX, XII around the clock
bShowTicks	EQU	1	; Show / hide ticks
bSecMode	EQU	2	; Dot  / Arc second hand
bMinMode	EQU	3	; Dot  / Bar minute 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 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			; Cleared in interrupt routine at RC5_error
bRC5_WaitStart	EQU	0
bRC5_DataReady	EQU	1
;		EQU	2	; Reserved for backward compatibility
bRC5_Idle	EQU	3
bRC5_ReSynced	EQU	4
bRC5_prev_inp	EQU	bRC5inp	; Has to be on same bit as bRC5inp on PortA
bRC5_HalfBit	EQU	6
;		EQU	7	; Can be used, but interrupt routine clears RC5_flags if error in communication

	if ((bRC5_WaitStart==bRC5_prev_inp) || (bRC5_DataReady==bRC5_prev_inp) || (bRC5_HalfBit==bRC5_prev_inp) || (bRC5_Idle==bRC5_prev_inp) || (bRC5_ReSynced==bRC5_prev_inp))
	  error "RC5_flags configuration error"
	endif

  ifdef UsePCF8583RTC
	if ((bPixel0==bRC5_prev_inp) || (bOuterLED==bRC5_prev_inp) || (bSCL==bRC5_prev_inp) || (bCalibration==bRC5_prev_inp) || (bSDA==bRC5_prev_inp) || (bRC5inp!=bRC5_prev_inp))
	  error "PORTA configuration error"
	endif
  else
	if ((bPixel0==bRC5_prev_inp) || (bOuterLED==bRC5_prev_inp) || (bCalibration==bRC5_prev_inp) || (bRC5inp!=bRC5_prev_inp))
	  error "PORTA configuration error"
	endif
  endif

	if (bRC5inp!=bRC5_prev_inp)
	  error "bRC5inp and bRC5_prev_inp have to be on same bit position"
	endif

;**********************************************************************
; PortA  - a copy of PORTA is in CCPR1L
; -!-!- Don't use bsc, bsf, operation with PORTA,f (like xorwf  PORTA,f). Only clrf PORTA and movwf PORTA will work -!-!-
; -!-!- Make modification on CCPR1L and use only XorToPorta, ToPorta rutines -!-!-
; -!-!- Disable interrupt (bcf INTCON,GIE) before these routines, enable (bsf INTCON,GIE) afther -!-!-

;#define	Pixel0		PORTA,BPixel0
#define 	OuterLED	PORTA,bOuterLED
#define		SCL			PORTA,bSCL
#define		Calibration	PORTA,bCalibration
#define		SDA			PORTA,bSDA
#define 	RC5inp		PORTA,bRC5inp

; PortB
#define 	IndexPuls	PORTB,bIndexPuls


; CCPR1L	used for copy of PORTA
; PORTA read-modify-write instructions set SCL and SDA to 1 -- external pull up resistor
; PORTA read-modify-writes disturb I2C routines - CCPR1L is used to store value written to PORTA

; T1CON
#define		MotorDirCC	T1CON,bMotorDirCC
#define		NewRot		T1CON,bNewRot
#define		PStorage	T1CON,bPStorage
#define		RC5_TimeSet	T1CON,bRC5_TimeSet

; TMR1 		registers used for rotation metering

; CCP1CON	flags4
#define		STick12		CCP1CON,bSTick12

; flags5
#define		BinMode		flags5,bBinMode


; CCPR1H 	register  used to store scroll speed

; Flags
#define		ShowOuter	flags,bShowOuter
#define		ShowDayName	flags,bShowDayName
#define		Digit12Mode	flags,bDisp12Mode
#define		DateFormat	flags,bDateFormat
#define		ShowWDay	flags,bShowWDay
#define		ShowDTime	flags,bShowDTime
#define		ShowDDate	flags,bShowDDate
#define		ShowCentury	flags,bShowCentury

; Flags3
#define		Show36912	flags3,bShow36912
#define		ShowTicks	flags3,bShowTicks
#define		SecMode		flags3,bSecMode
#define		MinMode		flags3,bMinMode
#define		ShowSecHand	flags3,bShowSecHand
#define		ShowMinHand	flags3,bShowMinHand
#define		ShowHourHand	flags3,bShowHourHand
#define		AnalMode24h	flags3,bAnalMode24h

; Flags2
#define		fDspEnabled	flags2,bDspEnabled
#define		NewPCnt		flags2,bNewPCnt
#define		NewTime		flags2,bNewTime
#define		NewPPitch	flags2,bNewPPitch
#define		fText		flags2,bText
#define		fScrollOn	flags2,bScrollOn
#define		fDemo		flags2,bDemo
#define		fTimeInv	flags2,bTimeInv

; RC5 Flags
#define		RC5_WaitStart	RC5_flags,bRC5_WaitStart
#define		RC5_DataReady	RC5_flags,bRC5_DataReady
#define		RC5_HalfBit	RC5_flags,bRC5_HalfBit
#define		RC5_Idle	RC5_flags,bRC5_Idle
#define		RC5_prev_inp	RC5_flags,bRC5_prev_inp
#define		RC5_ReSynced	RC5_flags,bRC5_ReSynced

;******************************************************************************
;	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

casenomatch    	macro   val
	        xorlw   val ^ sel_last
			btfss	STATUS,Z
sel_last set val
         	endm

;
;******************************************************************************
;	Define EEPROM content for initial message
;******************************************************************************

	ORG     0x21F0           ; Start of EEPROM message
;       	 0123456789ABCDE   F
		de	"Propeller Clock", 0x00

	ORG     0x2100           ; Start of EEPROM page 0
		de	"===> This version of Bob Blick's Propeller Clock was built with "
		de	"16F684A, PCF8583 RTC ",0x83,0x84
		de	" Ver. ",VersionMajor | 0x30 ,".", ((VersionMinor>>4) & 0x0F) | 0x30, ((VersionMinor) & 0x0F) | 0x30, " <==="
		de	0x00

	ORG     0x2180           ; Start of EEPROM page 1
		de	"===> Displays day of week, rotation speed and store times in PCF8583 RTC ",0x83,0x84," <==="
		de	" ",0x83,0x84
		de	0x00

;**********************************************************************
		ORG     0x000           ; processor reset vector
		clrf	PORTA
		clrf	PORTB
		clrf	CCPR1L
		goto    main            ; go to beginning of program

;**********************************************************************
		ORG     0x004           ; 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		; IT routine is in 0x000..0x7FF
		clrf	STATUS		; select bank 0 & 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	0xff		;
		movwf	TMR0		; force TMR0 to 0xFF

		movlw	StorePCnt1_H
		btfss	PStorage		
		movlw	StorePCnt2_H
		movwf	FSR
		movf	PeriodCnt_H,w	;
		movwf	INDF
		incf	FSR,f
		movf	PeriodCnt_L,w	;
		movwf	INDF
		movlw	1<<bPStorage
		xorwf	T1CON,f

;StoreDone:
		bsf	NewPCnt		; 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	; iDispIndex = DispOffset
		movwf	iFSR		;
		btfss	NewPPitch	; is there a new value calculated by main prg?
		goto	lINT_RB0	; no, continue
		movf	NewPPitch_H,w	; PixelPitch = NewPPitch
		movwf	PixelPitch_H	;
		movf	NewPPitch_L,w	;
		movwf	PixelPitch_L	;
		movf	NewPPitch_F,w	;
		movwf	PixelPitch_F	;
		bcf	NewPPitch	;

lINT_RB0
		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
;--------
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	CCPR1L,bOuterLED; Other bit of PortA, PortB bits and PortC 0 will be cleared by lDisp_1
		call	ToPortA

lDisp_1
		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 pixeldata

		movf	iFSR,w			; load new memory pointer in w
		movwf	FSR			; load File Select register with Display Index
		movlw	0x00			; Blank the display if rotation too slow
		btfsc	flags2,bDspEnabled
		movf	INDF,w			; Get display data

		movwf	PORTB			; PortB = DisplayData(index)

		xorwf	CCPR1L,w
		andlw	(1 << bPixel0)
		call	XorToPortA		; dispatch bit 0 to PORTA

	ifdef	MotorDirFromCalibration
		btfsc	MotorDirCC		; Get direction of motor rotation
		call	CheckDecrementFSR	; decrement FSR, check correct progress of diplay memory pointer
		btfss	MotorDirCC		; Get direction of motor rotation
		call	CheckIncrementFSR	; increment FSR, check correct progress of diplay memory pointer
	else

	  ifdef MotorCounterClockWise
		call	CheckDecrementFSR	; decrement FSR, check correct progress of diplay memory pointer
	  else
		call	CheckIncrementFSR	; increment FSR, check correct progress of diplay 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	; ROUND 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?
		btfsc	STATUS,Z	; PixelOff = 0 ?
		goto	lDispDone	; no, jump

		decfsz	PixelOff,f	; pixel is on, countdown
		goto	lDispDone	;
		clrf	PORTB		; turn off display LED's
		bcf	CCPR1L,bPixel0	; also turn off PortC LED
		call	ToPortA

lDispDone
		bcf	INTCON,T0IF	; clear TMR0 interrupt flag before return

;--------
INT_TMR2
		btfss	PIR1,TMR2IF	; interrupt on TMR2?
		goto	INT_EXIT	; nope, interrupt is done!

					; do the TMR2 stuff, we get here every 200uSec

		movlw   1<<bCalibration	; toggle PORTC.5, use scope or freq counter
		call	XorToPortA

					; 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	NewTime		; signal new time to main program

		call	InitSubSecCnt	; reload counter SubSecond = 0x10000 - .2500 = 0xF63C

		movlw	1<<bOuterLED	; Toggle outerled if time invalid
		btfsc	fTimeInv
		call	XorToPortA
		
		movlw	.120			; Minute passed
		xorwf	Second2,w
		btfss	STATUS,Z
		goto	lTime_1			; No, goto RC5 task

		movf	TMR1L,w			; Read rotation from Timer1
		bsf	STATUS,RP1
		movwf	rotation_L		; Store it
		bcf	STATUS,RP1
		movf	TMR1H,w
		bsf	STATUS,RP1
		movwf	rotation_H		
		bcf	STATUS,RP1

		clrf	TMR1H			; Reset Timer 1
		clrf	TMR1L

		bsf	NewRot			; Sign new rotation data avaible

lTime_1

lRC5_Stuff				; Start RC5 stuff here
		btfsc	RC5_DataReady	;
		goto	lRC5_Exit	;
		btfss	RC5_Idle	;
		goto	lRC5_Not_Idle	;
		decfsz	RC5_Tmr,f	;
		goto	lRC5_Exit	;
		btfsc	RC5inp		; test input
		bcf	RC5_Idle	; input = high, cancel Idle state
		incf	RC5_Tmr,f	; continue Idle state until input = high
		goto	lRC5_Exit	;

lRC5_Not_Idle
		btfss	RC5_WaitStart	;
		goto	lRC5_ReSync	;

lRC5WaitStart
		btfsc	RC5inp		; test input
		goto	lRC5_Exit	; no startbit
		bcf	RC5_WaitStart	; start received
		movlw	.13		; 13 bits to receive
		movwf	RC5_BitCnt	;
		clrf 	RC5_Addr	;
		clrf	RC5_Cmd		;
		movlw	.6		;
		goto	lRC5_Reload	;

lRC5_ReSync				;
		movf	PORTA,w		;
		xorwf	RC5_flags,w	;
		andlw	1<<bRC5inp	;
		btfsc	STATUS,Z	;
		goto	lRC5_no_sync	;
		bsf	RC5_ReSynced	;
		movlw	.6		; re-sync the timer
		btfss	RC5_HalfBit	;
		movlw	.2		;
		movwf	RC5_Tmr		;
		bcf	RC5_prev_inp	; clear previous input
		btfsc	RC5inp		;
		bsf	RC5_prev_inp	;

lRC5_no_sync
		btfsc	RC5_HalfBit	;
		goto	lRC5_2nd_Half	;

lRC5_1st_Half
		decfsz	RC5_Tmr,f	;
		goto	lRC5_Exit	;
		bcf	STATUS,C	;
		btfsc	RC5inp		;
		bsf	STATUS,C	; C = RC5inp
		rlf	RC5_Cmd,f	;
		rlf	RC5_Addr,f	;
		bsf	RC5_HalfBit	; indicate that the first half bit is received
		bcf	RC5_ReSynced	;
		movlw	.4		; reload timer
		goto	lRC5_Reload

lRC5_2nd_Half
		btfsc	RC5_ReSynced	;
		goto	lReSyncOK	;
		decfsz	RC5_Tmr,f	;
		goto	lRC5_Exit	;

lRC5_Error
		movf	RC5_flags,w
		andlw	(1>>7) | (1<<bRC5_DataReady)
		iorlw	(1<<bRC5_WaitStart)|(1<<bRC5_Idle)	;
		movwf	RC5_flags
		movlw	.128		;

lRC5_Reload
		movwf	RC5_Tmr		;
		goto	lRC5_Exit	;

lReSyncOK
					; test second bit half
		bcf	RC5_HalfBit	;
		decfsz	RC5_BitCnt,f	;
		goto	lRC5_Exit	;
		rlf	RC5_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 in RC5_Addr
					; RC5_Addr 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
		bsf	RC5_DataReady	; Only lower 5 bits of RC5_Addr are valid
lRC5_Exit
		bcf	PIR1,TMR2IF	; clear TMR2 interrupt flag
;--------
INT_EXIT
		bsf	STATUS,RP1	; Context saving variables are on Bank2 except w_temp
		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	;
		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

		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
		movwf	NewPPitch_H	;
		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	;

					; start calculation for pixel width
		clrc			; Clear Carry
		rrf	NewPPitch_L,w	;
		movwf	PixelWidth	; W = PixelWidth = NewPPitch_L * 4 / 8
		clrc
		rrf	PixelWidth,f	; PixelWidth = NewPPitch_L * 2 / 8
		clrc
		rrf	PixelWidth,f	; PixelWidth = NewPPitch_L * 1 / 8
		addwf	PixelWidth,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	NewPPitch	; signal new Pitch value to interrupt routine

CalcDone:
		bcf	NewPCnt		; 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
		btfsc	STATUS,C        ; if Day incremented increment WDay as well
		incf	WDay,f

		movlw	.7		; if Day of week == 7
		subwf	WDay,w
		btfsc	STATUS,C        ; if Day of week < 7 then c=0 (borrow)
		movwf	WDay		; Day of week = 0

		movlw	.32		; DMon = 32
		movwf	DMon
		movf	Month,w		;
		movwf	Scratch		; For months <8 odd  months have 31 days
		btfsc	Month,3
		incf	Scratch,f	; For months >7 even months have 31 days
		btfss	Scratch,0
		decf	DMon,f
		xorlw	.2		; Month = February ?
		btfss	STATUS,Z	;
		goto	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
		btfss	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
		movlw	.100		;
		call	CheckAndIncNext
					; FSR -> Century
		movlw	.100		;
		subwf	Century,w	; Century < 100 ?
		btfsc	STATUS,C	;
		clrf	Century		;

		bcf	NewTime		; 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

LoadBCDDay
		movf	digitindex,w	; Read names backward
		sublw	.9
		movwf	Scratch
		swapf	Language,w	; Multiply language code by 7
		movwf	BCD
		clrc
		rrf	BCD,f
		movf	Language,w
		subwf	BCD,w
		addwf	WDay,w		; Add day of week
		movwf	BCD		; Multiply by 10
		addwf	BCD,f
		movf	BCD,w
		rlf	BCD,f
		rlf	BCD_High,f
		rlf	BCD,f
		rlf	BCD_High,f
		addwf	BCD,w
		btfsc	STATUS,C
		incf	BCD_High,f
		addwf	Scratch,w	; Add 9-digitindex
		btfsc	STATUS,C
		incf	BCD_High,f
		movwf	BCD
		movlw	high(DayNames)	; Add address of table
		call	CharPattern	; Get next character
		clrf	PCLATH		; Use page 0

		clrf	BCD_High
		addlw	-' '		; Convert ascii code to internal
		clrc		
		movwf	BCD
		bcf	BCD,7
		rlf	BCD,f		; Multiply by 6
		rlf	BCD,w
		rlf	BCD_High,f
AddBCD16
		addwf	BCD,f				
		btfsc	STATUS,C
		incf	BCD_High,f
		return			; Store new code

CharPatternTab
		btfsc	BCD_High,7
		goto	CharPatternBin
		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 
		movwf	PCLATH		; Store it in PCLATH
		movf	BCD,w		; Get low byte
		movwf	PCL		; Get next character

;=======================================================
; No execution passes here

CharPatternBin					; If calls out from lower 2K, afther call PCLATH has to be set to 0
		movlw	high(BinTab)		; Get high byte 
		movwf	PCLATH			; Store it in PCLATH , PCLATH has only 5 bits - bit7 of BCD removed
		movf	BCD,w			; Get low byte
		addlw	low(BinTab)-(6*('0'-' ')) ; Convert start address of character
		movwf	PCL			; Get next character

;-------- 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, load start parameters for
		clrf	dotindex	; 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
		clrf	BCD_High

		btfsc	ShowDTime
		call	LoadBCDTime	; dotindex = 0, load new digit

		btfss	ShowDTime
		call	LoadBCDTest	; dotindex = 0, load new digit

l_DTime_3
		decfsz	dotindex,f	;
		goto	l_DTime_2

		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

		iorwf	tdd,f		; Load pixed data to temp disp data

;		incf	BCD,f		; Move index of character table
;		btfsc	STATUS,Z
;		incf	BCD_High,f
;		return			;
		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, load start parameters for
		clrf	dotindex	; digit displaying

l_DDate_1
		movf	dotindex,w	;
		btfss	STATUS,Z	;
		goto	l_DDate_11

		movlw	.6
		addwf	dotindex,f
		clrf	BCD_High

		btfss	ShowDDate
		goto	l_DDate_10

		btfss	ShowWDay
		goto	l_DDate_9

		btfss	Second2,3
		call	LoadBCDWDay
		btfsc	Second2,3
l_DDate_9
		call	LoadBCDDate	; dotindex = 0, load new digit

l_DDate_10
		movlw	.4		; Read dot patterns backward
		addwf	BCD,f
		btfsc	STATUS,C
		incf	BCD_High,f

l_DDate_11
		decfsz	dotindex,f	;
		goto	l_DDate_2	; dotindex < 6, display data

		incf	digitindex,f	; select next digit
		return			; to get a gap between digits

l_DDate_2
		call	CharPatternTab	; get the dot pattern for this column
		clrf	PCLATH

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

		decf	BCD,f		; Move table pointer backward
		incf	BCD,w
		btfsc	STATUS,Z
		decf	BCD_High,f
		return			;

;--------
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 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	;

		btfss	ShowSecHand	; Second hand disabled
		goto	MinuteHand

		movf	Second2,w	;
		andlw	0xFE		; filter out 1/2 second

		subwf	Scratch4,w
ArcSec					; Draw arc if Scratch4<= (Second2 and 0xFE)
		btfss	SecMode		; Set C if dot second hand mode
		bsf	STATUS,C
		btfss	STATUS,C
		bsf	tdd,bSecLED	; Sec led - second hand
SecHand
		btfsc	STATUS,Z	;
		bsf	tdd,bSecLED	; Sec led - second hand

MinuteHand
		bcf	STATUS,C	;
		rlf	Minute,w	; Clears C, because Minute < .60
		movwf	Scratch		; Scratch = minute * 2

		btfss	ShowMinHand	; Minute hand disabled
		goto	HourHand

		xorwf	Scratch4,w	;
		btfss	STATUS,Z	;
		goto	HourHand	; Minute hand not in this dpi

		btfsc	MinMode		;
		goto	DotMinHand

		movlw	B'00001111'	;
		iorwf	tdd,f		; Turn on minute hand
		bsf	tdd,bInnerLED	; Turn on analog innner Leds
		goto	HourHand

DotMinHand
		bsf	tdd,bMinLED	; Turn on minute dot

HourHand
		btfss	ShowHourHand	; Hour hand disabled
		return

		rlf	Hour,w		; Get hour
		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
		movlw	.120		; Scratch2 = (10 * Hour) + (2 * Minute / 12)

		btfsc	AnalMode24h
		rrf	Scratch2,f

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	;
		btfsc	STATUS,Z	;
					; Turn on hour hand
		bsf	tdd,bInnerLED	; Turn on analog innner Leds
		return					;

;-------- Get character Digital Date Display
; For characters ' ' to 'J'    Set BCD_High = 0
; For characters 'K' to 'u'    Set BCD_High = 1
; For characters 'v' to 0x9F   Set BCD_High = 2
;
;--------
LoadBCDDate				; load BCD with date digits
		movlw	high(DateTable0)
		movwf	PCLATH
		movf	digitindex,w	;
		addwf	digitindex,w	;
		btfss	ShowCentury
		addlw	DF_YYMMDD-DF_YYYYMMDD
		btfsc	DateFormat
		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	6*('-'-' ')	; '-'
		goto	l_dot		;
;3--
		movf	Month,w		; Month   1 digit
		goto	l_convert	;
;4--
		movf	Month,w		; Month  10 digit
		goto	l_convert_swap	;
;5--
		movlw	6*('-'-' ')	; '-'
		goto	l_dot		;
;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	6*('-'-' ')	; '-'
		goto	l_dot		;
;15--
		movf	Month,w		; Month   1 digit
		goto	l_convert	;
;16--
		movf	Month,w		; Month  10 digit
		goto	l_convert_swap	;
;17--
		movlw	6*('-'-' ')	; '-'
		goto	l_dot		;
;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	6*(' '-' ')	; ' '
		goto	l_dot		;
;21--
		movf	Day,w		; Day     1 digit
		goto	l_convert	;
;22--
		movf	Day,w		; Day    10 digit
		goto	l_convert_swap	;
;23--
		movlw	6*('-'-' ')	; '-'
		goto	l_dot		;
;24--
		movf	Month,w		; Month   1 digit
		goto	l_convert	;
;25--
		movf	Month,w		; Month  10 digit
		goto	l_convert_swap	;
;26--
		movlw	6*('-'-' ')	; '-'
		goto	l_dot		;
;27--
		movf	Year,w		; Year    1 digit
		goto	l_convert	;
;28--
		movf	Year,w		; Year   10 digit
		goto	l_convert_swap
;29--
		movlw	6*(' '-' ')	; ' '
		goto	l_dot		;

;  DateFormat: DD-MM-YY
DF_DDMMYY
;30--
		movlw	6*(' '-' ')	; ' '
		goto	l_dot		;
;31--
		movf	Year,w		; Year    1 digit
		goto	l_convert	;
;32--
		movf	Year,w		; Year   10 digit
		goto	l_convert_swap	;
;33--
		movlw	6*('-'-' ')	; '-'
		goto	l_dot		;
;34--
		movf	Month,w		; Month   1 digit
		goto	l_convert	;
;35--
		movf	Month,w		; Month  10 digit
		goto	l_convert_swap	;
;36--
		movlw	6*('-'-' ')	; '-'
		goto	l_dot		;
;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

LoadBCDTime				; load BCD with time digits
		movf	Hour,w
		btfss	Digit12Mode	; 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 
		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	BCD,w
		goto	l_PM		;
;1--
		movf	BCD,w		; Hour   10 digit
		goto	l_leading_swap_PM;
;2--
		movf	BCD,w		; Hour    1 digit
		goto	l_convert	;
;3--
		movlw	6*(':'-' ')	; ':'
		goto	l_dot		;
;4--
		movf	Minute,w	; Minute 10 digit
		goto	l_convert_swap	;
;5--
		movf	Minute,w	; Minute  1 digit
		goto	l_convert	;
;6--
		movlw	6*(':'-' ')	; ':'
		goto	l_dot		;
;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

LoadBCDWDay
		btfsc	ShowDayName
		goto	LoadBCDDay

		movlw	high(TempTable0)
		movwf	PCLATH
		movf	digitindex,w	;
		addwf	digitindex,w	; Clears C

TempTable0
		addwf	PCL,f		;
;0--
l_Space
		movlw	6*(' '-' ')	; ' '
		goto	l_dot_clr	;
;1--
		movlw	6*(' '-' ')	; ' '
		goto	l_dot_clr	;
;2--
		movlw	6*(' '-' ')	; ' '
		goto	l_dot_clr	;
;3--
		movlw	6*(' '-' ')	; ' '
		goto	l_dot_clr	;
;4--
		movlw	6*(' '-' ')	; ' '
		goto	l_dot_clr	;
;5--
		incf	WDay,w		; Day of week
		goto	l_convert	;
;6--
		movlw	6*(' '-' ')	; ' '
		goto	l_dot_clr	;
;7--
		movlw	6*(' '-' ')	; ' '
		goto	l_dot_clr	;
;8--
		movlw	6*(' '-' ')	; ' '
		goto	l_dot_clr	;
;9--
		goto	l_Space		;

TempTable1

	IF high(TempTable0) != high(TempTable1)
		ERROR "Temp jump table page error"
        ENDIF

;-------- Update Display memory with rotation measurement

LoadBCDTest				; load BCD with test digits
		movlw	high(TestTable0)
		movwf	PCLATH
		movf	digitindex,w	;
		addwf	digitindex,w	; Clears C
		bsf	STATUS,RP1	; Bank2

TestTable0
		addwf	PCL,f		;
;0--
		movlw	6*(' '-' ')	; ' '
		goto	l_dot		;
;1--
		movf	rot_bcd+4,w	; Rotation digit 10000
		goto	l_BCD		;
;2--
		movf	rot_bcd+3,w	; Rotation digit  1000
		goto	l_BCD		;
;3--
		movf	rot_bcd+2,w	; Rotation digit   100
		goto	l_BCD		;
;4--
		movf	rot_bcd+1,w	; Rotation digit    10
		goto	l_BCD		;
;5--
		movf	rot_bcd,w	; Rotation digit     1
		goto	l_BCD		;
;6--
		movlw	low(6*('R'-' ')); 'R'
		goto	l_dot_BCDH_1	;
;7--
		movlw	6*('/'-' ')	; '/'
		goto	l_dot		;
;8--
		movlw	low(6*('m'-' ')); 'm'
		goto	l_dot_BCDH_1	;
;9--
		goto	l_Space		;

TestTable1

	IF high(TestTable0) != high(TestTable1)
		ERROR "Test jump table page error"
        ENDIF


;=======================================================
; No execution passes here

l_dot_BCDH_2
		incf	BCD_High,f

l_dot_BCDH_1
		incf	BCD_High,f

l_dot_clr
		bcf	BCD_High,7	;
l_dot
		bcf	STATUS,RP1	; Bank 0 --- For entry from DrawTest
		movwf	BCD		;
		return

l_leading_swap_PM
		call	l_convert_swap
		xorlw	6*('0'-' ')
		btfss	STATUS,Z
		xorlw	6*('0'-' ')
		btfss	STATUS,Z
		goto	l_dot
		goto	l_pm_ap
		
l_leading_swap
		call	l_convert_swap
		xorlw	6*('0'-' ')
		btfss	STATUS,Z
		xorlw	6*('0'-' ')
		goto	l_dot

l_PM
		btfss	Digit12Mode
		goto	l_Space
		call	Conv2BCD
		andlw	0xF0
		btfsc	STATUS,Z
		goto	l_Space
l_pm_ap		
		movlw	.12
		subwf	Hour,w
		btfss	STATUS,C	;
		goto	l_Space
		movlw	6*("'"-' ')	; '''
		goto	l_dot_clr

l_convert_swap
		call	Conv2BCD
l_BCD_swap
		movwf	BCD		;
		swapf	BCD,w		;
		goto	l_BCD
l_convert
		call	Conv2BCD
l_BCD
		andlw	0x0F		;
		bcf	STATUS,RP1	; Bank0
;l_mult6
		movwf	BCD		;
		addwf	BCD,f		; BCD = BCD * 2
		sublw	.9		; w = 9 - BCD
		btfss	STATUS,C	; Check for decimal character (A..F converted to space)
		goto	l_Space
		movf	BCD,w		; W = BCD * 2
		addwf	BCD,w		; W = BCD * 4
		addwf	BCD,w		; W = BCD * 6
		addlw	6*('0'-' ')	; Convert to character code, C=0
		btfsc	flags5,4	; Test for binary mode
		bsf	BCD_High,7
		goto	l_dot

;-------- Update Display memory with Time Ticks every 5 minutes

Ticks
		movf	dpi,w
		xorwf	Scratch3,w
		btfss	STATUS,Z	; At a tick position
		return

		bsf	tdd,bTickLED	; Turn on analog tick Leds

		btfsc	STick12
		goto	Ticks10		; If single tick at 12 always add .10

		movf	Scratch3,w	; Dpi=30 at 12 o clock
		xorlw	.20
		btfsc	STATUS,Z	; Draw " at 12, ' at other
		goto	Ticks9
		xorlw	.20^.29
		btfsc	STATUS,Z
		goto	Ticks2
		xorlw	.29^.31
		btfss	STATUS,Z
Ticks10
		movlw	.1
Ticks9
		addlw	.7		; W = 0 if jump to here
Ticks2
		addlw	.2		; W = 0 if jump to here
		addwf	Scratch3,f
		return

;******************************************************************************
;	Processing of RC5 command's, called by main program if a command is received
;******************************************************************************

ProcessRC5
	ifdef	RC5AddrCheck
		movf	RC5_Addr,w	;
		xorlw	RemoteAddr	; test if RC5_Addr = RemoteAddr
		andlw	0x1F		; Only 5 bits to test
		btfss	STATUS,Z	;
		goto	ProcessRC5Done	;
	endif

;		movf	RC5_Cmd,w	;
;		andlw	0x7F		;

		movf	RC5_Cmd,w	;
		xorwf	RC5_Cmd2,f	; Compare command with toggle bit
		btfsc	STATUS,Z	;
		goto	ProcessRC5Done	;
		andlw	0x7F		; New command, remove toggle bit

		select_w
		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	WDAY_UP		;
		  goto	IncWDay		; Adjust Date : Increment Day of week
		case	WDAY_DN		;
		  goto	DecWDay		; Adjust Date : Decrement Day of week
		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	INDEX_UP	;
		  goto	DecDispOffset	; Adjust index sensor Offset, rotate display left
		case	INDEX_DN	;
		  goto	IncDispOffset	; Adjust index sensor Offset, rotate display right

					; Toggle functions
;		movf	RC5_Cmd,w	;
;		xorwf	RC5_Cmd2,f	;
;		btfsc	STATUS,Z	;
;		goto	ProcessRC5Done	;
;		andlw	0x7F		;

;		select_w
		case	TOuterLine 	;
		  goto	ToggleOuterLed	; Outer Line
		case	DigitalMode	;
		  goto	ChgDigitMode
		case	AnalogueMode	;
		  goto	ChgAnalogMode
		case	AnalogueHands	;
		  goto	ChgAnalogHands
		case	DemoM		;
		  goto	ToggleDemo	; Demo Mode
		case	TextMode	;
		  goto	ToggleText	; Text Mode
		case	TextMode	;
		  goto	ToggleText	; Scrolling Text Mode
		case	TStaticText	;
		  goto	ToggleStaticText; Static Text Mode
		case	TWDayName	;
		  goto	ToggleName	; Togge day name display mode
		case	SET_SP		;
		  goto	SetScrollSp	; Set Scrolling speed
		case	TBinMode	;
		  goto	ToggleBinMode	; Toggle binay mode
		case	TLANGUAGE	;
		  goto	SetLanguage	; Set Language
		case	TTicks		;
		  goto	ToggleTicks	; Toggle Ticks mode
		case	STANDBY		;
		  bcf	fDspEnabled	; Disable LEDs
;		default			; If none of listed codes
		goto	ProcessRC5Done

SetScrollSp
		movlw	0xF0		; Set scrolling speed
		addwf	CCPR1H,w
		iorlw	0x0F		; Speeds are 0x0F, 0x1F, ..., 0xEF, 0xFF
		movwf	CCPR1H
		call	ScrollSpToRtc	; Save it to RTC
		goto	ProcessRC5Done	;

SetLanguage				; Set language
		movlw	RTC_Language
		movwf	I2CWordAddr
		incf	Language,w
		andlw	0x0F		; Only 16 language
		movwf	Language
		goto	WriteToRtc	;

ToggleBinMode
		movlw	RTC_flags5
		movwf	I2CWordAddr
		movlw	1 << bBinMode
		xorwf	flags5,w
		andlw	0x30
		movwf	flags5
		goto	WriteToRtc	;

ToggleName
		movlw	1 << bShowDayName;
		addwf	flags,w
		xorwf	flags,w
		andlw	(1<<bDateFormat) | (1<<bDisp12Mode) | (1<<bShowDayName)
		goto	XorToFlags

ToggleOuterLed
		btfsc	RC5_TimeSet	; If time modified
		call	StoreTime	; Write it into RTC
		bcf	RC5_TimeSet	; Clear modification flag
		movlw	1 << bShowOuter	;

XorToFlags
		xorwf	flags,f		;

FlagsToRTC				; Save flags settings to RTC ram
		movlw	RTC_flags	; Address Flags
		movwf	I2CWordAddr
		movf	flags,w
WriteToRtc
		call	I2CByteWrite
		goto	ProcessRC5Done	;

ChgDigitMode
		movlw	1 << bShowWDay
		addwf	flags,f
		goto	FlagsToRTC	;

ChgAnalogHands
		movlw	1 << bShowSecHand;
		addwf	flags3,f
		goto	Flags3ToRTC

ToggleTicks
		movlw	RTC_flags4
		movwf	I2CWordAddr
		movlw	0x10
		addwf	CCP1CON,w
		andlw	0x30
		movwf	CCP1CON
		goto	WriteToRtc	;

ChgAnalogMode
		movlw	1 << 1<<bShowTicks;
		addwf	flags3,w
		xorwf	flags3,w
		andlw	 (1<<bMinMode) | (1<<bSecMode) | (1<<bShowTicks)

XorToFlags3
		xorwf	flags3,f

Flags3ToRTC				; Save flags3 settings to RTC ram
		movlw	RTC_flags3	; Address Flags3
		movwf	I2CWordAddr
		movf	flags3,w
		call	I2CByteWrite
		movf	CCP1CON,w
		goto	WriteToRtc	;

IncDispOffset
		incf	DispOffset,w	;
		call 	CheckIncrement 	;
		goto	SetDispOffset

DecDispOffset
		decf	DispOffset,w	;
		call 	CheckDecrement	;

SetDispOffset				; Save flags settings to RTC ram
		movwf	DispOffset	;
		call	DispOffsToRtc	; Save it to RTC
		goto	ProcessRC5Done	;

IncSecond
		incf	Second2,f	; Inc seconds
		incf	Second2,f	;
		movlw	.120		;
		subwf	Second2,w	;
		btfsc	STATUS,C	;
ClrSecond				; Clear seconds
		clrf	Second2		;
		goto	TimeSetRC5Done	;

DecSecond
		movlw	.2		; Dec seconds
		subwf	Second2,f	;
		movlw	.120		;
		btfss	STATUS,C	;
		addwf	Second2,f	;
		goto	TimeSetRC5Done	;

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	ProcessRC5Done	;
		decf	DMon,w		;
		movwf	Day		;
		goto	TimeSetRC5Done	;

IncWDay
		incf	WDay,f		; Inc day of week
		movlw	.7
		xorwf	WDay,w
 	    btfsc	STATUS,Z	;
StoreWDay
		movwf	WDay		;
		goto	TimeSetRC5Done	;

DecWDay
		decf	WDay,f		; Dec day of week
		btfss	WDay,7
		goto	TimeSetRC5Done	;
		movlw	.6
		goto	StoreWDay

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	;

DecYear					; Dec year
		decf	Year,f
		movlw	.99		;
		btfss	Year,7
		goto	TimeSetRC5Done	;
		movwf	Year
		decf	Century,f
		goto	TimeSetRC5Done	;

IncYear					; Increment year -> TimeCheck will correct
		incf	Year,f

TimeSetRC5Done
		bsf		RC5_TimeSet
		bcf		fTimeInv

ProcessRC5Done
		movf	RC5_Cmd,w	;
		movwf	RC5_Cmd2	;
		bsf	NewTime		; force display update
		bcf	RC5_DataReady	;

SetOuterLed
		btfss	fDspEnabled	; Disable LEDs
		goto	OuterLedOff

		bsf	CCPR1L,bOuterLED;
		btfss	ShowOuter	;

OuterLedOff
		bcf	CCPR1L,bOuterLED; Set OuterLED as in flags
		bcf	INTCON,GIE		; Disable interrupts
		call	ToPortA			; Changing PORTA is a critical operation, PORTA and it's copy has to be the same everytime
		bsf	INTCON,GIE		; Enable  interrupts
		return				;

ToggleStaticText				; Static text
		bcf	fScrollOn		; Scrolling OFF
		movlw	1 << bText		; toggle Text flag
		xorwf	flags2,f		;
		btfsc	fText
		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
		movf	Second2,f		;
		btfss	STATUS,Z		;
		return

TextON_OFF
		bcf	fScrollOn		; Scrolling OFF
		movlw	1 << bText		; toggle Text flag
		xorwf	flags2,f		;
		btfss	fText			; test Text flag
		return				;
		bsf	fScrollOn		; Scrolling ON

ClearDisplay
		bsf	STATUS,RP1		; jump to bank 2
		movlw	.120
		movwf	ch_dot_index
		movlw	0x20			; set FSR to 0x20
cldisp
		movwf	FSR			;
		clrf	INDF			; clear display memory
		call	CheckIncrementFSR	; Increment and test pointer
		decfsz	ch_dot_index,f		; Loop for .120 positions
		goto	cldisp			; Loop clears ch_dot_index

						; init stuff needed for Text Scroll function
      	clrf	ch_blanking			;

		clrf	ch_flags
		btfsc	fDemo
		bsf	ch_flags,bDemo

	if	(EEADR & 0x180)!=(ch_blanking & 0x180)
		banksel	EEADR			; Bank1
	endif

		movlw	0x80			; If EEPROM_SIZE==256 there are two messages
		andwf	EEADR,f			; Clear address for next read - keep message index

RetBank0
		clrf	STATUS			; goto bank 0
		return


;******************************************************************************
;	Main program
;******************************************************************************

main

InitIO
;		clrf	PORTA
;		clrf	PORTB			; PortA, PortB, PortC cleared at reset vector
;		clrf	PORTC			; all LED OFF

	ifdef	MotorDirFromCalibration
		btfsc	PORTC,bCalibration	; Read Calibration input
		bsf		MotorDirCC	; Set direction of motor rotation
	endif
	
		bsf	STATUS,RP0		; Bank1

		movlw	0xFF^((1<<bPixel0)|(1<<bOuterLED)|(1<<bCalibration))	;
		movwf	TRISA		; set bit 7..4, 2 input/ 3, 1..0 output
		movlw	1<<bIndexPuls	; set bit 0 input/ 7..1 output
 		movwf	TRISB		; LEDs will be turned on if rotation is stable

;		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	; send w to option.
		movlw	.249		; TMR2 period=250 PR2=249
		movwf	PR2		;
		bsf	PIE1,TMR2IE	; enable Peripheral interrupt from TMR2

	ifdef	__16F88
		clrf	ANSEL		; On 16F88 use all PORTA pins as digital I/O, A/D is off afther reset
	endif

		bsf	STATUS,RP1	; Bank3
		bcf	STATUS,RP0	; Bank2

		movlw	0x0F
		movwf	rot_bcd		; Blank rotation BCD data
		movwf	rot_bcd+1	; Wait min. 2 minutes to get first measurement
		movwf	rot_bcd+2
		movwf	rot_bcd+3
		movwf	rot_bcd+4

		bcf	STATUS,RP1	; Bank0

InitRam
		clrf	PixelWidth	;
		clrf	PixelOff	;

		call	InitSubSecCnt	; reload counter SubSecond = 0x10000 - .2500 = 0xF63C

	ifdef	CMCON
	  if	(CMCON & 0x180)==0x80
		bsf	STATUS,RP0	; Bank1 for 16F87 and 16F88, Voltage reference modul is off afther reset
	  endif	
		movwf	CMCON		; Turn comparators OFF
	  if	(CMCON & 0x180)==0x80
		bcf	STATUS,RP0	; Bank0
	  endif	
	endif

		clrf	flags2		; clear flags2

		call	InitTime	; Init time counter variables and Display flags

		clrf	RC5_flags	; clear RC5_flags
		clrf	RC5_Tmr		;
		bsf	RC5_WaitStart	; RC5 is waiting for startbit

		movf	DispOffset,w
		movwf	iFSR

InitDisp
		call 	ClearDisplay	; clear display content
InitTmr
		clrf	INTCON		; clear and dissable all possible interrupt flag
		clrf	PIR1		; clear all pripheral interrupt flag

		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

MainLoop
		btfsc	RC5_DataReady	;
		call	ProcessRC5	;

		btfss	fScrollOn	;
		goto	NoScrolling	;
		movf	TmrScroll,f	;
		btfss	STATUS,Z	;
		goto	NoScrolling	;
		movf	CCPR1H,w	; Get Scrolling speed
		movwf	TmrScroll	; Reinit scrolling timer
		call	ScrollText	;

NoScrolling
		btfsc	NewPCnt		; test Period counter flag
		call	CalcPixelPitch  ; calculate new pixel pitch

		btfss	NewTime		; test new time flag
		goto	MainLoop	;

					; one second past. Do timecheck and if text=off, also a display update.
		call	TimeCheck	;

		btfsc	fDemo		; Check for demo mode
		call	DemoMode	;

		btfsc	fText		; test Image flag
		goto  	MainLoop	; if Image flag SET, leave display-content unchanged

		btfsc	NewRot		; Convert rotation measurement
		call	Word2Bcd5

					; start display memory update
		clrf	dpi		; dpi = 0
		clrf	Scratch3	; keep index for 5 min timeticks
		clrf	BCD_High
		movlw	0x20		; start of display memory

lUpdateDisplay
		movwf	FSR

		clrf	tdd		;

		btfsc	ShowDTime	;
		call	DTime		; Display digital Time

		btfsc	ShowDDate	;
		call	DDate		; Display digital Date

		call	Hands		; Analogue clock's hands

		btfsc	ShowTicks	;
		call	Ticks		; Analogue clock's ticks

		movf	flags,w
		andlw	(1<<bShowDDate)|(1<<bShowDTime)
		btfss	STATUS,Z
		goto	StoreTdd
		movf	flags3,w
		andlw	(1<<bShowHourHand)|(1<<bShowMinHand)|(1<<bShowSecHand)
		btfss	STATUS,Z
		goto	StoreTdd
		call	DTime		; Display digital Rotation

StoreTdd
		movf	tdd,w		; store data in
		movwf	INDF		; display memory

		incf	dpi,f		;
		movlw	.120		;
		xorwf	dpi,w		;
		btfsc	STATUS,Z	;
		goto  	MainLoop	;

		call	CheckIncrementFSR ; Move pointer
		goto	lUpdateDisplay

;******************************************************************************
;	Text display functions
;******************************************************************************

CharOffset					; Must be called with Bank 2 active
		movwf	ch_dot_point_L		; store ascii_code
		clrf	ch_dot_point_H		; clear high byte
		movlw	.32			; ascii_code - .32
		subwf	ch_dot_point_L,f	;

		btfsc	ch_dot_point_L,7	; (ascii_code - .32) > .127 means invalid code,
		clrf	ch_dot_point_L		; relpace with " "

		movlw	.6			; Called only when ch_dot_index == 0
		addwf	ch_dot_index,f		; indicate start of new char, clears C

		rlf	ch_dot_point_L,f	; ch_dot_point_L = (ascii_code - .32) * 2, C = 0 because ch_dot_point_L <.128
;;;		rlf	ch_dot_point_H,f	; Why rotate a 0x00 if C=0 [ max 0x7F<<1 == 0xFE , C = 0 ]
						; C = 0
		rlf	ch_dot_point_L,w	; W = (ascii_code - 32) * 4
		rlf	ch_dot_point_H,f	; Save C to high part
		addwf	ch_dot_point_L,f	; ch_dot_point_L = (ascii_code - 32) * 6
		btfsc	STATUS,C		; If C==1, increment high part
		incf	ch_dot_point_H,f	; ch_dot_point (16bit) = (ascii_code - 32) * 6
		return

CharGenx					; Calls out of first 2K
		movlw	high(CharTab)		; Add address of char gen table
		addwf	ch_dot_point_H,w	; Get high path of index
		movwf	PCLATH			; PCHATH 5.4 = 01
		movf	ch_dot_point_L,w	; IT routine MUST save PCLATH
		movwf	PCL

;=======================================================
; No execution passes here

;--------
LoadChrData					; Must be called with Bank 2 active

		call	CharGenx		; Get next dot pattern
		clrf	PCLATH			; Call / Goto in first 2K
		incf	ch_dot_point_L,f	; pointer++
		btfsc	STATUS,Z		; If owerflow
		incf	ch_dot_point_H,f	;  increment high part (J and u are on boundary)
		return

;--------
PrintDisp
		call	ClearDisplay		; clear display content, clears ch_dot_index
						; None of these controller has EEADR on Bank3
	if	(EEADR & 0x080)==0x80
		bsf	STATUS, RP0		; Bank1
	endif
	if	(EEADR & 0x100)==0x100
		bsf	STATUS, RP1		; Bank2
	endif

		movlw	0x70
		movwf	EEADR			; start of static message in EEProm
		movlw	0xE1			; Start for first char a 7 o'clock
		movwf	FSR			;
		movlw	.15			; 15 char to display
		movwf	Scratch3		;
pdisp_1
		call	EpromRead		; Read next character from EEProm, returns with Bank2 selected
		call	CharOffset		; call character data

pdisp_2
		call	LoadChrData		; load pixel data from CharGen
		movwf	INDF			; store char pixel data in display memory
		call 	CheckIncrementFSR	; increment FSR
		movwf	FSR			;
		decfsz	ch_dot_index,f		; 6 dot's in one character, all displayed ?
		goto	pdisp_2			;

		decfsz	Scratch3,f		; Loop for 15 characters
		goto	pdisp_1

		bcf	STATUS,RP1		; Bank0
		return

;--------
ScrollText
		bsf	STATUS,RP1		; Bank2

      	movf	ch_dot_index,w			;
		btfss	STATUS,Z		; ch_dot_index == 0 ?
		goto	Scroll_0		; No - process next dot pattern

		movf	ch_blanking,w		; ch_blanking == 0 ?
		btfsc	STATUS,Z		;
		goto	Scroll_read_ee		; Yes - Read character form EEProm
		decfsz	ch_blanking,f		;
		goto	Scroll_2		; insert one more " "
						; ch_blanking == 0 - End of message and leadout

						; None of these controller has EEADR on Bank3
	if	(EEADR & 0x180)!=(ch_blanking & 0x180)
		banksel	EEADR			; Bank1
	endif

	if	EEPROM_SIZE==256
		movlw	0x80			; On 16F684A, 16F87, 16F88 change message
		andwf	EEADR,f
		xorwf	EEADR,f
	else
		clrf	EEADR			; On 16F628(A) Go to beginning of message
	endif

	if	(EEADR & 0x180)!=(ch_blanking & 0x180)
		banksel	ch_blanking		; Bank2
	endif

		btfss	ch_flags,bDemo		; in demo mode?
		goto	Scroll_read_ee		; No: re-read char

		clrf	STATUS			; Bank0
		goto	TextON_OFF		; at end of line, turn text off

Scroll_read_ee
		call	EpromRead		; Read next character from EEProm, returns with Bank2 selected
		btfss	STATUS,Z		; 0x00 indicates end of line
		goto	Scroll_1		;

		movlw	0x0F			; insert 15 " " at end of string to clear display
		movwf	ch_blanking		;

Scroll_2
		movlw	" "			; w = " "

Scroll_1
		call	CharOffset		; call character data
Scroll_0
		call	LoadChrData		; load pixel data from CharGen
		decf	ch_dot_index,f		; dec ch_dot_index
		movwf	Scratch			;

	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			; Init display memory pointer
ScrollLoop
		movf	INDF,w			; Get current display data = Previous_INDF
		xorwf	Scratch,w		; W = (Previous_INDF ^ Scratch)
		xorwf	INDF,f			; INDF = (Previous_INDF ^ Scratch) ^ 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		; Check for end of area: FSR = 0xE3 (or 0xC0)
		goto	ScrollLoop		;

		goto	RetBank0

;******************************************************************************
;	Some general functions
;******************************************************************************

;******************************************************************************
; Reads next character from EEProm memory - returns with Bank2 selection

EpromRead
		banksel	EECON1			; Select Bank of EEDATA, may be on Bank1 or Bank3

		bsf	EECON1, RD		; read character from EEProm

	if (EECON1 & 0x180)!=(EEADR & 0x180)
		bcf		STATUS,RP0	; Bank2 if EECON1 is on Bank3
	endif
						; If EECON1 is on Bank1 EEADR is there
		incf	EEADR,f			; inc address for next read

		movf	EEDATA,w		; Get next character

	if (EEDATA & 0x180)!=(ch_dot_index & 0x180)
		banksel	ch_dot_index		; Bank2 if EEADR is on Bank1
	endif
						; Returns with Bank2 selected
		return


;- 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
;******************************************************************************

InitTime					; Init time from I2C RTC
		movlw	RTC_Second		; Address of Seconds
						; I2CWordAddr = 0x02
		call	I2CByteReadSetAddr	; Read seconds
		call	BcdToBin
		movwf	Second2
		addwf	Second2,f
						; I2CWordAddr = 0x03

		call	I2CByteRead		; Read minute
		call	BcdToBin
		movwf	Minute
						; I2CWordAddr = 0x04

		call	I2CByteRead		; Read hour
		call	BcdToBin3F		; Mask format and AM/PM
		movwf	Hour
						; I2CWordAddr = 0x05

		call	I2CByteRead		; Read day
		call	BcdToBin3F
		movwf	Day
		swapf	tdd,f
		rrf	tdd,f
		rrf	tdd,w
		andlw	0x03
		movwf	dotindex		; Save year bit 1..0
						; I2CWordAddr = 0x06

		call	I2CByteRead		; Read Month
		andlw	0x1F
		call	BcdToBin
		movwf	Month
		swapf	tdd,f
		rrf	tdd,w
		andlw	0x07
		movwf	WDay
						; I2CWordAddr = 0x07

		movlw	RTC_Year		; Address of Year
		call	I2CByteReadSetAddr	; Read year
		movwf	Year
						; I2CWordAddr = 0x11

		call	I2CByteRead		; Read year ^ 0xff
		xorlw	0xFF
		xorwf	Year,w
						; I2CWordAddr = 0x12

		btfss	STATUS,Z
		goto	InitTimeDef		; Year not valid, init with default values

		call	I2CByteRead		; Read Century
		movwf	Century
						; I2CWordAddr = 0x13

		call	I2CByteRead		; Read flags
		movwf	flags
						; I2CWordAddr = 0x14

		call	I2CByteRead		; Read DispOffset
		movwf	DispOffset
		call	ValidateOffs
						; I2CWordAddr = 0x15

		call	I2CByteRead		; Read Scroll speed
		iorlw	0xCF
		movwf	CCPR1H
						; I2CWordAddr = 0x16
		call	I2CByteRead		; Read flags3
		movwf	flags3
						; I2CWordAddr = 0x17

		call	I2CByteRead		; Read flags4
		andlw	0x30
		movwf	CCP1CON
						; I2CWordAddr = 0x18

		call	I2CByteRead		; Read language code
		andlw	0x0F
		movwf	Language
						; I2CWordAddr = 0x19

		call	I2CByteRead		; Read flags4
		andlw	0x30
		movwf	flags5
						; I2CWordAddr = 0x1A

		movf	Year,w			; Has the RTC increment Year
		xorwf	dotindex,w
		andlw	0x03
		btfsc	STATUS,Z
		return				; No, return

		incf	Year,f			; Yes, increment Year
		call	TimeCheck		; Will correct Year and Century
		goto	StoreYear

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
		goto	DifDispOffs

InitTimeDef
		movlw	.12			;why do clocks always start
		movwf	Hour			;at 12:00 ?
		clrf	Minute
        clrf	Second2
		movlw	.1
		movwf	Day
		clrf	WDay
		movwf	Month
		movwf	Year
		movlw	.20
		movwf	Century

;;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

		movlw	(1<<bShowHourHand) | (1<<bShowMinHand) |(1<<bShowSecHand) | (1<<bShowTicks) 
		movwf	flags3			; Init flags3
		clrf	CCP1CON			; Init flags4
		clrf	flags5			; Init flags5

		clrf	Language		; Init language

		bsf		fTimeInv

		movlw	RTC_Language	; Address of language in RTC
		movwf	I2CWordAddr
					; I2CWordAddr = 0x18
;;1 
;;1 return
		movf	Language,w
		call	I2CByteWrite	; Store it in RTC

; Init display offset with default value
DifDispOffs
		movlw	DISPLAYOFFSET	; Initial Display Offset for the hardware
		movwf	DispOffset	;
		call	DispOffsToRtc

		movlw	0xFF		; Scroll speed
		movwf	CCPR1H

ScrollSpToRtc
		movlw	RTC_ScrollSp	; Address of scrolling speed in RTC
		movwf	I2CWordAddr
					; I2CWordAddr = 0x15
		movf	CCPR1H,w
		goto	I2CByteWrite	; Store it in RTC

DispOffsToRtc
		movlw	RTC_disp_off	; Address DispOffset
		movwf	I2CWordAddr
					; I2CWordAddr = 0x14
		movf	DispOffset,w
		goto	I2CByteWrite

BcdToBin3F
		andlw	0x3F
BcdToBin				; Uses only numbers < 60
		movwf	FSR
		andlw	0x0F
		btfsc	FSR,4
		addlw	.10
		btfsc	FSR,5
		addlw	.20
		btfsc	FSR,6
		addlw	.40
		btfsc	FSR,7
		addlw	.80
		return

StoreTime
		movlw	0x80		; Disable counting command
		call	SendRtcCmd
					; I2CWordAddr = 0x01

		incf	I2CWordAddr,f	; Address of seconds
					; I2CWordAddr = 0x02

		bcf	STATUS,C	; Store Second
		rrf	Second2,w
		call	I2CBcdWrite
					; I2CWordAddr = 0x03

		movf	Minute,w	; Store Minute
		call	I2CBcdWrite
					; I2CWordAddr = 0x04

		movf	Hour,w		; Store Hour
		call	I2CBcdWrite
					; I2CWordAddr = 0x05

		swapf	Year,w		; Store Day and Year bit 1..0
		movwf	tdd
		rlf	tdd,f
		rlf	tdd,f
		movlw	0xC0
		andwf	tdd,f
		movf	Day,w
		call	Conv2BCD
		andlw	0x3F
		iorwf	tdd,w
		call	I2CByteWrite
					; I2CWordAddr = 0x06

		swapf	WDay,w		; Store Month and Wday
		movwf	tdd
		rlf		tdd,f
		movlw	0xE0
		andwf	tdd,f
		movf	Month,w
		call	Conv2BCD
		andlw	0x1F
		iorwf	tdd,w
		call	I2CByteWrite
					; I2CWordAddr = 0x07

		movlw	0x00		; Enable counting command
		call	SendRtcCmd
					; I2CWordAddr = 0x01

StoreYear
		movlw	RTC_Year	; Address Year
		movwf	I2CWordAddr
					; I2CWordAddr = 0x10
		movf	Year,w
		call	I2CByteWrite
					; I2CWordAddr = 0x11
		comf	tdd,w
		call	I2CByteWrite
					; I2CWordAddr = 0x12
		movf	Century,w
		goto	I2CByteWrite

SendRtcCmd
		clrf	I2CWordAddr	; I2CWordAddr = 0x00
		goto	I2CByteWrite


;******************************************************************************
;	I2C low level functions
;******************************************************************************

XorToPortA
		xorwf	CCPR1L,f
ToPortA
		movf	CCPR1L,w
		movwf	PORTA
		return

  ifdef	UsePCF8583RTC
; Temporary variables are in common Ram - Can be used from Bank of TRISA too
; START selects BANK1 to access TRISA   - STOP select BANK0 before return

; At reset SCL and SDA bits in PORTA and CCPR1L are cleared
; PortA writes are made with copying CCPR1L to PORTA to keep these bits cleared

;******************************************************************************
; Reads a byte from RTC to tdd, address is in w
; store address in I2CWordAddr, I2CWordAddr incremented afther execution

I2CByteReadSetAddr
					;
		movwf	I2CWordAddr	; Store address

; Reads a byte from RTC to tdd, address is in I2CWordAddr
; I2CWordAddr incremented afther execution

I2CByteRead
	CALL 	START			; Generate Start, returns with 10100000 RTCADDR in W
	CALL 	OUT_BYTE		; Send slave address byte + nack
	CALL 	OUT_BYTE_ADDR		; Send word  address byte + nack

	CALL 	START			; Generate repeted start
	MOVLW	RTC_ADDR | 1		; output 10100001 for read
	CALL 	OUT_BYTE		; Send byte + nack

IN_BYTE					; Read byte on i2c bus
	CALL 	HIGH_SDA		; Configure SDA as input
	bsf	FSR,3			; Load 8 to FSR, OUT_BYTE celared FSR
IN_BIT
	CALL 	HIGH_SCL		; SCL -> 1 ; 5us wait
	BCF	STATUS,RP0		; Bank 0 to read PORTA
	BCF	STATUS, C		; clear carry
	BTFSC 	SDA			; test SDA bit
	BSF 	STATUS, C		; set carry if SDA == 1
	BSF	STATUS,RP0		; Bank 1 to control TRISA
	RLF 	tdd,F			; tdd = (tdd << 1) | input bit
	CALL 	LOW_SCL			; SCL -> 0 ; 5us wait
	DECFSZ 	FSR, F			; decrement bit counter
	GOTO 	IN_BIT
	CALL	NACK			; Clock out nack bit SDA must be high (input)

ToStop
	CALL 	STOP			; Generate stop condition
	incf	I2CWordAddr,f		; Increment word address
	movf	tdd,W			; Return data just read
	bcf	STATUS,RP0		; Back to Bank 0
	return

;******************************************************************************
; Writes W to RTC in BCD format, address is in I2CWordAddr
; I2CWordAddr incremented afther execution

I2CBcdWrite
	call	Conv2BCD		; Convert w to BCD

; Writes W to RTC, address is in I2CWordAddr
; I2CWordAddr incremented afther execution

I2CByteWrite
	movwf	tdd			; Save data to be written to RTC
	CALL 	START			; Generate Start, returns with 10100000 RTCADDR in W
	CALL 	OUT_BYTE		; Send slave address byte + nack
	CALL 	OUT_BYTE_ADDR		; Send word  address byte + nack
	MOVF 	tdd, W			; Get output data
	CALL 	OUT_BYTE		; Send data byte + nack
	goto	ToStop

; Generate stop condition on I2C bus
STOP:					; SDA 0 -> 1 while SCL == 1
					; SCL must be LOW afther (N)ACK's CLOCK_PULSE
	CALL	LOW_SDA			; SDA -> 0 - NACK has done it
	CALL	HIGH_SCL		; SCL -> 1 and make 5us stop setup time

; Make SDA high by making it input
HIGH_SDA:				; high impedance by making SDA an input
	BSF 	SDA			; make SDA pin an input
	GOTO 	DELAY_5US		; SDA -> 1 and make 5us bus free time

; Generate start / repeated start condition on I2C bus
START:					; SDA 1 -> 0 while SCL == 1, then SCL -> 0
	BSF 	STATUS, RP0		; Bank 1 - Access TRISA
	CALL 	HIGH_SDA		; SDA 0 -> 1 ; wait 5 us - For repeated start
	CALL 	HIGH_SCL		; SCL 0 -> 1 ; make 5 us Start setup time
	CALL 	LOW_SDA			; SDA 1 -> 0 ; make 5 us Start hold  time
	GOTO 	LOW_SCL			; SCL 1 -> 0 ; wait 5 us

; Shift out a byte to I2C bus, clock in (n)ack, get data from I2CWordAddr
OUT_BYTE_ADDR
	MOVF	I2CWordAddr,w		; output address to be read

; Shift out a byte to I2C bus, clock in (n)ack, data is in w
OUT_BYTE:				; send o_byte on I2C bus
	movwf	BCD			; Store data to send
	MOVLW 	.8
	MOVWF 	FSR			; Loop for 8 bits
OUT_BIT:
	BTFSC 	BCD,7			; if  one, send a  one
	CALL 	HIGH_SDA		; SDA at logic one
	BTFSS 	BCD,7			; if zero, send a zero
	CALL 	LOW_SDA			; SDA at logic zero
	CALL 	CLOCK_PULSE		; SCL -> 1 ; 5 us wait, SCL -> 0 ; 5 us wait
	RLF 	BCD,F			; left shift, move mext bit to bit7
	DECFSZ 	FSR,F			; decrement bit counter - Leaves with FSR = 0
	GOTO 	OUT_BIT

; Clock in/out (n)ack
NACK:					; bring SDA high and clock, SDA must be input
	CALL 	HIGH_SDA
	CALL	CLOCK_PULSE		; SCL -> 1 ; 5 us wait, SCL -> 0 ; 5 us wait

; Make SDA low by making it output
LOW_SDA:				; SDA -> 0 ; 5 us wait
	BCF 	SDA			; make SDA pin an output
	GOTO 	DELAY_5US

; Generate clock pulse 			; SCL -> 1 ; 5 us wait, SCL -> 0 ; 5 us wait
CLOCK_PULSE:				; SCL momentarily to logic one
	CALL 	HIGH_SCL		; SCL -> 1 ; 5 us wait

; Make SCL low by making it output
LOW_SCL:				; SCL -> 0 ; 5 us wait
	BCF 	SCL			; make SCL pin an output
	GOTO	DELAY_5US

; Make SCL high by making it input
HIGH_SCL:				; SCL -> 1 ; wait 5 us
	BSF 	SCL			; make SCL pin an input

; Delay 5uS @ 20MHz
DELAY_5US:				; provides nominal >5 us delay @20MHz
					; 1 instuction takes 200ns
	MOVLW	 .8			; 0.2 us
	MOVWF 	dpi			; 0.2 us
DELAY_1:				; Loop of 3 inst. time
	DECFSZ 	dpi, F			; 7*0.2+0.4 us
	GOTO 	DELAY_1			; 7*0.4 us
	RETLW	RTC_ADDR		; Return address of RTC for OUT_BYTE 0.4 us

  else

I2CByteReadSetAddr
					;
		movwf	I2CWordAddr	; Store address
I2CByteRead
I2CBcdWrite
		call	Conv2BCD	; Convert w to BCD
I2CByteWrite
		incf	I2CWordAddr,f
		return

  endif

;******************************************************************************
;	Base conversion function for rotation displaying
;******************************************************************************


Word2Bcd5
;Takes hex number in NumH:NumL  Returns decimal in ;TenK:Thou:Hund:Tens:Ones
;written by John Payson

;input

;=A3*16^3 + A2*16^2+ A1*16^1+ A0*16^0
;=A3*4096 + A2*256 + A1*16  + A0

NumH            EQU rotation_H  ;A3*16+A2
NumL            EQU rotation_L	;A1*16+A0

;=B4*104 + B3*103 + B2*102 + B1*101 + B0*100
;=B4*10000 + B3*1000 + B2*100 + B1*10 + B0

TenK            EQU rot_bcd+4   ;B4
Thou            EQU rot_bcd+3	;B3
Hund            EQU rot_bcd+2	;B2
Tens            EQU rot_bcd+1	;B1
Ones            EQU rot_bcd	;B0

	bsf	STATUS,RP1	; Bank2
	swapf	NumH,w		;w  = A2*16+A3
        iorlw   0xF0		;w  = A3-16
        movwf   Thou		;B3 = A3-16
        addwf   Thou,f		;B3 = 2*(A3-16) = 2A3 - 32
        addlw   .226		;w  = A3-16 - 30 = A3-46
        movwf   Hund		;B2 = A3-46
        addlw   .50		;w  = A3-46 + 50 = A3+4
        movwf   Ones		;B0 = A3+4

        movf    NumH,w		;w  = A3*16+A2
        andlw   0x0F		;w  = A2
        addwf   Hund,f		;B2 = A3-46 + A2 = A3+A2-46
        addwf   Hund,f		;B2 = A3+A2-46  + A2 = A3+2A2-46
        addwf   Ones,f		;B0 = A3+4 + A2 = A3+A2+4
        addlw   .233		;w  = A2 - 23
        movwf   Tens		;B1 = A2-23
        addwf   Tens,f		;B1 = 2*(A2-23)
        addwf   Tens,f		;B1 = 3*(A2-23) = 3A2-69 (Doh! thanks NG)

        swapf   NumL,w		;w  = A0*16+A1
        andlw   0x0F		;w  = A1
        addwf   Tens,f		;B1 = 3A2-69 + A1 = 3A2+A1-69 range -69...-9
        addwf   Ones,f		;B0 = A3+A2+4 + A1 = A3+A2+A1+4 and Carry = 0 (thanks NG)

        rlf     Tens,f		;B1 = 2*(3A2+A1-69) + C = 6A2+2A1-138 and Carry is now 1 as tens register had to be negitive
        rlf     Ones,f		;B0 = 2*(A3+A2+A1+4) + C = 2A3+2A2+2A1+9 (+9 not +8 due to the carry from prev line, Thanks NG)
        comf    Ones,f		;B0 = ~(2A3+2A2+2A1+9) = -2A3-2A2-2A1-10 (ones complement plus 1 is twos complement. Thanks SD)

;;First two instructions make up negation. So,
;;Ones  = -1 * Ones - 1 
;;      = - 2 * (A3 + A2 + A1) - 9 - 1 
;;      = - 2 * (A3 + A2 + A1) - 10
        rlf     Ones,f	;B0 = 2*(-2A3-2A2-2A1-10) = -4A3-4A2-4A1-20

        movf    NumL,w		;w  = A1*16+A0
        andlw   0x0F		;w  = A0
        addwf   Ones,f		;B0 = -4A3-4A2-4A1-20 + A0 = A0-4(A3+A2+A1)-20 range -215...-5 Carry=0
        rlf     Thou,f		;B3 = 2*(2A3 - 32) = 4A3 - 64

        movlw   0x07		;w  = 7
        movwf   TenK		;B4 = 7

;B0 = A0-4(A3+A2+A1)-20	;-5...-200
;B1 = 6A2+2A1-138		;-18...-138
;B2 = A3+2A2-46			;-1...-46
;B3 = 4A3-64			;-4...-64
;B4 = 7					;7
; At this point, the original number is
; equal to TenK*10000+Thou*1000+Hund*100+Tens*10+Ones 
; if those entities are regarded as two's compliment 
; binary.  To be precise, all of them are negative 
; except TenK.  Now the number needs to be normal- 
; ized, but this can all be done with simple byte 
; arithmetic.

        movlw   .10		;w  = 10
Lb1:				;do
        addwf   Ones,f		; B0 += 10
        decf    Tens,f		; B1 -= 1
        btfss   3,0
         goto   Lb1		; while B0 < 0
Lb2:				;do
        addwf   Tens,f		; B1 += 10
        decf    Hund,f		; B2 -= 1
        btfss   3,0
         goto   Lb2		; while B1 < 0
Lb3:				;do
        addwf   Hund,f		; B2 += 10
        decf    Thou,f		; B3 -= 1
        btfss   3,0
         goto   Lb3		; while B2 < 0
Lb4:				;do
        addwf   Thou,f		; B3 += 10
        decf    TenK,f		; B4 -= 1
        btfss   3,0
         goto   Lb4		; while B3 < 0

		movf	TenK,w	; Remove leading zeros
		movwf	FSR
		movlw	0x0F
		btfsc	STATUS,Z
		movwf	TenK

		movf	Thou,w
		iorwf	FSR,f
		movlw	0x0F
		btfsc	STATUS,Z
		movwf	Thou

		movf	Hund,w
		iorwf	FSR,f
		movlw	0x0F
		btfsc	STATUS,Z
		movwf	Hund

		movf	Tens,w
		iorwf	FSR,f
		movlw	0x0F
		btfsc	STATUS,Z
		movwf	Tens

		bcf	STATUS,RP1	; Bank0
		bcf	NewRot
        return

	END    				; directive 'end of program'
