//==================================================================
//=====							       =====
//=====            VHF Source PIC Control Program              =====
//=====              By: Steve Hageman 29Dec98                 =====
//=====		      www.sonic.net/~shageman		       ===== 	
//=====							       =====	
//==================================================================
//=====	Copyright 1999, by Steven C. Hageman, This code can be =====
//===== used only for private use with the VHF Source hardware =====
//===== as described in the Jan, 2000 QEX article.	       =====
//===== All other rights reserved by Steven C. Hageman, 1999   =====
//==================================================================
//=====      Written in CCS C PCM Compiler Version 2.685       =====
//==================================================================
//=====  Ver: 0.0 - Initial Writing - 29Dec98                  =====
//=====  Ver: 1.0 - Initial Release - 11Oct99                  =====
//==================================================================


//-----< Initilization code >---------------------------------------
#define VER	10 	// Firmware Version 
			// xxy -> xx = Major, y = Minor (base 10)  


//-----< Include Files >-----
#include <16c63.h>
#include <stdio.h>


//-----< Initilize all RAM >-----
#ZERO_RAM


//-----< Compiler use statements >-----
#use delay(clock=10000000, RESTART_WDT) 			
#use rs232(baud=19200, xmit=PIN_C6, rcv=PIN_C7, RESTART_WDT) // Hardware UART
#fuses HS, WDT, NOPROTECT, PUT, BROWNOUT

// For peek and poke (use set_tris() to get tris registers back 
// to the way they need to be)
#use standard_io(A)
#use standard_io(B)
#use standard_io(C)


//-----< General Program Defines >-----
#define DOOMSDAY	0	// Not here yet!
#define OFF		0	// Used for pin i/o
#define ON		1	// Used for pin i/o
#define FULL		0	// Used by RS232 xmit register (98h, bit1)
#define RX_TIME_OUT	254	// Counter value for RS232 RX timeout


//-----< Port location defines >-----
#pragma byte port_a = 0x05
#pragma byte port_b = 0x06
#pragma byte port_c = 0x07


//-----< Pin defines >-----
#pragma bit DEBUG_1	= port_a.0	// Reserved for Debug 1 pin
#pragma bit DEBUG_2	= port_a.1	// Reserved for Debug 2 pin
#pragma bit EN_RES_3	= port_a.2	// Reserved for future use	
#pragma bit EN_RES_1	= port_a.3	// Reserved for future use
#pragma bit ADDRESS_0	= port_a.4	// Address low bit input
#pragma bit ADDRESS_1	= port_a.5	// Address hi bit input

#pragma bit LOCK_0 	= port_b.0	// PLL 0 Lock Input (1 = Locked)
#pragma bit LOCK_1 	= port_b.1	// PLL 1 Lock Input (1 = Locked)
#pragma bit RES_0 	= port_b.2	// Reserved for future use     
#pragma bit LEVEL	= port_b.3	// Output leveling loop input (0 = Leveled)       
#pragma bit RES_1	= port_b.4	// Reserved for future use
#pragma bit RES_2	= port_b.5	// Reserved for future use           
#pragma bit CLK		= port_b.6	// Internal serial clock line
#pragma bit DATA     	= port_b.7	// Internal serial data line

#pragma bit EN_DAC	= port_c.0	// Output level DAC enable
#pragma bit TXFR_NCO	= port_c.1	// Enable data transfer in NCO
#pragma bit EN_NCO	= port_c.2	// NCO serial transfer enable
#pragma bit EN_PLL_0	= port_c.3	// PLL 0 Enable
#pragma bit EN_PLL_1	= port_c.4	// PLL 1 Enable
#pragma bit EN_RES_2	= port_c.5	// Reserved for future use


//-----< Global Variables >-----

//.....General
int MyAddress;		// This PIC's Device address (read at startup)

//.....PLL's (Numbered 0 - 1  for pll 0 and 1)
long R_Counter[2];	// Valid values 1 or 5 to 8191
long N_Counter[2];	// Valid values 5 to 4095 (N >= A)
int  A_Counter[2];	// Valid values 0 to 63   (N >= A)
long Output_Level;	// Valid values are from 0 to 4095 (12 bits)


//-----< RS232 Packet definitions >-----
int RX_Packet_Ready;		// TRUE If a receive packet is ready

//.....RX Packet from PC
struct
{
	byte Address;		// The command address
	byte Command[2]; 	// Two Command ID Bytes
	byte Data[4];		// Four Data Bytes
} ReceivePacket;

//.....TX Packet to PC
struct 
{
	byte Identifier;	// ID of packet
	byte Data[2];		// Two Data Bytes
} TransmitPacket;


//=====< General routines >===============================================

// Note: Peek and Poke may mess up TRIS registers because they operate
// as 'standard_io' and do what you ask them to do!
// Call set_tris to reset the TRIS registers to how this program needs them!

// Peek at a pin, return the value
int peek(int pin_num)
{
	switch (pin_num)
	{
		//...Port A
		case PIN_A0:
		{
			return( (int)input( PIN_A0 ) );
			break;
		}
		case PIN_A1:
		{
			return( (int)input( PIN_A1 ) );
			break;
		}
		case PIN_A2:
		{
			return( (int)input( PIN_A2 ) );
			break;
		}
		case PIN_A3:
		{
			return( (int)input( PIN_A3 ) );
			break;
		}
		case PIN_A4:
		{
			return( (int)input( PIN_A4 ) );
			break;
		}
		case PIN_A5:
		{
			return( (int)input( PIN_A5 ) );
			break;
		}

		//... Port B
		case PIN_B0:
		{
			return( (int)input( PIN_B0 ) );
			break;
		}
		case PIN_B1:
		{
			return( (int)input( PIN_B1 ) );
			break;
		}
		case PIN_B2:
		{
			return( (int)input( PIN_B2 ) );
			break;
		}
		case PIN_B3:
		{
			return( (int)input( PIN_B3 ) );
			break;
		}
		case PIN_B4:
		{
			return( (int)input( PIN_B4 ) );
			break;
		}
		case PIN_B5:
		{
			return( (int)input( PIN_B5 ) );
			break;
		}
		case PIN_B6:
		{
			return( (int)input( PIN_B6 ) );
			break;
		}
		case PIN_B7:
		{
			return( (int)input( PIN_B7 ) );
			break;
		}

		//... Port C
		case PIN_C0:
		{
			return( (int)input( PIN_C0 ) );
			break;
		}
		case PIN_C1:
		{
			return( (int)input( PIN_C1 ) );
			break;
		}
		case PIN_C2:
		{
			return( (int)input( PIN_C2 ) );
			break;
		}
		case PIN_C3:
		{
			return( (int)input( PIN_C3 ) );
			break;
		}
		case PIN_C4:
		{
			return( (int)input( PIN_C4 ) );
			break;
		}
		case PIN_C5:
		{
			return( (int)input( PIN_C5 ) );
			break;
		}
		case PIN_C6:
		{
			return( (int)input( PIN_C6 ) );
			break;
		}
		case PIN_C7:
		{
			return( (int)input( PIN_C7 ) );
			break;
		}
	}
}

// Poke a pin with state
void poke(int pin_num, int state)
{
	// Value was out of range, Don't do anything
	if ( state > 1 )
		return;
	
	switch (pin_num)
	{
		//...Port A
		case PIN_A0:
		{
			output_bit( PIN_A0, state );
			break;
		}
		case PIN_A1:
		{
			output_bit( PIN_A1, state );
			break;
		}
		case PIN_A2:
		{
			output_bit( PIN_A2, state );
			break;
		}
		case PIN_A3:
		{
			output_bit( PIN_A3, state );
			break;
		}
		case PIN_A4:
		{
			output_bit( PIN_A4, state );
			break;
		}
		case PIN_A5:
		{
			output_bit( PIN_A5, state );
			break;
		}

		//... Port B
		case PIN_B0:
		{
			output_bit( PIN_B0, state );
			break;
		}
		case PIN_B1:
		{
			output_bit( PIN_B1, state );
			break;
		}
		case PIN_B2:
		{
			output_bit( PIN_B2, state );
			break;
		}
		case PIN_B3:
		{
			output_bit( PIN_B3, state );
			break;
		}
		case PIN_B4:
		{
			output_bit( PIN_B4, state );
			break;
		}
		case PIN_B5:
		{
			output_bit( PIN_B5, state );
			break;
		}
		case PIN_B6:
		{
			output_bit( PIN_B6, state );
			break;
		}
		case PIN_B7:
		{
			output_bit( PIN_B7, state );
			break;
		}

		//... Port C
		case PIN_C0:
		{
			output_bit( PIN_C0, state );
			break;
		}
		case PIN_C1:
		{
			output_bit( PIN_C1, state );
			break;
		}
		case PIN_C2:
		{
			output_bit( PIN_C2, state );
			break;
		}
		case PIN_C3:
		{
			output_bit( PIN_C3, state );
			break;
		}
		case PIN_C4:
		{
			output_bit( PIN_C4, state );
			break;
		}
		case PIN_C5:
		{
			output_bit( PIN_C5, state );
			break;
		}
		case PIN_C6:
		{
			output_bit( PIN_C6, state );
			break;
		}
		case PIN_C7:
		{
			output_bit( PIN_C7, state );
			break;
		}
	}
}


// Resets the TRIS registers
void set_tris()
{
	//----- Setup Ports / Unused pins are set to output
	set_tris_a(0b00110000);	// Mixed I/O
	set_tris_b(0b00001011);	// Mixed I/O
	set_tris_c(0b10000000);	// RS232 port and Mixed I/O	
	port_b_pullups(FALSE);	// OFF (Not needed for this application)
}


//=====< Hardware Control Subroutines >===================================

//-----< Initilize the C register of both PLL's >-----
void initilize_pll(void)
{

	// Setup pins
	CLK = 0;
	DATA = 0;
	EN_PLL_0 = 1;
	EN_PLL_1 = 1;

	//..... First setup the PLL's
	// 5 clocks
	EN_PLL_0 = 0;
	EN_PLL_1 = 0;
	CLK = 1;	// 1
	CLK = 0;
	CLK = 1;	// 2
	CLK = 0;
	CLK = 1;	// 3
	CLK = 0;
	CLK = 1;	// 4
	CLK = 0;
	DATA = 1;
	CLK = 1;	// 5
	EN_PLL_0 = 1;
	EN_PLL_1 = 1;
	CLK = 0;
	DATA = 0;
	EN_PLL_0 = 0;
	EN_PLL_1 = 0;
	
	// 5 Clocks
	CLK = 1;	// 1
	CLK = 0;
	CLK = 1;	// 2
	CLK = 0;
	CLK = 1;	// 3
	CLK = 0;
	CLK = 1;	// 4
	CLK = 0;
	DATA = 1;
	CLK = 1;	// 5
	EN_PLL_0 = 1;
	EN_PLL_1 = 1;
	CLK = 0;
	DATA = 0;
	EN_PLL_0 = 0;
	EN_PLL_1 = 0;
	
	// 5 Clocks, this time w/o the DATA going high	
	CLK = 1;	// 1
	CLK = 0;
	CLK = 1;	// 2
	CLK = 0;
	CLK = 1;	// 3
	CLK = 0;
	CLK = 1;	// 4
	CLK = 0;
	CLK = 1;	// 5
	EN_PLL_0 = 1;
	EN_PLL_1 = 1;
	CLK = 0;

	//..... Now setup C reg
	EN_PLL_0 = 0;
	EN_PLL_1 = 0;
	
	// C7 - POL of PD
	DATA = 1;
	CLK = 1;
	CLK = 0;
	
	// C6 - PD A
	DATA = 1;
	CLK = 1;
	CLK = 0;
	
	// C5 - Lock Detect
	DATA = 1;
	CLK = 1;
	CLK = 0;
	
	// C4 - Standby
	DATA = 0;
	CLK = 1;
	CLK = 0;
	
	// C3/2 - I2 & I1
	DATA  = 1;
	CLK = 1;
	CLK = 0;
	CLK = 1;
	CLK = 0;
	
	// C1 - Port Select
	DATA = 1;
	CLK = 1;
	CLK = 0;
	
	// C0 - Output B -> High Z
	DATA = 1;
	CLK = 1;
	CLK = 0;

	EN_PLL_0 = 1;
	EN_PLL_1 = 1;
	
	// Now C reg is setup
		
}


//-----< Set the R register of the specified PLL >-----
void pll_r_reg(int pll_num)
{
// Note: R Reg Globals must be set with the proper values before
// using this routine.
// R registers (Valid values are 1 and 5 to 8191)
// Note: pll_num can be 0-1.

int ctr;
long reg_value;

	// Clock must be low before moving the enables
	CLK = 0;

	// Select proper PLL
	switch(pll_num)
	{
		case 0:
		{
			EN_PLL_0 = 0;
			break;
		}
		case 1:
		{
			EN_PLL_1 = 0;
			break;
		}
		
		// Default of this switch is for nothing to happen
		default: return;
	}
	
	// OR the ref osc mode to the first 3 MSB's
	// 0x4000 sets the mode to Reference Mode, Ref_out = low
	// 0x6000 sets the mode to Reference Mode, Ref_out = Ref_in
	reg_value = R_Counter[pll_num] | 0x6000;

	// Shift out 16 R reg bits
	for( ctr = 0 ; ctr <= 15 ; ctr++)
	{
		// Decompose the PLL R value into bits, set data pin
		DATA = shift_left(&reg_value, 2, 0);
		
		// Cycle the clock
		CLK = 1;
		CLK = 0;	
	}

	// Pull enables high
	// Clock must be low before moving the enables
	CLK = 0;
	EN_PLL_0 = 1;
	EN_PLL_1 = 1;
	
	// Now to update and start counting with new R ratio
	switch(pll_num)
	{
		case 0:
		{
			EN_PLL_0 = 0;
			break;
		}
		case 1:
		{
			EN_PLL_1 = 0;
			break;
		}
		
		// No default needed here, it was taken care of earlier
	}
	 
	// Pull enables high
	// Clock must be low before moving the enables
	CLK = 0;
	EN_PLL_0 = 1;
	EN_PLL_1 = 1;
}


//-----< Set the A, N and OUTPUT_A Register of the specified PLL >-----
void update_pll(int pll_num)
{
// Note: A and N Register Globals must be set with the proper 
// values before using this routine.
// N registers (Valid values are 5 to 4095 and N >= A)
// A registers (Valid values are 0 to 63 and N >= A)
// Note: pll_num can be 0-1.
int ctr;
long reg_value;

	// Clock must be low before moving the enables
	CLK = 0;

	// Select proper PLL
	switch(pll_num)
	{
		case 0:
		{
			EN_PLL_0 = 0;
			break;
		}
		case 1:
		{
			EN_PLL_1 = 0;
			break;
		}
		
		// Default of this switch is for nothing to happen
		default: return;
	}

	// Manually set the first 4 bits of the A register
	//... A23 and A22 are set to 1 so that output A is Fr
	DATA = 1;
	CLK = 1;
	CLK = 0;
	CLK = 1;
	CLK = 0;
	
	
	//... A21 and A20 must be set to 1
	DATA = 1;
	CLK = 1;
	CLK = 0;
	CLK = 1;
	CLK = 0;
	
	// Now shift in the N counter (3 bytes = 12 Bits)
	reg_value = N_Counter[pll_num];

	// First shift the first 4 bits out into nothing 
	// They don't exist.
	for( ctr = 0 ; ctr <= 3 ; ctr++)
	{
		shift_left(&reg_value, 2, 0);
	}	
	
	// Shift out the real 12 N reg bits
	for( ctr = 0 ; ctr <= 11 ; ctr++)
	{
		// Decompose the PLL N value into bits, set data pin
		DATA = shift_left(&reg_value, 2, 0);
		
		// Cycle the clock
		CLK = 1;
		CLK = 0;	
	}

	// Now shift in the A counter (2 bytes = 8 Bits)
	reg_value = (long) A_Counter[pll_num];

	// First shift the first 8 bits out into nothing 
	// They don't exist.
	for( ctr = 0 ; ctr <= 7 ; ctr++)
	{
		shift_left(&reg_value, 2, 0);
	}	
	
	// Shift out the real 8 A reg bits
	for( ctr = 0 ; ctr <= 7 ; ctr++)
	{
		// Decompose the PLL A value into bits, set data pin
		DATA = shift_left(&reg_value, 2, 0);
		
		// Cycle the clock
		CLK = 1;
		CLK = 0;	
	}
	
	// Pull enables high, This updates the 
	// A, R and N registers all at once!
	// Clock must be low before moving the enables
	CLK = 0;
	EN_PLL_0 = 1;
	EN_PLL_1 = 1;
}


//-----< Set NCO Frequency >-----
void set_nco(void)
{
// Note: Receive packet must be set with the proper values before
// using this routine.
int ctr, data_byte;
int bit_data;

	// Enable NCO frequency shift register
	EN_NCO = 0;

	// Shift in byte 0 (MSB first)
	for(data_byte = 0 ; data_byte <= 3 ; data_byte++)
	{
		bit_data = ReceivePacket.Data[data_byte];
	
		// Shift in the individual bits of the packet data
		for(ctr = 0 ; ctr <= 7 ; ctr++)
		{
			// Decompose the value into bits, set data pin
			DATA = shift_left(&bit_data, 1, 0);
		
			// Cycle the clock
			CLK = 1;
			CLK = 0;	
		}
	}

	// XFER Data to DDS chip output register
	TXFR_NCO = 0;
	TXFR_NCO = 1;
				
	// Clean up
	EN_NCO = 1;
	CLK = 0;
	DATA = 0;
}


//-----< Set Output Level >-----
set_output_level()
{
// Note: Valid values for the AD7543 are 0 to 4095 (12 bit DAC).
// Coding: 0=0 volts, 4095=+4.9988 volts output, 1 LSB = 1.2 mV.
// The AD7243 updates on the falling edge of the clock.
// The AD7243 ignores the first 4 bits of the data word.
// With LDAC low the DAC updates on the 16th bit sent.
// The AD7243 calls the enable pin SYNC (bar).
// The DAC word is set with the global variable Output_Level (Long).
int ctr;

	// Setup Clock
	CLK = 1;

	// Drop the DAC enable
	EN_DAC = 0;
	
	// Shift out 16 Output_Level reg bits
	for(ctr = 0 ; ctr <= 15 ; ctr++)
	{
		// Decompose the Output_Level value into bits, set data pin
		// Data is MSB first, the first 4 bits are don't cares
		DATA = shift_left(&Output_Level, 2, 0);
		
		// Cycle the clock
		CLK = 0;
		CLK = 1;	
	}

	// Pull DAC enable high
	EN_DAC = 1;

	// Set the clock low now
	CLK = 0;
}


//=====< RS232 Subroutines >==============================================

//-----< Get a RS232 input packet >-----
// Note: This routine is interrupt driven, RS232 input takes priority
// over every other operation in the system.

#INT_RDA	// Interrupt driven
void rs232_isr(void)
{
	// Reset the timer
	set_rtcc(0);
	
	// Get the receive packet  
	// NOTE: The getc's restart the WDT internally
	
	// Implement a timeout on waiting for a char

	// Address
	set_rtcc(0);
	while( kbhit() == FALSE )
	{
		if(get_rtcc() >= RX_TIME_OUT)
		{
			RX_Packet_Ready = FALSE;
			return;
		}
		restart_wdt();
	}	
	ReceivePacket.Address = getc();

	// Command 0
	set_rtcc(0);
	while( kbhit() == FALSE )
	{
		if(get_rtcc() >= RX_TIME_OUT)
		{
			RX_Packet_Ready = FALSE;
			return;
		}
		restart_wdt();
	}	
	ReceivePacket.Command[0] = getc();
	
	// Command 1
	set_rtcc(0);
	while( kbhit() == FALSE )
	{
		if(get_rtcc() >= RX_TIME_OUT)
		{
			RX_Packet_Ready = FALSE;
			return;
		}
		restart_wdt();
	}	
	ReceivePacket.Command[1] = getc();
	
	// Data 0
	set_rtcc(0);
	while( kbhit() == FALSE )
	{
		if(get_rtcc() >= RX_TIME_OUT)
		{
			RX_Packet_Ready = FALSE;
			return;
		}
		restart_wdt();
	}	
	ReceivePacket.Data[0] = getc();

	// Data 1
	set_rtcc(0);
	while( kbhit() == FALSE )
	{
		if( get_rtcc() >= RX_TIME_OUT)
		{
			RX_Packet_Ready = FALSE;
			return;
		}
		restart_wdt();
	}	
	ReceivePacket.Data[1] = getc();

	// Data 2
	set_rtcc(0);
	while( kbhit() == FALSE )
	{
		if( get_rtcc() >= RX_TIME_OUT)
		{
			RX_Packet_Ready = FALSE;
			return;
		}
		restart_wdt();
	}	
	ReceivePacket.Data[2] = getc();

	// Data 3
	set_rtcc(0);
	while( kbhit() == FALSE )
	{
		if( get_rtcc() >= RX_TIME_OUT)
		{
			RX_Packet_Ready = FALSE;
			return;
		}
		restart_wdt();
	}	
	ReceivePacket.Data[3] = getc();

	// If here then the full packet was received
	RX_Packet_Ready = TRUE;
}


//-----< Transmit a packet >------------------------------------------
void send_packet(void)
{
	// Just send the packet out, one byte at a time
	restart_wdt();
	putc(TransmitPacket.Identifier);
	restart_wdt();
	putc(TransmitPacket.Data[0]);
	restart_wdt();
	putc(TransmitPacket.Data[1]);
	restart_wdt();
}


//-----< Decode the receive packet >----------------------------------
void decode_rs232(void)
{
int pll_number;
	
	// Just to be safe, first things first...
	disable_interrupts(GLOBAL);
	restart_wdt();
	RX_Packet_Ready = FALSE;

	//===== Check for master bus reset =====
	// All connected instruments respond to this Address
	if( ReceivePacket.Address == 255 )
	{
	  if( ReceivePacket.Command[0] == 'M' )
	  {
	    if( ReceivePacket.Command[1] == '-' )
	    {
	      if( ReceivePacket.Data[0] == 'R' )
	      {
	        if( ReceivePacket.Data[0] == 'E' )
		{
		  if( ReceivePacket.Data[1] == 'S' )
		  {
		    if( ReceivePacket.Data[2] == 'E' )
		    {
		      if( ReceivePacket.Data[3] == 'T' )
		      {
		        // Long, but easy way to get to decoding
			// the global 'M-RESET' (Master Reset) command
			//....The path of no return
			#asm
			  goto 000
			#endasm
		      }
		    }
		  }
		}
	      }
	    }
	  }
	} // End of M-RESET command parser
	
		
	//===== Did the PC address me correctly, it's all very proper you know =====
	if( ReceivePacket.Address != MyAddress )
	{
		// Hey, you talking to me?
		// I guess not, so ta ta
		goto leave_town;
	} 
	
	// Set the local variables (This value may or may not be
	// needed later, but it is easy to set here)
	pll_number = ReceivePacket.Command[1];
	
	switch(ReceivePacket.Command[0])
	{
		//===== NCO Commands ====== 
		case 'N':
		{
			if(ReceivePacket.Command[1] == 'C')
			{
				// Set the NCO
				set_nco();
				break;
			}
			break;
		}

		//===== PLL Commands =====
		//... Get new N and A values, then update PLL specified
		case 'P':
		{
			// Get PLL Number
			pll_number = ReceivePacket.Command[1];

			// Get the N values		
			//... N registers (Valid values are 5 to 4095 and N >= A)
			N_Counter[pll_number] =   ReceivePacket.Data[1] * 256
				       	        + ReceivePacket.Data[2];	 
		
			// Get the A value		
			//... A registers (Valid values are 0 to 63 and N >= A)					
			A_Counter[pll_number] = ReceivePacket.Data[3];	 
			
			// Update the PLL specified
			update_pll(pll_number);
			
			break;
		}
		
		//... R registers (Valid values are 1 and 5 to 8191)
		// Note: The data[0] and data[1] packet are always 0 here.
		case 'R':
		{
			// Get PLL Number
			pll_number = ReceivePacket.Command[1];

			// Set the PLL # 'R' Register
			R_Counter[pll_number] =   ReceivePacket.Data[2] * 256
				                + ReceivePacket.Data[3];	 
		
			pll_r_reg(pll_number);
			break;
		}
		
		//===== Sig Gen Other Functions =====
		//... Set output leveling DAC (Valid values are 0 to 4095)
		// Note: data[0] and data[1] packet are always 0 here
		// Command[1] is not used
		case 'L':
		{
			Output_Level =   ReceivePacket.Data[2] * 256
				       + ReceivePacket.Data[3];
			set_output_level();
			break;
		}
		
		
		//... PLL Lock and output leveling Status
		case 'S':
		{
			TransmitPacket.Identifier = 'S';
			// The PLL's reeturn 1 = Locked
			TransmitPacket.Data[0] = LOCK_0 + LOCK_1*2;
			// The leveling loop returns 0 = leveled, so I
			// invert it here to be like the PLL's
			TransmitPacket.Data[1] = ~LEVEL & 0x01;
			send_packet();
			break;
		}			


		//===== Send firmware revision =====
		case 'V':
		{
			// Format is: 
			// V = Version information
			// Data 0 = Firmware Version
			// Data 1 = Current Address 
			//  	    ^ Redundant, as we must have 
			//            known to get this far
			TransmitPacket.Identifier = 'V';
			TransmitPacket.Data[0] = VER;
			TransmitPacket.Data[1] = MyAddress;
			send_packet();
			break;			
		}
		
		
		//===== Peek and Poke (IO) =====
		case 'I':
		{
			if( ReceivePacket.Command[1] == 'O' )
			{
				// I = Input or Peek				
				if( ReceivePacket.Data[0] = 'I' )
				{
					peek( ReceivePacket.Data[3] );
				}
				
				// O = Output or Poke
				if( ReceivePacket.Data[0] = 'O' )
				{
					// Pin number is Data[3]
					// State is Data[2] = 1 or 0 (Only!)
					poke( ReceivePacket.Data[3], ReceivePacket.Data[2]  );
				}
			
				// T = Tris reset
				if( ReceivePacket.Data[0] = 'T' )
				{
					set_tris();	
				}	
			}
			break;
		}
		
			
		//===== ID Hardware =====
		// Special case, send back a sequence of bytes to signify
		// that the RS232 is now syncronized. Also used to find
		// this hardware on a RS232 port.
		case '?': 
		{
			TransmitPacket.Identifier = 0b11111111; // 255 (0xff) - Always 255
			TransmitPacket.Data[0] = 0b00000000;	// 0   (0x00) - Always 0
			TransmitPacket.Data[1] = 0b10101010;	// 170 (0xaa) - Instrument type (170 = SigGen)
			// This last bit is used to identify the specific
			// hardware attached, in this case it is a Sig_Gen (0xaa)
			send_packet();
			break;
		}
	}
	
leave_town:

	// Note: This might be a good place to clear the UART receive buffer
	// but testing showed up no problems, so I left it out of the
	// code... SCH Dec98
	
	// Enable interrupts again
	enable_interrupts(GLOBAL);
}


//=====< Main >======================================================

void main(void)
{

	//----- Setup Ports / Unused pins are set to output
	set_tris();

	
	//----- Initilize critical ports & things
	restart_wdt();
	delay_ms(500);	// Let everything powerup correctly


	//----- Get the device address from the address switch 
	MyAddress = ADDRESS_0 + ADDRESS_1 * 2;


	//----- Initilize internal timer / counter 
	// At 10 MHz, div by 256 = 102 uS per count, 26 mSec F.S.
	// WDT will be 7-33 mSec
	setup_counters(RTCC_DIV_256, RTCC_INTERNAL);
	set_rtcc(0);


	//----- Initilize global variables
	RX_Packet_Ready = FALSE;

	
	//----- Initilize port pins
	// Initilize all output pins to a known state
	CLK = 0;
	DATA = 0;
	EN_DAC = 1;
	TXFR_NCO = 1;
	EN_NCO = 1;
	EN_PLL_0 = 1;
	EN_PLL_1 = 1;


	//----- Initilize Hardware
	//... Set the output level to about 0 dBm
	// This is about 3.397 Volts at DAC
	Output_Level = 2783; 
	set_output_level();
	
	//... Setup the PLL's
	initilize_pll();

	R_Counter[0] = 107;
	pll_r_reg(0);
	
	R_Counter[1] = 100;
	pll_r_reg(1);


	// Initilize the PLL's for an output frequency of 10 MHz
	// Set PLL_0 for 740 MHz
	// F = N*64+A * 0.1 MHz
	N_Counter[0] = 115;	
	A_Counter[0] = 40;
	update_pll(0);
	
	// Set PLL_1 for 750 MHz
	// F = N*64+A * 0.1 MHz
	N_Counter[1] = 117;	
	A_Counter[1] = 12;
	update_pll(1);

	
	//... Initilize the NCO to 10.7 MHz
	// These numbers are for a 40 MHz clock
	ReceivePacket.Data[0] = 68;
	ReceivePacket.Data[1] = 122;
	ReceivePacket.Data[2] = 225;
	ReceivePacket.Data[3] = 71;
	set_nco();
	
	restart_wdt();


	//----- Enable RS232 interrupts
	disable_interrupts(GLOBAL);	// Turn all off
	enable_interrupts(INT_RDA);	// Set the RS232 input interrupt
	enable_interrupts(GLOBAL);	// Now enable it

				
	//----- Main loop -----	
	while(!DOOMSDAY)
	{
		// Reset the WDT
		restart_wdt();
		
		// Just sit here cooling our jets
		if( RX_Packet_Ready == TRUE)
		{
			decode_rs232();
		}
			
							
	} // End of main loop			


} //----- End of main -----


//----- Fini -----
