#include "hal_data.h"
#include "common_utils.h"
#include "audio_data.h"
#include "ssi.h"

/*******************************************************************************************************************//**
 * @addtogroup ssi_master_ep
 * @{
 **********************************************************************************************************************/
volatile bool g_send_data_in_main_loop = false, g_read_data_in_main_loop = false;
static unsigned char g_rbyte[BUFFER_SIZE_DOWN] = {RESET_VALUE};
static uint8_t g_selection_value = RESET_VALUE;
volatile i2s_event_t g_i2s_event = I2S_EVENT_TX_EMPTY;
static uint16_t g_write_counter = VALUE_0;
static uint16_t g_read_counter = VALUE_0;
static bool g_read_in_cb = false;

i2s_state_t i2s_state;

/* Private functions */
static void deinit_gpt(void);
static void deinit_ssi(void);
static void master_write_slave_read_operation(void);
static void master_read_slave_write_operation(void);

FSP_CPP_HEADER
void R_BSP_WarmStart(bsp_warm_start_event_t event);
FSP_CPP_FOOTER

/*******************************************************************************************************************//**
 * main() is generated by the RA Configuration editor and is used to generate threads if an RTOS is used.  This function
 * is called by main() when no RTOS is used.
 **********************************************************************************************************************/
void hal_entry(void)
{
    fsp_err_t err = FSP_SUCCESS;
    fsp_pack_version_t version =   { RESET_VALUE };
    g_read_data_in_main_loop = true;

    /* version get API for FLEX pack information */
    R_FSP_VersionGet (&version);

    APP_PRINT(BANNER_INFO, EP_VERSION,version.version_id_b.major, version.version_id_b.minor, version.version_id_b.patch);


    /* Open SSI channel */
    err = R_SSI_Open(&g_i2s_master_ctrl, &g_i2s_master_cfg);
    /* Handle error */
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("\r\n SSI open failed \r\n");
        /* Trap here */
        APP_ERR_TRAP(err);
    }

    /* Open GPT channel */
    err = R_GPT_Open(&ssi_clock_ctrl, &ssi_clock_cfg);
    /* Handle error */
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("\r\n GPT open failed\r\n");
        /* Trap here */
        APP_ERR_TRAP(err);
    }

    /* Start GPT Timer */
    err = R_GPT_Start(&ssi_clock_ctrl);
    /* Handle error */
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("\r\n GPT start failed\r\n");
        /* Trap here */
        APP_ERR_TRAP(err);
    }

    while(true)
    {
        APP_PRINT("\r\nOperating mode: MASTER");

        /* User input selection */
        APP_PRINT("\r\nPlease select the desired operation\n"
                "1. Press 1 for Master Write - Slave Read\r\n"
                "2. Press 2 for Master Read  - Slave Write\r\n");
        while(true)
        {
            if (APP_CHECK_DATA)
            {
                /* Cleaning buffer */
                memset(&g_rbyte[INDEX_0], NULL_CHAR, BUFFER_SIZE_DOWN);
                APP_READ(g_rbyte);
                g_selection_value = (uint8_t)atoi((char *)g_rbyte);
                if ((SELECTION_MAX >= g_selection_value) && (SELECTION_MIN <= g_selection_value))
                {
                    APP_PRINT("\r\nSelected Mode %d\r\n",g_selection_value);
                    if (MASTER_WRITE_SLAVE_READ == g_selection_value)
                    {
                        APP_PRINT("\r\nMASTER WRITE - SLAVE READ Mode Selected\r\n");
                    }
                    if (MASTER_READ_SLAVE_WRITE == g_selection_value)
                    {
                        APP_PRINT("\r\nMASTER READ - SLAVE WRITE Mode Selected\r\n");
                    }
                    break;
                }
                else
                {
                    APP_PRINT("\r\nInvalid input. Enter valid input\r\n");
                }
            }
        }
        if (MASTER_WRITE_SLAVE_READ == g_selection_value)
        {
            /*-------W R I T E-------*/
            master_write_slave_read_operation();
        }
        if (MASTER_READ_SLAVE_WRITE == g_selection_value)
        {
            /*-------R E A D-------*/
            master_read_slave_write_operation();
        }
    }
}


/*******************************************************************************************************************//**
 * This function is called at various points during the startup process.  This implementation uses the event that is
 * called right before main() to set up the pins.
 *
 * @param[in]  event    Where at in the start up process the code is currently at
 **********************************************************************************************************************/
void R_BSP_WarmStart(bsp_warm_start_event_t event)
{
    if (BSP_WARM_START_RESET == event)
    {
#if BSP_FEATURE_FLASH_LP_VERSION != 0

        /* Enable reading from data flash. */
        R_FACI_LP->DFLCTL = ENABLE_READING_FROM_DATA_FLASH;

        /* Would normally have to wait tDSTOP(6us) for data flash recovery. Placing the enable here, before clock and
         * C runtime initialization, should negate the need for a delay since the initialization will typically take more than 6us. */
#endif
    }

    if (BSP_WARM_START_POST_C == event)
    {
        /* C runtime environment and system clocks are setup. */

        /* Configure pins. */
        R_IOPORT_Open (&g_ioport_ctrl, g_ioport.p_cfg);
    }
}


/*******************************************************************************************************************//**
 * @brief       Close SSI module
 * @param[in]   None
 * @return      None
 **********************************************************************************************************************/
static void deinit_ssi(void)
{
    fsp_err_t err = FSP_SUCCESS;
    /* Close SSI Module */
    err = R_SSI_Close(&g_i2s_master_ctrl);
    /* Handle error */
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("\r\n R_SSI_Close API Failed \r\n");
    }
}


/*******************************************************************************************************************//**
 * @brief       Close GPT module
 * @param[in]   None
 * @return      None
 **********************************************************************************************************************/
static void deinit_gpt(void)
{
    fsp_err_t err = FSP_SUCCESS;
    /* Close GPT module */
    err = R_GPT_Close(&ssi_clock_ctrl);
    /* Handle error */
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("\r\n R_SSI_Close API Failed \r\n");
    }
}


 /*******************************************************************************************************************//**
 * @brief       master_write_slave_read_operation
 * @param[in]   None
 * @return      None
 **********************************************************************************************************************/
static void master_write_slave_read_operation(void)
{
    fsp_err_t err = FSP_SUCCESS;
    g_buf_row_index = INDEX_0;
    g_write_counter = VALUE_0;
    g_send_data_in_main_loop = false;

    APP_PRINT("Writing data to Slave...\r\n");
    /* Write data to slave */
    err = R_SSI_Write(&g_i2s_master_ctrl, &g_src_buff[g_buf_row_index][INDEX_0], (BUF_FIFO_STAGE)* sizeof(int32_t));
    /* Handle error */
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("\r\n Write API failed, Closing SSI and GPT \r\n");
        deinit_ssi();
        deinit_gpt();
        /* Trap here */
        APP_ERR_TRAP(err);
    }

    while(WRITE_COUNTS > g_write_counter)
    {
        if ((true == g_send_data_in_main_loop))
        {
            /* Write data to slave */
            if((I2S_EVENT_IDLE == g_i2s_event)||(I2S_EVENT_TX_EMPTY == g_i2s_event))
            {
                g_send_data_in_main_loop = false;
                err = R_SSI_Write(&g_i2s_master_ctrl, &g_src_buff[g_buf_row_index][INDEX_0], (BUF_FIFO_STAGE)* sizeof(int32_t));
                /* Handle error */
                if (FSP_SUCCESS != err)
                {
                    APP_ERR_PRINT("\r\n Write API failed, Closing SSI and GPT \r\n");
                    deinit_ssi();
                    deinit_gpt();
                    /* Trap here */
                    APP_ERR_TRAP(err);
                }
                else
                {
                    g_write_counter++;
                }
            }
        }
        R_BSP_SoftwareDelay (WAIT_TIME, BSP_DELAY_UNITS_MICROSECONDS);
    }

    APP_PRINT("Writing complete \r\n");
    APP_PRINT("Turn the Slave OFF and Press any key to Terminate the process \r\n");
    while(true)
    {
        if (APP_CHECK_DATA)
        {
            /* Cleaning buffer */
            memset(&g_rbyte[INDEX_0], NULL_CHAR, BUFFER_SIZE_DOWN);
            APP_READ(g_rbyte);
            APP_PRINT("\r\nTerminating...\r\n");
            break;
        }
    }
}


/*******************************************************************************************************************//**
 * @brief       master_read_slave_write_operation
 * @param[in]   None
 * @return      None
 **********************************************************************************************************************/
static void master_read_slave_write_operation(void)
{
    fsp_err_t err = FSP_SUCCESS;
    g_buf_row_index = INDEX_0;
    g_read_in_cb = false;
    g_read_data_in_main_loop = false;
    g_read_counter = VALUE_0;

    /* Wait for incoming data */
    APP_PRINT("Reading data from Slave...\r\n");
    /* clear the buffer before reading it */
    memset(g_dest_buff, VALUE_0, sizeof(g_dest_buff));

    /* Read data from slave */
    err = R_SSI_Read(&g_i2s_master_ctrl, &g_dest_buff[g_buf_row_index][INDEX_0], (BUF_FIFO_STAGE)* sizeof(int32_t));
    /* Handle error */
    if (FSP_SUCCESS != err)
    {
        APP_ERR_PRINT("\r\n Read API failed, Closing SSI and GPT \r\n");
        deinit_ssi();
        deinit_gpt();
        /* Trap here */
        APP_ERR_TRAP(err);
    }

    while(true)
    {
        if(true == g_read_in_cb)
        {
            /* printing read data */
            APP_PRINT("\r\n");
            for(uint16_t index = VALUE_0; index < BUF_FIFO_STAGE; index++)
            {
                APP_PRINT("0x%02x, ", g_dest_buff[g_buf_row_index + INDEX_1 ][index]);
            }

            /* Data was not ready yet, send it in the main loop. */
            g_read_data_in_main_loop = true;

            /*reset the read flag*/
            g_read_in_cb = false;
        }
        if (true == g_read_data_in_main_loop)
        {
            /* Read data from slave */
            if((I2S_EVENT_IDLE == g_i2s_event) || (I2S_EVENT_RX_FULL == g_i2s_event))
            {
                g_read_data_in_main_loop = false;

                /* Read data from slave */
                err = R_SSI_Read(&g_i2s_master_ctrl, &g_dest_buff[g_buf_row_index][INDEX_0], (BUF_FIFO_STAGE)* sizeof(int32_t));
                /* Handle error */
                if (FSP_SUCCESS != err)
                {
                    APP_ERR_PRINT("\r\n Read API failed, Closing SSI and GPT \r\n");
                    deinit_ssi();
                    deinit_gpt();
                    /* Trap here */
                    APP_ERR_TRAP(err);
                }
                else
                {
                    /* Increment Read counter */
                    g_read_counter++;
                    /* printing read data */
                    APP_PRINT("\r\n");
                    for(uint16_t index = VALUE_0; index < BUF_FIFO_STAGE; index++)
                    {
                        APP_PRINT("0x%02x, ", g_dest_buff[g_buf_row_index][index]);
                    }
                }
            }
        }
        R_BSP_SoftwareDelay (WAIT_TIME, BSP_DELAY_UNITS_MICROSECONDS);

        /* Check if the counter reaches READ_COUNTS */
        if(READ_COUNTS == g_read_counter)
        {
            APP_PRINT("\r\nReading data from Slave completed...\r\n");
            APP_PRINT("To Terminate the read process Press any key...\r\n");
            while(true)
            {
                if (APP_CHECK_DATA)
                {
                    /* Cleaning buffer */
                    memset(&g_rbyte[INDEX_0], NULL_CHAR, BUFFER_SIZE_DOWN);
                    APP_READ(g_rbyte);
                    APP_PRINT("\r\nTerminating...\r\n");
                    break;
                }
            }
            break;
        }
    }
}


/*******************************************************************************************************************//**
 * @brief       SSI callback function
 * @return      None
 **********************************************************************************************************************/
void ssi_example_callback (i2s_callback_args_t * p_args)
{
    g_i2s_event = p_args->event;

    if (((I2S_EVENT_TX_EMPTY == p_args->event) || (I2S_EVENT_IDLE == p_args->event))  && (MASTER_WRITE_SLAVE_READ == g_selection_value) && (WRITE_COUNTS > g_write_counter))
    {
        /* Reload FIFO and handle errors. */
        R_SSI_Write(&g_i2s_master_ctrl, &g_src_buff1[g_buf_row_index][INDEX_0], (BUF_FIFO_STAGE)* sizeof(int32_t));

        /* Data was not ready yet, send it in the main loop. */
        g_send_data_in_main_loop = true;
    }

    if (((I2S_EVENT_RX_FULL == p_args->event) || (I2S_EVENT_IDLE == p_args->event)) && (MASTER_READ_SLAVE_WRITE == g_selection_value)&& (READ_COUNTS > g_read_counter))
    {
        /* Reload FIFO and handle errors. */
        R_SSI_Read(&g_i2s_master_ctrl, &g_dest_buff[g_buf_row_index+1][INDEX_0], (BUF_FIFO_STAGE)* sizeof(int32_t));

        /* set the flag to read it in the main loop */
        g_read_in_cb = true;
    }
}

/*******************************************************************************************************************//**
 * @} (end addtogroup ssi_master_ep)
 **********************************************************************************************************************/
