/* ###################################################################
**     Filename    : main.c
**     Processor   : S32K1xx
**     Abstract    :
**         Main module.
**         This module contains user's application code.
**     Settings    :
**     Contents    :
**         No public methods
**
** ###################################################################*/
/*!
** @file main.c
** @version 01.00
** @brief
**         Main module.
**         This module contains user's application code.
*/         
/*!
**  @addtogroup main_module main module documentation
**  @{
*/         
/* MODULE main */


/* Including necessary module. Cpu.h contains other modules needed for compiling.*/
#include "Cpu.h"
#include "lpuart_hw_access.h"
#include "callbacks.h"
#include "string.h"
#include <stdio.h>
#include <stdarg.h>

volatile int exit_code = 0;

/* User includes (#include below this line is not maintained by Processor Expert) */


/**
 *  lpuart test example for 1000000 bps in DMA mode
 *
 *  Author: wjandsq@163.com  2019/10/21
 *
 *  all rights reserved  http://www.mcu.so
 *
 *
 *  1. you can creat a new project use SEGGER J-Link,  when you want use PEMicro OpenSDA Debug
 *
 *     you must add "${cross_prefix}gdb${cross_suffix}" in GDB Client Settings\Executable
 *
 *  2. Select Device is S32K144FS512M15
 *
 *  3. you can need add  include path for "lpuart_hw_access.h"¡¢"callbacks.h" before S32DS System SDK 3.0.0 path
 *
 *     lpuart_hw_access.h  PATH : "${ProjDirPath}/SDK/platform/drivers/src/lpuart"
 *
 *     callbacks.h         PATH : "${ProjDirPath}/SDK/platform/devices"
 *
 *  4. run recovery.bat to copy "lpuart_hw_access.h"¡¢"callbacks.h" to current project SDK file folder,
 *     overwrite old file
 *
 */
 
 
#if defined (INST_LPUART1)

#ifdef USING_OS_FREERTOS
#else
  uint8_t UART1_Tx_Finished_Flag = 1;
#endif

#define UART1_Rx_Buf_Size  256
#define UART1_Tx_Buf_Size  256
uint8_t UART1_Rx_Buf[UART1_Rx_Buf_Size];          /* UART1 Hardware DMA receive  buffer */
uint8_t UART1_Tx_Buf[UART1_Tx_Buf_Size];          /* UART1 Hardware DMA transmit buffer */

#define UART1_Drv_Rx_Buf_Size 2048
#define UART1_Drv_Tx_Buf_Size 2048
uint8_t UART1_Drv_Rx_Buf[UART1_Drv_Rx_Buf_Size];  /* UART1 Driver receive  buffer */
uint8_t UART1_Drv_Tx_Buf[UART1_Drv_Tx_Buf_Size];  /* UART1 Driver transmit buffer */

uint8_t  UART1_Drv_Rx_Full = 0;
uint16_t UART1_Drv_Rx_In   = 0;
uint16_t UART1_Drv_Rx_Out  = 0;

uint16_t UART1_Drv_Tx_PStr = 0;

#define sprintf_buf_size 128
uint8_t sprintf_buf[sprintf_buf_size];            /* UART1 sprintf buffer */

static void LPUART1_Tx_Callback_IRQHandler(void *driverState, uart_event_t event, void *userData);
static void LPUART1_Rx_Callback_IRQHandler(void *driverState, uart_event_t event, void *userData);

#endif

#if defined (INST_LPUART1)
/**
  *  @brief Callback for all peripherals which support UART features
  * Implements : uart_callback_t_Class
  * typedef void (*uart_callback_t)(void *driverState, uart_event_t event, void *userData);
  */
static void LPUART1_Tx_Callback_IRQHandler(void *driverState, uart_event_t event, void *userData)
{
#ifdef USING_OS_FREERTOS
	static portBASE_TYPE xHigherPriorityTaskWoken;
	xHigherPriorityTaskWoken = pdFALSE;

	if (event == UART_EVENT_END_TRANSFER) {
		xSemaphoreGiveFromISR( BinarySem_UART1_TxHandle, &xHigherPriorityTaskWoken);
		portYIELD_FROM_ISR( xHigherPriorityTaskWoken );
	}
#else
	UART1_Tx_Finished_Flag = 1;
#endif
}

/**
  *  @brief Callback for all peripherals which support UART features
  * Implements : uart_callback_t_Class
  * typedef void (*uart_callback_t)(void *driverState, uart_event_t event, void *userData);
  */
static void LPUART1_Rx_Callback_IRQHandler(void *driverState, uart_event_t event, void *userData)
{
  lpuart_state_t * s_lpuartStatePtr = ( lpuart_state_t * ) driverState;
#if (FEATURE_LPUART_HAS_DMA_ENABLE)
  uint32_t rx_count;
  uint32_t remainbytes;
  if (s_lpuartStatePtr->transferType != LPUART_USING_INTERRUPTS) {
    if (event == UART_EVENT_DMA_IDLE) {
      remainbytes = s_lpuartStatePtr->rxSize;
      if (remainbytes != 0) {
        rx_count = UART1_Rx_Buf_Size - remainbytes;
      } else {
        rx_count = UART1_Rx_Buf_Size;
      }
      if ((UART1_Drv_Rx_In + rx_count) < UART1_Drv_Rx_Buf_Size){
          memcpy(&UART1_Drv_Rx_Buf[UART1_Drv_Rx_In], UART1_Rx_Buf, rx_count);
          UART1_Drv_Rx_In = UART1_Drv_Rx_In + rx_count;
      } else {
    	  UART1_Drv_Rx_Full = 1;
      }
      memset(UART1_Rx_Buf, 0, UART1_Rx_Buf_Size);
      LPUART_DRV_ReceiveData(INST_LPUART1, UART1_Rx_Buf, UART1_Rx_Buf_Size);
    } else if (event == UART_EVENT_RX_FULL) {
      rx_count = UART1_Rx_Buf_Size;
      if ((UART1_Drv_Rx_In + rx_count) < UART1_Drv_Rx_Buf_Size){
          memcpy(&UART1_Drv_Rx_Buf[UART1_Drv_Rx_In], UART1_Rx_Buf, rx_count);
          UART1_Drv_Rx_In = UART1_Drv_Rx_In + rx_count;
      } else {
    	  UART1_Drv_Rx_Full = 1;
      }
      memset(UART1_Rx_Buf, 0, UART1_Rx_Buf_Size);
      LPUART_DRV_SetRxBuffer(INST_LPUART1, UART1_Rx_Buf, UART1_Rx_Buf_Size);
    }
  }
#else
  if (s_lpuartStatePtr->transferType == LPUART_USING_INTERRUPTS) {
      /* Start the reception process using interrupts */

  }
#endif

}

/**
 * @brief
 * @param
 * @param
 * @retval None
 */
void put_char(uint32_t instance, uint8_t ch)
{
	LPUART_DRV_SendDataPolling(instance, &ch, 1);
}


/**
  * @brief  put a packet by lpuart0¡¢lpuart1¡¢lpuart2, the string buffer is locked until complete.
  * @param  buf Pointer to a string buffer that contains
  *                the data information for the specified UART module.
  * @retval None
  */
void put_packet(uint32_t instance, void * buf, uint16_t size)
{
#ifdef USING_OS_FREERTOS
	LPUART_DRV_SendData(instance, buf, size);
#if defined (INST_LPUART1)
	if (instance == 1) {
		xSemaphoreTake(BinarySem_UART1_TxHandle, portMAX_DELAY);
	}
#endif
#else
	LPUART_DRV_SendDataPolling(instance, buf, size);
#endif
}

/**
 * @brief  system_printf
 * @param  instance  INST_LPUART0¡¢ INST_LPUART1¡¢ INST_LPUART2
 *         format
 *         ...       param list
 *
 * format:
 *
 * system_printf (INST_LPUART1, "\r\n %s\r\n",s);
 * system_printf (INST_LPUART1, "\r\n %d %d %d\r\n",i,j,k);
 * system_printf (INST_LPUART1, "\r\n 0x%x 0x%x 0x%x\r\n", i, j, k);
 *
 *
 */
uint8_t system_printf(uint32_t instance, const char * format, ...)
{
  uint8_t real_len = 0;
  va_list arg;
  va_start(arg, format);
  real_len = vsprintf(( char * ) sprintf_buf, format, arg);
  va_end(arg);
#if defined (INST_LPUART1)
  if (real_len > sprintf_buf_size) {
	  while(1);
  }
  LPUART_DRV_SendDataPolling(instance, sprintf_buf, real_len);
#endif
  return real_len;
}

/**
 * @brief
 * @param
 * @retval None
 */
void get_char(uint32_t instance, uint8_t * ch)
{
#if defined (INST_LPUART1)
	if (instance == 1) {
	  if(UART1_Drv_Rx_Full){
		  UART1_Drv_Rx_Full = 0;
		  UART1_Drv_Rx_Out  = 0;
		  UART1_Drv_Rx_In   = 0;
	  }
	  while(UART1_Drv_Rx_Out == UART1_Drv_Rx_In){
		  asm("NOP"); asm("NOP"); asm("NOP");
	  }
	  if (UART1_Drv_Rx_Out < UART1_Drv_Rx_In){
		*ch = UART1_Drv_Rx_Buf[UART1_Drv_Rx_Out];
		UART1_Drv_Rx_Out++;
		if (UART1_Drv_Rx_Out == UART1_Drv_Rx_In){
			UART1_Drv_Rx_Out  = 0;
			UART1_Drv_Rx_In   = 0;
			UART1_Drv_Rx_Full = 0;
		}
	  }
	}
#endif
}

/**
 * @brief
 * @param
 * @retval None
 */
void get_packet(uint32_t instance, uint8_t * buf, uint16_t get_len)
{
    uint32_t real_len = 0;
#if defined (INST_LPUART1)
	if (instance == 1) {
	  while(1){
		  if (UART1_Drv_Rx_Out < UART1_Drv_Rx_In){
			  real_len = UART1_Drv_Rx_In - UART1_Drv_Rx_Out;
			  if (real_len >= get_len) {
				  break;
			  } else {
				  asm("NOP");
				  asm("NOP");
				  asm("NOP");
			  }
		  }
	  }
	  memcpy(buf, &UART1_Drv_Rx_Buf[UART1_Drv_Rx_Out], get_len);
	  UART1_Drv_Rx_Out = UART1_Drv_Rx_Out + get_len;
	  if (UART1_Drv_Rx_Out == UART1_Drv_Rx_In) {
		UART1_Drv_Rx_Out  = 0;
		UART1_Drv_Rx_In   = 0;
		UART1_Drv_Rx_Full = 0;
	  }
	}
#endif
}

#endif


uint8_t lpuart1_rx_buf[1033];
/*! 
  \brief The main function for the project.
  \details The startup initialization sequence is the following:
 * - startup asm routine
 * - main()
*/
int main(void)
{
  /* Write your local variable definition here */
  CLOCK_SYS_Init(g_clockManConfigsArr, CLOCK_MANAGER_CONFIG_CNT, g_clockManCallbacksArr, CLOCK_MANAGER_CALLBACK_CNT);
  CLOCK_SYS_UpdateConfiguration(0, CLOCK_MANAGER_POLICY_FORCIBLE);
  PINS_DRV_Init(NUM_OF_CONFIGURED_PINS, g_pin_mux_InitConfigArr);

  EDMA_DRV_Init(&dmaController1_State, &dmaController1_InitConfig0, edmaChnStateArray, edmaChnConfigArray, EDMA_CONFIGURED_CHANNELS_COUNT);
  EDMA_DRV_ChannelInit(&dmaController1Chn0_State, &dmaController1Chn0_Config); /* LPUART1_RX */
  EDMA_DRV_ChannelInit(&dmaController1Chn1_State, &dmaController1Chn1_Config); /* LPUART1_TX */

  LPUART_DRV_Init(INST_LPUART1, &lpuart1_State, &lpuart1_InitConfig0);

  LPUART_DRV_InstallRxCallback(INST_LPUART1, LPUART1_Rx_Callback_IRQHandler, NULL);
  LPUART_DRV_InstallTxCallback(INST_LPUART1, LPUART1_Tx_Callback_IRQHandler, NULL);
  LPUART_ClearStatusFlag(LPUART1, LPUART_IDLE_LINE_DETECT);
  LPUART_SetIntMode(LPUART1, LPUART_INT_IDLE_LINE, true);
  LPUART_DRV_ReceiveData(INST_LPUART1, UART1_Rx_Buf, UART1_Rx_Buf_Size);

  /*** Processor Expert internal initialization. DON'T REMOVE THIS CODE!!! ***/
  #ifdef PEX_RTOS_INIT
    PEX_RTOS_INIT();                   /* Initialization of the selected RTOS. Macro is defined by the RTOS component. */
  #endif
  /*** End of Processor Expert internal initialization.                    ***/

  /* Write your code here */
  /* For example: for(;;) { } */
  uint32_t x = lpuart1_InitConfig0.baudRate;
  system_printf(1, "lpuart1 test: %d bps", x);

  for(;;) {
	  asm("NOP");
	  asm("NOP");
	  asm("NOP");
	  get_packet(1, lpuart1_rx_buf, 1033);
	  asm("NOP");
	  asm("NOP");
	  asm("NOP");
  }
  /*** Don't write any code pass this line, or it will be deleted during code generation. ***/
  /*** RTOS startup code. Macro PEX_RTOS_START is defined by the RTOS component. DON'T MODIFY THIS CODE!!! ***/
  #ifdef PEX_RTOS_START
    PEX_RTOS_START();                  /* Startup of the selected RTOS. Macro is defined by the RTOS component. */
  #endif
  /*** End of RTOS startup code.  ***/
  /*** Processor Expert end of main routine. DON'T MODIFY THIS CODE!!! ***/
  for(;;) {
    if(exit_code != 0) {
      break;
    }
  }
  return exit_code;
  /*** Processor Expert end of main routine. DON'T WRITE CODE BELOW!!! ***/
} /*** End of main routine. DO NOT MODIFY THIS TEXT!!! ***/

/* END main */
/*!
** @}
*/
/*
** ###################################################################
**
**     This file was created by Processor Expert 10.1 [05.21]
**     for the NXP S32K series of microcontrollers.
**
** ###################################################################
*/
