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

/** I N C L U D E S **********************************************************/
#include <p18cxxx.h>
#include <usart.h>
#include "system\typedefs.h"
#include "stdio.h"
#include "delays.h"
#include "system\usb\usb.h"

#include "io_cfg.h"             // I/O pin mapping
#include "user\user.h"

/** V A R I A B L E S ********************************************************/
#pragma udata

char input_buffer[64];
char output_buffer[64];
char out_ptr;
char Buffer;


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



/** 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 send_9854Freq(void); 	// IQPro update


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

#define	TPin		LATAbits.LATA5		// Test Pin

#pragma code
void UserInit(void)
{

    CMCON = 0x07;
	CVRCON = 0x00;
	ADCON0 = 0x00;
	ADCON1 = 0x0F;
    // Make all of PORTA digital output
    LATA = 0x00;
    TRISA = 0x00;
	// Make all of PORTB an output
	LATB = 0xFF;
	TRISB = 0x00;
	

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

	  // Test for specific device
	  if (input_buffer[4]< 2)
	  {
	    // send control word to DDS30 or DDS60
	    DDSx0();
	   }else{

		// Process AD 9854 initalization and freq update
		if (first_time) // if true set up AD9854
			{
			first_time = FALSE;
			AD9854Int();

			}else{

			// send control word to IQPro / AD 9854
			send_9854Freq();
			}// end of first time test
	   }// end of AD type 

	}//bytesIN

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

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

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

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

	
		Buffer = input_buffer[4];             //Control word
		output_buffer[4] = Buffer;			
		SPIleast(); 	// Sends data LSB out PortB.7; clocked by PortB.6


		//LATAbits.LATA2 = 1;		//Latch Freq word into DDS
		DDS_ioud = 1;		//Latch Freq word into DDS
 		Delay100TCYx(200);

		//LATAbits.LATA2 = 0;		//Clear Latch
		DDS_ioud = 0;		     	//Clear Latch
	    
		// Send result back to PC
		if(mUSBUSARTIsTxTrfReady())
	        {

				mUSBUSARTTxRam((byte*)output_buffer,5); 
			}
}// 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

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

  Buffer >>= 1;

  //Delay100TCYx(10); 

  } //end of for loop
 
}// end of SPIlike

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

  Delay100TCYx(10);

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

  Delay100TCYx(10); 

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

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


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