/**
 * \file common.c
 * \brief Contains Mykonos API common wrapper functions for user hardware platform drivers
 */

#include <stdio.h>
#include <time.h>
#include <errno.h>
#include <stdint.h>
#include <stdlib.h>
#include "common.h" 
#include "core_spi.h"
#include "sample_hw_platform.h"
#include "core_gpio.h"


extern spi_instance_t g_core_spi;
extern spi_instance_t g_core_spi1;
extern gpio_instance_t g_gpio_out;

static uint8_t _writeBitPolarity = 1;
static uint8_t _longInstructionWord = 1;
static uint8_t _chipSelectIndex = 4;

//static uint8_t g_master_tx_buffer[5] = { 0x00, 0x01, 0x02, 0x03, 0xAA};

int HAL_initSpi(uint8_t chipSelectIndex, uint8_t CPOLHA,uint8_t spiClkFreq_Hz);
int HAL_spiRead(uint8_t * write_buffer, uint32_t size_in_bytes,uint8_t * read_buffer );
int HAL_spiWrite(uint8_t * write_buffer, uint32_t size_in_bytes);
int HAL_setTimeout_ms(uint32_t timeOut_ms);
int HAL_setTimeout_us(uint32_t timeOut_us);
int HAL_hasTimeoutExpired();
//int nanosleep(struct timespec *waitTime, struct timespec *remaining);
//static uint8_t g_master_rx_buffer[8] = { 0u };
static uint32_t Timeout_check = 10;

ADI_LOGLEVEL CMB_LOGLEVEL = ADIHAL_LOG_NONE;

static uint32_t _desired_time_to_elapse_us = 0;
//extern spi_device spi_dev;

commonErr_t CMB_closeHardware(void)
{
    //HAL_closeSpi();
    //HAL_closeLogFile();

    return(COMMONERR_OK);
}

commonErr_t CMB_setGPIO(uint32_t gpio)
{
    return(COMMONERR_OK);
}

commonErr_t CMB_hardReset(uint8_t spiChipSelectIndex)
{

	uint32_t resetGPIO = 0;

#if 1

	switch(spiChipSelectIndex)
	{
		case 0://ad9371
			resetGPIO = GPIO_4;
			break;
		case 1://ad9528
			resetGPIO = GPIO_5;
			break;
		case 2://ad9731_1
			resetGPIO = GPIO_10;
			break;
		default:
			break;
	}


	GPIO_set_output( &g_gpio_out, resetGPIO,0x1 );
	CMB_wait_ms(1);
	
	GPIO_set_output( &g_gpio_out, resetGPIO,0x0);
	CMB_wait_ms(1);

	GPIO_set_output( &g_gpio_out, resetGPIO,0x1);
	CMB_wait_ms(1);
#endif
    return(COMMONERR_OK);
}

commonErr_t CMB_setSPIOptions(spiSettings_t *spiSettings)
{
    int32_t error = 0;
    _writeBitPolarity = spiSettings->writeBitPolarity & 0x01;
    _longInstructionWord = spiSettings->longInstructionWord & 0x01;

    error = HAL_initSpi((spiSettings->chipSelectIndex), (uint8_t)((spiSettings->CPOL <<1) | (spiSettings->CPHA)), (spiSettings->spiClkFreq_Hz));

    if(error < 0)
    {
        return(COMMONERR_FAILED);
    }

    return(COMMONERR_OK);
}

commonErr_t CMB_setSPIChannel(uint16_t chipSelectIndex )
{
    /* 0 = all chip selects de-asserted */
    _chipSelectIndex = (uint8_t)chipSelectIndex;

    return(COMMONERR_OK);
}

commonErr_t CMB_SPIWriteByte(spiSettings_t *spiSettings, uint16_t addr, uint8_t data)
{
    int32_t retval = 0;
    unsigned char txbuf[] = {0x00,0x00,0x00};

    if (_chipSelectIndex != spiSettings->chipSelectIndex)
    {
        if(CMB_setSPIOptions(spiSettings))
        {
            return(COMMONERR_FAILED);
        }

        if(CMB_setSPIChannel(spiSettings->chipSelectIndex))
        {
            return(COMMONERR_FAILED);
        }
    }

    if(CMB_LOGLEVEL & ADIHAL_LOG_SPI)
    {
        printf("SPIWrite: CS:%2d, ADDR:0x%03X, DATA:0x%02X \n", spiSettings->chipSelectIndex,addr, data);
    }

    if (spiSettings->longInstructionWord){
        txbuf[0] = ((_writeBitPolarity & 1) << 7) | ((addr >> 8) & 0x7F);
        txbuf[1] = addr & 0xFF;
        txbuf[2] = data;
        retval = HAL_spiWrite(txbuf, 3);

        if (retval < 0)
        {
            printf("Error writing SPI");
            return(COMMONERR_FAILED);
        }
    }
    else
    {
        txbuf[0] = ((_writeBitPolarity & 1) << 7) | (addr  & 0x7F);
        txbuf[1] = data;
        HAL_spiWrite(txbuf, 2);

        if (retval < 0)
        {
            printf("Error writing SPI");
            return(COMMONERR_FAILED);
        }
    }

    return(COMMONERR_OK);
}

commonErr_t CMB_SPIWriteBytes(spiSettings_t *spiSettings, uint16_t *addr, uint8_t *data, uint32_t count)
{
    uint32_t i = 0;
    uint32_t txBufIndex = 0;
    int32_t retval = 0;
    unsigned char txbuf[SPIARRAYSIZE] = {0x00};
    uint32_t spiArrayTripSize = SPIARRAYTRIPSIZE;

    if (_chipSelectIndex != spiSettings->chipSelectIndex)
    {
        if(CMB_setSPIOptions(spiSettings))
        {
            return(COMMONERR_FAILED);
        }

        if(CMB_setSPIChannel(spiSettings->chipSelectIndex))
        {
            return(COMMONERR_FAILED);
        }
    }

    if (spiSettings->longInstructionWord)
    {
        if (spiSettings->enSpiStreaming)
        {

        }
        else
        {
            txBufIndex = 0;

            for (i = 0; i < count; i++)
            {
                txbuf[txBufIndex++] = ((_writeBitPolarity & 1) << 7) | ((addr[i] >> 8) & 0x7F);
                txbuf[txBufIndex++] = (addr[i] & 0xFF);
                txbuf[txBufIndex++] = data[i];

                if(CMB_LOGLEVEL & ADIHAL_LOG_SPI)
                {
                    printf("SPIWrite: CS:%2d, ADDR:0x%03X, DATA:0x%02X \n", spiSettings->chipSelectIndex, addr[i], data[i]);
                }

                /* Send full buffer when possible */
                if (txBufIndex >= spiArrayTripSize)
                {
                    /* Send full buffer when possible */
                    retval = HAL_spiWrite(txbuf, txBufIndex);
                    txBufIndex = 0;
                }

            }

            /* Send any data that was not sent as a full buffer before */
            if (txBufIndex > 0)
            {
                retval = HAL_spiWrite(txbuf, txBufIndex);
                txBufIndex = 0;
            }

        }

        if (retval < 0)
        {
            printf("Error writing SPI");
            return(COMMONERR_FAILED);
        }
    }
    else
    {
        /* 8bit instruction word */
        if (spiSettings->enSpiStreaming)
        {

        }
        else
        {

            txBufIndex = 0;
            spiArrayTripSize = ((SPIARRAYSIZE / 2) * 2);

            for (i = 0; i < count; i++)
            {
                txbuf[txBufIndex++] = ((_writeBitPolarity & 1) << 7) | (addr[i]  & 0x7F);
                txbuf[txBufIndex++] = data[i];

                if(CMB_LOGLEVEL & ADIHAL_LOG_SPI)
                {
                	printf("SPIWrite: CS:%2d, ADDR:0x%03X, DATA:0x%02X \n", spiSettings->chipSelectIndex, addr[i], data[i]);
                }

                if (txBufIndex >= spiArrayTripSize)
                {
                    /* Send full buffer when possible */
                    retval = HAL_spiWrite(txbuf, txBufIndex);
                    txBufIndex = 0;
                }
            }

            /* Send any data that was not sent as a full buffer before */
            if (txBufIndex > 0)
            {
                retval = HAL_spiWrite(txbuf, txBufIndex);
                txBufIndex = 0;
            }

            if (retval < 0)
            {
                printf("Error writing SPI");
                return(COMMONERR_FAILED);
            }
        }
    }

    return(COMMONERR_OK);
}

commonErr_t CMB_SPIReadByte(spiSettings_t *spiSettings, uint16_t addr, uint8_t *readdata)
{
    uint8_t data=0;
    int32_t retval = 0;
    unsigned char txbuf[] = {0x00,0x00,0x00};

    if(_chipSelectIndex != spiSettings->chipSelectIndex)
    {
        if(CMB_setSPIOptions(spiSettings))
        {
            return(COMMONERR_FAILED);
        }
        if(CMB_setSPIChannel(spiSettings->chipSelectIndex))
        {
            return(COMMONERR_FAILED);
        }
    }
    if(spiSettings->longInstructionWord)
    {
        txbuf[0] = ((~_writeBitPolarity & 1) << 7) | ((addr >> 8) & 0x7F);
        txbuf[1] = addr & 0xFF;
        retval = HAL_spiRead(txbuf, 2, &data);
        if (retval < 0)
        {
            printf("Error writing SPI");
            return(COMMONERR_FAILED);
        }
        else
        {
            *readdata =(uint8_t)data;
        }
    }
    else
    {
        txbuf[0] = ((~_writeBitPolarity & 1) << 7) | (addr & 0x7F);
        retval = HAL_spiRead(txbuf, 1, &data);
        if (retval < 0)
        {
            printf("Error writing SPI");
            return(COMMONERR_FAILED);
        }
        else
        {
            *readdata =(uint8_t)data;
        }
    }
    if(CMB_LOGLEVEL & ADIHAL_LOG_SPI)
    {
    	printf("SPIRead: CS:%2d, ADDR:0x%03X, ReadData:0x%02X\n", spiSettings->chipSelectIndex, addr, *readdata);
    }

    return(COMMONERR_OK);
}

commonErr_t CMB_SPIWriteField(spiSettings_t *spiSettings, uint16_t addr, uint8_t field_val, uint8_t mask, uint8_t start_bit)
{
    uint8_t Val=0;

    if(CMB_LOGLEVEL & ADIHAL_LOG_SPI)
    {
    	printf("SPIWriteField: CS:%2d, ADDR:0x%03X, FIELDVAL:0x%02X, MASK:0x%02X, STARTBIT:%d \n", spiSettings->chipSelectIndex,addr, field_val, mask, start_bit);
    }
    if(CMB_SPIReadByte(spiSettings, addr, &Val))
    {
        return(COMMONERR_FAILED);
    }
    Val = (Val & ~mask) | ((field_val << start_bit) & mask);
    if(CMB_SPIWriteByte(spiSettings, addr, Val))
    {
        return(COMMONERR_FAILED);
    }

    return(COMMONERR_OK);
}

/* read a field in a single register space (not multibyte fields) */
commonErr_t CMB_SPIReadField(spiSettings_t *spiSettings, uint16_t addr, uint8_t *field_val, uint8_t mask, uint8_t start_bit)
{
    uint8_t data;

    if(CMB_SPIReadByte(spiSettings, addr, &data))
    {
        return(COMMONERR_FAILED);
    }
    *field_val =(uint8_t)((data & mask) >> start_bit);

    if(CMB_LOGLEVEL & ADIHAL_LOG_SPI)
    {
    	printf("SPIReadField: CS:%2d, ADDR:0x%03X, MASK:0x%02X, STARTBIT:%d, FieldVal:0x%02X\n", spiSettings->chipSelectIndex,addr, mask, start_bit, *field_val);
    }

    return(COMMONERR_OK);
}
#if 0
commonErr_t CMB_writeToLog(ADI_LOGLEVEL level, uint8_t deviceIndex, uint32_t errorCode, const char *comment)
{

    if((CMB_LOGLEVEL & ADIHAL_LOG_ERROR) && (level == ADIHAL_LOG_ERROR))
    {
    	printf("ERROR: %d: %s", (int)errorCode, comment);
    }
    else if((CMB_LOGLEVEL & ADIHAL_LOG_WARNING) && (level == ADIHAL_LOG_WARNING))
    {
    	printf("WARNING: %d: %s",(int)errorCode, comment);
    }
    else if((CMB_LOGLEVEL & ADIHAL_LOG_MESSAGE) && (level == ADIHAL_LOG_MESSAGE))
    {
    	printf("MESSAGE: %d: %s",(int)errorCode, comment);
    }
    else if(CMB_LOGLEVEL == ADIHAL_LOG_NONE )
    {
        /*HAL_writeToLogFile("MESSAGE: %d: %s",(int)errorCode, comment);*/
    }
    else
    {
    	printf("Undefined Log Level: %0x%X", level);
    }

    return(COMMONERR_OK);
}
#endif

/* if filename null, a default path will be used in logging.c */
commonErr_t CMB_openLog(const char *filename)
{
    //HAL_openLogFile(filename);

    return(COMMONERR_OK);
}

commonErr_t CMB_closeLog(void)
{
    //HAL_closeLogFile();

    return(COMMONERR_OK);
}

commonErr_t CMB_flushLog(void)
{
    //HAL_flushLogFile();

    return(COMMONERR_OK);
}

commonErr_t CMB_wait_ms(uint32_t time_ms)
{
    
	//mdelay(time_ms);
	delay(time_ms * 1000);
    return(COMMONERR_OK);
}

commonErr_t CMB_wait_us(uint32_t time_us)
{
	//udelay(time_us);
	delay(time_us);
	return(COMMONERR_OK);
}

commonErr_t CMB_setTimeout_ms(uint32_t timeOut_ms)
{
   // HAL_setTimeout_ms(timeOut_ms);
   _desired_time_to_elapse_us = timeOut_ms * 1000;

    return(COMMONERR_OK);
}

commonErr_t CMB_setTimeout_us(uint32_t timeOut_us)
{
	_desired_time_to_elapse_us = timeOut_us;
    //HAL_setTimeout_us(timeOut_us);

    return(COMMONERR_OK);
}

commonErr_t CMB_hasTimeoutExpired()
{
	//udelay(1);

	delay(100);

	_desired_time_to_elapse_us--;
	if (_desired_time_to_elapse_us > 0)
		return(COMMONERR_OK);
#if 0
    uint8_t retval = 0;
    retval = HAL_hasTimeoutExpired();

    if (retval > 0)
    {
        return (COMMONERR_FAILED);
    }
    else 
    {
        return(COMMONERR_OK);
    }
#endif
	return(COMMONERR_FAILED);
}

commonErr_t CMB_regRead(uint32_t offset, uint32_t *data)
{
	return(COMMONERR_OK);
}

commonErr_t CMB_regWrite(uint32_t offset, uint32_t data)
{
	return(COMMONERR_OK);
}

commonErr_t CMB_memRead(uint32_t offset, uint32_t *data, uint32_t len)
{
	return(COMMONERR_OK);
}

commonErr_t CMB_memWrite(uint32_t offset, uint32_t *data, uint32_t len)
{
	return(COMMONERR_OK);
}



//hal functions

#if 1

int HAL_initSpi(uint8_t chipSelectIndex, uint8_t CPOLHA,uint8_t spiClkFreq_Hz)
{
	int test= 0;
#if 0
	MSS_SPI_init(&g_mss_spi0);

	MSS_SPI_configure_master_mode(&g_mss_spi0,
								   chipSelectIndex,
								   MSS_SPI_MODE0,
								   32u,
								   16);

	//Initialize and Configure  Slave.

	MSS_SPI_set_slave_select(&g_mss_spi0, chipSelectIndex);

	//slave configuration
#endif

#if 0
	SPI_init( &g_core_spi, FLASH_CORE_SPI_BASE, 1 );

	SPI_configure_master_mode( &g_core_spi );
#endif
	if(chipSelectIndex != 2)
	{
	SPI_clear_slave_select(&g_core_spi, _chipSelectIndex);

	delay(1000);

	SPI_set_slave_select( &g_core_spi, chipSelectIndex );
	}
	else
	SPI_set_slave_select( &g_core_spi1, chipSelectIndex );

	return test;

}


int HAL_spiWrite(uint8_t * write_buffer, uint32_t size_in_bytes)
{

	delay(1000);
//    MSS_SPI_transfer_block( &g_mss_spi0, write_buffer, size_in_bytes, 0, 0 );
	if(_chipSelectIndex != 2)
	{
	SPI_transfer_block( &g_core_spi,
					write_buffer,
					size_in_bytes,
					0,
					0 );
	}
	else
	{
		SPI_transfer_block( &g_core_spi1,
							write_buffer,
							size_in_bytes,
							0,
							0 );
	}

	delay(1000);
#if 0
	//delay(10000);
    while ( !MSS_SPI_tx_done(&g_mss_spi0) )
    {
        ;
    }
#endif
    return 0;
}

int  HAL_spiRead(uint8_t * write_buffer, uint32_t size_in_bytes,uint8_t * read_buffer )
{

#if 0
	//MSS_SPI_set_slave_select( &g_mss_spi0, MSS_SPI_SLAVE_0 );
	//delay(1000);
	MSS_SPI_transfer_block( &g_mss_spi0, write_buffer, size_in_bytes,read_buffer, 1 );
	//delay(10000);

	//MSS_SPI_clear_slave_select( &g_mss_spi0, MSS_SPI_SLAVE_0 );
#endif

	delay(1000);
	if(_chipSelectIndex != 2)
	{
	SPI_transfer_block( &g_core_spi,
						write_buffer,
						size_in_bytes,
						read_buffer,
						1 );
	}
	else
	{
	SPI_transfer_block( &g_core_spi1,
						write_buffer,
						size_in_bytes,
						read_buffer,
						1);
	}

	delay(1000);

	return 0;

}
#endif
int HAL_setTimeout_ms(uint32_t timeOut_ms)
{

//	MSS_TIM1_init(MSS_TIMER_ONE_SHOT_MODE);
//	MSS_TIM1_load_immediate((timeOut_ms * SYS_CLK_FREQ)/1000);
//	MSS_TIM1_start();
//	MSS_TIM1_enable_irq();
#if 0
	TMR_init(&g_timer1,
				  CORETIMER1_BASE_ADDR,
				  TMR_ONE_SHOT_MODE,
				  PRESCALER_DIV_1024, // (50MHZ / 1024) ~ 50kHz
				  timeOut_ms * 50);//50000);//((timeOut_ms * SYS_CLK_FREQ)/1000)); // (50kHz / 50000) ~ 1sec



	 TMR_enable_int(&g_timer1);

 // Start the timer
	 TMR_start(&g_timer1);
#endif
	Timeout_check = 10;

	while(Timeout_check)
	{
		;
	}

}
int HAL_setTimeout_us(uint32_t timeOut_us)
{

//	MSS_TIM1_init(MSS_TIMER_ONE_SHOT_MODE);
//	MSS_TIM1_load_immediate((timeOut_us * SYS_CLK_FREQ)/1000000);
//	MSS_TIM1_start();
//	MSS_TIM1_enable_irq();
#if 0
	TMR_init(&g_timer1,
					  CORETIMER1_BASE_ADDR,
					  TMR_ONE_SHOT_MODE,
					  PRESCALER_DIV_1024, // (50MHZ / 1024) ~ 50kHz
					  timeOut_us * 0.05);//50000);//((timeOut_us * SYS_CLK_FREQ)/1000000)); // (50kHz / 50000) ~ 1sec

	TMR_enable_int(&g_timer1);

	// Start the timer
	TMR_start(&g_timer1);
#endif
	Timeout_check = 10;

	while(Timeout_check)
	{
		;
	}
}



#if 0
void Timer1_IRQHandler(void)
{

	Timeout_check = 0;
    /* Clear TIM1 interrupt */
    MSS_TIM1_clear_irq();
}
#endif
int HAL_hasTimeoutExpired()
{

	if(Timeout_check == 0)
	{
		return 0;
	}
	else
	{
		return 1;
	}

}

