/*******************************************************************************
 ** � Copyright 2012 - 2013 Xilinx, Inc. All rights reserved.
 ** This file contains confidential and proprietary information of Xilinx, Inc. and
 ** is protected under U.S. and international copyright and other intellectual property laws.
 *******************************************************************************
 **   ____  ____
 **  /   /\/   /
 ** /___/  \  /   Vendor: Xilinx
 ** \   \   \/
 **  \   \
**  /   /
 ** /___/    \
** \   \  /  \   7 Series FPGA AMS Targeted Reference Design
 **  \___\/\___\
**
 **  Device: xc7a200t
 **  Version: 1.2
 **  Reference:
 **
 *******************************************************************************
 **
 **  Disclaimer:
 **
 **    This disclaimer is not a license and does not grant any rights to the materials
 **    distributed herewith. Except as otherwise provided in a valid license issued to you
 **    by Xilinx, and to the maximum extent permitted by applicable law:
 **    (1) THESE MATERIALS ARE MADE AVAILABLE "AS IS" AND WITH ALL FAULTS,
 **    AND XILINX HEREBY DISCLAIMS ALL WARRANTIES AND CONDITIONS, EXPRESS, IMPLIED, OR STATUTORY,
 **    INCLUDING BUT NOT LIMITED TO WARRANTIES OF MERCHANTABILITY, NON-INFRINGEMENT, OR
 **    FITNESS FOR ANY PARTICULAR PURPOSE; and (2) Xilinx shall not be liable (whether in contract
 **    or tort, including negligence, or under any other theory of liability) for any loss or damage
 **    of any kind or nature related to, arising under or in connection with these materials,
 **    including for any direct, or any indirect, special, incidental, or consequential loss
 **    or damage (including loss of data, profits, goodwill, or any type of loss or damage suffered
 **    as a result of any action brought by a third party) even if such damage or loss was
 **    reasonably foreseeable or Xilinx had been advised of the possibility of the same.


 **  Critical Applications:
 **
 **    Xilinx products are not designed or intended to be fail-safe, or for use in any application
 **    requiring fail-safe performance, such as life-support or safety devices or systems,
 **    Class III medical devices, nuclear facilities, applications related to the deployment of airbags,
 **    or any other applications that could lead to death, personal injury, or severe property or
 **    environmental damage (individually and collectively, "Critical Applications"). Customer assumes
 **    the sole risk and liability of any use of Xilinx products in Critical Applications, subject only
 **    to applicable laws and regulations governing limitations on product liability.

 **  THIS COPYRIGHT NOTICE AND DISCLAIMER MUST BE RETAINED AS PART OF THIS FILE AT ALL TIMES.

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

/***************************** Include Files *********************************/

#include "xparameters.h"		/* Parameters file for hardware offsets and other utility files */
#include "xil_exception.h"
#include "xil_io.h"
#include "xstatus.h"
#include "stdio.h"

#include "xuartlite.h"			/* UART Lite driver */
#include "xuartlite_l.h"
#include "xspi.h"				/* SPI device driver */
#include "xspi_l.h"
#include "xsysmon.h"			/* System monitor driver */
#include "xbram.h"				/* BRAM Controller driver */
#include "xgpio.h"				/* GPIO driver */

//- Files specific to design
#include "register_map.h"		/* Register offset definitions */
#include "xadc_design_utils.h"		/* Utilities file */
#include "SineWaveSample.h"		/* File containing sine wave sample values */

/************************** Constant Definitions *****************************/
/*
 * The following constants map to the XPAR parameters created in the
 * xparameters.h file. They are defined here such that a user can easily
 * change all the needed parameters in one place.
 */
#define UARTLITE_DEVICE_ID      XPAR_UARTLITE_1_DEVICE_ID
#define SPI_DEVICE_ID			XPAR_SPI_0_DEVICE_ID
#define PMBUS_IIC_DEVICE_ID 	XPAR_AXI_IIC_0_DEVICE_ID
#define SYSMON_DEVICE_ID		XPAR_SYSMON_0_DEVICE_ID
#define BRAM_DEVICE_ID			XPAR_BRAM_0_DEVICE_ID
#define GPIO_EXAMPLE_DEVICE_ID 	XPAR_AXI_GPIO_0_DEVICE_ID

#define SPI_BASEADDR			XPAR_SPI_0_BASEADDR
#define UARTLITE_BASEADDR	   	XPAR_UARTLITE_1_BASEADDR
#define PMBUS_IIC_BASEADDR		XPAR_IIC_0_BASEADDR

#define UART_BUFFER_SIZE        16
#define DAC_WR_BUFFER_SIZE	    4

#define HIST_DATA_COUNT			4096		//- For 12-bit output, there would be 4096 bins
#define RAW_SAMPLE_CNT			4096		//- This is the FFT points
#define SINE_SAMPLES			4096		//- Number is sine wave samples for DAC programming
#define RAW_DATA_MEMORY_OFFSET	0x4000		//- Memory address offset from where data is stored
#define SINE_DATA_OFFSET  		0xB000		//- Memory address offset from where sine samples are stored
#define RAMP_COUNT				0x02
//- DAC specific macro definitions
#define DAC_SPI_SELECT          0x01
#define DAC_ADDRESS_A           0x0
#define DAC_ADDRESS_B           0x3
#define DAC_ADDRESS_A_B         0xF
#define DAC_WRITE_COMMNAD       0x03
#define DAC_RESET_COMMNAD       0x07


#define LED 					1

/**************************** Flags *******************************/
volatile static int EN_DAC_DC 			= FALSE;		//- Flag indicating DAC to generate DC
volatile static int EN_DAC_RAMP			= FALSE;		//- Flag indicating DAC to generate ramp
volatile static int DAC_RAMPING			= FALSE;
volatile static int RAMP_DOWN			= FALSE;
volatile static int EN_DAC_SINE 		= FALSE;		//- Flag indicating DAC to generate sine
volatile static int USE_UNIPOLAR_MODE 	= TRUE;		    //- Flag indicating uni-polar mode
volatile static int USE_BIPOLAR_MODE 	= FALSE;	    //- Flag indicating bi-polar mode
volatile static int USE_DIFFERENTIAL_MODE = FALSE;	    //- Flag indicating bi-polar mode
volatile static int USE_DAC_A 			= TRUE;	        //- Flag indicating DAC to be used
volatile static int USE_DAC_B 			= FALSE;	    //- Flag indicating DAC to be used
volatile static u16 DAC_A_DC_VALUE 		= 0x00FF;
volatile static u16 DAC_B_DC_VALUE 		= 0x00FF;
volatile static u8 CHANNEL_OPTION		= 0x01;		//- Single by default
volatile static int DECIMATION_FACTOR 	= 0;
volatile static int DAC_B_RAMPING		= 0x01;     //- Set this to 0x01 while using AMS FMC
volatile static int DAC_B_SINE_SRC		= 0x01;     //- Set this to 0x01 while using AMS FMC
volatile static int SINE_DC_OFFSET      = 0x3333;   //- DC Offset value for sine wave generated from DAC, 13107-unipolar, 6775-bipolar
volatile static int VN_OFFSET_VALUE     = 0x0;      //- Offset value for XADC's VN

/*
 * Design Version
 * 	[15:12] - Device Family
 * 				0001 - Artix, 0010 - Kintex, 0011 - Virtex
 * 	[11:8] - Major version number
 * 	[7:0]  - Minor version number
 */
u16 DESIGN_VERSION = 0x1120;

volatile static int EN_DEBUG	= FALSE;

/************************** Function Prototypes ******************************/
int UartLiteControl();

int initialize_peripherals(void);
int init_SysMon(XSysMon* SysMonInstPtr);
int SendOverUart(XUartLite* UartLite, u8 *SendBuffer, int NumBytes, int IsChar, int toASCII);
void SendNewLine();
void ProgramSampleRate(XSysMon* SysMonInstPtr, u8 DividerVal);
void SetChannelOption(XSysMon* SysMonInstPtr, u8 ChanOption);
void SetInputMode(XSysMon* SysMonInstPtr, u8 InputMode);
int SetSeqMode(XSysMon* SysMonInstPtr, u32 ChanMask, u32 SeqMode);

int CollectRawData(XSysMon* SysMonInstPtr, u32 StartAdrs, int NumSamples, int DecFactor);
int CollectRawData_DacSine(XSysMon* SysMonInstPtr, u32 StartAdrs, int NumSamples, int DecFactor);
int CollectRawData_SimulChan(XSysMon* SysMonInstPtr, u32 StartAdrs, int NumSamples, int DecFactor);
int CollectRawData_SimulChan_DacSine(XSysMon* SysMonInstPtr, u32 StartAdrs, int NumSamples, int DecFactor);
int CollectSensorData(XSysMon* SysMonInstPtr, u32 StartAdrs, int NumSamples);
int CollectShortData(XSysMon* SysMonInstPtr, u32 StartAdrs, int NumSamples);
int ReadBram_SendData(u32 StartAdrs, int NumBytes, int UartBurstSize, int IsHistogram);
int InitSpiDevice(u16 SpiDeviceId, XSpi *SpiInstancePtr);
int GenerateRamp(u16 SpiDeviceId, XSpi *SpiInstancePtr);
int GenerateSine(u16 SpiDeviceId, XSpi *SpiInstancePtr, u8 SineFrequency);
int GenerateFixedVoltage(u16 SpiDeviceId, XSpi *SpiInstancePtr, u16 DcValue, u8 SelDac);
int WriteDac(XSpi *SpiInstancePtr, u8 Command,u8 Addr, u16 Data);
int LoadBramWithSineSamples(void);
void CaptureDecimatedData(int DecFactor, int NumSamples, u32 StartAdrs);
void CaptureDecimatedData_DacSine(int DecFactor, int NumSamples, u32 StartAdrs);
int GetHistogram(XSysMon* SysMonInstPtr, u32 StartAdrs);
void InitializeBram(u32 Adrs);
void IncrementBram(u32 Adrs);

u8 ReadVoltage(u8 DevAdrs, u8 PageAdrs, u8 *RecvBuf);

u8 ReadCurrent(u8 DevAdrs, u8 PageAdrs, u8 *RecvBuf);
int ProgramVoltage(u8 DevAdrs, u8 PageAdrs, u8 *SendBufPtr, u8 Command);
int ReadExtSensorData(XSysMon* SysMonInstPtr, u8 DevAdrs, u8 PageAdrs, u8 *SendBufPtr);

/************************** Variable Definitions *****************************/

XUartLite 			UartLite;            		/* The instance of the UartLite Device */

XGpio 				Gpio; 						/* The Instance of the GPIO Driver */

XBram 				Bram;						/* The Instance of the BRAM Driver */
static XSpi  		SpiInstance;				/* Instance of SPI driver */
static XSysMon 		SysMonInst;					/* System Monitor driver instance */

volatile static int EocPoll = FALSE;	/* EOC interrupt */

static int dac_code = 0x00;
static int incr_size = 0x0;


u8 ReceiveBuffer[UART_BUFFER_SIZE];
u32 MemoryAdrs;

//- For W AAAA DDDD, it gets 12 characters including newline
volatile static int WR_RX_CNT = 12;
//- For R AAAA, it gets 7 characters including newline
volatile static int RD_RX_CNT = 7;

/******************************************************************************/
/**
*
* Main function to call the UartLite interrupt example.
*
* @param	None
*
* @return	XST_SUCCESS if successful, XST_FAILURE if unsuccessful
*
* @note		None
*
*******************************************************************************/
int main(void)
{
	int Status;

	Status = initialize_peripherals();
	print("\ncheck\n");
	if (Status != XST_SUCCESS) {
#ifdef ENABLE_DEBUG
		print("Peripheral Initialization Failure!\n");
#endif
		return XST_FAILURE;
	}
	print("\n**** XADC Evaluation Design ****\n");

//#ifdef ENABLE_DEBUG
		print("\n**** XADC Evaluation Design ****\n");
		print("\nPeripherals initialized\n");
//	}
//#endif

	Status = UartLiteControl();
	if (Status != XST_SUCCESS) {
		print("\nUartLite Failed\n");
		return XST_FAILURE;
	}
	return XST_SUCCESS;
}

/*
 * @note
 * This function receives the commands received over UART and calls corresponding functions
 * Command Format:
 * 		R AAAA for reads where 'A' indicates one nibble - specify all 16-bits of address
 * 		W AAAA DDDD for writes where 'A' indicates one nibble of address and 'D' is one nibble of data
 *
 * 		Note: Provide all 16-bits even if uppermost nibbles are zero.
 */

int UartLiteControl()
{
	int Status=0;
	int Index;
	u8 SendArray[3];
	u16 RegAdrs, RegData;
	u8 Command;
	u8 DevAdrs, PageAdrs;

	while (1)
	{
		if (!XUartLite_IsReceiveEmpty(UARTLITE_BASEADDR))
		{
			ReceiveBuffer[0] = XUartLite_RecvByte(UARTLITE_BASEADDR);
			//- If the input character indicates 'Write', wait till WR_RX_CNT-1 characters are received
			if ((ReceiveBuffer[0] == 'W') | (ReceiveBuffer[0] == 'w')) {
				for (Index = 1; Index < WR_RX_CNT; Index++)
				{
					ReceiveBuffer[Index] = XUartLite_RecvByte(UARTLITE_BASEADDR);
				}
				SendArray[0] = (AsciiToHex(ReceiveBuffer[9]) << 4) + AsciiToHex(ReceiveBuffer[10]);
				SendArray[1] = (AsciiToHex(ReceiveBuffer[7]) << 4) + AsciiToHex(ReceiveBuffer[8]);

					//- PMBUS Write
				if (ReceiveBuffer[2] != ASCII_ZERO) {
					DevAdrs = (AsciiToHex(ReceiveBuffer[2]) << 4) + AsciiToHex(ReceiveBuffer[3]);
					PageAdrs = AsciiToHex(ReceiveBuffer[4]);
				}
					//- Write to debug register
				else if (ReceiveBuffer[3] == ASCII_ZERO + 0x2) {
					if (SendArray[0] == 0x0) {
						EN_DEBUG = FALSE;
					} else {
						EN_DEBUG = TRUE;
#ifdef ENABLE_DEBUG
						print("Debug enabled\n");
#endif
					}
				} else {
					Command = (AsciiToHex(ReceiveBuffer[4]) << 4) + AsciiToHex(ReceiveBuffer[5]);
					if (Command == DAC_B_OFFSET_REG) {
						DAC_B_DC_VALUE = (SendArray[1] << 8) + SendArray[0];
						Status = GenerateFixedVoltage(SPI_DEVICE_ID, &SpiInstance, DAC_B_DC_VALUE, 0x01);
						SINE_DC_OFFSET = DAC_B_DC_VALUE;
#ifdef ENABLE_DEBUG
							xil_printf("Program offset value for sine wave with %0x\n", SINE_DC_OFFSET);
#endif
					}
					else if (Command == DAC_A_OFFSET_REG) {
						DAC_A_DC_VALUE = (SendArray[1] << 8) + SendArray[0];
						Status = GenerateFixedVoltage(SPI_DEVICE_ID, &SpiInstance, DAC_A_DC_VALUE, 0x00);
						VN_OFFSET_VALUE = DAC_A_DC_VALUE;
#ifdef ENABLE_DEBUG
							xil_printf("Program VN offset value with %0x\n", VN_OFFSET_VALUE);
#endif
					}
						//- DAC to generate sinusoidal signal
					else if (Command == SINE_ADRS_REG) {
						if (SendArray[0] == 0x01){
							EN_DAC_SINE = TRUE;
					    } else if(SendArray[0] == 0x02){
							SetInputMode(&SysMonInst, 0x03);
						    EN_DAC_SINE = TRUE;
					    } else {
							EN_DAC_SINE = FALSE;
					    }
						EN_DAC_DC = FALSE;
						EN_DAC_RAMP = FALSE;
#ifdef ENABLE_DEBUG
							print("Program DAC to generate Sine\n");
#endif
					}
						//- Program clock divider value
					else if (Command == CLK_SEL_REG) {
#ifdef ENABLE_DEBUG
							xil_printf("Program clock divider value of %0x\n", SendArray[0]);
#endif
						ProgramSampleRate(&SysMonInst, SendArray[0]);
					}
						//- Set channel option
					else if (Command == CHAN_SEL_REG) {
#ifdef ENABLE_DEBUG
							xil_printf("Program channel option %0x\n", SendArray[0]);
#endif
						CHANNEL_OPTION = SendArray[0];
						SetChannelOption(&SysMonInst, SendArray[0]);
					}
					else if (Command == DAC_RAMP_REG) {
#ifdef ENABLE_DEBUG
							xil_printf("Program DAC ramp A/B %0x\n", SendArray[0]);
#endif
						DAC_B_RAMPING = SendArray[0];
					}
					else if (Command == DAC_SINE_REG) {
#ifdef ENABLE_DEBUG
							xil_printf("Program DAC ramp A/B %0x\n", SendArray[0]);
#endif
						DAC_B_SINE_SRC = SendArray[0];
					}
						//- Set input mode
					else if (Command == IN_TYPE_REG) {
#ifdef ENABLE_DEBUG
							xil_printf("Program input mode %0x\n", SendArray[0]);
#endif
						SetInputMode(&SysMonInst, SendArray[0]);
					}
						//- Set decimation factor
					else if (Command == DEC_FACTOR_REG) {
						DECIMATION_FACTOR = SendArray[0];
					}
				}
				//- Send back an "OK" acknowledgement
				SendArray[0] = 'O';
				SendArray[1] = 'K';
				SendArray[2] = '\n';
				Status = SendOverUart(&UartLite, SendArray, 3, 1, 0);
				//- If the input character indicates 'Read', wait till RD_RX_CNT-1 characters are received
			} else if ((ReceiveBuffer[0] == 'R') | (ReceiveBuffer[0] == 'r')) {
				u8 value[2];
				for (Index = 1; Index < RD_RX_CNT; Index++)
				{
					ReceiveBuffer[Index] = XUartLite_RecvByte(UARTLITE_BASEADDR);
				}
				//////////////////////////////////RISHI
				if (ReceiveBuffer[2] == SENSOR_OFFSET_1 || ReceiveBuffer[2]
						== SENSOR_OFFSET_2) {
					DevAdrs = (AsciiToHex(ReceiveBuffer[2]) << 4) + AsciiToHex(
							ReceiveBuffer[3]);
					PageAdrs = AsciiToHex(ReceiveBuffer[5]);
                    ReadExtSensorData(&SysMonInst,DevAdrs,PageAdrs,SendArray);
                    Status = SendOverUart(&UartLite, SendArray, 2, 0, 1);
					SendNewLine();

				}
				//////////////////////////////////////
				else if (ReceiveBuffer[2] != ASCII_ZERO) {
					DevAdrs = (AsciiToHex(ReceiveBuffer[2]) << 4) + AsciiToHex(ReceiveBuffer[3]);
					PageAdrs = AsciiToHex(ReceiveBuffer[4]);
						//- Read voltage
					if (ReceiveBuffer[5] == ASCII_ZERO)
					{
						RegData = ReadVoltage(DevAdrs, PageAdrs, SendArray);
						Status = SendOverUart(&UartLite, SendArray, RegData, 0, 1);
						SendNewLine();
					}
						//- Read Current
					else if (ReceiveBuffer[5] == (ASCII_ZERO + 0x01))
					{
						RegData = ReadCurrent(DevAdrs, PageAdrs, SendArray);
						Status = SendOverUart(&UartLite, SendArray, RegData, 0, 1);
						SendNewLine();
					}
				} else {
					Command = (AsciiToHex(ReceiveBuffer[4]) << 4) + AsciiToHex(ReceiveBuffer[5]);
#ifdef ENABLE_DEBUG
						xil_printf("Command = %0x\n", Command);
#endif
					if (ReceiveBuffer[3] == (ASCII_ZERO + 0x2)) {
						SendArray[0] = 0x0;
#ifdef ENABLE_DEBUG
							SendArray[1] = 0x1;
#else
							SendArray[1] = 0x0;
#endif
						Status = SendOverUart(&UartLite, SendArray, 2, 0, 1);
						SendNewLine();
					}
						//- Receiving XADC Read reg command
					else if (ReceiveBuffer[3] == (ASCII_ZERO + 0x1)) {
						//- Read address starting with 0x1xx which indicates XADC register access
						//- Add 0x200 which is AXI-XADC IP offset and
						//  multiply address by 4 to map to the right register offset
						RegAdrs = XSM_TEMP_OFFSET + (((AsciiToHex(ReceiveBuffer[4]) << 4) +  (AsciiToHex(ReceiveBuffer[5]))) << 2);
						RegData = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, RegAdrs);
						SendArray[1] = (u8) RegData;
						SendArray[0] = RegData >> 8;
						Status = SendOverUart(&UartLite, SendArray, 2, 0, 1);
						SendNewLine();
#ifdef ENABLE_DEBUG
							xil_printf("Read XADC Reg: %0x %0x\n", RegAdrs, RegData);
#endif
					}
						//- Design version read command
					else if (Command == DESIGN_VERSION_REG) {
						SendArray[1] = DESIGN_VERSION;
						SendArray[0] = DESIGN_VERSION >> 8;
						Status = SendOverUart(&UartLite, SendArray, 2, 0, 1);
						SendNewLine();
					}
						//- Collect raw data command
					else if (Command == RAW_DATA_REG){
						MemoryAdrs = XPAR_BRAM_0_BASEADDR + RAW_DATA_MEMORY_OFFSET;
						if (CHANNEL_OPTION == 0x02)
						{
							if (EN_DAC_SINE){
								Status = CollectRawData_SimulChan_DacSine(&SysMonInst, MemoryAdrs, RAW_SAMPLE_CNT, 0);
								Status = ReadBram_SendData(MemoryAdrs, (RAW_SAMPLE_CNT << 2), 16, 0);
							} else {
							//- Raw data collection for simultaneous channel mode
								Status = CollectRawData_SimulChan(&SysMonInst, MemoryAdrs, RAW_SAMPLE_CNT, 0);
								Status = ReadBram_SendData(MemoryAdrs, (RAW_SAMPLE_CNT << 2), 16, 0);
							}
						} else {
							//- Gathering raw data on Vp/Vn channel
							if (EN_DAC_SINE){
								Status = CollectRawData_DacSine(&SysMonInst, MemoryAdrs, RAW_SAMPLE_CNT, DECIMATION_FACTOR);
								Status = ReadBram_SendData(MemoryAdrs, (RAW_SAMPLE_CNT << 1), 16, 0);
						    } else {
								Status = CollectRawData(&SysMonInst, MemoryAdrs, RAW_SAMPLE_CNT, DECIMATION_FACTOR);
							    Status = ReadBram_SendData(MemoryAdrs, (RAW_SAMPLE_CNT << 1), 16, 0);
						    }
						}
						SendNewLine();
#ifdef ENABLE_DEBUG
							print("Collect Raw Data Done\n");
#endif
					}
						//- Gather Histogram as DAC ramps
					else if (Command == HIST_DATA_REG)
					{
#ifdef ENABLE_DEBUG
							print("Command to generate histogram while DAC ramps");
#endif
						EN_DAC_RAMP = TRUE;
						MemoryAdrs = XPAR_BRAM_0_BASEADDR + RAW_DATA_MEMORY_OFFSET;
						InitializeBram(MemoryAdrs);
						Status = GetHistogram(&SysMonInst, MemoryAdrs);
						Status = ReadBram_SendData(MemoryAdrs, HIST_DATA_COUNT, 16, 1);
						SendNewLine();
						EN_DAC_RAMP = FALSE;
					}
						//- Collect sensor data
					else if (Command == SENSOR_DATA_REG) {
						MemoryAdrs = XPAR_BRAM_0_BASEADDR + RAW_DATA_MEMORY_OFFSET;
						Status = CollectSensorData(&SysMonInst, MemoryAdrs, 4);
							//- Send Temperature
						Status = ReadBram_SendData(MemoryAdrs, 8, 8, 0);
						SendNewLine();
							//- Send VCCAUX
						Status = ReadBram_SendData((MemoryAdrs+8), 8, 8, 0);
						SendNewLine();
							//- Send VCCINT
						Status = ReadBram_SendData((MemoryAdrs+16), 8, 8, 0);
						SendNewLine();
							//- Send VCCBRAM
						Status = ReadBram_SendData((MemoryAdrs+24), 8, 8, 0);
						SendNewLine();
#ifdef ENABLE_DEBUG
							print("Collect Sensor Data DONE\n");
#endif
					}
						//- Collect VREFN Data
					else if (Command == VREFN_DATA_REG) {
						MemoryAdrs = XPAR_BRAM_0_BASEADDR + RAW_DATA_MEMORY_OFFSET;
						Status = CollectShortData(&SysMonInst, MemoryAdrs, RAW_SAMPLE_CNT);
						Status = ReadBram_SendData(MemoryAdrs, (RAW_SAMPLE_CNT << 1), 16, 0);
						SendNewLine();
#ifdef ENABLE_DEBUG
							print("Collect VREFN Data DONE\n");
#endif
					}
						//- Decimation factor value
					else if (Command == DEC_FACTOR_REG) {
						SendArray[1] = DECIMATION_FACTOR;
						SendArray[0] = DECIMATION_FACTOR >> 8;
						Status = SendOverUart(&UartLite, SendArray, 2, 0, 1);
						SendNewLine();
					}
					else if (Command == DAC_A_OFFSET_REG) {
						SendArray[1] = DAC_A_DC_VALUE;
						SendArray[0] = DAC_A_DC_VALUE >> 8;
						Status = SendOverUart(&UartLite, SendArray, 2, 0, 1);
						SendNewLine();
					}
					else if (Command == DAC_B_OFFSET_REG) {
						SendArray[1] = DAC_B_DC_VALUE;
						SendArray[0] = DAC_B_DC_VALUE >> 8;
						Status = SendOverUart(&UartLite, SendArray, 2, 0, 1);
						SendNewLine();
					}
					else if (Command == CLK_SEL_REG) {
						RegData = XSysMon_GetAdcClkDivisor(&SysMonInst);
						SendArray[1] = (u8) RegData;
						SendArray[0] = RegData >> 8;
						Status = SendOverUart(&UartLite, SendArray, 2, 0, 1);
						SendNewLine();
					}
					else if (Command == CHAN_SEL_REG) {
						SendArray[1] = CHANNEL_OPTION;
						SendArray[0] = CHANNEL_OPTION >> 8;
						Status = SendOverUart(&UartLite, SendArray, 2, 0, 1);
						SendNewLine();
					}
					else if (Command == IN_TYPE_REG) {
						if (USE_UNIPOLAR_MODE)
							SendArray[1] = 0x01;
						else if(USE_BIPOLAR_MODE)
							SendArray[1] = 0x02;
						else if(USE_DIFFERENTIAL_MODE)
							SendArray[1] = 0x03;
						SendArray[0] = 0x00;
						Status = SendOverUart(&UartLite, SendArray, 2, 0, 1);
						SendNewLine();
					}
					else if (Command == SINE_ADRS_REG) {
						if (EN_DAC_SINE)
							SendArray[1] = 0x01;
						else
							SendArray[1] = 0x00;
						SendArray[0] = 0x00;
						Status = SendOverUart(&UartLite, SendArray, 2, 0, 1);
						SendNewLine();
					}
				}
			} else if ((ReceiveBuffer[0] == 'E') | (ReceiveBuffer[0] == 'e')) {
		    	XGpio_DiscreteWrite(&Gpio, 1, 0);
		    	break;
		    } else
		    	continue;
		}
	 }
#ifdef ENABLE_DEBUG
		 print("Exiting the program\n\r");
#endif
	 return XST_SUCCESS;
}

void SendNewLine()
{
	u8 SendData[1];

	SendData[0] = '\n';
	SendOverUart(&UartLite, SendData, 1, 1, 0);
}

/*
 * @note This function sends the specified number of bytes from a pointed buffer over UART
 */
int SendOverUart(XUartLite* UartLite, u8 *SendBuffer, int NumBytes, int IsChar, int toASCII)
{
	int Status;
	u8 SendBuf[16];
	int TotalBytes;
	int Index;
	int BytesSent;

		//- If character, send directly otherwise convert to ASCII
	if (IsChar) {
		TotalBytes = NumBytes;
		for (Index = 0; Index < NumBytes; Index++)
			SendBuf[Index] = SendBuffer[Index];
	} else {
		if (NumBytes > 16) {
#ifdef ENABLE_DEBUG
			print("Numbytes greater than allowed value!\n");
#endif
			return XST_FAILURE;
		}
		if (toASCII) {
			TotalBytes = HexToASCII(SendBuffer, NumBytes, SendBuf);
		} else {
			TotalBytes = NumBytes;
		}
	}
	while(1)
	{
		Status=XUartLite_IsSending(UartLite);
		if (Status == 0)
			break;
	}
	if (toASCII)
		BytesSent = XUartLite_Send(UartLite, SendBuf, TotalBytes);
	else
		BytesSent = XUartLite_Send(UartLite, SendBuffer, TotalBytes);
	if ( BytesSent != TotalBytes) {
#ifdef ENABLE_DEBUG
		print("UART Send Failure!\n");
#endif
		return XST_FAILURE;
	}
	return XST_SUCCESS;
}

//- Set the XADC clock divider value to vary sampling rate
void ProgramSampleRate(XSysMon* SysMonInstPtr, u8 DividerVal)
{
	//Change clock divide to slow down XADC
	XSysMon_SetAdcClkDivisor(SysMonInstPtr, DividerVal);
}

//- Sets the channel option for XADC
//- 0x01 - Single Channel Mode
//- 0x02 - Simultaneous sampling mode
void SetChannelOption(XSysMon* SysMonInstPtr, u8 ChanOption)
{
	if (ChanOption == 0x01) {
		//- Program for single channel mode
		XSysMon_SetSequencerMode(SysMonInstPtr, XSM_SEQ_MODE_CONTINPASS);
		XSysMon_WriteReg(SysMonInstPtr->Config.BaseAddress, XSM_SEQ00_OFFSET,
				 0x0800);
		XSysMon_WriteReg(SysMonInstPtr->Config.BaseAddress, XSM_SEQ01_OFFSET,
						 0x0000);
	} else if (ChanOption == 0x02){
		//- Program for simultaneous sampling mode
		XSysMon_SetSequencerMode(SysMonInstPtr, XSM_SEQ_MODE_SIMUL);
		XSysMon_WriteReg(SysMonInstPtr->Config.BaseAddress, XSM_SEQ00_OFFSET,
						 0x0000);
		XSysMon_WriteReg(SysMonInstPtr->Config.BaseAddress, XSM_SEQ01_OFFSET,
								 0x0101);
	}
}

/*
 * @note 	Sets input mode for XADC
 * 				0x01: Unipolar
 * 				0x02: Bipolar
 */
void SetInputMode(XSysMon* SysMonInstPtr, u8 InputMode)
{
	u8 SeqMode;

	//- Needs sequencer mode to be disabled first....
	SeqMode=XSysMon_GetSequencerMode(SysMonInstPtr);
	XSysMon_SetSequencerMode(SysMonInstPtr, XSM_SEQ_MODE_SINGCHAN);

	if (InputMode == 0x01) {
		//- Program Unipolar mode for select channels; bitmask of zero indicates unipolar mode
		XSysMon_WriteReg(SysMonInstPtr->Config.BaseAddress, XSM_CFR0_OFFSET,
								 0x0000);
		XSysMon_SetSeqInputMode(SysMonInstPtr, 0x00);
		USE_UNIPOLAR_MODE = TRUE;
		USE_BIPOLAR_MODE = FALSE;
		USE_DIFFERENTIAL_MODE = FALSE;
	} else if (InputMode == 0x02) {
		//- Program Bipolar mode for select channels; bit mask of 1 indicates bipolar mode for Vp/Vn channel
		XSysMon_SetSeqInputMode(SysMonInstPtr, XSM_SEQ_CH_VPVN);
		XSysMon_WriteReg(SysMonInstPtr->Config.BaseAddress, XSM_CFR0_OFFSET,
								 0x0400);
		USE_UNIPOLAR_MODE = FALSE;
		USE_DIFFERENTIAL_MODE = FALSE;
		USE_BIPOLAR_MODE = TRUE;
	} else	if (InputMode == 0x03) {
		//- Program Bipolar mode for select channels; bit mask of 1 indicates bipolar mode for Vp/Vn channel
		XSysMon_SetSeqInputMode(SysMonInstPtr, XSM_SEQ_CH_VPVN);
		XSysMon_WriteReg(SysMonInstPtr->Config.BaseAddress, XSM_CFR0_OFFSET,
						 0x0400);
		USE_UNIPOLAR_MODE = FALSE;
		USE_DIFFERENTIAL_MODE = TRUE;
		USE_BIPOLAR_MODE = FALSE;
	}
	XSysMon_SetSequencerMode(SysMonInstPtr, SeqMode);
}

/*
 * Sets the XADC Sequencer mode
 * @param Takes the sysmon instance pointer along with channel mask and sequencer mode to be set
 * @return Returns success or failure of operation
 * @note This function first puts the XADC in single channel mode before enabling any channels
 * and then puts it back in desired sequencer mode
 */
int SetSeqMode(XSysMon* SysMonInstPtr, u32 ChanMask, u32 SeqMode)
{
	int Status;

	// Set single channel mode of operation
	XSysMon_SetSequencerMode(SysMonInstPtr, XSM_SEQ_MODE_SINGCHAN);

	//Enable channel Vp/Vn
	Status = XSysMon_SetSeqChEnables(SysMonInstPtr, ChanMask);
	if (Status != XST_SUCCESS)
	{
		return XST_FAILURE;
	}
	//Enter into continuous channel mode
	XSysMon_SetSequencerMode(SysMonInstPtr, SeqMode);

	return XST_SUCCESS;
}

/*
 * @note This functions gathers raw samples from XADC when using Internal shorting (or VREFN) mode
 */
int CollectShortData(XSysMon* SysMonInstPtr, u32 StartAdrs, int NumSamples)
{
	int Status;
	u32 Index;
	u16 RawData;
	u32 NextAdrs;

	Status = SetSeqMode(SysMonInstPtr, XSM_SEQ_CH_VREFN, XSM_SEQ_MODE_CONTINPASS);

	EocPoll = FALSE;

	for (Index = 0; Index < (2*NumSamples); Index = Index+2)
	{
		while (EocPoll!= TRUE)
		{
			Status = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_SR_OFFSET);
			if ((Status && XSM_IPIXR_EOC_MASK)==1)
			{
				EocPoll= TRUE;
			}
		}
		EocPoll = FALSE;
		NextAdrs = StartAdrs + Index;
			//Access XADC result register for VREFN data
		RawData = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_VREFN_OFFSET);
#ifdef ENABLE_DEBUG
			xil_printf("DEBUG: RawVREFN = %0x, Adrs = %0x\n", RawData, NextAdrs);
#endif
			//Write to BRAM
		Xil_Out16(NextAdrs, RawData);
	}
#ifdef ENABLE_DEBUG
		xil_printf("\n %0d Samples collected for VREFN data - address = %0x\n", NumSamples, NextAdrs);
#endif
	return XST_SUCCESS;
}

/*
 * @note This function collects sensor data from XADC - temperature, VCCAUX, VCCINT and VBRAM
 * 		specified number of samples of each sensor data are collected and stored in Block RAM
 */
int CollectSensorData(XSysMon* SysMonInstPtr, u32 StartAdrs, int NumSamples)
{
	int Status;
	u32 Index;
	u16 RawTemp, RawVccAux, RawVccInt, RawVBram;
	u32 NextAdrs;

	Status = SetSeqMode(SysMonInstPtr, (XSM_SEQ_CH_TEMP | XSM_SEQ_CH_VCCINT | XSM_SEQ_CH_VCCAUX | 0x00004000),
														XSM_SEQ_MODE_CONTINPASS);

	EocPoll = FALSE;

	for (Index = 0; Index < (2*NumSamples); Index = Index+2)
	{
		while (EocPoll!= TRUE)
		{
			Status = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_SR_OFFSET);
			if ((Status && XSM_IPIXR_EOC_MASK)==1)
			{
				EocPoll= TRUE;
			}
		}
		EocPoll = FALSE;
		NextAdrs = StartAdrs + Index;
		//Access XADC result register for various sensor data
		RawTemp = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_TEMP_OFFSET);
		RawVccAux = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_VCCAUX_OFFSET);
		RawVccInt = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_VCCINT_OFFSET);
		RawVBram = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_VBRAM_OFFSET);
#ifdef ENABLE_DEBUG
			xil_printf("DEBUG: RawTemp = %0x, Rawvccaux=%0x, RawVccInt=%0x, RawVBram=%0x\n", RawTemp, RawVccAux, RawVccInt, RawVBram);
#endif
		//Write to BRAM
		Xil_Out16(NextAdrs, RawTemp);
		Xil_Out16((NextAdrs+8), RawVccAux);
		Xil_Out16((NextAdrs+16), RawVccInt);
		Xil_Out16((NextAdrs+24), RawVBram);

	}
#ifdef ENABLE_DEBUG
		xil_printf("\n %0d Samples collected for sensor data - address = %0x\n", NumSamples, NextAdrs);
#endif
	return XST_SUCCESS;
}

/*
 * @note 	This function collects specified number of samples of raw Vp/Vn channel data
 * 			and writes it to Block RAM from a specified address
 */
int CollectRawData(XSysMon* SysMonInstPtr, u32 StartAdrs, int NumSamples, int DecFactor)
{
	int Status;
	u32 NextAdrs;
	u32 Index;
	u32 AdcData;

	Status = SetSeqMode(SysMonInstPtr, XSM_SEQ_CH_VPVN, XSM_SEQ_MODE_CONTINPASS);

	if (DecFactor == 0) {
		EocPoll = FALSE;

		for (Index = 0; Index < (2*NumSamples); Index = Index+2)
		{
			while (EocPoll!= TRUE)
			{
				Status = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_SR_OFFSET);
				if ((Status & XSM_SR_EOC_MASK)==XSM_SR_EOC_MASK)
				{
					EocPoll= TRUE;
				}
			}
			EocPoll = FALSE;
			NextAdrs = StartAdrs + Index;
			//Access XADC result register for Vp/Vn
			AdcData = (u16)  (XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_TEMP_OFFSET + (XSM_CH_VPVN << 2)));
#ifdef ENABLE_DEBUG
				xil_printf("DEBUG: Rawdata = %0x, Address = %0x\n", AdcData, NextAdrs);
#endif
			//Write to BRAM
			Xil_Out16(NextAdrs, AdcData);
				//- DAC to generate sinusoid signal if enabled
		}
	} else {
		CaptureDecimatedData(DecFactor, NumSamples, StartAdrs);
	}
#ifdef ENABLE_DEBUG
		xil_printf("\n%0d Samples collected - address = %0x\n", NumSamples, NextAdrs);
#endif

	return XST_SUCCESS;
}

void CaptureDecimatedData(int DecFactor, int NumSamples, u32 StartAdrs)
{
	uint status;
	int i, decimate_sel, decimate_control;
	u16 AdcData;
	u32 NextAdrs;

	// Encode the decimation factor:
	// 	2-> 0, 4->1, 8->2, 16->3, 32->4
	if((DecFactor > 32) || (DecFactor < 2))
		DecFactor = 2;
	// select the first power of 2 that matches the parameter passed, and subtract 1
	decimate_sel=0;					// default to decimate by 2
	for(i=5; i>=1; i--) {
		if( (1<<i) & DecFactor) {
			decimate_sel = i-1;
	    	break;
	    }
	}

	// write the decimate select value, and start the capture
	// decimate control word is mapped to DRP address 62 (1 location before status flag register)
	if (USE_BIPOLAR_MODE | USE_DIFFERENTIAL_MODE)
		decimate_control = (decimate_sel & 0x000F) | 0x0030;	// bits 3:0 are the select value, bit 4 is the enable capture, bit 5 is bipolar mode
	else
		decimate_control = (decimate_sel & 0x000F) | 0x0010;	// bits 3:0 are the select value, bit 4 is the enable capture

	XSysMon_WriteReg(XPAR_AXI_XADC_0_BASEADDR, XSM_FLAG_REG_OFFSET-4, decimate_control);

	// Poll the status register - and check the decimate valid signal
	// When the data valid is high, read back the data and store in the next memory address
	for(i=0; i < (2 * NumSamples); i=i+2) {
		status = 0;
		while((status & XSM_SR_JTAG_BUSY_MASK) == 0) {	// decimate data valid signal is mapped onto jtag_busy status bit
			status = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR,XSM_SR_OFFSET);
		}
		NextAdrs = StartAdrs + i;
		// there is decimate data ready - read from the DRP address space to get the data
		// reading any DRP address will return the data - config reg 0 is picked here.
		AdcData = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_CFR0_OFFSET);
		//Write to BRAM
		Xil_Out16(NextAdrs, AdcData);

	}

	// all data has been collected - disable the decimate capture to return the XADC to normal operation
	XSysMon_WriteReg(XPAR_AXI_XADC_0_BASEADDR, XSM_FLAG_REG_OFFSET-4, 0);
}

/*
 * @note 	This function collects specified number of samples of raw Vp/Vn channel data
 * 			and writes it to Block RAM from a specified address when DAC is sinusoid signal source
 */
int CollectRawData_DacSine(XSysMon* SysMonInstPtr, u32 StartAdrs, int NumSamples, int DecFactor)
{
	int Status;
	u32 NextAdrs;
	u32 Index;
	u32 AdcData;
	volatile int j;

	Status = SetSeqMode(SysMonInstPtr, XSM_SEQ_CH_VPVN, XSM_SEQ_MODE_CONTINPASS);

	if (DecFactor == 0) {
		EocPoll = FALSE;

		//- First set the VN offset value
		if(DAC_B_SINE_SRC){
			Status=WriteDac(&SpiInstance,DAC_WRITE_COMMNAD,DAC_ADDRESS_A, VN_OFFSET_VALUE);
		} else {
			Status=WriteDac(&SpiInstance,DAC_WRITE_COMMNAD,DAC_ADDRESS_B, VN_OFFSET_VALUE);
        }

		incr_size = 0;
		for (Index = 0; Index < (2*NumSamples); Index = Index+2)
		{
			//- DAC to generate sinusoid signal if enabled
			Status = GenerateSine(SPI_DEVICE_ID,&SpiInstance, 0);
			if (USE_BIPOLAR_MODE | USE_DIFFERENTIAL_MODE)
							for (j = 0; j < 1450; j++)
								;
						else
							for (j = 0; j < 1350; j++)
								;

			while (EocPoll!= TRUE)
			{
				Status = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_SR_OFFSET);
				if ((Status & XSM_SR_EOC_MASK)==XSM_SR_EOC_MASK)
				{
					EocPoll= TRUE;
				}
			}

			EocPoll = FALSE;
			NextAdrs = StartAdrs + Index;
			//Access XADC result register for Vp/Vn
			AdcData = (u16)  (XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_VPVN_OFFSET));
#ifdef ENABLE_DEBUG
				xil_printf("DEBUG: Rawdata = %0x, Address = %0x\n", AdcData, NextAdrs);
#endif
			//Write to BRAM
			Xil_Out16(NextAdrs, AdcData);
		}
	} else {
		CaptureDecimatedData_DacSine(DecFactor, NumSamples, StartAdrs);
	}
#ifdef ENABLE_DEBUG
		xil_printf("\n%0d Samples collected - address = %0x\n", NumSamples, NextAdrs);
#endif

	return XST_SUCCESS;
}

void CaptureDecimatedData_DacSine(int DecFactor, int NumSamples, u32 StartAdrs)
{
	uint status;
	int i, decimate_sel, decimate_control;
	u16 AdcData, wait_cycles;
	u32 NextAdrs;
    volatile int j;

	// Encode the decimation factor:
	// 	2-> 0, 4->1, 8->2, 16->3, 32->4
	if((DecFactor > 32) || (DecFactor < 2))
		DecFactor = 2;
	// select the first power of 2 that matches the parameter passed, and subtract 1
	decimate_sel=0;					// default to decimate by 2
	for(i=5; i>=1; i--) {
		if( (1<<i) & DecFactor) {
			decimate_sel = i-1;
	    	break;
	    }
	}

	// write the decimate select value, and start the capture
	// decimate control word is mapped to DRP address 62 (1 location before status flag register)
	//decimate_control = (decimate_sel & 0x000F) | 0x0010;	// bits 3:0 are the select value, bit 4 is the enable capture
	if (USE_BIPOLAR_MODE | USE_DIFFERENTIAL_MODE)
		decimate_control = (decimate_sel & 0x000F) | 0x0030;	// bits 3:0 are the select value, bit 4 is the enable capture, bit 5 is bipolar mode
	else
		decimate_control = (decimate_sel & 0x000F) | 0x0010;	// bits 3:0 are the select value, bit 4 is the enable capture

	XSysMon_WriteReg(XPAR_AXI_XADC_0_BASEADDR, XSM_FLAG_REG_OFFSET-4, decimate_control);

	//- First set the VN offset value
	if(DAC_B_SINE_SRC){
		status=WriteDac(&SpiInstance,DAC_WRITE_COMMNAD,DAC_ADDRESS_A, VN_OFFSET_VALUE);
	} else {
		status=WriteDac(&SpiInstance,DAC_WRITE_COMMNAD,DAC_ADDRESS_B, VN_OFFSET_VALUE);
	}

	// Poll the status register - and check the decimate valid signal
	// When the data valid is high, read back the data and store in the next memory address
	if(DecFactor == 32)wait_cycles=2200;
	else if(DecFactor == 16) {
		if (USE_BIPOLAR_MODE | USE_DIFFERENTIAL_MODE) wait_cycles=3000;//2400;
		else wait_cycles=3000;//2785;
	} else wait_cycles=2600;//2048;
	///
	if (DecFactor == 32)
			wait_cycles = 2200;
		else if (DecFactor == 16) {
			if (USE_BIPOLAR_MODE | USE_DIFFERENTIAL_MODE)
				wait_cycles = 3650;
			else
				wait_cycles = 3500;//3320;
		} else if (DecFactor == 8) {
			if (USE_BIPOLAR_MODE | USE_DIFFERENTIAL_MODE)
				wait_cycles = 2099;
			else
				wait_cycles = 2400;
		} else if (DecFactor == 4) {
			if (USE_BIPOLAR_MODE | USE_DIFFERENTIAL_MODE)
				wait_cycles = 1000;
			else
				wait_cycles = 2000;//1336;
		} else if (DecFactor == 2) {
			if (USE_BIPOLAR_MODE | USE_DIFFERENTIAL_MODE)
				wait_cycles = 2040;
			else
				wait_cycles = 2300;
		}
		else
			wait_cycles = 2040;
	///

	incr_size = 0;
	for(i=0; i < (2*NumSamples); i=i+2) {
		GenerateSine(SPI_DEVICE_ID, &SpiInstance, 0);
		for(j=0;j<wait_cycles;j++);
		status = 0;
		while((status & XSM_SR_JTAG_BUSY_MASK) == 0) {	// decimate data valid signal is mapped onto jtag_busy status bit
			status = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR,XSM_SR_OFFSET);
		}
		NextAdrs = StartAdrs + i;
		// there is decimate data ready - read from the DRP address space to get the data
		// reading any DRP address will return the data - config reg 0 is picked here.
		AdcData = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_CFR0_OFFSET);
		//Write to BRAM
		Xil_Out16(NextAdrs, AdcData);
	}

	// all data has been collected - disable the decimate capture to return the XADC to normal operation
	XSysMon_WriteReg(XPAR_AXI_XADC_0_BASEADDR, XSM_FLAG_REG_OFFSET-4, 0);
}

int CollectRawData_SimulChan(XSysMon* SysMonInstPtr, u32 StartAdrs, int NumSamples, int DecFactor)
{
	int Status;
	u32 NextAdrs;
	u32 Index;
	u32 AdcData;

	XSysMon_SetSequencerMode(SysMonInstPtr, XSM_SEQ_MODE_SINGCHAN);

	if(USE_BIPOLAR_MODE){
		Status=XSysMon_SetSeqInputMode(SysMonInstPtr, (XSM_SEQ_CH_AUX00 | XSM_SEQ_CH_AUX08));
	}

	Status = SetSeqMode(SysMonInstPtr, (XSM_SEQ_CH_AUX00 | XSM_SEQ_CH_AUX08), XSM_SEQ_MODE_SIMUL);

		EocPoll = FALSE;
		NextAdrs = StartAdrs ;
		for (Index = 0; Index < 4096; Index = Index+1)
		{
			while (EocPoll!= TRUE)
			{
				Status = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_SR_OFFSET);
				if ((Status & XSM_SR_EOC_MASK)==XSM_SR_EOC_MASK)
				{
					EocPoll= TRUE;
				}
			}
			EocPoll = FALSE;
			AdcData = (u16)  (XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_AUX00_OFFSET));
			AdcData = (u32)  ((XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_AUX08_OFFSET) << 16) | AdcData );
			//Write to BRAM
			Xil_Out32(NextAdrs, AdcData);
			NextAdrs =  NextAdrs + 4;

		}

#ifdef ENABLE_DEBUG
		xil_printf("\n%0d Samples collected - address = %0x\n", NumSamples, NextAdrs);
#endif

	return XST_SUCCESS;
}

int CollectRawData_SimulChan_DacSine(XSysMon* SysMonInstPtr, u32 StartAdrs, int NumSamples, int DecFactor)
{
	int Status;
	u32 NextAdrs;
	u32 Index;
	u32 AdcData;
	u16 wait_cycles;
	volatile int j;

	XSysMon_SetSequencerMode(SysMonInstPtr, XSM_SEQ_MODE_SINGCHAN);

	if(USE_BIPOLAR_MODE | USE_DIFFERENTIAL_MODE){
		Status=XSysMon_SetSeqInputMode(SysMonInstPtr, (XSM_SEQ_CH_AUX00 | XSM_SEQ_CH_AUX08));
	}

	Status = SetSeqMode(SysMonInstPtr, (XSM_SEQ_CH_AUX00 | XSM_SEQ_CH_AUX08), XSM_SEQ_MODE_SIMUL);

		EocPoll = FALSE;
		NextAdrs = StartAdrs;
		incr_size = 0;
		wait_cycles=256;
		//- Program any offsets if needed for DACs here

		for (Index = 0; Index < 4096; Index = Index+1)
	    {
			//- Write same sample to both DACs
			Status = GenerateSine(SPI_DEVICE_ID, &SpiInstance, 1);
			for(j=0;j<wait_cycles;j++);
			while (EocPoll!= TRUE)
			{
				Status = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_SR_OFFSET);
				if ((Status & XSM_SR_EOC_MASK)==XSM_SR_EOC_MASK)
				{
					EocPoll= TRUE;
				}
			}
			EocPoll = FALSE;
			AdcData = (u16)  (XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_AUX00_OFFSET));
			AdcData = (u32)  ((XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_AUX08_OFFSET) << 16) | AdcData );
			//Write to BRAM
			Xil_Out32(NextAdrs, AdcData);
			NextAdrs =  NextAdrs + 4;

		}

#ifdef ENABLE_DEBUG
		xil_printf("\n%0d Samples collected - address = %0x\n", NumSamples, NextAdrs);
#endif

	return XST_SUCCESS;
}


/*
 * This function generates histogram as DAC ramps from 0V to 1V for INL/DNL plots in GUI
 */
int GetHistogram(XSysMon* SysMonInstPtr, u32 StartAdrs)
{
	int Status;
	u32 NextAdrs;
	u32 AdcData;
	int Index;

	Status = SetSeqMode(SysMonInstPtr, XSM_SEQ_CH_VPVN, XSM_SEQ_MODE_CONTINPASS);

	EocPoll = FALSE;
	AdcData = 0x0;
	//-Set DAC_RAMPING to TRUE here
	DAC_RAMPING = TRUE;
	dac_code = 0x0;

	//- First set the VN offset value
	if (DAC_B_RAMPING)
		Status=WriteDac(&SpiInstance, DAC_WRITE_COMMNAD, DAC_ADDRESS_A, VN_OFFSET_VALUE);
	else
		Status=WriteDac(&SpiInstance, DAC_WRITE_COMMNAD, DAC_ADDRESS_B, VN_OFFSET_VALUE);
		//- this is the flag which will be decide how long to calculate histogram for
	do
	{
		Status = GenerateRamp(SPI_DEVICE_ID, &SpiInstance);
#ifdef ENABLE_DEBUG
			xil_printf("\n Histogram: ** dac_code = %0x\t AdcData is ",dac_code);
#endif

		for (Index = 0; Index < RAMP_COUNT; Index++)
		{
			while (EocPoll!= TRUE)
			{
				Status = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_SR_OFFSET);
				if ((Status && XSM_IPIXR_EOC_MASK)==1)
				{
					EocPoll= TRUE;
				}
			}
			EocPoll = FALSE;

		//Access XADC result register for Vp/Vn
			AdcData = (u16)  (XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_TEMP_OFFSET + (XSM_CH_VPVN << 2)));
#ifdef ENABLE_DEBUG
				xil_printf("%0x\t", AdcData);
#endif
			NextAdrs = StartAdrs + (AdcData >> 4);
			// Increment bin
			IncrementBram(NextAdrs);
		}
	} while (DAC_RAMPING);
#ifdef ENABLE_DEBUG
		xil_printf("\n Histogram data collected - address = %0x\n", NextAdrs);
#endif
	return XST_SUCCESS;
}

//- This function initializes Block RAM (4096 locations) with zero for histogram calculations
void InitializeBram(u32 Adrs)
{
	int Index;

	for (Index = 0; Index < 4096; Index++)
	{
		Xil_Out8((Adrs + Index), 0);
	}
}

//- This function increments the content of a given Block RAM address by one
void IncrementBram(u32 Adrs)
{
	u8 BramData;

	BramData = Xil_In8(Adrs);
	BramData = BramData + 1;
	Xil_Out8(Adrs, BramData);
}

/*
 * This function reads Block RAM from specified address and for specified amount of samples/bytes
 * and sends them across UART
 */
int ReadBram_SendData(u32 StartAdrs, int NumBytes, int UartBurstSize, int IsHistogram)
{
	u32 DataAdrs;
	int ReadIter;
	int Index, Burst;
	u32 AdcData;
	u8 AdcDataArray[16];
	int Status;

	DataAdrs = StartAdrs;
	if (NumBytes < UartBurstSize)
		ReadIter = 1;
	else
			//- Each sample is 2B which needs 4 ASCII characters to transmit over UART
			//- Hence, for 16-deep UART FIFO, 4 samples can be transmitted at any time
		ReadIter = NumBytes/UartBurstSize;

	for (Burst = 0; Burst < ReadIter; Burst++)
	{
		for (Index=0;Index<(UartBurstSize - 1);Index=Index+4)
		{
			//Access 32 bit word from BRAM
			AdcData = XBram_In32(DataAdrs);
#ifdef ENABLE_DEBUG
				if (AdcData != 0)
					xil_printf("DEBUG: ReadData=%0x, Address = %0x\n", AdcData, DataAdrs);
				else
					xil_printf("DEBUG: Data zero - Address = %0x\n", DataAdrs);
#endif

			if (IsHistogram) {
					//- Pass on the data directly byte by byte
				AdcDataArray[Index]   = (AdcData & 0x000000FF);
				AdcDataArray[Index+1] = (AdcData & 0x0000FF00) >> 8;
				AdcDataArray[Index+2] = (AdcData & 0x00FF0000) >> 16;
				AdcDataArray[Index+3] = (AdcData & 0xFF000000) >> 24;
			} else {
				//- Pass on the data directly byte by byte
				//- Need data MSB first for proper transmission over UART
				AdcDataArray[Index]	  = (AdcData & 0x0000FF00) >> 8;
				AdcDataArray[Index+1] = (AdcData & 0x000000FF);
				AdcDataArray[Index+2] = (AdcData & 0xFF000000) >> 24;
				AdcDataArray[Index+3] = (AdcData & 0x00FF0000) >> 16;
			}
			DataAdrs = DataAdrs + 4;
		}
		Status = SendOverUart(&UartLite, AdcDataArray, UartBurstSize, 0, 0);
	}
	//- Make sure last burst goes through before program control is transferred elsewhere
	while(1)
	{
		Status=XUartLite_IsSending(&UartLite);
		if (Status==0)
			break;
	}

	return XST_SUCCESS;
}

//- This function initializes the DAC connected through SPI
int InitSpiDevice(u16 SpiDeviceId, XSpi *SpiInstancePtr)
{
	int Status;

	/* Pointer to Configuration data */
	XSpi_Config *ConfigPtr;

	ConfigPtr = XSpi_LookupConfig(SpiDeviceId);
	if (ConfigPtr == NULL) {
		return XST_DEVICE_NOT_FOUND;
	}

	Status = XSpi_CfgInitialize(SpiInstancePtr, ConfigPtr, ConfigPtr->BaseAddress);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	Status = XSpi_SelfTest(SpiInstancePtr);
	if (Status != XST_SUCCESS) {
		return XST_FAILURE;
	}
	Status = XSpi_GetStatusReg(SpiInstancePtr);
	/* Enable SPI device with the following options
	 * SPI Master Option
	 * Manual Slave Select Option
	 * Active low clock selection as DAC assumes active low clock edge
	 */
	Status = XSpi_SetOptions(SpiInstancePtr, XSP_MASTER_OPTION |
					XSP_MANUAL_SSELECT_OPTION |
					XSP_CLK_ACTIVE_LOW_OPTION);
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	return XST_SUCCESS;
}

//- This function generates fixed DC voltage from DAC
int GenerateFixedVoltage(u16 SpiDeviceId,XSpi *SpiInstancePtr, u16 DcValue, u8 SelDac)
{
	u32 Status;

	Status = XSpi_SetSlaveSelect(SpiInstancePtr, DAC_SPI_SELECT);
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	XSpi_Start(SpiInstancePtr);

	XSpi_IntrGlobalDisable(SpiInstancePtr);

    if (SelDac == 0x00){
    	Status=WriteDac(SpiInstancePtr, DAC_WRITE_COMMNAD, DAC_ADDRESS_A, DcValue);
    } else {
    	Status=WriteDac(SpiInstancePtr, DAC_WRITE_COMMNAD, DAC_ADDRESS_B, DcValue);
    }
    if(Status!=XST_SUCCESS){
       	return XST_FAILURE;
    }

	return XST_SUCCESS;
}

//- This functions programs DAC to generate a ramp
int GenerateRamp(u16 SpiDeviceId,XSpi *SpiInstancePtr)
{
	u32 Status;

	Status = XSpi_SetSlaveSelect(SpiInstancePtr, DAC_SPI_SELECT);
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	XSpi_Start(SpiInstancePtr);

	XSpi_IntrGlobalDisable(SpiInstancePtr);

	if (DAC_B_RAMPING)
		Status=WriteDac(SpiInstancePtr, DAC_WRITE_COMMNAD, DAC_ADDRESS_B, dac_code);
	else
		Status=WriteDac(SpiInstancePtr, DAC_WRITE_COMMNAD, DAC_ADDRESS_A, dac_code);

	if(Status!=XST_SUCCESS){
#ifdef ENABLE_DEBUG
    	print("Write DAC Failed!\n");
#endif
       	return XST_FAILURE;
    }

    if (dac_code == 0x7FFF)
    	RAMP_DOWN	= TRUE;

    if (RAMP_DOWN== TRUE){
    	dac_code = dac_code-1;
    	if(dac_code == 0)
    		RAMP_DOWN	= FALSE;
    	else
    		RAMP_DOWN	= TRUE;
    } else {
    	dac_code = dac_code + 1;
    }

    //- Based on DAC reaching a specific code value or cycles of sawtooth, flag can be set FALSE
    if (dac_code == 0x0)
    	DAC_RAMPING = FALSE;

	return XST_SUCCESS;
}

//- This function programs DAC to generate sine wave
int GenerateSine(u16 SpiDeviceId,XSpi *SpiInstancePtr, u8 SineFrequency)
{
	u32 Status;
	u32 bram_addr_a,bram_addr_b;
	int bram_value_a=0,bram_value_b=0;

	Status = XSpi_SetSlaveSelect(SpiInstancePtr, DAC_SPI_SELECT);
	if(Status != XST_SUCCESS) {
		return XST_FAILURE;
	}

	XSpi_Start(SpiInstancePtr);

	XSpi_IntrGlobalDisable(SpiInstancePtr);
		/* This function does the following
		 * Read sine wave samples from BRAM
		 * Increment BRAM address by 4 for next set of samples
		 */
	if (USE_UNIPOLAR_MODE){
		bram_addr_a = XPAR_BRAM_0_BASEADDR + SINE_DATA_OFFSET + incr_size;
		bram_value_a=  SINE_DC_OFFSET + Xil_In16(bram_addr_a);
		bram_value_b=  VN_OFFSET_VALUE;
	} else if(USE_BIPOLAR_MODE){
		bram_addr_a = XPAR_BRAM_0_BASEADDR + SINE_DATA_OFFSET + incr_size;
		bram_value_a=  SINE_DC_OFFSET + Xil_In16(bram_addr_a);
		bram_value_b=  VN_OFFSET_VALUE;
	} else if(USE_DIFFERENTIAL_MODE){
    	bram_addr_a = XPAR_BRAM_0_BASEADDR + SINE_DATA_OFFSET + 2*SINE_SAMPLES + incr_size;
    	bram_value_a=  SINE_DC_OFFSET + Xil_In16(bram_addr_a);
    	bram_addr_b = XPAR_BRAM_0_BASEADDR + SINE_DATA_OFFSET + 4*SINE_SAMPLES + incr_size;
    	bram_value_b=  VN_OFFSET_VALUE + Xil_In16(bram_addr_b);
    }
#ifdef ENABLE_DEBUG
	   	xil_printf("DEBUG: SineSampleAddr=%0x, SineSampleData=%0x\n",bram_addr_a,bram_value_a);
#endif


	if(SineFrequency==0) {
		if (USE_UNIPOLAR_MODE){
			if(DAC_B_SINE_SRC){
				Status=WriteDac(SpiInstancePtr,DAC_WRITE_COMMNAD,DAC_ADDRESS_B, bram_value_a);
			} else {
				Status=WriteDac(SpiInstancePtr,DAC_WRITE_COMMNAD,DAC_ADDRESS_A, bram_value_a);
			}
		} else if(USE_BIPOLAR_MODE){
			if (DAC_B_SINE_SRC){
				Status=WriteDac(SpiInstancePtr,DAC_WRITE_COMMNAD,DAC_ADDRESS_B, bram_value_a);
				Status=WriteDac(SpiInstancePtr,DAC_WRITE_COMMNAD,DAC_ADDRESS_A, bram_value_b);
			} else {
				Status=WriteDac(SpiInstancePtr,DAC_WRITE_COMMNAD,DAC_ADDRESS_A, bram_value_a);
				Status=WriteDac(SpiInstancePtr,DAC_WRITE_COMMNAD,DAC_ADDRESS_B, bram_value_b);
			}
		} else if(USE_DIFFERENTIAL_MODE){
			if (DAC_B_SINE_SRC){
				Status=WriteDac(SpiInstancePtr,DAC_WRITE_COMMNAD,DAC_ADDRESS_B, bram_value_a);
				Status=WriteDac(SpiInstancePtr,DAC_WRITE_COMMNAD,DAC_ADDRESS_A, bram_value_b);
			} else {
				Status=WriteDac(SpiInstancePtr,DAC_WRITE_COMMNAD,DAC_ADDRESS_A, bram_value_a);
				Status=WriteDac(SpiInstancePtr,DAC_WRITE_COMMNAD,DAC_ADDRESS_B, bram_value_b);
			}
		}
	}else if(SineFrequency==1){
		if(USE_DIFFERENTIAL_MODE){
			if(DAC_B_SINE_SRC){
	  			Status=WriteDac(SpiInstancePtr,DAC_WRITE_COMMNAD,DAC_ADDRESS_B, bram_value_a);
	  			Status=WriteDac(SpiInstancePtr,DAC_WRITE_COMMNAD,DAC_ADDRESS_A, bram_value_b);
	  		}else{
				Status=WriteDac(SpiInstancePtr,DAC_WRITE_COMMNAD,DAC_ADDRESS_A, bram_value_a);
				Status=WriteDac(SpiInstancePtr,DAC_WRITE_COMMNAD,DAC_ADDRESS_B, bram_value_b);
			}
		} else {
			if(DAC_B_SINE_SRC){
	  			Status=WriteDac(SpiInstancePtr,DAC_WRITE_COMMNAD,DAC_ADDRESS_B, bram_value_a);
	  			Status=WriteDac(&SpiInstance,DAC_WRITE_COMMNAD,DAC_ADDRESS_A, VN_OFFSET_VALUE);
	  		}else{
				Status=WriteDac(SpiInstancePtr,DAC_WRITE_COMMNAD,DAC_ADDRESS_A, bram_value_a);
				Status=WriteDac(&SpiInstance,DAC_WRITE_COMMNAD,DAC_ADDRESS_B, VN_OFFSET_VALUE);
			}
		}
 	}

	if(Status!=XST_SUCCESS){
	   	return XST_FAILURE;
	}

	incr_size = incr_size + 2;

	return XST_SUCCESS;
}

//- This functions writes to DAC
	/* AD5065 DAC input register has the following format
	 * Right most nibble [3:0] is reserved
	 * 16 bit data is written in [19:4]
	 * Nibble [23:20] needs to be filled with address
	 * Nibble [27:24] has the command field
	 * [31:28] is reserved
	 */
int WriteDac(XSpi *SpiInstancePtr, u8 Command,u8 Addr, u16 Data)
{
	u8 WriteBuffer[DAC_WR_BUFFER_SIZE];

	WriteBuffer[0] = (Data & 0xF) << 4;
	WriteBuffer[1] = (Data >> 4) & 0xFF;
	WriteBuffer[2] = ((Data >> 12) & 0xF) | ((Addr & 0xF) << 4);
	WriteBuffer[3] = Command;

    XSpi_Transfer(SpiInstancePtr, WriteBuffer, NULL, DAC_WR_BUFFER_SIZE);

    return XST_SUCCESS;
}

//- This function loads the Block RAM with Sine wave samples
int LoadBramWithSineSamples(void) {
	int i = 0;
	u32 startmemadr, next_addr,offset;

	startmemadr = XPAR_BRAM_0_BASEADDR + SINE_DATA_OFFSET;
	offset = 0;
	for (i=0; i<3*SINE_SAMPLES;i++)
	{
		next_addr = startmemadr + offset;
		Xil_Out16(next_addr, Sine_data_arr[i]);
		offset = offset + 2;
	}
    return XST_SUCCESS;
}

//- This function initializes all peripherals connected to the MicroBlaze system
int initialize_peripherals(void) {
	int Status;
	int Index;
	XBram_Config *BramConfigPtr;

	Status = XUartLite_Initialize(&UartLite, UARTLITE_DEVICE_ID);
	if (Status != XST_SUCCESS)
	{
#ifdef ENABLE_DEBUG
		print("UART Initialization Failure!\n");
#endif
		return XST_FAILURE;
	}

	Status = XUartLite_SelfTest(&UartLite);
	if (Status != XST_SUCCESS)
	{
#ifdef ENABLE_DEBUG
		print("UART Self-Test Failure!\n");
#endif
		return XST_FAILURE;
	}

	Status = XGpio_Initialize(&Gpio, GPIO_EXAMPLE_DEVICE_ID);

	XGpio_SetDataDirection(&Gpio, 1, 0);

	XGpio_DiscreteWrite(&Gpio, 1, LED);

	for (Index = 0; Index < UART_BUFFER_SIZE; Index++)
	{
		ReceiveBuffer[Index] = 0;
	}


	BramConfigPtr = XBram_LookupConfig(BRAM_DEVICE_ID);
	if (BramConfigPtr == (XBram_Config *) NULL) {
#ifdef ENABLE_DEBUG
		print("Block RAM Controller Pointer Failure!\n");
#endif
		return XST_FAILURE;
	}
	Status = XBram_CfgInitialize(&Bram, BramConfigPtr, BramConfigPtr->CtrlBaseAddress);
	if (Status != XST_SUCCESS) {
#ifdef ENABLE_DEBUG
		print("Block RAM Controller Initialization Failure!\n");
#endif
		return XST_FAILURE;
	}
 	Status = XBram_SelfTest(&Bram,XBRAM_IR_ALL_MASK);

 	if (Status != XST_SUCCESS) {
#ifdef ENABLE_DEBUG
 		print("Block RAM Controller Self-test Failure!\n");
#endif
 		return XST_FAILURE;
 	}

#ifdef ENABLE_DEBUG
 		xil_printf("BRAM Controller Base = %0x\t High = %0x\n", BramConfigPtr->MemBaseAddress, BramConfigPtr->MemHighAddress);
#endif

 	Status = init_SysMon(&SysMonInst);
 	Status = InitSpiDevice(SPI_DEVICE_ID, &SpiInstance);
 	if (Status != XST_SUCCESS) {
#ifdef ENABLE_DEBUG
 		print("SPI Initialization Failure!\n");
#endif
 		return XST_FAILURE;
 	}

 	LoadBramWithSineSamples();

	return XST_SUCCESS;
}

//- This function initializes the XADC
int init_SysMon(XSysMon* SysMonInstPtr) {
	int Status;
	XSysMon_Config *ConfigPtr;

		/*
		 * Initialize the SysMon driver.
		 */
		 ConfigPtr = XSysMon_LookupConfig(SYSMON_DEVICE_ID);
		 if (ConfigPtr == NULL)
		 {
			return XST_FAILURE;
		 }

		 XSysMon_CfgInitialize(SysMonInstPtr, ConfigPtr, ConfigPtr->BaseAddress);

		 // Set single channel mode of operation
		 XSysMon_SetSequencerMode(SysMonInstPtr, XSM_SEQ_MODE_SINGCHAN);

		 //Enable channel Vp/Vn
		 Status = XSysMon_SetSeqChEnables(SysMonInstPtr, XSM_SEQ_CH_VPVN);

		 if (Status != XST_SUCCESS)
		 {
		 	return XST_FAILURE;
		 }

		 //Change clock divide to slow down XADC
		 //- Changed to 5 for design operating at 125MHz
		 //XSysMon_SetAdcClkDivisor(SysMonInstPtr, 5);
		 XSysMon_SetAdcClkDivisor(SysMonInstPtr, 4);

		 //Enter into continuous channel mode
		 XSysMon_SetSequencerMode(SysMonInstPtr, XSM_SEQ_MODE_CONTINPASS);

	return XST_SUCCESS;
}

/* This function reads the voltage over PMBUS given device and page address
 * Interpretation of read values
 * For example-
	Data[0] = 0xF6; Data[1] = 0xF
	Values are read LSB first so in the LINEAR16 format what is received is FF6
	Actual voltage = 0xFF6 (in decimal)/4096 = 4086/4096 = 0.99v
 */
u8 ReadVoltage(u8 DevAdrs, u8 PageAdrs, u8 *RecvBuf)
{
	u8 RxByteCnt;
	u8 tmpVar;

	tmpVar = RecvBuf[0];
	RecvBuf[0] = RecvBuf[1];
	RecvBuf[1] = tmpVar;
#ifdef ENABLE_DEBUG
		xil_printf("ReadVoltage: DevAdrs = %0x, PageAdrs = %0x, RxByteCnt=%0d, Data[0]=%0x, Data[1]=%0x\n",
				DevAdrs, PageAdrs, (int)RxByteCnt, RecvBuf[0], RecvBuf[1]);
#endif
	return RxByteCnt;
}

/* This function reads the current over PMBUS given device and page address for a rail
 * Interpretation of read values
 * For example-
	Data[0] = 0x76; Data[1] = 0xCA
	Values are read LSB first so in the LINEAR11 (5.11) format what is received is 0xCA76
	Actual current calculation:
		exponent is 11001 which is -7 (-7 + 11 = 4);
		shift left mantissa by 4 = 01001110110 which is 0010011101100000 = 0x2760
		0x2760 x 2**(-11) = 4.921A
*/
u8 ReadCurrent(u8 DevAdrs, u8 PageAdrs, u8 *RecvBuf)
{
	u8 RxByteCnt;
	u8 tmpVar;

	tmpVar = RecvBuf[0];
	RecvBuf[0] = RecvBuf[1];
	RecvBuf[1] = tmpVar;
#ifdef ENABLE_DEBUG
		xil_printf("ReadCurrent: DevAdrs = %0x, PageAdrs = %0x, RxByteCnt=%0d, Data[0]=%0x, Data[1]=%0x\n",
					DevAdrs, PageAdrs, (int)RxByteCnt, RecvBuf[0], RecvBuf[1]);
#endif
	return RxByteCnt;
}

/*
 * This function programs a particular voltage on rail
 * 	DevAdrs - 7-bit address of the device
 * 	PageAdrs - Page address of the supply voltage rail
 * 	SendBufPtr - value to be programmed - expected 2 bytes in LINEAR16 format with LS followed by MS
 * 	Command - VOUT_MAX or VOUT_COMMAND for voltage programming
 */

int ReadExtSensorData(XSysMon* SysMonInstPtr,u8 DevAdrs, u8 PageAdrs, u8 *SendBufPtr)
{
	u16 value=0x0;
	int Status;
	EocPoll = FALSE;
	volatile int i,j;
		switch (PageAdrs) {
		case 0x0:{
			if(DevAdrs==0x41){
				Status = SetSeqMode(SysMonInstPtr, XSM_SEQ_CH_VCCINT, XSM_SEQ_MODE_CONTINPASS);
				XSysMon_WriteReg(XPAR_AXI_XADC_0_BASEADDR, XSM_FLAG_REG_OFFSET-4, 0x0C2);
				value = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_VCCINT_OFFSET);
			}
			else if(DevAdrs==0x51){
				Status = SetSeqMode(SysMonInstPtr, XSM_SEQ_CH_AUX01, XSM_SEQ_MODE_CONTINPASS);
				XSysMon_WriteReg(XPAR_AXI_XADC_0_BASEADDR, XSM_FLAG_REG_OFFSET-4, 0x012);
				for( i=0; i<1000;i++){
					for( j=0; j<100;j++);
				}
				while (EocPoll!= TRUE)
				{
					Status = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_SR_OFFSET);
					if ((Status & XSM_SR_EOC_MASK)==XSM_SR_EOC_MASK)
					{
						EocPoll= TRUE;
					}
				}

				EocPoll = FALSE;
				value = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_AUX01_OFFSET);
			}
			XSysMon_WriteReg(SysMonInstPtr->Config.BaseAddress, XSM_SRR_OFFSET,0x000A);
			break;
		}
		case 0x1:{
			if(DevAdrs==0x41){
				Status = SetSeqMode(SysMonInstPtr, XSM_SEQ_CH_VCCAUX, XSM_SEQ_MODE_CONTINPASS);
				XSysMon_WriteReg(XPAR_AXI_XADC_0_BASEADDR, XSM_FLAG_REG_OFFSET-4, 0x0C2);
				value = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_VCCAUX_OFFSET);
			}
			else if(DevAdrs==0x51){
				Status = SetSeqMode(SysMonInstPtr, XSM_SEQ_CH_AUX01, XSM_SEQ_MODE_CONTINPASS);
				XSysMon_WriteReg(XPAR_AXI_XADC_0_BASEADDR, XSM_FLAG_REG_OFFSET-4, 0x052);
				for( i=0; i<1000;i++){
					for( j=0; j<100;j++);
				}
				while (EocPoll!= TRUE)
				{
					Status = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_SR_OFFSET);
					if ((Status & XSM_SR_EOC_MASK)==XSM_SR_EOC_MASK)
					{
						EocPoll= TRUE;
					}
				}

				EocPoll = FALSE;
				value = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_AUX01_OFFSET);
			}
			XSysMon_WriteReg(SysMonInstPtr->Config.BaseAddress, XSM_SRR_OFFSET,0x000A);
			break;
		}
		case 0x2:{
			if(DevAdrs==0x41){
				Status = SetSeqMode(SysMonInstPtr, XSM_SEQ_CH_VBRAM, XSM_SEQ_MODE_CONTINPASS);
				XSysMon_WriteReg(XPAR_AXI_XADC_0_BASEADDR, XSM_FLAG_REG_OFFSET-4, 0x0C2);
				value = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_VBRAM_OFFSET);
			}
			else if(DevAdrs==0x51){
				Status = SetSeqMode(SysMonInstPtr, XSM_SEQ_CH_AUX01, XSM_SEQ_MODE_CONTINPASS);
				XSysMon_WriteReg(XPAR_AXI_XADC_0_BASEADDR, XSM_FLAG_REG_OFFSET-4, 0x092);
				for( i=0; i<1000;i++){
					for( j=0; j<100;j++);
				}
				while (EocPoll!= TRUE)
				{
					Status = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_SR_OFFSET);
					if ((Status & XSM_SR_EOC_MASK)==XSM_SR_EOC_MASK)
					{
						EocPoll= TRUE;
					}
				}

				EocPoll = FALSE;
				value = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_AUX01_OFFSET);
			}
			XSysMon_WriteReg(SysMonInstPtr->Config.BaseAddress, XSM_SRR_OFFSET,0x000A);
			break;
		}
		case 0x3: {
			if(DevAdrs==0x41){
				Status = SetSeqMode(SysMonInstPtr, XSM_SEQ_CH_AUX01, XSM_SEQ_MODE_CONTINPASS);
				XSysMon_WriteReg(XPAR_AXI_XADC_0_BASEADDR, XSM_FLAG_REG_OFFSET-4, 0x0D2);
			}
			else if(DevAdrs==0x51){
				Status = SetSeqMode(SysMonInstPtr, XSM_SEQ_CH_AUX01, XSM_SEQ_MODE_CONTINPASS);
				XSysMon_WriteReg(XPAR_AXI_XADC_0_BASEADDR, XSM_FLAG_REG_OFFSET-4, 0x112);
			}
			for( i=0; i<1000;i++){
				for( j=0; j<100;j++);
			}
			while (EocPoll!= TRUE)
			{
				Status = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_SR_OFFSET);
				if ((Status & XSM_SR_EOC_MASK)==XSM_SR_EOC_MASK)
				{
					EocPoll= TRUE;
				}
			}

			EocPoll = FALSE;
			value = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_AUX01_OFFSET);
			XSysMon_WriteReg(SysMonInstPtr->Config.BaseAddress, XSM_SRR_OFFSET,0x000A);
			break;
		}
		case 0x4: {
			if(DevAdrs==0x41){
				Status = SetSeqMode(SysMonInstPtr, XSM_SEQ_CH_AUX01, XSM_SEQ_MODE_CONTINPASS);
				XSysMon_WriteReg(XPAR_AXI_XADC_0_BASEADDR, XSM_FLAG_REG_OFFSET-4, 0x152);
			}
			else if(DevAdrs==0x51){
				Status = SetSeqMode(SysMonInstPtr, XSM_SEQ_CH_AUX01, XSM_SEQ_MODE_CONTINPASS);
				XSysMon_WriteReg(XPAR_AXI_XADC_0_BASEADDR, XSM_FLAG_REG_OFFSET-4, 0x192);
			}
			//for( i=0; i<10000;i++);
			for( i=0; i<1000;i++){
				for( j=0; j<100;j++);
			}
			while (EocPoll!= TRUE)
			{
				Status = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_SR_OFFSET);
				if ((Status & XSM_SR_EOC_MASK)==XSM_SR_EOC_MASK)
				{
					EocPoll= TRUE;
				}
			}

			EocPoll = FALSE;
			value = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_AUX01_OFFSET);
			XSysMon_WriteReg(SysMonInstPtr->Config.BaseAddress, XSM_SRR_OFFSET,0x000A);
			break;
		}
		case 0x5: {
			if(DevAdrs==0x41){
				Status = SetSeqMode(SysMonInstPtr, XSM_SEQ_CH_AUX01, XSM_SEQ_MODE_CONTINPASS);
				XSysMon_WriteReg(XPAR_AXI_XADC_0_BASEADDR, XSM_FLAG_REG_OFFSET-4, 0x1D2);
				for( i=0; i<1000;i++){
					for( j=0; j<100;j++);
				}
				while (EocPoll!= TRUE)
				{
					Status = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_SR_OFFSET);
					if ((Status & XSM_SR_EOC_MASK)==XSM_SR_EOC_MASK)
					{
						EocPoll= TRUE;
					}
				}
				EocPoll = FALSE;
				value = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_AUX01_OFFSET);
			}
			else if(DevAdrs==0x51){
				Status = SetSeqMode(SysMonInstPtr, XSM_SEQ_CH_AUX09, XSM_SEQ_MODE_CONTINPASS);
				XSysMon_WriteReg(XPAR_AXI_XADC_0_BASEADDR, XSM_FLAG_REG_OFFSET-4, 0x012);
				for( i=0; i<61;i++){
					for( j=0; j<10;j++);
				}
				while (EocPoll!= TRUE)
				{
					Status = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_SR_OFFSET);
					if ((Status & XSM_SR_EOC_MASK)==XSM_SR_EOC_MASK)
					{
						EocPoll= TRUE;
					}
				}
				EocPoll = FALSE;
				value = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_AUX09_OFFSET);
			}
			XSysMon_WriteReg(SysMonInstPtr->Config.BaseAddress, XSM_SRR_OFFSET,0x000A);
			break;
		}
		case 0x6:{
			if(DevAdrs==0x41){
				Status = SetSeqMode(SysMonInstPtr, XSM_SEQ_CH_AUX09, XSM_SEQ_MODE_CONTINPASS);
				XSysMon_WriteReg(XPAR_AXI_XADC_0_BASEADDR, XSM_FLAG_REG_OFFSET-4, 0x052);
			}
			else if(DevAdrs==0x51){
				Status = SetSeqMode(SysMonInstPtr, XSM_SEQ_CH_AUX09, XSM_SEQ_MODE_CONTINPASS);
				XSysMon_WriteReg(XPAR_AXI_XADC_0_BASEADDR, XSM_FLAG_REG_OFFSET-4, 0x092);
			}
			for( i=0; i<1000;i++){
				for( j=0; j<100;j++);
			}
			while (EocPoll!= TRUE)
			{
				Status = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_SR_OFFSET);
				if ((Status & XSM_SR_EOC_MASK)==XSM_SR_EOC_MASK)
				{
					EocPoll= TRUE;
				}
			}

			EocPoll = FALSE;
			value = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_AUX09_OFFSET);
			XSysMon_WriteReg(SysMonInstPtr->Config.BaseAddress, XSM_SRR_OFFSET,0x000A);
			break;
		}
		case 0x7:{
			if(DevAdrs==0x41){
				Status = SetSeqMode(SysMonInstPtr, XSM_SEQ_CH_AUX09, XSM_SEQ_MODE_CONTINPASS);
				XSysMon_WriteReg(XPAR_AXI_XADC_0_BASEADDR, XSM_FLAG_REG_OFFSET-4,0x0D2);
			}
			else if(DevAdrs==0x51){
				Status = SetSeqMode(SysMonInstPtr, XSM_SEQ_CH_AUX09, XSM_SEQ_MODE_CONTINPASS);
				XSysMon_WriteReg(XPAR_AXI_XADC_0_BASEADDR, XSM_FLAG_REG_OFFSET-4, 0x0112);
			}
			for( i=0; i<1000;i++){
				for( j=0; j<100;j++);
			}
			while (EocPoll!= TRUE)
			{
				Status = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_SR_OFFSET);
				if ((Status & XSM_SR_EOC_MASK)==XSM_SR_EOC_MASK)
				{
					EocPoll= TRUE;
				}
			}

			EocPoll = FALSE;
			value = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_AUX09_OFFSET);
			XSysMon_WriteReg(SysMonInstPtr->Config.BaseAddress, XSM_SRR_OFFSET,0x000A);
			break;
		}
		case 0x8:{
			if(DevAdrs==0x41){
				Status = SetSeqMode(SysMonInstPtr, XSM_SEQ_CH_AUX09, XSM_SEQ_MODE_CONTINPASS);
				XSysMon_WriteReg(XPAR_AXI_XADC_0_BASEADDR, XSM_FLAG_REG_OFFSET-4, 0x152);
			}
			else if(DevAdrs==0x51){
				Status = SetSeqMode(SysMonInstPtr, XSM_SEQ_CH_AUX09, XSM_SEQ_MODE_CONTINPASS);
				XSysMon_WriteReg(XPAR_AXI_XADC_0_BASEADDR, XSM_FLAG_REG_OFFSET-4, 0x192);
			}
			for( i=0; i<1000;i++){
				for( j=0; j<100;j++);
			}
			while (EocPoll!= TRUE)
			{
				Status = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_SR_OFFSET);
				if ((Status & XSM_SR_EOC_MASK)==XSM_SR_EOC_MASK)
				{
					EocPoll= TRUE;
				}
			}

			EocPoll = FALSE;
			value = XSysMon_ReadReg(XPAR_AXI_XADC_0_BASEADDR, XSM_AUX09_OFFSET);
			XSysMon_WriteReg(SysMonInstPtr->Config.BaseAddress, XSM_SRR_OFFSET,0x000A);
			break;
		}
		}


	*SendBufPtr=((value & 0xff00) >> 8);
	*(++SendBufPtr)=(value & 0xff);
	return 1;
}
