
#include "stdlib.h"
#include "usart.h"
#include <errno.h>
#ifndef LINUX_TEMP_PORT 
#include "stm32f7xx_hal_uart.h"
#include "cmsis_os.h"
#endif
#include "exo_hal_io_al_common.h"
#include "exo_osal.h"

#include "csp.h"
#include "csp_thread.h"




extern ioal_uart_hdle ioal_huart6;
extern UART_HandleTypeDef huart6;

extern ioal_uart_hdle ioal_huart4;
extern UART_HandleTypeDef huart4;


os_sem_handle_ptr csp_uart_sem;



ahw_al_gen_info csp_uart;
ioal_uart_hdle *uart_hdl;

typedef struct {
	csp_usart_callback_t rx_callback;
	void * user_data;
	csp_usart_fd_t fd;
	csp_thread_handle_t rx_thread;
} usart_context_t;

uint16_t csp_g_tail = 0;
xQueueHandle csp_g_qUsart;
#define CBUF_SIZE  400
uint8_t csp_bGet[CBUF_SIZE] = {0};
uint8_t PLACE_IN_EXT_RAM_MEM uhf_uart_rsp[CBUF_SIZE] = {0};
uint16_t PLACE_IN_EXT_RAM_MEM uhf_uart_rsp_len = 0;
uint16_t length=0;

uint16_t csp_usart_Recv(uint8_t* bArray, uint16_t maxLength);

void usart_rx_cb(void * arg);

void csp_uart_error_cb(void* args)
{
#ifdef COREBOARD
			io_hal_uart_dma_receive_to_idle(&ioal_huart4,&csp_uart,csp_bGet, CBUF_SIZE);
#else
			io_hal_uart_dma_receive_to_idle(&ioal_huart6,&csp_uart,csp_bGet, CBUF_SIZE);
#endif
}

void csp_uart_tx_cplt_cb(void* args)
{
}

void csp_uart_rx_cplt_cb(void* args)
{
}


void usart_rx_cb(void * arg)
{
	//usart_context_t * ctx =arg;
	usart_context_t * ctx = ((os_thread_handle_ptr)arg)->app_entry_args;
	uint8_t cbuf[CBUF_SIZE];


	while(1)
	{
		if(os_sem_take(csp_uart_sem, 5000) == ral_success)
		{
			os_memcpy(cbuf,csp_bGet,length);
#ifdef COREBOARD
			io_hal_uart_dma_receive_to_idle(&ioal_huart4,&csp_uart,csp_bGet, CBUF_SIZE);
#else
			io_hal_uart_dma_receive_to_idle(&ioal_huart6,&csp_uart,csp_bGet, CBUF_SIZE);
#endif

			if (length)
			{
				os_memcpy(uhf_uart_rsp,csp_bGet,length);
				uhf_uart_rsp_len = length;
				if (ctx->rx_callback)
					ctx->rx_callback(ctx->user_data, csp_bGet, length, NULL);

				length =0;
			}
		}
		else
		{
#ifdef COREBOARD
			io_hal_uart_dma_receive_to_idle(&ioal_huart4,&csp_uart,csp_bGet, CBUF_SIZE);
#else
			io_hal_uart_dma_receive_to_idle(&ioal_huart6,&csp_uart,csp_bGet, CBUF_SIZE);
#endif
		}
	}
}

#if 0
static CSP_DEFINE_TASK(usart_rxTask)
{
	uint16_t length;
	for(;;)
	{
#ifdef COREBOARD
		length = CBUF_SIZE - huart4.hdmarx->Instance->NDTR;
#else
		length = CBUF_SIZE - huart6.hdmarx->Instance->NDTR;
#endif
		while(length - csp_g_tail)
		{
			uint8_t tmp = csp_bGet[csp_g_tail];
			xQueueSendToBack( csp_g_qUsart, &tmp, 100 );
			csp_g_tail++;
			if (csp_g_tail == CBUF_SIZE)
				csp_g_tail = 0;
		}
		osDelay(1);
	}
}

uint16_t csp_usart_Recv(uint8_t* bArray, uint16_t maxLength)
{
	uint8_t tmp = 0;
	uint16_t length = 0;
	while(uxQueueMessagesWaiting(csp_g_qUsart))
	{
		xQueueReceive( csp_g_qUsart, &tmp, 100 );
		bArray[length] = tmp;
		length++;
		if (length >= maxLength)
			break;
	}
	return length;
}

#endif
/**
   Write data on open UART.

   @param[in] fd file descriptor.
   @param[in] data data to write.
   @param[in] data_length length of \a data.
   @return number of bytes written on success, a negative value on failure.
*/
int csp_usart_open(ioal_uart_hdle *uart_hdl, csp_usart_callback_t rx_callback, void * user_data, csp_usart_fd_t * fd)
{
	  *fd = 1;
#ifdef COREBOARD
    csp_uart.io_intf_id=IOAL_INST_UART4;
#else
    csp_uart.io_intf_id=IOAL_INST_UART6;
#endif
    ahal_register_io_cb(&csp_uart,UART_TX_CPLT_CB,csp_uart_tx_cplt_cb,HISR);
    ahal_register_io_cb(&csp_uart,UART_RX_CPLT_CB,csp_uart_rx_cplt_cb,HISR);
    ahal_register_io_cb(&csp_uart,UART_ERROR_CB,csp_uart_error_cb,HISR);
    os_sem_create_bin(&csp_uart_sem, "CSP_UART_SEM");
    os_sem_take(csp_uart_sem, 5000);
    io_hal_uart_dma_receive_to_idle(uart_hdl,&csp_uart,csp_bGet, CBUF_SIZE);
 //   io_hal_uart_receive_it(uart_hdl,&csp_uart,csp_bGet, CBUF_SIZE);
	  usart_context_t * ctx = calloc(1, sizeof(*ctx));

    if (ctx == NULL) {
        csp_log_error("%s: Error allocating context, errno: %s", __FUNCTION__, strerror(errno));
        csp_tm_global.csp_err_nomem++;
        return CSP_ERR_NOMEM;
    }

    ctx->rx_callback = rx_callback;
    ctx->user_data = user_data;
    ctx->fd = 1;
    if (rx_callback) {
        if (csp_thread_create(usart_rx_cb, "usart_cb", (128 * 4), ctx, P_UART_RX, &ctx->rx_thread) != CSP_ERR_NONE) {
            csp_log_error("%s: csp_thread_create() failed to create Rx cb for, errno: %s", __FUNCTION__, strerror(errno));
            free(ctx);
            csp_tm_global.csp_err_nomem++;
            return CSP_ERR_NOMEM;
        }

//        if (csp_thread_create(usart_rxTask, "usart_rx", (1280 ), NULL, P_CSP_INTF_UART_RX, NULL) != CSP_ERR_NONE) {
//            csp_log_error("%s: csp_thread_create() failed to create Rx loop for, errno: %s", __FUNCTION__, strerror(errno));
//            csp_tm_global.csp_err_nomem++;
//            return CSP_ERR_NOMEM;
//        }
        csp_g_qUsart = xQueueCreate(CBUF_SIZE, sizeof( unsigned char ));
        return CSP_ERR_NONE;
    }
    csp_tm_global.csp_err_inval++;
    return CSP_ERR_INVAL;
}

/**
   Opens UART device and add KISS interface.

   This is a convience function for opening an UART device and adding it as an interface with a given name.

   @note On read failures, exit() will be called - terminating the process.

   @param[in] conf UART configuration.
   @param[in] ifname internface name (will be copied), or use NULL for default name.
   @param[out] return_iface the added interface.
   @return #CSP_ERR_NONE on success, otherwise an error code.
*/

int csp_usart_write(ioal_uart_hdle *uart_hdl, const void * data, size_t data_length)
{
	hal_ret_sts  status;
    status =1;
    status=io_hal_uart_transmit_dma(uart_hdl,&csp_uart,(uint8_t*)data,data_length);

	while (io_hal_uart_get_state(uart_hdl) != IOAL_UART_STATE_READY)
	{
		if (io_hal_uart_get_state(uart_hdl) == IOAL_UART_STATE_BUSY_RX)
			break;
		osDelay(1);
	}
	//if (status == HAL_OK)
	if (status == HAL_SCS)
		return data_length;
	return 0;

}

uint32_t uhf_fw_usart_write(uint8_t* data, uint16_t data_len)
{
	hal_ret_sts  status;
	//ioal_uart_hdle *uart_hdl1;
	    status =1;
#ifdef COREBOARD
	    status=io_hal_uart_transmit_dma(&ioal_huart4,&csp_uart,(uint8_t*)data,data_len);
#else
	    status=io_hal_uart_transmit_dma(&ioal_huart6,&csp_uart,(uint8_t*)data,data_len);
#endif

		while (io_hal_uart_get_state(uart_hdl) != IOAL_UART_STATE_READY)
		{
			if (io_hal_uart_get_state(uart_hdl) == IOAL_UART_STATE_BUSY_RX)
				break;
			osDelay(1);
		}
		//if (status == HAL_OK)
		if (status == HAL_SCS)
		{
			//UHF_FW_UP = 1;
			return data_len;
		}
		//else UHF_FW_UP = 0;

	return 0;

}

uint8_t uhf_fw_write(int8* data, uint8_t reply, uint16_t data_len)
{
	int ret_sts = 0;
	uint8_t* fw_data = (uint8*) data;

	ret_sts = uhf_fw_usart_write(fw_data, data_len);
	if(ret_sts == data_len)
	{
		return 0; // wr succ
	}
	else
	{
		return 1; // wr fail
	}

}
