;-----------------------------------------------------------------------
; PIC based clock timer. Copyright (C) 2012 Luke Mester
;
; Unreleased version 1/3/14
;	1/15/14 Added temperature sensor
;	1/25/14  Beats per minute, Beats per hour display
;	1/26/14	Average the temperature data to reduce ADC sample noise
;	2/12/14 use 18F14K22
;	02/15/14 Add bootloader to allow serial software update
;	02/16/14 Option to power down the bluetooth module
;	2/18/14
;	Add options to enable/disable clock and temperature display
;	Quick access buttons Select changes SPB,BPM,BPH
;	Plus enable/disable log, Minus enable/disable LCD backlight
;	
;
;The following PIC pins are used:
;Pin numbers will vary depending upon the IC package used
;See table 1-1 on the PIC18F1XK22 data sheet
;
;
;Symbol		Pin			Description
;
;Input switches for selecting operating modes.
;SetSw		RA1			;Config switch (Set)
;SelSw		RA2			;Choose selection switch (Select)
;NxtSw		RC3			;Next,Advance,Plus	switch
;PrvSw		RC4			;Prev,Retard,Minus	switch
;
;Bluetooth serial link control
;BTOff		RC5			;Bluetooth serial shutdown
;
;Rate count input
;RCInp		RC2 		;Rate count input minute hand sensor
;
;LED outputs
;LED		RC0		;Beat LED Blinks when pendulum motion sensed (INT0)
;LED2		RC1		;Time LED Currently just a 1 second blinker
;					;Runs from low priority interrupt
;
;Clock beat input signal. 
;INT0		RA0,INT0	;Edge triggered signal when clock ticks
;
; RS-232 serial port
; Currently connected to a bluetooth module to provide wireless data transfer
; 			RX			;Serial receive data
;			TX			;Serial transmit data
;
; I2C IIC (I squared C) serial port
;Connected to a 20x4 character LCD display module
;			SCL			;Serial clock
;			SDA			;Serial data
;	crystal or oscillator module
; Currently configured for a TCXO module
;			OSC1		;Crystal pin or clock input
;			OSC2		;crystal pin or clock output
;------------------------------------------------------------------------



;		LIST   P=PIC18F13K22		;list directive to define processor
;		#include <p18F13K22.inc>	;processor specific definitions


		LIST   P=PIC18F14K22		;list directive to define processor
		#include <p18F14K22.inc>	;processor specific definitions


  
		#include <Adj_Delay_ms.inc>
		#include <text.inc>
		#include <LCD_I2C.inc>
		#include <18fdiv.inc>


		errorlevel -302		;suppress "not in bank 0" message

     ;Setup CONFIG11H
;     CONFIG FOSC = IRC, PLLEN = OFF, PCLKEN = OFF, FCMEN = OFF, IESO = OFF ;internal
;     CONFIG FOSC = HS, PLLEN = OFF, PCLKEN = OFF, FCMEN = OFF, IESO = OFF ;20MHz xtal
     CONFIG FOSC = HS, PLLEN = ON, PCLKEN = OFF, FCMEN = OFF, IESO = OFF ;10MHz xtal 4 x PLL
;     CONFIG FOSC = ECCLKOUTH, PLLEN = ON, PCLKEN = OFF, FCMEN = OFF, IESO = OFF ;10MHz external osc 4 x PLL 
    ;Setup CONFIG2L
     CONFIG PWRTEN = ON, BOREN = ON, BORV = 19
     ;Setup CONFIG2H
     CONFIG WDTEN = OFF, WDTPS = 1
     ;Setup CONFIG3H
     CONFIG MCLRE = OFF, HFOFST = OFF ;mclre = on
     ;Setup CONFIG4L
     CONFIG STVREN = OFF, LVP = OFF, BBSIZ = OFF, XINST = OFF
     ;Setup CONFIG5L
     CONFIG CP0 = OFF, CP1 = OFF
     ;Setup CONFIG5H
     CONFIG CPB = OFF, CPD = OFF
     ;Setup CONFIG6L
     CONFIG WRT0 = OFF, WRT1 = OFF
     ;Setup CONFIG6H
     CONFIG WRTB = OFF, WRTC = OFF, WRTD = OFF
     ;Setup CONFIG7L
     CONFIG EBTR0 = OFF, EBTR1 = OFF
     ;Setup CONFIG7H
     CONFIG EBTRB = OFF

;----------------------------------------------------------------------------
;Constants


;Time constants
;Times for 40 MHz

RTClock		equ	 .62500	;Real time clock timer 3 trigger value
;rs-232 serial
SerBaud		EQU  .1041 ;9600 @ 40MHz  set baud rate 9600 

RX_BUF_LEN	EQU	.3		;length of receive buffer
TX_BUF_LEN	EQU	.3		;length of transmit buffer
TrigStep	EQU	 .2		;Trigger delay step
BeatVVal 	EQU	.10		;Beat valid counter initial value
RptTv		equ  .10	;Button repeat delay

;LCD display line addresses
;These values are for a 20x4 display
LCDL1P		equ	0x00		;Line 1
LCDL2P		equ	0x40		;Line 2
LCDL3P		equ	0x14		;Line 3
LCDL4P		equ	0x54		;Line 4
;----------------------------------------------------------------------------
;Bit Definitions
ReceivedCR	EQU	0		;bit indicates <CR> character received
;Input switches
SetSw	equ	RA1			;Config switch
SelSw	equ	RA2			;Choose selection switch
NxtSw	equ	RC3			;Next,Advance,Plus	switch
PrvSw	equ	RC4			;Prev,Retard,Minus	switch

;Rate count input
RCInp	equ	RC2 		;Rate count input minute hand sensor

;Switch status bits
 ;Current status of switch. 1=Pressed
#define	SetSt	SwitchSt, .0
#define	SelSt	SwitchSt, .1
#define	NxtSt	SwitchSt, .2
#define	PrvSt	SwitchSt, .3

;Switch pressed flag. 1 = Switch has beed pressed
;Manually clear flag after handling event
#define	SetPr	SwitchSt, .4
#define	SelPr	SwitchSt, .5
#define	NxtPr	SwitchSt, .6
#define	PrvPr	SwitchSt, .7

;Status bits for timer operation and configuration
;Where persistent settings are useful the bits are saved in EEPROM
;
;Timer status bits stored in TimerStat1
BeatOn		equ	0		;On = Beat input triggered
RTCTick		equ	1		;1= real time clock has ticked (1 second elapsed)
RTCEnab		equ	2		;1= Enable real time clock update.
StrikeMode	equ	3		;Strike count mode 1 = Enabled
BeatFlag	equ	4		;First, Second beat flag for calculating average beat
BeatValid	equ	5		;Wait until beat values have been updated (Valid)
BeatErrDir	equ	6		;Beat error sign (direction)
LogEnab		equ	7		;Data logging 1 = enabled

;Timer status bits stored in TimerStat2
;Restored from EEPROM
#define	CDOn	TimerStat2, .0	;Clock display 1=On
#define	TDOn	TimerStat2, .1	;Temperature display 1=On

#define LCDBL	TimerStat2, .3	;LCD Backlight. 1=on
#define	BeatPHM	TimerStat2, .4	;0= Display beats per hour, 1=Display beats per minute
#define	SecPB	TimerStat2, .5	;1= Display seconds per beat
#define BTStat	TimerStat2,	.6	;Bluetooth radio 1=on 

;Timer status bits stored in TimerStat3
#define	SecPBD	TimerStat3, .0	;1=Decimal point position for Seconds per beat, 0 = BPH, BPM 
#define RateC	TimerStat3, .1 	;Rate calculator mode 1 = Enabled
#define	RateTF	TimerStat3, .2	;Rate counter hourly trigger flag
#define Calib	TimerStat3,	.3	;Calibration mode. Log data for every beat.
#define	RptBf	TimerStat3, .4	;1=Button auto repeat
#define	PrvRA	TimerStat3, .5	;Previous, minus button repeat active
#define	NxtRA	TimerStat3, .6	;Next, plus button repeat active
#define	SetChg	TimerStat3,	.7	;Settings changed flag 1=unsaved changes

;IO bit definitions

BTOn	equ	RC5			;Port C RC5 Bluetooth radio control.
LED		equ	RC0			;Beat LED
LED2	equ	RC1			;Time LED
;----------------------------------------------------------------------------
;Variables
	
permdat		udata_acs	;Permanent data access ram
; save data for IRQ's
W_TEMP         RES        1      ; w register for context saving (ACCESS)
STATUS_TEMP    RES        1      ; status used for context saving 
BSR_TEMP       RES        1      ; bank select used for ISR context saving

;RS-232 Buffered RS-232 not currently used
;Flags	res 1		;byte to store indicator flags
;RxByteCount	res 1	;number of bytes received
;TxByteCount	res 1	;number of bytes to transmit
;TxPointer	res 1	;pointer to data in buffer
;TxBuffer res TX_BUF_LEN
;RxBuffer res RX_BUF_LEN
;ccount	res 1		;ASCII char counter

bc1 		res 1 			;LED blink count
SwitchSt	res	1			;Input switches press,debounce state flags
TimerStat1	res	1			;clock status/option bits

TimerStat2	res	1
global	TimerStat2

TimerStat3	res	1			;Clock status/option bits

RptTmP		res	1	;Button repeat timer Plus, Next button
RptTmM		res	1	;Button repeat timer Minus, Prev button

;ADC output data
ADCHI	res 1
ADCLO	res 1
MenuSel	res	1		;current selection for sub menu
SetSel	res	1		;Current menu setup option
TimeHH	res	1	;Time HH:MM:SS
TimeMM	res	1
TimeSS	res	1
SecCnt0	res	1	;Saves previous timer value for 1 second interval timer
SecCnt1	res	1
SecCnt2	res	1

SecDif0	res	1	;Time difference for 1 second timer test. Used in int don't re-use
SecDif1	res	1
SecDif2	res	1

BeatT1		res 1	;beat timer Time of last trigger
BeatT2	res 1
BeatT3	res 1
BeatT4	res 1
BeatI3	res	1		;Int timer adds 16 bits to hardware timer
BeatI4	res	1

sBeatI3	res	1		;seconds timer adds 16 bits to hardware timer


;Storage for even & odd beats
BeatA1	res	1
BeatA2	res	1
BeatA3	res	1
BeatA4	res	1
BeatB1	res	1
BeatB2	res	1
BeatB3	res	1
BeatB4	res	1

BeatAR1	res 1
BeatAR2	res 1
BeatAR3	res 1
BeatAR4	res 1

BeatBR1	res 1
BeatBR2	res 1
BeatBR3	res 1
BeatBR4	res 1

;Simple moving average IIR Filter
SAve1	res	1
SAve2	res	1
SAve3	res	1
SAve4	res	1

;Divide by 5

;*** Now other temps Need to rename

D5TMP0	res	1
D5TMP1	res	1
D5TMP2	res	1
D5TMP3	res	1



;Bin to ASCII number
;Takes hex number in DIVIDEND_HI:DIVIDEND_LO  Returns decimal in ;DIG1:DIG2:DIG3:DIG4:DIG5

DIVIDEND_HI	 res 1 ; high byte of 16 bit value
DIVIDEND_LO	 res 1 ; low byte of 16 bit value

;32 bits as ASCII number
DIG1	res 1		;High order ASCII digit
DIG2	res 1
DIG3	res 1
DIG4	res 1
DIG5	res 1

DIG6	res 1
DIG7	res 1
DIG8	res 1
DIG9	res 1
DIG10	res	1

;BinToBCD 10 digit packed BCD number
BCDL1	res 1		;Low order bcd digits
BCDH1	RES 1
BCDL2	res 1
BCDH2	res 1
BCDL3	res 1
;BCDH3	res	1

;32 bit binary unsigned number
BINL1	res 1
BINH1	RES 1
BINL2	res 1
BINH2	res 1

COUNT 	res 1		;Counter for BCD conversion

StrikeDly	res	1	; 
StrikeCnt	res	1	;Clock strike counter


BeatVCnt	res 1	;Beat valid counter
TrigDelay	res	1	;trigger delay value

;---------------------------------------------------
tempdat	access_ovr   ;Temporary data access ram

PmTmp	res	1		;PrtPMChgL  message:"Print + -" temp for cursor pos
Tcal	res 1		;Temperature sensor calibration
TCTmp1	res	1
TCTmp2	res	1

;TcalH	res	1


tempdat	access_ovr   ;Temporary data access ram


DATA_EE_DATA res 1	;EEPROM Write
DATA_EE_ADDR res 1
d0ms		res 1	;Time delay counters
d1ms		res	1
d2ms		res	1
SerSel		res	1	;Serial input char

MkUpper		res	1	;Make serial upper case

;-----------------------------------------------------
;Variables
;permanent data banked ram
bankdat	udata

;Rate counter
RCHourL 	res	1	;Number of hours elapsed
RCHourH 	res	1
RCBeatL		res	1	
RCBeatH		res	1	;Number of beats
RCBPHL		res	1	;Current beats per hour
RCBPHH		res	1

ADCLOA		res 1	;Temperature
ADCHIA		res	1
TempCal		res	1	;Temperature calibration
;TempCalH	res	1

;division routine
Divisor		res	 4 ;3 argb
Dividend	res	8  ;6 arga
Temp		res	8 ;6  rem
Temp2		res	4 ;1
BitCount	res	1 ; loop

;LCDbuf res .160 	;LCD Display output buffer

;------------------------------------------------------------------------------
; EEPROM INITIALIZATION
;
; The 18F14K22 has 256 bytes of non-volatile EEPROM starting at 0xF00000
; 
;------------------------------------------------------------------------------

DATAEE    CODE_pack    0xF00000 ; Starting address for EEPROM for 18F13K22
;Default values stored in EEPROM
    DE	.2				;Trigger delay value
	DE		b'01101011'		;ClockStatus2  Bit 3 LCD Backlight = on
;Rate units select Sec. per beat Bit 4=0,Bit 5=1 Bluetooth on bit 6=1
;Time display bit 0=1, Temperature display Bit 1=1
	DE	.0				;Default temperature calibration

;------------------------------------------------------------------------------
; RESET VECTOR
;------------------------------------------------------------------------------

RES_VECT  CODE    0x0000            ; processor reset vector
          goto    Main            ; go to beginning of program

;------------------------------------------------------------------------------
; HIGH PRIORITY INTERRUPT VECTOR
;------------------------------------------------------------------------------

ISRHV     CODE    0x0008

          ; Run the High Priority Interrupt Service Routine
          GOTO    HIGH_ISR             

;------------------------------------------------------------------------------
; LOW PRIORITY INTERRUPT VECTOR
;------------------------------------------------------------------------------

ISRLV     CODE    0x0018
          
          ; Run the Low Priority Interrupt Service Routine
          GOTO    LOW_ISR             

;------------------------------------------------------------------------------
; HIGH PRIORITY INTERRUPT SERVICE ROUTINE
;------------------------------------------------------------------------------
; Used for main timing function Extends TIMER1 to 32 bits
; Used for clock beat input. Capture timer value when INT0 active
;------------------------------------------------------------------------------

ISRH      CODE                        ; let linker place high ISR routine

HIGH_ISR  
		btfss	PIR1,TMR1IF			;Timer 1 int	
		bra		Int0Do 			;Not the timer. Handle INT0
		infsnz	BeatI3				;Yes, roll over timer to higher bytes
		incf	BeatI4
		bcf		PIR1,TMR1IF			;Clear timer int.


;!!!!!!!!!!!! need to fix !!!!!!!!!!!!!


;Check for INT0 during timer int, Handle it immediately for less jitter.
;'		btfss	INTCON,INT0IF		;Port a INT0 ? 
		retfie	FAST
;'		movff	TMR1L,BeatT1		;Save time when INT0 triggered
;'		movff	TMR1H,BeatT2
;'		movff	BeatI3,BeatT3		;save higher 2 bytes
;'		movff	BeatI4,BeatT4
;'		bra		RSkp				;Disable INT0, set flags & return.
;'		retfie	FAST ;remove when uncomment




;		INT0 clock beat trigger. Save current timer value.
Int0Do:
		movff	TMR1L,BeatT1		;Save time when INT0 triggered
		movff	TMR1H,BeatT2
		btfss	PIR1,TMR1IF			;Check for timer rollover during copy
									;Timer rolled if int flag set
		bra		NoRoll				;No timer rollover

		movff	TMR1L,BeatT1		;Save time again
		movff	TMR1H,BeatT2
;Subtract from time to account for extra code executed for timer roll	
		movlw	0x03				
		subwf	BeatT1,F				
		movff	BeatI3,BeatT3		;save higher 2 bytes
		movff	BeatI4,BeatT4
		infsnz	BeatT3				;Manually roll over higher bytes
		incf	BeatT4

		bra		RSkp
NoRoll	movff	BeatI3,BeatT3		;No Roll just save higher 2 bytes
		movff	BeatI4,BeatT4
	
RSkp

;Disable INT0, set flags & return. debounce trigger delay and enable runs in main code.
		bcf		INTCON,INT0IE		;disable INT0
		bcf		INTCON,INT0IF		; clear Port a INT0  flag



		bsf		TimerStat1,BeatOn	;set comparator trip flag
       RETFIE  FAST


;------------------------------------------------------------------------------
; LOW PRIORITY INTERRUPT SERVICE ROUTINE
;------------------------------------------------------------------------------

ISRL      CODE                        ; let linker place low ISR routine

LOW_ISR
          ; Context Saving for Low ISR
          MOVWF   W_TEMP              ; save W register
          MOVFF   STATUS, STATUS_TEMP ; save status register
          MOVFF   BSR, BSR_TEMP       ; save bankselect register
		btfss	TimerStat1,RTCEnab		;Is clock update enabled?
		bra		Buttons					;No. Skip clock update, just scan pushbuttons.
		incf	sBeatI3
		movf	SecCnt0,W					;Interval since last tick in SecCnt
		subwf	TMR0L,W
		movwf	SecDif0
		movf	SecCnt1,W
		subwfb	TMR0H,W
		movwf	SecDif1	
		movf	SecCnt2,W
		subwfb	sBeatI3,W
		movwf	SecDif2	


; 1 second count values for various prescale settings
;16:1=0x098968
;08:1=0x1312d0
;04:1=0x2625a0
;01:1=0x989680


		movlw	0xd0 				;Subtract 10E6/prescale see if 1 second elapsed
		subwf	SecDif0,W
		movlw	0x12 
		subwfb	SecDif1,W
		movlw	0x13 
		subwfb	SecDif2,w
		btfsc	STATUS,C			;Is elapsed greater than 1 sec?
		bra		Buttons				;No, Skip clock update.

;Update the clock, set clock tick flag and add another second to counter
		call	IncTime				;Update the clock
		bsf		TimerStat1,RTCTick	;Set flag clock has ticked. Cleared in main loop
		call	AddClkSec			;Add another 1 second to temp 10E6/prescale. Change prescale value also in this sub.

;		btg		LATC,LED2			;clock test blink led

Buttons:
;Check button presses and debounce
;Debounce time is Int timer overflow time
;xxxPr = 1 = button has been pressed clear flag manually to ack the press
;xxxSt = 1 = button is currrently pressed, current status of the button


;"Set" Button check
		btfsc	PORTA,SetSw	
		bra		SetBRC
		btfsc	SetSt
		bra		SetBF
		bsf		SetPr
		bsf		SetSt
		bra		SetBF
SetBRC:
		btfss	SetSt
		bra		SetBF
		bcf		SetSt
SetBF:





;"Select" Button check
		btfsc	PORTA,SelSw	
		bra		SelBRC
		btfsc	SelSt
		bra		SelBF
		bsf		SelPr
		bsf		SelSt
		bra		SelBF
SelBRC:
		btfss	SelSt
		bra		SelBF
		bcf		SelSt
SelBF:


;"Previous, Minus" Button check
		btfsc	PORTC,PrvSw		;Is button currently pressed?
		bra		PrvBRC			;No
		btfsc	PrvSt			;Yes, Was it pressed before?
		bra		PrvNBF			;Yes, don't set button press flags
		bsf		PrvPr			;Set Button has been pressed & not yet handled
		bsf		PrvSt			;Button has already been pressed
PrvNBF:
		btfss	RptBf		;Auto repeat on?
		bra		RptNoP		;no	done

		btfsc	PrvRA		;Repeat delay expired
		bra		RptDoP		;Yes
		movlw	RptTv		;Repeat delay setting
		cpfslt	RptTmP		;Repeat time < w?
		bra		RptDoP		
		incf	RptTmP		;Auto repeat start deley
		bra		RptNoP
RptDoP:	bcf		PrvSt		;Set button is not pressed force repeat
		bsf		PrvRA		;Repeat delay expired

		bra		RptNoP		;DONE

PrvBRC:							;Button is not currently pressed

		bcf		PrvSt			;Set button current status as released
		clrf	RptTmP		;Reset delay
		bcf		PrvRA		;Repeat not active


		
RptNoP:


;"Next, Plus" Button check


		btfsc	PORTC,NxtSw		;Is button currently pressed?
		bra		NxtBRC			;No
		btfsc	NxtSt			;Yes, Was it pressed before?
		bra		NxtNBF			;Yes, don't set button press flags
		bsf		NxtPr			;Set Button has been pressed & not yet handled
		bsf		NxtSt			;Button has already been pressed
NxtNBF:
		btfss	RptBf		;Auto repeat on?
		bra		RptNoM		;no	done

		btfsc	NxtRA		;Repeat delay expired
		bra		RptDoM		;Yes
		movlw	RptTv		;Repeat delay setting
		cpfslt	RptTmM		;Repeat time < w?
		bra		RptDoM		
		incf	RptTmM		;Auto repeat start deley
		bra		RptNoM
RptDoM:	bcf		NxtSt		;Set button is not pressed force repeat
		bsf		NxtRA		;Repeat delay expired

		bra		RptNoM		;DONE

NxtBRC:							;Button is not currently pressed

		bcf		NxtSt			;Set button current status as released
		clrf	RptTmM		;Reset delay
		bcf		NxtRA		;Repeat not active


		
RptNoM:









RetLo:	bcf		INTCON,TMR0IF			;Clear timer0 int flag
          ; Context Saving for Low ISR
		MOVFF   BSR_TEMP, BSR       ; restore bankselect register
		MOVF    W_TEMP, W           ; restore W register
		MOVFF   STATUS_TEMP, STATUS ; restore status register
		RETFIE

;------------------------------------------------------------
;Sub used in Low isr and clock set
; 1 second count values for various prescale settings
;16:1=0x098968
;08:1=0x1312d0
;04:1=0x2625a0
;01:1=0x989680


AddClkSec:	bcf		STATUS,C
		movlw	0xd0 				;Add another 1 second to temp 10E6/prescale
		addwfc	SecCnt0,F
		movlw	0x12 
		addwfc	SecCnt1,F
		movlw	0x13 
		addwfc	SecCnt2,F
		return
;------------------------------------------------------------------------------
; MAIN PROGRAM
;------------------------------------------------------------------------------

MAIN_PROG CODE                        ; let linker place main program

Main:
	
		clrf	BSR				;Boot loader changes BSR
		clrf	TBLPTRU

		bcf		TRISC,LED		;LED  set as output
		bsf		LATC,LED		;LED on
		bcf		TRISC,LED2		;LED  set as output
		bcf		LATC,LED2		;LED on
		


;MPU Clock init.
;		movlw	b'01011010'	;4MHz internal clock
		movlw	b'01011000'	;External crystal
		movwf	OSCCON		;system clock	  
		bsf		OSCTUNE,PLLEN

;I/O port init


		bcf		CM1CON0,7		;turn off comparators
		bcf		CM2CON0,7	 	;
		bcf		ADCON0,0		;A2D off
		clrf	ANSEL			;digital i/o
		clrf	ANSELH			;digital i/o

		setf	TRISA			;porta input
		bcf		INTCON2,RABPU	;Enable pull ups
		setf	WPUA			;Pull ups on for port a
		setf	TRISB			;portb input
		setf	TRISC			;portc input

;Bluetooth serial 
		bcf		TRISC,BTOn		;BTOn  set as output

;Interrupt config
		bsf		RCON,IPEN			;Enable interrupt priority
		clrf	INTCON
		clrf	INTCON2

		bsf		INTCON,GIEH			;Enable all unmasked  high irq's
		bsf		INTCON,GIEL			;Enable all unmasked  low irq's



;############################################################
;Timer 0 
;Timer used for real time clock and button scan/debounce

		clrf	T0CON					;Timer off
		bcf		INTCON,TMR0IF			;Clear int flag
		bcf		INTCON2,TMR0IP			;Timer 0 to low priority
		movlw	0x80
		movwf	TMR0H
		clrf 	TMR0L					;Reset timer
		clrf	sBeatI3

		clrf	SecCnt0					;Clear seconds counter
		clrf	SecCnt1
		clrf	SecCnt2

		bsf		INTCON,TMR0IE			;enable TMR0 int

;Timer 1
;Timer used for clock beat interval timer
;Timer on,16 bit,int clock,rise edge,prescale on,prescale=08:1

		movlw	b'10010010'
		movwf	T0CON					;Timer on

		CLRF 	TMR1H
		clrf 	TMR1L			;Reset timer

		clrf	BeatI3
		clrf	BeatI4

		MOVLW	 b'10000101' ; Configure for internal clock,
		MOVWF	 T1CON ; Asynchronous operation, external oscillator
		bsf		IPR1,TMR1IP			;Timer 1 to high priority
		bsf		PIE1,TMR1IE		;enable int



;Port A INT0 config
		bcf		INTCON,INT0IF		;Clear RA0/INT0 int flag
		bsf		INTCON2,INTEDG0		;RA0/INT0 Select rising edge trigger
		clrf	IOCA		;Disable int on change
		bsf		INTCON,INT0IE		;Enable INT0


;Test code make sure prog is runnung
		bcf		TRISC,LED		;LED  set as output
		bsf		LATC,LED		;LED on
		bcf		TRISC,LED2		;LED  set as output
		bcf		LATC,LED2		;LED on


;#####################################################

;Initial values
		movlw	.01				;Initial time value or clock HH:MM:SS
		movwf	TimeHH
		movlw	.01
		movwf	TimeMM
		movlw	.80
		movwf	TimeSS

;!!!!!!!!!!!!!!!!!!!!!!!
;Defaults also set in EEPROM



		clrf	TimerStat1	;Init clock status flags to zero
		clrf	TimerStat3

		call	ReadConfig			;Restore settings from EEPROM
		bsf		LATC,BTOn		;BTOn = 1 (Bluetooth on)
		btfss	BTStat			;Restore bluetooth radio state
		bcf		LATC,BTOn

;Restore trigger delay and LCD Backlight status

		bcf		RptBf		;Button auto repeat off
		bcf		PrvRA		;Previous, minus button repeat off
		bcf		NxtRA		;Next, plus button repeat off

		call	BeatNotV	;Clear valid beat counter and flag.


;
;Pushbutton switches init
		clrf	SwitchSt	;Init button press, debounce value
		clrf	RptTmM		;Button repeat timer
		clrf	RptTmP		;Button repeat timer
		bcf		RptBf		;Button repeat off
		bcf		PrvRA		;Previous, minus button repeat not active
		bcf		NxtRA		;Next, plus button repeat not active

;Timer start values
		bsf		TimerStat1,RTCEnab		;Turn on real time clock update.
		bcf		TimerStat1,LogEnab		;Logging off
		bcf		TimerStat1,BeatFlag		;Start on same beat


		call 	SetupSerial	;Init serial port & baud rate

		call	LCDINIT		; Initialize LCD Display
		call 	LCDTxtUp	;Update LCD text strings


Mainl2p:

;-----------------------------------------------------------------------
;real time clock display update

			btfss	CDOn				;Display the clock?
			bra		NoCD				;No                        
			btfss	TimerStat1,RTCTick	;Time to update the clock?
			bra		NoRTCUp				;No, skip
			movlw	LCDL4P+.0			;LCD addr for RTC clock display       
			call	TimeToLCD 			;Yes, update RTC time display on LCD
NoCD:

;-----------------------------------------------------------------------
;Temperature display update.

			btfss	TimerStat1,RTCTick	;Time to update the temp?
			bra		NoTD				;No, skip


			btfss	TDOn				;Display temperature?
			bra		NoTD				;No
			call	ReadADC				;Get value from temp. sensor
;										;10 bits to ADCLO,ADCHI
			call	TempCalAdj				;Appy calibration to average temp value ADCLO,HI
										;Result in DIVIDEND_LO,HI
			movlw	LCDL4P+.9			;LCD addr for temperature display 
			call	TempToLCD			;Display temperature on display.

NoTD:

;--------------
;Strike counter timer. Runs always. Only used when strike counter enabled
			incf	StrikeDly			;Count seconds for strike end test

			bcf		TimerStat1,RTCTick	;Reset RTC update flag
NoRTCUp:


;-----------------------------------------------------------------------



;Check serial in and buttons for commands

;Check serial input
			movlw 	.0					;0 if no char received
			call	ReceiveSerUcase		;Check serial input
			movwf	SerSel				;save ser input
			xorlw	"S"  				;compare with S Set		
			bnz		NoMuL				;Not S
			call	SetupMenu
NoMuL:

;----------------------------------------------------------------------
;Check pushbuttons
;----------------------------------------------------------------------

			btfsc	SetPr 			;Check mode setup switch pressed active hi
			call	SetupMenu			;go to setup

;Quick access button commands

;Button toggle of BPM,BPH (Select button)

			btfss	SelPr			;Select pressed?
			bra		NoSelPr			;No,Skip
			btfsc	SecPB
			goto	bhm
			btfsc	BeatPHM
			bra		bhspb
			bsf		BeatPHM
			bra		bhxit
bhspb:		bsf		SecPB
			bra		bhxit
bhm:
			bcf		BeatPHM
			bcf		SecPB

bhxit:		bcf		SelPr			;Clear button
			call	LCDTxtUpNC			;Update LCD don't clear screen
NoSelPr:

;Button toggle of backlight (Prv-Minus)

			btfss	PrvPr			;prv-minus pressed?
			bra		NoPrvPr			;No,Skip
			btg		LCDBL
			movlw .0
			call	LCDADD			;Do lcd update to set backlight
			bcf		PrvPr
	
NoPrvPr:
;Button toggle of log (Next-Plus)
			btfss	NxtPr			;Next-Plus pressed?
			bra		QASerial			;No,Skip
			btg		TimerStat1,LogEnab
			call	LCDCLR				;Clear old data
			call	LCDTxtUp			;Restore LCD text
			call	BeatNotV			;Clear beat counter and flag. Beat data is not valid.

			bcf		NxtPr

QASerial:
;Quick access serial commands


			movf	SerSel,W
			xorlw	"I" 				;compare with I Display current settings		
			bnz		CalibTg
			call	SerStats




CalibTg:	movf	SerSel,W
			xorlw	"C" 				;compare with C Calibration mode		
			bnz		NoSerial
			btg 	Calib



NoSerial:

;--------------------------------------------------------------
;Strike count mode
;Strike display if enabled, strike count >0 and timer expired
		tstfsz	StrikeCnt				;Skip if no strikes counted
		btfss	TimerStat1,StrikeMode	;Strike count mode enabled?
		bra		NoStrikeD			;No
				
		movlw	.3					;Seconds to wait for striking to end
		cpfsgt	StrikeDly			;Has delay expired?
		bra		NoStrikeD			;No
;Display strike info, reset for next strike


		movff	StrikeCnt,BINL1	;Display number of strikes
		clrf	BINH1
		clrf	BINL2
		clrf	BINH2
		call	DWordToBCD		;Convert to bcd
		call	ByteToSer		;Send to serial port
		movlw	LCDL3P+.1 ;0x15			;LCD line 3 + 2 col
		call	ByteToLCD
		movlw	low ModeSS1	;"Strike(s)."
		movwf	TBLPTRL
		movlw	high ModeSS1	
		movwf	TBLPTRH
		call	prtstrs			;print string serial

	call	SerPrtCRLF	;Send CRLF (new line)

		clrf	StrikeCnt			;Reset counter, wait for next strike
		
NoStrikeD:
;--------------------------------------------------------------------
;Rate count mode
;Hour trigger check
		btfss	RateC	;Is rate counter enabled?
		bra		NoRC0	;No

		btfss	RateTF			;Are we waiting for RCInp = 1? RateTF = 1 = waiting
		bra		RCBW			;no


		btfss	PORTC,RCInp		;Has rcimp gone high?
		bra		NoRC0			;No

		bcf		RateTF			;Yes, reset flag wait for RCInp = 0

		;May need to debounce

RCBW:	btfsc	PORTC,RCInp		;Test for hour hand trigger. 0=triggered
		bra		NoRC0


		infsnz	RCHourL	;Count hours 16 bit
		incf	RCHourH

		movff	RCHourL,BINL1	;Display hours
		movff	RCHourH,BINH1
		clrf	BINL2
		clrf	BINH2

		bsf		SecPBD			;Select seconds per beat display
		movlw	LCDL2P + 5			;LCD line 2 + 5
		call	DWordToLCD

;Rate counter function
		bsf		RateTF			;Set flag = 1 waiting for port to go high
NoRC0:
;--------------------------------------------------------------------
;Test for clock beat. Loop in menu check if no beat
		btfss	TimerStat1,BeatOn			
		bra		Mainl2p				;Not triggered, check again (loop)


;LCD and LED beat status on		
		call	BeatOnLCD
		bsf		LATC,LED				;LED on
		movlw 	.1
		call	adj_del_ms

;---------------------------------------------------------------
;Rate count mode

		btfss	RateC	;Is rate counter enabled?
		bra		NoRC1	;No

		infsnz	RCBeatL		;Count beats 16 bit
		incf	RCBeatH
		movff	RCBeatL,BINL1	;Display beats
		movff	RCBeatH,BINH1
		clrf	BINL2
		clrf	BINH2

		bsf		SecPBD			;Select seconds per beat display
		movlw	LCDL1P + 5			;LCD line 1 + 5
		call	DWordToLCD

		goto	BtSkip			;Skip all but beat reset





NoRC1:
;--------------------------------------------------------------
;Strike count mode
;Count each beat as 1 strike

		btfss	TimerStat1,StrikeMode
		bra		NoStrikeC


		tstfsz	StrikeCnt		;Skip time print after first strike
		bra		NoStrTm
		movlw	low ModeSS2	;"Strike time: "
		movwf	TBLPTRL
		movlw	high ModeSS2	
		movwf	TBLPTRH
		call	prtstrs			;print string serial
		movlw 	LCDL2P + 0x0c		;Second line lcd
		call 	TimeToLCD		;Print strike start time LCD
		call	TimeToSer		;Print strike start time serial
		call	SerPrtSpa		;print space
NoStrTm:

		incf	StrikeCnt		;Count strike




		movff	StrikeCnt,BINL1	;Display number of strikes
		clrf	BINH1
		clrf	BINL2
		clrf	BINH2
		call	DWordToBCD		;Convert to bcd
;		call	ByteToSer		;Send to serial port
		movlw	LCDL3P+.1 ;0x15			;LCD line 3 + 2 col
		call	ByteToLCD




		clrf	StrikeDly		;Reset timer
		goto	BtSkip			;Skip all but beat reset
NoStrikeC:

;Even / odd beat check
		btfss	TimerStat1,BeatFlag
		goto	BeatBn


		movlw	.2
		call	adj_del_ms
;Beat A


	movff	BeatT1,BeatAR1		;Save Beat A time
	movff	BeatT2,BeatAR2
	movff	BeatT3,BeatAR3
	movff	BeatT4,BeatAR4


	movf	BeatBR1,W			;Subtract old val from new for current beat time
	subwf	BeatT1,W
	movwf	BeatA1

	movf	BeatBR2,W
	subwfb	BeatT2,W
	movwf	BeatA2	

	movf	BeatBR3,W
	subwfb	BeatT3,W
	movwf	BeatA3	

	movf	BeatBR4,W
	subwfb	BeatT4,W
	movwf	BeatA4	

	goto 	BtSSk


BeatBn:


	movff	BeatT1,BeatBR1		;Save Beat B time
	movff	BeatT2,BeatBR2
	movff	BeatT3,BeatBR3
	movff	BeatT4,BeatBR4


	movf	BeatAR1,W
	subwf	BeatT1,W
	movwf	BeatB1

	movf	BeatAR2,W
	subwfb	BeatT2,W
	movwf	BeatB2	

	movf	BeatAR3,W
	subwfb	BeatT3,W
	movwf	BeatB3	

	movf	BeatAR4,W
	subwfb	BeatT4,W
	movwf	BeatB4	






BtSSk:

;Calibration mode. 1 = log every beat.

		btfsc	Calib		;Calibration?
		bra		CalMode0	;Yes, calibrating display every beat
		btfsc	TimerStat1,BeatFlag	;Output only every 2 beats
		goto	BtNv

CalMode0:


	movff	BeatB1,D5TMP0	;BeatB to temp for addition
	movff	BeatB2,D5TMP1
	movff	BeatB3,D5TMP2
	movff	BeatB4,D5TMP3


;Add beats together result in D5TMP3
	movf	BeatA1,w ; add byte 0 (LSB)
	addwf	D5TMP0,f
	movf	BeatA2,w ; add byte 1
	btfsc	STATUS,C
	incfsz	BeatA2,w
	addwf 	D5TMP1,f
	movf 	BeatA3,w ; add byte 2
	btfsc 	STATUS,C
	incfsz 	BeatA3,w
	addwf 	D5TMP2,f
	movf 	BeatA4,w ; add byte 3 (MSB)
	btfsc 	STATUS,C
	incfsz 	BeatA4,w
	addwf 	D5TMP3,f

;Divide by 2 for average

	bcf		STATUS,C
	rrcf	D5TMP3
	rrcf	D5TMP2
	rrcf	D5TMP1
	rrcf	D5TMP0



;	goto	SkpBPHM
;-----------------------------------------------------------
;SPB,BPM,BPH calc
;##########################################################
;Print beats per hour



;36000000000 (3600 seconds) / 256 = 0x 08 61 c4 68
;300000000 (30 seconds) /256 = 0x 00 11 e1 a3
;3600000000000 (360000) /256 = 0x 03 46 30 b8 a0
;3600000000000 			     = 0x 03 46 30 b8 a0 00
;36000000000000 (3600000) /256 = 0x 20 bd e7 36 40
;36000000000000 (3600000)    = 0x 20 bd e7 36 40 00
;60000000000			  	 = 0x 0d f8 47 58 00
;60000000000  (6000) / 256   = 0x 0d f8 47 58
;600000000000 (60000)/ 256   = 0x 8b b2 c9 70
;600000000000 (60000)        = 0x 8b b2 c9 70 00

	btfsc	SecPB		;1= Seconds per beat
	goto	SkpBPHM		;Skip calculations just use Seconds per beat.
	btfsc	BeatPHM		;0=Beats per hourH,1=Beats per minute
	goto	DoBPM

;Constant 3600/Sec per beat for Beats per hour
;constant is 36000000000000
	clrf	Dividend+0
	clrf	Dividend+1
	movlw	0x20
	movwf	Dividend+2
	movlw	0xbd
	movwf	Dividend+3
	movlw	0xe7
	movwf	Dividend+4
	movlw	0x36
	movwf	Dividend+5
	movlw	0x40
	movwf	Dividend+6
	movlw	0x00
	movwf	Dividend+7

	goto	BPMS
;Constant 60/Sec per beat for Beats per minute
;Constant is 60000000000
DoBPM:
	clrf	Dividend+0
	clrf	Dividend+1
	clrf	Dividend+2
;	clrf	Dividend+3

	movlw	0x8b
	movwf	Dividend+3
	movlw	0xb2
	movwf	Dividend+4
	movlw	0xc9
	movwf	Dividend+5
	movlw	0x70
	movwf	Dividend+6
	movlw	0x00
	movwf	Dividend+7

BPMS:

;****
;Drop low byte (D5TMP0) to divide by 256

	movff	D5TMP0,Divisor+3	;Big endian to little endian beat data to divisor for BPH calculation
	movff	D5TMP1,Divisor+2
	movff	D5TMP2,Divisor+1
	movff	D5TMP3,Divisor+0



;Little endian data. Dividend 48 bits divisor 24 bits
;	call	DIVIDE_48by24 

;Little endian. Divident 64 bits divisor 32 bits
	call	Divide64x32u

;	mkdiv Divide, Dividend, Divisor, Temp, BitCount, d'64', d'32', UNSIGNED 

;Dividend has result

;Save converted data back to BeatT. BeatT is allways Sec per beat not BPM or BPH

		movff	Dividend+4,D5TMP3
		movff	Dividend+5,D5TMP2
		movff	Dividend+6,D5TMP1
		movff	Dividend+7,D5TMP0


SkpBPHM:	;Skip calculatinos just use seconds per beat
;------------------------------------------------------------




;Calculate simple running average (IIR filter)
;Add new value to average value
	movf	D5TMP0,W
	addwf	SAve1,F
	movf	D5TMP1,W
	addwfc	SAve2,F	
	movf	D5TMP2,W
	addwfc	SAve3,F	
	movf	D5TMP3,W
	addwfc	SAve4,F	

;Divide by 2 for running average

	bcf		STATUS,C
	rrcf	SAve4
	rrcf	SAve3
	rrcf	SAve2
	rrcf	SAve1

			btfss	TimerStat1,LogEnab		;Wait for log enable
			bra		BtV0					;skip if log off
			btfsc	TimerStat1,BeatValid		;Delay for valid data?
			bra		BtV0 ;Beat now valid. Don't load default
;			call 	BeatNotV

;Default value for running average to beat time
;starts log with valid ave data
			movff	D5TMP0,SAve1
			movff	D5TMP1,SAve2
			movff	D5TMP2,SAve3
			movff	D5TMP3,SAve4
BtV0:

			btfsc	Calib	;Calibration mode. log every beat.
			bra		CalMode1

;Average beat from temp to DWordToLCD input

	movff	D5TMP0,BINL1
	movff	D5TMP1,BINH1
	movff	D5TMP2,BINL2
	movff	D5TMP3,BINH2



	bra		BeatATmp	;Don't do calibration
CalMode1:				;Show every beat
;***** Calibration for testing ****
;***** print both beats instead of average rate ****
;Even / odd beat check
		btfss	TimerStat1,BeatFlag
		goto	BeatBtmp
;Print beat A
	movff	BeatA1,BINL1
	movff	BeatA2,BINH1
	movff	BeatA3,BINL2
	movff	BeatA4,BINH2
	goto 	BeatATmp
;Print beat B
BeatBtmp:
	movff	BeatB1,BINL1
	movff	BeatB2,BINH1
	movff	BeatB3,BINL2
	movff	BeatB4,BINH2

BeatATmp:




; Log functions wait for log enabled and valid beat data

			btfss	TimerStat1,LogEnab		;Wait for log enable
			bra		BeatGood
			btfsc	TimerStat1,BeatValid		;Delay for valid data?
			bra		BeatGood

			decfsz	BeatVCnt
			goto	BtNv	;beats not valid	


;Print log header once when log enable and beat valid


		movlw	low CSVHeader	;Data log header string address lo
		movwf	TBLPTRL
		movlw	high CSVHeader
		movwf	TBLPTRH
		call	prtstrs			;print string



			bsf	TimerStat1,BeatValid

BeatGood:








;Print rate, 2 beat average time
	movlw LCDL1P+.9				;LCD Address

	bsf		SecPBD			;Select seconds per beat display format
	btfss	SecPB
	bcf		SecPBD			;Select Beats per hour or minute display format

	call	DWordToLCD
;	call	SerPrtCSV		;CSV comma delimiter
	btfss	TimerStat1,LogEnab	;Output serial only if log enabled
	bra		NoLg0
	call	DwordToSer	;Send to serial port
	call	SerPrtCSV
NoLg0

;IIR average from SAve to DWordToLCD input

	movff	SAve1,BINL1
	movff	SAve2,BINH1
	movff	SAve3,BINL2
	movff	SAve4,BINH2
	movlw	LCDL3P+.9				;LCD Address

	bsf		SecPBD			;Select seconds per beat display format
	btfss	SecPB
	bcf		SecPBD			;Select Beats per hour or minute display format


	call	DWordToLCD
	btfsc	TimerStat1,LogEnab	;Output serial only if log enabled
	call	DwordToSer	;Send to serial port

;Calculate beat error


		movff	BeatB1,D5TMP0
		movff	BeatB2,D5TMP1
		movff	BeatB3,D5TMP2
		movff	BeatB4,D5TMP3

;Subtract beats find beat error 

		bsf		TimerStat1,BeatErrDir	;Beat error direction (sign)
		movf	BeatA1,W
		subwf	D5TMP0,F
		movf	BeatA2,W
		subwfb	D5TMP1,F
		movf	BeatA3,W
		subwfb	D5TMP2,F
		movf	BeatA4,W
		subwfb	D5TMP3,F
		btfsc	STATUS,C 
		bra		SubOK		;Subtracted smaller from larger
;Wrong way, subtract again in opposite order

		bcf		TimerStat1,BeatErrDir	;Beat error direction (sign)
		movff	BeatB1,D5TMP0
		movff	BeatB2,D5TMP1
		movff	BeatB3,D5TMP2
		movff	BeatB4,D5TMP3

		bsf		STATUS,C
		movf	BeatA1,W
		subfwb	D5TMP0,F
		movf	BeatA2,W
		subfwb	D5TMP1,F
		movf	BeatA3,W
		subfwb	D5TMP2,F
		movf	BeatA4,W
		subfwb	D5TMP3,F
SubOK:
	movff	D5TMP0,BINL1
	movff	D5TMP1,BINH1
	movff	D5TMP2,BINL2
	movff	D5TMP3,BINH2

	btfsc	TimerStat1,LogEnab	;Output serial only if log enabled
	call	SerPrtCSV		;CSV comma delimiter

;Print beat error



	movlw LCDL2P+.6 ;0x46				;LCD Address
	call LCDADD
	movlw	"+"
	btfss	TimerStat1,BeatErrDir
	movlw	"-"
	call	LCDSEND		;Send direction (sign) of beat error (LCD)

	movlw	"+"
	btfss	TimerStat1,BeatErrDir
	movlw	"-"

	btfsc	TimerStat1,LogEnab	;Output serial only if log enabled
	call	TransmitCharW	;Send serial




	movlw LCDL2P+.9				;LCD Address


	bsf		SecPBD			;Select seconds per beat display format


	call	DWordToLCD




	btfss	TimerStat1,LogEnab	;Output serial only if log enabled
	bra		NoLg1				;Log disabled, Skip all logging.

	call	DwordToSer	;Send to serial port


;##########################################################
;Calibration mode
	btfss	Calib			;Calibration mode enabled?
	bra		NoCb0			;No, Skip calib data.

;Print raw counter value

	call	SerPrtCSV		;CSV comma delimiter
	movff	BeatT1,BINL1		;Convert to BCD
	movff	BeatT2,BINH1
	movff	BeatT3,BINL2
	movff	BeatT4,BINH2

	call	DWordToBCD	
	call	DwordToSer	;Send to serial port
	BRA		SEnd		;Exit with CRLF


NoCb0:

;Print current temperature
	call	SerPrtCSV		;CSV comma delimiter

			call	TempCalAdj				;Appy calibration to average temp value ADCLO,HI
										;Result in DIVIDEND_LO,HI

	call	TempToSer


SEnd:	call	SerPrtCRLF	;Send CRLF (new line) to CSV file

NoLg1:	;Log disabled

BtNv:	;Skip output til valid



	btg		TimerStat1,BeatFlag	;Flip to other beat


BtSkip:	;Skip all calcs and output for strike count mode

;Enable INT0 after trigger delay time
;delay plus 1 pass through main code

		movf	TrigDelay,W			;Get trigger delay time
		call	adj_del_ms			;Delay for W * 10 ms

		bcf	LATC,LED				;LED off
		bcf		TimerStat1,BeatOn	;Reset flag wait for next pulse
;LCD beat status off		

		Call	BeatOffLCD	;Beat indicator off


;Now accept another trigger pulse
		bcf		INTCON,INT0IF		; clear Port a INT0  flag
		bsf		INTCON,INT0IE		;enable INT0
	goto Mainl2p






;-------------------------------------------------------------------------
;setup menu
;Check buttons and serial for menu selections

SetupMenu:

;LCD menu
			call	LCDCLR			;Clear LCD display


			bcf		SetPr			;Clear button pressed flags
			bcf		SelPr
			bcf		NxtPr
			bcf		PrvPr
; select options	


			clrf	MenuSel				;Default Select option
SetI:		clrf 	SetSel				;Default setup option
			call	UpLCD				;Update LCD for current setting

SetNext:	movlw 	.0					;0 if no char received
			call	ReceiveSerUcase		;Check serial input
			movwf	SerSel				;save ser input
			xorlw	"S"  				;compare with S Set		
			bnz		NoMnuL				;Not S
			bra		SSer				;Serial S pressed
NoMnuL:		movf	SerSel,w			;Get last input char

			xorlw	"L"					;compare with L seLect
			bnz		NoMnuS				;Not L
			goto	DoSel				;Serial L pressed do select menu	

NoMnuS: 	btfss	SetPr				;Set button pressed?

			bra		NoSet				;No. Skip
SSer:		incf	SetSel,f			;Next set option
			bcf		SetPr				;Clear set button pressed flag
;**********************************************
;***    Set number of selections in set menu (0-n)
			movlw	.12				;13 selections
			cpfsgt	SetSel			;Past last option?
			goto	SelCk			;Next option. Update display. ;SetNext
			goto	SetI			;Past last. Cycle through the options again	
SelCk:

			call	UpLCD				;Update LCD for current setting


NoSet:		btfsc	SelPr	;Select button pressed?		
			goto	DoSel			;Do the current selection
			bra		SetNext
			goto	SetI			;Cycle through the options again	

;------------------------------------------------------------------
;Jump table for menu selections

DoSel:
			bcf		SelPr				;Clear select button pressed flag
			movf	SetSel,w		;Get current selection
			call    Case            ; w = index/case [ 0..2 ]
			goto    LogSel       	; ModeMnu 	0 Data log
			goto    TrigDly       	; 	    	1 Trigger delay
			goto    TimeSet     	;			2 Set time
			goto	StrikeC			;			3 Strike counter
			GOTO	BLSel			;			4 LCD Backlight
			goto	RCSel			;			5 Rate counter
			goto	CalTemp			;			6 Calibrate temperature
			goto	RateSet			;			7 Rate display select SPB,BPM,BPH
			goto	BTState			;			8 Bluetooth serial Enable/Disable
			goto	ClkSel			;			9 Clock display On/Off
			goto	TempSel			;			10 Temperature display On/Off

			goto    SaveSet	        ; 			18 Save settings to flash
			goto	SetDone			;			19 Exit


;
 ;******************************************************************
 ;
 ;  Case Function (modifies return address by index W*4)
 ;
 ;  Entry: W = Index 0..63, jump instruction table must
 ;         immediately follow the calling instruction
 ;
Case:
          rlncf   WREG,f          ;
          rlncf   WREG,f          ;
          addwf   TOSL,f          ;
          movlw   h'00'           ;
          addwfc  TOSH,f          ;
 ;         addwfc  TOSU,f          ; for > 64-kbyte memory
          return                  ;
 ;


;############################################
; Update LCD and Serial with current set selection
UpLCD:

;Serial menu first line
		movlw	low SelMnuS		;mode Select menu
		movwf	TBLPTRL
		movlw	high SelMnuS
		movwf	TBLPTRH
		call	prtstrs			;print string serial




		movlw	0x00			;First line  LCD text                           
		call	LCDADD	
		movlw	low SelMnu		;"Press SET for next option
		movwf	TBLPTRL
		movlw	high SelMnu	
		movwf	TBLPTRH
		call	prtstrl			;print string LCD

		movlw	0x40			;2nd line  LCD text                           
		call	LCDADD	

		movlw	.0
		cpfseq	SetSel
		bra		s1				;Check next item
		movlw	low ModeMnu0		;OPT 0 Log selection
		movwf	TBLPTRL
		movlw	High ModeMnu0
		movwf	TBLPTRH
		call	prtstrl			;print string LCD

		movlw	low ModeMnu0S
		movwf	TBLPTRL
		movlw	high ModeMnu0S
		movwf	TBLPTRH
		call	prtstrs			;print string serial
		return
				
s1:		movlw	.1
		cpfseq	SetSel
		bra		s2
		movlw	low ModeMnu1		;OPT 1 Trigger delay
		movwf	TBLPTRL
		movlw	High ModeMnu1
		movwf	TBLPTRH
		call	prtstrl	

		movlw	low ModeMnu1S
		movwf	TBLPTRL
		movlw	high ModeMnu1S
		movwf	TBLPTRH
		call	prtstrs	
		return

s2:		movlw	.2
		cpfseq	SetSel
		bra		s3
		movlw	low ModeMnu2		;OPT 2 Time set
		movwf	TBLPTRL
		movlw	High ModeMnu2
		movwf	TBLPTRH
		call	prtstrl	

		movlw	low ModeMnu2S
		movwf	TBLPTRL
		movlw	high ModeMnu2S
		movwf	TBLPTRH
		call	prtstrs	
		return

s3:		movlw	.3
		cpfseq	SetSel
		bra		s4
		movlw	low ModeMnu3		;OPT 3 Strike count
		movwf	TBLPTRL
		movlw	High ModeMnu3
		movwf	TBLPTRH
		call	prtstrl	

		movlw	low ModeMnu3S
		movwf	TBLPTRL
		movlw	high ModeMnu3S
		movwf	TBLPTRH
		call	prtstrs	
		return


s4:		movlw	.4
		cpfseq	SetSel
		bra		s5
		movlw	low ModeMnu4		;OPT 4 Backlight control
		movwf	TBLPTRL
		movlw	High ModeMnu4
		movwf	TBLPTRH
		call	prtstrl	

		movlw	low ModeMnu4S
		movwf	TBLPTRL
		movlw	high ModeMnu4S
		movwf	TBLPTRH
		call	prtstrs	
		return

s5:		movlw	.5
		cpfseq	SetSel
		bra		s6
		movlw	low ModeMnu5		;OPT 5 Rate counter
		movwf	TBLPTRL
		movlw	High ModeMnu5
		movwf	TBLPTRH
		call	prtstrl	

		movlw	low ModeMnu5S
		movwf	TBLPTRL
		movlw	high ModeMnu5S
		movwf	TBLPTRH
		call	prtstrs	
		return


s6:		movlw	.6
		cpfseq	SetSel
		bra		s7
		movlw	low ModeMnu6		;OPT 6 Calibrate temperature
		movwf	TBLPTRL
		movlw	High ModeMnu6
		movwf	TBLPTRH
		call	prtstrl	

		movlw	low ModeMnu6S
		movwf	TBLPTRL
		movlw	high ModeMnu6S
		movwf	TBLPTRH
		call	prtstrs	
		return


s7:		movlw	.7
		cpfseq	SetSel
		bra		s8
		movlw	low ModeMnu7		;OPT 7 Rate display select
		movwf	TBLPTRL
		movlw	High ModeMnu7
		movwf	TBLPTRH
		call	prtstrl	

		movlw	low ModeMnu7S
		movwf	TBLPTRL
		movlw	high ModeMnu7S
		movwf	TBLPTRH
		call	prtstrs	
		return

s8:		movlw	.8
		cpfseq	SetSel
		bra		s9
		movlw	low ModeMnu10		;OPT 8  Bluetooth
		movwf	TBLPTRL
		movlw	High ModeMnu10
		movwf	TBLPTRH
		call	prtstrl	

		movlw	low ModeMnu10S
		movwf	TBLPTRL
		movlw	high ModeMnu10S
		movwf	TBLPTRH
		call	prtstrs	
		return


s9:		movlw	.9
		cpfseq	SetSel
		bra		s10
		movlw	low ModeMnu11		;OPT 9  Clock
		movwf	TBLPTRL
		movlw	High ModeMnu11
		movwf	TBLPTRH
		call	prtstrl	

		movlw	low ModeMnu11S
		movwf	TBLPTRL
		movlw	high ModeMnu11S
		movwf	TBLPTRH
		call	prtstrs	
		return



s10:	movlw	.10
		cpfseq	SetSel
		bra		s18
		movlw	low ModeMnu12		;OPT 10  Clock
		movwf	TBLPTRL
		movlw	High ModeMnu12
		movwf	TBLPTRH
		call	prtstrl	

		movlw	low ModeMnu12S
		movwf	TBLPTRL
		movlw	high ModeMnu12S
		movwf	TBLPTRH
		call	prtstrs	
		return






;Options kept at end of list
s18:		movlw	.11					
		cpfseq	SetSel
		bra		s19					;OPT 9 Save settings
		movlw	low ModeMnu8
		movwf	TBLPTRL
		movlw	High ModeMnu8
		movwf	TBLPTRH
		call	prtstrl	

		movlw	low ModeMnu8S
		movwf	TBLPTRL
		movlw	high ModeMnu8S
		movwf	TBLPTRH
		call	prtstrs	
		return

s19:;		movlw	.12					
;		cpfseq	SetSel
;		bra		s10					;OPT 9 exit

		movlw	low ModeMnu9		;OPT 10 exit
		movwf	TBLPTRL
		movlw	High ModeMnu9
		movwf	TBLPTRH
		call	prtstrl	

		movlw	low ModeMnu9S
		movwf	TBLPTRL
		movlw	high ModeMnu9S
		movwf	TBLPTRH
		call	prtstrs	
		return



SetDone:
		call	LCDTxtUp			;Restore LCD text
		return

;-------------------------------------------------------------------
;Print clock status serial port

SerStats:

;
		movlw	low SerStats3	;"Log is "
		movwf	TBLPTRL
		movlw	high SerStats3	
		movwf	TBLPTRH
		call	prtstrs			;print string serial

		btfss	TimerStat1,LogEnab
		call	OffToSer

		btfsc	TimerStat1,LogEnab
		call	OnToSer
		movlw	low SerStats4	;"Time: "
		movwf	TBLPTRL
		movlw	high SerStats4	
		movwf	TBLPTRH
		call	prtstrs			;print string serial
		call	TimeToSer		;Print current time

		movlw	low SerStats2	;"Trigger Dealy is "
		movwf	TBLPTRL
		movlw	high SerStats2	
		movwf	TBLPTRH
		call	prtstrs


		movff	TrigDelay,BINL1		;Current trigger delay value
		clrf	BINH1
		clrf	BINL2
		clrf	BINH2

		call	DWordToBCD		;Convert to bcd
		call	ByteToSer		
		Call	SerPrtPer		;Period
		call	SerPrtCRLF

		movlw	low ModeRCS	;"Rate counter is "
		movwf	TBLPTRL
		movlw	high ModeRCS	
		movwf	TBLPTRH
		call	prtstrs

		btfss	RateC
		call	OffToSer

		btfsc	RateC
		call	OnToSer
		Call	SerPrtPer		;Period
		call	SerPrtCRLF



	bra		ssxx
;divide test code for new division sub

;Constants

;36000000000 (3600 seconds) / 256 = 0x 08 61 c4 68
;300000000 (30 seconds) /256 = 0x 00 11 e1 a3
;3600000000000 (360000) /256 = 0x 03 46 30 b8 a0
	clrf	Dividend+0
;	clrf	Dividend+1
	movlw	0x03
	movwf	Dividend+1
	movlw	0x46
	movwf	Dividend+2
	movlw	0x30
	movwf	Dividend+3
	movlw	0xb8
	movwf	Dividend+4
	movlw	0xa0
	movwf	Dividend+5

;	clrf	Dividend+3
;	clrf	Dividend+4
;	clrf	Dividend+5

;	clrf	Divisor+0
;	clrf	Divisor+1


	movlw	0x11
	movwf	Divisor+0
	movlw	0xe1
	movwf	Divisor+1
	movlw	0xa3
	movwf	Divisor+2
;test 0x0000800000 / 0x000002


;Little endian
	call	DIVIDE_48by24 
;Dividend has result

		movff	Dividend+2,BINH2
		movff	Dividend+3,BINL2
		movff	Dividend+4,BINH1
		movff	Dividend+5,BINL1


		call	DWordToBCD		;Convert to bcd
		call	DwordToSer		;Print serial	
		Call	SerPrtPer		;Period
		call	SerPrtCRLF

ssxx:

		return
;-------------------------------------------------------------
;Log enable/disable
LogSel:
			bcf 	RptBf			;Button auto repeat off

			movlw	0x40			;Second line  LCD text       
			call	PrtPMChgL					;print strings "+ - to change sel to end"

			movlw	0x00			;Fourth line  LCD text                           
			call	LCDADD	
			movlw	low ModeLS0		;Text: "Log is "
			movwf	TBLPTRL
			movlw	High ModeLS0
			movwf	TBLPTRH
			call	prtstrl			;print string LCD
			bra		LeUp			;Update log status display



LeTst:									;Wait for button press. + - toggles log, Sel exits


			movlw 	.0					;0 if no char received
			call	ReceiveSerUcase		;Check serial input
			movwf	SerSel				;save ser input
			xorlw	"+" 				;compare with P Log + -		
			bz		LeSel
			movf	SerSel,w
			xorlw	"-" 				;compare with M Log + -		
			bz		LeSel

			movf	SerSel,w
			xorlw	"L" 				;compare with L Select		
			bz		LeXit


			btfsc	NxtPr  ;LeBt:
			bra		LeSel
			btfsc	PrvPr
			bra		LeSel
			btfss	SelPr
			bra		LeTst




LeXit:
			bcf		SelPr
			call	LCDTxtUp			;Restore LCD text
			call	BeatNotV			;Clear beat counter and flag. Beat data is not valid.
			return

LeSel:									;Toggle log, update display



			btg	TimerStat1,LogEnab		;Toggle log enable/disable 1=enabled
LeUp:	


			movlw	low SerStats3	;"Log is "
			movwf	TBLPTRL
			movlw	high SerStats3	
			movwf	TBLPTRH
			call	prtstrs			;print string serial

			bcf		PrvPr
			bcf		NxtPr


			btfsc	TimerStat1,LogEnab
			bra		LeOn


			movlw	0x0c
			call	OffToLCD
			call	OffToSer
			bra		LePr
LeOn:
			movlw	0x0c
			call	OnToLCD
			call	OnToSer
LePr:		call	SerPrtCRLF
     
			call	PrtPMChgS	;print strings serial "+ - to change sel to end"
			bra		LeTst

;-------------------------------------------------------------
TrigDly:
;Adjust trigger delay time
;Time before another input will be accepted.
;100 ms steps
			bsf 	RptBf			;Button auto repeat on
			movlw	0x40			;Second line  LCD text       
			call	PrtPMChgL					;print strings "+ - to change sel to end" LCD
			call	PrtPMChgS		;print strings "+ - to change sel to end" serial
			movlw	0x00			;Fourth line  LCD text                           
			call	LCDADD	
			movlw	low ModeTS0		;Text: 	"Trigger delay is xxx.   
			movwf	TBLPTRL
			movlw	High ModeTS0
			movwf	TBLPTRH
			call	prtstrl			;print string LCD
			bra		TDUpD			;Update display



TDTst:									;Wait for button press. + - toggles log, Sel exits


			movlw 	.0					;0 if no char received
			call	ReceiveSerUcase		;Check serial input
			movwf	SerSel				;save ser input
			xorlw	"+" 				;compare with P Log + -		
			bz		TDUp
			movf	SerSel,w
			xorlw	"-" 				;compare with M Log + -		
			bz		TDDn

			movf	SerSel,w
			xorlw	"L" 				;compare with L Select		
			bnz		TDBt
			call	LCDTxtUp			;Restore LCD text
			return

TDBt:		btfsc	NxtPr
			bra		TDUp
			btfsc	PrvPr
			bra		TDDn
			btfss	SelPr
			bra		TDTst
			bcf		SelPr
			call	LCDTxtUp			;Restore LCD text
			call	BeatNotV			;Clear beat counter and flag. Beat data is not valid.
			return
TDUp:

;Increase delay
		movlw	(TrigStep)	;Trigger delay increment time
        addwf  TrigDelay, F
		movlw .50			;1 second max delay
		cpfsgt	TrigDelay	;Roll over at 1 second
		bra 	NoIpRl
		movlw	(TrigStep)
		movwf	TrigDelay
NoIpRl:	bra		TDUpD

TDDn:
;Decrease impulse timer
		movlw	(TrigStep)	;Trigger delay increment time
        subwf  TrigDelay, F
		movlw .1			;1 second max delay
		cpfslt	TrigDelay	;Roll over at 1 second
		bra 	NoIpDl
		movlw	.50
		movwf	TrigDelay
NoIpDl:


TDUpD:		;Update display



		movlw	low SerStats2	;"Trigger Dealy is "
		movwf	TBLPTRL
		movlw	high SerStats2	
		movwf	TBLPTRH
		call	prtstrs			;print string serial


	movff	TrigDelay,BINL1		;Current trigger delay value
	clrf	BINH1
	clrf	BINL2
	clrf	BINH2



	call	DWordToBCD		;Convert to bcd
	movlw	0x11			;LCD cursor pos
	call	ByteToLCD
	call	ByteToSer		

	call	SerPrtCRLF

		call	PrtPMChgS		;print strings "+ - to change sel to end" serial



			bcf		PrvPr
			bcf		NxtPr

			bsf		SetChg		;Settings changed warning on
			bra		TDTst

;----------------------------------------------------------------------------------------

;Temperature calibration



CalTemp:

			bsf 	RptBf			;Button auto repeat on
			movlw	0x40			;Second line  LCD text       
			call	PrtPMChgL					;print strings "+ - to change sel to end" LCD
			call	PrtPMChgS		;print strings "+ - to change sel to end" serial
			movlw	0x00			;Fourth line  LCD text                           
			call	LCDADD	
			movlw	low ModeCTL		;Text: 	"Temp calibrate xxx.   
			movwf	TBLPTRL
			movlw	High ModeCTL
			movwf	TBLPTRH
			call	prtstrl			;print string LCD
			bra		TCUpD			;Update display



TCTst:									;Wait for button press. + - toggles log, Sel exits


			movlw 	.0					;0 if no char received
			call	ReceiveSerUcase		;Check serial input
			movwf	SerSel				;save ser input
			xorlw	"+" 				;compare with P Log + -		
			bz		TCUp
			movf	SerSel,w
			xorlw	"-" 				;compare with M Log + -		
			bz		TCDn

			movf	SerSel,w
			xorlw	"L" 				;compare with L Select		
			bnz		TCBt
			call	LCDTxtUp			;Restore LCD text
			return

TCBt:		btfsc	NxtPr
			bra		TCUp
			btfsc	PrvPr
			bra		TCDn
			btfss	SelPr
			bra		TCTst
			bcf		SelPr
			call	LCDTxtUp			;Restore LCD text
			call	BeatNotV			;Clear beat counter and flag. Beat data is not valid.
			return
TCUp:

			incf	TempCal
			bra		TCUpD
TCDn:

			decf	TempCal

TCUpD:		;Update display

			bsf		SetChg				;Settings changed flag

			movlw	low ModeCTS			;Text: 	"Temp calibrate " 
			movwf	TBLPTRL
			movlw	high ModeCTS	
			movwf	TBLPTRH
			call	prtstrs				;print string serial



;Temperature display update.



			call	TempCalAdj				;Apply calibration to ADC data

			movff	DIVIDEND_LO,TCTmp1	;Save DIVIDEND_ Destroyed by temptllcd
			movff	DIVIDEND_HI,TCTmp2

			movlw	LCDL1P+.15			;LCD addr for temperature display 
			call	TempToLCD			;Display temperature on display.





;	call	SerPrtCSV		;CSV comma delimiter

			movff	TCTmp1,DIVIDEND_LO	
			movff	TCTmp2,DIVIDEND_HI
			
			
			call	TempToSer

			call	SerPrtCRLF

			call	PrtPMChgS		;print strings "+ - to change sel to end" serial



			bcf		PrvPr
			bcf		NxtPr


			bra		TCTst


;Apply temperature calibration offset
;Input 10 bits to ADCLOA,ADCHIA
;Result in DIVIDEND_LO,HI
TempCalAdj:
			movff	TempCal,Tcal

			movff	ADCLOA,DIVIDEND_LO	
			movff	ADCHIA,DIVIDEND_HI
	
			btfss	Tcal,	.7				;Negative #?
			bra		tcncmp					;No

			negf	Tcal					;Two's compliment

			movf	Tcal,W 				;Subtract temperature sensor calibration offset.
			subwf	DIVIDEND_LO,F
			movlw	.0
			subwfb	DIVIDEND_HI,F
			bra		TCTD			
tcncmp:

			movf	Tcal,W 				; Add temperature sensor calibration offset.
			addwf	DIVIDEND_LO,F
			movlw	.0
			addwfc	DIVIDEND_HI,F	

TCTD:		return
;----------------------------------------------------------------------------------------
;Set rate units display

RateSet:

			bcf 	RptBf			;Button auto repeat off

			movlw	LCDL3P			;Fourth line  LCD text       
			call	PrtPMChgL					;print strings "+ - to change sel to end"
			movlw	LCDL1P			;First line  LCD text                           
			call	LCDADD	
			movlw	low SerStats5		;Text: " Rate display units "
			movwf	TBLPTRL
			movlw	High SerStats5
			movwf	TBLPTRH
			call	prtstrl			;print string LCD
			bra		RSUp			;Update log status display



RSTst:									;Wait for button press. + - toggles log, Sel exits


			movlw 	.0					;0 if no char received
			call	ReceiveSerUcase		;Check serial input
			movwf	SerSel				;save ser input
			xorlw	"+" 				;compare with P Log + -		
			bz		RSSelS
			movf	SerSel,w
			xorlw	"-" 				;compare with M Log + -		
			bz		RSSelS

			movf	SerSel,w
			xorlw	"L" 				;compare with L Select		
			bnz		RSBt
			call	LCDTxtUp			;Restore LCD text
			return

RSBt:		btfsc	NxtPr
			bra		RSSelS
			btfsc	PrvPr
			bra		RSSelS
			btfss	SelPr
			bra		RSTst
			bcf		SelPr
			call	LCDTxtUp			;Restore LCD text
			return

RSSelS:									;Toggle units, update display



			bsf		SetChg				;Settings changed flag


;Button toggle of BPM,BPH (Select button)

			btfsc	SecPB
			goto	RSm
			btfsc	BeatPHM
			bra		RSspb
			bsf		BeatPHM
			bra		RSxit
RSspb:		bsf		SecPB
			bra		RSxit
RSm:
			bcf		BeatPHM
			bcf		SecPB

RSxit:		bcf		SelPr			;Clear button


RSUp:

			bcf		PrvPr			;Reset button state
			bcf		NxtPr

			movlw	low SerStats5		;Text: " Rate display units "
			movwf	TBLPTRL
			movlw	high SerStats5	
			movwf	TBLPTRH
			call	prtstrs			;print string serial



			btfss	SecPB			;Seconds per beat?
			bra		SecHMc			;No

;	Display seconds per beat
			movlw	LCDL2P			;Second line  LCD text                           
			call	LCDADD	
			movlw	low RDL0		;Text: "Seconds per beat.   "
			movwf	TBLPTRL
			movlw	High RDL0
			movwf	TBLPTRH
			call	prtstrl			;print string LCD

			movlw	low RDL0		;Text: "Seconds per beat.   "
			movwf	TBLPTRL
			movlw	High RDL0
			movwf	TBLPTRH
			call	prtstrs			;print string serial
			bra		RSPr
SecHMc:

			btfss	BeatPHM			;Beats per minute?
			bra		DisBPH			;No			

;	Display beats per minute
			movlw	LCDL2P			;Second line  LCD text                           
			call	LCDADD	
			movlw	low RDL1		;Text: "Beats per minute.   "
			movwf	TBLPTRL
			movlw	High RDL1
			movwf	TBLPTRH
			call	prtstrl			;print string LCD
			movlw	low RDL1		;Text: "Beats per minute.   "
			movwf	TBLPTRL
			movlw	High RDL1
			movwf	TBLPTRH
			call	prtstrs			;print string serial
			bra		RSPr

;	Display beats per hour
DisBPH:		movlw	LCDL2P			;Second line  LCD text                           
			call	LCDADD	
			movlw	low RDL2		;Text: "Beats per hour.     "
			movwf	TBLPTRL
			movlw	High RDL2
			movwf	TBLPTRH
			call	prtstrl			;print string LCD
			movlw	low RDL2		;Text: "Beats per hour.     "
			movwf	TBLPTRL
			movlw	High RDL2
			movwf	TBLPTRH
			call	prtstrs			;print string serial


RSPr:		call	SerPrtCRLF
			call	PrtPMChgS
			bra		RSTst




;----------------------------------------------------------------------------------------

;Set real time clock



TimeSet:


;;Prepare to reset clock

		bsf		RptBf					;Enable key repeat
		bcf		TimerStat1,RTCEnab		;Turn off real time clock update.
		clrf 	TimeSS			;Zero only current seconds. Set clock in minute increments.

		bcf		TimerStat1,RTCTick	;Reset RTC update flag

;real time clock display update
		movlw	0x00			;First line  LCD text       
		call	LCDADD	
		movlw	low ModeS0		;Text: "Press + - to change     "
		movwf	TBLPTRL
		movlw	High ModeS0
		movwf	TBLPTRH
		call	prtstrl			;print string LCD

		movlw	0x40			;Second line  LCD text.                           
		call	LCDADD	
		movlw	low ModeLT0		;Text: "Press Select to     "
		movwf	TBLPTRL
		movlw	High ModeLT0
		movwf	TBLPTRH
		call	prtstrl			;print string LCD

		movlw	0x14			;Third line  LCD text.                           
		call	LCDADD	
		movlw	low ModeLT1		;Text: 	"Start clock and exit"
		movwf	TBLPTRL
		movlw	High ModeLT1
		movwf	TBLPTRH
		call	prtstrl			;print string LCD


			movlw	low ModeST0	;Text: "Press L to start clock and exit."
			movwf	TBLPTRL
			movlw	high ModeST0	
			movwf	TBLPTRH
			call	prtstrs			;print string serial

			movlw	LCDL4P+0			;addr for RTC clock display                               
			call	TimeToLCD 			;update RTC time display on LCD
			call	TimeToSer			;update RTC time display on Serial
		call	SerPrtCRLF

WtBtn:		movlw 	.0					;0 if no char received
			call	ReceiveSerUcase		;Check serial input
			movwf	SerSel				;save ser input
			xorlw	"+" 				;Advance clock ?		
			bnz		NoAdv
			call 	IncTimeM			;Advance clock by minutes
			bra		Tup
NoAdv:		movf	SerSel,W
			xorlw	"-" 				;Retard clock ?		
			bnz		CkBtnA				;No, check button inputs.
			call 	DecTimeM			;Retard clock by minutes
			bra		Tup

CkBtnA:
			btfss	NxtPr				;adv,next button press?
			bra		tsrd				;No, check retard
			call 	IncTimeM
			bcf		NxtPr				;Clear button press flag
			bra		Tup
tsrd:		btfss	PrvPr				;Retard,prv button press?
			bra		NoRet				;Check select start clock
			call 	DecTimeM			;Retard clock by minutes
			bcf		PrvPr				;Clear button press flag



;real time clock display update
Tup:		movlw	LCDL4P+0			;addr for RTC clock display                               
			call	TimeToLCD 			;update RTC time display on LCD
			call	PrtPMChgS			;Serial print strings "+ - to change sel to end"
			call	TimeToSer			;update RTC time display on Serial
			call	SerPrtCRLF
NoRet:
;Check for start clock using serial
			movf	SerSel,W			;Last serial input
			xorlw	"L" 				;Start clock? "L"
			bnz		NoSerStrt
			bra		ClkStart
;Check for start clock using button
NoSerStrt:
			btfss	SelPr				;Select button press?
			bra		WtBtn
			bcf		SelPr


ClkStart:
		clrf	sBeatI3					;Clear seconds counters before restart
		clrf	SecCnt0	
		clrf	SecCnt1
		clrf	SecCnt2
		clrf	SecDif0
		clrf	SecDif1
		clrf	SecDif2
		clrf	TMR0H					;Reset hardware timer plus 8 bits software extension.
		clrf	TMR0L
		clrf	sBeatI3

		call	AddClkSec				;Add 1 sec. to counter. 1 sec. elapsed before first tick.
										;Also called in low ISR. Never call unless RTC is disabled!
		bsf		TimerStat1,RTCEnab		;Turn on real time clock update.
			call	LCDTxtUp			;Restore LCD text

			call	SerStats
			call	BeatNotV			;Clear beat counter and flag. Beat data is not valid.
		return


;-----------------------------------------------------------
;Strike count mode
StrikeC


		bcf		RptBf			;Button auto repeat off



		movlw	0x00			;First line  LCD text                           
		call	LCDADD	
		movlw	low ModeSL0		;Text: "Strike count is xxx."
		movwf	TBLPTRL
		movlw	High ModeSL0
		movwf	TBLPTRH
		call	prtstrl			;print string LCD

		call	ScUpd			;update displays

ScTst:									;Wait for button press. + - toggles log, Sel exits


			movlw 	.0					;0 if no char received
			call	ReceiveSerUcase		;Check serial input
			movwf	SerSel				;save ser input
			xorlw	"+" 				;compare with - Log + -		
			bz		ScSel
			movf	SerSel,w
			xorlw	"-" 				;compare with + Log + -		
			bz		ScSel

			movf	SerSel,w
			xorlw	"L" 				;compare with L Select		
			bz		ScXit				;Done, Exit		

ScBt:		btfsc	NxtPr
			bra		ScSel
			btfsc	PrvPr
			bra		ScSel
			btfss	SelPr				;Button Select pressed?
			bra		ScTst				;No, Keep checking
			bra		ScXit

ScSel:		btg		TimerStat1,StrikeMode		;Toggle count strike mode
			call	ScUpd					;Display update
			bra		ScTst					;Check for another change
ScXit:
			bcf		SelPr
			movlw	0x00			;First line  LCD text                           
			call	LCDADD	
			movlw	low ModeMnu3		;Text: "Strike counter."
			movwf	TBLPTRL
			movlw	High ModeMnu3
			movwf	TBLPTRH
			call	prtstrl			;print string LCD

			movlw	0x40			;Second line  LCD text                           
			call	LCDADD	
			movlw	low ModeSL1		;Text: "Strike time hh:mm:ss."
			movwf	TBLPTRL
			movlw	High ModeSL1
			movwf	TBLPTRH
			call	prtstrl			;print string LCD

			movlw	0x14			;Third line  LCD text                           
			call	LCDADD	
			movlw	low ModeSL2		;Text: "xxx strikes."
			movwf	TBLPTRL
			movlw	High ModeSL2
			movwf	TBLPTRH
			call	prtstrl			;print string LCD



			btfsc	TimerStat1,StrikeMode
			bra		ScOnX
			call	LCDTxtUp			;Restore LCD text
			call	BeatNotV			;Clear beat counter and flag. Beat data is not valid.
ScOnX:			return


;Update serial and LCD display
ScUpd:

			movlw	low ModeSS0	;Text: "Strike counter is "
			movwf	TBLPTRL
			movlw	high ModeSS0	
			movwf	TBLPTRH
			call	prtstrs			;print string serial
			bcf		PrvPr
			bcf		NxtPr
			btfsc	TimerStat1,StrikeMode
			bra		ScOn
			movlw	0x10
			call	OffToLCD
			call	OffToSer
			bra		ScPr
ScOn:
			movlw	0x10
			call	OnToLCD
			call	OnToSer
ScPr:		call	SerPrtCRLF
			movlw	0x40			;Second line  LCD text       
			call	PrtPMChgL	;print string LCD "+ - to change sel to end"
			call	PrtPMChgS	;print string serial "+ - to change sel to end"
			return



;---------------------------------------------------------------
;Set LCD backlight
BLSel:

			bcf 	RptBf			;Button auto repeat off

			movlw	0x40			;Second line  LCD text       
			call	PrtPMChgL					;print strings "+ - to change sel to end"
			movlw	0x00			;First line  LCD text                           
			call	LCDADD	
			movlw	low ModeLB0		;Text: "LCD light is xxx.   "
			movwf	TBLPTRL
			movlw	High ModeLB0
			movwf	TBLPTRH
			call	prtstrl			;print string LCD
			bra		BLUp			;Update log status display



BLTst:									;Wait for button press. + - toggles log, Sel exits


			movlw 	.0					;0 if no char received
			call	ReceiveSerUcase		;Check serial input
			movwf	SerSel				;save ser input
			xorlw	"+" 				;compare with P Log + -		
			bz		BLSelS
			movf	SerSel,w
			xorlw	"-" 				;compare with M Log + -		
			bz		BLSelS

			movf	SerSel,w
			xorlw	"L" 				;compare with L Select		
			bnz		BLBt
			call	LCDTxtUp			;Restore LCD text
			return

BLBt:		btfsc	NxtPr
			bra		BLSelS
			btfsc	PrvPr
			bra		BLSelS
			btfss	SelPr
			bra		BLTst
			bcf		SelPr
			call	LCDTxtUp			;Restore LCD text
			return

BLSelS:									;Toggle backlight, update display

			bsf		SetChg				;Settings changed flag

			btg		LCDBL		;Toggle LCD backlight
BLUp:


			movlw	low ModeSB0			; Text: "LCD backlight is "
			movwf	TBLPTRL
			movlw	high ModeSB0	
			movwf	TBLPTRH
			call	prtstrs			;print string serial

			bcf		PrvPr
			bcf		NxtPr


			btfsc	LCDBL
			bra		BLOn


			movlw	0x0d
			call	OffToLCD
			call	OffToSer
			bra		BLPr
BLOn:
			movlw	0x0d
			call	OnToLCD
			call	OnToSer
BLPr:		call	SerPrtCRLF
;			movlw	0x40			;Second line  LCD text       
			call	PrtPMChgS	;print strings serial "+ - to change sel to end"
			bra		BLTst


;------------------------------------------------------------------------------
;Set Bluetooth enable/disable
BTState:

			bcf 	RptBf			;Button auto repeat off

			movlw	0x40			;Second line  LCD text       
			call	PrtPMChgL					;print strings "+ - to change sel to end"
			movlw	0x00			;First line  LCD text                           
			call	LCDADD	
			movlw	low ModeBTL		;Text: "Bluetooth is xxx."
			movwf	TBLPTRL
			movlw	High ModeBTL
			movwf	TBLPTRH
			call	prtstrl			;print string LCD
			bra		BTUp			;Update log status display



BTTst:									;Wait for button press. + - toggles log, Sel exits


			movlw 	.0					;0 if no char received
			call	ReceiveSerUcase		;Check serial input
			movwf	SerSel				;save ser input
			xorlw	"+" 				;compare with P Log + -		
			bz		BTSelS
			movf	SerSel,w
			xorlw	"-" 				;compare with M Log + -		
			bz		BTSelS

			movf	SerSel,w
			xorlw	"L" 				;compare with L Select		
			bnz		BTBt
			call	LCDTxtUp			;Restore LCD text
			return

BTBt:		btfsc	NxtPr
			bra		BTSelS
			btfsc	PrvPr
			bra		BTSelS
			btfss	SelPr
			bra		BTTst
			bcf		SelPr
			call	LCDTxtUp			;Restore LCD text
			return

BTSelS:									;Toggle backlight, update display
			bsf		SetChg				;Settings changed flag


			btg		LATC,BTOn			;Toggle Bluetooth
BTUp:


			movlw	low ModeBTS			; Text: "Bluetooth is "
			movwf	TBLPTRL
			movlw	high ModeBTS	
			movwf	TBLPTRH
			call	prtstrs			;print string serial

			bcf		PrvPr
			bcf		NxtPr


			btfsc	LATC,BTOn			;Toggle Bluetooth
			bra		BTOnl


			movlw	0x0d
			call	OffToLCD
			call	OffToSer
			bra		BTPr
BTOnl:
			movlw	0x0d
			call	OnToLCD
			call	OnToSer
BTPr:		call	SerPrtCRLF
			call	PrtPMChgS	;print strings serial "+ - to change sel to end"
			bra		BTTst



;------------------------------------------------------------------------------
;Set clock display enable/disable
ClkSel:

			bcf 	RptBf			;Button auto repeat off

			movlw	0x40			;Second line  LCD text       
			call	PrtPMChgL					;print strings "+ - to change sel to end"
			movlw	0x00			;First line  LCD text                           
			call	LCDADD	
			movlw	low ModeCDL		;Text: "Clock is xxx."
			movwf	TBLPTRL
			movlw	High ModeCDL
			movwf	TBLPTRH
			call	prtstrl			;print string LCD
			bra		CDUp			;Update log status display



CDTst:									;Wait for button press. + - toggles log, Sel exits


			movlw 	.0					;0 if no char received
			call	ReceiveSerUcase		;Check serial input
			movwf	SerSel				;save ser input
			xorlw	"+" 				;compare with P Log + -		
			bz		CDSelS
			movf	SerSel,w
			xorlw	"-" 				;compare with M Log + -		
			bz		CDSelS

			movf	SerSel,w
			xorlw	"L" 				;compare with L Select		
			bnz		CDBt
			call	LCDTxtUp			;Restore LCD text
			return

CDBt:		btfsc	NxtPr
			bra		CDSelS
			btfsc	PrvPr
			bra		CDSelS
			btfss	SelPr
			bra		CDTst
			bcf		SelPr
			call	LCDTxtUp			;Restore LCD text
			return

CDSelS:									;Toggle log, update display

			bsf		SetChg				;Settings changed flag

			btg		CDOn			;Toggle clock display flag
CDUp:


			movlw	low ModeCDS			; Text: "Clock is "
			movwf	TBLPTRL
			movlw	high ModeCDS	
			movwf	TBLPTRH
			call	prtstrs			;print string serial

			bcf		PrvPr
			bcf		NxtPr


			btfsc	CDOn			;clock display flag
			bra		CDOnl


			movlw	LCDL1P+0x09
			call	OffToLCD
			call	OffToSer
			bra		CDPr
CDOnl:
			movlw	LCDL1P+0x09
			call	OnToLCD
			call	OnToSer
CDPr:		call	SerPrtCRLF
			call	PrtPMChgS	;print strings serial "+ - to change sel to end"
			bra		CDTst


;------------------------------------------------------------------------------
;Set temperature display enable/disable
TempSel:

			bcf 	RptBf			;Button auto repeat off

			movlw	0x40			;Second line  LCD text       
			call	PrtPMChgL					;print strings "+ - to change sel to end"
			movlw	0x00			;First line  LCD text                           
			call	LCDADD	
			movlw	low ModeTDL		;Text: "Temp display is xxx."
			movwf	TBLPTRL
			movlw	High ModeTDL
			movwf	TBLPTRH
			call	prtstrl			;print string LCD
			bra		TDUp1			;Update temp status display



TDTst1:									;Wait for button press. + - toggles log, Sel exits


			movlw 	.0					;0 if no char received
			call	ReceiveSerUcase		;Check serial input
			movwf	SerSel				;save ser input
			xorlw	"+" 				;compare with P Log + -		
			bz		TDSelS
			movf	SerSel,w
			xorlw	"-" 				;compare with M Log + -		
			bz		TDSelS

			movf	SerSel,w
			xorlw	"L" 				;compare with L Select		
			bnz		TDBt1
			call	LCDTxtUp			;Restore LCD text
			return

TDBt1:		btfsc	NxtPr
			bra		TDSelS
			btfsc	PrvPr
			bra		TDSelS
			btfss	SelPr
			bra		TDTst1
			bcf		SelPr
			call	LCDTxtUp			;Restore LCD text
			return

TDSelS:									;Toggle temp, update display

			bsf		SetChg				;Settings changed flag

			btg		TDOn	 			;Toggle temp display flag
TDUp1:


			movlw	low ModeTDS			; Text: "Temp display is xxx."
			movwf	TBLPTRL
			movlw	high ModeTDS	
			movwf	TBLPTRH
			call	prtstrs			;print string serial

			bcf		PrvPr
			bcf		NxtPr


			btfsc	TDOn		;Clock display flag
			bra		TDOnl


			movlw	0x10
			call	OffToLCD
			call	OffToSer
			bra		TDPr
TDOnl:
			movlw	0x10
			call	OnToLCD
			call	OnToSer
TDPr:		call	SerPrtCRLF
			call	PrtPMChgS	;print strings serial "+ - to change sel to end"
			bra		TDTst1



;---------------------------------------------------------------
;Select rate counter mode
RCSel:

			bcf 	RptBf			;Button auto repeat off

			movlw	0x40			;Second line  LCD text       
			call	PrtPMChgL					;print strings "+ - to change sel to end"
			movlw	0x00			;First line  LCD text                           
			call	LCDADD	
			movlw	low ModeRCL		;Text: "Rate counter is xxx.   "
			movwf	TBLPTRL
			movlw	High ModeRCL
			movwf	TBLPTRH
			call	prtstrl			;print string LCD
			bra		RCUp			;Update log status display



RCTst:									;Wait for button press. + - toggles log, Sel exits


			movlw 	.0					;0 if no char received
			call	ReceiveSerUcase		;Check serial input
			movwf	SerSel				;save ser input
			xorlw	"+" 				;compare with P Log + -		
			bz		RCSelS
			movf	SerSel,w
			xorlw	"-" 				;compare with M Log + -		
			bz		RCSelS

			movf	SerSel,w
			xorlw	"L" 				;compare with L Select		
			bnz		RCBt
			bra		RCXit				;Done, exit

RCBt:		btfsc	NxtPr
			bra		RCSelS
			btfsc	PrvPr
			bra		RCSelS
			btfss	SelPr
			bra		RCTst
			bcf		SelPr




RCXit:

			bcf		SelPr
			movlw	0x00			;First line  LCD text                           
			call	LCDADD	
			movlw	low RCL0		;Text: "Beats"
			movwf	TBLPTRL
			movlw	High RCL0
			movwf	TBLPTRH
			call	prtstrl			;print string LCD

			movlw	0x40			;Second line  LCD text                           
			call	LCDADD	
			movlw	low RCL1		;Text: "Hours"
			movwf	TBLPTRL
			movlw	High RCL1
			movwf	TBLPTRH
			call	prtstrl			;print string LCD

			movlw	0x14			;Third line  LCD text                           
			call	LCDADD	
			movlw	low RCL2		;Text: "BPH."
			movwf	TBLPTRL
			movlw	High RCL2
			movwf	TBLPTRH
			call	prtstrl			;print string LCD



			btfsc	RateC
			bra		RCOnX
			call	LCDTxtUp			;Restore LCD text
			call	BeatNotV			;Clear beat counter and flag. Beat data is not valid.
RCOnX:
			bcf		RateTF			;Hour trigger input flag
			clrf	RCHourL			;Rate hour counter
			clrf	RCHourH
			clrf	RCBeatL			;Rate beat counter
			clrf	RCBeatH
			return




RCSelS:									;Toggle log, update display



			btg		RateC				;Toggle rate counter
RCUp:


			movlw	low ModeRCS			; Text: "Rate counter is "
			movwf	TBLPTRL
			movlw	high ModeRCS	
			movwf	TBLPTRH
			call	prtstrs				;print string serial

			bcf		PrvPr
			bcf		NxtPr


			btfsc	RateC
			bra		RCOn


			movlw	0x11				;Cursor pos
			call	OffToLCD
			call	OffToSer
			bra		RCPr
RCOn:
			movlw	0x11
			call	OnToLCD
			call	OnToSer
RCPr:		call	SerPrtCRLF
			movlw	0x40			;Second line  LCD text       
			call	PrtPMChgL	;print string LCD "+ - to change sel to end"
			call	PrtPMChgS	;print string serial "+ - to change sel to end"

			bra		RCTst





;---------------------------------------------------------------
;Read configuration settings from EEPROM
ReadConfig:

		movlw 	.0		;EEPROM address
		movwf	DATA_EE_ADDR
					;Read byte from EEPROM
					;EE address in DATA_EE_ADDR
					;Returns EE data in W
		call	EERead
		movwf	TrigDelay	;Restore trigger delay
		movlw 	.1		;EEPROM address
		movwf	DATA_EE_ADDR
					;Read byte from EEPROM
					;EE address in DATA_EE_ADDR
					;Returns EE data in W
		call	EERead
		movwf	TimerStat2	;Restore LCD Backlight setting
		movlw 	.2		;EEPROM address
		movwf	DATA_EE_ADDR
					;Read byte from EEPROM
					;EE address in DATA_EE_ADDR
					;Returns EE data in W
		call	EERead
		movwf	TempCal	;Restore temperature calibration
		return

;---------------------------------------------------------------
;Reset configuration settings to defaults
;LaneE all lanes enabled
;AbortRaceTm Maximum race abort time
DefSet:

    movlw	.5				;Trigger delay value
	movwf	TrigDelay
	movlw	b'00101000'		;ClockStatus2  Bit 3 LCD Backlight = on  Rate units select Sec. per beat Bit 4=0,Bit 5=1
	movwf	TimerStat2
	clrf	TempCal

;---------------------------------------------------------------
;Save current settings to EEPROM
SaveSet:

		bsf		BTStat			;Save bluetooth state
		btfss	PORTC,BTOn
		bcf		BTStat


		movf	TrigDelay,w		;Save trigger delay value
		movwf	DATA_EE_DATA
		
		movlw 	.0		;EEPROM address
		movwf	DATA_EE_ADDR
		call	EEWrite

		movf	TimerStat2,w	;Save LCD Backlight setting
		movwf	DATA_EE_DATA
		
		movlw 	.1
		movwf	DATA_EE_ADDR
		call	EEWrite


		movf	TempCal,w		;Save temperature calibration
		movwf	DATA_EE_DATA
		
		movlw 	.2
		movwf	DATA_EE_ADDR
		call	EEWrite

		movlw	LCDL3P			;Line 3 LCD
		call	LCDADD		
		movlw	low SaveSEL		;Text: "Settings saved."
		movwf	TBLPTRL
		movlw	high SaveSEL	
		movwf	TBLPTRH
		call	prtstrl	

		movlw	low SaveSEL		;Text: "Settings saved."
		movwf	TBLPTRL
		movlw	high SaveSEL	
		movwf	TBLPTRH
		call	prtstrs	

		call	SerPrtCRLF
		call	BlinkLED
		call	LCDTxtUp			;Restore LCD text
		bcf		SetChg			;Clear changed setting warning
		return


;Write byte to EEPROM
;EE data in DATA_EE_DATA 
;EE address in DATA_EE_ADDR




;------------------------------------------------------------
; print strings "+ - to change." "Select when done."
;Print to LCD
;W = LCD text position
;W can be line 2 or 3 2nd line will be at line 3 or 4
PrtPMChgL:
 		movwf	PmTmp			;save cursor position.                   
		call	LCDADD		
		movlw	low ModeS0		;Text: "+ - To change."
		movwf	TBLPTRL
		movlw	high ModeS0	
		movwf	TBLPTRH
		call	prtstrl			;Print string LCD	

		movlw	LCDL2P		;Start at line 3?
		cpfseq	PmTmp
		bra		PrtPm1	
		movlw	LCDL3P	
		bra		PrtPm2	
PrtPm1:
		movlw	LCDL4P                      
PrtPm2:
		call	LCDADD		
		movlw	low ModeS1		;Text: "Select to end."
		movwf	TBLPTRL
		movlw	high ModeS1	
		movwf	TBLPTRH
		call	prtstrl	
		return

;------------------------------------------------------------
; print strings "+ - to change." "Select when done."
;Print to serial
PrtPMChgS:
		movlw	low ModeS0s	;Text: "Press + - to change, L when done."
		movwf	TBLPTRL
		movlw	high ModeS0s	
		movwf	TBLPTRH
		call	prtstrs			;Print string serial.
		return


;---------------------------------------------------------------

;Print initial messages to serial and LCD
LCDTxtUp:

		call	LCDCLR		;Clear screen

LCDTxtUpNC:

;Don't clear screen

;Greeting string
		movlw	low Greet	;Greeting string address lo
		movwf	TBLPTRL
		movlw	high Greet	;Greeting string address hi
		movwf	TBLPTRH
		call	prtstrs			;print string


		movlw	0x00			;First line  LCD text                           
		call	LCDADD		
		movlw	low LCDL1		;text "rate"
		movwf	TBLPTRL
		movlw	high LCDL1	
		movwf	TBLPTRH
		call	prtstrl
		movlw	LCDL1P+.7		;Cursor pos
		call	BeatDM			;Rate display mode select


		movlw	0x40			;Second line  LCD text                           
		call	LCDADD		
		movlw	low LCDL2		;text "Beat err"
		movwf	TBLPTRL
		movlw	high LCDL2	
		movwf	TBLPTRH
		call	prtstrl	

		movlw	0x14			;Third line  LCD text                           
		call	LCDADD		
		movlw	low LCDL3		;text "Rate ave"
		movwf	TBLPTRL
		movlw	high LCDL3	
		movwf	TBLPTRH
		call	prtstrl	
		movlw	LCDL3P+.7		;Cursor pos
		call	BeatDM			;Rate display mode select

		movlw	LCDL4P+.17		;cursor pos
		call	LCDADD
		movlw	"s"				;Unsaved settings warning
		btfsc	SetChg
		call	LCDSEND

		movlw	LCDL4P+.15
		call	LCDADD
		movlw	"l"				;Log enabled
		btfsc	TimerStat1,LogEnab	;Log enabled
		call	LCDSEND			;Enabled

		return
;Display rate mode on LCD "S" sec per beat, "M" beat per min "H" beat per hour
;Cursor pos in W
BeatDM:	
		call	LCDADD
		movlw	"s"				;Seconds per beat
		btfsc	SecPB
		bra		BDUp
		movlw	"h"
		btfss	BeatPHM
		bra		BDUp
		movlw	"m"
BDUp:	call	LCDSEND
		return



;----------------------------------------------------------------------------
;Setup serial I/O and buffers

SetupSerial:	movlw	0xc0		;set tris bits for TX and RX
;		iorwf	TRISC,F
		movlw	LOW	SerBaud		;set baud rate
		movwf	SPBRG
		movlw	HIGH SerBaud
		movwf	SPBRGH
		movlw	0x24		;enable transmission and high baud rate
		movwf	TXSTA
		movlw	0x90		;enable serial port and reception
		movwf	RCSTA
		bsf		BAUDCON,BRG16

;		lfsr	0,RxBuffer	;load start address of RX buffer
;		clrf	RxByteCount	;clear receive buffer data count
;		clrf	TxByteCount	;xmit too
;		clrf	Flags		;clear all flags
		return





;----------------------------------------------------------------------------
;Transmit data if there is data in the transmit buffer.

;TransmitSerial:	movf	TxByteCount,F	;check if data to be transmitted
;		btfsc	STATUS,Z
;		return			;return if no data to be transmitted
;;		call BlinkLED ;blink when send
;		btfss	PIR1,TXIF	;check if transmitter busy
;		return			;return if transmitter busy
;
;		movff	POSTINC1,TXREG	;get the data and transmit
;		decf	TxByteCount,F	;decrement number of bytes left
;		return


;----------------------------------------------------------------------------
;Get byte from serial make upper case.W-0 if no data
ReceiveSerUcase:
			movlw .0
			call	ReceiveSerial
			Movwf	MkUpper					;Save serial char

			xorlw	"+" 				;Non-alpha char "+"	
			bz		SpecChar			;Yes, return it no change.

			movf	MkUpper,W					;Restore char
			xorlw	"-" 				;Non-alpha char "-"	
			bz		SpecChar			;Yes, return it no change.

			movf	MkUpper,W
			andlw	b'11011111'			;Make alpha (a-z) upper case
			return
SpecChar:
			movf	MkUpper,W				;Restore non-alpha char & return
			return
;----------------------------------------------------------------------------
;Check if data received and if so, place in a buffer. Also check for <CR>.




ReceiveSerial:	btfss	PIR1,RCIF	;check if data
		return			;return if no data
;		movlw .1
;		call BlinkLED ;blink when data
		btfsc	RCSTA,OERR	;if overrun error occurred
		bra	ErrSerialOverr	;then go handle error
		btfsc	RCSTA,FERR	;if framing error occurred
		bra	ErrSerialFrame	;then go handle error

;		movlw	LOW RxBuffer+RX_BUF_LEN	;get end of buffer
;
;		movlw	LOW RxBuffer
;		addlw	RX_BUF_LEN


;		xorwf	FSR0L,W		;and compare with pointer
;		bz	ErrRxBufOver	;go handle error if buffer full

		movf	RCREG,W		;get received data
;		movwf	POSTINC0	;place in buffer and increment pointer
;;		incf	RxByteCount,F	;increment count of bytes received
;ReceiveSer1:	xorlw	0x0d		;compare with <CR>		
;		btfsc	STATUS,Z	;check if the same
;		bsf	Flags,ReceivedCR ;indicate <CR> character received
;		return

;potential error because Rx buffer is now full
;can do special error handling here - this code lets last byte be overwritten

;ErrRxBufOver:	movf	RCREG,W		;get received data
;		movwf	INDF0		;place in buffer without pointer incr
;		bra	ReceiveSer1

;error because OERR overrun error bit is set
;can do special error handling here - this code simply clears and continues

ErrSerialOverr:	bcf	RCSTA,CREN	;reset the receiver logic
		bsf	RCSTA,CREN	;enable reception again
		return

;error because FERR framing error bit is set
;can do special error handling here - this code simply clears and continues

ErrSerialFrame:	movf	RCREG,W		;discard received data that has error
		return


;----------------------------------------------------------------------------
;Copy data from receive buffer to transmit buffer to echo the line back



;CopyRxToTx:	tstfsz	TxByteCount	;check if TX buffer still has data
;		bra	ErrTxBufOver	;error if previous TX is still busy
;		movff	RxByteCount,TxByteCount ;copy number of bytes
;		lfsr	1,TxBuffer	;load start address of TX buffer
;		lfsr	0,RxBuffer	;load start address of RX buffer
;CopyRxTx1:
;		movff	POSTINC0,POSTINC1 ;copy from RX buffer to TX buffer
;		decfsz	RxByteCount,F	;decrement counter and see if all done
;		bra	CopyRxTx1	;repeat if not done
;
;		lfsr	1,TxBuffer	;load start address of TX buffer
;		lfsr	0,RxBuffer	;load start address of RX buffer
;		bcf	Flags,ReceivedCR ;clear indicator for <CR> received
;		call BlinkLED
;		return

;error because Tx buffer still has data and new data is available to transmit
;can do special error handling here - this code simply discards the new data

;ErrTxBufOver:	lfsr	0,RxBuffer	;load start address of RX buffer
;		clrf	RxByteCount	;clear receive buffer data count
;		bcf	Flags,ReceivedCR ;indicate <CR> not yet received
;		return


;----------------------------------------------------------------------------
;Send ASCII character on serial port

;TransmitChar:
;		btfss	PIR1,TXIF		;check if transmitter busy
;		goto	TransmitChar		;Loop until ready
;		movf	ccount,W 			;letter to print
;		addlw	0x40			;make ASCII
;		movwf	TXREG			;and transmit
;		decfsz	ccount
;		goto	TransmitChar	
;		return

TransmitCharW:					;Send char in W	
		btfss	PIR1,TXIF		;check if transmitter busy
		goto TransmitCharW		;Loop until ready
		movwf	TXREG			;transmit
		return


;----------------------------------------------------------------------------
;print string zero terminated SERIAL

prtstrs:
		tblrd*+			;read from table and inc ptr
		movf	TABLAT,W	; table data to w

		andlw	b'11111111'	
		bz		prtst1	;Last character 0?		
		call	TransmitCharW	;Output char rs-232
		bra		prtstrs
prtst1:	return

;----------------------------------------------------------------------------
;print string zero terminated LCD

prtstrl:	tblrd*+			;read from table and inc ptr
		movf	TABLAT,W	; table data to w

		andlw	b'11111111'	
		bz		prtst1l	;Last character 0?		
		call	LCDSEND	;Output char LCD
		bra		prtstrl
prtst1l:	return

;---------------------------------------------------------------------------
;Beat not valid. Reset timer and flag
;Delay before log starts to skip invalid data
BeatNotV:
			movlw	BeatVVal
			movwf	BeatVCnt			;Init valid beat delay counter
			bcf		TimerStat1,BeatValid		;Set data not valid
			bcf		TimerStat1,BeatFlag		;Start on same beat
;Clear any pending int
		bcf		INTCON,INT0IF		; clear Port a INT0  flag
		bsf		INTCON,INT0IE		;enable INT0



			movff	D5TMP0,SAve1
			movff	D5TMP1,SAve2
			movff	D5TMP2,SAve3
			movff	D5TMP3,SAve4

;		clrf	SAve1					;clear Running average total
;		clrf	SAve2
;		clrf	SAve3
;		clrf	SAve4

		clrf	BeatAR1
		clrf	BeatAR2
		clrf	BeatAR3
		clrf	BeatAR4

		clrf	BeatBR1
		clrf	BeatBR2
		clrf	BeatBR3
		clrf	BeatBR4
			return
;--------------------------------------------------------------------------
;Toggle RB0 to blink LED

BlinkLED:    
		movlw   .3	           ; Blink LED W times.
		movwf   bc1            
blinkc:
		BSF     LATC,LED        ; Turn on LED connected to 
		movlw	.20	       ; 100 ms delay
        CALL adj_del_ms
        BCF     LATC,LED        ; Turn off LED connected to 
        movlw	.20
        CALL    adj_del_ms 
        decfsz  bc1,f           
        goto    blinkc
		return


;----------------------------------------------------------------------
;Convert 16 bit to ASCII number
;input: DIVIDEND_HI,DIVIDEND_LO=16bit value
;Output: DIG1-5 = ASCII digits MSD=5,LSD=1

FIND_DIGITS 
	SETF    DIG1 
    SETF    DIG2 
    SETF    DIG3 
    SETF    DIG4 
FIND_DIG1 
    INCF    DIG1 
    MOVLW   LOW (.10000) 
    SUBWF   DIVIDEND_LO,F 
    MOVLW   HIGH(.10000) 
    SUBWFB  DIVIDEND_HI,F 
    BC      FIND_DIG1 
    
    MOVLW   LOW (.10000) 
    ADDWF   DIVIDEND_LO,F 
    MOVLW   HIGH(.10000) 
    ADDWFC  DIVIDEND_HI,F 
FIND_DIG2 
    INCF    DIG2 
    MOVLW   LOW (.1000) 
    SUBWF   DIVIDEND_LO,F 
    MOVLW   HIGH(.1000) 
    SUBWFB  DIVIDEND_HI,F 
    BC      FIND_DIG2 
    
    MOVLW   LOW (.1000) 
    ADDWF   DIVIDEND_LO,F 
    MOVLW   HIGH(.1000) 
    ADDWFC  DIVIDEND_HI,F 
FIND_DIG3 
    INCF    DIG3 
    MOVLW   .100 
    SUBWF   DIVIDEND_LO,F 
    BTFSC	STATUS,C
	GOTO	FIND_DIG3
    MOVLW	.1
	SUBWF	DIVIDEND_HI,F
	BTFSC	STATUS,C
	GOTO	FIND_DIG3

    MOVLW   .100 
    ADDWF   DIVIDEND_LO,F 
    BTFSC	STATUS,Z 
    INCF  	DIVIDEND_HI,F 
FIND_DIG4 
    INCF    DIG4 
    MOVLW   .10 
    SUBWF   DIVIDEND_LO,F 
    BC      FIND_DIG4 
    
    MOVLW   .10 
    ADDWF   DIVIDEND_LO,F 
FIND_DIG5
	MOVFF	DIVIDEND_LO,DIG5
;		Make digits ASCII numbers OR with 0x30
		movlw	0x30
		iorwf	DIG1,f
		iorwf	DIG2,f
		iorwf	DIG3,f
		iorwf	DIG4,f
		iorwf	DIG5,f

;suppress zero's
		cpfseq DIG1
		bra	lzsx
		movlw	0x20 ;space
		movwf	DIG1
		movlw	0x30
		cpfseq DIG2
		bra	lzsx
		movlw	0x20 ;space
		movwf	DIG2
		movlw	0x30
		cpfseq DIG3
		bra	lzsx
		movlw	0x20 ;space
		movwf	DIG3
;		movlw	0x30	;Leave last two LSD zero's
;		cpfseq DIG4
;		bra	lzsx
;		movlw	0x20 ;space
;		movwf	DIG4
;		movlw	0x30		
;		cpfseq DIG5
;		bra	lzsx
;		movlw	0x20 ;space
;		movwf	DIG5
lzsx				



	RETURN 


ReadADC:


;Configures the ADC
;for polling, 1.024V reference  AN8 input 

		movlw	b'10010000'		;Voltage reference enabled 1.024v
		movwf	VREFCON0


		MOVLW	B'10101111'		 ;right justify, Frc,
		MOVWF	ADCON2
		MOVLW	B'00001000'		 ;ADC ref = Vdd,Vss
		MOVWF	ADCON1

		BSF	TRISC,RC6 			;Set RC6 to input
		BSF	ANSELH,ANS8			;Set RC6 to analog
		MOVLW	B'00100001'		;AN8, ADC on
		MOVWF	ADCON0

		BSF	ADCON0,GO			;Start conversion
ADCPoll:
		BTFSC	ADCON0,GO		;Is conversion done?
		BRA	ADCPoll				;No, test again
; Result is complete - store 2 MSbits in
; RESULTHI and 8 LSbits in RESULTLO
		MOVFF	ADRESH,ADCHI
		MOVFF	ADRESL,ADCLO
		movlw	B'00000011'

		andwf	ADCHI,F


;Calculate simple running average (IIR filter)
;Add new value to average value
	movf	ADCLO,W
	addwf	ADCLOA,F
	movf	ADCHI,W
	addwfc	ADCHIA,F	

;Divide by 2 for running average

	bcf		STATUS,C
	rrcf	ADCHIA
	rrcf	ADCLOA

		



		return


DwordToSer: ;Send ASCII number to serial port
;Must call DwordToBCD to convert number first

		movf	DIG1,w
		xorlw	0x20 				;Skip spaces
		bz		sksp1
		movf	DIG1,w
		call	TransmitCharW
sksp1:	movf	DIG2,w
		xorlw	0x20
		bz		sksp2
		movf	DIG2,w
		call	TransmitCharW
sksp2:	movf	DIG3,w
		xorlw	0x20
		bz		sksp3
		movf	DIG3,w
		call	TransmitCharW
sksp3:	movlw	"."		;mS Displayed as x.xxx sec

;		movlw	"."		;Place decimal point
		btfsc	SecPBD	;Decimal point for seconds per beat?	
		call 	TransmitCharW	;Yes, ms Displayed as xxx.xxxxxxx sec

;		call 	TransmitCharW
		movf	DIG4,w
		xorlw	0x20
		bz		sksp4
		movf	DIG4,w
		call	TransmitCharW
sksp4:	movf	DIG5,w
		xorlw	0x20
		bz		sksp5
		movf	DIG5,w
		call	TransmitCharW
sksp5:	movf	DIG6,w
		xorlw	0x20
		bz		sksp6
		movf	DIG6,w
		call	TransmitCharW
sksp6:	movf	DIG7,w
		call	TransmitCharW

		movlw	"."		;Place decimal point
		btfss	SecPBD	;Decimal point for beats per hour,Min??	
		call	TransmitCharW


		movf	DIG8,w
		call	TransmitCharW
		movf	DIG9,w
		call	TransmitCharW
		movf	DIG10,w
		call	TransmitCharW

		return

;----------------------------------------------------------------------------

ByteToSer: ;Send 8 bits ASCII number to serial port
;Must call DwordToBCD to convert number first


		movf	DIG8,w
		xorlw	0x30 				;Skip zeros
		bz		sksp1b
		movf	DIG8,w
		call	TransmitCharW
sksp1b:	movf	DIG9,w
		xorlw	0x30
		bz		sksp2b
		movf	DIG9,w
		call	TransmitCharW
sksp2b:
		movf	DIG10,w
		call	TransmitCharW
		return

;----------------------------------------------------------------------------
; print Return,Linefeed
SerPrtCRLF:
		movlw  	0x0d ;CR	
		call	TransmitCharW
		movlw  	0x0a ;LF	
		call	TransmitCharW

		return

;----------------------------------------------------------------------------

; print comma for CSV file
SerPrtCSV:
		movlw  	','	
		call	TransmitCharW

		return
;----------------------------------------------------------------------------

; print period to serial
SerPrtPer:
		movlw  	'.'	
		call	TransmitCharW

		return
;----------------------------------------------------------------------------

; print space to serial
SerPrtSpa:
		movlw  	' '	
		call	TransmitCharW

		return
;---------------------------------------------------------------------------
OnToSer: ;Print "On" to serial port
           
		call	LCDADD		
		movlw	low TxtOn	
		movwf	TBLPTRL
		movlw	high TxtOn	
		movwf	TBLPTRH
		call	prtstrs			;print string LCD
		return


OffToSer: ;Print "Off" to serial port
           
		call	LCDADD		
		movlw	low TxtOff	
		movwf	TBLPTRL
		movlw	high TxtOff	
		movwf	TBLPTRH
		call	prtstrs			;print string LCD
		return

;----------------------------------------------------------------------------

;3-1/2 bytes to ASCII number on lcd. Didn't need highest nybble
;input: W=cursor position, BINL1,BINH1,BINL2,BINH2=28bit value
;Output: DIG1-9

DWordToLCD:                            

		call	LCDADD		 		;Cursor pos in W

		call	DWordToBCD 			;Convert to ASCII

		movf	DIG1,w
		call	LCDSEND
		movf	DIG2,w
		call	LCDSEND
		movf	DIG3,w
		call	LCDSEND
	
		movlw	"."		;Place decimal point
		btfsc	SecPBD	;Decimal point for seconds per beat?	
		call 	LCDSEND	;Yes, ms Displayed as xxx.xxxxxxx sec

		movf	DIG4,w
		call	LCDSEND
		movf	DIG5,w
		call	LCDSEND
		movf	DIG6,w
		call	LCDSEND
		movf	DIG7,w
		call	LCDSEND

		movlw	"."		;Place decimal point
		btfss	SecPBD	;Decimal point for beats per hour,Min??	
		call	LCDSEND

		movf	DIG8,w
		call	LCDSEND
		movf	DIG9,w
		call	LCDSEND
		movf	DIG10,w
		call	LCDSEND
		return



;----------------------------------------------------------------------------

ByteToLCD: ;Send 8 bits ASCII number to LCD
;Must call DwordToBCD to convert number first
;Leading zero's suppressed with space
;W = LCD cursor location



		call	LCDADD		 		;Cursor pos in W

		movlw	0x30 	;Suppress Zero
		cpfseq DIG8
		bra	btlc
		movlw	0x20 	;ASCII Space
		movwf	DIG8

		movlw	0x30
		cpfseq DIG9
		bra	btlc
		movlw	0x20
		movwf	DIG9
btlc:
		movf	DIG8,w
		call	LCDSEND
		movf	DIG9,w
		call	LCDSEND
		movf	DIG10,w
		call	LCDSEND
		return



;--------------------------------------------------------------------------
;3-1/2 bytes to ASCII number. 
;input: W=cursor position, BINL1,BINH1,BINL2,BINH2=32 bit value
;Output: DIG1-9
DWordToBCD:                 clrf    BCDL1
             			    clrf    BCDH1
    			            clrf    BCDL2
							clrf	BCDH2
							clrf	BCDL3
;							clrf	BCDH3


                 movlw   .32
                 movwf   COUNT
ConvertBit:
                 rlcf    BINL1,F
                 rlcf    BINH1,F
                rlcf    BINL2,F
                rlcf    BINH2,F

                 movf    BCDL1,W
                 addwfc  BCDL1,W
                 daw
                 movwf   BCDL1

                 movf    BCDH1,W
                 addwfc  BCDH1,W
                 daw
                 movwf   BCDH1
  
                movf    BCDL2,W
                addwfc  BCDL2,W
                daw
                movwf   BCDL2

                movf    BCDH2,W
                addwfc  BCDH2,W
                daw
                movwf   BCDH2
   


				movf    BCDL3,W
				addwfc  BCDL3,W
                daw
                movwf   BCDL3

                 decfsz  COUNT
                 bra     ConvertBit
; now convert packed BCD to ASCII


	movf	BCDL1,W
	andlw	0x0f		;Mask high nybble
	movwf	DIG10
	movlw	0x30		;Make ASCII digit
	iorwf	DIG10,F
	swapf	BCDL1		;swap nybbles
	movf	BCDL1,W
	andlw	0x0f
	movwf	DIG9
	movlw	0x30
	iorwf	DIG9,f



	movf	BCDH1,W ;BCDL2,W
	andlw	0x0f
	movwf	DIG8
	movlw	0x30
	iorwf	DIG8,F
	swapf	BCDH1
	movf	BCDH1,W
	andlw	0x0f
	movwf	DIG7
	movlw	0x30
	iorwf	DIG7,f





	movf	BCDL2,W ;BCDH1,W
	andlw	0x0f
	movwf	DIG6
	movlw	0x30
	iorwf	DIG6,F
	swapf	BCDL2
	movf	BCDL2,W
	andlw	0x0f
	movwf	DIG5
	movlw	0x30
	iorwf	DIG5,f




	movf	BCDH2,W
	andlw	0x0f
	movwf	DIG4
	movlw	0x30
	iorwf	DIG4,F
	swapf	BCDH2
	movf	BCDH2,W
	andlw	0x0f
	movwf	DIG3
	movlw	0x30
	iorwf	DIG3,f




	movf	BCDL3,W
	andlw	0x0f
	movwf	DIG2
	movlw	0x30
	iorwf	DIG2,F
	swapf	BCDL3
	movf	BCDL3,W
	andlw	0x0f
	movwf	DIG1
	movlw	0x30
	iorwf	DIG1,f





;suppress leading zero's

		movlw	0x30 	;ASCII Zero
		cpfseq DIG1
		bra	lzsxw
		movlw	0x20 	;ASCII Space
		movwf	DIG1

		movlw	0x30
		cpfseq DIG2
		bra	lzsxw
		movlw	0x20
		movwf	DIG2


		btfsc	SecPBD	;Seconds per beat
		bra		lzsxw	;Yes, skip extra LZS

		movlw	0x30
		cpfseq DIG3
		bra	lzsxw
		movlw	0x20 
		movwf	DIG3

		movlw	0x30
		cpfseq DIG4
		bra	lzsxw
		movlw	0x20 
		movwf	DIG4

		movlw	0x30		
		cpfseq DIG5
		bra	lzsxw
		movlw	0x20
		movwf	DIG5

		movlw	0x30		
		cpfseq DIG6
		bra	lzsxw
		movlw	0x20
		movwf	DIG6

;		movlw	0x30		
;		cpfseq DIG7
;		bra	lzsxw
;		movlw	0x20
;		movwf	DIG7


lzsxw

                 return
 


;------------------------------------------------------------------

;!!!!!!! currently not used !!!!!!!!!!
;WordToLCD: ;two bytes to ASCII number on lcd
;input: W=cursor position, DIVIDEND_HI,DIVIDEND_LO=16bit value
;Output: DIG1-5

                             
		call	LCDADD		 		;Cursor pos in W

		call	FIND_DIGITS 		;Convert 16bit in dividendh,l to ASCII number

		movf	DIG1,w
		call	LCDSEND
		movf	DIG2,w
		call	LCDSEND
		movf	DIG3,w
		call	LCDSEND
		movf	DIG4,w
		call	LCDSEND
		movf	DIG5,w
		call	LCDSEND
		return
;------------------------------------------------------------------
OnToLCD: ;Print "On" to LCD at pos in W
           
		call	LCDADD		
		movlw	low TxtOn	
		movwf	TBLPTRL
		movlw	high TxtOn	
		movwf	TBLPTRH
		call	prtstrl			;print string LCD
		return

;------------------------------------------------------------------
OffToLCD: ;Print "On" to LCD at pos in W
           
		call	LCDADD		
		movlw	low TxtOff	
		movwf	TBLPTRL
		movlw	high TxtOff	
		movwf	TBLPTRH
		call	prtstrl			;print string LCD
		return
;------------------------------------------------------------------
BeatOnLCD:	;LCD beat indicator on
		movlw	LCDL4P+.19
		call	LCDADD	
		movlw	"*"
		call	LCDSEND
		return
;------------------------------------------------------------------
BeatOffLCD:	;LCD beat indicator off
		movlw	LCDL4P+.19
		call	LCDADD	
		movlw	" "
		call	LCDSEND
		return

;------------------------------------------------------------------
IncTime:
;Count time HH:MM:SS
		incf TimeSS
		movlw	.60
		cpfseq	TimeSS
		return
		clrf	TimeSS
		incf	TimeMM

;		movlw	.60		
		cpfseq	TimeMM
		return

		clrf	TimeMM
		incf	TimeHH

		movlw	.13
		cpfseq	TimeHH
		return

		movlw	.1
		movwf	TimeHH
		return

;-----------------------------------------------------------------
;Count up by one minute
IncTimeM:	
;Count time HH:MM:SS
;		incf TimeSS
;		movlw	.60
;		cpfseq	TimeSS
;		return
;		clrf	TimeSS
		incf	TimeMM

		movlw	.60		
		cpfseq	TimeMM
		return

		clrf	TimeMM
		incf	TimeHH

		movlw	.13
		cpfseq	TimeHH
		return

		movlw	.1
		movwf	TimeHH
		return

;-----------------------------------------------------------------
;Count down by one minute
DecTimeM:	
;Count time HH:MM:SS
;		incf TimeSS
;		movlw	.60
;		cpfseq	TimeSS
;		return
;		clrf	TimeSS
		decf	TimeMM

		movlw	0xff		
		cpfseq	TimeMM
		return
		movlw	 .59
		movwf	TimeMM

		decf	TimeHH
		movlw 	.0
		cpfseq	TimeHH
		return
		movlw	.12
		movwf	TimeHH
		return

;-----------------------------------------------------------------

TimeToLCD:
;LCD Position in W
;Prints hh:mm:ss
		call	LCDADD

		clrf	DIVIDEND_HI
		movff	TimeHH,DIVIDEND_LO
		Call	FIND_DIGITS		;16bit to ascii
		movf	DIG4,w
		call	LCDSEND
		movf	DIG5,w
		call	LCDSEND
		movlw	0x3a	; ":"
		call	LCDSEND

		clrf	DIVIDEND_HI
		movff	TimeMM,DIVIDEND_LO
		Call	FIND_DIGITS		;16bit to ascii
		movf	DIG4,w
		call	LCDSEND
		movf	DIG5,w
		call	LCDSEND
		movlw	0x3a	; ":"
		call	LCDSEND


		clrf	DIVIDEND_HI
		movff	TimeSS,DIVIDEND_LO
		Call	FIND_DIGITS		;16bit to ascii
		movf	DIG4,w
		call	LCDSEND
		movf	DIG5,w
		call	LCDSEND

		return

;-----------------------------------------------------------------
TimeToSer:

;Prints hh:mm:ss to serial


		clrf	DIVIDEND_HI
		movff	TimeHH,DIVIDEND_LO
		Call	FIND_DIGITS		;16bit to ascii
		movf	DIG4,w
		call	TransmitCharW
		movf	DIG5,w
		call	TransmitCharW
		movlw	0x3a	; ":"
		call	TransmitCharW

		clrf	DIVIDEND_HI
		movff	TimeMM,DIVIDEND_LO
		Call	FIND_DIGITS		;16bit to ascii
		movf	DIG4,w
		call	TransmitCharW
		movf	DIG5,w
		call	TransmitCharW
		movlw	0x3a	; ":"
		call	TransmitCharW


		clrf	DIVIDEND_HI
		movff	TimeSS,DIVIDEND_LO
		Call	FIND_DIGITS		;16bit to ascii
		movf	DIG4,w
		call	TransmitCharW
		movf	DIG5,w
		call	TransmitCharW

		return

;-------------------------------------------------------------
;Temperature to LCD display

TempToLCD: ;two bytes to ASCII number on lcd
;input: W=cursor position, DIVIDEND_HI,DIVIDEND_LO=16bit value
;Output: DIG1-5

                             
		call	LCDADD		 		;Cursor pos in W
		call	FIND_DIGITS 		;Convert 16bit in dividendh,l to ASCII number

		movlw	0x30 	;Suppress leading Zero
		cpfseq DIG2		;Is it a zero?
		bra	tlcd1
		movlw	0x20 	;Replace with ASCII Space
		movwf	DIG2

		movlw	0x30
		cpfseq DIG3
		bra	tlcd1
		movlw	0x20
		movwf	DIG3
tlcd1:
		movf	DIG2,w
		call	LCDSEND
		movf	DIG3,w
		call	LCDSEND
		movf	DIG4,w
		call	LCDSEND
		movlw	"."		;mV temp Displayed as xxx.x degrees.
		call	LCDSEND
		movf	DIG5,w
		call	LCDSEND
		return

;************************************************************
;Temperature to serial port.

TempToSer:

                           
		call	LCDADD		 		;Cursor pos in W
		call	FIND_DIGITS 		;Convert 16bit in dividendh,l to ASCII number

		movlw	0x30 	;Suppress leading Zero
		cpfseq DIG2		;Is it a zero?
		bra	tlsp1
		movlw	0x20 	;Replace with ASCII Space
		movwf	DIG2

		movlw	0x30
		cpfseq DIG3
		bra	tlsp1
		movlw	0x20
		movwf	DIG3
tlsp1:
		movf	DIG2,w
		call	TransmitCharW
		movf	DIG3,w
		call	TransmitCharW
		movf	DIG4,w
		call	TransmitCharW
		movlw	"."		;mV temp Displayed as xxx.x degrees.
		call	TransmitCharW
		movf	DIG5,w
		call	TransmitCharW
		return

;*************************************************************
; Calls the delay_1ms W times
;*************************************************************
delaymsw
	movwf	d0ms
dly_loop
	call	delay_1msm	;2
	decfsz	d0ms, F		;1(2)
	goto	dly_loop	;2
	return


;*************************************************************	
; 1ms delay.
; Modify this to match your processor speed.
; http://www.piclist.org/techref/piclist/codegen/delay.htm
;*************************************************************
delay_1msm

;	movlw	0xF3 ;4mhz		;2498 cycles
	movlw	0xC6 ;20mhz		;12513 cycles
	movwf	d1ms
;	movlw	0x02 ;4mhz
	movlw	0x0A ;20mhz
	movwf	d2ms
Delay_0
	decfsz	d1ms, f
	goto	$+4
	decfsz	d2ms, f
	goto	Delay_0
	goto	$+2		;2 cycles
	return			;4 cycles (including call)



;------------------------------------------------------------------------
;Read byte from EEPROM
;EE address in DATA_EE_ADDR
;Returns EE data in W
EERead:
	MOVF	 DATA_EE_ADDR,w
	MOVWF	 EEADR 			;Data Memory Address to read
	BCF		 EECON1, EEPGD 	;Point to DATA memory
	BCF		 EECON1, CFGS 	;Access EEPROM
	BSF		 EECON1, RD		;EEPROM Read
	MOVF	 EEDATA, W		;W = EEDATA
	return

;------------------------------------------------------------------------
;Write byte to EEPROM
;EE data in DATA_EE_DATA 
;EE address in DATA_EE_ADDR

EEWrite:
	MOVF	 DATA_EE_ADDR,w 
	MOVWF	 EEADR 			;Data Memory Address to write
	MOVf	 DATA_EE_DATA ,w
	MOVWF	 EEDATA 			;Data Memory Value to write
	BCF		 EECON1, EEPGD 	;Point to DATA memory
	BCF		 EECON1, CFGS 	;Access EEPROM
	BSF		 EECON1, WREN 	;Enable writes
	BCF		INTCON, GIEH	 ;Disable Interrupts
	MOVLW	 55h 
	MOVWF	 EECON2			 ;Write 55h
	MOVLW	 0AAh 
	MOVWF	 EECON2 		;Write 0AAh
	BSF		 EECON1, WR		 ;Set WR bit to begin write
	BSF		 INTCON, GIEH 	;Enable Interrupts

WaitWR:	btfsc	EECON1,WR				;wait for write to complete
	bra		WaitWR
	BCF		 EECON1, WREN	; Disable writes on write complete (EEIF set)
	return

;-----------------------------------------------------------------------


;Divide  48 by 24
;****************************************************
; result upto 48 bits !
;
; Formula:      Dividend = Dividend/Divisor
;       
; Format:       Little endian, Ram = msb, Ram+x = lsb ( where x=bytesize-1)
; Ram used:     Dividend 6 bytes ( 48 bits )
;               Divisor 3 bytes ( 24 bits )
;               Temp 3 bytes 
;               BitCount 1 byte for loop counting ( and temp. saving of carry )
; 
; Divisor is preserved
; Dividend holds result
; Returns with zero in W if failed ( division with zero )
; Else returns with one in w
; 
; Based on pseudo-code from Nikolai Golovchenko [golovchenko@mail.ru]
; 
;max time in loop: 30 cycles


DIVIDE_48by24

        ; Test for zero division
        MOVF    Divisor,W
        IORWF   Divisor+1,W
        IORWF   Divisor+2,W
        BTFSC   STATUS,Z
        RETLW   0x00    ; divisor = zero, not possible to calculate return with zero in w

        ; prepare used variables
        CLRF    Temp
        CLRF    Temp+1
        CLRF    Temp+2

        clrf    Temp2

        MOVLW   D'48'           ; initialize bit counter
        MOVWF   BitCount

DIVIDE_LOOP_48by24
        RLcF     Dividend+5,F
        RLcF     Dividend+4,F
        RLcF     Dividend+3,F
        RLcF     Dividend+2,F
        RLcF     Dividend+1,F
        RLcF     Dividend,F
        ; shift in highest bit from dividend through carry in temp
        RLcF     Temp+2,F
        RLcF     Temp+1,F
        RLcF     Temp,F

        rlcf     Temp2, f

        MOVF    Divisor+2,W     ; get LSB of divisor
        btfsc   Temp2, 7
        goto    Div48by24_add

        ; subtract 24 bit divisor from 24 bit temp
        SUBWF   Temp+2,F        ; subtract

        MOVF    Divisor+1,W     ; get middle byte
;        SKPC                    ;  if overflow ( from prev. subtraction )
        BTFSs   STATUS,C     
        INCFSZ  Divisor+1,W     ; incresase source
        SUBWF   Temp+1,F        ; and subtract from dest.

        MOVF    Divisor,W       ; get top byte
;       SKPC                    ;  if overflow ( from prev. subtraction )
        BTFSs   STATUS,C 
        INCFSZ  Divisor,W       ; increase source
        SUBWF   Temp,F          ; and subtract from dest.

        movlw 1
;        skpc
        BTFSs   STATUS,C 
         subwf   Temp2, f
        GOTO    DIVIDE_SKIP_48by24 ; carry was set, subtraction ok, continue with next bit

Div48by24_add
        ; result of subtraction was negative restore temp
        ADDWF   Temp+2,F        ; add it to the lsb of temp

        MOVF    Divisor+1,W     ; middle byte
        BTFSC   STATUS,C        ; check carry for overflow from previous addition
        INCFSZ  Divisor+1,W     ; if carry set we add 1 to the source
        ADDWF   Temp+1,F        ; and add it if not zero in that case Product+Multipland=Product

        MOVF    Divisor,W       ; MSB byte
        BTFSC   STATUS,C        ; check carry for overflow from previous addition
        INCFSZ  Divisor,W
        ADDWF   Temp,F          ; handle overflow

        movlw 1
;        skpnc
        BTFSc   STATUS,C 
         addwf   Temp2, f

DIVIDE_SKIP_48by24
        DECFSZ  BitCount,F      ; decrement loop counter
        GOTO    DIVIDE_LOOP_48by24      ; another run
        ; finally shift in the last carry
        RLcF     Dividend+5,F
        RLcF     Dividend+4,F
        RLcF     Dividend+3,F
        RLcF     Dividend+2,F
        RLcF     Dividend+1,F
        RLcF     Dividend,F
        RETLW   0x01    ; done

;****************************************************
;Create divide macro code
	mkdiv Divide, Dividend, Divisor, Temp, BitCount, d'64', d'32', UNSIGNED 


	end

