#include "FreeRTOS.h"
#include "task.h"
#include "diag.h"
#include "main.h"
#include <example_entry.h>

#include "freertos_pmu.h"
#include "gpio_irq_api.h"
#include "serial_api.h"

// select uart tx/rx pin with gpio interrupt function
#define UART_TX    PA_4
#define UART_RX    PA_0

#define LOGUART_RX_WAKE PC_1

#define WAKELOCK_EXAMPLE WAKELOCK_USER_BASE

serial_t mysobj;
volatile char rc = 0;

extern void wlan_netowrk(void);
extern void console_init(void);

char cmdbuf[128];
int cmdbuf_index = 0;
void uart_irq_callback(uint32_t id, SerialIrq event)
{
	serial_t *sobj = (void*)id;

	if(event == RxIrq) {
		acquire_wakelock(WAKELOCK_EXAMPLE);

		rc = serial_getc(sobj);

		if (rc == '\r' || rc == '\n') {
			serial_putc(sobj, '\r');
			serial_putc(sobj, '\n');
			serial_putc(sobj, '#');
			serial_putc(sobj, ' ');

			if (cmdbuf_index != 0) {

                /* NOTICE: If you don't want loss any data from treating UART signal as GPIO interrupt,
                 *         you can set FREERTOS_PMU_TICKLESS_PLL_RESERVED to 1 in "platform_opt.h".
                 *         It will reserved PLL clock in tickless and UART can receive the whole data.
                 *         But it also cost more power consumption.
                 **/

				// process command
				printf("cmd(%d): %s\r\n", cmdbuf_index, cmdbuf);

				// release wakelock and reset buf
				cmdbuf_index = 0;
				release_wakelock(WAKELOCK_EXAMPLE);
			}
		}

		if (!(rc == '\r' || rc == '\n' )) {
			// receive command
			serial_putc(sobj, rc);
			cmdbuf[cmdbuf_index] = rc;
			cmdbuf_index++;
			cmdbuf[cmdbuf_index] = '\0';
		}
	}
}

void gpio_uart_rx_irq_callback(uint32_t id, gpio_irq_event event)
{
	acquire_wakelock(WAKELOCK_EXAMPLE);
}

void pre_sleep_process_callback(unsigned int expected_idle_time)
{
	// For peripherals that need turned off before sleep, call disable or deinit peripheral here
}

void post_sleep_process_callback(unsigned int expected_idle_time)
{
	// For peripherals that are turned off before sleep, call enable or init peripheral here
}

void config_uart()
{
	// setup uart
	serial_init(&mysobj, UART_TX, UART_RX);
	serial_baud(&mysobj, 38400);
	serial_format(&mysobj, 8, ParityNone, 1);

	serial_irq_handler(&mysobj, uart_irq_callback, (uint32_t)&mysobj);
	serial_irq_set(&mysobj, RxIrq, 1);
	serial_irq_set(&mysobj, TxIrq, 1);

	// config uart rx as gpio wakeup pin
	gpio_irq_t gpio_rx_wake;
	gpio_irq_init(&gpio_rx_wake, UART_RX, gpio_uart_rx_irq_callback, NULL);
	gpio_irq_set(&gpio_rx_wake, IRQ_FALL, 1);   // Falling Edge Trigger
	gpio_irq_enable(&gpio_rx_wake);
}

void gpio_loguart_rx_irq_callback (uint32_t id, gpio_irq_event event)
{
	/*  WAKELOCK_LOGUART is also handled in log service.
	 *  It is release after a complete command is sent.
	 **/
	acquire_wakelock(WAKELOCK_LOGUART);
}

void config_loguart()
{
	/*  Log uart RX pin doesn't support gpio interrupt.
	 *  To make log uart wake system, we can parallel log uart RX with another gpio interrupt pin.
	 */
	gpio_irq_t gpio_rx_wake;
	gpio_irq_init(&gpio_rx_wake, LOGUART_RX_WAKE, gpio_loguart_rx_irq_callback, NULL);
	gpio_irq_set(&gpio_rx_wake, IRQ_FALL, 1);   // Falling Edge Trigger
	gpio_irq_enable(&gpio_rx_wake);
}

/**
  * @brief  Main program.
  * @param  None
  * @retval None
  */
void main(void)
{
	if ( rtl_cryptoEngine_init() != 0 ) {
		DiagPrintf("crypto engine init failed\r\n");
	}

	/* Initialize log uart and at command service */
	console_init();	

	/* pre-processor of application example */
	pre_example_entry();

	/* wlan intialization */
#if defined(CONFIG_WIFI_NORMAL) && defined(CONFIG_NETWORK)
	wlan_network();
#endif

	// setup uart with capability of wakeup system
	config_uart();

	// setup log uart with capability of wakeup system
	config_loguart();

	// By default tickless is disabled because WAKELOCK_OS is locked.
	// Release this wakelock to enable tickless
	release_wakelock(WAKELOCK_OS);

	// Register pre/post sleep callback. They are called when system automatically enter/leave sleep.
	register_sleep_callback_by_module(1, pre_sleep_process_callback, WAKELOCK_EXAMPLE);
	register_sleep_callback_by_module(0, post_sleep_process_callback, WAKELOCK_EXAMPLE);

	/* Execute application example */
	example_entry();

    	/*Enable Schedule, Start Kernel*/
#if defined(CONFIG_KERNEL) && !TASK_SCHEDULER_DISABLED
	#ifdef PLATFORM_FREERTOS
	vTaskStartScheduler();
	#endif
#else
	RtlConsolTaskRom(NULL);
#endif
}
