/******************************************************************************
*
* Copyright (C) 2009 - 2014 Xilinx, Inc.  All rights reserved.
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* Use of the Software is limited solely to applications:
* (a) running on a Xilinx device, or
* (b) that interact with a Xilinx device through a bus or interconnect.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
* XILINX  BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
* OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* Except as contained in this notice, the name of the Xilinx shall not be used
* in advertising or otherwise to promote the sale, use or other dealings in
* this Software without prior written authorization from Xilinx.
*
******************************************************************************/

/*
 * helloworld.c: simple test application
 *
 * This application configures UART 16550 to baud rate 9600.
 * PS7 UART (Zynq) is not initialized by this application, since
 * bootrom/bsp configures it to baud rate 115200
 *
 * ------------------------------------------------
 * | UART TYPE   BAUD RATE                        |
 * ------------------------------------------------
 *   uartns550   9600
 *   uartlite    Configurable only in HW design
 *   ps7_uart    115200 (configured by bootrom/bsp)
 *
 *******************************************************************************/

#include <stdio.h>
#include "xil_printf.h"
#include "xparameters.h"
#include "xspi.h"
#include "xil_io.h"
//#include "platform.h"


XSpi spi;
int32_t spi_init(uint32_t device_id,XSpi *InstancePtr);
int spi_write_data(uint32_t addr, uint8_t value);
uint8_t spi_read_data(uint16_t addr);


/* ADC3669 REGISTERS */

#define CFG_RDY_REG 			0x25    	// Read the D[4] -- if 1 power supply, reset seq is good, device is ready
#define RESET_REG 				0x100   	// Write '1' in D[0] to reset all internal registers to default values
#define GLOBAL_PLW_DWN 			0x101  		// Write '1' in D[4] to power down the entire device
#define CH_TERM  				0x104 		// Internal termination -- D[1] - ChB, D[0] - ChA. Default 100Ohms.

#define CHANNEL_SWAP 			0x110 		// D[1] - '0' - Swaps ChA and ChB; '1' - Normal Operation
#define FCLK_DUTYCYCLE			0x115		// D[3] - '1' - FClk stays high for 50% of the output sample
#define LVDS_EDGE_SWAP 			0x116		// D[6] - '1' - Output Bits on rising and falling edge are swapped

#define TEST_PATTERN	 		0x14A		// D[4] - '0' - ADC Clk, '1' - DDC Clk; D[2-0] - Test Patterns
#define CUSTOM_PATTERN_LSB 		0x14B
#define CUSTOM_PATTERN 			0x14C
#define CUSTOM_PATTERN_MSB 		0x14D

#define DIGITAL_GAIN_CHA  		0x15B
#define DIGITAL_GAIN_CHB  		0x15C

#define DDC_MODE_SEL 			0x162		// D[2] - '1' - Complex decimation, D[1] - '1' - 32-bit resolution, D[0] - '1' - offset binary
#define DDC_INPUT_MUX			0x163		// input data source to decimation filters, channel A and B swapping
#define NCO_MODE				0x164		// NCO update and Mode
#define NCO_SEL_EN				0x165		// Bit[1] - '1' - Enables NCO selection via SPI register 0x166
#define DDC_NCO_SEL				0x166		// selects which of the four frequencies are active
#define UNEQUAL_DECI_F01		0x167		// Unequal decimation factors for DDC0, DDC1
#define UNEQUAL_DECI_F23 		0x168		// Unequal decimation factors for DDC2, DDC3
#define COMMON_DECIMATION_SEL	0x169		// Number of DDCs and common decimation factor and unequal decimation selection
#define CLOCK_DIV_ENABLE 		0x590

#define DDC0_NCO_FREQ0_0		0x200		// LSB
#define DDC0_NCO_FREQ0_1		0x201
#define DDC0_NCO_FREQ0_2		0x202
#define DDC0_NCO_FREQ0_3		0x203
#define DDC0_NCO_FREQ0_4		0x204
#define DDC0_NCO_FREQ0_5		0x205		// MSB

#define DDC1_NCO_FREQ0_0		0x240		// LSB
#define DDC1_NCO_FREQ0_1		0x241
#define DDC1_NCO_FREQ0_2		0x242
#define DDC1_NCO_FREQ0_3		0x243
#define DDC1_NCO_FREQ0_4		0x244
#define DDC1_NCO_FREQ0_5		0x245		// MSB

/// threshold and testing functionality registors to be added

#define UNITRAMP
#define CUSTOM_PATTERN_TOGGLE
#define CH_TERM_ENABLE
#define CH_SWAP
#define bits_swap
//#define GAIN_INC

#define FCLK_DUTYCYLE_50P

#define MB_GPIO 0x40000000

int main()
{

	uint8_t data;
	int ret = 0;

	init_platform();

	ret = spi_init(XPAR_AXI_QUAD_SPI_0_DEVICE_ID, &spi);
	if(!ret){
	   xil_printf("spi_init failed:%d\n",ret);
	}

	Xil_Out32(XPAR_AXI_QUAD_SPI_0_BASEADDR + 0x60, 0x186);				// SPI mode
	ret = Xil_In32(XPAR_AXI_QUAD_SPI_0_BASEADDR + 0x60);

	spi_read_data(CFG_RDY_REG);											// Device Readiness Check
	usleep(1);


//   while(1) {

	   data = spi_read_data(CFG_RDY_REG);
	   xil_printf("CFG_READY_REG:%d\n",data);

#ifndef FCLK_DUTYCYLE_50P
	   spi_write_data(FCLK_DUTYCYCLE, 0x08);
	   usleep(1);
	   data = spi_read_data(FCLK_DUTYCYCLE);
	   xil_printf("FCLK_DUTYCYCLE:%d\n",data);
#endif

#ifdef DDC_CHANNEL_SEL
	   spi_write_data(DDC_INPUT_MUX, 0x11);				//all DDCs get input from ChB;
	   usleep(1);
	   data=spi_read_data(DDC_INPUT_MUX);
	   xil_printf("DDC_INPUT_MUX:%d\n",data);
#endif


#ifndef COMPLEX_DECIMATION_EN_x2
	   spi_write_data(DDC_MODE_SEL,0x04);		//Complex Decimation, 16-bit, 2s complement
	   usleep(1);
	   data=spi_read_data(DDC_MODE_SEL);
	   xil_printf("DDC_MODE_SEL:%d\n",data);

	   spi_write_data(COMMON_DECIMATION_SEL,0x01);
	   usleep(1);
	   data=spi_read_data(COMMON_DECIMATION_SEL);
	   xil_printf("COMMON_DECIMATION_SEL:%d\n",data);

#ifndef NCO_EN
	   spi_write_data(NCO_SEL_EN,0x02);
	   usleep(1);

	   spi_write_data(DDC0_NCO_FREQ0_0,0xAA);
	   usleep(1);
	   spi_write_data(DDC0_NCO_FREQ0_1,0xAA);
	   usleep(1);
	   spi_write_data(DDC0_NCO_FREQ0_2,0xAA);
	   usleep(1);
	   spi_write_data(DDC0_NCO_FREQ0_3,0xAA);
	   usleep(1);
	   spi_write_data(DDC0_NCO_FREQ0_4,0xAA);
	   usleep(1);
	   spi_write_data(DDC0_NCO_FREQ0_5,0x6A);
	   usleep(1);


	   spi_write_data(DDC1_NCO_FREQ0_0,0xAA);
	   usleep(1);
	   spi_write_data(DDC1_NCO_FREQ0_1,0xAA);
	   usleep(1);
	   spi_write_data(DDC1_NCO_FREQ0_2,0xAA);
	   usleep(1);
	   spi_write_data(DDC1_NCO_FREQ0_3,0xAA);
	   usleep(1);
	   spi_write_data(DDC1_NCO_FREQ0_4,0xAA);
	   usleep(1);
	   spi_write_data(DDC1_NCO_FREQ0_5,0x6A);
	   usleep(1);



#ifdef INDIVIDUAL_NCO_UPDATE
	   spi_write_data(NCO_MODE,0x00);
	   usleep(1);
	   spi_write_data(NCO_MODE,0x30);		//Update NCO1,0 frequencies
	   usleep(1);
	   spi_write_data(NCO_MODE,0x00);
#endif

	   spi_write_data(NCO_SEL_EN,0x02);
	   usleep(1);
	   spi_write_data(NCO_SEL_EN,0x03);
	   usleep(1);
	   spi_write_data(NCO_SEL_EN,0x02);
	   usleep(1);

#endif

#endif




//	   spi_write_data(DDC_DEC_MODE_SEL1,0x01);			//0x169 - 0x01
//	   usleep(1);
//	   data=spi_read_data(DDC_DEC_MODE_SEL1);
//	   xil_printf("DDC_DEC_MODE_SEL1:%d\n",data);


//	   usleep(10);
//	   spi_write_data(DDC_BYPASS,0x00);
//	   usleep(1);
//	   data=spi_read_data(DDC_BYPASS);
//	   xil_printf("DDC_BYPASS:%d\n",data);
//	   usleep(10);
//	   spi_write_data(DDC_DEC_MODE_SEL0,0x01);
//	   usleep(1);
//	   data=spi_read_data(DDC_DEC_MODE_SEL0);
//	   xil_printf("DDC_DEC_MODE_SEL0:%d\n",data);
//	   usleep(10);
//	   spi_write_data(DDC_DEC_MODE_SEL1,0x2);
//	   usleep(1);
//	   data=spi_read_data(DDC_DEC_MODE_SEL1);
//	   xil_printf("DDC_DEC_MODE_SEL1:%d\n",data);
//
//
//	   spi_write_data(CLOCK_DIV_ENABLE,0x01);   // DECIMATION CLK OUT ENABLE
//	   usleep(1);
//	   data=spi_read_data(CLOCK_DIV_ENABLE);
//	   xil_printf("CLOCK_DIV_ENABLE:%d\n",data);

#ifdef CUSTOM_PATTERN_TOGGLE
	   spi_write_data(CUSTOM_PATTERN_LSB,0x55);
	   usleep(1);
	   data=spi_read_data(CUSTOM_PATTERN_LSB);
	   xil_printf("CUSTOM_PATTERN_LSB:%d\n",data);
	   usleep(1);
	   spi_write_data(CUSTOM_PATTERN,0x55);

	   usleep(1);
	   data=spi_read_data(CUSTOM_PATTERN);

	   xil_printf("CUSTOM_PATTERN:%d\n",data);
	   usleep(1);
	   spi_write_data(CUSTOM_PATTERN_MSB,0x05);
	   usleep(1);
	   data=spi_read_data(CUSTOM_PATTERN_MSB);
	   xil_printf("CUSTOM_PATTERN_MSB:%d\n",data);
	   usleep(1);
	   spi_write_data(TEST_PATTERN,0x05);      // Test Pattern = 5 => Toggles between custom pattern and invert of the custom pattern; Test Pattern = 2 and custom pattern LSB = 0x10 => UNIT RAMP
	   usleep(1);
	   data=spi_read_data(TEST_PATTERN);
	   xil_printf("TEST_PATTERN:%d\n",data);
#endif

#ifndef UNITRAMP
	   spi_write_data(TEST_PATTERN,2);      // test pattern = 2 and custom test pattern LSB = 0x10 then UNIT RAMP
	   usleep(1);
	   data=spi_read_data(TEST_PATTERN);
	   xil_printf("TEST_PATTERN:%d\n",data);
	   spi_write_data(CUSTOM_PATTERN_LSB,0x10);
	   usleep(1);
	   data=spi_read_data(CUSTOM_PATTERN_LSB);
	   xil_printf("CUSTOM_PATTERN_LSB:%d\n",data);
	   usleep(1);
#endif

	   Xil_Out32(MB_GPIO+8,1);
	   spi_write_data(TEST_PATTERN,0x00);      // Test Pattern = 5 => Toggles between custom pattern and invert of the custom pattern; Test Pattern = 2 and custom pattern LSB = 0x10 => UNIT RAMP
	   usleep(1);
	   data=spi_read_data(TEST_PATTERN);
	   xil_printf("TEST_PATTERN:%d\n",data);



#ifdef CH_SWAP
	   data=spi_read_data(CHANNEL_SWAP);
	   xil_printf("CHANNEL_SWAP:%d\n",data);
	   spi_write_data(CHANNEL_SWAP,2);
	   usleep(1);
	   data=spi_read_data(CHANNEL_SWAP);
	   xil_printf("CHANNEL_SWAP:%d\n",data);
#endif


#ifdef bits_swap
	   spi_write_data(LVDS_EDGE_SWAP,64);
	   usleep(1);
	   data=spi_read_data(LVDS_EDGE_SWAP);
	   xil_printf("LVDS_EDGE_SWAP:%d\n",data);

#endif



#ifdef GAIN_INC
	   usleep(1);
	   data=spi_read_data(DIGITAL_GAIN_CHA);
	   xil_printf("DIGITAL_GAIN_CHA:%d\n",data);


	   spi_write_data(DIGITAL_GAIN_CHA,127);
	   usleep(1);
	   data=spi_read_data(DIGITAL_GAIN_CHA);
	   xil_printf("DIGITAL_GAIN_CHA:%d\n",data);

	   usleep(1);
	   data=spi_read_data(DIGITAL_GAIN_CHB);
	   xil_printf("DIGITAL_GAIN_CHB:%d\n",data);

	   spi_write_data(DIGITAL_GAIN_CHB,127);
	   usleep(1);
	   data=spi_read_data(DIGITAL_GAIN_CHB);
	   xil_printf("DIGITAL_GAIN_CHB:%d\n",data);
#endif

#ifndef CH_TERM_ENABLE   // this will enable 200 ohm termination instead of 100 ohm
	   spi_write_data(CH_TERM,3);
	   usleep(1);
	   data=spi_read_data(CH_TERM);
	   xil_printf("CH_TERM_enabled:%d\n",data);
#endif



#ifndef CUSTOM_PATTERN_TOGGLE
	   spi_write_data(CUSTOM_PATTERN_LSB,0x2);
	   usleep(1);
	   data=spi_read_data(CUSTOM_PATTERN_LSB);
	   xil_printf("CUSTOM_PATTERN_LSB:%d\n",data);
	   usleep(1);
//	   spi_write_data(CUSTOM_PATTERN,0x55);
//	   usleep(1);
//	   data=spi_read_data(CUSTOM_PATTERN);
//	   xil_printf("CUSTOM_PATTERN:%d\n",data);
//	   usleep(1);
//	   spi_write_data(CUSTOM_PATTERN_MSB,0x5);
//	   usleep(1);
//	   data=spi_read_data(CUSTOM_PATTERN_MSB);
//	   xil_printf("CUSTOM_PATTERN_MSB:%d\n",data);
	   usleep(1);
	   spi_write_data(TEST_PATTERN,2);      // test pattern = 2 and custom test pattern LSB = 0x10 then UNIT RAMP
	   usleep(1);
	   data=spi_read_data(TEST_PATTERN);
	   xil_printf("TEST_PATTERN:%d\n",data);
#endif

	   usleep(100);

//    }
    return 0;

    print("Hello -World\n\r");
    print("Successfully ran Hello World application");
    cleanup_platform();
    return 0;
}



int32_t spi_init(uint32_t device_id,XSpi *InstancePtr)

{
	uint32_t base_addr	 = 0;
	uint32_t spi_options = 0;
	XSpi_Config *spi_config;

	XSpi_Initialize(InstancePtr, device_id);
	XSpi_Stop(InstancePtr);
	spi_options = XSP_MASTER_OPTION |
				  XSP_CLK_PHASE_1_OPTION |
				  XSP_MANUAL_SSELECT_OPTION;
	XSpi_SetOptions(InstancePtr, spi_options);
	XSpi_Start(InstancePtr);
	XSpi_IntrGlobalDisable(InstancePtr);
	XSpi_SetSlaveSelect(InstancePtr, 1);

	return 1;
}

uint8_t spi_read_data(uint16_t addr)
{
	uint8_t send_buffer[2];
	uint32_t data1;

	int value=1;    // spi read bit
	int length = 0;
	int bytes_number = 3;
	value = (value << 23);
//	value = value|(length <<20);
	value = value|(addr <<8);
	send_buffer[2] = value ;
	send_buffer[1] = value >> 8 ;
	send_buffer[0] = value >> 16 ;
	XSpi_Transfer(&spi, send_buffer, &data1, bytes_number);
	return (data1 >> 16);
}

int spi_write_data(uint32_t addr,uint8_t value)
{
	uint8_t send_buffer[3];
	uint8_t recv_buffer[3];

	uint32_t value1=0;   // spi write bit
	uint32_t length = 0;
	int bytes_number = 3;
	value1 = (value1 << 23);
//	value1 = value1|(length <<20);
	value1 = value1|(addr <<8);
	value1= value1| (value);
	send_buffer[2] = value1 ;
	send_buffer[1] = value1 >> 8 ;
	send_buffer[0] = value1 >> 16 ;
	XSpi_Transfer(&spi, send_buffer, recv_buffer, bytes_number);
	return 1;

}
