/*******************************************************************************
* (c) Copyright 2011 Microsemi Corporation.  All rights reserved.
*
* File: main.c
* File history:
*      Revision: 1.0 Date: September 09, 2011
*
* Description:
* This application code corresponds to the application note:
* "SmartFusion: Enhancing Analog Front-End Performance using Oversampling and
*  Fourth-Order Sigma-Delta Modulator - Improved Wire Implementation"
* This application configures the SmartFusion ACE peripheral and provides user
* interface to configure static parameters of fabric based Sigma-Delta modulator.
*
* Author: Corporate Applications Engineering
*********************************************************************************/

/**************************************************************************/
/* Standard Includes */
/**************************************************************************/
#include <stdio.h>
#include <string.h>
#include <math.h>

/**************************************************************************/
/* Firmware Includes */
/**************************************************************************/
#include "mss_uart.h"
#include "mss_ace.h"
#include "cpu_types.h"
#include "hw_reg_access.h"
#include "functions.h"

/**************************************************************************/
/* Function definitions */
/**************************************************************************/

void Modify_Q_C_Comp(void)
{
	uint16_t Q_comp_new, C_comp_new;
	uint16_t Q_comp_current, C_comp_current;
	uint16_t Q_comp_updated, C_comp_updated;
	const uint8_t currentvalue_QC[] = "\n\r Current Value of Quadratic Compensation is:	";
	const uint8_t currentvalue_CC[] = "\n\r Current Value of Cubic Compensation is:	";
	const uint8_t Enter_Quad_Comp[] = "\n\r Enter new value for Quad Comp in Range(0x0000-0xFFFF):";
	const uint8_t Enter_Cubic_Comp[] = "\n\r Enter new value for Cubic Comp in Range(0x0000-0xFFFF):";
	const uint8_t newvalue_QC[] = "\n\r Quadratic Compensation is Now set to:	";
	const uint8_t newvalue_CC[] = "\n\r Cubic Compensation is Now set to:	";

	Q_comp_current = HW_get_16bit_reg(0x40050004);
	C_comp_current = HW_get_16bit_reg(0x40050008);
	MSS_UART_polled_tx( &g_mss_uart0, currentvalue_QC, sizeof(currentvalue_QC));
	senddouble(Q_comp_current);
	MSS_UART_polled_tx( &g_mss_uart0, currentvalue_CC, sizeof(currentvalue_CC));
	senddouble(C_comp_current);
	MSS_UART_polled_tx( &g_mss_uart0, Enter_Quad_Comp, sizeof(Enter_Quad_Comp));
	Q_comp_new	= readword();
	HW_set_16bit_reg(0x40050004,Q_comp_new);
	MSS_UART_polled_tx( &g_mss_uart0, Enter_Cubic_Comp, sizeof(Enter_Cubic_Comp));
	C_comp_new = readword();
	HW_set_16bit_reg(0x40050008,C_comp_new);
	MSS_UART_polled_tx( &g_mss_uart0, newvalue_QC, sizeof(newvalue_QC));
	Q_comp_updated = HW_get_16bit_reg(0x40050004);
	senddouble(Q_comp_updated);
	MSS_UART_polled_tx( &g_mss_uart0, newvalue_CC, sizeof(newvalue_CC));
	C_comp_updated = HW_get_16bit_reg(0x40050008);
	senddouble(C_comp_updated);
}

void Modify_Quasi_Static_Inputs(void)
{
	/*Bits [7:4] - Clk_Div; [3:2] - RTZ_Mode; [1:0] - SD_MOD*/
	uint8_t Quasi_Static_Current_Byte;
	uint16_t Quasi_Static_New_Byte;
	uint8_t SD_MOD_Temp_Byte, RTZ_Mode_Temp_Byte, Clk_Div_Temp_Byte;
	uint8_t rx_size, user_selection;
	const uint8_t currentvalue_SD_MOD[] = "\n\r Current Value of SD_MOD input is:	";
	const uint8_t currentvalue_RTZ_MOD[] = "\n\r Current Value of RTZ_MOD input is:	";
	const uint8_t currentvalue_Clk_Div[] = "\n\r Current Value of Clk_Div input is:	";
	const uint8_t newvalue_SD_MOD[] = "\n\r New Value of SD_MOD input is:	";
	const uint8_t newvalue_RTZ_MOD[] = "\n\r New Value of RTZ_MOD input is:	";
	const uint8_t newvalue_Clk_Div[] = "\n\r New Value of Clk_Div input is:	";
	const uint8_t Changing_Quasi_Static_Inputs[] = "\n\r Would you like to change SD_MOD, RTZ & Clk_Div? : ";
	const uint8_t menu_msg[] =          "\n\r Please Type (y) to modify: Type any other key to bypass: ";
	const uint8_t SD_MOD_Input[] =      "\n\r SD_MOD: Enter 0 - 1st Order: 1 - 2nd Order: 2 - 4th Order: Default is 2 : ";
	const uint8_t RTZ_Mode_Input[] =    "\n\r RTZ_MODE: Enter 0-  Normal:1 - RTZ:2 - RTZ/RTO Default is 0 : ";
	const uint8_t Clk_Div_Input[] =    "\n\r Clk_Div: Enter Value in Range (0x1 -0xF): Default is 0 : ";

	Quasi_Static_Current_Byte 	= HW_get_16bit_reg(0x4005000C);
	MSS_UART_polled_tx( &g_mss_uart0, currentvalue_SD_MOD, sizeof(currentvalue_SD_MOD));
	sendnibble(Quasi_Static_Current_Byte & 0x03);
	MSS_UART_polled_tx( &g_mss_uart0, currentvalue_RTZ_MOD, sizeof(currentvalue_RTZ_MOD));
	sendnibble((Quasi_Static_Current_Byte & 0x0C)>> 2);
	MSS_UART_polled_tx( &g_mss_uart0, currentvalue_Clk_Div, sizeof(currentvalue_Clk_Div));
	sendnibble((Quasi_Static_Current_Byte & 0xF0) >> 4);
	MSS_UART_polled_tx( &g_mss_uart0, Changing_Quasi_Static_Inputs, sizeof(Changing_Quasi_Static_Inputs));
	MSS_UART_polled_tx( &g_mss_uart0, menu_msg, sizeof(menu_msg));
    do
	 {
	     rx_size = MSS_UART_get_rx(&g_mss_uart0, &user_selection, 1);
	 }
    while (rx_size ==0);
    if (user_selection == ('y')){
			MSS_UART_polled_tx( &g_mss_uart0, SD_MOD_Input, sizeof(SD_MOD_Input));
			do
			{
				     rx_size = MSS_UART_get_rx(&g_mss_uart0, &user_selection, 1);
			}
			while (rx_size ==0);
			switch(user_selection) {
				case ('0'):
				SD_MOD_Temp_Byte = 0x00;
				break;
				case ('1'):
				SD_MOD_Temp_Byte = 0x01;
				break;
				case ('2'):
    			SD_MOD_Temp_Byte = 0x02;
				break;
				default:
				SD_MOD_Temp_Byte = 0x02;
				break;

			}
			MSS_UART_polled_tx( &g_mss_uart0, RTZ_Mode_Input, sizeof(RTZ_Mode_Input));
			do
			{
				rx_size = MSS_UART_get_rx(&g_mss_uart0, &user_selection, 1);
			}
			while (rx_size ==0);
				switch(user_selection) {
					case ('0'):
					RTZ_Mode_Temp_Byte = 0x00;
					break;
					case ('1'):
					RTZ_Mode_Temp_Byte = 0x01;
					break;
					case ('2'):
					RTZ_Mode_Temp_Byte = 0x02;
					break;
					default:
					RTZ_Mode_Temp_Byte = 0x00;
					break;
				}
			MSS_UART_polled_tx( &g_mss_uart0, Clk_Div_Input, sizeof(Clk_Div_Input));
			Clk_Div_Temp_Byte	= readbyte();
			Clk_Div_Temp_Byte 	= (Clk_Div_Temp_Byte << 4);
			RTZ_Mode_Temp_Byte 	= (RTZ_Mode_Temp_Byte << 2);
			/* Construct New Byte */
			Quasi_Static_New_Byte =	( (Clk_Div_Temp_Byte ) | (RTZ_Mode_Temp_Byte) | (SD_MOD_Temp_Byte));
			/* Write New Byte */
			HW_set_16bit_reg(0x4005000C, Quasi_Static_New_Byte);
			/* Read Back Just Written Byte */
			Quasi_Static_Current_Byte 	= HW_get_16bit_reg(0x4005000C);
			MSS_UART_polled_tx( &g_mss_uart0, newvalue_SD_MOD, sizeof(newvalue_SD_MOD));
			sendnibble(Quasi_Static_Current_Byte & 0x03);
			MSS_UART_polled_tx( &g_mss_uart0, newvalue_RTZ_MOD, sizeof(newvalue_RTZ_MOD));
			sendnibble((Quasi_Static_Current_Byte & 0x0C)>> 2);
			MSS_UART_polled_tx( &g_mss_uart0, newvalue_Clk_Div, sizeof(newvalue_Clk_Div));
			sendnibble((Quasi_Static_Current_Byte & 0xF0) >> 4);
    }
}

/**************************************************************************/
/* Main Function */
/**************************************************************************/

int main(void)
{
	uint8_t rx_size, user_selection;
	const uint8_t design_name[] = "\n\r ***SmartFusion: Enhancing Analog Front-End performance using Oversampling***"
								  "\n\r ***and Fourth-Order Sigma-Delta Modulator - Improved Wire Implementation.***";

	const uint8_t menu_msg[] =          "\n\rDo you want to modify fabric Sigma-Delta Modulator parameters? "
										"\n\rIf yes, press (y):";
    const uint8_t case_default_msg[] =  "\n\r Invalid Selection: Please type :(y)to modify fabric Sigma-Delta Modulator parameters";


	/* UART Initialization and Configuration */
	MSS_UART_init
	(
			&g_mss_uart0,
			MSS_UART_57600_BAUD,
			MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT
	);

	/* ACE Initialization */
	ACE_init();

	/* Defining DAC0 Configuration */
	ACE_configure_sdd
	(
			SDD0_OUT,
			SDD_16_BITS,
			SDD_VOLTAGE_MODE | SDD_NON_RTZ,
			INDIVIDUAL_UPDATE
	);

	/* Enable SDD_0 */
	ACE_enable_sdd(SDD0_OUT);

	/* Setting Default Values at startup Modulator by writing to registers*/
	/* Bits [19:0] Input to Modulator */
	HW_set_32bit_reg(0x40050000, 0x00000000);
	/* Bits [14:0] Quadratic Compensation value */
	HW_set_32bit_reg(0x40050004, 0x00000000);
	/* Bits [14:0] Cubic Compensation value */
	HW_set_32bit_reg(0x40050008, 0x00000000);
	/* Bits [1:0] - Modulation Type
	   Bits [3:2] - RTZ_Mode
	   Bits [7:4] - Clk Divider Setting */
	HW_set_32bit_reg(0x4005000C, 0x00000042);
	MSS_UART_polled_tx( &g_mss_uart0, design_name, sizeof(design_name));
	MSS_UART_polled_tx( &g_mss_uart0, menu_msg, sizeof(menu_msg));

	do
	    {
	        rx_size = MSS_UART_get_rx(&g_mss_uart0, &user_selection, 1);
	    }
	    while (rx_size ==0);
	rx_size = 0;

	while (1)
	{
		do
		{
		switch (user_selection)
		{
		case('y'):
			Modify_Q_C_Comp();
			Modify_Quasi_Static_Inputs();
			MSS_UART_polled_tx( &g_mss_uart0, menu_msg, sizeof(menu_msg));
		    do
		    {
		        rx_size = MSS_UART_get_rx(&g_mss_uart0, &user_selection, 1);
		    }
	        while (rx_size ==0);
		break;

	    default:
		    MSS_UART_polled_tx( &g_mss_uart0, case_default_msg, sizeof(case_default_msg) );
		    do
		    {
		        rx_size = MSS_UART_get_rx(&g_mss_uart0, &user_selection, 1);
		    }
	        while (rx_size ==0);
        break;
	    }
		} while (user_selection != ('y'));
	}
    return 0;
}

