#pragma NOIV               // Do not generate interrupt vectors
//-----------------------------------------------------------------------------
//   File:      periph.c
//   Contents:   Hooks required to implement USB peripheral function.
//
//   Copyright (c) 1997 AnchorChips, Inc. All rights reserved
//-----------------------------------------------------------------------------
// Modified for N2PK VNA
// Modifications (C) 2004 Dave Roberts G8KBB
// 14 Sept 2006 - extended for VNAccess.dll
// 08 Nov 2006 - significant rewrite

#include "fx2.h"
#include "fx2regs.h"
#include "fx2sdly.h"            // SYNCDELAY macro
#include "vna.h"

//-----------------------------------------------------------------------------
// These are used to include various time / space tradeoffs to improve performance
//-----------------------------------------------------------------------------
#define UNWRAP_DDS_INNER_LOOP_OPTIMISATION
#define USEAUTOPTRFORADCRESULTS
#define COPYCACHEEXPLICIT
#define N2PK_RESET

//-----------------------------------------------------------------------------
// flags and data storage defined in fw.c
//-----------------------------------------------------------------------------
extern BOOL   GotSUD;         // Received setup data flag
extern BOOL   Sleep;
extern BOOL   Rwuen;
extern BOOL   Selfpwr;

//-----------------------------------------------------------------------------
// flags and variables defined here
//-----------------------------------------------------------------------------
BYTE   Configuration;      // Current configuration
BYTE   AlternateSetting;   // Alternate settings
BYTE   AdcReadsDone;       // number of ADC reads performed
BYTE   AdcReadCount;       // Number of ADC reads requested
BYTE   AdcTimeStart;       // timeout timer for ADC reset
BYTE   AdcReadDelay;       // delay counter (msec) before first ADC read
BYTE   AdcMode;            // flags for which ADC and ADC mode
BYTE   ReturnStatus;       // status byte returned to controller
BYTE   LastCommand;        // what command did I last receive?
bit    PauseDataIn;        // Pause sending Data In frames during ADC conversion
bit    PauseDataOut;       // Pause processing Data Out frames during ADC conversion
bit    bOverrideMode;      // flag settable from config command to force ADC speed mode
BYTE   ModeOverrideValue;  // and what value we set it to
bit    bAdcConverting;     // flag set when ADC converting (used in double conversion state machine)
BYTE   DoubleConvertState; // finite stae machine for double conversion mode
BYTE   CacheCommand[CmdVnaSweepSize];  // message cache - set to greater of size of this and CmdVnaSetDdsSizeLong
BYTE   SweepState;			// finite state machine for frequency scanning
BYTE 	FreqLO[5];           // current frequency when sweeping (LO)
BYTE 	FreqRF[5];           // current frequency when sweeping (RF)
unsigned long SweepCount;  // number of points in sweep
BYTE	minAdcDelay;          // enforced min delay for ADC reads ( 8usec counter + min )

// ADC resuts are stored in this buffer pending return to the PC
xdata volatile BYTE   AdcInData[ADCMAXREADS*2][4] _at_ 0xE000;

//-----------------------------------------------------------------------------
// function prototypes
//-----------------------------------------------------------------------------

void handle_in(void);
void handle_adc1(void);
void handle_adc2(void);
void handle_both_adcs(void);
void handle_out(void);
void Startup_Adc(BYTE mindelay);
void handle_double_convert(void);
void SetDDS( BYTE *LOptr, BYTE *RFptr );
void SweepFSM();
void clock_adc_5_times();
void adc_tail(void);
void usecDelayWait( void );
void AdcCompleteStartup(void);

//-----------------------------------------------------------------------------
// Task Dispatcher hooks
//   The following hooks are called by the task dispatcher.
//
// TD_Init() is caalled once at FW startup
// TD_Poll() is callled continually by FW main loop
//-----------------------------------------------------------------------------

void TD_Init(void)             // Called once at startup
{
	// set the CPU clock to 12MHz & disable clock out
	// should already hve been though!
	//CPUCS = (CPUCS & ~bmCLKSPD & ~bmCLKOE);
	// set the CPU clock to 48MHz
	CPUCS = ((CPUCS & ~bmCLKSPD) | bmCLKSPD1) ;

	// we are just using the default values, so yes this is not necessary...
	EP1OUTCFG = 0x20;             // to enable it, 0xA0;
	EP1INCFG = 0x20;              // to enable it, 0xA0;
	SYNCDELAY;                    // see TRM section 15.14
	EP2CFG = 0xA2;                // EP2 output, bulk, 512 byte double buffered
	SYNCDELAY;
	EP4CFG = 0x20;                // EP4 output, bulk, DISABLED (enable with 0xA0)
	SYNCDELAY;
	EP6CFG = 0xE2;                // EP6 input, bulk, 512 byte double buffered
	SYNCDELAY;
	EP8CFG = 0x60;                // EP8 input, bulk, DISABLED (enable with 0xE0)
	bOverrideMode = 0;
	ModeOverrideValue = 0;

	// out endpoints do not come up armed
	// since the defaults are double buffered we must write dummy byte counts twice
//	SYNCDELAY;
	EP2BCL = 0x80;                // arm EP2OUT by writing byte count w/skip.
	SYNCDELAY;
	EP2BCL = 0x80;
//	SYNCDELAY;
//  EP4BCL = 0x80;                // arm EP4OUT by writing byte count w/skip.
//  SYNCDELAY;
//  EP4BCL = 0x80;

	// enable dual autopointer feature
	AUTOPTRSETUP |= 0x01;

	Rwuen = TRUE;                 // Enable remote-wakeup

	// clear main counters and flags. Enable IN and OUT handling
	AdcReadsDone = 0;
	AdcReadCount = 0;
	ReturnStatus = 0;
	PauseDataIn = FALSE;
	PauseDataOut = FALSE;
	AdcMode = 0;
	bAdcConverting = FALSE;
	DoubleConvertState = 0;
	SweepState = 0;
	minAdcDelay = DEFMINADCDELAY;

	// configure timer 1 for usec delay timer function
	// 13 bit upcounter, clocked at 48MHz/12 == 4 MHz (250nsec)
	// so writing count to high byte of 13 bit counter will
	// count in units of 32*.25 = 8 usec.
	TMOD = 0;

	// set up ports for VNA interface
	IOA = 0;
	IOB = 0;
	IOD = 0;
	OEB = ~(bmVNAPower | bmADC2SdoPin);
	OEA = ~bmADC1SdoPin;
	OED = 0xFF;
}


// Poll loop is called repeatedly by task dispatcher.
// It handles, messages from the PC, ADC conversions and responses

void TD_Poll(void)             // Called repeatedly while the device is idle
{
	if( PauseDataOut == FALSE )
		handle_out();

	if( AdcMode & CmdVnaSetDdsAdcModeSimultaneous )  handle_both_adcs();
	else if( AdcMode & CmdVnaSetDdsAdcModeDet2 )     handle_adc2();
	else  handle_adc1();

	if( DoubleConvertState != 0 )
		handle_double_convert();

	if( SweepState )
		SweepFSM();

	if( PauseDataIn == FALSE )
		handle_in();
}


//-----------------------------------------------------------------------------
// main process to handle output frames from host to USB
//-----------------------------------------------------------------------------

void handle_out(void)
{
	BYTE i;
	WORD count;
#ifdef N2PK_RESET
	BYTE j;
#endif

	// check EP2 EMPTY(busy) bit in EP2468STAT (SFR), core set's this bit when FIFO is empty
	// indicates message waiting for VNA
	if(!(EP2468STAT & bmEP2EMPTY) )
	{
		// clear in data pause just in case
		PauseDataIn = FALSE;
		// find how big packet is
		count = (EP2BCH << 8) + EP2BCL;
		switch( EP2FIFOBUF[0] )
		{
			case CmdVnaSetDds:
				LastCommand = CmdVnaSetDds;
				SweepState = 0;
				// check command data is sufficient
				if( count >= CmdVnaSetDdsSize )
				{
					// check if flags require a DDS reset before load
					if( EP2FIFOBUF[CmdVnaSetDdsFlagsOfs] & CmdVnaSetDdsFlagsReset )
					{
#ifdef N2PK_RESET
						// set all DDS lines low at start with
						IOA &= ~(bmResetDdsPin|bmWClkDdsPin|bmFQUDDdsPin|bmLoDdsDataPin|bmRfDdsDataPin);
						for( i=0; i<2;i++)
						{
							// pulse Reset pin
							IOA |= bmResetDdsPin;
							IOA &= ~bmResetDdsPin;
							if( i )
							{
								// if this is the second time, pulse FQ_UD
								IOA |= bmFQUDDdsPin;
								IOA &= ~bmFQUDDdsPin;
							}
							// we must now put it into serial mode.
							// set clock pin high then low
							IOA |= bmWClkDdsPin;
							IOA &= ~bmWClkDdsPin;
							// load partial 8 bit word
							IOA |= bmFQUDDdsPin;
							IOA &= ~bmFQUDDdsPin;
							// clock DDS 40 times
							for(j=40; j ; j--)
							{
								IOA |= bmWClkDdsPin;
								IOA &= ~bmWClkDdsPin;
							}
							// second time round, pulse FQ_UD
							if( i )
							{
								IOA |= bmFQUDDdsPin;
								IOA &= ~bmFQUDDdsPin;
							}
						}
#else
						IOA |= bmResetDdsPin;
						IOA &= ~bmResetDdsPin;
						// we must now put it into serial mode.
						// set clock pin high then low
						IOA |= bmWClkDdsPin;
						IOA &= ~bmWClkDdsPin;
						// load partial 8 bit word
						IOA |= bmFQUDDdsPin;
#endif
					}
					// finish reset process (FQ_UD) and put port into default state
					IOA &= ~ bmFQUDDdsPin;
					// check if DDS configuration is required, if so, write DDS data
					if( EP2FIFOBUF[CmdVnaSetDdsFlagsOfs] & CmdVnaSetDdsFlagsDdsSet )
					{
						SetDDS( &EP2FIFOBUF[CmdVnaSetDdsLoOfs], &EP2FIFOBUF[CmdVnaSetDdsRfOfs] );
						// 14 Sept 06
						// if single function flag is set then do not pulse FQUD as we have just set the DDS
						if( (EP2FIFOBUF[CmdVnaSetDdsFlagsOfs] & CmdVnaSetDdsFlagsDdsSetSingleFunction ) == 0 )
						{
							// load 40 bits of data to each DDS using FQ_UD pin
							IOA |= bmFQUDDdsPin;
							IOA  &= ~ bmFQUDDdsPin;
						}
					}
					// 14 Sept 06
					// we have not updated the DDS freq resisters so if single function flag is set pulse FQUD
					else if( EP2FIFOBUF[CmdVnaSetDdsFlagsOfs] & CmdVnaSetDdsFlagsDdsSetSingleFunction )
					{
						// load 40 bits of data to each DDS using FQ_UD pin
						IOA |= bmFQUDDdsPin;
						IOA  &= ~ bmFQUDDdsPin;
					}

					// if double conversion requested, set state accordingly
					DoubleConvertState = (EP2FIFOBUF[CmdVnaSetDdsFlagsOfs] & CmdVnaSetDdsFlagsDoubleConversion ) &&
						(count >= CmdVnaSetDdsSizeLong) ? 1 : 0;

					// 14 Sept 06 - we should not affect ADC if we are just setting the DDS
					// so if ADC reads is zero, skip all ADC related code below
					if( EP2FIFOBUF[CmdVnaSetDdsAdcReads] != 0)
					{
						// There are two copy routines. The simple (slow) one copies the whole message
						// into cache - we need it for second conversion.
						// The optimised one copies just the bytes needed without a loop for speed.
#ifndef COPYCACHEEXPLICIT
						for(i=1;i<CmdVnaSetDdsSizeLong;i++)
							CacheCommand[i] = EP2FIFOBUF[i];
#else
						CacheCommand[CmdVnaSetDdsFlagsOfs] = EP2FIFOBUF[CmdVnaSetDdsFlagsOfs];
						CacheCommand[CmdVnaSetDdsAdcDelOfs] = EP2FIFOBUF[CmdVnaSetDdsAdcDelOfs];
						CacheCommand[CmdVnaSetDdsAdcReads] = EP2FIFOBUF[CmdVnaSetDdsAdcReads];
						CacheCommand[CmdVnaSetAdcMode] = EP2FIFOBUF[CmdVnaSetAdcMode];
						CacheCommand[CmdVnaSetDdsLoOfs2] = EP2FIFOBUF[CmdVnaSetDdsLoOfs2];
						CacheCommand[CmdVnaSetDdsLoOfs2+1] = EP2FIFOBUF[CmdVnaSetDdsLoOfs2+1];
						CacheCommand[CmdVnaSetDdsLoOfs2+2] = EP2FIFOBUF[CmdVnaSetDdsLoOfs2+2];
						CacheCommand[CmdVnaSetDdsLoOfs2+3] = EP2FIFOBUF[CmdVnaSetDdsLoOfs2+3];
						CacheCommand[CmdVnaSetDdsLoOfs2+4] = EP2FIFOBUF[CmdVnaSetDdsLoOfs2+4];
						CacheCommand[CmdVnaSetDdsRfOfs2] = EP2FIFOBUF[CmdVnaSetDdsRfOfs2];
						CacheCommand[CmdVnaSetDdsRfOfs2+1] = EP2FIFOBUF[CmdVnaSetDdsRfOfs2+1];
						CacheCommand[CmdVnaSetDdsRfOfs2+2] = EP2FIFOBUF[CmdVnaSetDdsRfOfs2+2];
						CacheCommand[CmdVnaSetDdsRfOfs2+3] = EP2FIFOBUF[CmdVnaSetDdsRfOfs2+3];
						CacheCommand[CmdVnaSetDdsRfOfs2+4] = EP2FIFOBUF[CmdVnaSetDdsRfOfs2+4];
#endif
						// no reads done yet, set counter to zero
						AdcReadsDone = 0;
						Startup_Adc(minAdcDelay);
						ReturnStatus &= ~(AdcReadTimeout | AdcDataReady);
					}
				}
//				SYNCDELAY;
				EP2BCL = 0x80;          // re(arm) EP2OUT
				break;

			case CmdVnaRawData:
				LastCommand = CmdVnaRawData;
				// check command data is sufficient
				if( count >= CmdVnaRawDataSizeMin )
				{
					// if flags indicate data write, write port A
					if( EP2FIFOBUF[CmdVnaRawDataFlagsOfs] & CmdVnaRawDataFlagsWriteA )
						IOA = EP2FIFOBUF[CmdVnaRawDataPortOfsA];
					// if flags indicate data write, write port B
					if( EP2FIFOBUF[CmdVnaRawDataFlagsOfs] & CmdVnaRawDataFlagsWriteB )
						IOB = EP2FIFOBUF[CmdVnaRawDataPortOfsB];
					if( EP2FIFOBUF[CmdVnaRawDataFlagsOfs] & CmdVnaRawDataFlagsWriteD )
						IOD = EP2FIFOBUF[CmdVnaRawDataPortOfsD];
					if( EP2FIFOBUF[CmdVnaRawDataFlagsOfs] & CmdVnaRawDataFlagsSetAtt )
					{
						if( EP2FIFOBUF[CmdVnaRawDataSetAtten] <= 7 )
						{
							IOB &= ~(bmAtten2 | bmAtten1 | bmAtten0);
							IOB |= EP2FIFOBUF[CmdVnaRawDataSetAtten] << 2;
						}
					}
					if( EP2FIFOBUF[CmdVnaRawDataFlagsOfs] & CmdVnaRawDataFlagsSetSw )
					{
						IOA &= ~(bmSwitch1Pin | bmSwitch0Pin);
						IOA |= EP2FIFOBUF[CmdVnaRawDataSetSwitch] & 3;
					}
				}
//				SYNCDELAY;                    
				EP2BCL = 0x80;          // re(arm) EP2OUT
				break;

			case CmdVnaConfigure:
				LastCommand = CmdVnaConfigure;
				// check command data is sufficient
				if( count >= CmdVnaConfigureSizeMin )
				{
					// if flags indicate data write, update mode override value
					if( EP2FIFOBUF[CmdVnaConfigureFlagsOfs] & CmdVnaConfigureModeOverrideOn )
					{
						ModeOverrideValue = EP2FIFOBUF[CmdVnaConfigureModeValue];
						bOverrideMode = ( ModeOverrideValue > 0x0f ) ? 0 : 1;
						ModeOverrideValue &= 0x0f;
					}
					if( EP2FIFOBUF[CmdVnaConfigureFlagsOfs] & CmdVnaConfigureModeDelayMin )
						minAdcDelay = EP2FIFOBUF[CmdVnaConfigureMinDelayValue];
					
				}
//				SYNCDELAY;                    
				EP2BCL = 0x80;          // re(arm) EP2OUT
				break;

			case CmdVnaSwpDds:
				LastCommand = CmdVnaSwpDds;
				if( count >= CmdVnaSweepSize )
				{
					for(i=1;i<CmdVnaSweepSize;i++)
						CacheCommand[i] = EP2FIFOBUF[i];
					SweepState = 1;
				}
//				SYNCDELAY;                    
				EP2BCL = 0x80;          // re(arm) EP2OUT
				break;

			default:                  // Invalid request
				LastCommand = 0;
				EZUSB_STALL_EP0();      // Stall End Point 0
		}
	}
}

//-----------------------------------------------------------------------------
// This function is called to set the DDSes to the required frequencies.
//-----------------------------------------------------------------------------

void SetDDS( BYTE *LOptr, BYTE *RFptr )
{
#ifndef UNWRAP_DDS_INNER_LOOP_OPTIMISATION
	BYTE j;
#endif
	BYTE i, LObyte, RFbyte;

	// loop through each bit of data for both DDS a byte at a time
    for(i=4; i!=0xff; i--)
	{
		// read next byte for each DDS
		LObyte = *(LOptr+i);
		RFbyte = *(RFptr+i);
		// loop through each bit in byte
#ifdef UNWRAP_DDS_INNER_LOOP_OPTIMISATION
		if( LObyte & 1 ) IOA |= bmLoDdsDataPin;
		if( RFbyte & 1 ) IOA |= bmRfDdsDataPin;
		IOA |= bmWClkDdsPin;
		IOA &= ~(bmLoDdsDataPin | bmRfDdsDataPin | bmWClkDdsPin);
		if( LObyte & 2 ) IOA |= bmLoDdsDataPin;
		if( RFbyte & 2 ) IOA |= bmRfDdsDataPin;
		IOA |= bmWClkDdsPin;
		IOA &= ~(bmLoDdsDataPin | bmRfDdsDataPin | bmWClkDdsPin);
		if( LObyte & 4 ) IOA |= bmLoDdsDataPin;
		if( RFbyte & 4 ) IOA |= bmRfDdsDataPin;
		IOA |= bmWClkDdsPin;
		IOA &= ~(bmLoDdsDataPin | bmRfDdsDataPin | bmWClkDdsPin);
		if( LObyte & 8 ) IOA |= bmLoDdsDataPin;
		if( RFbyte & 8 ) IOA |= bmRfDdsDataPin;
		IOA |= bmWClkDdsPin;
		IOA &= ~(bmLoDdsDataPin | bmRfDdsDataPin | bmWClkDdsPin);
		if( LObyte & 0x10 ) IOA |= bmLoDdsDataPin;
		if( RFbyte & 0x10 ) IOA |= bmRfDdsDataPin;
		IOA |= bmWClkDdsPin;
		IOA &= ~(bmLoDdsDataPin | bmRfDdsDataPin | bmWClkDdsPin);
		if( LObyte & 0x20 ) IOA |= bmLoDdsDataPin;
		if( RFbyte & 0x20 ) IOA |= bmRfDdsDataPin;
		IOA |= bmWClkDdsPin;
		IOA &= ~(bmLoDdsDataPin | bmRfDdsDataPin | bmWClkDdsPin);
		if( LObyte & 0x40 ) IOA |= bmLoDdsDataPin;
		if( RFbyte & 0x40 ) IOA |= bmRfDdsDataPin;
		IOA |= bmWClkDdsPin;
		IOA &= ~(bmLoDdsDataPin | bmRfDdsDataPin | bmWClkDdsPin);
		if( LObyte & 0x80 ) IOA |= bmLoDdsDataPin;
		if( RFbyte & 0x80 ) IOA |= bmRfDdsDataPin;
		IOA |= bmWClkDdsPin;
		IOA &= ~(bmLoDdsDataPin | bmRfDdsDataPin | bmWClkDdsPin);
#else
		for(j=1; j != 0 ; j<<=1 )
		{
			// if next LO bit is set, set LO data pin high
			if( LObyte & j )
				IOA |= bmLoDdsDataPin;
			// if next RF bit is set, set RF data pin high
			if( RFbyte & j )
				IOA |= bmRfDdsDataPin;
			// set clock pin high then low (and clear data bits for next loop)
			IOA |= bmWClkDdsPin;
			IOA &= ~(bmLoDdsDataPin | bmRfDdsDataPin | bmWClkDdsPin);
		}
#endif
	}
}

//-----------------------------------------------------------------------------
// utiltiy used to configure for an ADC conversion and start a time delay if needed
// Note it uses the cached data not the FIFO
//-----------------------------------------------------------------------------

void Startup_Adc( BYTE mindelay)
{
	// stop timer 0 in case running and clear "done" flag
	TR0 = 0;
	TF0 = 0;
	if( CacheCommand[CmdVnaSetDdsAdcDelOfs] == 0 )
		CacheCommand[CmdVnaSetDdsFlagsOfs] |= CmdVnaSetDdsFlagsDelayIsUsec;
	// set up for either short (timer) delay or long (counter tick) delay
	if(  CacheCommand[CmdVnaSetDdsFlagsOfs] & CmdVnaSetDdsFlagsDelayIsUsec )
	{
		// short delay. Set long counter to zero, set up timer 0 for usec delay
		AdcReadDelay = 0;
		// set timer 0 for short delay and start timer
		// 48 MHz clock, divide by 12 => 4MHz timer clock
		// low order 5 bits (TL0) mean each count in high
		// order byte is 8 usec. Therefore count up to FF in these units

		if( CacheCommand[CmdVnaSetDdsAdcDelOfs] < mindelay )
			CacheCommand[CmdVnaSetDdsAdcDelOfs] = mindelay;
		TH0 = ~CacheCommand[CmdVnaSetDdsAdcDelOfs];
		TL0 = 0;
		// start timer
		TR0 = 1;
	}
	else // long delay.
		AdcReadDelay = CacheCommand[CmdVnaSetDdsAdcDelOfs];

	// set number of ADC reads to be done
	AdcReadCount = CacheCommand[CmdVnaSetDdsAdcReads];
	// force limit on number
	if( (CacheCommand[CmdVnaSetDdsFlagsOfs] & CmdVnaSetDdsFlagsDoubleConversion ))
	{
		if( AdcReadCount > ADCMAXREADS/2 )
			AdcReadCount = ADCMAXREADS/2;
	}
	else
	{
		if( AdcReadCount > ADCMAXREADS )
			AdcReadCount = ADCMAXREADS;
	}

	// if we have conversions to do, then check if we need to pause
	// IN and OUT handling, then set flag to start ADC process
	// also record ADC mode byte to select ADC and speed
	if( AdcReadCount )
	{
		if(  CacheCommand[CmdVnaSetDdsFlagsOfs] & CmdVnaSetDdsFlagsPauseDataOut )
			PauseDataOut = TRUE;
		if( CacheCommand[CmdVnaSetDdsFlagsOfs] & CmdVnaSetDdsFlagsPauseDataIn )
			PauseDataIn = TRUE;
		ReturnStatus |= AdcStartFlag;
		ReturnStatus &= ~AdcNotResponding;
		AdcMode = CacheCommand[CmdVnaSetAdcMode];
		// test code for mode override
		if( bOverrideMode )
		{
			AdcMode &= 0xf0;
			AdcMode |= ModeOverrideValue;
		}
		// end of test code
	}
	// clear timeout timer and flags
	AdcTimeStart = 0;
}

//-----------------------------------------------------------------------------
// Handle Sweep command by means of finite state machine
//-----------------------------------------------------------------------------
// SweepState takes following values
// 0 - idle
// 1 - set up for start of a sweep
// 2 - in the middle of a sweep

void SweepFSM()
{
	BYTE i;

	// wait until step delay is complete
	if( AdcReadDelay != 0 )
    	return;
	usecDelayWait();
	switch( SweepState )
	{
		case 1:
			// set the current frequency to the start of the sweep
			for(i=0;i<5;i++)
			{
				FreqLO[i] = CacheCommand[CmdVnaSweepLoOfs+i];
				FreqRF[i] = CacheCommand[CmdVnaSweepRfOfs+i];
			}
			// if we have been asked to pulse SW1, set it high
			if ( CacheCommand[CmdVnaSweepFlagsOfs] & CmdVnaSweepFlagsPulseSW1 )
				IOA |= bmSwitch1Pin;
			// read the sweep counter
			// NOTE - here and below we make use of byte storage order in a long
			SweepCount = *((unsigned long *)(&CacheCommand[CmdVnaSweepSteps]));
			// if count is zero, stop now. otherwise next state is 2
			SweepState = ( SweepCount ) ? 2 : 0;
			break;
		case 2:
			// now increment frequency and phase leaving control bits unchanged
			*((unsigned long *)&FreqLO[1]) += *((unsigned long *)&CacheCommand[CmdVnaSweepLoStepOfs+1]); 
			*((unsigned long *)&FreqRF[1]) += *((unsigned long *)&CacheCommand[CmdVnaSweepRfStepOfs+1]);
 		    FreqLO[0] = (((FreqLO[0] & 0xF8) + CacheCommand[CmdVnaSweepLoStepOfs])&0xf8) + (CacheCommand[CmdVnaSweepLoOfs] & 7 );
 		    FreqRF[0] = (((FreqRF[0] & 0xF8) + CacheCommand[CmdVnaSweepRfStepOfs])&0xf8) + (CacheCommand[CmdVnaSweepRfOfs] & 7 );
			if( (CacheCommand[CmdVnaSweepFlagsOfs] &CmdVnaSweepFlagsPowerDownBetween) && (SweepCount == 0 ))
			{
				FreqRF[0] |= 4;
				FreqLO[0] |= 4;
			}
			// end of sweep? if so go back to state 1 otherwise set up timer for next step delay
			if( SweepCount-- == 0 )
			{
				if ( CacheCommand[CmdVnaSweepFlagsOfs] & CmdVnaSweepFlagsPulseSW1 )
					IOA &= ~bmSwitch1Pin;
				SweepState = 1;
			}
	}
	// and set the DDS to the new frequencies
	SetDDS( &FreqLO[0], &FreqRF[0] );
   	IOA |= bmFQUDDdsPin;
   	IOA  &= ~ bmFQUDDdsPin;
	// stop timer 0 in case running and clear "done" flag
	TR0 = 0;
	TF0 = 0;
	i = SweepState == 2 ? CacheCommand[CmdVnaSweepStepDelOfs] : CacheCommand[CmdVnaSweepInitDelOfs];
	// set up for either short (timer) delay or long (counter tick) delay
	if(  CacheCommand[CmdVnaSweepFlagsOfs] & (SweepState == 2 ? CmdVnaSweepFlagsStepDelayIsUsec : CmdVnaSweepFlagsInitDelayIsUsec))
	{
		// short delay. Set long counter to zero, set up timer 0 for usec delay
		// we reduse ADC timer as that is what the timer process uses
		AdcReadDelay = 0;
		// set timer 0 for short delay and start timer
		// 48 MHz clock, divide by 12 => 4MHz timer clock
		// low order 5 bits (TL0) mean each count in high
		// order byte is 8 usec. Therefore count up to FF in these units
		TH0 = ~i;
		TL0 = 0;
		// start timer
		TR0 = 1;
	}
	else // long delay.
		AdcReadDelay = i;
}

//-----------------------------------------------------------------------------
// Ivan's double conversion needs a little finite stae machine to make it work.
// states are:
// 0 - nothing to do - idle
// 1 - waiting for ADC conversion to start, then whilst we are waiting for it to finish, send next data to DDS
// 2 - when ADC conversion has completed, pulse FQUD to set DDS, then start another ADC conversion sequence
// 3 - when the ADC is running again, set the finite state machine to idle
//-----------------------------------------------------------------------------

void  handle_double_convert(void)
{
	switch( DoubleConvertState )
	{
		case 1:
			if( bAdcConverting )
			{
			  DoubleConvertState = 2;
			  SetDDS( &CacheCommand[CmdVnaSetDdsLoOfs2], &CacheCommand[CmdVnaSetDdsRfOfs2] );
			}
			break;
		case 2:
			if( !bAdcConverting )
			{
			    // used to load 40 bits of data to each DDS using FQ_UD pin
				// now this step is done in ADC conversion to make it happen
				// at start of read of last ADC conversion in each group
 //           	IOA |= bmFQUDDdsPin;
 //         	IOA  &= ~ bmFQUDDdsPin;
				Startup_Adc( 0 );
				bAdcConverting = TRUE;
				ReturnStatus &= ~AdcDataReady;
			    DoubleConvertState = 3;
			}
			break;
		case 3:
			if( !bAdcConverting )
			    DoubleConvertState = 0;
	}
}


//-----------------------------------------------------------------------------
// there are three copies of this routine for speed. One for ADC1 and one for ADC2, plus one for both.
//-----------------------------------------------------------------------------

void handle_adc1(void)             // Called repeatedly while the device is idle
{
	BYTE i,j,k,n;

	// see if an ADC start is pending
	if( ReturnStatus & AdcStartFlag )
	{
		// case 1 - we have just tried to abort a sequence and now need to start conversion 
		// case 2 - we previously finished a conversion with this ADC - CS is low and Clk is high
		//          so the ADC is being held ready to convert when we drop the clock line
		//          cater for both by raising CS, lowering clock and lowering CS
		if( ((IOB & bmADC1CsPin ) == 0) && ((IOB & bmADCnSClkPin) != 0 ))
		{
			// stop the other ADC (will probably cause an immediate conversion - sort it out later
			IOB |= bmADC2CsPin;
			// handle post DDS delay if one is requested
			if( AdcReadDelay != 0 )
	   			return;
			usecDelayWait();
			IOB |= bmADC1CsPin;
			IOB &= ~bmADCnSClkPin;
			IOB &= ~bmADC1CsPin;
			AdcCompleteStartup();
			// make sure SDO is high (ie ADC is converting )
			if( ( IOA & bmADC1SdoPin ) != 0 )
				ReturnStatus |= AdcNotResponding;
			return;
		}
		// case 3 - CS was high so either startup condition or ADC was being held whilst other was used
		//          or of course it could be a fault condition. Either way set both low and proceed as fro case 4
		else if( IOB & bmADC1CsPin )
		{
			IOB &= ~bmADCnSClkPin;
			IOB &= ~bmADC1CsPin;
		}
		// case 4 - may be case 3 from above or CS and clk may both have been low
		//          if we were converting on ADC then see if it is ready. Wait until SDI goes low
		//          but if we timeout, just try resetting anyway - we'll discover the fault
		//          when we try to get the result (might as well be an optimist :-) )
		if( (IOA & bmADC1SdoPin) == 0 )
		{
			if( AdcTimeStart <= 3 )
				return;
		}
		// ok, so SDI is low - we are probably in data IO phase. Clock it 5 times then make it a case 2
		// and case 2 will pulse CS high then low to start conversion as normal
		clock_adc_5_times();
		return;
	}

	// otherwise, have we more readings to collect?
	else if( AdcReadCount )
	{
		// check for and handle ADC input
		if( ( IOA & bmADC1SdoPin ) != 0 )
		{
			if( DoubleConvertState == 2 && AdcReadCount == 1 )
			{
				IOA |= bmFQUDDdsPin;
				IOA  &= ~ bmFQUDDdsPin;
			}
			// set mask to get bits of ADC mode for ltc2440
			n = 0x10;
#ifdef USEAUTOPTRFORADCRESULTS
			AUTOPTRH2 = MSB( &AdcInData[AdcReadsDone][0] );
			AUTOPTRL2 = LSB( &AdcInData[AdcReadsDone][0] );
#endif
			// 4 bytes of data (32 bits)
			for( i=0; i<4; i++)
			{
				// no need to clear next byte to start with (shift data in)
				// AdcInData[i] = 0;
				// step thru each bit of data
				// use variable k to accumulate byte of data
				for( j=0; j<8; j++)
				{
					// in case this is an ltc2440, shift out mode on SDI pin
					// only do this for the first 5 bits
					// 23-05-06 change
					// when doing exeter I found that if SDI bit was left high
					// it caused problems so pulled low when OSR has been sent.
					IOA &= ~bmAdcSdiPin;
					if( n ) 
					{
						if( AdcMode & n )
							IOA |= bmAdcSdiPin;
						n >>= 1;
					}
					// set clock high
					IOB |= bmADCnSClkPin;
					// shift left ready for next bit
					k <<= 1;
					// read data bit
					if(  ( IOA & bmADC1SdoPin ) == 0 )
						k |= 1;
					// and set clock low again unless this is the last bit
					if( (j!=7) || (i!=3) )
						IOB &= ~bmADCnSClkPin;
				}
#ifdef USEAUTOPTRFORADCRESULTS
				EXTAUTODAT2 = k;
#else
				AdcInData[AdcReadsDone][i] = k;
#endif
			}
			adc_tail();
		}
		// idle too long? give up!
		else if( AdcTimeStart  > 3 )
			AdcTimeout();
	}
}

//-----------------------------------------------------------------------------
// simple utility to wait until usec timer times out then stop it
//-----------------------------------------------------------------------------

void usecDelayWait( void )
{
	if( TR0 )
		while( TF0 == 0 )
			;
	TR0 = 0;
	TF0 = 0;
}

//-----------------------------------------------------------------------------
// simple utility complete ADC startup (common code block shared to save space)
//-----------------------------------------------------------------------------

void AdcCompleteStartup()
{
	// next time round go check for completion of ADC conversion
	ReturnStatus &= ~( AdcStartFlag );
	// reset timeout counter for next timeout period
	AdcTimeStart = 0;
	// flag fact that ADC is running for double conversion state machine
	bAdcConverting = TRUE;
	// small delay to allow settling of SDO line
	SYNCDELAY;
}

//-----------------------------------------------------------------------------
// simple utility to complete ADC readings (common block to save space)
//-----------------------------------------------------------------------------

void adc_tail(void)
{
	// reset timeout timer for next conversion
	AdcTimeStart = 0;
	// update counters for conversion just done
	AdcReadsDone++;
	AdcReadCount--;
	//If there are more conversions to do restart immediately
	//otherwise stop, and restart sending data to PC in case it was suspended
	if( AdcReadCount )
		IOB &= ~bmADCnSClkPin;
	else
	{
		// flag fact that ADC is not running for double conversion state machine
		bAdcConverting = FALSE;
		PauseDataIn = FALSE;
		ReturnStatus |= AdcDataReady;
	}
}

//-----------------------------------------------------------------------------
// simple utility to clock ADC 5 times leaving clock high
//-----------------------------------------------------------------------------

void clock_adc_5_times()
{
	IOB |= bmADCnSClkPin;
	IOB &= ~bmADCnSClkPin;
	IOB |= bmADCnSClkPin;
	IOB &= ~bmADCnSClkPin;
	IOB |= bmADCnSClkPin;
	IOB &= ~bmADCnSClkPin;
	IOB |= bmADCnSClkPin;
	IOB &= ~bmADCnSClkPin;
	IOB |= bmADCnSClkPin;
}

//-----------------------------------------------------------------------------
// this is the copy for ADC2
//-----------------------------------------------------------------------------

void handle_adc2(void)             // Called repeatedly while the device is idle
{
	BYTE i,j,k,n;

	// see if an ADC start is pending
	if( ReturnStatus & AdcStartFlag )
	{
		// case 1 - we have just tried to abort a sequence and now need to start conversion 
		// case 2 - we previously finished a conversion with this ADC - CS is low and Clk is high
		//          so the ADC is being held ready to convert when we drop the clock line
		//          cater for both by raising CS, lowering clock and lowering CS
		if( ((IOB & bmADC2CsPin ) == 0) && ((IOB & bmADCnSClkPin) != 0 ))
		{
			// stop the other ADC (will probably cause an immediate conversion - sort it out later
			IOB |= bmADC1CsPin;
			// handle post DDS delay if one is requested
			if( AdcReadDelay != 0 )
				return;
			usecDelayWait();
			IOB |= bmADC2CsPin;
			IOB &= ~bmADCnSClkPin;
			IOB &= ~bmADC2CsPin;
			AdcCompleteStartup();
			// make sure SDO is high (ie ADC is converting )
			if( ( IOB & bmADC2SdoPin ) != 0 )
				ReturnStatus |= AdcNotResponding;
			return;
		}
		// case 3 - CS was high so either startup condition or ADC was being held whilst other was used
		//          or of course it could be a fault condition. Either way set both low and proceed as fro case 4
		else if( IOB & bmADC2CsPin )
		{
			IOB &= ~bmADCnSClkPin;
			IOB &= ~bmADC2CsPin;
		}
		// case 4 - may be case 3 from above or CS and clk may both have been low
		//          if we were converting on ADC then see if it is ready. Wait until SDI goes low
		//          but if we timeout, just try resetting anyway - we'll discover the fault
		//          when we try to get the result (might as well be an optimist :-) )
		if( (IOB & bmADC2SdoPin) == 0 )
		{
			if( AdcTimeStart <= 3 )
				return;
		}
		// ok, so SDI is low - we are probably in data IO phase. Clock it 5 times then make it a case 2
		// and case 2 will pulse CS high then low to start conversion as normal
		clock_adc_5_times();
		return;
	}

	// otherwise, have we more readings to collect?
	else if( AdcReadCount )
	{
		// check for and handle ADC input
		if( ( IOB & bmADC2SdoPin ) != 0 )
		{
			if( DoubleConvertState == 2 && AdcReadCount == 1 )
			{
				IOA |= bmFQUDDdsPin;
				IOA  &= ~ bmFQUDDdsPin;
			}
 
#ifdef USEAUTOPTRFORADCRESULTS
			AUTOPTRH2 = MSB( &AdcInData[AdcReadsDone][0] );
			AUTOPTRL2 = LSB( &AdcInData[AdcReadsDone][0] );
#endif

			// set mask to get bits of ADC mode for ltc2440
			n = 0x10;
			// 4 bytes of data (32 bits)
			for( i=0; i<4; i++)
			{
				// no need to clear next byte to start with (shift data in)
				// AdcInData[i] = 0;
				// step thru each bit of data
				// use variable k to accumulate byte of data
				for( j=0; j<8; j++)
				{
					// in case this is an ltc2440, shift out mode on SDI pin
					// only do this for the first 5 bits
					// 23-05-06 change
					// when doing exeter I found that if SDI bit was left high
					// it caused problems so pulled low when OSR has been sent.
					IOA &= ~bmAdcSdiPin;
					if( n ) 
					{
						if( AdcMode & n )
							IOA |= bmAdcSdiPin;
						n >>= 1;
					}
					// set clock high (clocks SDI in and SDO out)
					IOB |= bmADCnSClkPin;
					// shift left ready for next bit
					k <<= 1;
					// read data bit
					if(  ( IOB & bmADC2SdoPin ) == 0 )
						k |= 1;
					// and set clock low again unless this is the last bit
					if(  (j!=7) || (i!=3)  )
						IOB &= ~bmADCnSClkPin;
				}
#ifdef USEAUTOPTRFORADCRESULTS
				EXTAUTODAT2 = k;
#else
				AdcInData[AdcReadsDone][i] = k;
#endif
			}
			adc_tail();
		}
		// idle too long? give up!
		else if( AdcTimeStart  > 3 )
			AdcTimeout();
	}
}

//-----------------------------------------------------------------------------
// this is the copy for simultaneous conversions on both ADCs
//-----------------------------------------------------------------------------

void handle_both_adcs(void)             // Called repeatedly while the device is idle
{
	BYTE i,j,k,n,m;

	// see if an ADC start is pending
	if( ReturnStatus & AdcStartFlag )
	{
		// case 1 - we have just tried to abort a sequence and now need to start conversion 
		// case 2 - we previously finished a conversion with this ADC - CS is low and Clk is high
		//          so the ADC is being held ready to convert when we drop the clock line
		//          cater for both by raising CS, lowering clock and lowering CS
		if( ((IOB & (bmADC1CsPin | bmADC2CsPin)) == 0) && ((IOB & bmADCnSClkPin) != 0 ))
		{
			// handle post DDS delay if one is requested
			if( AdcReadDelay != 0 )
				return;
			usecDelayWait();
			IOB |= (bmADC1CsPin | bmADC2CsPin);
			IOB &= ~bmADCnSClkPin;
			IOB &= ~( bmADC1CsPin | bmADC2CsPin);
			AdcCompleteStartup();
			// make sure SDO is high (ie ADC is converting )
			if( ( IOA & bmADC1SdoPin ) != 0 || ( IOB & bmADC2SdoPin ) != 0)
				ReturnStatus |= AdcNotResponding;
			return;
		}
		// case 3 - CS was high so either startup condition or ADC was being held whilst other was used
		//          or of course it could be a fault condition. Either way set both low and proceed as fro case 4
		else if( IOB & (bmADC2CsPin | bmADC1CsPin ))
		{
			IOB &= ~bmADCnSClkPin;
			IOB &= ~( bmADC1CsPin | bmADC2CsPin);
		}
		// case 4 - may be case 3 from above or CS and clk may both have been low
		//          if we were converting on ADC then see if it is ready. Wait until SDI goes low
		//          but if we timeout, just try resetting anyway - we'll discover the fault
		//          when we try to get the result (might as well be an optimist :-) )
		if( (IOB & bmADC2SdoPin) == 0 )
		{
			if( AdcTimeStart <= 3 )
				return;
		}
		// ok, so SDI is low - we are probably in data IO phase. Clock it 5 times then make it a case 2
		// and case 2 will pulse CS high then low to start conversion as normal
		clock_adc_5_times();
		return;
	}


	// otherwise, have we more readings to collect?
	else if( AdcReadCount )
	{
		// check for and handle ADC input
		if( (( IOB & bmADC2SdoPin ) != 0 ) && (( IOA & bmADC1SdoPin ) != 0 ))
		{
			if( DoubleConvertState == 2 && AdcReadCount == 1 )
			{
				IOA |= bmFQUDDdsPin;
				IOA  &= ~ bmFQUDDdsPin;
			}
			// set mask to get bits of ADC mode for ltc2440
			n = 0x10;
			// 4 bytes of data (32 bits)
			for( i=0; i<4; i++)
			{
				// no need to clear next byte to start with (shift data in)
				// AdcInData[i] = 0;
				// step thru each bit of data
				// use variable k,m to accumulate byte of data
				k = 0;
				m = 0;
				for( j = 0x80; j != 0; j >>= 1 )
				{
					// in case this is an ltc2440, shift out mode on SDI pin
					// only do this for the first 5 bits
					// 23-05-06 change
					// when doing exeter I found that if SDI bit was left high
					// it caused problems so pulled low when OSR has been sent.
					IOA &= ~bmAdcSdiPin;
					if( n ) 
					{
						if( AdcMode & n )
							IOA |= bmAdcSdiPin;
						n >>= 1;
					}
					// set clock high (clocks SDI in and SDO out)
					IOB |= bmADCnSClkPin;
					// wait for lines to settle
					SYNCDELAY;
					// read data bit
					if(  ( IOA & bmADC1SdoPin ) == 0 )
						k |= j;
					if(  ( IOB & bmADC2SdoPin ) == 0 )
						m |= j;
					// and set clock low again unless this is the last bit
					if(  (j!=1) || (i!=3)  )
					{
						IOB &= ~bmADCnSClkPin;
					}
				}
				AdcInData[AdcReadsDone][i] = k;
				AdcInData[AdcReadsDone+1][i] = m;
			}
			adc_tail();
			// double conversions - cheat - bump the counter so we added 2 to it overall
			AdcReadsDone++;
		}
		// idle too long? give up!
		else if( AdcTimeStart  > 3 )
			AdcTimeout();
	}
}

//-----------------------------------------------------------------------------
// This function handles all comms in to the PC
//-----------------------------------------------------------------------------

void handle_in(void)             // Called repeatedly while the device is idle
{
	BYTE j,k;

	// check EP6 EMPTY  bit in EP2468STAT (SFR), core set's this bit when FIFO is empty
	// do this to avoid double buffering
	//if((EP2468STAT & bmEP6EMPTY))
	// check EP6 FULL(busy) bit in EP2468STAT (SFR), core set's this bit when FIFO is full
	// do this for double buffering
	if(!(EP2468STAT & bmEP6FULL))
	{
		AUTOPTRH2 = MSB( &EP6FIFOBUF );
		AUTOPTRL2 = LSB( &EP6FIFOBUF );
		AUTOPTR1H = MSB( &AdcInData );
		AUTOPTR1L = LSB( &AdcInData );

		// put last command into response
		EXTAUTODAT2 = LastCommand;
		// signal whether we thought VNA power was present
		if( IOB & bmVNAPower )
			ReturnStatus &= ~VnaNoPower;
		else
			ReturnStatus |= VnaNoPower;
		// put return status flags and current IO ports into reply 
		// plus number of ADC reads completed
		EXTAUTODAT2 = ReturnStatus;
		EXTAUTODAT2 = IOA;
		EXTAUTODAT2 = IOB;
		EXTAUTODAT2 = AdcReadsDone;
		// If a sequence of ADC reads is finished, copy output data to reply
		// then reset for next command
		if( ReturnStatus & AdcDataReady )
		{
			for( j= 4*AdcReadsDone; j>0; j--)
				EXTAUTODAT2 = EXTAUTODAT1; //AdcInData[j][i];
			k = 5+(4*AdcReadsDone);
			AdcReadsDone = 0;
			PauseDataOut = FALSE;
			ReturnStatus &= ~( AdcDataReady | AdcNotResponding);
		}
		else
			k = 5;        
		// arm EP6IN
//		SYNCDELAY;
		EP6BCH = 0;  
		SYNCDELAY;
		EP6BCL = k;
	}
}

//-----------------------------------------------------------------------------
// suspend and resume hooks - not used here
//-----------------------------------------------------------------------------

BOOL TD_Suspend(void)          // Called before the device goes into suspend mode
{
   return(TRUE);
}

BOOL TD_Resume(void)          // Called after the device resumes
{
   return(TRUE);
}

//-----------------------------------------------------------------------------
// An ADC function has timed out. Clear down all
// flags and timers to start again
//-----------------------------------------------------------------------------

void AdcTimeout()
{
	// flag fact that ADC is not running for double conversion state machine
	bAdcConverting = FALSE;
	AdcReadsDone = 0; 
	AdcReadCount = 0;
	PauseDataIn = FALSE;
	PauseDataOut = FALSE;
	AdcMode = 0;
	ReturnStatus |= AdcReadTimeout;
	ReturnStatus &= ~(AdcDataReady | AdcStartFlag );
}


//-----------------------------------------------------------------------------
// Device Request hooks
//   The following hooks are called by the end point 0 device request parser.
//-----------------------------------------------------------------------------

BOOL DR_GetDescriptor(void)
{
   return(TRUE);
}

BOOL DR_SetConfiguration(void)   // Called when a Set Configuration command is received
{
   Configuration = SETUPDAT[2];
   return(TRUE);            // Handled by user code
}

BOOL DR_GetConfiguration(void)   // Called when a Get Configuration command is received
{
   EP0BUF[0] = Configuration;
   EP0BCH = 0;
   SYNCDELAY;               // check is this needed?
   EP0BCL = 1;
   return(TRUE);            // Handled by user code
}

BOOL DR_SetInterface(void)       // Called when a Set Interface command is received
{
   AlternateSetting = SETUPDAT[2];
   return(TRUE);            // Handled by user code
}

BOOL DR_GetInterface(void)       // Called when a Set Interface command is received
{
   EP0BUF[0] = AlternateSetting;
   EP0BCH = 0;
   SYNCDELAY;               // check is this needed?
   EP0BCL = 1;
   return(TRUE);            // Handled by user code
}

BOOL DR_GetStatus(void)
{
   return(TRUE);
}

BOOL DR_ClearFeature(void)
{
   return(TRUE);
}

BOOL DR_SetFeature(void)
{
   return(TRUE);
}

BOOL DR_VendorCmnd(void)
{
	EP0BUF[0] = SETUPDAT[0];
	EP0BUF[1] = SETUPDAT[1];
	EP0BUF[2] = SETUPDAT[2];
	EP0BCH = 0;
	SYNCDELAY;               // check is this needed?
	EP0BCL = 3;
	return FALSE;
//	return(TRUE);
}


//-----------------------------------------------------------------------------
// USB Interrupt Handlers
//   The following functions are called by the USB interrupt jump table.
//-----------------------------------------------------------------------------

// Setup Data Available Interrupt Handler
void ISR_Sudav(void) interrupt 0
{
   GotSUD = TRUE;            // Set flag
   EZUSB_IRQ_CLEAR();
   USBIRQ = bmSUDAV;         // Clear SUDAV IRQ
}

// Setup Token Interrupt Handler
void ISR_Sutok(void) interrupt 0
{
   EZUSB_IRQ_CLEAR();
   USBIRQ = bmSUTOK;         // Clear SUTOK IRQ
}

void ISR_Sof(void) interrupt 0
{
   EZUSB_IRQ_CLEAR();
   USBIRQ = bmSOF;            // Clear SOF IRQ
}

void ISR_Ures(void) interrupt 0
{
   // whenever we get a USB reset, we should revert to full speed mode
   pConfigDscr = pFullSpeedConfigDscr;
   ((CONFIGDSCR xdata *) pConfigDscr)->type = CONFIG_DSCR;
   pOtherConfigDscr = pHighSpeedConfigDscr;
   ((CONFIGDSCR xdata *) pOtherConfigDscr)->type = OTHERSPEED_DSCR;
   
   EZUSB_IRQ_CLEAR();
   USBIRQ = bmURES;         // Clear URES IRQ
}

void ISR_Susp(void) interrupt 0
{
   Sleep = TRUE;
   EZUSB_IRQ_CLEAR();
   USBIRQ = bmSUSP;
}

void ISR_Highspeed(void) interrupt 0
{
   if (EZUSB_HIGHSPEED())
   {
      pConfigDscr = pHighSpeedConfigDscr;
      ((CONFIGDSCR xdata *) pConfigDscr)->type = CONFIG_DSCR;
      pOtherConfigDscr = pFullSpeedConfigDscr;
      ((CONFIGDSCR xdata *) pOtherConfigDscr)->type = OTHERSPEED_DSCR;
   }

   EZUSB_IRQ_CLEAR();
   USBIRQ = bmHSGRANT;
}
void ISR_Ep0ack(void) interrupt 0
{
}
void ISR_Stub(void) interrupt 0
{
}
void ISR_Ep0in(void) interrupt 0
{
}
void ISR_Ep0out(void) interrupt 0
{
}
void ISR_Ep1in(void) interrupt 0
{
}
void ISR_Ep1out(void) interrupt 0
{
}
void ISR_Ep2inout(void) interrupt 0
{
}
void ISR_Ep4inout(void) interrupt 0
{
}
void ISR_Ep6inout(void) interrupt 0
{
}
void ISR_Ep8inout(void) interrupt 0
{
}
void ISR_Ibn(void) interrupt 0
{
}
void ISR_Ep0pingnak(void) interrupt 0
{
}
void ISR_Ep1pingnak(void) interrupt 0
{
}
void ISR_Ep2pingnak(void) interrupt 0
{
}
void ISR_Ep4pingnak(void) interrupt 0
{
}
void ISR_Ep6pingnak(void) interrupt 0
{
}
void ISR_Ep8pingnak(void) interrupt 0
{
}
void ISR_Errorlimit(void) interrupt 0
{
}
void ISR_Ep2piderror(void) interrupt 0
{
}
void ISR_Ep4piderror(void) interrupt 0
{
}
void ISR_Ep6piderror(void) interrupt 0
{
}
void ISR_Ep8piderror(void) interrupt 0
{
}
void ISR_Ep2pflag(void) interrupt 0
{
}
void ISR_Ep4pflag(void) interrupt 0
{
}
void ISR_Ep6pflag(void) interrupt 0
{
}
void ISR_Ep8pflag(void) interrupt 0
{
}
void ISR_Ep2eflag(void) interrupt 0
{
}
void ISR_Ep4eflag(void) interrupt 0
{
}
void ISR_Ep6eflag(void) interrupt 0
{
}
void ISR_Ep8eflag(void) interrupt 0
{
}
void ISR_Ep2fflag(void) interrupt 0
{
}
void ISR_Ep4fflag(void) interrupt 0
{
}
void ISR_Ep6fflag(void) interrupt 0
{
}
void ISR_Ep8fflag(void) interrupt 0
{
}
void ISR_GpifComplete(void) interrupt 0
{
}
void ISR_GpifWaveform(void) interrupt 0
{
}



