;******************************************************************************************************
; GPS-Based Frequency Standard, By Bertrand Zauhar, VE2ZAZ
; For more details, visit VE2ZAZ's website at: 
; http://www3.sympatico.ca/b.zauhar 
;******************************************************************************************************
; Filename: GPSstd_main.asm 
; Date: 17/03/2009 
; Firmware Version: 4 
;
; Designed to run on PICmicro PIC18F2220.
; 
; Author: Bertrand Zauhar 

; Changes in Version 4:
; - Added the 10MHZ/5MHz bootup OCXO selection via pin RB0
; - Added the Alarm latch clear function via a pushbutton on pin RB1
; - Modernized the CONFIG instructions to comply with the new assembler directive format
; - Added a RAM clearing loop at bootup and deleted corresponding individual register CLRF commands
; - Turned on the Brownout Voltage Detect (required to fix an EEPROM glitch on the PIC Micro)
; 
;******************************************************************************************************
; Files required: P18F2220.INC 
; Assembles using Microchip's MPASM assembler software
;******************************************************************************************************

 LIST P=18F2220 ;directive to define processor
 #include <P18F2220.INC> ;processor specific variable definitions

;******************************************************************************************************
;Configuration bits
; The CONFIG directives defines configuration data within the .ASM file.
; The labels following the directive are defined in the P18F2220.INC file.
; The PIC18F2220/2320/4220/4320 Data Sheet explains the functions of the
; configuration bits.

;CONFIG1H
 CONFIG OSC = INTIO2, FSCM = OFF, IESO = OFF
;CONFIG2L
 CONFIG PWRT = OFF, BOR = ON, BORV = 20 
;CONFIG2H
 CONFIG WDT = OFF
;CONFIG3H
 CONFIG MCLRE = ON, PBAD = DIG, CCP2MX = B3
;CONFIG4L
 CONFIG DEBUG = OFF, LVP = ON, STVR = OFF
;CONFIG5L
 CONFIG CP0 = OFF, CP1 = OFF
;CONFIG5H
 CONFIG CPB = OFF, CPD = OFF
;CONFIG6L
 CONFIG WRT0 = OFF, WRT1 = OFF
;CONFIG6H
 CONFIG WRTB = OFF, WRTC = OFF, WRTD = OFF 
;CONFIG7L
 CONFIG EBTR0 = OFF, EBTR1 = OFF 
;CONFIG7H
 CONFIG EBTRB = OFF

;******************************************************************************************************
;Bank 1 has 256 locations available
;Bank 0 is skipped to simplify variable access.

 CBLOCK 0x100 ;All of these variables are located in the RAM Bank 1.

 WREG_TEMP ;0_variable used for context saving when interrupt occurs
 STATUS_TEMP ;1_variable used for context saving when interrupt occurs
 BSR_TEMP ;2_variable used for context saving when interrupt occurs

 FREQ_MEAS_STAT ;3_GPS 1PPS capture process and frequency measurement status byte
 ; 7-End of Dither done
 ; 6-Dither denied (end of DAC registers reached)
 ; 5-New Dither cycle flag
 ; 4-Frequency change req'd 
 ; 3-Frequency increase (1) / decrease (0) req'd
 ; 2-Fine (0) / Coarse (1) frequency adjustment req'd
 ; 1-New capture value available flag
 ; 0-FLL running (1) or in manual (0) mode flag

 FREQ_MEAS_STAT2 ;4_Second Status/Flag register
 ; 7-(not used)
 ; 6-(not used)
 ; 5-(not used)
 ; 4-FLL in holdover (1) or Locked (0) 
 ; 3-"In sampling" phase flag
 ; 2-FLL locked(0) or unlocked (1) current status
 ; 1-bit to specify when in stabilization cycle after freq. change is 
 pdate required after CCP interrupt (including no change of frequency)

 FREQ_ALM_STAT ;5_GPS 1PPS capture process and frequency measurement status byte
 ; 7-(not used)
 ; 6-(not used)
 ; 5-(not used)
 ; 4-(not used)
 ; 3-Holdover period expired alarm
 ; 2-Low-side (1) end of DAC reached alarm. 
 ; 1-High-side (1) end of DAC reached alarm.
 ; 0-FLL in Lock (0), unlocked(1) alarm

 LED_STAT ;6_LED status and control register
 ; 7-(not used)
 ; 6-(not used)
 ; 5-(not used)
 ; 4-(not used)
 ; 3-This flag is used to signal when a CCP1 interrupt just happened
 ; 2-This flag is used to signal when CCP1 (1 PPS) is high
 ; 1-Unlocked (Red) LED status (1 is on, 0 is off)
 ; 0-Locked (Green) LED status (1 is on, 0 is off)

 TX_RX_STAT ;7_This is the USART status flag register 
 ; 7-Request to transmit Startup prompt
 ; 6-transmit Help menu being performed
 ; 5-Request to transmit Help menu
 ; 4-Request to transmit FLL information
 ; 3-tx cycle being performed.
 ; 2-Request to transmit settings information
 ; 1-LF character received (end of user command entry)
 ; 0-New character transmission cycle required

 GENERAL1_STAT ;8_This is the USART status flag register 
 ; 7-(not used)
 ; 6-(not used)
 ; 5-(not used)
 ; 4-(not used) 
 ; 3-(not used)
 ; 2-(not used)
 ; 1-GPS 1PPS Loss Of Signal flag
 ; 0-Flags when a FLL parameters EEPROM Write cycle is required

 FREQ160_REG_L ;9_LSB of frequency calculation
 FREQ160_REG_H ;10_MSB of frequency calculation
 ; FREQ160_REG is ((65535 - CCPR1H/L initial) + CCPR1H/L final).
 ; The number of Timer1 interrupts is not considered and assumed to be 2441.

 OLD_CCPR1L ;11_LSB of previous CCPR1L value
 OLD_CCPR1H ;12_LSB of previous CCPR1L value

 PWM_DITH_CTR ;13_PWM Dither counter.

 PWM_DUTY_L ;14_PWM duty cycle register, lower 8 bits 
 PWM_DUTY_H ;15_PWM duty cycle output register, higher 2 bits

 PWM_DUTY_DITH ;16_PWM dither register (4 additional bits)

 TEMP1_HI ;17_Temporary 16-bit variable available throughout code execution.
 TEMP1_LO ;18_ "

 TEMP2_HI ;19_Temporary 16-bit variable available throughout code execution.
 TEMP2_LO ;20_ "

 TEMP3_HI ;21_Temporary 16-bit variable available throughout code execution.
 TEMP3_LO ;22_ "


 DITHER_LIMIT ;23_This is the limit by which a fine or coarse freq adj is made.

 PWM_DITH_L ;24_PWM_DUTY_L during the dither cycle (PWM_DITH_L may equal PWM_DUTY_L + 1
 PWM_DITH_H ;25_PWM_DUTY_H during the dither cycle (PWM_DITH_H may equal PWM_DUTY_H + 1

 FILT_AVG_CTR_H ;26_This is the counter used to count how many samples are taked in the frequency averaging process
 FILT_AVG_CTR_L ;27_"

 FILT_AVG_VAL_H ;28_16-bit signed variable to track frequency delta from ideal frequency during averaging process
 FILT_AVG_VAL_L ;29_ " 

 FILT_AVG_LIMIT_H ;30_This is the number of frequency samples taken during averaging process
 FILT_AVG_LIMIT_L ;31_ " 

 FILT_AVG_CTR_STOR_H ;32_This is equal to FILT_AVG_CTR_H/L and is used to store value to be re-used by USART Tx string routine
 FILT_AVG_CTR_STOR_L ;33_ "

 FILT_AVG_VAL_STOR_H ;34_This is equal to FILT_AVG_VAL_H/L and is used to store value to be re-used by USART Tx string routine
 FILT_AVG_VAL_STOR_L ;35_ "

 SAMPLE_CTR_H ;36_16 bit Counter that increments every frequency sample. Displayed for statistical purpose
 SAMPLE_CTR_L ;37_ "

 LOCK_LIMIT ;38_;This is the frequency offset threshold beyond which the FLL will switch from Locked to Holdover or Unlocked mode. The
 ; FLL will also switch back to Locked state when the frequency delta is less than this threshold.

 FREQ_DELTA_H ;39_16-bit signed variable to store frequency delta from ideal frequency for one sample
 FREQ_DELTA_L ;40_ "

 HOLDOVER_CTR ;41_This is the counter of frequency samples (16 secs each) during holdover. 

 HOLDOVER_CTR_LIMIT ;42_This is the threshold of frequency samples allowed to stay in holdover mode. Beyond
 ;this threshold, the FLL will switch to Unlocked.

 HOLDOVER_LIMIT ;43_This is the threshold value beyond which the FLL will go into holdover.

 WRT_EEPROM_POS ;44_EEPROM Writing Counter. Indicates what parameter to write in EEPROM

 GPS_LOS_2SEC_CTR ;45_This counter counts the number of Timer0 2-second cycles. Will count up to 8 (16 sec)

 FREQ_CHG_THRESH ;46_This is the threshold value beyond which a frequency change will happen, otherwise it will be cancelled.

 CTRL_REF_OUT_MODE ;47_The Reference output control line register.

 FILT_AVG_VAL_L_ABS ;48_This is the absolute value of average frequency difference (L) after sampling cycle

 VCXO_SLOPE_MODE ;49_The VCXO frequency adjustment slope: 0x01 = positive, 0x02 = negative

 FLL_AVG_MODE ;50_The FLL averaging mode: 0x01 = sample voting, 0x02 = sample summing

 CCP1_INT_CTR ;51_The counter used to count 16 CCP1 (GPS PPS) interrupts before processing read frequency.

 NOMINAL_FREQ_VAL_H ;52_Holds the nominal value H to compare to measured value
 NOMINAL_FREQ_VAL_L ;53_Holds the nominal value L to compare to measured value

 
 ENDC ;########### Maximum 128 variables in this block!############.

 CBLOCK 0x180
 SERIAL_RX_BUFF ;Serial USART Receive Buffer memory. 16 positions reserved.
 ENDC

 CBLOCK 0x190
 SERIAL_TX_BUFF ;Serial USART Transmit Buffer memory.
 ENDC

;******************************************************************************************************
;Constant definitions

 ;Bit Positions
gps_1pps EQU .2 ;PortC bit2, GPS 1pps input
led_green_out EQU .3 ;PortC bit3, Green LED Anode
led_red_out EQU .4 ;PortC bit4, Red LED Anode
led_green_stat EQU .0 ;Locked LED status bit position in LED_STAT
led_red_stat EQU .1 ;Unlocked LED status bit position in LED_STAT
ref_10m_ctrl EQU .1 ;PortC bit3, 10MHz reference control pin
ccp_high EQU .2 ;CCP1 is high bit position in LED_STAT
alm_fll_unlock EQU .0 ;FLL locked (0) or unlocked (1) alarm bit position in FREQ_ALM_STAT
stat_fll_unlock EQU .2 ;FLL locked (0) or unlocked (1) current state bit position
highside_end EQU .1 ;high-side end of DAC bit position in FREQ_ALM_STAT
lowside_end EQU .2 ;low-side end of DAC bit position in FREQ_ALM_STAT
freq_inc_dec EQU .3 ;Frequency increase (1) / decrease (0) bit position in FREQ_MEAS_STAT
freq_chg EQU .4 ;Frequency change bit position in FREQ_MEAS_STAT
freq_coarse_fine EQU .2 ;Coarse (1) / Fine (0) Frequency change bit position in FREQ_MEAS_STAT
freq_upd_req EQU .0 ;Frequency update required (CCP value avail.) bit position in FREQ_MEAS_STAT
new_dith_cycle EQU .5 ;position of new dither cycle bit
lf_eoc_received EQU .1 ;position of the new cycle of character reception is required
send_info EQU .2 ;position of the bit to request sending settings information
tx_cycle_on EQU .3 ;position of the tx cycle being performed flag
tx_fll_info_req EQU .4 ;bit to request to transmit FLL information string on USART
in_sampling_phase EQU .3 ;Flags that the FLL is in a sampling phase.
holdover_flag EQU .4 ;Flags that the FLL in in holdover
write_cycle_req EQU .0 ;bit position for flagging when a FLL parameter Write in EEPROM is req'd
command_menu_req EQU .5 ;bit to request to send help menu
command_menu_cycle_on EQU .6 ;bit position to flag that the send help menu is being sent
startup_prompt_req EQU .7 ;bit to request to send startup prompt
stabil_done EQU .1 ;This is the stabilization done flag bit position in FREQ_MEAS_STAT2
gps_1pps_los EQU .1 ;Bit position for the GPS 1PPS LOS flag
holdover_ctr_expired EQU .3 ;bit position in ALM register to specify that the holdover period is expired
new_cpp_val EQU .1 ;used to set new CPP value flag in variable GPS1PPS_STAT
freq_upd_run EQU .0 ;used to signal if the automatic frequency measurement process is enabled
ref_ctrl_on_mode EQU .2 ;value used to set CTRL_REF_OUT_MODE to "off" 
ccp1_int_raised EQU .3 ;bit position to signal to LED and CCP1 LOS routines when a 1 second ccp1 interrupt happens.
bootup_freq_test EQU .0 ;bit position on PORTB to sense what OCXO frequency (10MHz or 5MHz) to set the firmware to.
alm_clr_pushbutton EQU .1 ;bit position on PORTB to sense the level of the alarm clear pushbutton

 ;Bit Masks
gps_1pps_mask EQU b'00000100' ;PortC bit2 mask, GPS 1pps input
freq_coarse_inc EQU b'00011100' ;mask used to indicate that a coarse increase of freq. is req'd
freq_coarse_dec EQU b'00010100' ;mask used to indicate that a coarse decrease of freq. is req'd
freq_fine_inc EQU b'00011000' ;mask used to indicate that a fine increase of freq. is req'd
freq_fine_dec EQU b'00010000' ;mask used to indicate that a fine decrease of freq. is req'd
no_freq_adj EQU b'00000000' ;mask used to indicate that a no freq. adjustment is req'd
mask_duty_2con EQU b'00110000' ;mask used to isolate the two MSb's of the PWM duty cycle
mask_duty_l EQU b'00000011' ;mask used to isolate the two MSB's of the PWM duty cycle in the PWM_DUTY_H register
mask_freq_adj_clr EQU b'11100011' ;mask to clear all frequency adjust flags
new_tx_cycle EQU b'00000001' ;mask to test if new cycle of character transmission is required

 ;Initialization Values
;W EQU .0 ;Is the working Register flag in various commands (defined in .INC file)
F EQU .1 ;File register flag in various commands
ccp1_init EQU b'00000101' ;used to initialize CCP1 in capture, every rising edge 
ccp2_init EQU b'00001100' ;used to initialize CPP2 in PWM mode
pwm_period_init EQU 0xFF ;used to set PWM period
pwm_duty_r2h_init EQU 0x7F ;default duty cycle value to be loaded in CPPR2H
pwm_duty_2con_init EQU b'00110000' ;default duty cycle value to be loaded in CPP2CON, bits 5 and 4
dither_init EQU .0 ;Initial Dither value
ccp_160mhz_h EQU 0x68 ;when frequency counted is exactly 160MHz, OLD_CCPR1 reads 26624, or 0x6800
ccp_160mhz_l EQU 0x00 ; "
ccp_80mhz_h EQU 0xB4 ;when frequency counted is exactly 80MHz, OLD_CCPR1 reads 46080, or 0xB400
ccp_80mhz_l EQU 0x00 ; "
separ_char EQU "|" ;The separator character for the TX string
blank_char EQU "." ;This is the blank character used in the Tx string
number_param_to_stor EQU .13 ;This is the number of parameters that are saved/restored in Data EEPROM, incl. addr. 0. 
dither_limit_init EQU .8 ;Initial dither limit value
lock_limit_init EQU .8 ;the initial FLL lock limit
holdover_ctr_limit_init EQU .200 ;Initial value for the holdover counter limit
freq_chg_thresh_init EQU .3 ;this is the initial frequency change threshold
Ref_10m_mode_init EQU .2 ;The initial mode (enabled) for 10M reference control pin 
eecon1_data_eeprom_access EQU b'00000000' ;will initialize EECON1 register for a Data EEPROM access.
eecon1_prog_ee_access EQU b'00000000' ;will initialize EECON1 register for a Data EEPROM access.
ref_ctrl_off_mode EQU .1 ;Reference output control "off" state value
pos_vcxo_slope EQU .1 ;VCXO tuning slope positive value
FLL_in_summing_mode EQU .2 ;FLL averaging mode value for sample summing mode

;******************************************************************************
;Reset vector
; This code will start executing when a reset occurs.

 ORG 0x0000
 GOTO MAIN ;go to start of main code

;******************************************************************************************************
;High priority interrupt vector
; This code will start executing when a high priority interrupt occurs or
; when any interrupt occurs if interrupt priorities are not enabled.

 ORG 0x0008
 BRA HIGHINT ;go to high priority interrupt routine

;******************************************************************************************************
;LOWINT
;Low priority interrupt vector and routine
; This code will start executing when a low priority interrupt occurs.

 ORG 0x0018
LOWINT
 MOVFF STATUS,STATUS_TEMP ;save STATUS register
 MOVFF WREG,WREG_TEMP ;save working register
 MOVFF BSR,BSR_TEMP ;save BSR register
CCP1_INT_CHECK
 BTFSC PIR1,CCP1IF ;CCP1 value available interrupt flag set? if no, skip next instruction
 BRA CCP1_VAL_AVAIL ;yes, jump
SERIAL_INT_CHECK
 BTFSS PIE1,TXIE ;Is TX interrupt enabled?
 BRA SERIAL_RX_CHECK ;No, go to test RX
 BTFSC PIR1,TXIF ;Yes, Did USART TX cause interrupt?
 BRA USART_TX_INT ;Yes, service it.
SERIAL_RX_CHECK
 BTFSS PIE1,RCIE ;Is RX interrupt enabled?
 BRA NO_VALID_INT ;No, go to other test
 BTFSC PIR1,RCIF ;Yes, Did USART RX cause interrupt?
 BRA USART_RX_INT ;Yes, service it.
NO_VALID_INT
 BRA LOWINT_EXIT ;no, branch to leave interrupt routine
CCP1_VAL_AVAIL
 BCF PIR1,CCP1IF ;clear CCP1 interrupt request flag 
 BSF LED_STAT,ccp1_int_raised ;set the CCP1 interrupt raised flag (for LED and CCP1 LOS routines). 
 MOVLW h'C2' ;Load Timer0 H register with the proper value for a 2-second count 
 MOVWF TMR0H ; "
 MOVLW h'F6' ;Load Timer0 L register with the proper value for a 2-second count
 MOVWF TMR0L ; "
 BCF INTCON,TMR0IF ;Clear the Timer 0 count rollover flag
 INCF CCP1_INT_CTR,F ;Increment the CCP1_Interrupt counter
 MOVLW .16 ;Is it the 16th CCP1 interrupt?
 CPFSEQ CCP1_INT_CTR ; "
 BRA LOWINT_EXIT ;No, branch to leave interrupt routine
 CLRF CCP1_INT_CTR ;Yes, clear the CCP1 interrupt counter
 BSF FREQ_MEAS_STAT,new_cpp_val ;Set new CPP value flag for main routine READ_FREQ to act 
 BRA LOWINT_EXIT ;branch to leave interrupt routine
USART_TX_INT
 BTFSS TX_RX_STAT,new_tx_cycle ;verify if new character tx cycle initiated
 BRA NO_NU_CYCLE ;no, go to next validation
 LFSR FSR0,0x190 ;yes, load Serial Tx buffer's base address in FSR register
 BCF TX_RX_STAT,new_tx_cycle ;yes, clear new Tx cycle flag
NO_NU_CYCLE
 TSTFSZ INDF0 ;is there a character in the buffer?
 BRA CHAR_PRESENT ;yes, go load it in tx buffer
 BCF TX_RX_STAT,tx_cycle_on
 BCF PIE1,TXIE ;no, disable future TX interrupts 
 BCF PIR1,TXIF ;Clear interrupt request Flag.
 BRA LOWINT_EXIT ;go to end of ISR, restore context, return 
CHAR_PRESENT
 MOVFF INDF0,TXREG ;transfer (indirect addressing) character to Tx register 
 CLRF POSTINC0 ;clear character and increase indirect pointer
 BCF PIR1,TXIF ;Clear interrupt request Flag.
 BRA LOWINT_EXIT ; go to end of ISR, restore context, return
USART_RX_INT 
 BCF PIR1,RCIF ;clear Rx char.  MOVLW 06h ;Mask out unwanted bits
 ANDWF RCSTA,W ;Check for errors
 BTFSS STATUS,Z ;Was either error status bit set?
 BRA RXERROR ;Found error, flag it
 TSTFSZ SERIAL_RX_BUFF ;is there a character in the first rx buffer cell?
 BRA NO_NU_RX_CYCLE ;yes, go read next character
 LFSR FSR1,0x180 ;no, load Serial rx buffer's base address in FSR register
NO_NU_RX_CYCLE
 MOVFF RCREG,POSTINC1 ;Get rx character from USART and increment indirect addr. pointer
 MOVLW h'8F' ;Has end of Rx buffer been reached (address 0x18F)?
 CPFSLT FSR1L ;"
 BRA END_RX_CYCLE ;Yes, go end Rx cycle
 MOVLW .10 ;No, Load LF char in Wreg
 CPFSEQ RCREG ;Is character received LF
 BRA LOWINT_EXIT ;No, go to end of ISR, restore context, return
END_RX_CYCLE
 BSF TX_RX_STAT,lf_eoc_received ;Yes, lift the end of user command flag
 BRA LOWINT_EXIT ; go to end of ISR, restore context, return
RXERROR
 MOVF RCREG,W ;Discard received errored byte
 BCF RCSTA,CREN ;Clear receiver status
 BSF RCSTA,CREN ; "
LOWINT_EXIT
 MOVFF BSR_TEMP,BSR ;restore BSR register
 MOVFF WREG_TEMP,WREG ;restore working register
 MOVFF STATUS_TEMP,STATUS ;restore STATUS register
 RETFIE 0 ;this exits and re-enable low priority interrupts

;******************************************************************************************************
;HIGHINT 
;High priority interrupt routine
; no need to save status registers for a high priority interrupt routine

HIGHINT 
 MOVFF PWM_DITH_H,CCPR2L ;load initial eight duty cycle MSb's in CCP2 register 
 BCF CCP2CON,4 ;clear two duty cycle LSb's in CCP register
 BCF CCP2CON,5 ; "
 MOVF PWM_DITH_L,W ;load Wreg with the 2 duty cycle LSbs
 MULLW .16 ;this shifts the two duty cycle LSb's in position 4 and 5.
 MOVF PRODL,W ;move multiplication result back in Wreg
 IORWF CCP2CON,F ;transfer bits 4 and 5 in CCP register 
 INCF PWM_DITH_CTR,F ;increment the dither counter.
 BCF PIR1,TMR2IF ;clear TIMER2 interrupt request flag 
 RETFIE FAST ;this restores the 3 status registers and exits interrupt routine.


;******************************************************************************************************
;MAIN
;Start of main program
;Initialization Area. This stuff is executed only once and at Reset time.

MAIN 
 MOVLB .1 ;Select RAM bank 1 for all variable accesses 
 CLRF INTCON ;disable interrupts
 MOVLW b'10000000' ;enable interrupt priorities (high/low)
 MOVWF RCON ; "
 MOVLW b'01110010' ;select internal oscillator and set it to 8MHz
 MOVWF OSCCON ; "
 MOVLW b'10000111' ;Set Timer0 to operate on internal clock with a prescaler value of 256.
 MOVWF T0CON
 MOVLW b'00000111' ;set timer1 and enable it Used for CCP1 (Capture)
 MOVWF T1CON ; " 
 MOVLW b'00110110' ;enable CCP1 interrupt, and enable Timer2=PR2 interrupt, Rx interrupt
 MOVWF PIE1 ; " 
 MOVLW b'00000001' ;enable CCP2 interrupt
 MOVWF PIE2 ; " 
 MOVLW b'00000010' ;assign low priority to CCP1 interrupt, Timer1 ovfl, USART Tx 
 MOVWF IPR1 ; and high priority to CCP2=PR2 (PWM)
 CLRF CCPR1L ;clear capture registers
 MOVLW b'10000101' ;PORTC set as follows:
 MOVWF TRISC ; 7-Serial input
 ; 6-Serial output
 ; 5-output (not used)
 ; 4-Red LED Anode output, cathode goes to PortC, bit3 
 ; 3-Green LED Anode output, cathode goes to PortC, bit4
 ; 2-Capture1 input (GPS 1 pps)
 ; 1-10MHz output Reference control pin. Low disabled 10MHz outs, high enables them. 
 ; 0-Timer1 osc. input
 MOVLW b'11110111' ;PORTB set as follows:
 MOVWF TRISB ; 7-input (not used). Has internal pull-up.
 ; 6-input (not used). Has internal pull-up.
 ; 5-input (not used). Has internal pull-up. 
 ; 4-input (not used). Has internal pull-up.
 ; 3-PWM2 output (see also configuration bit CONFIG3H)
 ; 2-input (not used). Has internal pull-up.
 ; 1-input Alarm clear pushbutton.
 ; 0-input Senses whether to boot up in 10MHz mode (high) or 5MHz mode (low). Has internal pull-up.
 MOVLW b'00000000' ;PORTA set as follows: 
 MOVWF TRISA ; 7-output (not used)
 ; 6-output (not used)
 ; 5-output (not used) 
 ; 4-output (not used)
 ; 3-output (not used)
 ; 2-output (not used)
 ; 1-output (not used)
 ; 0-output (not used)
 BCF INTCON2,7 ;Enable the weak pullups on port B 
STARTUP_DELAY ;This 1 sec delay is added to let the supply voltage stabilize.
 MOVLW h'E1' ;Load 1 second equivalent (500ns * 256 * (0x10000 - 0xE17B)) into timer0 value
 MOVWF TMR0H ; "
 MOVLW h'7B' ; "
 MOVWF TMR0L ; "
 BCF INTCON,TMR0IF ;Clear the timer0 overflow interrupt flag
STARTUP_DELAY_LOOP 
 BTFSS INTCON,TMR0IF ;Is flag raised (timer0 overflow)?
 BRA STARTUP_DELAY_LOOP ;No, loop to test again
CLEAR_VARIABLES ;Clear all variables, except the RS232 buffers
 LFSR FSR1,0x100 ;Load indirect addressing register with base address of the variables to clear
CLR_VARS_LOOP
 CLRF POSTINC1 ;Clear variable and increase indirect addressing pointer
 MOVLW 0x7F ;Have it reached end of variable addresses
 CPFSEQ FSR1L ; "
 BRA CLR_VARS_LOOP ;No, loop again. 
CONT_AFTER_DELAY ;Yes, continue with initialization
 MOVLW ccp1_init ;enables ccp1, capture every rising edge 
 MOVWF CCP1CON ; "
 MOVLW pwm_period_init ;loads period in timer2 period register
 MOVWF PR2 ; "
 MOVLW dither_init ;Load initial dither value
 MOVWF PWM_DUTY_DITH ; "
 BCF CCP2CON,4 ;load initial two duty cycle MSb's directly into CCP2 register
 BCF CCP2CON,5 ; "
 MOVLW pwm_duty_2con_init ; " (mask has bit 4 and 5 updated)
 IORWF CCP2CON,F ; "
 MOVLW b'00000101' ;set timer2 to prescaler div. by 4 (2.4KHz frequency) 
 MOVWF T2CON ; and enable it
 MOVLW ccp2_init ;enables ccp2 in PWM mode
 MOVWF CCP2CON ; "
 BSF FREQ_MEAS_STAT,freq_upd_run ;enable FLL running mode
 BSF FREQ_MEAS_STAT,new_dith_cycle ;enable new dither cycle flag
 BSF FREQ_MEAS_STAT2,stat_fll_unlock ;put FLL in unlocked state
 BSF FREQ_MEAS_STAT2,stabil_done ;set the stabilization done flag
 BSF FREQ_MEAS_STAT2,in_sampling_phase ;set the sampling phase flag
 BCF FREQ_MEAS_STAT2,holdover_flag ;clear the holdover flag
READ_EEPROM_PARAMS ;Parameters are transfered from Data EEPROM to RAM variables
 MOVLW .1 ;Load Data Memory address into Wreg
 CALL READ_EEPROM_DATA ;Read data from ERPROM address 
 MOVWF FILT_AVG_LIMIT_H ;load the filter sampling size H
 MOVLW .2 ;Load Data Memory address into Wreg
 CALL READ_EEPROM_DATA ;Read data from ERPROM address 
 MOVWF FILT_AVG_LIMIT_L ;load the filter sampling size H
 MOVLW .3 ;Load Data Memory address into Wreg
 CALL READ_EEPROM_DATA ;Read data from ERPROM address 
 MOVWF DITHER_LIMIT ;Load initial dither limit
 MOVLW .4 ;Load Data Memory address into Wreg
 CALL READ_EEPROM_DATA ;Read data from ERPROM address 
 MOVWF LOCK_LIMIT ;load the FLL lock limit.
 MOVLW .5 ;Load Data Memory address into Wreg
 CALL READ_EEPROM_DATA ;Read data from ERPROM address 
 MOVWF HOLDOVER_CTR_LIMIT ;Load Holdover counter limit
 MOVLW .6 ;Load Data Memory address into Wreg
 CALL READ_EEPROM_DATA ;Read data from ERPROM address 
 MOVWF FREQ_CHG_THRESH ;Load Frequency change threshold
 MOVLW .7 ;Load Data Memory address into Wreg
 CALL READ_EEPROM_DATA ;Read data from ERPROM address 
 MOVWF CCPR2L ; "
 MOVWF PWM_DUTY_H ;and load same value in duty cycle register PWM_DUTY_H
 MOVWF PWM_DITH_H ;and load same value in dither register PWM_DITH_H
 MOVLW .8 ;Load Data Memory address into Wreg
 CALL READ_EEPROM_DATA ;Read data from ERPROM address 
 MOVWF PWM_DUTY_L ;load bits 0 and 1 in duty cycle register PWM_DUTY_L
 MOVWF PWM_DITH_L ;and load same value in dither register PWM_DITH_L
 MOVLW .9 ;Load Data Memory address into Wreg
 CALL READ_EEPROM_DATA ;Read data from ERPROM address 
 MOVWF CTRL_REF_OUT_MODE ;load the 10M reference mode value
 MOVLW .10 ;Load Data Memory address into Wreg
 CALL READ_EEPROM_DATA ;Read data from ERPROM address 
 MOVWF HOLDOVER_LIMIT ;load the holdover value
 MOVLW .11 ;Load Data Memory address into Wreg
 CALL READ_EEPROM_DATA ;Read data from ERPROM address 
 MOVWF VCXO_SLOPE_MODE ;load the vcxo tuning slope value
 MOVLW .12 ;Load Data Memory address into Wreg
 CALL READ_EEPROM_DATA ;Read data from ERPROM address 
 MOVWF FLL_AVG_MODE ;load the FLL averaging mode value
CONT_INITIALIZE
 MOVLW b'00000001' ; Put alarm register in FLL Unlocked 
 MOVWF FREQ_ALM_STAT ; "
 MOVLW b'00100100' ;Enable USART TX, 8 bits, Async, High Speed
 MOVWF TXSTA ; "
 MOVLW .103 ; Set baud rate to 2400 bauds @ 8MHz CPU frequency
 MOVWF SPBRG ; "
 MOVLW b'10010000' ;Enable Serial port, enable Rx, 8 bits on Rx, Async
 MOVWF RCSTA ; "
LOAD_STARTUP_STRING
 BSF TX_RX_STAT,startup_prompt_req ;Raise the startup prompt requested flag
 LFSR FSR2,0x180 ;load Serial rx buffer's base address in FSR register
CLR_RX_BUFFER_LOOP
 CLRF POSTINC2 ;Clear Rx buffer cell and increase indirect addressing pointer
 TSTFSZ INDF2 ;Test next character. Is it Null
 BRA CLR_RX_BUFFER_LOOP ;No, loop again. Yes, exit routine
 MOVLW b'00000001' ;Put alarm register in FLL Unlocked 
 MOVWF FREQ_ALM_STAT ; "
 BTFSS PORTB,bootup_freq_test ;Is the frequency selection pin for 10MHz OCXO?
 BRA INIT_5MHz ;No, go initialize for 5MHz OCXO
INIT_10MHz ;Yes, initialize for 10MHz OCXO
 MOVLW ccp_160mhz_h ;Load nominal value H to compare to measured frequency
 MOVWF NOMINAL_FREQ_VAL_H ; "
 MOVLW ccp_160mhz_l ;Load nominal value L to compare to measured frequency
 MOVWF NOMINAL_FREQ_VAL_L ; "
 BRA INIT_FREQ_COMPLETED ;Go continue initialization
INIT_5MHz ;initialize for 5MHz OCXO
 MOVLW ccp_80mhz_h ;Load nominal value H to compare to measured frequency
 MOVWF NOMINAL_FREQ_VAL_H ; "
 MOVLW ccp_80mhz_l ;Load nominal value L to compare to measured frequency
 MOVWF NOMINAL_FREQ_VAL_L ; "
INIT_FREQ_COMPLETED ;Continue initialization
 BCF LED_STAT,ccp_high ;Clear the ccp_high flag
 BCF LED_STAT,ccp1_int_raised ;Clear the ccp1 interrupt flag
 CLRF PIR1 ;Clear all interrupt request flags
 CLRF PIR2 ; "
 BCF PIR1,RCIF ;Clear RCIF Interrupt Flag
 BSF INTCON,GIEH ;enable high priority interrupts
 BSF INTCON,GIEL ;enable low priority interrupts

;******************************************************************************************************
;This is the main loop that repeats indefinitely

GPSSTD_MAIN 
 CALL READ_CTRL_ALM_BUTT ;Read and control the alarm clearing pushbutton
 CALL READ_FREQ ;Read the 10MHz VCXO Frequency
 CALL CTRL_FILT_DATA ;Filter the Frequency information and instruct on VCXO frequency changes
 CALL CTRL_GPS_LOS_DET ;Monitor the GPS 1PPS signal for LOS and raise alarm accordingly
 CALL CTRL_FLL_STATE ;Monitor Frequency samples and update FLL state accordingly
 CALL CTRL_PWM ;Control the DAC output (using PWM) for coarse steps
 CALL CTRL_PWM_DITH ;Control the DAC output for fine steps (dither)
 CALL CTRL_LEDS ;Control the bi-color LED based on FLL state and alarms
 CALL CTRL_ALM ;Update alarm conditions
 CALL CTRL_REF_OUT ;Control the 10MHz output enable/disable pin
 CALL CTRL_FLL_STAT_TX ;Control contents of the FLL status line sent over serial port
 CALL CTRL_PARAM_INFO_TX ;Control contents of the FLL parameter line sent over serial port
 CALL CTRL_COMMAND_RX ;Control reception and process User Commands received over serial port
 CALL CTRL_OTHER_TX ;Control contents of Command Menu and startup prompt sent over serial port
 CALL CTRL_PARAM_UPD_EEPROM ;Control Writing in Flash EEPROM of FLL parameters
 GOTO GPSSTD_MAIN ;Loop back to beginning

;******************************************************************************************************
; READ_CTRL_ALM_BUTT
;This piece of code reads the alarm clear push button and clears the alarm latches accordingly.

READ_CTRL_ALM_BUTT
 BTFSC PORTB,alm_clr_pushbutton ;Is the pushbutton pressed (low level)?
 BRA READ_CTRL_ALM_BUTT_RET ;No, leave routine
 CLRF FREQ_ALM_STAT ;Yes, clear the alarm latch
READ_CTRL_ALM_BUTT_RET
 RETURN ;Leave routine

;******************************************************************************************************
; READ_FREQ
;This piece of code reads the CCP1 latched count and substracts the old count from it to calculate the frequency
;(10.0000MHz x 16 seconds =160,000,000 pulses). If frequency measured is exactly 10MHz, the resulting 16-bit count
;should be 26624 (0x6800).

READ_FREQ
 BTFSS FREQ_MEAS_STAT,new_cpp_val ;check if new CPP value available, yes, skip next instruction
 BRA READ_FREQ_RETN ; no, jump to leave routine
READ_OK 
 MOVLW b'11100011' ;Clear Frequency change bits
 ANDWF FREQ_MEAS_STAT,F ; "
 INCF SAMPLE_CTR_L,F ;Increment the 16-bit sample counter
 BNC NO_CTR_OVERFLOW ;Counter L overflow? No, continue
 INCF SAMPLE_CTR_H,F ;Yes, Increment counter H
 BSF GENERAL1_STAT,write_cycle_req ;write DAC value and all other parameters to EEPROM
NO_CTR_OVERFLOW
 MOVFF CCPR1L,FREQ160_REG_L ;load FREQ160_REG registers
 MOVFF CCPR1H,FREQ160_REG_H ; "
 MOVF OLD_CCPR1L,W ;The 16-bit substraction is made between CCPR1 and OLD_CCPR1
 SUBWF FREQ160_REG_L,F ; "
 MOVF OLD_CCPR1H,W ; " 
 SUBWFB FREQ160_REG_H,F ; " At this point, 160Mhz count value to compare is in FREQ160_REG_L/H 
CALC_F_DELTA
 MOVF NOMINAL_FREQ_VAL_L,W ;The 16-bit signed substraction is made between NOMINAL_FREQ_VAL_H/L and FREQ160_REG_H/L 
 SUBWF FREQ160_REG_L,W ; "
 MOVWF FREQ_DELTA_L ; "
 MOVF NOMINAL_FREQ_VAL_H,W ; " 
 SUBWFB FREQ160_REG_H,W ; "
 MOVWF FREQ_DELTA_H; ; " At this point, the frequency difference is located in FREQ_DELTA_H/L
UPD_FREQ_STAT
 MOVFF CCPR1L,OLD_CCPR1L ;Save CCP values for next pass
 MOVFF CCPR1H,OLD_CCPR1H ; "
 BCF FREQ_MEAS_STAT,new_cpp_val ;Clear the new CCP flag
 BSF FREQ_MEAS_STAT2,freq_upd_req ;Raise the freq. update flag
READ_FREQ_RETN
 RETURN

;******************************************************************************************************
; CTRL_FILT_DATA 
;This code filters the raw frequency data produced by the READ_FREQ code. It inserts a stabilization
;pause equivalent to one sample (16 secs). It then averages out the frequency difference from ideal 10MHz 
;by summing (substracting) the frequency differences from several samples. Based on the result, it 
;commands the frequency change (fine/coarse, increase/decrease).

CTRL_FILT_DATA 
 BTFSS FREQ_MEAS_STAT2,freq_upd_req ;Check if frequency update flag is raised 
 BRA FILT_DATA_RET ;no, exit routine
 BTFSC FREQ_MEAS_STAT2,stabil_done ;Is Stabilization cycle done?
 BRA STABILIZ_DONE ;Yes, go to treat filter normally
 CLRF FREQ_DELTA_H ;No, clear frequency delta variables
 CLRF FREQ_DELTA_L ; "
 BCF FREQ_MEAS_STAT2,freq_upd_req ;Clear the frequency update required flag
 BSF FREQ_MEAS_STAT2,stabil_done ;Set Stabilization cycle done flag
 BSF FREQ_MEAS_STAT2,in_sampling_phase ;Set the "in sampling pahase" flag 
 BRA FILT_DATA_RET ;Leave routine
STABILIZ_DONE 
 BSF TX_RX_STAT,tx_fll_info_req ;set the "send FLL satatus info required" flag
 INCF FILT_AVG_CTR_L,F ;Increment sample counter
 BNC SKIP_OVERFLOW ;Counter L overflow? No, continue 
 INCF FILT_AVG_CTR_H,F ;Yes, Increment counter H
SKIP_OVERFLOW
 MOVLW FLL_in_summing_mode ;Is FLL in summing mode?
 CPFSLT FLL_AVG_MODE ; " 
 BRA SAMPLE_SUMMING_MODE ;Yes, go process summing mode
SAMPLE_VOTING_MODE
 MOVF FREQ_DELTA_H,W ;No, Is Frequency delta positive or zero?
 BNN POS_DELTA ;Yes, go process a positive delta
 DECF FILT_AVG_VAL_L,F ;No, frequency delta is negative, decrement L average value
 BC STOR_AVG_VAL ;Is it a substraction rollover?, No, continue
 DECF FILT_AVG_VAL_H,F ;Yes, decrement H average value
 BRA STOR_AVG_VAL ;Continue
POS_DELTA 
 MOVF FREQ_DELTA_L,W ;Frequency Delta L is positive or zero. Is it equal to zero?
 BZ STOR_AVG_VAL ;Yes, no average value update required
 INFSNZ FILT_AVG_VAL_L,F ;No, increment L average value. Is it an increment rollover (carry)?
 INCF FILT_AVG_VAL_H,F ;Yes, increment H average value.
 BRA STOR_AVG_VAL ;No, continue
SAMPLE_SUMMING_MODE
 MOVF FREQ_DELTA_L,W ;Add (16 bits) the increment delta count to the average value
 ADDWF FILT_AVG_VAL_L,F ; "
 MOVF FREQ_DELTA_H,W ; "
 ADDWFC FILT_AVG_VAL_H,F ; "
STOR_AVG_VAL
 MOVFF FILT_AVG_CTR_H,FILT_AVG_CTR_STOR_H ;Save the average sample counter for later usage
 MOVFF FILT_AVG_CTR_L,FILT_AVG_CTR_STOR_L ; "
 MOVFF FILT_AVG_VAL_H,FILT_AVG_VAL_STOR_H ;Save the average value for later usage
 MOVFF FILT_AVG_VAL_L,FILT_AVG_VAL_STOR_L ;Save the average value for later usage
 MOVF FILT_AVG_CTR_H,W ; Is sample size reached?
 CPFSGT FILT_AVG_LIMIT_H ; "
 BRA TEST_CTR_L ;Maybe, test L register
 BRA FILT_DATA_RET ;No, Leave routine
TEST_CTR_L
 MOVF FILT_AVG_CTR_L,W ;Is sample size reached?
 CPFSGT FILT_AVG_LIMIT_L ; "
 BRA TEST_AVG_FREQ ;Yes, end sampling cycle
 BRA FILT_DATA_RET ;No, Leave routine
TEST_AVG_FREQ 
 BCF FREQ_MEAS_STAT2,in_sampling_phase ;Sampling cycle ended. Clear sampling phase flag
 MOVF FILT_AVG_VAL_H,W ;Is average delta value negative?
 BNN BYPASS_NEGATE ;No, bypass negate function
 BSF FREQ_MEAS_STAT,freq_inc_dec ;Yes, set the frequency change flag to increase
 NEGF FILT_AVG_VAL_L ;This is a 16-bit Negate
 BTFSC STATUS,C ; "
 DECF FILT_AVG_VAL_H ; "
 COMF FILT_AVG_VAL_H,F ; "
BYPASS_NEGATE ;Here, value is assumed positive 
 MOVFF FILT_AVG_VAL_L,FILT_AVG_VAL_L_ABS ;Save the absolute value of average delta value for later usage 
 MOVF FILT_AVG_VAL_L,W ;Is average delta less than Frequency Negate threshold?
 CPFSGT FREQ_CHG_THRESH ;
 BRA FINE_COARSE_CALC ;No, allow frequency change
 CALL END_SAMPLING_CYCLE ;Yes, end sampling cycle.
 BRA ZERO_AVG ;Do not allow a frequency change
FINE_COARSE_CALC
 TSTFSZ FILT_AVG_VAL_H ;Is H average value zero?
 BRA COARSE_CHG_OK ;No, go process coarse frequency change
 MOVF DITHER_LIMIT,W ;Yes, is average value larger than the fine/coarse change limit?
 CPFSGT FILT_AVG_VAL_L ;"
 BCF FREQ_MEAS_STAT,freq_coarse_fine ;No, process a fine frequency change
 CPFSLT FILT_AVG_VAL_L ;Yes, Is average value smaller than the fine/coarse change limit?
COARSE_CHG_OK
 BSF FREQ_MEAS_STAT,freq_coarse_fine ;No, process a coarse frequency change
 BSF FREQ_MEAS_STAT,freq_chg ;Trigger a frequency change
 BSF GENERAL1_STAT,write_cycle_req ;Write DAC value and all other parameters to EEPROM
 CALL END_SAMPLING_CYCLE ;End sampling cycle
 BRA FILT_DATA_RET ;Leave routine
ZERO_AVG
 MOVLW b'11100011' ;Clear Frequency change bits
 ANDWF FREQ_MEAS_STAT,F ; " 
FILT_DATA_RET
 RETURN

;******************************************************************************************************
; CTRL_GPS_LOS_DET
;This portion of code monitors the 1 PPS signal for Loss of signal. A 16-second period without the 1PPS
;signal will trigger the Holdover state.

CTRL_GPS_LOS_DET
 BTFSS LED_STAT,ccp1_int_raised 
 BRA TST_GPS_LOS ;No, go test LOS 
 BCF GENERAL1_STAT,gps_1pps_los ;Yes, clear the GPS in LOS flag
 BRA GPS_1PPS_ALM_RET ;Leave routine
TST_GPS_LOS
 BTFSS INTCON,TMR0IF ;Is 2-second Timer0 expired?
 BRA GPS_1PPS_ALM_RET ;No, leave routine
 BCF INTCON,TMR0IF ;Yes, clear the timer0 rollover flag
 INCF GPS_LOS_2SEC_CTR ;Increment the 2-second timer counter
 MOVLW .8 ;Is 2-second timer counter at 8 (16 seconds elapsed)?
 CPFSLT GPS_LOS_2SEC_CTR ; "
 BRA SET_GPS_LOS_FLAG ;Yes, go set the LOS flag
 BRA RESTART_GPS_CTR ;No, Restart the 2-second timer counter
SET_GPS_LOS_FLAG
 BSF GENERAL1_STAT,gps_1pps_los ;Set the GPS in LOS flag
 CLRF GPS_LOS_2SEC_CTR ;Clear the 2-second timer counter
 BTFSC FREQ_MEAS_STAT,freq_upd_run ;Is FLL disabled
 BRA RESTART_GPS_CTR ;No, go to restart the 2-second timer counter
 BSF TX_RX_STAT,tx_fll_info_req ;Yes, raise the Tx string send flag (the only place that will send Tx info string) 
RESTART_GPS_CTR
 MOVLW h'C2' ;Load Timer0 H register with the proper value for a 2-second count
 MOVWF TMR0H ; "
 MOVLW h'F6' ;Load Timer0 L register with the proper value for a 2-second count
 MOVWF TMR0L ; "
 BCF INTCON,TMR0IF ;Clear the Timer 0 count rollover flag
GPS_1PPS_ALM_RET
 RETURN ;Exit routine

;******************************************************************************************************
; CTRL_FLL_STATE
;This portion of code controls the PLL state (Locked, Unlocked, Holdover). It monitors the measured frequency
;and sets the state accordingly. It may cancel the frequency change set by CTRL_FILT_DATA if the mode 
;does not allow for it.

CTRL_FLL_STATE
 BTFSS FREQ_MEAS_STAT,freq_upd_run ;Is FLL disabled
 BRA ABORT_FREQ_CHG ;Yes, do not perform any frequency change
 BTFSC GENERAL1_STAT,gps_1pps_los; ;No, Is 1PPS in LOS?
 BRA GO_STAY_HOLDOVER ;Yes, Go (stay) into holdover
 BTFSS FREQ_MEAS_STAT2,freq_upd_req ;No, check if frequency update flag is raised 
 BRA CTRL_FLL_RET ;No, Leave routine
 BSF TX_RX_STAT,tx_fll_info_req ;Yes, raise the Tx info required flag
 BCF FREQ_MEAS_STAT2,freq_upd_req ;Clear the frequency update required flag
SERV_FREQ_CHG
 BTFSC FREQ_MEAS_STAT2,holdover_flag ;Is FLL in holdover?
 BRA TST_HOLDOVER ;Yes, go test holdover
 BTFSS FREQ_MEAS_STAT2,stat_fll_unlock ;No, is FLL unlocked?
 BRA TST_HOLDOVER ;No, go test holdover
 BTFSC FREQ_MEAS_STAT2,in_sampling_phase ;Yes, is FLL in sampling phase?
 BRA CTRL_FLL_RET ;Yes, allow frequency change by leaving routine 
 MOVF FILT_AVG_VAL_L_ABS,W ;No, can FLL transition into Locked state?
 CPFSGT LOCK_LIMIT ; "
 BRA CTRL_FLL_RET ;No, allow frequency change by leaving routine 
 BRA GO_LOCKED ;Yes, go in locked state
TST_HOLDOVER
 MOVF FREQ_DELTA_H,W ;
 BZ TEST_HOLDOVER_DELTA_L ;Is FREQ_DELTA_H = 0 ? Yes, go to test FREQ_DELTA_L
 BNN GO_STAY_HOLDOVER ;Is FREQ_DELTA_H > 0 ? Yes, go to validate the mode change
 NEGF FREQ_DELTA_L ;No, 16-bit Negate FREQ_DELTA_H/L
 BTFSC STATUS,C ; "
 DECF FREQ_DELTA_H ; "
 COMF FREQ_DELTA_H,F ; "
 BNZ GO_STAY_HOLDOVER ;If FREQ_DELTA_H not 0, goto validate the mode change
TEST_HOLDOVER_DELTA_L
 MOVF HOLDOVER_LIMIT,W ;Is FREQ_DELTA_L < holdover limit
 CPFSLT FREQ_DELTA_L ; "
 BRA GO_STAY_HOLDOVER ;No, go validate holdover mode
 BTFSS FREQ_MEAS_STAT2,holdover_flag ;Yes, is FLL in Holdover?
 BRA GO_LOCKED ;No, stay in locked state
 MOVF LOCK_LIMIT,W ;Yes, Is FREQ_DELTA_L < locked limit
 CPFSLT FREQ_DELTA_L ; "
 BRA GO_STAY_HOLDOVER ;No, stay in holdover
 BRA GO_LOCKED ;Yes, go to locked mode.
GO_STAY_HOLDOVER
 CALL END_SAMPLING_CYCLE ;End the sampling cycle
 BSF FREQ_MEAS_STAT2,holdover_flag ;Set the holdover flag
 BSF TX_RX_STAT,tx_fll_info_req ;raise the FLL status to be sent flag (this covers the GPS holdover case)
 BCF GENERAL1_STAT,gps_1pps_los ;Clear the GPS LOS flag
 INCF HOLDOVER_CTR,F ;Increment holdover counter
 MOVF HOLDOVER_CTR,W ;Is holdover counter limit reached?
 CPFSGT HOLDOVER_CTR_LIMIT ; "
 BRA GO_UNLOCKED ;Yes, go end holdover mode and go unlocked
 BRA ABORT_FREQ_CHG ;No, go end sample cycle and make no freq change
GO_LOCKED
 BCF FREQ_MEAS_STAT2,stat_fll_unlock ;Clear the unlock flag
 BCF FREQ_MEAS_STAT2,holdover_flag ;Clear the Holdover Flag
 CLRF HOLDOVER_CTR ;Clear the holdover counter
 BRA CTRL_FLL_RET ;Allow frequency change by leaving routine 
GO_UNLOCKED
 BSF FREQ_MEAS_STAT2,stat_fll_unlock ;Holdover end is reached. Set unlocked flag
 BCF FREQ_MEAS_STAT2,holdover_flag ;Clear holdover flag 
 BSF FREQ_ALM_STAT,holdover_ctr_expired ;set the holdover expired alarm flag
ABORT_FREQ_CHG
 MOVLW b'11100011' ;Clear Frequency change bits
 ANDWF FREQ_MEAS_STAT,F ; " 
CTRL_FLL_RET
 RETURN

;******************************************************************************************************
; CTRL_PWM 
;This section controls the 10-bit Pulse Width Modulator's duty cycle (acting like a DAC) to control the
;external VCXO frequiency. This routine works in conjunction with the High priority interrupt routine
;which constantly reloads the duty cycle.

CTRL_PWM 
 BTFSS FREQ_MEAS_STAT,freq_chg ;Frequency change required? Yes, skip next instruction
 BRA CALC_PWM_RET ;no, goto apply the same frequency
 BTFSS FREQ_MEAS_STAT,freq_inc_dec ;freq. increase required? 
 BRA TST_FREQ_DEC ;no, goto execute freq. decrease.
 MOVLW pos_vcxo_slope ;Frequency increase. Is vcxo slope set to positive? 
 CPFSGT VCXO_SLOPE_MODE ; "
 BRA DAC_INC ;no, go increase DAC.
 BRA DAC_DEC ;yes, goto decrease DAC.
TST_FREQ_DEC
 MOVLW pos_vcxo_slope ;Frequency decrease. Is vcxo slope set to positive? 
 CPFSGT VCXO_SLOPE_MODE ; "
 BRA DAC_DEC ;no, go decrease DAC.
 BRA DAC_INC ;yes, go increase DAC.
DAC_INC ;execute DAC increase
 BTFSC FREQ_MEAS_STAT,freq_coarse_fine ;Fine increase required? Yes, skip next instruction
 BRA TST_INC_L_REG ;no, go to test L register
 MOVLW h'0F' ;Is Dither register = 0F ? 
 CPFSLT PWM_DUTY_DITH ; "
 BRA TST_INC_L_REG ;yes, go to test L register
 INCF PWM_DUTY_DITH,F ;no, increment dither register
 BRA CALC_PWM_RET ;leave routine
TST_INC_L_REG
 MOVLW h'03' ;verify if upper end of L register range reached 
 CPFSEQ PWM_DUTY_L ; "
 BRA INC_L_OK ;no, go to increase L
 MOVLW h'FF' ;yes, verify if upper end of H register reached 
 CPFSEQ PWM_DUTY_H ; "
 BRA INC_H_OK ;no, go to increase H and L routine
 BSF FREQ_ALM_STAT,highside_end ;yes, raise DAC high-side flag reached 
 BRA CALC_PWM_RET ; do not increase DAC and Leave routine
INC_H_OK 
 INCF PWM_DUTY_H,F ;increase H register
INC_L_OK
 BTFSS FREQ_MEAS_STAT,freq_coarse_fine ;Fine DAC increase required? No, skip next instruction
 CLRF PWM_DUTY_DITH ;yes, clear dither register
 INCF PWM_DUTY_L,F ;increase L register
 MOVLW h'04' ;verify if upper end of L register range reached 
 CPFSLT PWM_DUTY_L ; "
 CLRF PWM_DUTY_L ;Yes, clear register
 BRA CALC_PWM_RET ;no, leave routine
DAC_DEC 
 BTFSC FREQ_MEAS_STAT,freq_coarse_fine ;Fine DAC decrease required? Yes, skip next instruction
 BRA TST_DEC_L_REG ;no, go to test L register
 MOVF PWM_DUTY_DITH,W ;Is Dither register = 0 ? 
 BZ TST_DEC_L_REG ;Yes, go test L reg. 
 DECF PWM_DUTY_DITH,F ;no, decrement dither register
 BRA CALC_PWM_RET
TST_DEC_L_REG
 TSTFSZ PWM_DUTY_L ;verify if lower end of L register range reached 
 BRA DEC_L_OK ;no, go to decrease L
 TSTFSZ PWM_DUTY_H ;Yes, verify if lower end of H register range reached 
 BRA DEC_H_OK ;no, go to decrease H and L routine
 BSF FREQ_ALM_STAT,lowside_end ;yes, raise DAC low-side flag reached 
 BRA CALC_PWM_RET ;yes, do not decrease DAC and Leave routine
DEC_H_OK 
 DECF PWM_DUTY_H,F ;decrease H register
DEC_L_OK
 BTFSC FREQ_MEAS_STAT,freq_coarse_fine ;Fine decrease required? 
 BRA DEC_NO_FINE ;No, go to decrease a coarse change
 MOVLW h'0F' ; yes, load dither register with 0F
 MOVWF PWM_DUTY_DITH ; "
DEC_NO_FINE
 DECF PWM_DUTY_L,F ;decrease L register
 MOVLW h'FF' ;verify if lower end of L register range reached 
 CPFSEQ PWM_DUTY_L ; "
 BRA CALC_PWM_RET ;No, leave routine
 MOVLW h'03' ;Yes, load register with rollover value of 3.
 MOVWF PWM_DUTY_L ; "
CALC_PWM_RET
 RETURN ;leave routine

;******************************************************************************************************
; CTRL_PWW_DITH
;This section adds granularity to the previous routine. It adds a 4-bit dither to the 10-bit Pulse Width Modulator,
;yielding a 14-bit equivalent DAC. This routine works in conjunction with the High priority interrupt routine
;which constantly reloads the duty cycle.

CTRL_PWM_DITH
 TSTFSZ PWM_DUTY_DITH ;Check if dither is required
 BRA DITH_OK ;Yes
 CLRF PWM_DITH_CTR ;No, clear dither counter 
 BRA DITH_END_OK ;do not treat dither and Leave routine
DITH_OK 
 BTFSS FREQ_MEAS_STAT,new_dith_cycle ;Check if new dither cycle is started, Yes, skip next instruction
 BRA NO_NEW_CYCLE ;no, jump
NEW_CYCLE
 BCF FREQ_MEAS_STAT,new_dith_cycle ;clear new dither cycle flag
 BCF FREQ_MEAS_STAT,7  ;Clear the end of dither done flag
 CLRF PWM_DITH_CTR ;clear dither counter
 MOVLW h'03' ;verify if upper end of L register range reached 
 CPFSEQ PWM_DUTY_L ; "
 BRA INC_L_DITH_OK ;no, go to increase dither via L routine
 MOVLW h'FF' ;verify if upper end of H register range reached 
 CPFSEQ PWM_DUTY_H ; "
 BRA INC_H_DITH_OK ;no, go to increase dither via L routine 
 BSF FREQ_MEAS_STAT,6 ;yes, raise the dither denied flag
 BRA CTRL_PWM_RET ;do not add dither and Leave routine
INC_H_DITH_OK
 MOVFF PWM_DUTY_H,PWM_DITH_H ;Transfer the DUTY Hi value into the Dither Hi reg.
 INCF PWM_DITH_H,F ;increase H register
 SETF PWM_DITH_L ;Load FF in L reg.This will become 00 in the next instruction
INC_L_DITH_OK
 MOVFF PWM_DUTY_L,PWM_DITH_L ;Transfer the DUTY Lo value into the Dither Lo reg.
 INCF PWM_DITH_L,F ;increase L register
 BRA CTRL_PWM_RET ;Leave routine
NO_NEW_CYCLE
 MOVF PWM_DITH_CTR,W ;Load dither counter into Wreg
 SUBWF PWM_DUTY_DITH,W ;Substract the counter from the dither reg.
 BZ DITH_END_TEST ;If equal, go end dither
 BNC TEST_CYCLE_END ;If negative (CTR > REG), go test if end of cycle reached
 BRA CTRL_PWM_RET ;Otherwise, leave routine
TEST_CYCLE_END
 MOVLW 10h ;Load 16 into Wreg
 CPFSEQ PWM_DITH_CTR ;Is dither counter = 16?
 BRA CTRL_PWM_RET ;No, leave routine
 BSF FREQ_MEAS_STAT,new_dith_cycle ;Yes, raise new Dither cycle flag
 BRA CTRL_PWM_RET ;leave routine
DITH_END_TEST
 BTFSC FREQ_MEAS_STAT,7 ;Check if end of dither was performed, 
 BRA CTRL_PWM_RET ;Yes, Leave
 BTFSS FREQ_MEAS_STAT,6 ;No, Check if dither cycle is denied, Yes, skip next instruction 
 BRA DITH_END_OK
 BCF FREQ_MEAS_STAT,6 ;no, clear the dither denied flag
 BRA CTRL_PWM_RET ;Leave routine 
DITH_END_OK
 MOVFF PWM_DUTY_L,PWM_DITH_L ;Yes, reload original Duty L value
 MOVFF PWM_DUTY_H,PWM_DITH_H ;Yes, reload original Duty L value
 BSF FREQ_MEAS_STAT,7 ;set the end of dither done flag
CTRL_PWM_RET
 RETURN

;******************************************************************************************************
;CTRL_LEDS
; This LED control routine will work when a bi-color LED is connected between RC1 and RC4. RC1=H, RC4=L 
; (green color perceived) when FLL is in locked state. RC1=L, RC4=H (red color perceived) when FLL is in unlocked state.
; RC1 and RC4 will toggle repeatedly when FLL is in holdover state (perceived color will be amber).
; In addition and regardless of output color, the LED should extinguish when the GPS pulse on CCP1 pin goes high,
; in effect giving a short blink every second.

CTRL_LEDS
    	BTFSC LED_STAT,ccp1_int_raised              ;Has CCP1 interrupt (1PPS) happened?
        BRA SET_CPP_HIGH_FLAG                       ;Yes, go set the CCP high state flag
        MOVF TMR0L,W                                ;No, read TMR0L to force the update of TMR0H 
        MOVLW h'C7'                                 ;Compare Timer0 Hi to 0xC7 (this is to see if it is time to cancel the flashing state)
    	CPFSLT TMR0H                                ; because LED flashing duration is dependent on Timer0
        BCF LED_STAT,ccp_high                       ;Yes, Timer0 Hi is >= to C7, clear ccp high flag
        BRA TEST_FLL_STATUS                         ;Go test the FLL state
SET_CPP_HIGH_FLAG
        BSF LED_STAT,ccp_high                       ;CCP1 interrupt just happened. Set the CCP high state flag
        BCF LED_STAT,ccp1_int_raised                ;Clear the CCP1 interrupt happened flag.
TEST_FLL_STATUS
        BTFSC FREQ_MEAS_STAT2,holdover_flag         ;FLL in holdover?
        BRA SET_HOLDOVER                            ;Yes, Go set holdover LED condition
        BTFSC FREQ_MEAS_STAT2,stat_fll_unlock       ;No, check if FLL in unlocked state.
        BRA SET_LED_RED                             ;Yes, go set the unlocked/disabled LED condition
        BTFSS FREQ_MEAS_STAT,freq_upd_run           ;No, is the FLL enabled? 
        BRA SET_LED_RED                             ;No, go set the unlocked/disabled LED condition
SET_LED_GREEN                                       ;Here, the FLL is considered locked
        BTFSC LED_STAT,ccp_high                     ;Is the CCP (1PPS) input pin high?
        BRA TST_ALM_1                               ;Yes, go test alarm latch for locked state
        BRA SET_GREEN_STAT                          ;No, go set the green status on LED flags
TST_ALM_1
        TSTFSZ FREQ_ALM_STAT                        ;CCP (1PPS) input is pin high. Any alarms latched?
        BRA SET_RED_STAT                            ;Yes, go set the red status on LED flags
        BRA SET_OFF_STAT                            ;No, go set the off status on LED flags
SET_LED_RED
        BTFSC LED_STAT,ccp_high                     ;Is the CCP (1PPS) input pin high?
        BRA SET_OFF_STAT                            ;Yes, go set the off status on LED flags
        BRA SET_RED_STAT                            ;No, go set the red status on LED flags
SET_HOLDOVER                        
        BTFSC LED_STAT,ccp_high                     ;Is the CCP (1PPS) input pin high?                  
        BRA TST_ALM_2                               ;Yes, go test alarm latch for holdover state
        BTFSC LED_STAT,led_green_stat               ;No, is the green color flag set?        
        BRA SET_RED_STAT                            ;Yes, go to set red status on LED flags
        BRA SET_GREEN_STAT                          ;No, go to set green status on LED flags
TST_ALM_2 
        TSTFSZ FREQ_ALM_STAT                        ;FLL in holdover and CCP (1PPS) input is pin high. Any alarms latched?
        BRA SET_RED_STAT                            ;Yes, go to set red status on LED flags
        BRA SET_OFF_STAT                            ;No, go to turn off status on LED flags
SET_GREEN_STAT                                      
        BSF LED_STAT,led_green_stat                 ;Turn on green status on LED flags
        BCF LED_STAT,led_red_stat                   ;Turn off red status on LED flags
        BRA UPDATE_LEDS_OUT                         ;Go update output LED pins                     
SET_RED_STAT
        BCF LED_STAT,led_green_stat                 ;Turn off green status on LED flags
        BSF LED_STAT,led_red_stat                   ;Turn on red status on LED flags
        BRA UPDATE_LEDS_OUT                         ;Go update output LED pins    
SET_OFF_STAT
        BCF LED_STAT,led_green_stat                 ;Turn off green status on LED flags
        BCF LED_STAT,led_red_stat                   ;Turn off red status on LED flags
UPDATE_LEDS_OUT            
        BCF PORTC,led_green_out                     ;Clear PortC green output pin
        BCF PORTC,led_red_out                       ;Clear PortC red output pin
        BTFSC LED_STAT,led_green_stat               ;Is green LED on required?
        BSF PORTC,led_green_out                     ;Yes, set green LED pin high
        BTFSC LED_STAT,led_red_stat                 ;No, Is red LED on required?
        BSF PORTC,led_red_out                       ;Yes, set red LED pin high
        RETURN                                      ;Leave routine

;******************************************************************************************************
; CTRL_ALM
;This part of code will latch an alarm for use in the FLL status string when it detects a valid alarm flag.

CTRL_ALM
        BTFSS FREQ_MEAS_STAT,freq_upd_run           ; Is the FLL running?
        BRA RAISE_UNLOCK_ALM                        ;No, go raise alarm
        BTFSC FREQ_MEAS_STAT2,stat_fll_unlock       ;Yes, is the FLL in unlocked state?
        BRA RAISE_UNLOCK_ALM                        ;Yes, go raise alarm
        BRA CTRL_ALM_RET                            ;No, leave routine
RAISE_UNLOCK_ALM            
        BSF FREQ_ALM_STAT,alm_fll_unlock            ;Raise FLL unlocked alarm flag    
CTRL_ALM_RET
        RETURN                                      ;Leave routine

;******************************************************************************************************
; CTRL_REF_OUT
;This part of code controls the 10MHz reference output state based on the control mode.

CTRL_REF_OUT
        MOVLW ref_ctrl_off_mode                     ;Is 10M ref control mode on?
        CPFSGT CTRL_REF_OUT_MODE                    ; "
        BRA SET_PIN_ON                              ;no, go set the pin to on
        BTFSC FREQ_MEAS_STAT2,holdover_flag         ;Yes, is FLL in holdover?
        BRA SET_PIN_ON                              ;yes, go set pin to on
        BTFSC FREQ_MEAS_STAT2,stat_fll_unlock       ;no, is the FLL locked?
        BRA SET_PIN_OFF                             ;no, go set the pin to off
SET_PIN_ON                            
        BSF PORTC,ref_10m_ctrl                      ;yes, FLL locked. Set the pin high                                   
        BRA CTRL_REF_RET                            ;leave
SET_PIN_OFF
        BCF PORTC,ref_10m_ctrl                      ;FLL unlocked, set pin off.
CTRL_REF_RET
        RETURN                                      ;Leave routine

;******************************************************************************************************
; CTRL_FLL_STAT_TX
; This code processes and sends out the FLL status string to the serial port. It formats the ASCII string based 
;on the various FLL states and counter values.

CTRL_FLL_STAT_TX
        BTFSS TX_RX_STAT,tx_fll_info_req            ;Is it requested to send out the FLL status string?
        BRA USART_TX_RET                            ;No, leave routine
        BTFSC TX_RX_STAT,tx_cycle_on                ;Yes, Is there a serial port Tx cycle currently being done elsewhere?
        BRA USART_TX_RET                            ;Yes, exit routine
        BTFSC TX_RX_STAT,command_menu_cycle_on      ;No, the command menu being sent flag raised?
        BRA USART_TX_RET                            ;Yes, exit routine
LOAD_TX_STRING
        BCF FREQ_MEAS_STAT2,freq_upd_req            ;No, This is where we clear the frequency update flag in the whole software.
LOAD_TX_L_U_M
        LFSR FSR2,0x190                             ;load Serial Tx buffer's base address in FSR register
        BTFSS FREQ_MEAS_STAT,freq_upd_run           ;check if frequency update process is running.
        BRA LD_DISABLED                             ;No, go to load the Disabled character
        BTFSC FREQ_MEAS_STAT2,holdover_flag         ;Yes, check if FLL in holdover.
        BRA LD_HOLDOVER                             ;Yes, go to load the Holdover character            
        BTFSS FREQ_MEAS_STAT2,stat_fll_unlock       ;No, check if FLL in lock.
        BRA LD_LOCK                                 ;Yes, go to load the lock character
LD_UNLOCK    
        MOVLW "U"                                   ;No, go load the unlock character
        BRA LD_SEP1                                 ;Go work on alarms
LD_LOCK
        MOVLW "L"                                   ;Load the locked character
        BRA LD_SEP1                                 ;Go work on alarms
LD_HOLDOVER
        MOVLW "H"                                   ;Load the holdover character
        BRA LD_SEP1                                 ;Go work on alarms
LD_DISABLED
        MOVLW "D"                                   ;Load the Disabled character
LD_SEP1
        MOVWF POSTINC2                              ;Transfer the FLL state character selected above to Tx buffer
        MOVLW separ_char                            ;Load the separator char.
        MOVWF POSTINC2                              ; "
LD_ALM    
        BTFSS FREQ_MEAS_STAT,freq_upd_run           ;check if frequency update process is running.
        BRA LD_UNLOCK_ALM                           ;No, go to load the Unlocked character
        BTFSC FREQ_ALM_STAT,highside_end            ;Yes, DAC high side reached?
        BRA LD_HIGHSIDE                             ;Yes, go load the highside reached character
        BTFSC FREQ_ALM_STAT,lowside_end             ;No, is the low side reached?
        BRA LD_LOWSIDE                              ;Yes, go load the lowside reached character
        BTFSC FREQ_ALM_STAT,holdover_ctr_expired    ;No, is the holdover period expired flag raised?
        BRA LD_HOLDOVER_EXPD                        ;Yes, Go load the Holdover expired character
        BTFSC FREQ_ALM_STAT,alm_fll_unlock          ;check if FLL in lock.
        BRA LD_UNLOCK_ALM                           ;No, go load the Unlocked character
LD_SEPAR_CHAR
        MOVLW blank_char                            ;Yes, Load the filler character
        BRA LD_SEP2                                 ;Go load the separator character
LD_UNLOCK_ALM
        MOVLW "U"                                   ;Load the Unlocked character
        BRA LD_SEP2                                 ;Go load the separator character
LD_LOWSIDE    
        MOVLW "B"                                   ;Load the lowside char (B for top rail reached).
        BRA LD_SEP2                                 ;Go load the separator character
LD_HIGHSIDE
        MOVLW "T"                                   ;Load the highside char (T for top rail reached).
        BRA LD_SEP2                                 ;Go load the separator character
LD_HOLDOVER_EXPD
        MOVLW "H"                                   ;Load the holdover expired character.
LD_SEP2
        MOVWF POSTINC2                              ;Transfer alarm character to Tx buffer
        MOVLW separ_char                            ;Load the separator char.
        MOVWF POSTINC2                              ; "
LD_DAC_VALUE
        CLRF TEMP2_HI                               ;Clear TEMP2_HI to 0
        MOVFF PWM_DUTY_H,TEMP2_LO                   ;Transfer PWM_DUTY_HI into TEMP2_LO
        BCF STATUS,C                                ;Clear Carry flag to 0
        RLCF TEMP2_LO,F	                            ;Shift TEMP2_LO (PWM_DUTY high) left by 2 positions and transfer carry bits into TEMP2_HI   
        RLCF TEMP2_HI,F                             ; "
        RLCF TEMP2_LO,F                             ; "
        RLCF TEMP2_HI,F                             ; "
        MOVF PWM_DUTY_L,W                           ;Load PWM_DUTY_L into working register
        ADDWF TEMP2_LO,F                          	;Add PWM_Duty low value back into TEMP2_LO.
        MOVFF TEMP2_HI,TEMP1_HI                     ;Load the PWM duty cycle H reg in TEMP1_HI                
        CALL HEX_2_ASCII                            ;Convert to two ASCII characters
        MOVFF TEMP1_HI,POSTINC2                     ;Conversion routine returns TEMP1_HI/TEMP1_HI. Load first Hex char into Tx buffer,
        MOVFF TEMP1_LO,POSTINC2                     ; and second hex char of PWM duty cycle H into Tx buffer.
        MOVFF TEMP2_LO,TEMP1_HI                     ;Load the PWM duty cycle L reg in TEMP1_HI
        CALL HEX_2_ASCII                            ;Convert to two ASCII characters
        MOVFF TEMP1_HI,POSTINC2                     ;Load first Hex char into Tx buffer,
        MOVFF TEMP1_LO,POSTINC2                     ; and second hex char of PWM duty cycle L into Tx buffer.
        MOVFF PWM_DUTY_DITH,TEMP1_HI                ;Load the PWM duty dither reg in TEMP1_HI
        CALL HEX_2_ASCII                            ;Convert to two ASCII characters
        MOVFF TEMP1_LO,POSTINC2                     ; and transfer hex char of PWM dither value into Tx buffer
LD_SEP3
        MOVLW separ_char                            ;Load the separator char.
        MOVWF POSTINC2                              ; "
LD_INC_DEC
        BTFSC FREQ_MEAS_STAT,freq_chg               ;Frequency change happening?
        BRA LD_FREQ_CHG                             ;Yes, go load change character
        BTFSC FREQ_MEAS_STAT2,in_sampling_phase     ;no, Check to see if in sampling phase
        BRA LD_SAMPLING                             ;Yes, go insert the blank character
        BTFSC FREQ_MEAS_STAT2,holdover_flag         ;Is FLL in holdover?        
        BRA LD_SAMPLING                             ;Yes, go load a blank character
        MOVLW "="                                   ;No, load = char
        MOVWF POSTINC2                              ; into Tx buffer
        BRA LD_SEP4                                 ;go load next separation char.
LD_SAMPLING
        MOVLW blank_char                            ;In sampling phase, load blank char
        MOVWF POSTINC2                              ; into Tx buffer
LD_SEP4
        MOVLW separ_char                            ;Load the separator char
        MOVWF POSTINC2                              ; into Tx buffer
        MOVLW blank_char                            ;Load filler char. 
        BRA LD_FREQ_CTR                             ;Go load frequency counter
LD_FREQ_CHG
        BTFSC FREQ_MEAS_STAT,freq_inc_dec           ;frequency change is happening check if frequency increase
        BRA LD_FREQ_CHG_INC                         ;Yes, go to load freq. increase character
        MOVLW "-"                                   ;No, load frequency decrease character
        MOVWF POSTINC2                              ; into Tx buffer.        
        BRA LD_SEP5                                 ;Go load coarse/fine character.
LD_FREQ_CHG_INC
        MOVLW "+"                                   ;Load freq. increase character
        MOVWF POSTINC2                              ; into Tx buffer
LD_SEP5
        MOVLW separ_char                            ;Load the separator char.
        MOVWF POSTINC2                              ; into Tx buffer
LD_COARSE_FINE
        BTFSC FREQ_MEAS_STAT,freq_coarse_fine       ;Check if it is a coarse change
        BRA LD_FREQ_CHG_COARSE                      ;Yes, go load coarse char.
        MOVLW "F"                                   ;No, load fine change char.
        BRA LD_FREQ_CTR                             ;Go load frequency counter.
LD_FREQ_CHG_COARSE                                  ;Coarse change. 
        MOVLW "C"                                   ;Load coarse char.
LD_FREQ_CTR    
        MOVWF POSTINC2                              ;Transfer Coarse/Fine character into Tx buffer
        MOVLW separ_char                            ;Load the separator char.
        MOVWF POSTINC2                              ; into Tx buffer
        MOVFF FREQ160_REG_H,TEMP1_HI                ;Convert FREQ160 High hexadecimal number      
        CALL HEX_2_ASCII                            ; to its ASCII equivalent
        MOVFF TEMP1_HI,POSTINC2                     ;Transfer first hex character into Tx buffer
        MOVFF TEMP1_LO,POSTINC2                     ;Transfer second hex character into Tx buffer
        MOVFF FREQ160_REG_L,TEMP1_HI                ;Convert FREQ160 Low hexadecimal number
        CALL HEX_2_ASCII                            ; to its ASCII equivalent
        MOVFF TEMP1_HI,POSTINC2                     ;Transfer first hex character into Tx buffer
        MOVFF TEMP1_LO,POSTINC2                     ;Transfer second hex character into Tx buffer       
        MOVLW separ_char                            ;Load the separator char.
        MOVWF POSTINC2                              ; "
        MOVFF FILT_AVG_CTR_STOR_H,TEMP1_HI          ;Convert FREQ160 Low hexadecimal number
        CALL HEX_2_ASCII                            ; to its ASCII equivalent
        MOVFF TEMP1_HI,POSTINC2                     ;Transfer first hex character into Tx buffer
        MOVFF TEMP1_LO,POSTINC2                     ;Transfer second hex character into Tx buffer
        MOVFF FILT_AVG_CTR_STOR_L,TEMP1_HI          ;Convert FREQ160 Low hexadecimal number
        CALL HEX_2_ASCII                            ; to its ASCII equivalent
        MOVFF TEMP1_HI,POSTINC2                     ;Transfer first hex character into Tx buffer
        MOVFF TEMP1_LO,POSTINC2                     ;Transfer second hex character into Tx buffer
        MOVLW separ_char                            ;Load the separator char.
        MOVWF POSTINC2                              ; "
        MOVFF FILT_AVG_VAL_STOR_H,TEMP1_HI          ;Convert FREQ160 Low hexadecimal number
        CALL HEX_2_ASCII                            ; to its ASCII equivalent
        MOVFF TEMP1_HI,POSTINC2                     ;Transfer first hex character into Tx buffer
        MOVFF TEMP1_LO,POSTINC2                     ;Transfer second hex character into Tx buffer
        MOVFF FILT_AVG_VAL_STOR_L,TEMP1_HI          ;Convert FREQ160 Low hexadecimal number
        CALL HEX_2_ASCII                            ; to its ASCII equivalent
        MOVFF TEMP1_HI,POSTINC2                     ;Transfer first hex character into Tx buffer
        MOVFF TEMP1_LO,POSTINC2                     ;Transfer second hex character into Tx buffer
        MOVLW separ_char                            ;Load the separator char.
        MOVWF POSTINC2                              ; "
        MOVFF SAMPLE_CTR_H,TEMP1_HI                 ;Convert FREQ160 Low hexadecimal number
        CALL HEX_2_ASCII                            ; to its ASCII equivalent
        MOVFF TEMP1_HI,POSTINC2                     ;Transfer first hex character into Tx buffer
        MOVFF TEMP1_LO,POSTINC2                     ;Transfer second hex character into Tx buffer
        MOVFF SAMPLE_CTR_L,TEMP1_HI                 ;Convert FREQ160 Low hexadecimal number
        CALL HEX_2_ASCII                            ; to its ASCII equivalent
        MOVFF TEMP1_HI,POSTINC2                     ;Transfer first hex character into Tx buffer
        MOVFF TEMP1_LO,POSTINC2                     ;Transfer second hex character into Tx buffer
        MOVLW separ_char                            ;Load the separator char.
        MOVWF POSTINC2                              ; "
        MOVFF HOLDOVER_CTR,TEMP1_HI                 ;Convert FREQ160 Low hexadecimal number
        CALL HEX_2_ASCII                            ; to its ASCII equivalent
        MOVFF TEMP1_HI,POSTINC2                     ;Transfer first hex character into Tx buffer
        MOVFF TEMP1_LO,POSTINC2                     ;Transfer second hex character into Tx buffer
LD_CR_LF
        MOVLW "\r"                                  ;Load CR
        MOVWF POSTINC2                              ; into Tx buffer
        MOVLW "\n"                                  ;Load LF
        MOVWF POSTINC2                              ; into Tx buffer
        MOVLW 00h                                   ;Load Null
        MOVWF POSTINC2                              ; into Tx buffer
        MOVLW mask_freq_adj_clr                     ;clear all frequency adjust flags 
        ANDWF FREQ_MEAS_STAT,F                      ; "
        BSF TX_RX_STAT,new_tx_cycle                 ;raise new TX cycle flag
        BSF TX_RX_STAT,tx_cycle_on                  ;Raise the Tx cycle on flag to get exclusive access of the serial port Tx. 
        BSF PIE1,TXIE                               ;enable TX interrupts             
        BCF TX_RX_STAT,tx_fll_info_req              ;Clear the FLL status string request flag    
USART_TX_RET
        RETURN                                      ;Leave routine

;******************************************************************************************************
;CTRL_PARAM_INFO_TX
;This piece of code processes the transmission of the FLL parameter string to the serial port. It teansfers the 
;FLL parameters and formats the ASCII string.

CTRL_PARAM_INFO_TX
        BTFSS TX_RX_STAT,send_info                  ;Is it requested to send FLL parameter string?
        BRA USART_INFO_RET                          ;no, exit routine   
        BTFSC TX_RX_STAT,tx_cycle_on                ;Yes, is a string being sent now?
        BRA USART_INFO_RET                          ;yes, exit routine            
        LFSR FSR2,0x190                             ;No, load Serial Tx buffer's base address in FSR register
SEND_SAMPLE_SIZE
        MOVLW "S"                                   ;Load "S" character
        MOVWF POSTINC2                              ; into Tx buffer
        MOVFF FILT_AVG_LIMIT_H,TEMP1_HI             ;Load the sample limit H reg in TEMP1_HI                
        CALL HEX_2_ASCII                            ;Convert to two ASCII characters
        MOVFF TEMP1_HI,POSTINC2                     ;Conversion routine returns TEMP1_HI/TEMP1_HI. Load first Hex char into Tx buffer.
        MOVFF TEMP1_LO,POSTINC2                     ; and second hex char of PWM duty cycle H into Tx buffer.
        MOVFF FILT_AVG_LIMIT_L,TEMP1_HI             ;Load the sample limit L reg in TEMP1_HI                
        CALL HEX_2_ASCII                            ;Convert to two ASCII characters
        MOVFF TEMP1_HI,POSTINC2                     ;Conversion routine returns TEMP1_HI/TEMP1_HI. Load first Hex char into Tx buffer.
        MOVFF TEMP1_LO,POSTINC2                     ; and second hex char of PWM duty cycle H into Tx buffer.
        MOVLW separ_char                            ;Load the separator char
        MOVWF POSTINC2                              ;  into Tx buffer.
SEND_FINE_COARSE_LIMIT
        MOVLW "F"                                   ;Load "F" character
        MOVWF POSTINC2                              ; into Tx buffer
        MOVFF DITHER_LIMIT,TEMP1_HI                 ;Load the fine/coarse limit in TEMP1_HI                
        CALL HEX_2_ASCII                            ;Convert to two ASCII characters
        MOVFF TEMP1_HI,POSTINC2                     ;Conversion routine returns TEMP1_HI/TEMP1_HI. Load first Hex char into Tx buffer.
        MOVFF TEMP1_LO,POSTINC2                     ; and second hex char of PWM duty cycle H into Tx buffer.
        MOVLW separ_char                            ;Load the separator char
        MOVWF POSTINC2                              ;  into Tx buffer.
SEND_LOCK_LIMIT
        MOVLW "L"                                   ;Load "L" character
        MOVWF POSTINC2                              ; into Tx buffer
        MOVFF LOCK_LIMIT,TEMP1_HI                   ;Load the Lock limit reg in TEMP1_HI                
        CALL HEX_2_ASCII                            ;Convert to two ASCII characters
        MOVFF TEMP1_HI,POSTINC2                     ;Conversion routine returns TEMP1_HI/TEMP1_HI. Load first Hex char into Tx buffer.
        MOVFF TEMP1_LO,POSTINC2                     ; and second hex char of PWM duty cycle H into Tx buffer.
        MOVLW separ_char                            ;Load the separator char
        MOVWF POSTINC2                              ;  into Tx buffer.
SEND_HOLDOVER_LIMIT
        MOVLW "H"                                   ;Load "H" character
        MOVWF POSTINC2                              ; into Tx buffer
        MOVFF HOLDOVER_LIMIT,TEMP1_HI               ;Load the Holdover limit reg in TEMP1_HI                
        CALL HEX_2_ASCII                            ;Convert to two ASCII characters
        MOVFF TEMP1_HI,POSTINC2                     ;Conversion routine returns TEMP1_HI/TEMP1_HI. Load first Hex char into Tx buffer.
        MOVFF TEMP1_LO,POSTINC2                     ; and second hex char into Tx buffer.
        MOVLW separ_char                            ;Load the separator char
        MOVWF POSTINC2                              ;  into Tx buffer.
SEND_HOLDOVER_CTR_LIMIT
        MOVLW "W"                                   ;Load "W" character
        MOVWF POSTINC2                              ; into Tx buffer
        MOVFF HOLDOVER_CTR_LIMIT,TEMP1_HI           ;Load the Holdover counter limit reg in TEMP1_HI                
        CALL HEX_2_ASCII                            ;Convert to two ASCII characters
        MOVFF TEMP1_HI,POSTINC2                     ;Conversion routine returns TEMP1_HI/TEMP1_HI. Load first Hex char into Tx buffer.
        MOVFF TEMP1_LO,POSTINC2                     ; and second hex char into Tx buffer.
        MOVLW separ_char                            ;Load the separator char
        MOVWF POSTINC2                              ;  into Tx buffer.
SEND_FREQ_CHG_THRESH
        MOVLW "N"                                   ;Load "N" character
        MOVWF POSTINC2                              ; into Tx buffer
        MOVFF FREQ_CHG_THRESH,TEMP1_HI              ;Load the Frequency Change Negate threshold reg in TEMP1_HI                
        CALL HEX_2_ASCII                            ;Convert to two ASCII characters
        MOVFF TEMP1_HI,POSTINC2                     ;Conversion routine returns TEMP1_HI/TEMP1_HI. Load first Hex char into Tx buffer.
        MOVFF TEMP1_LO,POSTINC2                     ; and second hex char into Tx buffer.
        MOVLW separ_char                            ;Load the separator char
        MOVWF POSTINC2                              ; into Tx buffer.
SEND_10M_REF_CTRL_STAT
        MOVLW "O"                                   ;Load "O" character
        MOVWF POSTINC2                              ; into Tx buffer
        MOVFF CTRL_REF_OUT_MODE,TEMP1_HI            ;Load the 10M reference control mode reg in TEMP1_HI                
        CALL HEX_2_ASCII                            ;Convert to two ASCII characters
        MOVFF TEMP1_HI,POSTINC2                     ;Conversion routine returns TEMP1_HI/TEMP1_HI. Load first Hex char into Tx buffer.
        MOVFF TEMP1_LO,POSTINC2                     ; and second hex char into Tx buffer.
        MOVLW separ_char                            ;Load the separator char
        MOVWF POSTINC2                              ;  into Tx buffer.
SEND_VCXO_SLOPE_MODE
        MOVLW "X"                                   ;Load "X" character
        MOVWF POSTINC2                              ; into Tx buffer
        MOVFF VCXO_SLOPE_MODE,TEMP1_HI              ;Load the VCXO xlope mode reg in TEMP1_HI                
        CALL HEX_2_ASCII                            ;Convert to two ASCII characters
        MOVFF TEMP1_HI,POSTINC2                     ;Conversion routine returns TEMP1_HI/TEMP1_HI. Load first Hex char into Tx buffer.
        MOVFF TEMP1_LO,POSTINC2                     ; and second hex char into Tx buffer.
        MOVLW separ_char                            ;Load the separator char
        MOVWF POSTINC2                              ;  into Tx buffer.
SEND_FLL_AVG_MODE
        MOVLW "M"                                   ;Load "M" character
        MOVWF POSTINC2                              ; into Tx buffer
        MOVFF FLL_AVG_MODE,TEMP1_HI                 ;Load the Frequency Averaging mode reg in TEMP1_HI                
        CALL HEX_2_ASCII                            ;Convert to two ASCII characters
        MOVFF TEMP1_HI,POSTINC2                     ;Conversion routine returns TEMP1_HI/TEMP1_HI. Load first Hex char into Tx buffer.
        MOVFF TEMP1_LO,POSTINC2                     ; and second hex char into Tx buffer.
SEND_CR_LF
        MOVLW "\r"                                  ;Load CR
        MOVWF POSTINC2                              ; into Tx buffer
        MOVLW "\n"                                  ;Load LF
        MOVWF POSTINC2                              ; into Tx buffer
        MOVLW 00h                                   ;Load Null
        MOVWF POSTINC2                              ; into Tx buffer
        BSF TX_RX_STAT,new_tx_cycle                 ;raise new TX cycle flag
        BCF TX_RX_STAT,send_info                    ;Clear the FLL parameter string request flag       
        BSF TX_RX_STAT,tx_cycle_on                  ;Raise the transmit cycle flag       
        BSF PIE1,TXIE                               ;enable TX interrupts              
USART_INFO_RET
        RETURN                                      ;Leave routine

;******************************************************************************************************
;CTRL_COMMAND_RX
;This piece of code processes the user commands received on the serial port and updates the FLL parameters whenever necessary.

;  RS-232 Commands Supported
;  --------------------------
;   
;  D<CR><LF>:       Disables FLL and enables manual tuning
;  E<CR><LF>:       Enables FLL and disables manual tuning
;  A<CR><LF>:       Clears any latched alarms
;  C<CR><LF>:       Clears the sample counter
;  R<CR><LF>:       Soft Reset of the Microprocessor
;  P<CR><LF>:       Sends parameter setting information to serial port
;  V<CR><LF>:       Sends startup string (version info) to serial port
;  Tyyzz<CR><LF>:   Tunes the DAC to hexadecimal value "yyzz". Maximum allowed value is 03FF (10 bits). Dither value unaffected.
;                   Caution! No validation is performed on the value.
;  Syyzz<CR><LF>:   Sets the sampling size to exadeciaml "yyzz" (number of 16-second samples averaged before adjusting FLL frequency
;                   Maximum allowed value is FFFF (16 bits)
;  Fxx<CR><LF>:     Sets the Fine/Coarse DAC adjustment threshold value to hexadeciaml "xx". Maximum allowed value is 0xFF (8 bits)
;                   Maximum allowed value is FF (8 bits)
;  Lxx<CR><LF>:     Sets the Locked/Unlocked threshold value to hexadeciaml "xx". Maximum allowed value is 0xFF (8 bits)
;                   Maximum allowed value is FF (8 bits)
;  Wxx<CR><LF>:     Sets the Holdover Wait Counter threshold value to hexadeciaml "xx". Maximum allowed value is 0xFF (8 bits)
;                   Maximum allowed value is FF (8 bits)
;  Hxx<CR><LF>:     Sets the Holdover threshold value to hexadeciaml "xx". Maximum allowed value is 0xFF (8 bits)
;                   Maximum allowed value is FF (8 bits)
;  Nxx<CR><LF>:     Sets the No Frequency Change Threshold value to hexadeciaml "xx". Maximum allowed value is 0xFF (8 bits)
;                   Maximum allowed value is FF (8 bits)
;  Oxx<CR><LF>:     Sets the 10MHz output control mode value to hexadecimal "01" (disabled) or "02" (enabled). Allowed values are 
;                   0x01 or 0x02 (8 bits).
;  Xxx<CR><LF>:     Sets the VCXO tuning slope mode value to hexadecimal "01" (positive) or "02" (negative).  Allowed values are 
;                   0x01 or 0x02 (8 bits).
;  Mxx<CR><LF>:     Sets the FLL averaging mode value to hexadecimal "01" (voting) or "02" (summing).  Allowed values are 
;                   0x01 or 0x02 (8 bits).

CTRL_COMMAND_RX
        BTFSC TX_RX_STAT,tx_cycle_on                ;Is a Tx cycle being processed?
        BRA USART_RX_RET                            ;Yes, leave (Indirect addressing reg. FSR2 shared with CTRL_TX_STRING)
        BTFSS TX_RX_STAT,lf_eoc_received            ;No, has end of command flag (LF) been detected by interrupt routine
        BRA USART_RX_RET                            ;No, leave routine
        BCF PIE1,RCIE                               ;Yes, disable RX interrupts                 
        BCF TX_RX_STAT,lf_eoc_received              ;Clear the end of command flag
        LFSR FSR2,0x180                             ;Load Serial rx buffer's base address in FSR register
        MOVFF POSTINC2,TEMP1_LO                     ;Transfer first char into temp variable
        MOVLW "D"                                   ;Load character D into Wreg
        CPFSEQ TEMP1_LO                             ;Is it the Disable command?
        BRA NEXT_CMD1                               ;No, go to next validation
        BCF FREQ_MEAS_STAT,freq_upd_run             ;Yes, Clear the Frequency update Running Flag
        BCF FREQ_MEAS_STAT2,holdover_flag           ;Clear FLL from any holdover
        BSF FREQ_MEAS_STAT2,stat_fll_unlock         ;Put FLL in unlock.
        CALL END_SAMPLING_CYCLE                     ;End frequency sampling cycle
        BRA CLR_RX_BUFF                             ;go empty rx buffer
NEXT_CMD1       
        MOVLW "E"                                   ;Load character E into Wreg
        CPFSEQ TEMP1_LO                             ;Is it Enable FLL command?
        BRA NEXT_CMD2                               ;No, go to next validation
        BSF FREQ_MEAS_STAT,freq_upd_run             ;Yes, Set the Frequency update Running Flag
        CALL END_SAMPLING_CYCLE                     ;End frequency sampling cycle
        BRA CLR_RX_BUFF                             ;go empty rx buffer
NEXT_CMD2
        MOVLW "A"                                   ;Load character A into Wreg
        CPFSEQ TEMP1_LO                             ;Is it Clear Alarm command?
        BRA NEXT_CMD3                               ;No, go to next validation
        CLRF FREQ_ALM_STAT                          ;Yes, clear the alarm register
        BRA CLR_RX_BUFF                             ;go empty rx buffer
NEXT_CMD3
        MOVLW "T"                                   ;Load character T into Wreg
        CPFSEQ TEMP1_LO                             ;Is it Tune command?
        BRA NEXT_CMD4                               ;No, go to next validation
        BTFSS FREQ_MEAS_STAT,freq_upd_run           ;Check if FLL running. 
        BRA PROCESS_T                               ;No, go to process Tune command
        BRA CLR_RX_BUFF                             ;Yes, do not process the Tune command and go to clear rx buffer
CHAR_XFER                                               ;Piece of code called by other command read below
        MOVFF POSTINC2,TEMP1_HI                     ;Transfer high character of hex into TEMP1_HI
        MOVFF POSTINC2,TEMP1_LO                     ;Transfer low character of hex into TEMP1_LO
        CALL ASCII_2_HEX                            ;Convert to hex value. Zero Flag is valid here.
        RETURN                                      ;Return
PROCESS_T                                           ;No LSB bit filtering performed here. No Dither tuning done
        BSF TX_RX_STAT,tx_fll_info_req              ;Set the Fll status string request flag
        BSF GENERAL1_STAT,write_cycle_req           ;Set the flag to write the EEPROM with the DAC value and all other parameters
        CALL CHAR_XFER                              ;Call the character transfer loop
        MOVFF TEMP1_HI,PWM_DUTY_H                   ;Transfer hex value into PWM_DUTY_H
        CALL CHAR_XFER                              ;Call the character transfer loop
        MOVF TEMP1_HI,W                             ;Transfer hex value into Wreg
        ANDLW 03h                                   ;Filter PWM_DUTY_L bits (Max value is 03)
        MOVWF PWM_DUTY_L                            ;Transfer hex value into PWM_DUTY_L
		BCF STATUS,C								;Clear Carry flag to 0
        RRCF PWM_DUTY_H,F                           ;Transfer PWM_DUTY_H bits with remaining PWM_DUTY_L bits into PWM_DUTY_H
        RRCF TEMP1_HI,F                             ;  Roll to the right twice to position the HI value.
        RRCF PWM_DUTY_H,F                           ;  Careful, the carry flag is important here....
        RRCF TEMP1_HI,F                             ; "
        MOVFF TEMP1_HI,PWM_DUTY_H                   ; "
        BRA CLR_RX_BUFF                             ;Go to clear rx buffer
NEXT_CMD4
        MOVLW "S"                                   ;Load character S into Wreg
        CPFSEQ TEMP1_LO                             ;Is it Sampling Size command?
        BRA NEXT_CMD5                               ;No, go to next validation
        CALL CHAR_XFER                              ;Yes, Call the character transfer loop
        MOVFF TEMP1_HI,TEMP2_HI                     ;Temporarily save the Hi value in TEMP2_HI
        CALL CHAR_XFER                              ;Call the character transfer loop
        TSTFSZ TEMP1_HI                             ;Is L value = 0?
        BRA S_NOT_ZERO                              ;No, Go accept new S value 
        TSTFSZ TEMP2_HI                             ;Yes, test the H value. Is H = 0?
        BRA S_NOT_ZERO                              ;No, Go accept new S value 
        BRA CLR_RX_BUFF_JMP_AGAIN                   ;Yes, go to clear rx buffer              
S_NOT_ZERO
        MOVFF TEMP2_HI,FILT_AVG_LIMIT_H             ;Transfer hex value into FILT_AVG_LIMIT Hi
        MOVFF TEMP1_HI,FILT_AVG_LIMIT_L             ;Transfer hex value into FILT_AVG_LIMIT Low           
        BSF GENERAL1_STAT,write_cycle_req           ;Set the flag to write the EEPROM with the DAC value and all other parameters
        BSF TX_RX_STAT,send_info                    ;set the send settings information flag
        BRA CLR_RX_BUFF                             ;Go to clear rx buffer                   
NEXT_CMD5 
        MOVLW "F"                                   ;Load character F into Wreg
        CPFSEQ TEMP1_LO                             ;Is it Fine/Coarse Granularity threshold set command?
        BRA NEXT_CMD6                               ;No, go to next validation
        CALL CHAR_XFER                              ;Yes, Call the character transfer loop
        BZ CLR_RX_BUFF_JMP_AGAIN                    ;If value = 0, go to clear rx buffer (via CLR_RX_BUFF_JMP_AGAIN, which is a relay to CLR_RX_BUFF)
        MOVFF TEMP1_HI,DITHER_LIMIT                 ;Transfer hex value into DITHER_LIMIT
        BSF GENERAL1_STAT,write_cycle_req           ;Set the flag to write the EEPROM with the DAC value and all other parameters
        BSF TX_RX_STAT,send_info                    ;set the send settings information flag
        BRA CLR_RX_BUFF                             ;Go to clear rx buffer             
NEXT_CMD6
        MOVLW "C"                                   ;Load character C into Wreg
        CPFSEQ TEMP1_LO                             ;Is it Clear sample counter command?
        BRA NEXT_CMD7                               ;No, go to next validation
        CLRF SAMPLE_CTR_H                           ;clear the counter H
        CLRF SAMPLE_CTR_L                           ;clear the counter L
        BRA CLR_RX_BUFF                             ;go empty rx buffer
NEXT_CMD7
        MOVLW "P"                                   ;Load character P into Wreg
        CPFSEQ TEMP1_LO                             ;Is it send parameter information command?
        BRA NEXT_CMD8                               ;No, go to next validation
        BSF TX_RX_STAT,send_info                    ;set the send settings information flag
        BRA CLR_RX_BUFF                             ;go empty rx buffer
NEXT_CMD8
        MOVLW "L"                                   ;Load character L into Wreg
        CPFSEQ TEMP1_LO                             ;Is it Locked/Unlocked threshold command?
        BRA NEXT_CMD9                               ;No, go to next validation
        CALL CHAR_XFER                              ;Yes, Call the character transfer loop
        BZ CLR_RX_BUFF_JMP_AGAIN                    ;If value = 0, go to clear rx buffer               
        MOVFF TEMP1_HI,LOCK_LIMIT                   ;Transfer hex value into LOCK_LIMIT
        BSF GENERAL1_STAT,write_cycle_req           ;Set the flag to write the EEPROM with the DAC value and all other parameters
        BSF TX_RX_STAT,send_info                    ;set the send settings information flag
        BRA CLR_RX_BUFF                             ;Go to clear rx buffer                   
NEXT_CMD9
        MOVLW "W"                                   ;Load character W into Wreg
        CPFSEQ TEMP1_LO                             ;Is it Holdover Wait Counter limit command?
        BRA NEXT_CMD10                              ;No, go to next validation
        CALL CHAR_XFER                              ;Yes, Call the character transfer loop
        BZ CLR_RX_BUFF                              ;If value = 0, go to clear rx buffer               
        MOVFF TEMP1_HI,HOLDOVER_CTR_LIMIT           ;Transfer hex value into HOLDOVER_CTR_LIMIT
        BSF GENERAL1_STAT,write_cycle_req           ;Set the flag to write the EEPROM with the DAC value and all other parameters
        BSF TX_RX_STAT,send_info                    ;set the send settings information flag
        BRA CLR_RX_BUFF                             ;Go to clear rx buffer                   
NEXT_CMD10
        MOVLW "N"                                   ;Load character N into Wreg
        CPFSEQ TEMP1_LO                             ;Is it the Frequency Change Negate threshold command?
        BRA NEXT_CMD11                              ;No, go to next validation
        CALL CHAR_XFER                              ;Yes, Call the character transfer loop
        BZ CLR_RX_BUFF                              ;If value = 0, go to clear rx buffer               
        MOVFF TEMP1_HI,FREQ_CHG_THRESH              ;Transfer hex value into FREQ_CHG_THRESH
        BSF GENERAL1_STAT,write_cycle_req           ;Set the flag to write the EEPROM with the DAC value and all other parameters  
        BSF TX_RX_STAT,send_info                    ;set the send settings information flag
        BRA CLR_RX_BUFF                             ;Go to clear rx buffer       
NEXT_CMD11
        MOVLW "O"                                   ;Load character O into Wreg
        CPFSEQ TEMP1_LO                             ;Is it the Reference output mode command?
        BRA NEXT_CMD12                              ;No, go to next validation
        CALL CHAR_XFER                              ;Yes, Call the character transfer loop
        BZ CLR_RX_BUFF                              ;If value = 0, go to clear rx buffer               
        MOVFF TEMP1_HI,CTRL_REF_OUT_MODE            ;Transfer hex value into CTRL_REF_OUT_MODE
        BSF GENERAL1_STAT,write_cycle_req           ;Set the flag to write the EEPROM with the DAC value and all other parameters
        BSF TX_RX_STAT,send_info                    ;set the send settings information flag
CLR_RX_BUFF_JMP_AGAIN                               ;This is used because the BZ instruction can only jump 127 bytes
        BRA CLR_RX_BUFF                             ;Go to clear rx buffer                               
NEXT_CMD12
        MOVLW "V"                                   ;Load character V into Wreg
        CPFSEQ TEMP1_LO                             ;Is it send startup prompt command?
        BRA NEXT_CMD13                              ;No, go to next validation
        BSF TX_RX_STAT,startup_prompt_req           ;Yes, set flag to send startup prompt
        BRA CLR_RX_BUFF                             ;go empty rx buffer
NEXT_CMD13
        MOVLW "?"                                   ;Load character ? into Wreg
        CPFSEQ TEMP1_LO                             ;Is it menu command?
        BRA NEXT_CMD14                              ;No, go to next validation
        BSF TX_RX_STAT,command_menu_cycle_on        ;Set the send command menu being sent flag
        BSF TX_RX_STAT,command_menu_req             ;set the send command menu flag
        BRA CLR_RX_BUFF                             ;go empty rx buffer
NEXT_CMD14
        MOVLW "H"                                   ;Load character H into Wreg
        CPFSEQ TEMP1_LO                             ;Is it Holdover threshold command?
        BRA NEXT_CMD15                              ;No, go to next validation
        CALL CHAR_XFER                              ;Yes, Call the character transfer loop
        BZ CLR_RX_BUFF                              ;If value = 0, go to clear rx buffer               
        MOVFF TEMP1_HI,HOLDOVER_LIMIT               ;Transfer hex value into HOLDOVER_CTR_LIMIT
        BSF GENERAL1_STAT,write_cycle_req           ;Set the flag to write the EEPROM with the DAC value and all other parameters
        BSF TX_RX_STAT,send_info                    ;set the send settings information flag
        BRA CLR_RX_BUFF                             ;Go to clear rx buffer                   
NEXT_CMD15
        MOVLW "X"                                   ;Load character X into Wreg
        CPFSEQ TEMP1_LO                             ;Is it the VCXO tuning slope command?
        BRA NEXT_CMD16                              ;No, go to next validation
        CALL CHAR_XFER                              ;Yes, Call the character transfer loop
        BZ CLR_RX_BUFF                              ;If value = 0, go to clear rx buffer               
        MOVFF TEMP1_HI,VCXO_SLOPE_MODE              ;Transfer hex value into VCXO_SLOPE_MODE
        BSF GENERAL1_STAT,write_cycle_req           ;Set the flag to write the EEPROM with the DAC value and all other parameters
        BSF TX_RX_STAT,send_info                    ;set the send settings information flag
        BRA CLR_RX_BUFF                             ;Go to clear rx buffer         
NEXT_CMD16
        MOVLW "M"                                   ;Load character M into Wreg
        CPFSEQ TEMP1_LO                             ;Is it the FLL averaging mode command?
        BRA NEXT_CMD17                              ;No, go to next validation
        CALL CHAR_XFER                              ;Yes, Call the character transfer loop
        BZ CLR_RX_BUFF                              ;If value = 0, go to clear rx buffer               
        MOVFF TEMP1_HI,FLL_AVG_MODE                 ;Transfer hex value into FLL_AVG_MODE
        CALL END_SAMPLING_CYCLE                     ;end sampling cycle
        BSF GENERAL1_STAT,write_cycle_req           ;Set the flag to write the EEPROM with the DAC value and all other parameters   
        BSF TX_RX_STAT,send_info                    ;set the send settings information flag
        BRA CLR_RX_BUFF                             ;Go to clear rx buffer                             
NEXT_CMD17
        MOVLW "R"                                   ;Load character R into Wreg
        CPFSEQ TEMP1_LO                             ;Is it Reset command?
        BRA CLR_RX_BUFF                             ;No, go to next validation
        RESET                                       ;Execute device reset
CLR_RX_BUFF
        LFSR FSR2,0x180                             ;load Serial rx buffer's base address in FSR register.
CLR_RX_BUFF_LOOP
        CLRF POSTINC2                               ;Clear Rx buffer cell and increase indirect addressing pointer
        MOVLW 0x90
        CPFSLT FSR2L
        BRA CLR_RX_BUFF_LOOP                        ;No, loop again. Yes, exit routine
USART_RX_RET                                        ;Yes, exit routine
        BSF PIE1,RCIE                               ;Enable RX interrupts                    
        RETURN                                      ;exit routine

;******************************************************************************************************
;CTRL_OTHER_TX
;This piece of code processes the transmission of the command menu and the startup prompt to the serial port.
;The command menu is processed one line at a time. This code is executed for each line of command menu.
;For the statup string, this code processes thw whole startup string at once.

CTRL_OTHER_TX
        BTFSC TX_RX_STAT,tx_cycle_on                ;Is a Tx cycle being processed by interrupt routine?
        BRA LOAD_STARTUP_RET                        ;Yes, leave
        BTFSC TX_RX_STAT,startup_prompt_req         ;No, is send startup prompt flag raised?
        BRA LD_STARTUP_STRING                       ;Go load startup string
        BTFSS TX_RX_STAT,command_menu_cycle_on      ;Is there a command menu transmission cycle being sent?
        BRA LOAD_STARTUP_RET                        ;No, leave routine    
        BTFSS TX_RX_STAT,command_menu_req           ;Yes, is send command menu request flag raised (new menu Tx cycle)?
        BRA BEGIN_LD_STRING                         ;No, go load next line of command menu.
INIT_MENU_TX
        BCF TX_RX_STAT,command_menu_req             ;Yes, here, we begin the command menu Tx processing. Clear the send command menu request flag.
        MOVLW high COMMAND_MENU_LOCN                ;Load Tx startup prompt's high address location in the table pointer H
        MOVWF TBLPTRH                               ; "
        MOVLW low COMMAND_MENU_LOCN                 ;Load Tx startup prompt's low address location in the table pointer L
        MOVWF TBLPTRL                               ; "
        BRA BEGIN_LD_STRING                         ;Go load first line of command menu.
LD_STARTUP_STRING
        BCF TX_RX_STAT,startup_prompt_req           ;Here we process the startup string. Clear startup prompt flag
        MOVLW high STARTUP_STRING_LOCN              ;Load Tx startup prompt's high address location in the table pointer H
        MOVWF TBLPTRH                               ; "
        MOVLW low STARTUP_STRING_LOCN               ;Load Tx startup prompt's low address location in the table pointer L
        MOVWF TBLPTRL                               ; "
BEGIN_LD_STRING
        CLRF TBLPTRU                                ;Load TBLPTR with the base address of the word
        LFSR FSR2,0x190                             ;load Serial Tx buffer's base address in FSR register
LOAD_TX_LOOP
        MOVLW eecon1_prog_ee_access                 ;Initialize EEPROM data configuration registrer
        MOVWF EECON1                                ; "
        TBLRD*+                                     ; read into TABLAT and increment TBLPTR
        TSTFSZ TABLAT                               ;Is character nil?      
        BRA LOAD_CHAR_OK                            ;no, go load character in TX stack
        BRA SEND_TX_DATA                            ;Yes, continue to initialize other registers
LOAD_CHAR_OK
        MOVFF TABLAT,POSTINC2                       ;get data and transfer it to the Tx buffer
        BRA LOAD_TX_LOOP                            ;go read next character
SEND_TX_DATA
        BTFSS TX_RX_STAT,command_menu_cycle_on      ;Is the command menu being sent flag raised?
        BRA SET_TX_FLAGS                            ;No, go set the transmission request flags
        TBLRD*                                      ;Yes, read into TABLAT but do not increment TBLPTR       
        MOVLW "$"                                   ;Is character $ (end of menu)?      
        CPFSEQ TABLAT                               ; "
        BRA SET_TX_FLAGS                            ;No, go set the transmission request flags
        BCF TX_RX_STAT,command_menu_cycle_on        ;Yes, clear the command menu being sent flag?         
SET_TX_FLAGS
        BSF TX_RX_STAT,new_tx_cycle                 ;Set new Tx cycle flag
        BSF TX_RX_STAT,tx_cycle_on                  ;Set the Tx cycle on flag     
        BSF PIE1,TXIE                               ;enable TX interrupts              
LOAD_STARTUP_RET
       RETURN                                       ;exit routine.

;******************************************************************************************************
;CTRL_PARAM_UPD_EEPROM
;This portion of code writes the FLL parameters to data EEPROM. This is a multi-pass process. Before the
;next byte write cycle can be processed, s/w must wait for the previous byte write cycle to complete.

CTRL_PARAM_UPD_EEPROM
        BTFSS GENERAL1_STAT,write_cycle_req         ;Is a Parameter Write cycle required or in progress?
        BRA UPDATE_PARAM_RET                        ;No, leave routine
        BTFSC TX_RX_STAT,tx_cycle_on                ;Is a Tx cycle being processed?
        BRA UPDATE_PARAM_RET                        ;Yes, leave (EEPROM access of Data and Program must not happen concurrently)
        BTFSC EECON1,WR                             ;Yes, is Write cycle happening
        BRA UPDATE_PARAM_RET                        ;Yes, leave routine
EXECUTE_WRITE                    
        MOVLW .0                                    ;No, is is time to load the valid Data Flag (00) parameter in the first location?
        CPFSEQ WRT_EEPROM_POS                       ; "
        BRA TEST_1                                  ;No, go test next parameter
        CLRF TEMP1_LO                               ;Yes, load 0 in TEMP1_LO
        BRA WRITE_EEPROM_NOW                        ;Go write parameter in EEPROM
TEST_1
        MOVLW .1                                    ;Is is time to load the first parameter?
        CPFSEQ WRT_EEPROM_POS                       ; "
        BRA TEST_2                                  ;No, go test next parameter
        MOVFF FILT_AVG_LIMIT_H,TEMP1_LO             ;Yes, load value in TEMP1_LO
        BRA WRITE_EEPROM_NOW                        ;Go write parameter in EEPROM
TEST_2
        MOVLW .2                                    ;Is is time to load the Second parameter?
        CPFSEQ WRT_EEPROM_POS                       ; "
        BRA TEST_3                                  ;No, go test next parameter
        MOVFF FILT_AVG_LIMIT_L,TEMP1_LO             ;Yes, load value in TEMP1_LO
        BRA WRITE_EEPROM_NOW                        ;Go write parameter in EEPROM
TEST_3
        MOVLW .3                                    ;Is is time to load the third parameter?
        CPFSEQ WRT_EEPROM_POS                       ; "
        BRA TEST_4                                  ;No, go test next parameter
        MOVFF DITHER_LIMIT,TEMP1_LO                 ;Yes, load value in TEMP1_LO
        BRA WRITE_EEPROM_NOW                        ;Go write parameter in EEPROM
TEST_4
        MOVLW .4                                    ;Is is time to load the forth parameter?
        CPFSEQ WRT_EEPROM_POS                       ; "
        BRA TEST_5                                  ;No, go test next parameter
        MOVFF LOCK_LIMIT,TEMP1_LO                   ;Yes, load value in TEMP1_LO
        BRA WRITE_EEPROM_NOW                        ;Go write parameter in EEPROM
TEST_5
        MOVLW .5                                    ;Is is time to load the fifth parameter?
        CPFSEQ WRT_EEPROM_POS                       ; "
        BRA TEST_6                                  ;No, go test next parameter
        MOVFF HOLDOVER_CTR_LIMIT,TEMP1_LO           ;Yes, load value in TEMP1_LO
        BRA WRITE_EEPROM_NOW                        ;Go write parameter in EEPROM
TEST_6
        MOVLW .6                                    ;Is is time to load the sixth parameter?
        CPFSEQ WRT_EEPROM_POS                       ; "
        BRA TEST_7                                  ;No, go test next parameter
        MOVFF FREQ_CHG_THRESH,TEMP1_LO              ;Yes, load value in TEMP1_LO
        BRA WRITE_EEPROM_NOW                        ;Go write parameter in EEPROM
TEST_7
        MOVLW .7                                    ;Is is time to load the seventh parameter?
        CPFSEQ WRT_EEPROM_POS                       ; "
        BRA TEST_8                                  ;No, go test next parameter
        MOVFF PWM_DUTY_H,TEMP1_LO                   ;Yes, load value in TEMP1_LO
        BRA WRITE_EEPROM_NOW                        ;Go write parameter in EEPROM
TEST_8
        MOVLW .8                                    ;Is is time to load the eighth parameter?
        CPFSEQ WRT_EEPROM_POS                       ; "
        BRA TEST_9                                  ;No, go test next parameter
        MOVFF PWM_DUTY_L,TEMP1_LO                   ;Yes, load value in TEMP1_LO
        BRA WRITE_EEPROM_NOW                        ;Go write parameter in EEPROM
TEST_9
        MOVLW .9                                    ;Is is time to load the ninth parameter?
        CPFSEQ WRT_EEPROM_POS                       ; "
        BRA TEST_10                                 ;No, go test next parameter
        MOVFF CTRL_REF_OUT_MODE,TEMP1_LO            ;Yes, load value in TEMP1_LO
        BRA WRITE_EEPROM_NOW                        ;Go write parameter in EEPROM
TEST_10
        MOVLW .10                                   ;Is is time to load the tenth parameter?
        CPFSEQ WRT_EEPROM_POS                       ; "
        BRA TEST_11                                 ;No, go test next parameter
        MOVFF HOLDOVER_LIMIT,TEMP1_LO               ;Yes, load value in TEMP1_LO
        BRA WRITE_EEPROM_NOW                        ;Go write parameter in EEPROM
TEST_11
        MOVLW .11                                   ;Is is time to load the eleventh parameter?
        CPFSEQ WRT_EEPROM_POS                       ; "
        BRA TEST_12                                 ;No, go test next parameter
        MOVFF VCXO_SLOPE_MODE,TEMP1_LO              ;Yes, load value in TEMP1_LO
        BRA WRITE_EEPROM_NOW                        ;Go write parameter in EEPROM
TEST_12
        MOVLW .12                                   ;Is is time to load the twelvth parameter?
        CPFSEQ WRT_EEPROM_POS                       ; "
        BRA FORCE_END_WRITE_CYCLE                   ;No, (this is not a normal end) go force end of write cycle and leave routine
        MOVFF FLL_AVG_MODE,TEMP1_LO                 ;Yes, load value in TEMP1_LO
        BRA WRITE_EEPROM_NOW                        ;Go write parameter in EEPROM
WRITE_EEPROM_NOW                                    ;EEPROM address is still currently in Wreg
        CALL WRITE_EEPROM_DATA                      ;Call EEPROM writing routine
        INCF WRT_EEPROM_POS,F                       ;Increment EEPROM Writing Position
        MOVLW number_param_to_stor                  ;Is this the last address (parameter) to write?
        CPFSEQ WRT_EEPROM_POS                       ; "
        BRA UPDATE_PARAM_RET                        ;No, Leave routine
FORCE_END_WRITE_CYCLE
        BCF GENERAL1_STAT,write_cycle_req           ;Clear the write cycle flag     
        CLRF WRT_EEPROM_POS                         ;Clear write position 
UPDATE_PARAM_RET
        RETURN                                      ;Leave routine

;******************************************************************************************************
;HEX_2_ASCII
;This code converts an hexadecimal byte to the equivalent two ASCII characters.

HEX_2_ASCII                                         ;The hex value is expected to be in TEMP1_HI when the routine is called
        MOVLW .58                                   ;Load ASCII equivalent of 10 into temporary var.
        MOVWF TEMP3_LO            
LO_NIBBLE
        MOVF TEMP1_HI,W                             ;Move hex value into Wreg
        ANDLW h'0F'                                 ;isolate lower nibble
        ADDLW .48                                   ;add ASCII ofset
        CPFSGT TEMP3_LO                             ;verify if ASCII char is higher than "9"
        ADDLW .7                                    ;yes, add additional ASCII offset
        MOVWF TEMP1_LO                              ;No, low ASCII characters is returned in TEMP1_LO
HI_NIBBLE
        SWAPF TEMP1_HI,W                            ;load nibble-swapped hex value into Wreg
        ANDLW h'0F'                                 ;isolate lower nibble
        ADDLW .48                                   ;add ASCII ofset
        CPFSGT TEMP3_LO                             ;verify if ASCII char is higher than "9"
        ADDLW .7                                    ;yes, add additional ASCII offset
        MOVWF TEMP1_HI                              ;No, high ASCII characters is returned in TEMP1_HI   
        RETURN                                      ;Leave routine. Result are in TEMP1_HI and TEMP1_LO

;******************************************************************************************************
;ASCII_2_HEX  
;This code converts two ASCII characters representing a hexadecimal byte to its numerical equivalent.

ASCII_2_HEX                                         ; The ASCII characters are expected to be in TEMP1_HI and TEMP1_LO when the routine is called
        MOVLW .10                                    ;load the offset required to test for gap between ASCII code for 9 and A
        MOVWF TEMP3_LO            
HIGH_CHAR
        MOVLW .48                                   ;load ASCII offset equiv. into Wreg
        SUBWF TEMP1_HI,W                            ;substract 48 from ASCII character
        CPFSGT TEMP3_LO                             ;is ASCII character higher than "9" (like A,B,C,D,E,F)
        ADDLW .249                                  ;yes, substract an additional ASCII offset of 7 (adding 249 does the same)
        MOVWF TEMP1_HI                              ;no, load result into TEMP1_HI
        SWAPF TEMP1_HI,F                            ;swap nibbles to move to higher hex position   
LO_CHAR
        MOVLW .48                                   ;load ASCII offset equiv. into Wreg
        SUBWF TEMP1_LO,W                            ;substract 48 from ASCII character
        CPFSGT TEMP3_LO                             ;is ASCII character higher than "9" (like A,B,C,D,E,F)
        ADDLW .249                                  ;yes, substract an additional ASCII offset of 7 (adding 249 does the same)
        ADDWF TEMP1_HI,F                            ;add the result to the higher hex result 
        RETURN                                      ;Leave routine. Result is in TEMP1_HI

;******************************************************************************************************
;READ_EEPROM_DATA
;This sub-routine reads one byte of Data EEPROM

READ_EEPROM_DATA
        MOVWF EEADR                                 ;Address to read is in Wreg  
        BCF EECON1, CFGS                            ;Point to DATA memory
        BCF EECON1,EEPGD                            ;Point to DATA memory
        BSF EECON1,RD                               ;EEPROM Read
        MOVF EEDATA,W                               ;value read is moved to Wreg 
        RETURN          

;******************************************************************************************************
;WRITE_EEPROM_DATA
;This sub-routine writes one byte of Data EEPROM

WRITE_EEPROM_DATA
        MOVWF EEADR                                 ;Data Memory Address to write is in Wreg
        MOVFF TEMP1_LO,EEDATA                       ;Data memory value is in TEMP1_LO
        BCF EECON1, CFGS                            ;Point to DATA memory
        BCF EECON1, EEPGD                           ;Point to DATA memory
        BCF INTCON, GIE                             ;Disable Interrupts
        BSF EECON1, WREN                            ;Enable writes
        MOVLW h'55'                     
        MOVWF EECON2                                ;Write 55h
        MOVLW h'AA'
        MOVWF EECON2                                ;Write AAh
        BSF EECON1, WR                              ;Set WR bit to begin write
        BCF EECON1, WREN                            ;Enable writes
        BSF INTCON, GIE                             ;Enable Interrupts
        RETURN

;******************************************************************************************************
;END_SAMPLING_CYCLE
;This sub-routine ends a frequency sampling cycle.

END_SAMPLING_CYCLE
        CLRF FILT_AVG_CTR_H
        CLRF FILT_AVG_CTR_L
        CLRF FILT_AVG_VAL_H
        CLRF FILT_AVG_VAL_L    
        BTFSS FREQ_MEAS_STAT2,holdover_flag         ;Is FLL in holdover?        
        BCF FREQ_MEAS_STAT2,stabil_done
        RETURN

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

;This is the Command menu definition and it is placed in Program Memory

        ORG 0x0DC0

COMMAND_MENU_LOCN                         
        DB "\r\n USER COMMANDS\r\n\x00"    
        DB "?     Send this menu\r\n\x00"
        DB "A     Clear Alarms\r\n\x00"       
        DB "C     Clear sample cntr\r\n\x00"       
        DB "D     Disable FLL\r\n\x00"       
        DB "E     Enable FLL\r\n\x00"       
        DB "Fxx   Set Fine-Coarse thres\r\n\x00"     
        DB "Hxx   Set Holdover thres\r\n\x00" 
        DB "Lxx   Set Lock Limit thres\r\n\x00"     
        DB "Mxx   Set FLL Avrging mode\r\n\x00"
        DB "Nxx   Set Freq Chg Negate thres\r\n\x00" 
        DB "Oxx   Set 10MHz Output mode\r\n\x00"   
        DB "P     Send Param Info\r\n\x00"       
        DB "R     Reset CPU\r\n\x00"       
        DB "Syyzz Set Avrging Sample Size\r\n\x00"     
        DB "Tyyzz Tune DAC\r\n\x00"   
        DB "V     Send Ver. Info\r\n\x00"       
        DB "Wxx   Set Holdover Wait\r\n\x00" 
        DB "Xxx   Set VCXO slope sign\r\n\n\x00"
        DB "$"                                      ;$ signals end of menu   

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

;Startup promt string definition. 80 characters reserved in Program Memory
    ;Make sure to change constant prompt_addr_high/low definitions to match ORG address
        ORG 0x0FB0    
STARTUP_STRING_LOCN
        DW "\r\n GPS_Std - v4 - 03/2009 - by VE2ZAZ\r\n\n -> Type '?' for Menu <-\r\n\00"    

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

;Default FLL parameter values added into Data EEPROM locations, starting at address 0x00
;Make sure the number_param_to_stor constant is updated when changing the number of parameters saved.
        ORG 0xF00000
PARAMETERS_LOCN
;          NULL ,     S     ,  F   ,  L   ,  W   ,  N   , DAC VALUE ,  O   ,  H   ,  X   ,  M  
        DE 0x00 , 0x00,0x08 , 0x08 , 0x04 , 0xC8 , 0x03 , 0x7F,0x03 , 0x01 , 0x08 , 0x01 , 0x01, 0xFF, 0xFF, 0xFF

;Then we fill the remaining data EEPROM values (except the last two) with FF. This makes the PIC burner happy.
        DE 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF 
        DE 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
        DE 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
        DE 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
        DE 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
        DE 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
        DE 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
        DE 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
        DE 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
        DE 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
        DE 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
        DE 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
        DE 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
        DE 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
        DE 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF

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

;The last Data EEPROM value stores the SW VERSION to allow to read the software version from PICMicro burner,  
;whitout running the software. It is not saved or retrieved by software. It is located in the last Data EEPROM Byte.
;             BLANK  ,   SW VERSION
        DE    0xFF   ,      .4

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

;End of program
        END