#include "mss_ace.h"
#include "mss_pdma.h"
#include "mss_uart.h"
#include <stdio.h>

#define AHB_SRAM            1
#define FREE_BUFFER         0
#define UNDER_DMA_CONTROL   1
#define DATA_READY          2

#define SAMPLES_BUFFER_SIZE    32
#define NB_OF_SAMPLE_BUFFERS    2

/* PDMA  destination */
uint32_t g_samples_buffer[NB_OF_SAMPLE_BUFFERS][SAMPLES_BUFFER_SIZE];

uint32_t g_buffer_status[NB_OF_SAMPLE_BUFFERS];

uint32_t g_pdma_irq_nb = 0;

void ace_pdma_handler( void );

uint32_t process_samples( uint32_t );

volatile uint32_t g_pdma_buffer_idx = NB_OF_SAMPLE_BUFFERS;

void display_value
(
    ace_channel_handle_t channel_handle,
    uint16_t raw_value
);

/*==============================================================================
 *
 */
int main()
{
    uint32_t i;
    uint32_t process_buffer_idx;
    uint8_t rx_size, input_selection;

    const uint8_t greating_msg[] = 		"\n\r*************  ACE with PDMA  ***************\n\r";
    const uint8_t instaruction_msg1[] = "\n\r****Rotate Thumb Wheel(RV1)to Display ADC Value****\n\r";
    const uint8_t menu_msg[] =          "\n\r****Please Type (y) to Start,(s)to Stop*******\n\r";
    const uint8_t stopped_msg[] =       "\n\r****Stopped:  Please Press:(y)to Resume ****\n\r";
    const uint8_t case_default_msg[] =  "\n\r****Invalid Selection: Please Press:(y)to Resume****\n\r";


    ACE_init();
    MSS_UART_init( &g_mss_uart0, MSS_UART_57600_BAUD, MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY
    		| MSS_UART_ONE_STOP_BIT );

    PDMA_init();

    MSS_UART_polled_tx( &g_mss_uart0, greating_msg, sizeof(greating_msg) );
    MSS_UART_polled_tx( &g_mss_uart0, instaruction_msg1, sizeof(instaruction_msg1) );

    /* This is to Transfer From ACE to eSRAM */
    PDMA_configure
    (
        PDMA_CHANNEL_0,
        PDMA_FROM_ACE,
        PDMA_LOW_PRIORITY | PDMA_WORD_TRANSFER | PDMA_INC_DEST_FOUR_BYTES,
        PDMA_DEFAULT_WRITE_ADJ
    );

    PDMA_set_irq_handler( PDMA_CHANNEL_0, ace_pdma_handler );
    PDMA_enable_irq( PDMA_CHANNEL_0 );
    NVIC_EnableIRQ( DMA_IRQn );


   for ( i = 0; i < NB_OF_SAMPLE_BUFFERS; ++i )
   {
       g_buffer_status[i] = FREE_BUFFER;
   }

   g_pdma_buffer_idx = 0;
   g_buffer_status[g_pdma_buffer_idx] = UNDER_DMA_CONTROL;
   process_buffer_idx = g_pdma_buffer_idx;

    /* Data Transfer from ACE To eSRAM */
    PDMA_start
    (
        PDMA_CHANNEL_0,
        /* Read PPE_PDMA_DOUT */
        (uint32_t) PDMA_ACE_PPE_DATAOUT,
        /* This is in MSS ESRAM */
        (uint32_t)g_samples_buffer[g_pdma_buffer_idx],
        SAMPLES_BUFFER_SIZE
    );

    MSS_UART_polled_tx( &g_mss_uart0, menu_msg, sizeof(menu_msg) );

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

    rx_size = 0;

    while (1)
    {

	    switch (input_selection) {

        case('y'):
		     do
		     {
			     process_buffer_idx = process_samples( process_buffer_idx );
			     MSS_UART_get_rx(&g_mss_uart0, &input_selection, 1);
		     }
		     while (input_selection != ('s'));
		     MSS_UART_polled_tx( &g_mss_uart0, stopped_msg, sizeof(stopped_msg) );
		     do
			 {
			     rx_size = MSS_UART_get_rx(&g_mss_uart0, &input_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, &input_selection, 1);
		    }
	        while (rx_size ==0);
        break;
	    }
    }
    return 0;
}

/*==============================================================================
 *
 */
void ace_pdma_handler( void )
{
    ++g_pdma_irq_nb;

    g_buffer_status[g_pdma_buffer_idx] = DATA_READY;

    PDMA_disable_irq( PDMA_CHANNEL_0 );
}

/*==============================================================================
 *
 */
uint32_t process_samples
(
    uint32_t process_buffer_idx
)
{
    ace_channel_handle_t channel_handle;
    uint32_t i;

    if ( DATA_READY == g_buffer_status[g_pdma_buffer_idx] )
    {
        uint32_t proc_buffer_idx = g_pdma_buffer_idx;

        ++g_pdma_buffer_idx;
        if ( g_pdma_buffer_idx >= NB_OF_SAMPLE_BUFFERS )
        {
            g_pdma_buffer_idx = 0;
        }

        g_buffer_status[g_pdma_buffer_idx] = UNDER_DMA_CONTROL;
        PDMA_start
            (
                PDMA_CHANNEL_0,
                /* Read PPE_PDMA_DOUT */
                (uint32_t) PDMA_ACE_PPE_DATAOUT,
                /* This is in MSS ESRAM */
                (uint32_t)g_samples_buffer[g_pdma_buffer_idx],
                SAMPLES_BUFFER_SIZE
            );

        PDMA_enable_irq( PDMA_CHANNEL_0 );

        for ( i = 0; i < SAMPLES_BUFFER_SIZE; ++i )
        {
            volatile uint16_t raw_value;

            raw_value =  ACE_translate_pdma_value(g_samples_buffer[proc_buffer_idx][i], 0);

            channel_handle = ACE_get_channel_handle((const uint8_t *)"VM_Direct");

            if ( channel_handle != INVALID_CHANNEL_HANDLE )
            {
                display_value( channel_handle, raw_value);
            }
        }
    }

    return process_buffer_idx;
}

/*------------------------------------------------------------------------------
 * Display sampled values over UART0.
 */
void display_value
(
    ace_channel_handle_t channel_handle,
    uint16_t raw_value
)
{
    int16_t real_value;
    uint8_t display_buffer[32];
    const uint8_t * channel_name;

	real_value = ACE_convert_to_mV( channel_handle, raw_value );
    if ( real_value < 0 )
    {
        real_value = real_value * (-1);
        snprintf( (char *)display_buffer, sizeof(display_buffer), ": -%d.%dV\n\r", real_value / 1000, real_value % 1000 );

    }
    else
    {
        snprintf( (char *)display_buffer, sizeof(display_buffer), ": %d.%dV\n\r", real_value / 1000, real_value % 1000 );
    }

    /* display channel name.*/
    channel_name = ACE_get_channel_name( channel_handle );
    MSS_UART_polled_tx_string( &g_mss_uart0, (const uint8_t *)" " );
    MSS_UART_polled_tx_string( &g_mss_uart0, channel_name );

    /* Display real_value value. */
    MSS_UART_polled_tx_string( &g_mss_uart0, display_buffer );

}

