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

 ********************************************************************/

/** 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"
/** V A R I A B L E S ********************************************************/

/**************	LOWEST FAST-ACCESS VARIABLES	**********************/
#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
near unsigned char	TxEnables;			// Transmit hardware enables
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[64];
char output_buffer[64];
char out_ptr;
char Buffer;

//  TFOX added
unsigned long	current_freq;		// current 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
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_freq;			// value to send to the DDS for frequency output
unsigned long	RxOffestFreq;		// receive offset frequency value
unsigned long	TxOffsetFreq;		// Transmit offset frequency
unsigned char	dds_pll;			// DDS internal PLL multiplier
unsigned char	freq_mult;			// DDS external frequency multiplier 
unsigned char	Atten;				// attenuator level storage
unsigned char	DDSdevice;			// DDS device identifier
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	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
unsigned char	FilterBand;			// current LP or BP filter operating band
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			TxIntWork;			// temporary to disale transmit interrupts
// end of TFOX adds

//	initializations for AD 9854 credit to AA0ZZ
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

/** 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 /2 ferq update
void AD9958Int(void);		// Init for AD9958
void send_9958Freq(void);	// AD9958 freq update
void set_atten(void);		// HRF-AT4611 attenuator set
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 filter_set(void);		// set the exteranl LP or BP filter
void showfreq(void);	// temporary to show frequency calculations work

/** D E C L A R A T I O N S **************************************************/
//	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

										//  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_OUT		LATBbits.LATB5			// 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)

											// 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	TX_ON		0x01					// transmit on flag

#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 MAXMHz32	4294967296				// 2^32 is maximum frequency in 32-bits
#define	MAXMHz24	16777216				// 2^24 is maximum freq in 24-bits
#define	MAXMHZ31	2147483648				// 2^31 is maximum  allowed osc for now

/////////////////////////////////////////////////////////////////////////////////////////
////////////////	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
//	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 isan  A/D command response
			SendToUSB();
			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
		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 it is now a high
				if(TxInPol == 1)						// and check polarization
					{									// here if pin high, pol is high, TX mode
					Transmitting = TRUE;				// show transmitting
					}	// end of TxIn=high, Pol=high
				else									// here if pin is high, but Pol is low, Rx
					{
					Transmitting = FALSE;				// show not transmitting
					}	// 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
					Transmitting = FALSE;				// which means we are NOT transmitting
					}	// end of TxIn=low, Pol=high
				else									// here is Tx In pin changed to Low and
					{									// polarity is low, means we ARE tranmsitting
					Transmitting = TRUE;				// show TRANSMITTING
					}	// end of TxIn=low, Pol=low
				}	// end of TxIn pin low transition
			}	// end of Tx In pin change
													// now update "transmitting", and change modes
		if(Transmitting)								// now, update the transmit flag and other
			{											// if we are now transmitting
			// put Transmitting to USB here
			if(TxEnables & eTXOUTPN)
				{
				if(TxOutPol == 1)							// and if output polarization active-high
					LATBbits.LATB5 = 1;				// Transmitting, active high.  Pin = high
				else										// otherwise, polarization is active-low
					LATBbits.LATB5 = 0;				// Transmitting, active low.  Pin = low
				}	// end of TxEnables & Tx Out Pin
			}	// end of transmitting
		else										// here if we are NOT transmitting
			{											// so, check polarity flag
			// put NOT Transmitting to USB here
			if(TxEnables & eTXOUTPN)
				{
				if(TxOutPol == 1)							// if the polarity is active-high
					LATBbits.LATB5 = 0;				// NOT transmitting, active high. Pin = low
				else										// otherwise, pin is active-low
					LATBbits.LATB5 = 1;				// NOT transmitting, active low.  Pin = high
				}	// end of TxEnables & Tx Out Pin
			}	// end of NOT Transmitting

		// add interrupt for Tx code here
		}

	}	// 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;
										// clear a bunch of flags & variables 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 = FALSE;						// turn OFF eeprom writes by default
	Transmitting = FALSE;					// turn off transmitting now flag
//// temporary setup frequency
	dds_display = 7055000;
		// temporary setup of Tx pin assignments
	TxInPin = 0x10;							// set Tx input pin to RB4 for now
	TxOutPin = 0x20;						// and set Tx output pin to RB5 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)

// temporary to disable Tx interrupts	
	TxIntWork = TRUE;	
									// 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
    TRISA = 0x20;								// enable AN4(pin RA5) analog in for AD8310
											// Make all of PORTB outputs to start
	LATB = 0x00;								// set the latch (Tom had all-high)
	TRISB = 0x00;								// set RB4=10, RB5=20 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;
									//////////////////////////////////////////////////////////////////
									/////  NEXT, get & check various data from PIC EEPROM storage	//
									//////////////////////////////////////////////////////////////////	
											////  START WITH GETTING Board State from EEPROM		//
												// test to see if any data in eeprom by checking
	eepadr = eBDSTATE;									// first, check the EEPROM Board State
	eepromRD();											// get the board state
	if(eepRdata == eEMPTY)								// did it come back as no data (0xFF)?
		{											// check the first ten bytes to make sure no data
		temp = 0;										// clear out temporary storage
		for(eepadr = 0; eepadr < 10; eepadr++)			// look at first ten eeprom bytes
			{
			eepromRD();									// get an EEPROM byte
			if(eepRdata != 0xFF)						// check it for programmed info (not 0xFF)
				temp++;									// if so, increment temp variable
			}	// end of for loop
		if(temp > 2)									// now check for number of non-0xFF bytes
			BD_state |= 0x80;							// if more than two not FF, allow USB response
		}	// end of EEPROM = 0xFF
	else												// eeprom read of BD_state was good,
		{
// need to add a test for always zero bits here before just copying BD_state to eeprom 
		// BD_state = eepRdata;							// save the data from EEPROM into BD state
		if(eepRdata & eUSBRESP)								// if the USB enable bit is set
			BD_state |= eUSBRESP;							// enable USB responses in board state
		else												// otherwise...
			BD_state &= !eUSBRESP;							// turn off USB responses
		if(eepRdata & eLEDHEART)						// Next, check LED heartbeat flag
			BD_state |= eLEDHEART;							// turn on LED heartbeat
		else												// otherwise
			BD_state &= !eLEDHEART;							// turn off LED heartbeat flag
		if(eepRdata & eTXPINSON)						// and check Tx In & Out pins enabled
			BD_state |= eTXPINSON;							// turn on Tx pins
		else												// otherwise
			BD_state &= !eTXPINSON;							// turn off Tx pins
		if(eepRdata & eEPRMWREN)						// Check to see is EEPROM writes are enabled
			{
			BD_state |= eEPRMWREN;							// Yes, turn on write flag in board state
			EepromWrEn = TRUE;								// and set Write enabled flag
			}
		else												// Otherwise, turn it off
			{
			BD_state &= !eEPRMWREN;							// turn off the write flag in board state
			EepromWrEn = FALSE;								// and clear write enabled flag
			}
		}	// end of good eeprom read
	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 = 0x04;									// set default dds PLL multiplier to 4
		freq_mult = 0x02;								// set default frequency multiplier to 2
		}
 											////////// get oscillator frequency from eeprom
														// note:  this is the actual osc. freq.
	osc_freq = 0;										// clear out old oscillator frequency
	eepadr = eMASOSC3;									// point to the most-significant byte
	for(temp = 1; temp < 5; temp++)						// read in four bytes
		{
		osc_freq <<= 8;									// and shift that 8-bits left
		eepromRD();										// get the MSB data from EEPROM
		osc_freq |= eepRdata;							// put it in the oscillator
		eepadr--;										// point to previous osc freq byte
		}
	if(osc_freq > MAXMHZ31)								// sanity check, if freq is too high...
														// (for example EEPROM is 0xFF FF FF FF)
		osc_freq = MHZ125;								// set to 125MHz instead
											/////////////	next, get 1Hz value from EEPROM
	freq_1Hz = 0;										// clear out old 1Hz value
	eepadr = eREFOSC3;									// point to the reference osc (1Hz) MSB
	for(temp = 1; temp < 5; temp++)						// read in four bytes
		{
		freq_1Hz <<= 8;									// first shift that 8-bits left
		eepromRD();										// get the MSB data from EEPROM
		freq_1Hz |= eepRdata;							// put it in the oscillator
		eepadr--;										// point to previous osc freq byte
		}
// need to work on this a little
	if(freq_1Hz > F20_1HZ)							// sanity check, if freq is too high...
														// (for example EEPROM is 0xFF FF FF FF)
		freq_1Hz = F500_1HZ;							// set to 500MHz version of 1Hz instead
											/////////////	next, get another eeprom value

											/////////////	next, get 1Hz value from EEPROM
//	freq_1Hz = 0;										// clear out old 1Hz value
//	eepadr = eREFOSC3;									// point to the reference osc (1Hz) MSB
//	for(temp = 1; temp < 5; temp++)						// read in four bytes
//		{
//		freq_1Hz <<= 8;									// first shift that 8-bits left
//		eepromRD();										// get the MSB data from EEPROM
//		freq_1Hz |= eepRdata;							// put it in the oscillator
//		eepadr--;										// point to previous osc freq byte
//		}
// need to work on this a little
//	if(freq_1Hz > F20_1HZ)							// sanity check, if freq is too high...
//														// (for example EEPROM is 0xFF FF FF FF)
//		freq_1Hz = F500_1HZ;							// set to 500MHz version of 1Hz instead


											/////////////	now, start calculating some values
	dds_clock = osc_freq * dds_pll;						// start by calculating the DDS clock input
	dds_out = dds_display * freq_mult;					// and calculate the DDS out frequency
	dds_freq = dds_out * freq_1Hz;						// calcualte the actual DDS frequency word




												//////////////////////////////////////////////////////////////
												////	Temporarily setup Tx Pin Setup						//
												////	 temporary add enable here							//
												//////////////////////////////////////////////////////////////
		if(BD_state & eTXPINSON)
			{
			if(TxIntWork)
				{
				// TransmitOn = PORTB;							// clear Port B for first time
				LATB = 0xEF;										// set pin RB4 as input in latch
				TRISB = 0x10;										// 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 Port B change flag by reading Port B
				TxPortLast = TxPortCur;								// and store it to the last port read as well
				//	PortB interrupt enable test
				INTCONbits.RBIE = 1;								// turn on RB port change interrupt enable
				INTCON2bits.RBIP = 0;								// and make it a low priority
				}	// end of TxIntWork
			}	// 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;
	
    // 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
      switch ( 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  - AD9834
		// 40 - 7F : Process special non- DDS devices, eg bandpass filters
		//tf	122 (7AH) - Set freq via PIC
		//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 9850		
		//		130 (82H) - Initialize 9854
		//		131 (83H) - Initialize 995x
		//		132 (84H) - Initialize 9958/9
		//tf	133 (84H) - Initialize AD9832/AD9835
		//tf	134 (85H) - Initialize AD9834	
		//tf	252 (FCH) - Tranmsit logic initialization
		//tf	253 (FDH) - Board initialization
		//tf	254 (FEH) - A/D Converter Initialization
		//tf	255 (FFH) - Board test command
      	{
        case cmBOARDID:							// send board ID data back to host
				BoardId();
			break;
		case cm9850UPD:							// send freq update control seq to DDS30
		  		input_buffer[4]= 0x00;				// set control word to 00
				DDSx0();
           break;
        case cm9851UPD:							// send freq update control seq to DDS60
				input_buffer[4]= 0x01;				// set control word
				DDSx0();
           break;
        case cm9854UPD:							// send freq update control seq to AD854
				send_9854Freq();
		   break;
        case cm995xUPD:							// send freq update control seq to AD995x
				send_9951Freq();
            break;
        case cm9958UPD:							// send freq update control seq to AD9958
				send_9958Freq();		
			break;
											// TFOX code added for following commands
		case cmSETFREQ:							// set frequency via PIC
				// set_freq();				// set frequency via the pic, with 32-bit binary
			break;
		case cmSETFLTR:							// set the LP/BP filters
				filter_set();
			break;
		case cmTXONOFF:							// Transmit on/off 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 = 0x01;	    		
				AD9850Int();
            break;
        case cm9851INI:							// Cmd 0x81 - Initialize 9851
				DDSdevice = 0x02;
	    		AD9850Int();
            break;
        case cm9854INI:							// Cmd 0x82 - Initialize 9854
	    		DDSdevice = 0x03;
				AD9854Int();
            break;
         case cm9951INI:						// Cmd 0x83 - Initialize 995x
	    		DDSdevice = 0x04;
				AD995xInt();
            break;
        case cm9958INI:							// Cmd 0x84 - Initialize 9858/9
				DDSdevice = 0x05;
	    		AD9958Int();
            break;
		//  TFOX code added for initialization sequences
		case 0x90:
				showfreq();
				break;
		case cmTXHWINI:							// Transmit logic initialization
				Tx_init();
			break;
		case cmBDINIT:							// do a complete board power-up initialization
				BoardInit();
			break;
		case cmADINIT:							// initialize A/D converter
				adInit();
			break;
		case cmBDTEST:							// test the board - won't affect most stuff
				Bdtest();
			break;
		//	end of TFOX added code
		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

/////////////////////////////////////////////////////////////////////////////////////////
void DDSx0(void)
{
// 	Freq word arrived - Send freq word to device serially. LSB
//	Control word is 0 for DDS30 / AD9850
//	Control word is 1 for DDS60 / AD9851

//  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 = input_buffer[3];
		output_buffer[0] = Buffer;
		//Buffer = 0xFE;
		SPIleast(); 	// Sends data LSB out PortB.7; clocked by PortB.6

	 	Buffer = input_buffer[2];
		output_buffer[1] = Buffer;
		//Buffer = 0x08;	
		SPIleast(); 	// Sends data LSB out PortB.7; clocked by PortB.6

	 	Buffer = input_buffer[1];
		output_buffer[2] = Buffer;
		//Buffer = 0xCD;			 	
		SPIleast(); 	// Sends data LSB out PortB.7; clocked by PortB.6

	 	Buffer = input_buffer[0];	
		output_buffer[3] = Buffer;
		//Buffer = 0x0A;	
		SPIleast(); 	// Sends data LSB out PortB.7; clocked by PortB.6

	
		Buffer = input_buffer[4];             //Control word
		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
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;
	SPIleast();		// Sends data LSB out PortB.7; clocked by PortB.6
 	Buffer = 0;
	SPIleast();		// Sends data LSB out PortB.7; clocked by PortB.6
 	Buffer = 0;
	SPIleast();		// Sends data LSB out PortB.7; clocked by PortB.6
 	Buffer = 0;	
	SPIleast();		// Sends data LSB out PortB.7; clocked by PortB.6
 	Buffer = 0;	
	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)
{
//  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 = CR_write_cmd;
	SPImost();

	// send 4 CR bytes
	Buffer = CR_byte_0;
	SPImost();
	Buffer = CR_byte_1;
	SPImost();
	Buffer = CR_byte_2;
	SPImost();
	Buffer = 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 = CR_write_cmd;
	SPImost();

	Buffer = CR_byte_0;
	SPImost();
	Buffer = CR_byte_1;
	SPImost();
	Buffer = CR_byte_2;
	SPImost();
	Buffer = 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 = freq_write_cmd;
	SPImost();
	Buffer = input_buffer[0];
    //Buffer = 0x0E;
	SPImost();
	Buffer = input_buffer[1];
	//Buffer = 0x6A;
	SPImost();
	Buffer = input_buffer[2];
    //Buffer = 0xFC;
	SPImost();
	Buffer = input_buffer[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)
	{ //DRAFT CODE _ UNTESTED

	// Send reset - might not be needed
	IQ_mreset = 1;
	IQ_mreset = 0;

	//Send word for register selection 

	// Select CFR 1 to set up devices
	Buffer = 0x01;
	SPImost();

	// send initialization bytes (24 bits)
	Buffer = 0x00;
	SPImost();
	Buffer = 0x00;
	SPImost();
					// TFNOTE:  THIS HAS BEEN COMMENTED OUT PREVIOUSLY
					//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 = input_buffer[0];	// Register byte set up in PC
	SPImost();

	// toggle IO update
	AD99_ioud = 1;
	wait_10_inst();
	AD99_ioud = 0;

	}// end of  AD995xInt

///////////////////////////////////////////////////////////////////////////////////////////
void send_9951Freq(void)
	{ //DRAFT CODE _ UNTESTED
	//Send bytes for fequency selection

	// Select Freq reg CFR 4
	Buffer = 0x04;	// select register cf4 - Freq
	SPImost();

	// Now send 32 bit freq word

	Buffer = input_buffer[0];
	SPImost();

	Buffer = input_buffer[1];
	SPImost();

	Buffer = input_buffer[2];
	SPImost();

	Buffer = input_buffer[3];
	SPImost();

	// toggle IO update
	AD99_ioud = 1;
	wait_10_inst();
	AD99_ioud = 0;

	}// end of send_9951Freq

///////////////////////////////////////////////////////////////////////////////////////////
void AD9958Int(void)
	{
	//Draft Code - untested

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

	// set PLL multiplier from MSB byte of initialization word
	//Buffer = 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
	//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 = input_buffer[0];
    //Buffer = 0x0E;
	SPImost();
	Buffer = input_buffer[1];
	//Buffer = 0x6A;
	SPImost();
	Buffer = input_buffer[2];
    //Buffer = 0xFC;
	SPImost();
	Buffer = 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 & June 2007

/////////////////////////////////////////////////////////////////////////////////////////
//	SendToUSB - sends output_buffer[0-5] data back to host, if enabled
void SendToUSB(void)
	{
	if(BD_state & USBresp)
		{
		if(mUSBUSARTIsTxTrfReady())						// Send result back to PC
   			{
			mUSBUSARTTxRam((byte*)output_buffer,5); 
			}
		}
	}

//////////////////////////////////////////////////////////////////////////////////////////
// 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 = input_buffer[0] & 0x3f;	// get and store the atten command
	atn = Atten;
	if(input_buffer[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;
	output_buffer[1] = 0;
	output_buffer[2] = 0;
	output_buffer[3] = input_buffer[3];
	output_buffer[4] = 0x7F;
	SendToUSB();

} // 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

/////////////////////////////////////////////////////////////////////////////////////////
// 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
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]		commande 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 can be 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
	}

////////////////////////////////////////////////////////////////////////////////////////////
// eeproWR can be 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)
	{
	// unsigned char eepWdata;
	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

////////////////////////////////////////////////////////////////////////////////////////////////
//  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 the channel to read rom 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 of int & 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
	OpenADC(ADC_FOSC_RC & ADC_8_TAD & ADC_RIGHT_JUST,		// startup ADC, AD clk source, justif, TAD
			ADC_CH4 & ADC_INT_OFF & ADC_VREFPLUS_VDD		// Channel, interrupts, volt config
			& ADC_VREFMINUS_VSS,
			0x0A);								// port configuration for AN4 (pin A5)
	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 routing
//	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

///////////////////////////////////////////////////////////////////////////////////////////////////
//	Transmit hardware initialization function
//	called with:
//		Byte[0] = Tx enables/disables.  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
//		Byte[1] = Tx pins to use. 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)
//							Bits 3 is Tx Out pin PORT to use.  0=PortB, 1=PortC.
//							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 7 set if status request response)
//		Byte[1] = Tx pins used
//		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, TxPinStore;

	if(input_buffer[0] == 0xFF)						// If status rqst, just update parameters
		{
		output_buffer[0] = TxEnables & 0x1F;
		output_buffer[0] |= 0x80;
		}
	else											// not status update, parse the command
		{
		if(input_buffer[0] == 0)					// if first byte is a zero, turn off Tx hardware
			{
			TxEnables = 0;								// show all transmit stuff turned off
			output_buffer[0] = TxEnables;
			output_buffer[0] |= 0x40;
// temporary changed last line from 0x00
			ClosePORTB();								// shut off Tx input interrupts
			}
		else										// Not status rqst or turn-off command, proceed
			{
			output_buffer[0] = TxEnables & 0x1F;				// show the enables in response
			output_buffer[0] |= 0x20;
// check and redo all this logic
			TxPinStore = input_buffer[1];						// store the pins information
			TxEnables = input_buffer[0] & 0x1F;					// Store transmit enable flags
			if(TxEnables & 0x01)								// is Tx In pin enabled?
				{												// yes, set up Tx In pin hardware
				TxPinWork = TxPinStore & 0x03;					// get the Tx IN pin bits
				switch(TxPinWork)
					{
					case 0:										// If bits 0-1 = 00, set up pin RB4
						TxInPin = 0x10;							// set up Tx In pin to be RB4
						break;
					case 1:										// If bits 0-1 = 01, set up pin RB5
						TxInPin = 0x20;							// set up Tx In pin to be RB5
						break;
					case 2:										// If bits 0-1 = 02, set up pin RB6
						TxInPin = 0x40;							// set up Tx In pin to be RB6
						break;
					case 3:										// If bits 0-1 = 03, set up pin RB7
						TxInPin = 0x80;							// set up Tx In pin to be RB7
						break;
					}	// end of Tx In switch
				if(TxPinStore & 0x04)							// 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
// move Tx In interrupt enable to here??
				}	// 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
// turn off Tx In interrupts here
				}	// end of Tx In pin setup test
			if(TxEnables & 0x02)								// now test fot Tx Out pin enabled
				{
				if(TxPinStore & 0x08)							// first set TxOut port flag
					TxOutPort = 1;								// set it to port B
				else
					TxOutPort = 0;								// set it to port C
				TxPinWork = (TxPinStore & 0x70) >> 4;			// now get the Tx Output pin number
	// add the Tx output pin switch statement here
				if(TxPinStore & 0x80)							// 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
// from here down needs work
// set up RB4 for input here....	
	//	OpenPORTB(PORTB_CHANGE_INT_ON & PORTB_PULLUPS_ON);		// set up Tx input Port B
	//	TRISB = TxInPin;										// Set up Tx in pin as input
			}
		}	// end of buffer[0] not FF

// the following is to read back status
												// read back the various Tx hardware parameters
//  redo to add tx pin logic
	output_buffer[1] = TxInPin;							// get the assigned transmit in pin
// following lines temporary for debugging
	if(TxInPol == 1)
		output_buffer[1] |= 0x08;
	else
		output_buffer[1] |= 0x04;
	if(TxOutPol == 1)
		output_buffer[1] |= 0x02;
	else
		output_buffer[1] |= 0x01;
	output_buffer[2] = TxEnables;
	output_buffer[3] = TxPinStore;
// end of added debug lines

// normally, these two lines would be enabled
//	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
 
///////////////////////////////////////////////////////////////////////////////////////////////////
//	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
	
	if(work & eUSBRESP)									// should we turn on USB return data enable flag
		BD_state |= eUSBRESP;								// yes, enable USB return frames
	else													// otherwise...
		BD_state &= 0x7F;									// turn off USB return frames

	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 &= 0xBF;									// clear the LED heartbeat flag
		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 & 0x01)								// test to see if Tx In pin is enabled
			{
			if(TxIntWork)
				{
				txinpinon();
				}
			}
		}
	else														// command was to turn off Tx pins
		{
		// turn off individual tranmsit enables?  probably not
		BD_state &= 0xEF;										// show the Tx pins are disabled
		if(TxIntWork)
			{
			txinpinoff();
			}
		}
	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 &= 0xFE;										// clear the write enable in board state
		EepromWrEn = FALSE;										// and turn off eeprom writes
		}
	BD_state &= 0xD7;											// 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;
	output_buffer[1] = eepRdata;;
	output_buffer[2] = 0;
	output_buffer[3] = 0;
	output_buffer[4] = input_buffer[4];
	SendToUSB();
	}	// 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;
	ClosePORTB();
	}

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

	if(input_buffer[1] == 0x01)
		{
		PORTB &= 0xf0;								// clear out the old filter data
		filter = input_buffer[0] & 0x07;			// clear all but lowest three bits of filter 
		PORTB |= filter;							// set any bits high from filter request
		output_buffer[0] = filter;
		output_buffer[1] = input_buffer[1];
		output_buffer[2] = 0;
		output_buffer[3] = 0;
		output_buffer[4] = input_buffer[4];
		SendToUSB();
		}
	}

/////////////////////////////////////////////////////////////////////////////////////////
////	termporary function to show various frequencies and other info

//  7:  unsigned long	current_freq;		// current frequency
//  6:  unsigned long	freq_work;			// intermediate work storage
//  1:  unsigned long	osc_freq;			// oscillator frequency (actual oscillator before PLL)
//	2:  unsigned long	dds_clock;			// DDS clock input results frequency (after PLL)
//  7:  unsigned long	freq_1Hz;			// 1 Hertz value
//  3:  unsigned long	dds_out;			// DDS output frequency (display * freq_mult)
//  4:  unsigned long	dds_display;		// DDS display frequency (wanted freq, before freq mult)
//  5:  unsigned long	dds_freq;			// value to send to the DDS for frequency output
//  8:  unsigned char dds_pll(L) & freq_mult(H)
//  9:  freq_1HZ
//		unsigned long	RxOffestFreq;		// receive offset frequency value
// 10:  unsigned long	TxOffsetFreq;		// Transmit offset frequency


void showfreq(void)
	{
	unsigned long freq_to_show = 0;

	switch(input_buffer[0])
		{
		case 1:
			freq_to_show = osc_freq;
			break;
		case 2:
			freq_to_show = dds_clock;
			break;
		case 3:
			freq_to_show = dds_out;
			break;
		case 4:
			freq_to_show = dds_display;
			break;
		case 5:
			freq_to_show = dds_freq;
			break;
		case 6:
			freq_to_show = freq_work;
			break;
		case 7:
			freq_to_show = current_freq;
			break;
		case 8:
			freq_to_show = (unsigned long)freq_mult;
			freq_to_show <<= 8;
			freq_to_show |= (unsigned long)dds_pll;
			break;
		case 9:
			freq_to_show = freq_1Hz;
			break;
		default:
			freq_to_show = 0x01020304;
		}
	output_buffer[3] = freq_to_show & 0x000000FF;
	freq_to_show >>= 8;
	output_buffer[2] = freq_to_show & 0x000000FF;
	freq_to_show >>= 8;
	output_buffer[1] = freq_to_show & 0x000000FF;
	freq_to_show >>= 8;
	output_buffer[0] = freq_to_show & 0x000000FF;
	output_buffer[4] = input_buffer[0];
	SendToUSB();
	}



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