/*********************************************************************
 *
 *                Microchip USB C18 Firmware Version 1.0
 *
 *********************************************************************
 * FileName:        user.c
 * Dependencies:    See INCLUDES section below
 * Processor:       PIC18
 * Compiler:        C18 2.30.01+
 * Company:         Microchip Technology, Inc.
 *
 * Software License Agreement
 *
 * The software supplied herewith by Microchip Technology Incorporated
 * (the “Company”) for its PICmicro® Microcontroller is intended and
 * supplied to you, the Company’s customer, for use solely and
 * exclusively on Microchip PICmicro Microcontroller products. The
 * software is owned by the Company and/or its supplier, and is
 * protected under applicable copyright laws. All rights are reserved.
 * Any use in violation of the foregoing restrictions may subject the
 * user to criminal sanctions under applicable laws, as well as to
 * civil liability for the breach of the terms and conditions of this
 * license.
 *
 * THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
 * WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
 * TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
 * PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. THE COMPANY SHALL NOT,
 * IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
 * CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
 *
 * Author               Date        Comment
 *~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
 * Rawin Rojvanit       11/19/04    Original.
 * Brian Schmalz		07/09/06	FW C v 1.0 now sends back PORT A
 *									inputs on every USB packet reception
 * Tom Rowley, W2TER	12/05/06	Replaced User code with input from C#
 *									specifying a target DDS device and frequency
 *									control word which is then serially
 *									bit-banged SPI-like to the device
 *									Will run on either 20Mhz breadboard or
 *									Bit Wacker 
 *									- first device is DDS-60
 *									- added DDS-30
 *						2/17/07		Re orged code layout to accommodate more 
 *									DDS devices in the future
 *									- Added support for AD9854
 *									- added support for AD995x
 * Cash Olsen, KD5SSJ	2/16/07		Added an initialization routine for
 *									AD9850/AD9851 DDS in serial mode. This
 *									corrects a failure to initialize the DDS
 *									properly.
 *									Modified SPIleast() to use wait_10_inst()
 *									to substantially speed up clock and strobe
 *									routines. I did not modify the AD9854
 *									routines because I don't have a system
 *									to test it on but the same modifications
 *									made should work on the other AD9854.
 *	Tom Rowley, w2ter	5/17/07		Re organized code to provide for more 
 *									flexibility in initialization and a 
 *									framework for broader device support
 *  Terry Fox, WB4JFI  5/24/07		fixed 995x ioupdate pin (per Tom, w2ter)
 *  Terry Fox, WB4JFI  5/24/07		added first attempt to set attenuator
 *	Terry Fox, WB4JFI  5/31/07		Added BoardId and test commands
 *	Terry Fox, WB4JFI  6/2/07		Added EEPROM read & write commands code	
 *	Terry Fox, WB4JFI  6/3/07		Added A/D conversion and timer code
 *	Terry Fox, WB4JFI  6/9/07		added LED flash, USB return flag
 *	Terry Fox, WB4JFI  6/9/07		Worked on Tx in/out pin code
 *	Terry Fox, WB4JIF  6/15/07		Started on stand-alone initialization
 *	Terry Fox, WB4JFI  7/12/07		Tx In/Out pins appear to be working
 *	Terry Fox, WB4JFI  7/17/07		Modified & tested new PIC pin equates
 *  Terry Fox, WB4JFI  8/08/07		Added PIC calculation of FTW
 *  Terry Fox, WB4JFI  8/25/07		Power-up DDS initialization code added
 *	Terry Fox, WB4JFI  9/04/07		Added bandpass filter setting on freq update
 *
 ********************************************************************/

/** I N C L U D E S **********************************************************/
#include <p18cxxx.h>
#include <usart.h>
#include "system\typedefs.h"
#include "stdio.h"
#include "adc.h"									// TFOX added 6/3/07
#include "timers.h"									// TFOX added 6/3/07
#include "portb.h"									// TFOX added 6/7/07
#include "delays.h"
#include "system\usb\usb.h"

#include "io_cfg.h"             						// I/O pin mapping
#include "user\user.h"
#include "user\eeprom.h"							// TFOX added 6/10/07
#include "user\tercmds.h"							// TFOX added 6/10/07

/** D E C L A R A T I O N S ****************************************************************/

#define	TFIOPINS						// uncomment for newer pin assignments

										// the following are used as power-up defaults ONLY
										// if EEPROM is blank,and no USB commands update them
#define	DEFAULT_BD		eUBWDDS				// set defuault Board ID to bit whacker and DDS
#define	DEFAULT_DDS		eAD9851				// set default DDS CHIP
#define	DEFAULT_PLL		0x06				// set default DDS cloock PLL multiplier
#define	DEFAULT_VFOM 	0x01				// set default VFO multiplier
#define DEFAULT_DDS32	TRUE				// set the default DDS 32-bit mode
#define DEFAULT_FREQ	7055000				// set a default operating frequency
#define	DEFAULT_OSC		30000000			// set the default master oscillator frequency
#define	DEFAULT_BPF		eFLTRDHW			// set default bandpass filter to WB6DHW board
#define DEFAULT_ALLPASS	0x03;				// default band-pass all-pass filter
#define	DEFAULT_RXOFS	0					// set the default Rx offset frequency
#define	DEFAULT_TXOFS	0					// set the default Tx offset frequency
#define	DEFAULT_VFOSRC	0x11				// set default VFO source to Rx & Tx to VFO A
#define	DEFAULT_EPWR	FALSE				// set the default EEPROM WRITE mode on power-up
										// Some common board default values:
										// DDS-30 is eAD9850, PLL=1, VFOM=1,
											// DDS32=TRUE, OSC=100,000,000 or 120,000,000
											// or 125,000,000 or even 66,000,000
										// DDS-60 is eAd9851, PLL=8, VFOM=4(?), 
											// DDS32=TRUE, OSC=30,000,000
										// Brainerd is eAD995x, PLL=4, VFOM=2,
											// DDS32=TRUE, OSC=125,000,000
										// FCC-2 & 75MHz is eAD9834, PLL=1, VFOM=1,
											// DDS32=FALSE, OSC=75,000,000
//#define	FREQ_DEBUG							// enable frequency readback for debugging

/** V A R I A B L E S ************************************************************************/

/**************	LOWEST FAST-ACCESS VARIABLES	**********************/
//		TFNOTE:  CHANGE THESE TO VOLITILE IF USED IN ISR

#pragma udata access fast_vars			// put fast-access variables for quick ISR

near unsigned char	adCmd;				// A/D command storage
near unsigned char	adDestination;		// where should A/D sample go.1=intrnl 2=USB
near unsigned char	adSampleSeq;		// A/D sample sequence number
near unsigned char	adChannel;			// active A/D channel (PIC input)
near unsigned char	BD_state;			// various board state storage(matches eBDSTATE)
near unsigned char	TxEnables;			// Transmit hardware enables (matches eTXENABL)
near unsigned char	TxDelay;			// transmit on/off delay value
near unsigned char	TxPortCur;			// storage for current Transmitter port
near unsigned char	TxPortLast;			// storage for previous Tx port value
near unsigned char	TxWork;				// misc transmit work storage
near unsigned int	TxTimeout;			// Transmit timeout delay value
near unsigned int	adDelayCnt;			// A/D delay between samples
near unsigned int	LED_tick_counter;	// LED counter between on/off commands
near unsigned int	adSampleFreq;		// A/D sample rate storage in 1msec
near int			ad_cur_sample;		// current (last) A/D conversion data
near BOOL 			Ints_on;			// interrupts on flag
near BOOL 			adRunning;			// A/D running a conversion right now
near BOOL			Transmitting;		// Flag to show are transmitting now

/************* NORMAL VARIABLES	*************************************/
#pragma udata

char input_buffer[32];				// ***** CAREFUL:  TFOX droped this from 64 bytes
char output_buffer[32];				// ***** CAREFUL:  TFOX DROPPED THIS FROM 64 BYTES
char out_ptr;
char Buffer;

//  TFOX added
unsigned long	max_freq;			// Maximum operating frequency
unsigned long	freq_work;			// intermediate work storage
unsigned long	osc_freq;			// oscillator frequency (actual oscillator before PLL)
unsigned long	dds_clock;			// DDS clock input results frequency (after PLL)
unsigned long	freq_1Hz;			// 1 Hertz value (based on osc, DDS PLL, and DDS type)
unsigned long	dds_out;			// DDS output frequency (display * freq_mult)
unsigned long	dds_display;		// DDS display frequency (wanted freq, before freq mult)
unsigned long	dds_ftw;			// value to send to the DDS for frequency output (FTW)
unsigned long	RxOffsetFreq;		// receive offset frequency value
unsigned long	TxOffsetFreq;		// Transmit offset frequency value
unsigned long	VFO_A;				// VFO A frequency (32-bit binary of frequency)
unsigned long	VFO_B;				// VFO B frequency (32-bit binary of frequency)
unsigned long	VFO_C;				// VFO C frequency (32-bit binary of frequency) - CALIBRATE
unsigned long	VFO_D;				// VFO D frequency (32-bit binary of frequency) - DDS display
unsigned long	old_mosc;			// temporary storage for old master osc data
unsigned long	old_freq;			// temporary storage for old operating freq
unsigned char	old_fmult;			// temporary storage for old VFO multiplier
unsigned char	cal_VFOM;			// flag for using VFO multiplier
unsigned char	dds_pll;			// DDS internal PLL clock multiplier
unsigned char	freq_mult;			// DDS external frequency multiplier (VFO Multiplier)
unsigned char	Atten;				// attenuator level storage
unsigned char	DDSdevice;			// DDS device identifier 	(matches eDDSID EEPROM)
unsigned char	BoardID;			// Board Identifier		 	(matches eBOARDID EEPROM)
unsigned char	eepadr;				// eeprom address storage
unsigned char	eepRdata;			// eeprom read data storage
unsigned char	eepWdata;			// eeprom write data storage
unsigned char	adAvailable;		// A/D conversion data available flag
unsigned char	TxHwPin;			// Transmit hardware pin assign (matches eTXHWPIN EEPROM)
unsigned char	TxInPin;			// Transmit in pin value
unsigned char	TxOutPin;			// Transmit output pin value
unsigned char	TxOutPort;			// Transmit output pin port value
unsigned char	TxInPol;			// transmit in pin polarization
unsigned char	TxOutPol;			// transmit out pin polarization
unsigned char	FilterType;			// Low-pass or Band-pass filter type  (matches eFLTRTYPE)
unsigned char	FilterBand;			// current LP or BP filter operating band (matches eINIBANDF)
unsigned char	Ofs_mode;			// Receive (bits 0-3) and Transmit (bits 4-7) offset mode
unsigned char	VFO_sources;		// Transmit and receive frequency sources
//unsigned char	FilterPort;			// LP or BP filter PIC port
//unsigned char	FilterBits;			// LP or BP filter control bits (lowest assumed lsb)
BOOL			LED_heartbeat;		// LED heartbeat on/off status
BOOL			EepromWrEn;			// EEPROM Write enable flag
BOOL			EepromRdBad;		// EEPROM read possibly not valid (reads back 0xFF)
BOOL			DDS32;				// DDS 32-bit if set, otherwise DDS is 28-bit
BOOL			Calmode;			// Calibrate master osc flag
//unsigned long	a, b, c, d;			// 32-bit multiply variables storage
//unsigned long	HI, LO, x, y;
unsigned long	un1, un0;
unsigned long	u1, u0;				// 64-bit divide routine dividend storage
unsigned long	un32, un21, un10;	// 64-bit divide routine intermediate work
unsigned long	v, vn1, vn0;		// 64-bit divide routine divisor storage
unsigned long	q2, q1, q0, q;		// 64-bit divide routine quotient storage
//unsigned long	q1g, q0g, rhat1g, rhat0g;	// TEMPORARY
unsigned long	r, rhat;			// 64-bit divide routine remainder storage
// unsigned long	un32a, un32b, un32c;
// int s;
unsigned int	BPF_start;			// start frequency of current bandpass filter
unsigned int	BPF_stop;			// stop frequency of current bandpass filter
char dds_cmd[6];					// DDS command buffer storage

// end of TFOX adds

//	initializations for AD 9854 credit to AA0ZZ
#define AD9854_fwr	0x02
#define AD9854_cwr	0x07
#define	AD9854_cb0	0x10				// Most signicant CR byte (0x1D) (COMP PD)
#define	AD9854_cb1	0x20 				// Second CR byte (0x1E) (Bypass PLL)
#define	AD9854_cb2	0x00 				// Third CR byte (0x1F) (No SRC QDAC + External UPDATE)
#define	AD9854_cb3	0x40 				// Fourth CR byte (0x20) (Bypass INV SINC)

//char freq_write_cmd = 0x02;
//char CR_write_cmd = 0x07;
//char CR_byte_0 = 0x10;				// Most signicant CR byte (0x1D) (COMP PD)
//char CR_byte_1 = 0x20; 				// Second CR byte (0x1E) (Bypass PLL)
//char CR_byte_2 = 0x00; 				// Third CR byte (0x1F) (No SRC QDAC + External UPDATE)
//char CR_byte_3 = 0x40; 				// Fourth CR byte (0x20) (Bypass INV SINC)
//BOOL first_time = TRUE;				// test for initialization stage
//BOOL first_AD995x = TRUE;			// test for initialization of AD995x

#pragma udata my_data0=0x100			// Additional 250 byte DATA storage or so
										// can hold 33 int, 32 long, and 56 bytes
static unsigned int BPfilter[33];			// room for 16 filters, plus a filter count (int[0])
static unsigned long freq_mem[32];			// room for 32 memories:
												// 12 band-specific memories (copied from EEPROM)
												// 8 misc memories (copied from EEPROM)
												// balance is not really needed - scratch?
static byte test[56];						// test to see how much will fit in this bank

//#pragma udata my_data1=0x200
//static byte downlink[20];
// OK at 20 bytes, fails at 21 byes

//#pragma udata my_data2=0x300
//static byte downlink[10];
// fails, stack is set to bank 3

//#pragma udata my_data3 = 0x400			// memory bank 400 is dual-ported with USB
//static byte test3[10];

//#pragma udata my_data1=0x700				// USB In/Out buffer storage
// 0x600 works for 250 bytes					// dual-ported with USB
// 0x700 works for 250 bytes					// dual-ported with USB
//static byte downlink[250];
//static unsigned char Uinput_buffer[10];	// ***** CAREFUL:  TFOX droped this from 64 bytes
//static unsigned char Uoutput_buffer[10];	// ***** CAREFUL:  TFOX DROPPED THIS FROM 64 BYTES
//char out_ptr;
//char Buffer;

/** P R I V A T E  P R O T O T Y P E S ***************************************/
void SPIleast(void);				// Serial LSB out
void DDSx0(void);					// DDS30 or DDS60
void SPImost(void);					// Serial MSB out
void AD9854Int(void);				// Startup IQPro
void wait_10_inst(void);			// timimg routine
void AD9850Int(void);				// AD9850/51 Init
void send_9854Freq(void); 			// IQPro update
void AD995xInt(void);				// Init for AD995x
void send_9951Freq(void);			// AD9951 freq update
void AD9958Int(void);				// Init for AD9958
void send_9958Freq(void);			// AD9958 freq update
void SPImost2(void);				// Modified SPIout for smaller DDS (TF 7/18/07)
void AD9833INI(void);				// AD9833 initialization (TF 7/18/07)
void send_9833Freq(void);			// AD9833 frequency update (TF 7/18/07)
void AD9832INI(void);				// AD9832/5 initialization (TF 7/18/07)
void send_9832Freq(void);			// AD9832/5 frequency update (TF 7/18/07)
void set_atten(void);				// HRF-AT4611 attenuator set
void set_freq(void);				// sets the requested freq via PIC calculations
void Bdtest(void);					// test to set LED and return data
void BoardId(void);					// returns board ID information
void rdwreeprom(void);				// USB read or write data in PIC EEPROM
void eepromWR(void);				// write a byte to the PIC EEPROM
void eepromRD(void);				// rea a byte from the PIC EEPROM
void adInit(void);					// initialize the PIC A/D
void adCommand(void);				// command the PIC A/D (on, off, channel,sample rate)
void BoardInit(void);				// reinitialize the board command
void SendToUSB(void);				// send data to host via USB connection
void Tx_init(void);					// transmit initialization routine
void txinpinon(void);				// internal tx in pin on routine
void txinpinoff(void);				// internal tx in pin off routine
void Tx_on_off(void);				// Transmit on or off command
void Transmit_ON(void);				// Turn the transmitter ON
void Transmit_OFF(void);			// Turn the transmitter OFF
void filter_set(void);				// set the exteranl LP or BP filter
void u64divide(void);				// unsigned 64-bit divide routine
void u32mult(void);					// unsigned 32-bit multiply routine
int nlz(unsigned long);				// unsigned 64-bit divide - V normalize routine
void OscSet(void);					// set the master oscillator frequency from Host
void PllMult(void);					// set the DDS PLL and out multiplier from Host
void freq_update(void);				// update the various frequencies
void ftw_calc(void);				// calculates and sends DDS FTW
void DDS_parse(void);				// parse a DDS FREQ command, based on DDS chip used
void DDS_init(void);				// Initializes the correct DDS chip
void Set_DHWbpf(void);				// Sets the WB6DHW BP filter based on frequency
void Osc_cal(void);					// calibrate the master oscillator frequency command
void show_param(void);				// Read various parameters to host via USB
void set_param(void);				// set various parameters, mostly frequency related
void get_data(void);				// builds an unsigned long in freq_work from rcvd USB data
void VFO_setup(void);					// sets up the various VFO modes, and copies/swaps
unsigned char eepRD4(unsigned char eadr, unsigned long *pvar); // read four bytes from EEPROM
unsigned char eepRD1(unsigned char eadr, unsigned char *pvar); // read one byte from EEPROM
unsigned char eepWR4(unsigned char eadr, unsigned long *pvar); // writes four bytes to EEPROM

void send_data(unsigned char mode, unsigned char cmd, unsigned char scmd);
									 // send a dataframe to the host via USB

///////////////////////////////////////////////////////////////////////////////////////////////
//////		TERRY FOX MODIFIED PIC INPUT & OUTPUT PIN DEFINITIONS					///////////
///////////////////////////////////////////////////////////////////////////////////////////////
#ifdef	TFIOPINS							// NEW PIN ASSIGNMENTS -> TESTED 7/17/07
											// Serial data bits to/from second UI PIC
#define	PIC2_RX		LATCbits.LATC7				// Serial port Tx data to/from UI PIC
#define	PIC2_TX		LATCbits.LATC6				// Serial port Rx data to/from UI PIC
#define	PAD20DB		LATCbits.LATC0
											// Honeywell attenuator control pins
#define	ATTEN_oe	LATAbits.LATA2				// Honeywell HRF-AT4611 Atten /OE (/CS)
#define	ATTEN_data	LATBbits.LATB7				// Attenuator data pin (shared with DDS)
#define ATTEN_clk	LATAbits.LATA4				// Attenuator clock pin
											//	Control pins for DS & serial devices
#define	DDS_data	LATBbits.LATB7				// Serial data pin (DDS & atten)
#define DDS_clk		LATBbits.LATB6				// Serial clock pin (DDS only)
#define	DDS_ioud	LATBbits.LATB5				// DDS I/O update (or chip select)
#define DDS_reset	LATAbits.LATA5				// DDS reset pin
										// these are temporary assignments until tested
#define	AD99_ioud	LATBbits.LATB5				// temporary assignment to test new pinouts
#define	IQ_clk		LATBbits.LATB6				// temporary assignment to test new pinouts
#define	IQ_data		LATBbits.LATB7				// temporary assignment to test new pinouts
#define	IQ_mreset	LATAbits.LATA5				// temporary assignment to test new pinouts
#define	IQ_ioreset	LATAbits.LATA5				// temporary assignment to test new pinouts
#define	IQ_ioud		LATBbits.LATB5				// temporary assignment to test new pinouts

											//	Transmit in/out pins
#define	TX_INP		0x10						// transmit in pin - Default is B4
#define	TX_OUTP		0x08						// transmit out pin - Default is B3
#define	TX_OUT		LATBbits.LATB3				// transmit out pin
#define	TX_IN		LATBbits.LATB4				// transmit in pin
											// Bandpass filter conrol pins
#define	FLTR_S2		LATBbits.LATB2				// filter select bit 2 (msb)
#define	FLTR_S1		LATBbits.LATB1				// filter select bit 1
#define	FLTR_S0		LATBbits.LATB0				// filter select bit 0 (lsb)
#define	FLTR_MSK	0x07						// Mask for BP filter bits

#define	ADREFIN		LATAbits.LATA3				// A/D +reference in from AD8310 VCC (3.3V)
#define	AD8310		LATAbits.LATA0				// A/D input from AD8310 Log amp output
#endif	// end of TFOX pin test configuration

//////////////////////////////////////////////////////////////////////////////////////////////
/////		ORIGINAL PIC INPUT & OUTPUT PIN DEFINITIONS								//////////
//////////////////////////////////////////////////////////////////////////////////////////////
#ifndef TFIOPINS						//// ORIGINAL **WORKING** DEFINITINS  ////
//	Control Pins for AD9854 - IQPro
#define IQ_clk		LATAbits.LATA4				// Serial clk
#define	IQ_ioud		LATAbits.LATA3				// I/O update
#define	IQ_data		LATAbits.LATA2				// Serial data
#define	IQ_ioreset	LATAbits.LATA1				// I/O reset
#define	IQ_mreset	LATAbits.LATA0				// Master Reset

//	Control pins for AD9850/51 = DDS 30/60
#define DDS_clk		LATBbits.LATB6				// Serial clk
#define	DDS_ioud	LATBbits.LATB5				// I/O update
#define	DDS_data	LATBbits.LATB7				// Serial data
 
//	TFOX_CODE Control pin for AD9951/52/54
#define AD99_ioud	LATAbits.LATA3				// I/O reset

#define	TPin		LATAbits.LATA5				// Test Pin

//	TFOX ADDED defines for various WB6DHW boards
											//  Control pins for Honeywell Attenuator
#define	ATTEN_data	LATCbits.LATC6				//  HRF-AT4611 serial data pin
#define	ATTEN_clk	LATCbits.LATC0				//  HRF-AT4611 serial clock pin
#define	ATTEN_oe	LATCbits.LATC7				//  HRF-AT4611 OE (Latch actuallly)
											//	Transmit in/out pins
#define	TX_INP		0x10						// transmit in pin - Default is B4
#define	TX_OUTP		0x08						// transmit out pin - Default is B3
#define	TX_OUT		LATBbits.LATB3				// transmit out pin
#define	TX_IN		LATBbits.LATB4				// transmit in pin
											// filter select pins
#define	FLTR_S3		LATBbits.LATB3				// filter select bit 3 (msb)
#define	FLTR_S2		LATBbits.LATB2				// filter select bit 2
#define	FLTR_S1		LATBbits.LATB1				// filter select bit 0
#define	FLTR_S0		LATBbits.LATB0				//  filter select bit 0 (lsb)
#define	FLTR_MSK	0x07						// Mask for BP filter bits
#endif	// end of NOT TFOX test pin assignment
///////////////////////////////////////////////////////////////////////////////////////////////

										// NOTE:  0xfe8A, 16bit, pres.32 = 1msec interrupts
										//		  0xf128, 16bit, pres.32 = 10msec ints.
#define	TMR0_10MS	0xf128					// 10msec timer 0 value (0xF128)

#define	ADINTERNAL	0x01					// send A/D results to internal process
#define	ADTOUSB		0x02					// snd A/D results to USB port & host
#define	LEDSLOW		0x0064					// slow LED value (2 seconds)
#define	LEDFST		0x0032					// fast LED value (1 second)
#define	LEDVFST		0x0016					// even faster LED value (1/2 second)

#define USBresp		0x80

#define	F500_1HZ	0x089705F4				// 1Hz number with a 500MHz DDS clock
#define	F20_1HZ		0xD6BF94D6				// 1HZ number with a 20MHz DDS clock
#define	MHZ125		0x07735940				// 125MHz in binary
#define	MHZ120		0x07270E00				// 120MHz in binary
#define	MHZ75		0x047868C0				// 75MHz in binary
#define	MHZ10		10000000				// 10MHz calibrate frequency
#define MAXMHz32	4294967296				// 2^32 is maximum frequency in 32-bits
#define	MAXMHz28	268435456				// 2^28 is maximum frequency in 28-bits	
#define	MAXMHz24	16777216				// 2^24 is maximum freq in 24-bits
#define	MAXMHZ31	2147483648				// 2^31 is maximum  allowed osc for now
#define	M32SHFTH	0x00FFFFFF				// 2^32 shifted high word (for osc calculation)
#define	M32SHFTL	0xFF000000				// 2^32 shifted low word (for osc calculation)
#define	M28SHFTH	0x000FFFFF				// 2^28 shifted high word (for osc calculation)
#define	M28SHFTL	0xFF000000				// 2^28 shifted low word (for osc calculation)
//	end of TFOX adds

//////////////////////////////////////////////////////////////////////////////////////////////
//	bpf_DHW_array[x] is the band-pass filter array of start and stop frequencies for each	//
//						filter.  The first entry is the total number of filters described	//
//						Each filter entry is a 16-bit piece of a 32-bit binary number that	//
//						represents the frequency to change to the next filter.				//
//						The 32-bit number is shifted down 12-bits, such that original		//
//						frequency bits 12-27 are now bits 0-15.  This gives a wider range	//
//						of filter frequency resolution while staying in only 16 bits		//
//		Example: 7,000,000MHz = 00-6A-CF-C0 (32-bit binary) = 06-AC = 6,995,968MHz (rounded)//
//////////////////////////////////////////////////////////////////////////////////////////////
#pragma romdata const_table
const rom unsigned int bpf_DHW_array[18]={0x0008,		// first byte is number of FILTERS
										0x0186, 0x0262, // filter 0: 1,597,400 - 2,498,560
										0x0262, 0x03E6,	// filter 1: 2,498,560 - 4,087,808
										0x03E6, 0x06AC, // filter 2: 4,087,808 - 6,995,968
										0x0000, 0xFFFF, // filter 3: BYPASS, feedthrough
										0xFFFF,	0xFFFF, // filter 4: Open, no pass
										0x06AC, 0x0AF7,	// filter 5:  6,995,968 - 11,497,743
										0x0AF7, 0x112A,	// filter 6: 11,497,743 - 17,997,824
										0x112A, 0x1C53, // filter 7: 17,997,824 - 29,700,096
										0xFFFF};		// array end, makes array even # bytes
									// 8 filters (plus qty) * 4 bytes is 36 bytes total
									//	0x0000, 0x0000	open or terminated, no feedthrough
									//	0x0000, 0x06AC	Low-pass filter: 0Hz - 6,995,968MHz
									//	0x0186, 0x0262	Bandpass filter: 1,597,400-2,498,560
									//	0x1C53, 0xFFFF	High-pass filter: 29,700,096 - TOP
									//	0x0000, 0xFFFF	All-pass filter (bypass), no loss
									//	0xFFFF, 0xFFFF	open or terminated, no feedthrough

const rom unsigned long hambands[24] = {1800, 2000,			// 160 Meters (0)
										3500, 4000,			//  80 meters (1)
										5331, 5403,			//  60 meters (2)
										7000, 7300,			//  40 meters (3)
										10100, 10150,		//  30 meters (4)
										14000, 14350,		//  20 meters (5)
										18068, 18168,		//  17 meters (6)
										21000, 21450,		//  15 meters (7)
										24890, 24990,		//  12 meters (8)
										28000, 29700,		//  10 meters (9)
										50000, 54000,		//   6 meters(10)
										00000, 00000};		// open for future
									// 12 bands * 8 bytes is 96 bytes total



/////////////////////////////////////////////////////////////////////////////////////////
////////////////	C O D E   S E G M E N T		/////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////////////////

#pragma code

/////////////////////////////////////////////////////////////////////////////////////////
//	Low-priority Interrupt Service Routine
//	1.  Timer0 interrupts every 10msec, used for:
//			A.  A/D converter sample timing
//			B.  LED 2 (red) heartbeat timing
//			C.  Transmit timeout (not implemented yet)
//	2.  A/D converter interrupts when done
//	3.  Change on RB pin for Tx In (one of RB4, RB5, RB6, or RB7)
/////////////////////////////////////////////////////////////////////////////////////////
#pragma interruptlow low_ISR
void low_ISR(void)
	{
	if(INTCONbits.TMR0IF)					// Do this on each Timer 0 interrupt
		{											// start with timer 0 housekeeping
		INTCONbits.TMR0IF = 0;						// clear timer 0 interrupt flag
		WriteTimer0(TMR0_10MS);						// restart timer 0 with same value
											// end of timer setup, now for actual work
		if(adCmd != 0)							// is the A/D converter supposed to run again?
			{										// yes, it should run again
			if(adDelayCnt-- == 0)					// decrement delay counter to next A/D sample
				{									// if zero, time to trigger another conversion
				adRunning = TRUE;					// show we are now running the A/D converter
				adDelayCnt = adSampleFreq; 			// reset delay amount for next sample
				ConvertADC();						//	kick-off another A/D conversion
				}	// end of delay count test
			}	// end of A/D command test
		// mLED_1_Toggle();							// toggle LED 1 (ylw) use this @ interrupt rate
		if(LED_heartbeat)						// if flashing LED is enabled
			{
			if(LED_tick_counter-- == 0)				// test to see if LED counter is timed out
				{									// yes, flash LED and do it again
				LED_tick_counter = LEDFST;			// reset counter value
				mLED_2_Toggle();					// toggle LED 2 (red)
				}	// end of LED tick counter
			}	// end of LED heartbeat
		// add Tx timers here
		}									// end of timer 0 interrupt servicing
	if(PIR1bits.ADIF)						// do this on A/D conversion completed interrupt
		{
		PIR1bits.ADIF = 0;							// clear A/D converter interrupt flag
		mLED_2_Toggle();							// test
		ad_cur_sample = ReadADC();					// read the A/D converter data
		switch(adCmd)								// was the command for multiple conversions?
			{
			case 0:									// should never get here.
				adRunning = FALSE;
				break;
			case 1:									// only wanted one conversion, now done
				adRunning = FALSE;					// turn off A/D running flag
				adDelayCnt = 0;						// set sample delay to zero
				adCmd = 0;							// show all done in A/D command
				break;
			case 0xFF:								// run continuously, do not reduce adCmd count
				break;
			default:
			adCmd--;								// reduce number of conversions left
			}	// end of adCmd switch
												// conversion data available, send it as appropriate
		if(adDestination & ADINTERNAL)					// see if should it go to internal processing
			{
			adAvailable++;							// increment internal data available counter
			}
		if(adDestination & ADTOUSB)					// test to see if it should go to the USB
			{										// yes it should, send to USB code
			output_buffer[0] = adCmd;					// copy subcommand to output buffer
			output_buffer[1] = adSampleSeq;				// copy sequence number to output buffer
			output_buffer[2] = (unsigned char) 
							ad_cur_sample & 0xFF;		// move low-byte of conv. data
			output_buffer[3] = (unsigned char) 
							((ad_cur_sample & 0xFF00) >> 8);  // move high-byte of conv data
			output_buffer[4] = 0x7E;					// show this is an A/D command response
			SendToUSB();								// send the data to USB (if enabled)
			adSampleSeq++;								// increment sample sequenc number
			}	// end of USB dest test.
		}										// end of A/D conversion completion interrupt

	if(INTCONbits.RBIF)							// test to see if RB pins have changed
		{												// (transmit in pin)
		INTCONbits.RBIF = 0;							// Clear PortB pin-change interrupt flag
		// mLED_1_Toggle();								// Toggle LED for now
		TxPortLast = TxPortCur;							// save last Tx port reading
		TxPortCur = PORTB;								// and get new Tx Port reading
		TxWork = TxPortLast ^ TxPortCur;				// find the changed bits
// need to add Tx hardware enabled test here??
		if(TxWork & TxInPin)							// if it's our Tx In pin that changed
			{											// the TxInPin has changed, but to what
			if(TxPortCur & TxInPin)						// check the TxInPin for a high or low
				{										// here if Tx In pin  is now a high
				if(TxInPol == 1)						// and check polarization
					{									// here if pin high, pol is high, TX mode
					Transmit_ON();						// go turn the transmiter ON
					}	// end of TxIn=high, Pol=high
				else									// here if pin is high, but Pol is low, Rx
					{
					Transmit_OFF();						// go turn the transmitter OFF
					}	// end of txIn=high, Pol=low
				}	// end of TxIn pin high transition
			else										// we get here if TxIN pin changed, now LOW
				{
				if(TxInPol == 1)						// check the Tx In polarization
					{									// here if Tx in pin is now low, Pol = High
					Transmit_OFF();						// go turn the transmitter OFF
					}	// end of TxIn=low, Pol=high
				else									// here is Tx In pin changed to Low and
					{									// polarity is low, means Tx shud be ON
					Transmit_ON();						// go turn the transmitter ON
					}	// end of TxIn=low, Pol=low
				}	// end of TxIn pin low transition
			}	// end of Tx In pin change
		}	// end of RB pin change test
	}	// end of low_ISR function

////////////////////////////////////////////////////////////////////////////////////
//	High-priority Interrupt Service Routine
#pragma interrupt high_ISR
void high_ISR(void)
	{
	}	// end of high_ISR function

//////////////////////////////////////////////////////////////////////////////////////////
////	UserInit function.  Initializes the board.										//
//////////////////////////////////////////////////////////////////////////////////////////
void UserInit(void)
	{
	unsigned int temp;
										// TFOX added clear a bunch of flags & vars at start
	Ints_on = FALSE;						// show interrupts are off at start
	adRunning = FALSE;						// clear A/D converter running flag
	adCmd = 0;								// make sure A/D doesn't start running
	adDestination = 0;						// turn off A/D data destination flags
	adAvailable = 0;						// zero out A/D conversion data counter
	BD_state = 0;							// set initial board state USB responses OFF
	LED_tick_counter = LEDFST;				// and initial LED countdown count
	LED_heartbeat = TRUE;					//  Shows the LED "heartbeat" ON at start
	EepromWrEn = DEFAULT_EPWR;				// turn OFF eeprom writes by default
	Transmitting = FALSE;					// turn off transmitting now flag
	Calmode = FALSE;						// turn off calibreation mode at startup
	DDS32 = DEFAULT_DDS32;					// start with the power-up default DDS32 state
//	VFO_A = DEFAULT_FREQ;					// Set VFO-A to the power-up default frequency
//	VFO_B = DEFAULT_FREQ;					// and set the VFO-B to the default freq as well
//	VFO_C = MHZ10;							// set VFO-C to the standard 10MHz calibrate freq
	dds_display = (unsigned long)DEFAULT_FREQ; // Set the power-up DDS display frequency
	VFO_D = dds_display;					// save the initial dds freq in VFO-D
//	RxOffsetFreq = DEFAULT_RXOFS;			// set the power-up default receive offset freq
//	TxOffsetFreq = DEFAULT_TXOFS;			// set the power-up default transmit offset freq
	freq_work = 0;							// initialize the temporary work to zero
// temporary setup of Tx pin assignments
									// added next several lines to stop DDS-60 from messing up
	TRISB = 0;
	LATB = 0;
	PORTB = 0;
	INTCONbits.RBIF = 0;					// turn OFF RB interrupt on change for now
	INTCONbits.RBIE = 0;					// turn OFF RB interrupt on change for now
	TxPortCur = PORTB;						// clear Port B change flag & read Port B
	TxPortCur = PORTB;
	TxPortLast = TxPortCur;					// store Port B read in last port read
									// end of adds
	TxInPin = TX_INP;						// set Tx input pin to RB4 for now
	TxOutPin = TX_OUTP;						// and set Tx output pin to RB3 for now
	TxInPol = 0;							// set default transmit IN pin to active low (L=Tx)
	TxOutPol = 1;							// and set default transmit OUT pin active high(Tx=H)

									// Next, clear a bunch of PIC peripheral stuff
    CMCON = 0x07;							// set comparator inputs as digital inputs
	CVRCON = 0x00;
	ADCON0 = 0x00;							// turn off th A/D converter for now
	ADCON1 = 0x0F;							// make all analog inputs digital for now
    										// Make all of PORTA digital output
    LATA = 0x00;								// set Port A latches to 00
#ifdef	TFIOPINS
    TRISA = 0x01;								// enable AN0(pin RA0) analog in for AD8310
#endif
#ifndef	TFIOPINS
    TRISA = 0x20;								// enable AN4(pin RA5) analog in for AD8310
#endif
											// Make all of PORTB outputs to start
	LATB = 0x00;								// set the latch (Tom had all-high)
	TRISB = 0x00;								// set RB4=10 for Tx_in input signal
	PORTB = 0x05;								// set the filter to 40 meters if connected
											// TFOX_CODE added for port C attenuator bit outputs
	LATC &= 0x3c;								// make C7, C6, C1, C0 outs, C2 in for "PGM" btn
	TRISC &= 0x3c;								// don't affect earlier (USB) pin setup
										// end of PIC initialize
	mInitAllLEDs();								// initialize LEDS off

	adDelayCnt = adSampleFreq;

	for(temp = 0; temp < 6; temp++)				// clear out the DDS command buffer
		dds_cmd[temp] = 0;						// set bytes to zero to start

								//////////////////////////////////////////////////////////////////
								/////  NEXT, get & check various data from PIC EEPROM storage	//
								//////////////////////////////////////////////////////////////////	
										//// START WITH GETTING THE BOARD ID from EEPROM		//
	if(eepRD1(eBOARDID, &BoardID) == eEMPTY)
		BoardID = DEFAULT_BD;
//	eepadr = eBOARDID;									// point to the board ID in EEPROM
//	eepromRD();											// and read the data there
//	if(eepRdata != eEMPTY)								// if it's not empty (0xFF)
//		BoardID = eepRdata;								// store away the board ID
//	else												// otherwise....
//		BoardID = DEFAULT_BD;							// set the ID to default for now
												////  Next, get the Board State from EEPROM
	eepadr = eBDSTATE;									// point to the EEPROM Board State
	eepromRD();											// get the board state
	if(eepRdata == eEMPTY)								// did it come back as no data (0xFF)?
		{												// yes, the eeprom data is wrong...
		BD_state = eLEDHEART;							// just set LED Heartbeat
		} // end of EEPROM not setup
	else												// eeprom read of BD_state was not empty (FF)
		{												// EEPROM data MAY be OK..
		if(eepRdata & 0x28)								// verify the two "OK" bits are not high
			{											// if either high, EEPROM board state bad
			BD_state = eLEDHEART;						// just set the LED heartbeat
			}
		else											// otherwise EEPROM data looks to be good..
			{
			BD_state = eepRdata;						// so just set board state from EEPROM
			}
		}	// end of good eeprom read
	if(eepRD1(eTXHWPIN, &TxHwPin) == eEMPTY)	//// point to EEPROM Transmit pin hardware storage
		TxHwPin = 0;

//	eepadr = eTXHWPIN;							//// point to EEPROM Transmit pin hardware storage
//	eepromRD();											// read the pin assigments from EEPROM
//	if(eepRdata != eEMPTY)								// if the Tx hardware pin EEPROM is not empty
//		{
//		TxHwPin = eepRdata;								// read the EEPROM value
//////// ADD PIN SETUPS HERE??
//		}
//	else												// if the Tx HW pin EEPROM is empty
//		{												// set to zero to...
//		TxHwPin = 0;									// disable transmit pin hardware
//		}

	if(eepRD1(eTXENABL, &TxEnables) == eEMPTY)	//// Now, point the transmit ENABLES in EEPROM
		TxEnables = 0;
//	eepadr = eTXENABL;							//// Now, point the transmit ENABLES in EEPROM
//	eepromRD();											// and get the Tx Enable data
//	if(eepRdata != eEMPTY)								// is the Tx Enable storage not empty?
//		{												// yes, read & setup Tx hardware, etc
//		TxEnables = eepRdata;							// get the Tx enables from EEPROM
///// set transmit pins up here??
//		}
//	else												// TxEnable EEPROM was not setup...
//		{												// so, just
//		TxEnables = 0;									// turn off all transmit enable flags
//		}
	Transmit_OFF();									//// and make sure the transmitter is OFF
												
	if(eepRD1(eFLTRTYPE, &FilterType) == eEMPTY) /// Get the BPF filter type, if any
		FilterType = DEFAULT_BPF;						// show default BP filter for now
//	eepadr = eFLTRTYPE;									// point to BP filter type
//	eepromRD();											// and get whatever is there
//	if(eepRdata != eEMPTY)								// if BPF is not empty in EEPROM
//		FilterType = eepRdata;							// set the filter in local storage
//	else												// otherwise...
//		FilterType = DEFAULT_BPF;						// show default BP filter for now

	if(eepRD1(eINIBANDF, &FilterBand) == eEMPTY) /// get the BP filter initial filter
		FilterBand = 0x03;								// set the filter in BYPASS mode
	eepadr = eINIBANDF;									// point to BP filter init BAND
//	eepromRD();											// and get whatever is there
//	if(eepRdata != eEMPTY)								// if BPF band is not empty in EEPROM
//		FilterBand = eepRdata;							// set the band in local storage
//	else												// otherwise...
//		FilterBand = 0x03;								// set filter in BYPASS mode

	if(eepRD1(eDDSID, &DDSdevice) == eEMPTY)	/// Get the DDS chip ID from EEPROM
		DDSdevice = DEFAULT_DDS;
//	eepadr = eDDSID;									// point to the DDS ID byte in EEPROM
//	eepromRD();											// and get whatever is there
//	if(eepRdata != eEMPTY)								// if DDS ID is not empty in EEPROM
//		DDSdevice = eepRdata;							// set the device in local storage
//	else												// otherwise...
//		DDSdevice = DEFAULT_DDS;						// show default DDS for now

	eepadr = eDDSMULT;							/// now get the EEPROM DDS Multiplier value
	eepromRD();
	if(eepRdata != eEMPTY)								// check to see if multiplier not empty
		{												// if eeprom data is good...
		dds_pll = eepRdata & eDDSPLL;					// save the DDS PLL data from eeprom
		freq_mult = (eepRdata & eDDSRMULT) >> 5;		// and save frequency multiplier; 
		}
	else												// otherwise, if eeprom data not valid
		{
		dds_pll = DEFAULT_PLL;							// set default dds PLL multiplier
		freq_mult = DEFAULT_VFOM;						// set default frequency multiplier
		}
	if(eepRD4(eMASOSC0, &osc_freq) == 0xFF)		/// get Master oscillator freq fm eeprom
		osc_freq = (unsigned long)DEFAULT_OSC;			// if EEPROM empty, use default
											
	if(eepRD4(eREFOSC0, &freq_1Hz) == 0xFF)		///	next, get 1Hz value from EEPROM
		freq_1Hz = F500_1HZ;				///////////////  NEED TO ADJUST THIS??

	if(eepRD1(eOFSMODE, &Ofs_mode) == eEMPTY)		///  Get Offset modes from EEPROM
		Ofs_mode = 0;									// if EEPROM blank, show no offsets
//	eepadr = eOFSMODE;									// point to the EEPROM Offset mode byte
//	eepromRD();											// and get whatever is there
//	if(eepRdata != eEMPTY)								// if Offset mode is not empty in EEPROM
//		Ofs_mode = eepRdata;							// set the mode flags in local storage
//	else												// otherwise...
//		Ofs_mode = 0;									// show NO offsets for now

	if(eepRD4(eOUTOFS0, &RxOffsetFreq) == 0xFF)		/// Get Receive Offset from EEPROM
		RxOffsetFreq = DEFAULT_RXOFS;					// if EEPROM empty, use default
	if(eepRD4(eTXOFS0, &TxOffsetFreq) == 0xFF)		///	Get Transmit offset from EEPROM
		TxOffsetFreq = DEFAULT_TXOFS;					// if EEPROM empty, use default
	if(eepRD4(eFVFO_A0, &VFO_A) == 0xFF)			/// Get VFO A from EEPROM storage
		VFO_A = DEFAULT_FREQ;							// if EEPROM empty, use default
	if(eepRD4(eFVFO_B0, &VFO_B) == 0xFF)			/// Get VFO B from EEPROM storage
		VFO_B = DEFAULT_FREQ;							// if EEPROM empty, use default
	if(eepRD4(eFVFO_C0, &VFO_C) == 0xFF)			/// Get VFO C (cal) from EEPROM storage
		VFO_C = MHZ10;									// if EEPROM empty, use default

	if(eepRD1(eVFO_SRC, &VFO_sources) == eEMPTY)	/// Get VFO sources for transmit & receive
		VFO_sources = DEFAULT_VFOSRC;					// if EEPROM blank, set VFO A as source
//	eepadr = eVFO_SRC;								///  Get VFO sources for transmit & receive
//	eepromRD();											// point to EEPROM VFO source storage
//	if(eepRdata != eEMPTY)								// if VFO_SRC mode is not empty in EEPROM
//		VFO_sources = eepRdata;							// set the sources in local storage
//	else												// otherwise...
//		VFO_sources = DEFAULT_VFOSRC;					// show VFO A source for now

	if(eepRD4(eMAXOUTF0, &max_freq) == 0xFF)		// get the maximum operating frequency
		max_freq = MAXMHz32;
								// need to change to clock X 0.4 or similar

											//////////////	Now do DDS-specific initialization

								//////////////////////////////////////////////////////////////////
								////	If DDS is AD995x, Shut down the DDS temporarily			//
								//////////////////////////////////////////////////////////////////
	if(DDSdevice == eAD995x)		//  TFOX code added to turn of unwanted stuff in DDS chip
		{
		for(temp = 0; temp < 60000; temp++)	// waste some time for the Ad995x to wake up
			Buffer = 0x00;					// at power-up
		Buffer = 0x00;						// point to Control Function register 1 (0x00)
		SPImost();							// and send pointer to DDS
		SPImost();
		SPImost();							// send bits 8-15
		SPImost();							// send bits 16-23
		Buffer = 0xFA;						// turn off comparator and SYNC_CLK out (bits 0-7)
		SPImost();							// send bits 24-31
		AD99_ioud = 1;						// now, toggle IO update UP
		wait_10_inst();						// wait for it....
		AD99_ioud = 0;						// and toggle IO update back down
										// Next, set up DDS PLL command for CFR2, bit 7-0
		dds_cmd[0] = (dds_pll << 3);		// put the DDS PLL amount into the proper bits (7-3)
		dds_cmd[0] = dds_cmd[0] & 0xF8;		// clear out the non-PLL bits
		dds_cmd[0] |= 0x06;					// or in the VFO-high and charge-pump bits
		}
	DDS_init();											// Initialize the DDS chip
											//////////////	now, start calculating some values
	freq_update();										// calculate the freq-dependent values

												//////////////////////////////////////////////
												////	Temporarily setup Tx Pin Setup		//
												////	 temporary add enable here			//
												//////////////////////////////////////////////
	if(BD_state & eTXPINSON)
		{
		// TransmitOn = PORTB;							// clear Port B for first time
		LATB = ~TX_INP;										// set pin RB4 as input in latch (0xEF)
		TRISB = TX_INP;										// set pin RB4 direction to input
		OpenPORTB(PORTB_CHANGE_INT_ON & PORTB_PULLUPS_ON);	// set up Tx input pin (for now RB4)
		TxPortCur = PORTB;									// clear PortB change flag - read PortB
		TxPortLast = TxPortCur;								// store it in last port read as well
		//	PortB interrupt enable test
		INTCONbits.RBIE = 1;								// turn on RB port change intrpt enable
		INTCON2bits.RBIP = 0;								// and make it a low priority
		}	// end of BS_state & eTXPINSON

												//////////////////////////////////////////////
												////	Set up Timer 0 10msec interrupts	//
												////	and general interrupts				//
												//////////////////////////////////////////////
	OpenTimer0(TIMER_INT_OFF & T0_16BIT & T0_SOURCE_INT & T0_PS_1_32);
	WriteTimer0(TMR0_10MS);						// set timer 0 to 10msec value (count-up)

	RCONbits.IPEN = 1;							// Enable priority level on interrupts
	T0CONbits.TMR0ON = 0;						// turn off timer 0 interrupts until ready

	INTCONbits.TMR0IE = 1;						// turn on Timer 0 interrupt enable
	INTCON2bits.TMR0IP = 0;						// disable Timer 0 high-priority interrupt

	INTCON2bits.RBIP = 0;						// make port RB changes a low priority

	INTCONbits.GIEH = 1;						// turn on Global interrupt High bit
	INTCONbits.GIEL = 1;						// turn on Global interrupt Low bit

 	T0CONbits.TMR0ON = 1;						// turn on Timer 0 interrupts
	Ints_on = TRUE;								// and show interrupts on
													// end of interrupt enables
	AD99_ioud = 0;
	mLED_2_Off();
	}//end UserInit

/******************************************************************************
 * Function:        void DDS_Out(void)
 *
 * PreCondition:    None
 *
 * Input:           USB received data 
 *
 * Output:          Serial stream to DDS device
 *
 * Side Effects:    None
 *
 * Overview:        DDS_Out receives a frequency control "word" from the C#
 *					program on the PC and sends it out to the device in a serial
 *
 * Note:            
 *
 *****************************************************************************/
void DDS_Out(void)
	{   
	char bytesIn = 0;
	int count;
    // User Application USB tasks
    if((usb_device_state < CONFIGURED_STATE)||(UCONbits.SUSPND==1)) return;

	// Pull in some new data if there is new data to pull in
	bytesIn = getsUSBUSART(input_buffer, 5);
	if (bytesIn > 0)
		{  // Have some USB data to process
		for(count = 0; count < 5; count++)				// copy the input buffer data
			dds_cmd[count] = input_buffer[count];		// into the dds command array
     	switch ( dds_cmd[4] /*input_buffer[4]*/ )
		//
		//SWITCH is the heart of the routine. The selection codes ranges are
		// 01 - 3F : Process Freq update for device
		//		1  - AD9850 / DDS 30
		//		2  - AD9851 / DDS 60
		//		3  - AD9854 / IQPro
		//		4  - AD995x
		//		5  - AD9958/9
		//tf	6  - AD9832/AD9835
		//tf	7  - AD9833
		//tf	8  - AD9834
		//tf	9  - AD9912
		// 40 - 7F : Process special non- DDS devices, eg bandpass filters
		//tf	119 (77H) - set various PIC parameters
		//tf	120 (78H) - read various parameters from PIC
		//tf	121 (79H) - Set freq via PIC calculations
		//tf	122 (7AH) - calibrate Master Oscillator frequency
		//tf	123 (7BH) - Set LP/BP filters
		//tf	124 (7CH) - Transmit on/off
		//tf	125 (7DH) - read/write to EEPROM
		//tf	126 (7EH) - A/D converter command
		//tf	127 (7FH) - Programmable attenuator (HRF AT4611) control
		// 80 - BF : Initialization sequences 
		//		128 (80H) - Initialize 9850
		//		129 (81H) - Initialize 9851		
		//		130 (82H) - Initialize 9854
		//		131 (83H) - Initialize 995x
		//		132 (84H) - Initialize 9958/9
		//tf	133 (85H) - Initialize AD9832/AD9835
		//tf	134 (86H) - Initialize AD9833
		//tf	135	(87H) - Initialize AD9834
		//tf	136 (88H) - Initialize AD9912	
		//tf	250	(FAH) - Set Master Oscillator frequency
		//tf	251	(FBH) - Set DDS PLL and out multiplier values
		//tf	252 (FCH) - Transmit logic initialization
		//tf	253 (FDH) - Board initialization
		//tf	254 (FEH) - A/D Converter Initialization
		//tf	255 (FFH) - Board test command
      	{
        case cmBOARDID:							// (0x00) send board ID data back to host
				BoardId();
			break;
		case cm9850UPD:							// (0x01) send freq update sequence to DDS30
		  		input_buffer[4]= 0x00;				// set control word to 00
				dds_cmd[4] = 0x00;					// set DDS_cmd buffer control word to 00
				DDSx0();
           break;
        case cm9851UPD:							// (0x02) send freq update sequence to DDS60
				input_buffer[4]= 0x01;				// set control word
				dds_cmd[4] = 0x01;					// set DS_cmd buffer control word to 01
				DDSx0();
           break;
        case cm9854UPD:							// (0x03) send freq update seq to AD9854
				send_9854Freq();
		   break;
        case cm995xUPD:							// (0x04) send freq update seq to AD995x
				send_9951Freq();
            break;
        case cm9958UPD:							// (0x05) send freq update seq to AD9958
				send_9958Freq();		
			break;
											// TFOX code added for following commands
		case cm9832UPD:							// (0x06) set Freq update to AD9832/AD9835
				send_9832Freq();
			break;
		case cm9833UPD:							// (0x07) send Frequency update to AD9833
				send_9833Freq();
			break;
		case cm9834UPD:							// (0x08) send frequency update to AD9834
				send_9833Freq();
			break;
		// case cm9912UPD:						// (0x09) Send freq update to AD9912 (FUTURE)
		//		send_9912Freq();
		//	break;
		//case cmMODE_SET():					// (0x75) Set mode and enable/disable modes
		//		set_mode()
		//	break;
		case cmVFO_SET:							// (0x76) Set various VFO modes (copy, etc)
				VFO_setup();
			break;
		case cmSETPARAM:						// (0x77) set various parameters for the PIC
				set_param();
			break;
		case cmGETPARAM:						// (0x78) Read various PIC parameters
				show_param();
			break;
		case cmSETFREQ:							// (0x79) set DDS operating frequency via PIC
				set_freq();						// set frequency via pic, with 32-bit binary
			break;
		case cmMOSCCAL:							// (0x7A) calibrate master oscillator frequency
				Osc_cal();
			break;
		case cmSETFLTR:							// (0x7B) Set the LP/BP filters
				filter_set();
			break;
		case cmTXONOFF:							// (0x7C) Transmit on/off via PIC command
				Tx_on_off();
			break;
		case cmRWEPROM:							// Cmd 0x7D - read/write EEPROM byte
				rdwreeprom();
			break;
		case cmADCMD:							// Cmd 0x7E - activate A/D converter
				adCommand();
			break;
		case cmATTNCMD:							// Cmd 0x7F - set AT4611 attenuator
				set_atten();
			break;
		// end_of TFOX_CODE add
		//
		//		Initialization Selections
		//
        case cm9850INI:							// Cmd 0x80 - Initialize 9850/51
				DDSdevice = eAD9850;    		
				AD9850Int();
            break;
        case cm9851INI:							// Cmd 0x81 - Initialize 9851
				DDSdevice = eAD9851;
	    		AD9850Int();
            break;
        case cm9854INI:							// Cmd 0x82 - Initialize 9854
	    		DDSdevice = eAD9854;
				AD9854Int();
            break;
         case cm9951INI:						// Cmd 0x83 - Initialize 995x
	    		DDSdevice = eAD995x;
				AD995xInt();
            break;
        case cm9958INI:							// Cmd 0x84 - Initialize 9858/9
				DDSdevice = eAD9958;
	    		AD9958Int();
            break;
		//  TFOX code added for initialization sequences
		case cm9832INI:							// CMD 0x85 - Initialize AD9832/AD9835
				DDSdevice = eAD9832;
				AD9832INI();
			break;
		case cm9833INI:							// CMD 0x86 - Initialize AD9833 DDS
				DDSdevice = eAD9833;
				AD9833INI();
			break;
		case cm9834INI:
				DDSdevice = eAD9834;			// CMD 0x87 - Initialize AD9834 DDS
				AD9833INI();						// uses AD9833 init for now...
			break;
		//case cm9912INI:						// CMD 0x88 - Initialize AD9912 DDS (FUTURE)
		//		DDSdevice = eAD9912;
		//		AD9912INI();
		//	break;
		//case cmMODEINI:						// CMD 0xF5 - Initialize DDS mode operation
		//		Mode_init();
		//	break;
		//case cmBPFINI:						// CMD 0xF9 - Initialize bandpass filters (FUTURE)
		//		BPF_init();
		//	break;
		case cmOSCSET:							// CMD 0xFA - Set the master oscillator
				OscSet();
			break;
		case cmPLLMULT:							// CMD 0xFB - set the DDS PLL and VFO mult
				PllMult();
			break;
		case cmTXHWINI:							// CMD 0xFC - Transmit logic initialization
				Tx_init();
			break;
		case cmBDINIT:							// CMD 0xFD - complete board power-up init
				BoardInit();
			break;
		case cmADINIT:							// CMD 0xFE - initialize A/D converter
				adInit();
			break;
		case cmBDTEST:							// CMD 0xFF - test the board.  Only changes LEDs
				Bdtest();							// NOTE:  This just tests USB connectivity
			break;
		//	end of TFOX added code
		default:								// DEFAULT - send control word to DDS60
	    		DDSx0();
      	}// End of switch statement

	}//end of bytesIN
											// temporary clean-up code for A/D results
	if(adAvailable != 0)						// check for any A/D results data
		adAvailable = 0;						// for now, just eat the internal A/D results
}//end ProcessIO

//////////////////////////////////////////////////////////////////////////////////////////
////	DDS_parse().	Parses the DDS set frequency command, based on DDS type of DDS	//
//////////////////////////////////////////////////////////////////////////////////////////
void DDS_parse(void)
	{
      switch (DDSdevice)
      	{
		case eAD9850:							// send freq update control seq to DDS30
		  		dds_cmd[4]= 0x00;				// set control word (PLL) to 00
				DDSx0();
           break;
        case eAD9851:							// send freq update control seq to DDS60
				dds_cmd[4]= 0x01;				// set control word (PLL) to 01
				DDSx0();
           break;
        case eAD9854:							// send freq update control seq to AD854
				send_9854Freq();
		   break;
        case eAD995x:							// send freq update control seq to AD995x
				send_9951Freq();
            break;
        case eAD9958:							// send freq update control seq to AD9958
				send_9958Freq();		
			break;
		case eAD9833:							// send Frequency update to AD9833
				send_9833Freq();
			break;
		case eAD9834:							// send frequency update to AD9834
				send_9833Freq();
			break;
		case eAD9832:							// set Frequency update to AD9832/AD9835
				send_9832Freq();
			break;
			default:
				DDSx0();
		}
	}

//////////////////////////////////////////////////////////////////////////////////////////////
////	DDS_init().		Initializes the proper DDS IC, based on DDSdevice parameter			//
//////////////////////////////////////////////////////////////////////////////////////////////
void DDS_init(void)
	{
	switch (DDSdevice)								// DDS Initialization Sequences
      	{
        case eAD9850:								// Initialize 9850/51	    		
				AD9850Int();
            break;
        case eAD9851:								// Initialize 9851
	    		AD9850Int();
//				if(dds_pll == 6)
//					dds_pll = 1;
            break;
        case eAD9854:								// Initialize 9854
				AD9854Int();
            break;
         case eAD995x:								// Initialize 995x
				AD995xInt();
            break;
        case eAD9958:								// Initialize 9858/9
	    		AD9958Int();
            break;
		case eAD9833:								// Initialize AD9833 DDS
				AD9833INI();
			break;
		case eAD9834:								// Initialize AD9834 DDS			
				AD9833INI();						// uses AD9833 init for now...
			break;
		case eAD9832:								// Initialize AD9832/AD9835
				AD9832INI();
			break;
		default:
				DDS32 = DEFAULT_DDS32;
		}
	}

/////////////////////////////////////////////////////////////////////////////////////////
void DDSx0(void)
{
// 	Freq word arrived - Send freq word to device serially. LSB
//	Control word is 0 for DDS30 / AD9850.  No REFCLOCK multiplier in AD9850
//	Control word is 1 for DDS60 / AD9851.  This is actually to enable AD9851 X6 REFCLOCK

//  DDS_clk		LATBbits.LATB6		// Serial clk
//  DDS_ioud	LATBbits.LATB5		// I/O update
//  DDS_data	LATBbits.LATB7		// Serial data
mLED_2_Toggle();

		DDS_ioud = 0;		//Clear Latch
	 	Buffer = dds_cmd[3];				// get FTW, least sig BYTE (W0-W7) (LSB)
		output_buffer[0] = Buffer;			// copy to out bfr in reverse order
		//Buffer = 0xFE;
		SPIleast(); 	// Sends data LSB out PortB.7; clocked by PortB.6

	 	Buffer = dds_cmd[2];				// get FTW bits W8-W15
		output_buffer[1] = Buffer;
		//Buffer = 0x08;	
		SPIleast(); 	// Sends data LSB out PortB.7; clocked by PortB.6

	 	Buffer = dds_cmd[1];				// get FTW, bits W16-W23
		output_buffer[2] = Buffer;
		//Buffer = 0xCD;			 	
		SPIleast(); 	// Sends data LSB out PortB.7; clocked by PortB.6

	 	Buffer = dds_cmd[0];				// get FTW, bits W24-W31
		output_buffer[3] = Buffer;
		//Buffer = 0x0A;	
		SPIleast(); 	// Sends data LSB out PortB.7; clocked by PortB.6
	
		Buffer = dds_cmd[4];             //Control word. AD9850 = 0x00 (no REFCLOCK)
										// AD9851 = 0x01 to enable X6 REFCLOCK
		output_buffer[4] = Buffer;	
		//Buffer = 0x01;		
		SPIleast(); 	// Sends data LSB out PortB.7; clocked by PortB.6


		//LATBbits.LATB5 = 1;		//Latch Freq word into DDS
		DDS_ioud = 1;		//Latch Freq word into DDS
 		Delay100TCYx(200);

		//LATBbits.LATB5 = 0;		//Clear Latch
		DDS_ioud = 0;		     	//Clear Latch
	    
		// Send result back to PC
		SendToUSB();
	//mLED_2_Toggle();
	}// end of DDSx0

//////////////////////////////////////////////////////////////////////////////////////
void SPIleast(void)
{
// Send byte of serial control word, LSB first

int i;

  DDS_clk = 0; // CLear clock  
  for(i=0;i<8;i++){ 

  DDS_data =(int)Buffer & 0x01; 
  DDS_clk = 1;  //Clock bit into DDS

	wait_10_inst();
  //Delay100TCYx(10); 
  DDS_clk = 0;

  Buffer >>= 1;
  wait_10_inst();
  //Delay100TCYx(10); 

  } //end of for loop
 
}// end of SPIleast

////////////////////////////////////////////////////////////////////////////////////
void SPImost(void)
	{
	// Send byte of serial control word, MSB first
	int i,j;
	char mask;
	
	mask = 0x80;
  	IQ_clk = 0; // CLear clock 
  j=1; 			// waste a little time

  for(i=0;i<8;i++)
	{ 
  	IQ_data =0;
  	if (Buffer & mask) IQ_data = 1; //set output to MSB
  
  	j=1;
  	IQ_clk = 1;  //Clock bit into DDS

  	wait_10_inst();

  	IQ_clk = 0;
  
  	mask >>= 1;    // left shift byte

  	//Delay100TCYx(10); 

  	} //end of for loop
 
  }// end of SPImost

////////////////////////////////////////////////////////////////////////////////////
void AD9850Int(void)
{						//  Send the sequence to set up the 9850/51 for serial updates
	DDS32 = TRUE;						// set the calculate frequency to 32-bits
	mLED_2_Toggle();
	DDS_clk = 1;	//Clock serial control into DDS
	wait_10_inst();
	DDS_clk = 0;

	wait_10_inst();

	DDS_ioud = 1;
	wait_10_inst();
	DDS_ioud = 0;

 	Buffer = 0;				// set frequency bits W0-W7 (LSB) to 0
	SPIleast();				// Sends data LSB out PortB.7; clocked by PortB.6
 	Buffer = 0;				// set frequency bits W8-W15 to 0
	SPIleast();				// Sends data LSB out PortB.7; clocked by PortB.6
 	Buffer = 0;				// set frequency bits W16-W23 to 0
	SPIleast();				// Sends data LSB out PortB.7; clocked by PortB.6
 	Buffer = 0;				// set frequency bits W24-W31 (MSB) to 0
	SPIleast();				// Sends data LSB out PortB.7; clocked by PortB.6
 	Buffer = 0x01;			// set the control word to enable X6 REF clock
	SPIleast();				// Sends data LSB out PortB.7; clocked by PortB.6

	wait_10_inst();

	DDS_ioud = 1;
	wait_10_inst();
	DDS_ioud = 0;

}// end of 9850/51Int

///////////////////////////////////////////////////////////////////////////////
void AD9854Int(void)
{
	DDS32 = TRUE;								// set the Max frequency to 32-bits

//  Send the sequence to set up the 9854 for serial updates
//  Protocol courtesy of Craig Johnson, AA0ZZ

	//	Pulse Master reset
	Delay100TCYx(20); 	//wait 8ms
	IQ_mreset = 1;
	Delay100TCYx(20); 	//wait 8ms
	IQ_mreset = 0;
	Delay100TCYx(20); 	//wait 8ms

	// Pulse IO reset
	IQ_ioreset = 1;
	Delay100TCYx(20); 	//wait 8ms
	IQ_ioreset = 0;

	//Send command to write CR register
	Buffer = AD9854_cwr;						// changed from: CR_write_cmd;
	SPImost();

	// send 4 CR bytes
	Buffer = AD9854_cb0;						// changed from: CR_byte_0;
	SPImost();
	Buffer = AD9854_cb1;						// changed from: CR_byte_1;
	SPImost();
	Buffer = AD9854_cb2;						// changed from: CR_byte_2;
	SPImost();
	Buffer = AD9854_cb3;						// changed from: CR_byte_3;
	SPImost();

//	External Update now set
//	Now send new IOreset and new command

	// Pulse IO reset
	IQ_ioreset = 1;
	Delay100TCYx(30); 	//wait 8ms
	IQ_ioreset = 0;

	//Send command to write CR register
	Buffer = AD9854_cwr;						// changed from: CR_write_cmd;
	SPImost();

	Buffer = AD9854_cb0;						// changed from: CR_byte_0;
	SPImost();
	Buffer = AD9854_cb1;						// changed from: CR_byte_1;
	SPImost();
	Buffer = AD9854_cb2;						// changed from: CR_byte_2;
	SPImost();
	Buffer = AD9854_cb3;						// changed from: CR_byte_3;
	SPImost();

//	Send external update to trigger initialization
	// raise IO update
	IQ_ioud = 1;
	wait_10_inst();
	IQ_ioud = 0;

		// Send result back to PC
		//if(mUSBUSARTIsTxTrfReady())
	     //   {

		//		mUSBUSARTTxRam((byte*)output_buffer,5); 
		//	}
	
}// end of 9854Int

///////////////////////////////////////////////////////////////////////////////////
void wait_10_inst(void)
{
// actually about 15 instruction
int i;
	i=1;
	i=2;

}// end of wait_10_inst routine

//////////////////////////////////////////////////////////////////////////////////
void send_9854Freq(void)
{
	// Pulse IOreset
	IQ_ioreset = 1;
	wait_10_inst();
	IQ_ioreset = 0;

	//Send command to write CR register
	Buffer = AD9854_fwr;						// changed from: freq_write_cmd;
	SPImost();
	Buffer = dds_cmd[0];
    //Buffer = 0x0E;
	SPImost();
	Buffer = dds_cmd[1];
	//Buffer = 0x6A;
	SPImost();
	Buffer = dds_cmd[2];
    //Buffer = 0xFC;
	SPImost();
	Buffer = dds_cmd[3];
    //Buffer = 0xCE;
	SPImost();
	Buffer = 0x00;
	SPImost();
	Buffer = 0x00;
	SPImost();

	// raise IO update
	IQ_ioud = 1;
	wait_10_inst();
	IQ_ioud = 0;
	
}// end of send_9854Freq

///////////////////////////////////////////////////////////////////////////////////////////
void AD995xInt(void)
	{
	DDS32 = TRUE;									// set the Max frequency to 32-bits
	// Send reset - might not be needed
	IQ_mreset = 1;										// HW RESET to AD995x DDS
	IQ_mreset = 0;										// And toggle reset bck low.

														//Send word for register selection 

	Buffer = 0x01;										// Select CFR-2 to set up devices
	SPImost();											// send it to the DDS
													// send CFR2 initialization bytes (24 bits)
	Buffer = 0x00;										// CFR2, bits 32-16 (not used)
	SPImost();											// Send it to the DDS
	Buffer = 0x00;										// CFR1 bits 15-8 (Syncs, XTAL out, OSK)
	SPImost();											// send that to DDS
									// TFNOTE:  THIS HAS BEEN PREVIOUSLY COMMENTED OUT
									//Note: This byte must be customized to the specific device
									//      configuration of the 995x -  test confg set for 
									//      20Mhz crystal multiplied 20 times
									//		10100-1-10 = 20x PLL- VCO>250MHZ -Default charge pump
									//Buffer = 0xA6;	// Pll Mult=20;
 
	Buffer = dds_cmd[0];								// Now send CFR2 bits 7-0, PLL multiplier
	SPImost();											// and send that to the DDS
													// Done sending CFR2 to DDS, toggle it in
	AD99_ioud = 1;										// Toggle DDS IO_UPDATE pin
	wait_10_inst();										// wait a little bit (not needed?)
	AD99_ioud = 0;										// and drop DDS IO_UPDATE pin
													//  TFOX code added to turn of unwanted stuff
	Buffer = 0x00;										// point to CFR-1 (0x00)
	SPImost();											// and send pointer to DDS
	SPImost();											// send CFR1 bits 24-31
	SPImost();											// send CFR1 bits 16-23
	SPImost();											// send CFR1 bits 8-15
	Buffer = 0x42;										// turn off onboard comparator 
														//    and SYNC_CLK out (bits 0-7)
	SPImost();											// send CFR1 bits 0-7
	AD99_ioud = 1;										// Toggle DDS IO_UPDATE pin UP
	wait_10_inst();										// wait a little bit (not needed?)
	AD99_ioud = 0;										// and drop DDS IO_UPDATE pin down again
													// end of temporary power-down test code
	}// end of  AD995xInt

///////////////////////////////////////////////////////////////////////////////////////////
void send_9951Freq(void)
	{
													//Send bytes for fequency selection to FTW0
	Buffer = 0x04;									// Point to DDS Freq Tuning Word 0 (0x04)
	SPImost();											// and send pointer to DDS
													// Now send 32 bit freq word to FTW0
	Buffer = dds_cmd[0];								// get the most-sig BYTE of FTW
	SPImost();											// and send it to FTW0 bits 21-24
	Buffer = dds_cmd[1];								// get the next most-sig BYTE of FTW
	SPImost();											// and send it to FTW0 bits 23-16
	Buffer = dds_cmd[2];								// get the next lowest BYTE of FTW
	SPImost();											// and send it to FTW0 bits 15-8
	Buffer = dds_cmd[3];								// finally, get least-sig BYTE of FTW
	SPImost();											// and send that to FTW0, bits 7-0
	AD99_ioud = 1;									// Toggle DDS IO_SYNC UP to lock in FTW
	wait_10_inst();										// wait a little bit (not needed?)
	AD99_ioud = 0;										// and drop IO_SYNC back down
	}// end of send_9951Freq

///////////////////////////////////////////////////////////////////////////////////////////
void AD9958Int(void)
	{
	//Draft Code - untested
	DDS32 = TRUE;				// set the Max frequency to 32-bits

	// First set the PLL from the initialization word
	Buffer = 0x01;	//Select Reg 1
	SPImost();

	// set PLL multiplier from MSB byte of initialization word
	//Buffer = dds_cmd[0];	//input_buffer[0];
	//Buffer <<= 2;    // right shift byte twice
	//Buffer = Buffer << 2;
	Buffer = 0x90;		// Set mult to 4 ( left shifted 2 bits)
	SPImost();
	Buffer = 0x00;		// byte 2
	SPImost();
	Buffer = 0x00;		// byte 3 of reg 1
	SPImost();

	// Wait 1ms for the clock to settle
	Delay10TCYx(50); 	//wait 1ms

	// Now set the channel 1 phase to 180 degrees from channel 0
	Buffer = 0x00;	//Select Reg 0
	SPImost();
	Buffer = 0x80;	//Enable only channel 1
	SPImost();

	Buffer = 0x05;	//Select Reg 5 = phase set
	SPImost();	
	Buffer = 0x20;		// Set phase to 180 degrees
	SPImost();
	Buffer = 0x00;		// byte 2
	SPImost();

	// Reset the channel bits so they are both being updated
	Buffer = 0x00;	//Select Reg 0
	SPImost();
	Buffer = 0xF0;	//Enable only channel 1
	SPImost();

	// Send initial frequency 7.040 at 500Mhz
	Buffer = 0x04;	//Select Reg 4 = freq set
	SPImost();	
	Buffer = 0x20;		// Freq MSB
	SPImost();
	Buffer = 0x00;		// byte 2
	SPImost();
	Buffer = 0x00;		// byte 3
	SPImost();
	Buffer = 0x00;		// Freq LSB
	SPImost();

	// Send IO_UPDATA to load all the parameters
	// toggle IO update

	AD99_ioud = 1;
	wait_10_inst();
	AD99_ioud = 0;
	}	// end of 9958 Init function

/////////////////////////////////////////////////////////////////////////////////////////
void send_9958Freq(void)
	{ //DRAFT CODE _ UNTESTED
	DDS32 = TRUE;				// set the Max frequency to 32-bits

	//Send bytes for fequency selection
	// Send initial frequency 7.040 at 500Mhz

	Buffer = 0x04;	//Select Reg 4 = freq set
	SPImost();	

	// Send freq from USB buffer
	Buffer = dds_cmd[0];		//input_buffer[0];
    //Buffer = 0x0E;
	SPImost();
	Buffer = dds_cmd[1];	//input_buffer[1];
	//Buffer = 0x6A;
	SPImost();
	Buffer = dds_cmd[2];	//input_buffer[2];
    //Buffer = 0xFC;
	SPImost();
	Buffer = dds_cmd[3];	//input_buffer[3];

	// Send IO_UPDATA to load all the parameters
	// toggle IO update

	AD99_ioud = 1;
	wait_10_inst();
	AD99_ioud = 0;

	}// end of send_9958Freq

//////////////////////////////////////////////////////////////////////////////////////////
//	The following code added by Terry Fox, WB4JFI May thru July 2007 for AD9832,		//
//											AD9833, AD9834B/C, AD9835					//
//////////////////////////////////////////////////////////////////////////////////////////

////////////////////////////////////////////////////////////////////////////////////
////		Modified version of SPImost() that keeps clock HIGH instead of LOW	////
////////////////////////////////////////////////////////////////////////////////////
void SPImost2(void)
	{							// Send a byte of serial data to the DDS chip, MSB first
	int i,j;
	char mask = 0x80;						// set the mask to most-sig BIT to start
  	for(i=0; i<8; i++)						// set loop up for eight bits
		{ 
  		if (Buffer & mask)						// if the bit being tested is high,
			DDS_data = 1; 						// set DDS serial data bit HIGH
		else									// otherwise...
			DDS_data = 0;						// set DDS serial data bit LOW
  		wait_10_inst;									// waste a little time (not needed?)
											// Note, these devices use clock trailing edge
  		DDS_clk = 0;							// now, toggle the DDS clock bit LOW
  		wait_10_inst();							// waste a little time (not needed?)
  		DDS_clk = 1;							// and then toggle the clock pin back high
    	mask >>= 1;								// move the mask by one bit down
  		} //end of for loop
 	DDS_data = 0;							//  and force DDS DATA pin low
  }// end of SPImost2

//////////////////////////////////////////////////////////////////////////////////////
///		AD9833INI().			Initializes the AD9833 DDS IC						//
//////////////////////////////////////////////////////////////////////////////////////
void AD9833INI(void)
	{
	DDS32 = FALSE;							// set the Max frequency to 28-bits
	DDS_clk = 1;							// Initialize CLOCK line HIGH for AD9833 & AD9834
	DDS_ioud = 1;							// Set FSYNC to high - AD9833 is active LOW
	wait_10_inst();							// and let it settle
										// Now begin by resetting the DDS chip via SW command
	DDS_ioud = 0;							// now, bring FSYNC low to start a 16-bit transfer
	Buffer = 0x21;							// Reset AD9833
	SPImost2();								// send reset to DDS control register
	Buffer = 0x00;							// leave rest of control word turned off
	SPImost2();								// and send that to the DDS
	DDS_ioud = 1;							// toggle FSYNC after DDS reset word is sent
	wait_10_inst();							// wait for RESET command ingestion
										// Lastly, turn OFF DDS software RESET via command
	DDS_ioud = 0;							// drop the FSYNC again for first freq word
	Buffer = 0x20;							// now, turn off RESET pin in control word
	SPImost2();								// send Control word bits 15-8 to the DDS
	Buffer = 0x00;							// rest of control word is 0x00 for now (no square)
	SPImost2();								// send Control word bits 7-0 to the DDS
	DDS_ioud = 1;							// toggle FSYNC after RESET off word is sent
	wait_10_inst();							// wait a little while...
	DDS_ioud = 1;							// finally, raise DDS FSYNC back HIGH
	DDS_clk = 1;							// and make sure DDS CLOCK pin is also HIGH
	}

//////////////////////////////////////////////////////////////////////////////////////////////
////	send_9833Freq().	Send a new frequency to the AD9833 DDS IC						//
////						NOTE:  AD9833 uses a 28-bit FTW, broken into two 14-bit parts	//
////								plus FREQ reg pointers in two most-sig bits of each word//
////						called with:	dds_cmd[0] = 4 most-sig bits of FTW				//
////										dds_cmd[1] = next 8 bits of FTW					//
////										dds_cmd[2] = next 8 bits of FTW					//
////										dds_cmd[3] = lowest 8 bits of FTW				//
////						This routing must do some bit manipulation with the 28-bit FTW	//
//////////////////////////////////////////////////////////////////////////////////////////////
void send_9833Freq(void)
	{
	unsigned char work;						// create temporary storage for intermediate work

	DDS_ioud = 0;							// drop the FSYNC again for first freq word
											// create and send the first FTW byte
												// Send top of lower 14-bits of FTW to Freq0
	Buffer = dds_cmd[2] & 0x3F;					// get the top 6 bits of lower FTW word
	Buffer = Buffer | 0x40;						// add pointer to FREQ0 register
	SPImost2();									// and send top 6-bits of lower part FTW
											// create and send the second FTW byte
	Buffer = dds_cmd[3];						// send btm of lower 14-bits of FTW to Freq0
	SPImost2();									// and send bottom 8-bits of lower-part FTW
	DDS_ioud = 1;								// toggle FSYNC after first freq word is sent
	wait_10_inst();								// and wait for first FTW word to be digested
	DDS_ioud = 0;								// drop the FSYNC again for first freq word
											// Create & send the third FTW byte
												// send top of upper 14-bits of 1MHz to Freq0
	work = dds_cmd[1] >> 6;						// shift two most-sig bits of upper
	Buffer = work & 0x03;						// make sure the rest of the bits are clear
	work = dds_cmd[0] << 2;						// get six most-significant FTW bits
	work = work & 0x3C;							// strip the two least-sig bits
	Buffer = Buffer | work;						// add in the four MS bits of the FTW
	Buffer = Buffer | 0x40;						// add in pointer to FREQ0 register
	SPImost2();									// now, send the third FTW byte
											// Create and send the fourth FTW byte
	work = dds_cmd[2] >> 6;						// get the two top bits from FTW byte 2
	Buffer = work & 0x03;						// make sure the rest of the bits are clear
	work = dds_cmd[1] << 2;						// get the remainder of the FTW
	work = work & 0xFC;							// and clear off the unwanted bits
	Buffer = Buffer | work;						// combine the bits into the last FTW word
	SPImost2();									// send btm of upper 14-bits of 1MHz to Freq0
											// now, clean up the DDS pins
	DDS_ioud = 1;								// toggle FSYNC after second freq word is sent
	wait_10_inst();
	DDS_clk = 1;								// and make sure DDS CLOCK pin is also HIGH

//	for(work = 0; work < 4; work++)				// now copy the FTW to the USB output buffer
//		output_buffer[work] = dds_cmd[work];	// so we can tell the host a freq update was done
//	output_buffer[4] = 0x07;					// and show this is an AD9833 Freq set
//	SendToUSB();								// and send it to the USB port
	}

////////////////////////////////////////////////////////////////////////////////////////////
///		AD9832INI().			Initializes the AD9832 or AD9835 DDS IC					////
////////////////////////////////////////////////////////////////////////////////////////////
void AD9832INI(void)
	{
	DDS32 = TRUE;						// set the Max frequency to 32-bits
	DDS_clk = 1;							// Initialize CLOCK line HIGH for AD9832 & AD9835
	DDS_ioud = 1;							// Set FSYNC to high - AD9833 is active LOW
	wait_10_inst();							// and let it settle
										// Now begin by resetting the DDS chip via SW command
	DDS_ioud = 0;							// now, bring FSYNC low to start a 16-bit transfer
	Buffer = 0xD8;							// Set RESET and CLEAR HIGH in the AD9832
	SPImost2();								// send reset to DDS control register
	Buffer = 0x00;							// leave rest of control word turned off
	SPImost2();								// and send that to the DDS
	DDS_ioud = 1;							// toggle FSYNC after DDS reset word is sent
	wait_10_inst();							// wait for RESET command ingestion
										// Set the DDS to Software select of Freq & phase regs
	DDS_ioud = 0;							// drop the FSYNC again for SW select command
	Buffer = 0x90;							// Send Freq & phase select under software cmd
	SPImost2();								// send it to the DDS
	Buffer = 0x00;							// Clear out lower eight bits of pin select
	SPImost2();								// send it to the DDS
	DDS_ioud = 1;							// toggle FSYNC after Freq & phase SW select
	wait_10_inst();							// wait for DDS ingestion
										// Now, select Freq0 and Phase0 registers for normal use
	DDS_ioud = 0;							// drop the FSYNC again for Register select
	Buffer = 0x60;							// Select Freq and Phase regs at the same time
	SPImost2();								// Send it to the DDS
	Buffer = 0x00;							// clear out the bottom eight bits of command
	SPImost2();								// send that to the DDS
	DDS_ioud = 1;							// toggle FSYNC after second freq word is sent
	wait_10_inst();							// wait for more ingestion
										// Lastly, turn OFF DDS software RESET via command
	DDS_ioud = 0;							// drop the FSYNC again for first freq word
	Buffer = 0xC0;							// now, turn off RESET pin in control word
	SPImost2();								// send Control word bits 15-8 to the DDS
	Buffer = 0x00;							// rest of control word is 0x00 for now (no square)
	SPImost2();								// send Control word bits 7-0 to the DDS
	DDS_ioud = 1;							// toggle FSYNC after RESET off word is sent
	wait_10_inst();							// wait a little while...
	DDS_ioud = 1;							// finally, raise DDS FSYNC back HIGH
	DDS_clk = 1;							// and make sure DDS CLOCK pin is also HIGH
	}

//////////////////////////////////////////////////////////////////////////////////////////////
////	send_9832Freq().	Send a new frequency to the AD9832 or AD9835 DDS IC				//
////						NOTE:  This is pretty simple... send an address, then FTW byte	//
////						called with:	dds_cmd[0] = 8 most-sig bits of FTW				//
////										dds_cmd[1] = next 8 bits of FTW					//
////										dds_cmd[2] = next 8 bits of FTW					//
////										dds_cmd[3] = lowest 8 bits of FTW				//
//////////////////////////////////////////////////////////////////////////////////////////////
void send_9832Freq(void)
	{
	unsigned char work;						// create temporary storage for intermediate work
										// send the FTW to FREQ0
	DDS_ioud = 0;							// drop the FSYNC again for first freq word
											// start by sending lower word (16 bits)FTW to Freq0	
	Buffer = 0x30;								// send DEFER command for FTW LSB to Freq0
	SPImost2();									// send it to the DDS
	Buffer = dds_cmd[3];						// get the lowest-eight bits of the FTW
	SPImost2();									// and send bottom 8-bits of lower-part FTW
	Buffer = 0x21;								// send LOAD command for FTW LSW to Freq0
	SPImost2();									// send it to the DDS
	Buffer = dds_cmd[2];						// get the 8 upper bits of the FTW LSW
	SPImost2();									// and send upper 8-bits of lower-part FTW
	DDS_ioud = 1;							// toggle FSYNC after first freq word is sent
	wait_10_inst();								// and wait for first FTW word to be digested
											// now send the upper 16-bit word of FTW to Freq0
	DDS_ioud = 0;								// drop the FSYNC again for first freq word
	Buffer = 0x32;								// send DEFER command for FTW MSB-low to Freq0
	SPImost2();									// send it to the DDS
	Buffer = dds_cmd[1];						// get the lower 8-bits of the FTW upper word
	SPImost2();									// and send bottom 8-bits of upper-part FTW
	Buffer = 0x23;								// send LOAD command for FTW MSW to Freq0
	SPImost2();									// send it to the DDS
	Buffer = dds_cmd[0];						// get the 8 upper bits of the FTW MSW
	SPImost2();									// and send upper 8-bits of upper-part FTW
	DDS_ioud = 1;							// toggle FSYNC after second freq word is sent
	wait_10_inst();								// wait for digestion
	DDS_clk = 1;								// and make sure DDS CLOCK pin is also HIGH
	}
/////////////	END OF TFOX ADDED CODE FOR SMALL DDS DEVICES	///////////////////////////////


//////////////////////////////////////////////////////////////////////////////////////////////
//	SendToUSB - sends output_buffer[0-5] data back to host, if enabled (default disabled)	//
//////////////////////////////////////////////////////////////////////////////////////////////
void SendToUSB(void)
	{
	if(BD_state & USBresp)								// test to see if OK to send to USB
		{
		if(mUSBUSARTIsTxTrfReady())						// If the USB tranmsitter is ready
   			{
			mUSBUSARTTxRam((byte*)output_buffer,5); 	// send result back to host PC
			}
		}
	}

//////////////////////////////////////////////////////////////////////////////////////////
// TFOX_CODE added to set AT4611 attenuator IC											//
//	Sent with:																			//
//		byte[0] is attenuator value, six bits, right justified							//
//		byte[1] is reserved for future fixed attenuator control							//
//		byte[2] is reserved for future fixed attenuator control							//
//		byte[3] is 0x01 to poll only, otherwise sets attenuator to new level			//
//		byte[4] is the command, 0x7F, 127D 												//
//		sends most-significant-bit first (0x20) to attenuator							//
//	Returns:																			//
//		byte[0] is current attenuator value												//
//		byte[1] reserved for future fixed attenuator									//
//		byte[2] reserved for future fixed attenuator									//
//		byte[3] is 01 for poll-only, all others are command response					//
//		byte[4] is echo of attenuator command (0x7F)									//
//////////////////////////////////////////////////////////////////////////////////////////
void set_atten(void)
	{
	int i,j, atn;
	
	ATTEN_data = 0;							// initialize the attenuator data pin
	ATTEN_clk = 0;							// initialize the attenuator clock pin
	ATTEN_oe = 0;							// and init the attenuator out enable pin
	
	Atten = dds_cmd[0] & 0x3f;				// get and store the atten command
	atn = Atten;
	if(dds_cmd[3] != 1)						// if byte[3] = 1, only get current Atten level
		{									// otherwise, send the new level to attenuator
		for(i=0; i<6; i++)						// send the six atten control bits
			{
			j = atn & 0x20;						// strip all but the bit of interest
			if(j)
				ATTEN_data = 1;					//  if it was a one, set the data bit
			else
				ATTEN_data = 0;					// otherwise clear the data bit to zero
			wait_10_inst();						// delay a little
			ATTEN_clk = 1;						// toggle the clock pin (leading edge)
			wait_10_inst();						// delay a little
			ATTEN_clk = 0;						// and reset the clock pin
			atn <<= 1;							// shift to test the next bit
		} // send-a-bit for loop				// done sending six bits, now clock OE pin
		wait_10_inst();							// delay a little
		ATTEN_oe = 1;							// Now, toggle the output enable bit - up
		wait_10_inst();							// delay a little
		ATTEN_oe = 0;							// and set the oe pin down
		ATTEN_data = 0;							// make sure data pin is down
		}
	output_buffer[0] = Atten;					// get the attenuator value back
	output_buffer[1] = 0;						// clear out intermediate bytes
	output_buffer[2] = 0;						// clear out intermediate bytes
	output_buffer[3] = input_buffer[3];			// and show the attenuator request
	output_buffer[4] = 0x7F;					// put in the attenuator command byte
	SendToUSB();								// and send response to host, if enabled

} // end of set_atten

//////////////////////////////////////////////////////////////////////////////////////////
//	Board test is a simple communication test function for now.							//
//	It flips the status of both LEDs, and echoes back all five data bytes.				//
//////////////////////////////////////////////////////////////////////////////////////////
void Bdtest(void)
	{
	int i;
	mLED_1_Toggle();								// toggle LED 1 (yellow)
	mLED_2_Toggle();								// toggle LED 2 (red)

	for(i=0; i<5; i++)								// copy command back as response
		{
		output_buffer[i] = input_buffer[i];			// copy one byte
		}
	SendToUSB();
	}  // end of board test

//////////////////////////////////////////////////////////////////////////////////////////
//		BoardID().  Get the board id, which is stored at eeprom[0]						//
//		and return the values to the host												//
// 	input parameters do not matter, but complete command should be 0x00 bytes			//
// 	returns:																			//
//		byte[0] = Board ID from EEPROM													//
//		byte[1] = Software ID from EEPROM												//
//		byte[2] = Software major revision level from EEPROM								//
//		byte[3] = DDS ID from EEPROM													//
//		byte[4] = 0x00 (indicates BOARDID response)										//
//////////////////////////////////////////////////////////////////////////////////////////
void BoardId(void)
	{
	eepadr = 0;						// setup up to read first eeprom byte (board ID)
	eepromRD();						// get board ID byte
	output_buffer[0] = eepRdata;	// and save it in the output buffer
	eepadr++;						// now point to the software ID in EEPROM
	eepromRD();						// get the software ID
	output_buffer[1] = eepRdata;	// save it in the output buffer
	eepadr++;						// point to the software major revision in EEPROM
	eepromRD();						// get the SW major rev 
	output_buffer[2] = eepRdata;	// and store it in the output buffer
	eepadr = 0x06;					// finally, point to the DDS ID from EEPROM
	eepromRD();						// and get the DDS ID
	output_buffer[3] = eepRdata;	// store it in the output buffer
	output_buffer[4] = 0x00;		// indicate a BoardID response
	SendToUSB();
	}

//////////////////////////////////////////////////////////////////////////////////////////
// read or write a byte of data from/to the PIC EEPROM area								//
// called with:																			//
//		byte[0]		02 = write data, all other = read									//
//		byte[1]		adress of eeprom data byte to read/write (00-ff)					//
//		byte[2]		byte to write to EEPROM												//
//		byte[3]		ignored																//
//		byte[4]		rdwreeprom command byte												//
//	returns with:																		//
//		byte[0]		02 = write response, all others read response						//
//		byte[1]		address of EEPROM location to read or write							//
//		byte[2]		EEPROM read data (as verification in write command)					//
//		byte[3]		ingored in read, write: 00=verification failed, 01=verified OK		//
//		byte[4]		command echo back to host											//
//////////////////////////////////////////////////////////////////////////////////////////
void rdwreeprom(void)
	{
	output_buffer[0] = input_buffer[0];		// copy read/write flag to out bfr
	output_buffer[1] = input_buffer[1];		// copy address value to out bfr
	output_buffer[3] = 0x00;				// set third byte to 00
	output_buffer[4] = input_buffer[4];		// copy command to out bfr
	eepadr = input_buffer[1];				// set up eeprom address value

	if(input_buffer[0] == 2)				// if eeprom command is a write
		{									//  write an eeprom byte
		eepWdata = input_buffer[2];				// get the data to write
		eepromWR();								// call the internal write function
		eepromRD();								// read data back to verify
		if(eepRdata != eepWdata)				// if compare fails
			output_buffer[3] = 0x00;			// set failure flag
		else									// otherwise
			output_buffer[3] = 0x01;			// show good compare
		}
	else									// command was a eeprom read command
		{						
		eepromRD();								// call the internal eeprom read
		}
	output_buffer[2] = eepRdata;				// show the byte read back from eeprom
	SendToUSB();
	}

//////////////////////////////////////////////////////////////////////////////////////////
// eepromRd().  Used internally to read data from the EEPROM							//
// set eepadr variable to the address to read, then call								//
// returns with data in eepRdata variable;												//
//  to do: change this to return value directly...										//
//////////////////////////////////////////////////////////////////////////////////////////
void eepromRD(void)
	{
	EECON1bits.EEPGD = 0;
	EEADR = eepadr;							// get the eeprom address
	EECON1bits.RD = 1;						// set the READ flag
	eepRdata = EEDATA;						// get the resulting eeprom data
	}

//////////////////////////////////////////////////////////////////////////////////////////
// eepromWR().  Used internally to write data to the EEPROM								//
// set eepadr variable to the EEPROM address to write to								//
// and eepWdata to the data to write to the eeprom										//
//////////////////////////////////////////////////////////////////////////////////////////
void eepromWR(void)
	{
	if(EepromWrEn)
		{
		EECON1bits.EEPGD = 0;
		EECON1bits.WREN = 1;
		EEADR = eepadr;							// get address of the location to write to
		EEDATA = eepWdata;						// get data to write to eeprom
		if(Ints_on)								// if interrupts presently on
			INTCONbits.GIEH = 0;				// tun off all interrputs
		EECON2 = 0x55;							// no interrupts these three lines
		EECON2 = 0xAA;							//  write procedure
		EECON1bits.WR = 1;						//  show write ready
		while(!PIR2bits.EEIF)					// wait until eeprom write completed
			;
		if(Ints_on)								// check to see if interrupts were enabled
			INTCONbits.GIEH = 1;				// if so, re-enable interrupts again
		}
	}	// end of eepromWR

//////////////////////////////////////////////////////////////////////////////////////////////////
//  adInit().  A/D converter intitialization routine.											//
//	called with:																				//
//*********NEED TO IMPLEMENT	byte[0] = A/D channel to sample (WB6DHW board: AN4, pin RA5)	//
//	byte[1] = low half sample rate  (in 10mSec) 												//
//	byte[2] = high half sample rate  (in 10mSec)												//
//	byte[3] = A/D internal (0x01) or USB (0x02).  0x03 = send to both							//
//	byte[4] = A/D Converter initialize command (0XFE)											//
//////////////////////////////////////////////////////////////////////////////////////////////////
void adInit(void)
	{
	unsigned int	tempData = 0;							// temporary place to work on data
	adChannel = input_buffer[0];							// get channel to read fm input buffer
//  NEED TO ADD A/D CHANNEL SELECTION HERE
	tempData = (unsigned int)input_buffer[2];				// get the high-half sample frequency
	adSampleFreq = (tempData << 8) & 0xFF00;				// move to high part & strip low bits
	tempData = (unsigned int)(input_buffer[1] & 0x00FF);	// now get low-half sample rate
	adSampleFreq = adSampleFreq | tempData;					// add it to the high portion
	adDestination = input_buffer[3];						// get the A/D result destination flags
#ifdef	TFIOPINS
	OpenADC(ADC_FOSC_RC & ADC_8_TAD & ADC_RIGHT_JUST,		// startup ADC, AD clk src, justif, TAD
			ADC_CH0 & ADC_INT_OFF & ADC_VREFPLUS_VDD		// Channel, interrupts, volt config
			& ADC_VREFMINUS_VSS,
			0x0B);								// port configuration for AN4 (pin A5)
#endif
#ifndef	TFIOPINS
	OpenADC(ADC_FOSC_RC & ADC_8_TAD & ADC_RIGHT_JUST,		// startup ADC, AD clk src, justif, TAD
			ADC_CH4 & ADC_INT_OFF & ADC_VREFPLUS_VDD		// Channel, interrupts, volt config
			& ADC_VREFMINUS_VSS,
			0x0A);								// port configuration for AN4 (pin A5)
#endif
	output_buffer[0] = adChannel;						// now, return init values back via USB
	output_buffer[1] = (unsigned char)adSampleFreq & 0x00FF;		// send sample freq low byte
	output_buffer[2] = (unsigned char)(adSampleFreq >>8) & 0x00FF;	// sample freq high byte
	output_buffer[3] = adDestination;						// get the destiantion for A/D results
	output_buffer[4] = input_buffer[4];						// and finally copy the command back
	SendToUSB();
	}	// end of adInit

//////////////////////////////////////////////////////////////////////////////////////////////////
//	A/D converter command routine																//
//	called with:																				//
//	byte[0] = A/D subcommand				(00 = stop A/D, 01 = single A/D conversion, 		//
//											02-FE = # conv rqstd, FF=continuous samples @ rate)	//
//	byte[1] = A/D sample sequence number 	(0-0xFE), or 0xFF to continue with old sequence		//
//	byte[2] = A/D channel to sample (WB6DHW board: AN4, pin RA5)								//
//	byte[3] = A/D sample internal (0x01) or USB out (0x02). 0x03 = send to both					//
//	byte[4] = A/D converter command (0x7E)														//
//	returns																						//
//	byte[0] = A/D channel to sample																//
//	byte[1] = A/D sample sequence number														//
//	byte[2] = A/D return sample value, low byte													//
//	byte[3] = A/D return sample value, high byte												//
//	byte[4] = A/D converter comamnd byte (0X7E)													//
//////////////////////////////////////////////////////////////////////////////////////////////////
void adCommand(void)
	{
	adCmd = input_buffer[0];
	if(input_buffer[1] != 0xFF)
		adSampleSeq = input_buffer[1];
	adChannel = input_buffer[2];
	adDestination = input_buffer[3];
//************	NEED TO ADD CHANNEL SELECTION CODE HERE	************************************
 
	if(input_buffer[0] = 0)
		{
		CloseADC();
		adRunning = FALSE;
		adDelayCnt = 0;
		}
	else
		{
		adRunning = TRUE;
		adDelayCnt = adSampleFreq;
		ConvertADC();
		}
	}  // end of adCommand

//////////////////////////////////////////////////////////////////////////////////////////////////
//	0xFC	Transmit hardware initialization function											//
//	called with:																				//
//		Byte[0] = Tx enables/disables.  Same as eTXENABLE, TxEnables, and cmTXHENAB				//
//					00=disable all.0x01=enable Tx in pin,0x02=enable Tx out pin					//
//					0x04 = enable Tx time-out, 0x08 = enable Tx delay for Rx-> Tx				//
// 					0x10 = enable Tx delay for Tx-> Rx.  0xFF = get current status only			//
//		NOTE:  For now, Tx In Pin is fixed at RB4, Tx Out Pin is fixed at RB3.					//
//				Therefore, Byte[1], bits 0-1, 3, and 4-6 are NOT used at this time.				//
//		Byte[1] = Tx pins to use. Same as eTXHWPIN, TxHwPin, and cmTXHPINS						//
//					(future) Bits 0-1 = Tx IN pin to use, needs to be Port B, bits 7,6,5,or 4	//
//					Bit 2 is Tx In pin polarity. 0=Tx low (Rx=H, Tx=L), 1=Tx high (Rx=L, Tx=H)	//
//					(future) Bits 3 is Tx Out pin PORT to use.  0=PortB, 1=PortC.				//
//					(future) Bits 4-6 is Tx Out pin to use.  Binary coded, bits 0-7 allowed		//
//					Bit 7 is Tx Out pin polarity. 0=Tx low (Rx=H, Tx=L), 1=Tx high (Rx=L, Tx=H)	//
//		Byte[2] = Tx timeout value, in 10 second(!) intervals 0-0xFF = 0-42 minutes				//
//		Byte[3] = Tx on & off delay in 10msec intervals											//
//		Byte[4] = Tx init command (0xFC)														//
//	RETURNS WITH:																				//
//		Byte[0] = Tx hardware enable/disable status return(bit 5 set if status request response)//
//		Byte[1] = Tx pins used (TxInPin, plus 0x02=InPolH, 01=InPol=L, 40=OutPol=H,20=OutPol=L)	//
//		Byte[2] = Tx timeout.  NOTE:  00= OK, 01-0xFE = amount, 0xFF = timed out flag			//
//		Byte[3] = Tx on & off delay amount in 10msec											//
//		Byte[4] = Tx init command echo (0xFC)													//
//////////////////////////////////////////////////////////////////////////////////////////////////
void Tx_init(void)
	{
	unsigned char TxPinWork;

	if(input_buffer[0] == 0xFF)							// If status rqst, just update parameters
		output_buffer[0] |= cmTXHSTRTN;					// set flag to show Status response
	else												// not status update, parse the command
		{
		if(input_buffer[0] == 0)							// if first byte is a zero,
			{												// turn off the transmit hardware
			TxEnables = 0;									// show all transmit stuff turned off
			txinpinoff();									// shut off Tx input interrupts
			}
		else												// Not status rqst or turn-off command
			{													// must be turn ON Tx In Pin
			TxHwPin = input_buffer[1];							// save Transmit in & out pin info
			TxEnables = input_buffer[0];						// Store transmit enable flags
			if(TxEnables & cmTXHINON)							// is Tx In pin being enabled?
				{												// yes, set up Tx In pin hardware
				TxInPin = TX_INP;								// Set Tx In Pin to RB4 for now
				if(TxHwPin /*TxPinStore*/ & cmTXHINPOL)			// get Tx In pin polarity flag
					TxInPol = 1;								// and set polarity high if 1
				else											// otherwise polarity must be low
					TxInPol = 0;								// so set it low
// add test to allow hardware Tx
				txinpinon();									// and turn on Tx In Pin
				}	// end of TxIn pin actual setup
			else												// TxIn pin disabled, turn off pins
				{
				TxInPin = 0;									// turn off any Tx in pins
				TxInPol = 0;									// and reset polarity
				txinpinoff();
				}	// end of Tx In pin setup test
			if(TxEnables & cmTXHOUTON)							// now test for Tx Out pin enabled
				{
				TxOutPin = TX_OUTP;								// set the Tx Out Pin = RB3 for now
				if(TxHwPin /*TxPinStore*/ & cmTXHOPOL)			// get Tx Out pin polarity flag
					TxOutPol = 1;								// and set polarity high if 1
				else											// otherwise polarity must be low
					TxOutPol = 0;								// so set it low
				}	// end of Tx out pin enable setup
			else												// TxOut pin disabled, turn off pins
				{
				TxOutPin = 0;									// turn off any Tx out pins
				TxOutPol = 0;									// and reset polarity
				}	// end of Tx out pin not enabled
														// here once Tx in&out pins have been set up
			TxTimeout = input_buffer[2];						// get the transmit timeout value
			TxDelay = input_buffer[3];							// get the transmit delay amount
			}
		}	// end of buffer[0] not FF

// the following is to read back status
												// read back the various Tx hardware parameters
	output_buffer[0] = TxEnables;						// show the enables in response
	output_buffer[1] = TxHwPin;							// get the assigned transmit in&out pin
// following lines temporary for debugging
	if(TxInPol == 1)
		output_buffer[1] |= 0x02;
	else
		output_buffer[1] |= 0x01;
	if(TxOutPol == 1)
		output_buffer[1] |= 0x40;
	else
		output_buffer[1] |= 0x20;
	output_buffer[2] = TxTimeout;						// get the transmit timeout value/status
	output_buffer[3] = TxDelay;							// get the transmit on/off delay amount
	output_buffer[4] = input_buffer[4];					// and get the command to echo back
	SendToUSB();
	}	// end of Tx init function
 
//////////////////////////////////////////////////////////////////////////////////////////////////
//	BoardID	0xFD	Initialize the board parameters as if we just powered it up.				//
//	called with:																				//
//		byte[0]:	bit 7 =USB response on/off, bit 6 =LED heartbeat on/off, bit 5 =always off	//
//					bit 4 =Tx pins enable on/off, bit 3 =always off, bit 0 =EEPROM write enable	//
//		byte[1]:																				//
//		byte[2]:																				//
//		byte[3]:																				//
// 		byte[4]:	Board initialize command (0xFD)												//
//	returns with:																				//
//		byte[0] = BD_state byte																	//
//		byte[1]																					//
//		byte[2]																					//
//		Byte[3]																					//
//		byte[4] = Echo of board initialize command												//
//////////////////////////////////////////////////////////////////////////////////////////////////
void BoardInit(void)
 	{
	unsigned char work;

	work = input_buffer[0];
	eepadr = eBDSTATE;							// get the board state from the EEPROM
	eepromRD();											// read board state in
	if(eepRdata == eEMPTY)								// if the BD_state is not initialized
		BD_state = eNULL;								// zero out the Board state
	else												// if old data was there
		BD_state = eepRdata;							// store the current board state

//////////////////  Add test for bits 5 or 3 set in received byte[0].  If either set,
//////////////////	ignore updates to board state.  command is to update another storage
	
	if(work & eUSBRESP)								// should we enable USB return data?
		BD_state |= eUSBRESP;							// yes, enable USB return frames
	else												// otherwise...
		BD_state &= ~eUSBRESP;							// turn off USB return frames (0x7F)
	if(work & eLEDHEART)								// see if LED heartbeat should be enabled
		{												// yes, turn on LED heartbeat
		BD_state |= eLEDHEART;							// Save the enabled state in board status
		LED_heartbeat = TRUE;							// turn on LED heartbeats
		}
	else												// otherwise, turn LED heartbeat off
		{
		BD_state &= ~eLEDHEART;							// clear the LED heartbeat flag (0xBF)
		LED_heartbeat = FALSE;							// disable LED heartbeats
		mLED_2_Off();									// turn off the LED
		}
	if(work & eTXPINSON)								// test for Tx pins enabled
		{
		BD_state |= eTXPINSON;							// show the Tx pins are enabled
		if(TxEnables & eTXINPON)						// test to see if Tx In pin is enabled
			txinpinon();								// if so, turn ON Tx In Pin
		}
	else												// command was to turn off Tx pins
		{
		BD_state &= ~eTXPINSON;							// show the Tx pins are disabled (0xEF)
		txinpinoff();									// now go turn transmit IN pin off
		}
	if(work & eEPRMWREN)								// see if EEPROM write should be enabled
		{
		BD_state |= eEPRMWREN;							// if so, save state in Board state
		EepromWrEn = TRUE;								// and show writes are OK
		}
	else												// Otherwise....
		{
		BD_state &= ~eEPRMWREN;							// clear the write enable in bd state
		EepromWrEn = FALSE;								// and turn off eeprom writes
		}
	BD_state &= eBDSVALID;								// make sure bits 5 & 3 are always 0
	eepadr = eBDSTATE;									// point to eeprom adr for Board status
	eepromWR();											// store new init state in EEPROM

	output_buffer[0] = BD_state;						// return current Board State
	output_buffer[1] = eepRdata;						// and return EEPROM eBDSTATE
	output_buffer[2] = 0;								// rest is zero
	output_buffer[3] = 0;								// rest is zero
	output_buffer[4] = input_buffer[4];					// echo back Board Init command
	SendToUSB();										// and send to USB
	}	// end of BoardInit function

//////////////////////////////////////////////////////////////////////////////////////////
//		Internal routine to turn on Tx In Pin											//
//////////////////////////////////////////////////////////////////////////////////////////
void txinpinon(void)
	{
	TRISB |= 0x10; //TxInPin;							// Set up Tx in pin as input
	OpenPORTB(PORTB_CHANGE_INT_ON & PORTB_PULLUPS_ON);	// set up Tx input Port B
	INTCONbits.RBIE = 1;								// turn on RB port change int enable
	INTCON2bits.RBIP = 0;								// and make it a low priority
	}

//////////////////////////////////////////////////////////////////////////////////////////
//		Internal routine to turn off Tx In Pin											//
//////////////////////////////////////////////////////////////////////////////////////////
void txinpinoff(void)
	{
	TRISB &= 0x00; //~TxInPin;							// disable Tx In pin on port B
	INTCONbits.RBIE = 0;								// turn off RB port change int enable
	INTCONbits.RBIF = 0;								// turn off RB interrupt flag
	ClosePORTB();										// and close port B for now
	}

///////////////////////////////////////////////////////////////////////////////////////////////
//		Tx_on_off command.  Turns on or off the transmitter - if enabled					///
//		Called with:	Byte[0] = 0xAA and Byte[1] = 0x55 to turn transmitter ON			///
//						All other combinations turns the transmitter OFF					///
///////////////////////////////////////////////////////////////////////////////////////////////
void Tx_on_off(void)
	{
	if(BD_state & eTXPINSON && TxEnables & eTXUSBOK)	// Check for Tx Pins on & USB enabled
		{
		if(input_buffer[0] == cmTXONB0 && input_buffer[1] == cmTXONB1)	// verify TX command
			Transmit_ON();												// turn Transmitter ON
		else															// otherwise...
			Transmit_OFF();												// Turn Transmitter OFF
		}
	else
		{												// Oops, USB transmit not allowed
		send_data(0x03, input_buffer[4], cmTXCMBAD);	// response shows CANNOT transmit
														// with an FF-00-00-00-?? response
		}
	}

//////////////////////////////////////////////////////////////////////////////////////////////
//		Internal routing to turn transmitter ON												//
//////////////////////////////////////////////////////////////////////////////////////////////
void Transmit_ON(void)
	{
	Transmitting = TRUE;
	if(TxEnables & eTXOUTPN)
		{
		if(TxOutPol == 1)						// and if output polarization active-high
			TX_OUT = 1;							// Transmitting, active high.  Pin = high
		else									// otherwise, polarization is active-low
			TX_OUT = 0;							// Transmitting, active low.  Pin = low
		}	// end of TxEnables & Tx Out Pin
/////////	ADD CHANGE TO TRANSMIT FREQUENCY HERE
	send_data(0x03, input_buffer[4], 0x55);		// Response shows transmit ON (55-00-00-00-??)

	}

//////////////////////////////////////////////////////////////////////////////////////////////
//		Internal routing to turn transmitter OFF											//
//////////////////////////////////////////////////////////////////////////////////////////////
void Transmit_OFF(void)
	{
	Transmitting = FALSE;


	if(TxEnables & eTXOUTPN)
		{
		if(TxOutPol == 1)						// if the polarity is active-high
			TX_OUT = 0;							// NOT transmitting, active high. Pin = low
		else									// otherwise, pin is active-low
			TX_OUT = 1;							// NOT transmitting, active low. Pin = high
		}	// end of TxEnables & Tx Out Pin
/////////	ADD CHANGE TO RECEIVE FREQUENCY HERE
	send_data(0x03, input_buffer[4], 0);		// show transmit OFF (00-00-00-00-??)
	}

///////////////////////////////////////////////////////////////////////////////////////////////
////	filter_set command.  Sets an external LP or BP filter, baased on USB command		///
///////////////////////////////////////////////////////////////////////////////////////////////
void filter_set(void)
	{
	unsigned char filter = 0;

	if(dds_cmd[1] == cmDHWBPFLTR)					// if David Brainerd BP filter board
		{
		PORTB &= 0xF8;									// clear out the old filter data
		filter = dds_cmd[0] & FLTR_MSK;				// clear all but low three bits of fltr 
		FilterBand = filter;							// and save present filter value
		PORTB |= filter;								// set any bits high from filter request
												// save filter change to EEPROM?? not for now.
		output_buffer[0] = filter;						// now return Filter band information
		output_buffer[1] = dds_cmd[1];					// and return filter ID
		output_buffer[2] = 0;							// set rest of response to zero
		output_buffer[3] = 0;							// set rest of response to zero
		output_buffer[4] = cmSETFLTR;					// sho filter set command byte
		SendToUSB();									// send response back via USB
		}
	}

//////////////////////////////////////////////////////////////////////////////////////////////////
////	set_freq command.  Sends the actual frequency of interest, the PIC calculates the FTW	//
////	0x79				This function sets the DDS frequency based on the CURRENT 1Hz value	//
////						It is called with the 32-bit binary requested frequency in dds_cmd	// 
////						This function DOES NOT RECALCULATE THE 1HZ value					//
//////////////////////////////////////////////////////////////////////////////////////////////////
void set_freq(void)
	{
	int frOK = 1;
	int temp;
	unsigned long work;

	get_data();										// get the frequency parameter from host
	freq_work = freq_work & 0x0FFFFFFF;				// strip off subcommand from requested freq
											////////////  add frequency bounds checking HERE
	frOK = 0x01;									// set Freq was OK flag for now
	dds_display = freq_work;						// copy the frequency into DDS Display
	ftw_calc();										// calculate and send the FTW to the DDS
	freq_work = dds_ftw;							// get the FTW to send back to the host

	if(frOK == 1)									// check the frequency OK flag
		temp = 0x80;									// if freq was OK, set the return flag
	else												// otherwise...
		temp = 0;										// don't send the OK flag
	send_data(0x02, 0x79, temp);					// send the response to the host
	}

//////////////////////////////////////////////////////////////////////////////////////////////////
////	u64divide().  Divides a 64-bit number (u1, u0) by 32-bit divisor (v).					//
////					Q holds the 32-bit quotient (q1, q0 are 16-bit), rhat holds remainder.	//
////					NOTE:  un32 calculation (-s >> 31) doesn't calculate at 0xFFFFFFFF		//
//////////////////////////////////////////////////////////////////////////////////////////////////
void u64divide(void)
	{
	const unsigned long b1 = 65536;						// indicate 16-bit operations
	int s;												// shift amount for normalization
	// unsigned long vn1, vn0;								// divisor two 16-bit word storage

	r = 1;											// force remainder delivery for now
	if(u1 >= v)											// test for potential overflow situation
		{												// here if overflow will happen
		q1 = 0xFFFFFFFF;								// show an overflow condition
		q0 = 0xFFFFFFFF;								// by setting quotient bytes to all ones
		if(r != NULL)									// check to see if remainder requested
			r = 0xFFFFFFFF;								// set remainder to all FF, not normal
		}
	else												// here if not overflow,start calculating
		{
		s = nlz(v);											// 0 <= s <= 31
		v = v << s;											// normalize the divisor itself
		vn1 = v >> 16;										// break divisor into two 16-bit
		vn0 = v & 0xFFFF;									// digits to set up calculations

		//un32a = u1 << s;
		//un32b = u0 >> 32 - s;
		//un32c = (-s) >> 31;
		un32 = (u1 << s) | (u0 >> 32 - s); // & (-s >> 31);	// not sure why the -s doesn't work
		un10 = u0 << s;										// shift dividend left

		un1 = un10 >> 16;									// break right-half of dividend into
		un0 = un10 & 0xFFFF;								// two digits for calculations

		q1 = un32 / vn1;									// compute the first quotient digit
		//q1g = q1;
		rhat = un32 - (q1 * vn1);								// q1, and remainder
		//rhat1g = rhat;
		again1:
		if(q1 >= b1 || q1 * vn0 > b1 * rhat + un1)
			{
			q1 = q1 -1;
			rhat = rhat + vn1;
			if(rhat < b1) goto again1;
			}
		un21 = (un32 * b1 + un1 - q1 * v);					// multiply and subtract

		q0 = un21 / vn1;									// computer the second digit, q0
		//q0g = q0;
		rhat = un21 - (q0 * vn1);								// and remainder
		//rhat0g = rhat;
		again2:
		if(q0 >= b1 || q0 * vn0 > b1 * rhat + un0)
			{
			q0 = q0 - 1;
			rhat = rhat + vn1;
			if(rhat < b1) goto again2;
			}
		if(r != 0x00)										// if the remainder was requested
			r = (q1 * b1) + q0;								// set up the remainder
		}
	q = 0;													// build up the 32-bit quotient
	q = q1 << 16;											// move the high 16-bit portion
	q = q & 0xFFFF0000;										// and clear out any garbage
	q = q | (q0 & 0xFFFF);									// add in the low 16-bit portion
	
	}

//////////////////////////////////////////////////////////////////////////////////////////////////
////	nlz(unsigned long).		Used by 64-bit divide routing to normalize the divisor			//
//////////////////////////////////////////////////////////////////////////////////////////////////
int nlz(unsigned long x)
	{
	int n;
	if(x == 0)
		return(32);
	n = 0;
	if(x <= 0x0000FFFF) {n = n + 16; x = x << 16;}
	if(x <= 0x00FFFFFF) {n = n + 8; x = x << 8;}
	if(x <= 0x0FFFFFFF) {n = n + 4; x = x << 4;}
	if(x <= 0x3FFFFFFF) {n = n + 2; x = x << 2;}
	if(x <= 0x7FFFFFFF) { n = n +1;}
	return n;
	}

//////////////////////////////////////////////////////////////////////////////////////////////////
////	u32mult().		Multiplies two 32-bit unsigned numbers, with a 64-bit result			//
////						Input: 
////						Output:
//////////////////////////////////////////////////////////////////////////////////////////////////
void u32mult(void)
	{
	unsigned long HI, LO, x, y;								// work space for HI and LO results
	unsigned long a, b, c, d;
	a = (vn1 >> 16) & 0xFFFF;								// put high-half multiplicand into a
	b = vn1 & 0xFFFF;										// put low-half multiplicand into b
	c = (vn0 >> 16) & 0xFFFF;								// put high-half multiplier into c
	d = vn0 & 0xFFFF;										// and low-half multiplier into d

	LO = b * d;
	x = a * d + c * b;
	y = ((LO >> 16) & 0xFFFF) + x;
	LO = (LO & 0xFFFF) | ((y & 0xFFFF) << 16);
	HI = (y >> 16) & 0xFFFF;
	HI += a * c;
	u1 = HI;									// need to put HI and LO into two 32-bit variables
	u0 = LO;									// //
	}

//////////////////////////////////////////////////////////////////////////////////////////////////
////	OscSet().		Sets Master Oscillator frequency from input buffer						//
////	0xFA			input_buffer[0] is MSB, buffer[3] is LSB								//
////				Since the OSC has changed, force a recompute of all stuff, including FTW	//
//////////////////////////////////////////////////////////////////////////////////////////////////
void OscSet(void)
	{
//	int temp, dlylp;
//	unsigned char workb;								// some temporary work storage
//	unsigned long work;

	get_data();											// get the new osc parameter in freq_work
	osc_freq = freq_work;								// save master OSC value into temporary
	eepWR4(eMASOSC0, &osc_freq);						// SAVE the new master freq to EEPROM
	freq_update();									////  UPDATE the DDS and all else
	freq_work = osc_freq;								// get the osc freq to return to host
	send_data(0x02, dds_cmd[4], 0);						// send result back to host
	}

//////////////////////////////////////////////////////////////////////////////////////////////////
////	PllMult command.  	Sets DDS PLL and DDS output multiplier from host					//
////	0xFB				called with:	byte[0] is DDS PLL value, 							//
////										byte[1] is DDS frequency output multiplier			//
////					Since this has changed, force a recompute of all stuff, including FTW	//
//////////////////////////////////////////////////////////////////////////////////////////////////
void PllMult(void)
	{
	dds_pll = input_buffer[0] & 0x1F;					// read in the new DDS PLL value
	freq_mult = input_buffer[1] & 0x07;					// read in the new VFO multiplier
													//// SAVE NEW PLL/MULT TO EEPROM
	eepWdata = freq_mult << 5;							// move the multiplier to bits 7-5
	eepWdata &= 0xE0;									// strip off all but mult bits
	eepWdata |= dds_pll;								// OR in the DDS PLL value
	eepadr = eDDSMULT;									// point to the EEPROM PLL & Mult storage
	eepromWR();											// and write the byte to EEPROM

	freq_update();									//// UPDATE the DDS and all else
														// Return response back to host computer
	output_buffer[3] = dds_pll;							// return the new DDS PLL value
	output_buffer[2] = freq_mult;						// return the new VFO multiplier value
	output_buffer[1] = 0xAA;							// not sure why I did this... fun?
	output_buffer[0] = 0x55;							// or this, it's something to send...
	output_buffer[4] = input_buffer[4];					// and copy the command byte back
	SendToUSB();										// send response back as verification
	}

//////////////////////////////////////////////////////////////////////////////////////////////////
////	freq_update().			Updates all the frequency-dependent information at once			//
////							Use this whenever a significant value changes that will			//
////	Internal				make the 1Hz number invalid.  this function recalculate the 	//
////							1Hz number first, then updates the DDS FTW						//
//////////////////////////////////////////////////////////////////////////////////////////////////
void freq_update(void)
	{
	int temp;
//	unsigned int fltr;
//	unsigned int temp2;
//	unsigned long work;
//	static unsigned int rom *r_ptr;					// pointer to ROM filter table
													////// start wth the one-time calculations
	dds_clock = osc_freq * dds_pll;						// calculate the DDS DAC clock (OSC*PLL)
	if(DDS32)											// if the current DDS chip uses 32-bit FTW
		{
		u1 = M32SHFTH;									// get the shifted 32-bit max frequency
		u0 = M32SHFTL;									// and the low-half shifted 32-bit max
		}
	else												// otherwise the current DDS uses 28-bit
		{
		u1 = M28SHFTH;									// get the shifted 32-bit max frequency
		u0 = M28SHFTL;									// and the low-half shifted 32-bit max
		}
	v = dds_clock;										// now, set up the divisor
	u64divide();										// divide the max 32-bit shifted by DDS
	freq_1Hz = q;										// and set up the result (quotient)
													////// SAVE new freq_1Hz to EEPROM
//	work = freq_1Hz;									// save 1Hz value into temporary
	eepWR4(eREFOSC0, &freq_1Hz);							// SAVE new fewq_1Hz into EEPROM
//	eepadr = eREFOSC0;									// point to the EEPROM REF OSC MSB
//	for(temp = 0; temp < 4; temp++)						// writefour bytes to EEPROM
//		{
//		eepWdata = work & 0xFF;							// get data to write to eeprom
//		eepromWR();										// and write the byte
//		work >>= 8;										// now shift that 8-bits left
//		eepadr += 1;									// move to next eeprom write location
//		}												// end of EEPROM save
	ftw_calc();											// calculate and send FTW to DDS
	}

//////////////////////////////////////////////////////////////////////////////////////////////////
////	ftw_calc().		INTERNAL		Calculates DDS FTW, and sends it to the DDS				//
////									before calling, dds_display should have frequency		//
////////////////////////////////////////////////////////////////////////////////////////////////// 
void ftw_calc(void)
	{
	int temp;
	unsigned long work;

	temp = Ofs_mode & eOFSRMSK;						// strip all but receive offset mask
	if(temp != 0x00)								// if there is a receive offset
		{
		switch (temp)									// detremine offset calculation mode
			{
			case eOFSMDPO:								// if mode is display PLUS offset
				//if(dds_display > RxOffsetFreq)		// only if display is larger than offset
				dds_display = dds_display + RxOffsetFreq;// Add the DDS display and Rx Offset
				break;
			case eOFSMDMO:								// if mode is display MINUS offset
				if(dds_display > RxOffsetFreq)			// only if display is larger than offset
					dds_display = dds_display - RxOffsetFreq; // subtract Rx offset from display
				break;
			case eOFSMOMD:								// if mode is Rx Offset MINUS display
				if(RxOffsetFreq > dds_display)			// only if display is larger than offset
					dds_display = RxOffsetFreq - dds_display; // subtract display from Rx offset
				break;
			default:									// if none of the above...
				dds_display = dds_display;				// do nothing for now
			}	// end of switch
		}	// end of Rx Offset test

	dds_out = dds_display * freq_mult;					// calculate the actual DDS out freq.
													////// multiply the 1Hz FTW by wanted freq
	vn1 = dds_out;										// set the DDS outut frequency
	vn0 = freq_1Hz;										// and set the calculated 1Hz FTW
	u32mult();											// go multiply the two 32-bit values
	dds_ftw = (u1 << 8);								// now, combine results for new FTW
	dds_ftw = dds_ftw & 0xFFFFFF00;						// strip off lowest bits
	dds_ftw = dds_ftw | (u0 >> 24) & 0xFF;				// and add low byte to the rest
////////////////	ADD SAVE TO EEPROM??  probably not???
													///// NEXT - SEND FTW to the RIGHT DDS CHIP
	if(DDSdevice != eDDSNONE)							// Don't send to DDS if none is defined
		{												// otherwise, update the DDS chip
		work = dds_ftw;									// copy the FTW into a working location
		for(temp = 3; temp >= 0; temp--)				// copy four bytes
			{
			dds_cmd[temp] = (unsigned)(work & 0xFF);	// copy the lowest eight bits
			work = work >> 8;							// and shift to the next eight bits
			}
		DDS_parse();									// send FTW to the DDS chip
		}
	if(FilterType == eFLTRDHW)							// If Brainerd band pass filter
		Set_DHWbpf();									// update the bandpass filter hardware

	}

//////////////////////////////////////////////////////////////////////////////////////////////////
////	Set_DHWbpf().	Internal, Sets WB6DHW band-pass filter, based on DDS Display frequency	//
//////////////////////////////////////////////////////////////////////////////////////////////////
void Set_DHWbpf(void)
	{
	unsigned int f_start, f_stop;					// current filter start and stop freqs
	unsigned int freq16, f_ptr;
	unsigned char fltr, allpass;					// storage for correct filter and all-pass
	unsigned char temp, temp2;				// change this to unsigned int for old code
	static unsigned int rom *r_ptr;					// pointer to ROM filter table

	fltr = 0xFF;									// show filter at no filter to start
	allpass = DEFAULT_ALLPASS;						// set allpass filter to default
	f_ptr = 0;										// start with filter table pointer at zero
	r_ptr = bpf_DHW_array;							// point to ROM filter table base
	freq16 = (unsigned int)(dds_display >> 12);		// get 16-bit version of current frequency
	temp = r_ptr[0];							// get the total number of filters in table
	f_ptr = 1;
	for(temp2 = 0; temp2 < temp; temp2++)			// loop through all filters looking for
		{												// correct filter, and all-pass
		f_start = r_ptr[f_ptr++];					// get the next filter's start frequency
		f_stop = r_ptr[f_ptr++];					// get the next fitler's stop frequency
		if(f_start == 0 && f_stop == 0xFFFF)		// test this filter for all-pass filter
			allpass = temp2;							// save this filter as all-pass
		if(f_start <= freq16 && freq16 <= f_stop)	// if the filter is the correct one
			{											// save the filter's parameters
			if(temp2 != allpass)					// first, test to see if it's an all-pass
				{										// if not an all-pass filter
				BPF_start = f_start;						// save the start frequency
				BPF_stop = f_stop;							// save the stop frequency
				fltr = temp2;								// save the filter
				}
			}
		}
	if(fltr == 0xFF)								// if a good filter was not found
		fltr = allpass;								// set filter to all-pass instead
	if(fltr != FilterBand)							// if the new filter isn't the existing flter
		{											// update the filter band on the BPF
		dds_cmd[0] = fltr;							// save the new selected filter band
		dds_cmd[1] = cmDHWBPFLTR;					// show we are adjusting the Brainerd BPF
		filter_set();								// go change the filter hardware
		}
	}

//////////////////////////////////////////////////////////////////////////////////////////////////
////	Osc_cal().		command to calibrate the master oscillator frequency					//
////	0x7A			This is called with the following parameters:							//
//////////////////////////////////////////////////////////////////////////////////////////////////
void Osc_cal(void)
	{
	unsigned char cal_cmd;							// storage for received command
//	unsigned char temp;								// temporary storage variable
//	unsigned long work;								// temporary storage variable

	cal_cmd = dds_cmd[cmOSCSCMD];					// copy the command byte to local storage
	cal_cmd &= cmOSCSMSK;							// strip all but the subcommand data
	cal_VFOM = 0x01;
	switch(cal_cmd)
		{
		case cmOSCALRD:								// Osc subcommand to read-back/ignore data
			freq_work = osc_freq;						// get the current master osc freq value
			send_data(0x02, dds_cmd[4], cal_cmd);		// send osc_freq back to host
			break;
		case cmOSCAL10:								// Start calibrate sequence at 10MHz
			if(!Calmode)								// only do if not already in cal mode
				{										// note: this starts with existing osc
				Calmode = TRUE;						// show we are now in calibrate mode
				old_mosc = osc_freq;				// save the original master osc value
				old_freq = dds_display;				// save the present DDS operating freq
				dds_display = VFO_C;				// set the frequency to Calibrate (10MHz)
				old_fmult = freq_mult;				// save the VFO multiplier (freq_mult)
				if((dds_cmd[0] & cmOSCALYM) != 0x80)// if the USE VFO multiplier flag cleared
					freq_mult = 0x01;					// set up calibrate VFO mult to X1
				freq_update();						// calculate and send new FTW
													// send 10MHz (00 98 96 80 hex) back
				freq_work = VFO_C;					// set freq_work to Calibrate freq (10MHz?)
				send_data(0x02, dds_cmd[4], cal_cmd);	// and send it back to the host
				}
			else									// oops, already in calibrate mode
				{										// don't do anything except send error
				send_data(0x04, dds_cmd[4], 0);			// send an error message back
				}
			break;
		case cmOSCALAD:								// Add cmd bytes[0]-[3] to present osc work
			if(Calmode)									// make sure we are in calibrate mode
				{
				get_data();							// get the amount to add to master osc
				freq_work = freq_work & 0x0FFFFFFF;		// strip off subcmd data from freq to add
				osc_freq = osc_freq + freq_work;	// add requested amount to master osc freq
				freq_update();						// go recalculate and send new FTW to DDS
				freq_work = osc_freq;				// send the new osc value back to host
				send_data(0x02, dds_cmd[4],0); 		// but, do not include the subcommand
				}
			else									// oops, not in calibrate mode - just send error
				{										// don't do anything except send error
				send_data(0x04, dds_cmd[4], 0);			// send an error message back
				}
			break;
		case cmOSCALSB:								// Subtract cmd [0]-[3] to present osc work
			if(Calmode)									// make sure we are in calibrate mode
				{
				get_data();							// read in amount to subtract from amster osc
				freq_work = freq_work & 0x0FFFFFFF;		// strip off subcmd data from freq to sub
				osc_freq = osc_freq - freq_work;	// subtract requested amount to master osc
				freq_update();						// go recalculate and send new FTW to DDS
				freq_work = osc_freq;				// send the new osc value back to host
				send_data(0x02, dds_cmd[4],0); 		// but, do not include the subcommand
				}
			else									// oops, not in calibrate mode - just send error
				{										// don't do anything except send error
				send_data(0x04, dds_cmd[4], 0);			// send an error message back
				}
			break;
		case cmOSCALWR:								// calibrate complete,write new master osc
			if(Calmode)									// make sure we are in the calibrate mode
				{
				Calmode = FALSE;						// turn OFF calibrate mode flag
				dds_display = old_freq;					// recover old dds diaplay frequency
				freq_mult = old_fmult;					// recover old VFO multiplier
				old_mosc = osc_freq;				// save the new master osc to EEPROM
				eepWR4(eMASOSC0, &old_mosc);			// SAVE the new Master Osc to EEPROM
//				eepadr = eMASOSC0;						// point to the EEPROM MASTER OSC MSB
//				for(temp = 0; temp < 4; temp++)			// write four bytes to EEPROM
//					{
//					eepWdata = old_mosc & 0xFF;			// get data to write to eeprom
//					eepromWR();							// and write the byte
//					old_mosc >>= 8;						// now shift that 8-bits left
//					eepadr += 1;						// move to next eeprom write location
//					}									// end of EEPROM save
				freq_update();						// update everything based on new osc
														// send back osc freq to host
				freq_work = osc_freq;					// get current master osc freq value
				send_data(0x02, dds_cmd[4], cal_cmd);		// and send it back to host
				}
			else									// oops, not in calibrate mode - just send error
				{										// don't do anything except send error
				send_data(0x04, dds_cmd[4], 0);			// send an error message back
				}
			break;
		case cmOSCALDI:								// calibrate complete,discard new master osc
			if(Calmode)								// only do the following if in calibrate mode
				{
				Calmode = FALSE;						// turn OFF calibrate mode flag
				osc_freq = old_mosc;					// recover old master oscillator freq
				dds_display = old_freq;					// recover old dds display frequency
				freq_mult = old_fmult;					// recover old VFO multiplier
				freq_update();							// and finally recalculate based on old
														// send back osc freq to host
				freq_work = osc_freq;						// get current master osc freq value
				send_data(0x02, dds_cmd[4], cal_cmd);		// and send it back to host
				}
			else									// oops, not in calibrate mode, just send error
				{
				send_data(0x04, dds_cmd[4], 0);
				}
			break;
		case cmOSCALFR:								// Start calibrate mode, using requested freq
			if(!Calmode)								// only do if not already in cal mode
				{										// note: this starts with existing osc
				Calmode = TRUE;							// show we are now in calibrate mode
				old_mosc = osc_freq;					// save the original master osc value
				old_freq = dds_display;					// save the present DDS operating freq
				get_data();							// get the requested calibrate frequency
				freq_work = freq_work & 0x0FFFFFFF;		// strip off subcmd data from freq to add
				dds_display = freq_work;			// set the display frequency to requested
				old_fmult = freq_mult;					// save the VFO multiplier (freq_mult)
				if((dds_cmd[0] & cmOSCALYM) != 0x80)	// if the USE VFO multiplier flag cleared
					freq_mult = 0x01;						// set up calibrate VFO mult to X1
				freq_update();							// calculate and send new FTW
				freq_work = dds_display;				// send rqstd frequency back to host
				send_data(0x02, dds_cmd[4], 0);			// send the command back to the host
				}
			else									// oops, already in calibrate mode
				{										// don't do anything except send error
				send_data(0x04, dds_cmd[4], 0);			// send an error back to the host
				}
			break;
		default:
			send_data(0x01, dds_cmd[4], 0);				// send the command back to the host
		}
	}

//////////////////////////////////////////////////////////////////////////////////////////////////
////	show_param().	 Gets various frequencies and other info from PIC and sends to host		//
////	0x78																					//
//  1:  unsigned long	osc_freq;			// oscillator frequency (actual osc before PLL)		//
//	2:  unsigned long	dds_clock;			// DDS clock input results frequency (after PLL)	//
//  3:  unsigned long	dds_out;			// DDS output frequency (display * freq_mult)		//
//  4:  unsigned long	dds_display;		// DDS display freq (wanted freq, before freq mult) //
//  5:  unsigned long	dds_ftw;			// value to send to the DDS for frequency output	//
//  6:  unsigned long	freq_work;			// intermediate work storage						//
//  7:  unsigned long	max_freq;			// maximum frequency								//
//  8:  unsigned long	DDSdevice, dds_pll, freq_mult											//
//  9:  unsigned long	freq_1Hz;			// calculated 1Hz 32-bit integer 					//
//  A:	unsigned long	RxOffestFreq;		// receive offset frequency value					//
//  B:  unsigned long	TxOffsetFreq;		// Transmit offset frequency						//
//  C:  unsigned long	VFO_A				// read VFO A frequency								//
//  D:	unsigned long	VFO_B				// read VFO B frequency								//
// 10:	unsigned ints	BPF_start & BPF_stop													//
//////////////////////////////////////////////////////////////////////////////////////////////////
void show_param(void)
	{
	unsigned long freq_to_show = 0;					// work variable for display
	static unsigned int rom *src;

	switch(input_buffer[0])
		{
		case cmGET_MOSC:
			freq_to_show = osc_freq;				// master oscillator frequency
			break;
		case cmGET_DCLK:
			freq_to_show = dds_clock;				// DDS accumulator & D/A clock frequency
			break;									// (master oscillator times DDS PLL)
		case cmGET_DOUT:
			freq_to_show = dds_out;					// actual DDS output frequency
			break;
		case cmGET_DISP:
			freq_to_show = dds_display;				// DDS display frequency (what the user sees)
			break;									// (or user-requested frequency to receive)
		case cmGET_DFTW:
			freq_to_show = dds_ftw;					// actual DDS frequency-tuning-word (FTW)
			break;
		case cmGET_FWRK:
			freq_to_show = freq_work;				// only used in a few functions
			break;
		case cmGET_MAXF:
			freq_to_show = max_freq;
			break;
		case cmGET_PLLV:
			freq_to_show = Ofs_mode;				// This will end up in byte[0]
			freq_to_show <<= 8;
			freq_to_show |= DDSdevice;				// This ends up in byte[1]
			freq_to_show <<= 8;
			freq_to_show |= freq_mult;				// This ends up in byte[2]
			freq_to_show <<= 8;
			freq_to_show |= dds_pll;				// this ends up in byte[3]
			break;
		case cmGET_F1Hz:							// FTW for 1 Hertz
			freq_to_show = freq_1Hz;				// based on master osc, DDS PLL, and DDS
			break;
		case cmGET_ROFS:
			freq_to_show = RxOffsetFreq;
			break;
		case cmGET_TOFS:
			freq_to_show = TxOffsetFreq;
			break;
		case cmGET_VFOA:
			freq_to_show = VFO_A;
			break;
		case cmGET_VFOB:
			freq_to_show = VFO_B;
			break;
		case cmGET_VFOC:
			freq_to_show = VFO_C;
			break;
		case cmGET_VFOD:
			freq_to_show = VFO_D;
			break;
		case cmGET_BPFS:								// get BPF start and stop values
			freq_to_show = BPF_start;
			freq_to_show = freq_to_show << 16;
			freq_to_show = freq_to_show & 0xFFFF0000;
			freq_to_show |= BPF_stop;
			break;
		case cmGET_VFOM:								// get VFO Mode storage info
			break;
		case cmGET_RITV:								// get RIT status and value
			break;
		case cmGET_BDID:
			freq_to_show = BoardID;						// get the Board ID value byte[0]
			freq_to_show <<= 8;
			freq_to_show |= BD_state;					// and get the Board state byte[1]
			freq_to_show <<= 8;
			freq_to_show |= TxEnables;					// get the Tx Enables byte[2]
			freq_to_show <<= 8;
			freq_to_show |= FilterType;					// and BP filter type byte[3]
			break;

#ifdef	FREQ_DEBUG							// these are only for freq calc debugging
		case 0x80:
			freq_to_show = u1;
			break;
		case 0x81:
			freq_to_show = u0;
			break;
		case 0x82:
			freq_to_show = vn1;
			break;
		case 0x83:
			freq_to_show = vn0;
			break;
		case 0x84:
			freq_to_show = q1;
			break;
		case 0x85:
			freq_to_show = q0;
			break;
		case 0x86:
			freq_to_show = un32;
			break;
		case 0x87:
			freq_to_show = un21;
			break;
		case 0x88:
			freq_to_show = un10;
			break;
		case 0x89:
			freq_to_show = un1;
			break;
		case 0x90:
			freq_to_show = un0;
			break;
#endif									// end of freq debugging use
		default:
			freq_to_show = 0x01020304;
		}
	freq_work = freq_to_show;							// copy data to work variable
	send_data(0x02, input_buffer[0], 0);				// and send it to the host
	}

/****************************************************************************************
*	set_param().	command to Set various parameters for the board, mostly freq related*
*	0X77			Called with:	byte[0], bits 7-4 hold the subcommand (pointer)		*
*										to change, as follows:							*
****************************************************************************************/
void set_param(void)
	{
	unsigned char subcmd;				// set parameter subcommand storage
	int temp;							// parameter byte read counter, and update flag
	int	upd_flg = 0;					// update frequency flag

	subcmd = dds_cmd[cmSET_SCMD];		// copy the command byte to local storage
	subcmd &= cmSET_SMSK;				// strip all but the subcommand data
	get_data();						// get the sent parameter from command buffer
	freq_work = freq_work & 0x1FFFFFFF;		// strip off subcmd data from parameter
	temp = 0;
	switch(subcmd)							// go do the requested command
		{
		case cmSET_VFOA:					// set VFO-A to new frequency, and update
			VFO_A = freq_work;					// save the new value in VFO A variable
			eepWR4(eFVFO_A0, &VFO_A);			// save the new VFO A in EEPROM
// add freq update - depending on mode
			break;
		case cmSET_VFOB:					// set VFO-B to new frequency, and update
			VFO_B = freq_work;					// save the new value in VFO B variable
			eepWR4(eFVFO_B0, &VFO_B);			// save the new VFO B in EEPROM
// add freq update - depending on mode
			break;
		case cmSET_VFOC:					// set VFO-C to new frequency, and update
			VFO_C = freq_work;					// save the new value in VFO C variable
			eepWR4(eFVFO_C0, &VFO_C);			// save the new VFO C in EEPROM
// add freq update - depending on mode
			break;
		case cmSET_VFOD:					// set VFO-D to new frequency, and update
			VFO_D = freq_work;					// save the new value in VFO D variable
			//eepWR4(eFVFO_D0, &VFO_D);			// save the new VFO D in EEPROM
// add freq update - depending on mode
			break;
		case cmSET_ROFS:					// set Rx Offset to new frequency, and update
			RxOffsetFreq = freq_work & 0x07FFFFFF;	// save just the offset frequency
			temp = dds_cmd[cmSET_SCMD] & 0x18;		// strip off but mask mode bits
			if(temp != eOFSNONE)					// if Rx offset should be enabled
				{										// store new offset in mode storage
				temp = temp >> 3;						// put Rx offset mode bits in 0-1
				temp = temp & 0x03;						// clear out all except Rx offset mode
				Ofs_mode = Ofs_mode & eOFSTMSK;			// strip off old receive mode bits
				Ofs_mode = Ofs_mode | temp;				// OR the new Rx offset mode bits
				}
			else									// here if not proper mode, turn OFF offset
				Ofs_mode = Ofs_mode & eOFSTMSK;			// strip off receive offset (no offset)
			// store new Rx offeset freq and offset mode in EEPROM
			if(!Transmitting)
				{
				// store freq
				// call set_freq(); (or ftw_calc?)
				}
// add EEPROM save
// add freq update (store freq, then call set_freq();
			break;
		case cmSET_TOFS:					// set Tx Offset to new frequency, and update
			TxOffsetFreq = freq_work & 0x07FFFFFF;	// save just the offset frequency
			temp = dds_cmd[cmSET_SCMD] & 0x18;		// strip off but mask mode bits
			if(temp != eOFSNONE)					// if Tx offset should be enabled
				{										// store new offset in mode storage
				temp = temp << 1;						// put tx offset mode bits in 4-5
				temp = temp & 0x30;						// clear out all except Tx offset mode
				Ofs_mode = Ofs_mode & eOFSRMSK;			// strip off old transmit mode bits
				Ofs_mode = Ofs_mode | temp;				// OR the new Tx offset mode bits
				}
			else									// here if not proper mode, turn OFF offset
				Ofs_mode = Ofs_mode & eOFSRMSK;			// strip off transmit offset (no offset)
			// store new Tx offeset freq and offset mode in EEPROM
			if(!Transmitting)					// don't change transmit freq while tranmsitting
				{
				// store freq
				// call set_freq(); (or ftw_calc?)
				}
// add EEPROM save
// add freq update
			break;
		case cmSET_MAXF:					// Set Max dds operating (display) frequency
			freq_work = freq_work << 4;			// shift max freq up four bits
			freq_work = freq_work & 0xFFFFFFF0;	// strip off least-significant bits
											// should the last line OR 0x0000000F instead?
			max_freq = freq_work;				// and save the new value to max_freq
			eepWR4(eMAXOUTF0, &max_freq);		// save new MAX Freq to EEPROM
			break;
		default:
			send_data(0x04, dds_cmd[4], subcmd);	// otherwise send an error back to host
		}
	// put frequency update here???
	send_data(0x01, dds_cmd[4], 0);					// echo command back for confirmation
	} 

/****************************************************************************************
*	send_data().	Internal function that configures and sends data to USB port		*
*					Called with:	unsigned char mode = mode to configure data			*
*									0x01 = copy dds_cmd buffer, 0x02 = freq_work		*
*									0x03 = return all 0x00, default = return all 0xFF	*
*									unsigned char cmd = data byte to put in bfr[4]		*
*									unsigned char scmd = subcommand to or into byte 0	*
****************************************************************************************/
void send_data(unsigned char mode, unsigned char cmd, unsigned char scmd)
	{
	unsigned long o_dta;
	int temp;

	switch(mode)
		{
		case 01:										// echo command back to host
			output_buffer[0] = dds_cmd[0];
			output_buffer[1] = dds_cmd[1];
			output_buffer[2] = dds_cmd[2];
			output_buffer[3] = dds_cmd[3];
			break;
		case 02:										// send a 32-bit parameter to host
			o_dta = freq_work;							// send freq_work to the host
		for(temp = 3; temp >= 0; temp--)				// and copy the four bytes to
			{											// output buffer to send via USB
			output_buffer[temp] = o_dta & 0xFF;			// copy a byte
			o_dta = o_dta >> 8;							// shift down next byte
			}
			output_buffer[0] |= scmd;
			break;
		case 03:										// send a null frame back to host
			output_buffer[0] = scmd;
			output_buffer[1] = 0x00;
			output_buffer[2] = 0x00;
			output_buffer[3] = 0x00;
			break;
		default:										// send error (0xFF)frame back to host
			output_buffer[0] = dds_cmd[0];
			output_buffer[1] = 0xFF;
			output_buffer[2] = 0xFF;
			output_buffer[3] = 0xFF;
			break;
		}
	output_buffer[4] = cmd;
	SendToUSB();
	}

/********************************************************************************************
*	get_data().	Internal function to get unsigned long data from USB, puts it in freq_work	*
********************************************************************************************/
void get_data(void)
	{
	int temp;
	unsigned int param;

	freq_work = 0;						// clear out the work register to start
	for(temp = 0; temp < 4; temp++)			// next read in four bytes worth of data
		{									// which will be the parameter
		freq_work = freq_work << 8;			// shift parameter eight bits up
		param = dds_cmd[temp];				// get the next byte of parameter
		param = param & 0xFF;				// make sure only 8 lower bits are used
		freq_work = freq_work | param;		// OR the results into the work word
		}									// freq_work now contains parameter
	}

/****************************************************************************************
*	VFO_setup() command	(0x76)		Sets up VFO modes, and copies, swaps, etc VFOs		*
****************************************************************************************/
void VFO_setup(void)
	{
	int subcmd;							// VFO set subcommand storage

	// VFO_sources holds the receive (0-3) and transmit (4-7) frequency sources
	//
	}

/****************************************************************************************
*	eepRD4()	INTERNAL		Reads four bytes from EEPROM into a 32-bit variable		*
*				Called with:	unsigned char:  EEPROM starting address					*
*								unsigned long:  pointer to variable to read data into	*
****************************************************************************************/
unsigned char eepRD4(unsigned char eadr, unsigned long *pvar)
	{
	int temp;
	unsigned long work;

	work = 0;									// clear out old variable value
	eepadr = eadr + 3;							// point to the LAST byte in EEPROM
	for(temp = 1; temp < 5; temp++)				// read in four bytes from EEPROM
		{
		work <<= 8;								// first shift that 8-bits left
		eepromRD();								// get the MSB data from EEPROM
		work |= eepRdata;						// put it in the variable
		eepadr--;								// point to previous byte in EEPROM
		}
	if(work == eEMPTYL)							// if the EEPROM was empty (all FF)
		return 0xFF;							// return 0xFF to show it blank
	else										// otherwise...
		{
		*pvar = work;
		return 0x00;							// show the read was OK
		}
	}

/****************************************************************************************
*	eepRD1()	INTERNAL	Reads ONE byte from EEPROM ino an unsigned char variable	*
****************************************************************************************/
unsigned char eepRD1(unsigned char eadr, unsigned char *pvar)
	{

	eepadr = eadr;								// point to the byte to read from EEPROM
	eepromRD();									// and read the data there
	if(eepRdata == eEMPTY)						// if it IS empty (0xFF)
		return 0xFF;							// return an empty flag
	else
		{
		*pvar = eepRdata;						// put it in the variable
		return eepRdata;
		}
	}
/****************************************************************************************
*	eepWR4()	INTERNAL		Writes four bytes to EEPROM from a 32-bit variable		*
****************************************************************************************/
unsigned char eepWR4(unsigned char eadr, unsigned long *pvar)
	{
	int temp, dlylp;
	unsigned long work;

	eepadr = eadr;								// point to the EEPROM first byte to write
	work = *pvar;								// get the data to save
	for(temp = 0; temp < 4; temp++)				// write four bytes to EEPROM
		{
		eepWdata = (unsigned char)(work & 0xFF); // get data to write to eeprom
		eepromWR();								// and write the byte
		work >>= 8;								// now shift that 8-bits left
		eepadr++;								// move to next eeprom write location
		for(dlylp = 0; dlylp < 2000; dlylp++);	// delay loop to let write recharge
		}										// end of EEPROM save
	}


/** EOF user.c ***************************************************************/
