/**
 * \file
 *
 * \brief Empty user application template
 *
 */

/**
 * \mainpage User Application template doxygen documentation
 *
 * \par Empty user application template
 *
 * Bare minimum empty user application template
 *
 * \par Content
 *
 * -# Include the ASF header files (through asf.h)
 * -# Minimal main function that starts with a call to board_init()
 * -# "Insert application code here" comment
 *
 */

/*
 * Include header files for all drivers that have been imported from
 * Atmel Software Framework (ASF).
 */
#include <asf.h>

#include "support/TWI_IO_Expander.h"
#include "support/USB.h"
#include "tasks/ports_controller.h"
#include "tasks/run_led.h"
#include "tasks/guardian.h"
#include "tasks/controller.h"
#include "support/DIO_Ports.h"

/* SRAM */
#define SRAM_SIZE				  (0x80000UL)
#define SRAM_BASE_ADDRESS         (0x60000000UL)


/*
 * Sets up the hardware ready to run this example.
 */
static void SetupHardware(void);

void configure_SRAM(void);

static void SetupSwResources(void);

/*
 * FreeRTOS hook (or callback) functions that are defined in this file.
 */
void vApplicationMallocFailedHook(void);
void vApplicationIdleHook(void);
void vApplicationStackOverflowHook(xTaskHandle pxTask, signed char *pcTaskName);
void vApplicationTickHook(void);

controller_handle_t controller_handle;
ports_controller_handle_t ports_controller_handle;
run_led_handle_t run_led_handle;
guardian_handle_t guardian_handle;

int main (void)
{
	/* Prepare the hardware to run this demo. */
	SetupHardware();
	debug_event(DIO_SEVERITY_CRITICAL, "Initialization...");
	
	/* */
	SetupSwResources();
	
	
	/* Start the RTOS scheduler. */
	debug_event(DIO_SEVERITY_CRITICAL, "Starting RTOS scheduler...");
	vTaskStartScheduler();

	/* If all is well, the scheduler will now be running, and the following line
	will never be reached.  If the following line does execute, then there was
	insufficient FreeRTOS heap memory available for the idle and/or timer tasks
	to be created.  See the memory management section on the FreeRTOS web site
	for more details. */
	debug_event(DIO_SEVERITY_CRITICAL, "Could not start RTOS scheduler.");
	for(;;){
	}
	return 0;
}

/*-----------------------------------------------------------*/

static void SetupSwResources(void)
{	
	
	if (ports_controller_init(&ports_controller_handle) != STATUS_OK) {
		debug_error(DIO_SEVERITY_CRITICAL, "Could not initialize 'Ports controller' task.");
		for (;;){
			;
		}
	}
	
	if (run_led_init(&ports_controller_handle, &run_led_handle) != STATUS_OK) {
		debug_error(DIO_SEVERITY_CRITICAL, "Could not initialize 'Run LED' task.");
		for (;;){
			;
		}
	}
	
	if (controller_init(&run_led_handle, &ports_controller_handle, &controller_handle) != STATUS_OK) {
		debug_error(DIO_SEVERITY_CRITICAL, "Could not initialize 'Controller' task.");
		for (;;){
			;
		}
	}
	
	if (guardian_init(&guardian_handle) != STATUS_OK) {
		debug_error(DIO_SEVERITY_CRITICAL, "Could not initialize 'Guardian' task.");
		for (;;){
			;
		}
	}
}

/*-----------------------------------------------------------*/

static void SetupHardware(void)
{
	const usart_serial_options_t usart_serial_options = {
		.baudrate   = CONF_UART_BAUDRATE,
		.paritytype = CONF_UART_PARITY
	};
	
	/* Enable IRQ */
	irq_initialize_vectors();
	cpu_irq_enable();

	/* ASF function to setup clocking. */
	sysclk_init();

	/* Ensure all priority bits are assigned as preemption priority bits. */
	NVIC_SetPriorityGrouping(0);

	/* Atmel library function to setup for the evaluation kit being used. */
	board_init();

	/* Enable unit test output peripheral. */
	sysclk_enable_peripheral_clock(CONSOLE_UART_ID);
	stdio_serial_init(CONSOLE_UART , &usart_serial_options);
	
	// Start USB stack to authorize VBus monitoring
	udc_start();
	
	if (!udc_include_vbus_monitoring())
		usb_vbus_callback(true);
}

void configure_SRAM(void)
{
	puts("Configure PMC to enable the SMC clock.\r\n");
	pmc_enable_periph_clk(ID_SMC);
	
	smc_set_setup_timing(SMC, 0, SMC_SETUP_NWE_SETUP(10)		// t_as >= 0ns
	| SMC_SETUP_NCS_WR_SETUP(0)						// t_as >= 0ns
	| SMC_SETUP_NRD_SETUP(2)						// not defined
	| SMC_SETUP_NCS_RD_SETUP(0));					// not defined
	smc_set_pulse_timing(SMC, 0, SMC_PULSE_NWE_PULSE(45)// t_wp >= 45ns
	| SMC_PULSE_NCS_WR_PULSE(1)
	| SMC_PULSE_NRD_PULSE(53)
	| SMC_PULSE_NCS_RD_PULSE(1));
	smc_set_cycle_timing(SMC, 0, SMC_CYCLE_NWE_CYCLE(55)	// t_wc >= 55ns
	| SMC_CYCLE_NRD_CYCLE(55));						// t_rc >= 55ns
	smc_set_mode(SMC, 0, SMC_MODE_READ_MODE | SMC_MODE_WRITE_MODE | SMC_MODE_DBW_8_BIT);
}

/*-----------------------------------------------------------*/

void vApplicationMallocFailedHook(void)
{
	/* vApplicationMallocFailedHook() will only be called if
	configUSE_MALLOC_FAILED_HOOK is set to 1 in FreeRTOSConfig.h.  It is a hook
	function that will get called if a call to pvPortMalloc() fails.
	pvPortMalloc() is called internally by the kernel whenever a task, queue,
	timer or semaphore is created.  It is also called by various parts of the
	demo application.  If heap_1.c or heap_2.c are used, then the size of the
	heap available to pvPortMalloc() is defined by configTOTAL_HEAP_SIZE in
	FreeRTOSConfig.h, and the xPortGetFreeHeapSize() API function can be used
	to query the size of free heap space that remains (although it does not
	provide information on how the remaining heap might be fragmented). */
	taskDISABLE_INTERRUPTS();
	debug_error(DIO_SEVERITY_CRITICAL, "");	
	for (;;) {
	}
}

/*-----------------------------------------------------------*/

void vApplicationIdleHook(void)
{
	/* vApplicationIdleHook() will only be called if configUSE_IDLE_HOOK is set
	to 1 in FreeRTOSConfig.h.  It will be called on each iteration of the idle
	task.  It is essential that code added to this hook function never attempts
	to block in any way (for example, call xQueueReceive() with a block time
	specified, or call vTaskDelay()).  If the application makes use of the
	vTaskDelete() API function (as this demo application does) then it is also
	important that vApplicationIdleHook() is permitted to return to its calling
	function, because it is the responsibility of the idle task to clean up
	memory allocated by the kernel to any task that has since been deleted. */
}
/*-----------------------------------------------------------*/

void vApplicationStackOverflowHook(xTaskHandle pxTask,
		signed char *pcTaskName)
{
	(void) pcTaskName;
	(void) pxTask;

	/* Run time stack overflow checking is performed if
	configCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2.  This hook
	function is called if a stack overflow is detected. */
	taskDISABLE_INTERRUPTS();
	debug_error(DIO_SEVERITY_CRITICAL, "Overflow for task %s.", pcTaskName);
	for (;;) {
	}
}

/*-----------------------------------------------------------*/

void vApplicationTickHook(void)
{
	/* This function will be called by each tick interrupt if
	configUSE_TICK_HOOK is set to 1 in FreeRTOSConfig.h.  User code can be
	added here, but the tick hook is called from an interrupt context, so
	code must not attempt to block, and only the interrupt safe FreeRTOS API
	functions can be used (those that end in FromISR()). */
}

