/*******************************************************************************
 * (c) Copyright 2010 Microsemi Corporation.  All rights reserved.
 *
 *  Webserver Application demo for SmartFusion
 *
 *
 * Author : Corporate Application Team
 * Rev    : 3.0
 *
 *******************************************************************************/

/**************************************************************************/
/* Standard Includes */
/**************************************************************************/

#include <stdio.h>
#include <stdlib.h>

/**************************************************************************/
/* Firmware Includes */
/**************************************************************************/

#include "a2fxxxm3.h"
#include "./drivers/mss_gpio/mss_gpio.h"
#include "./drivers/mss_uart/mss_uart.h"
#include "./drivers/mss_ace/mss_ace.h"

/**************************************************************************/
/* RTOS Includes */
/**************************************************************************/

#include "FreeRTOS.h"
#include "task.h"
#include "queue.h"
#include "semphr.h"

/**************************************************************************/
/* Preprocessor Macros*/
/**************************************************************************/

#define SYS_TICK_CTRL_AND_STATUS_REG      0xE000E010
#define SYS_TICK_CONFIG_REG               0xE0042038
#define SYS_TICK_FCLK_DIV_32_NO_REF_CLK   0x31000000
#define ENABLE_SYS_TICK                   0x7

/**************************************************************************/
/*Declaration of global variables*/
/**************************************************************************/

xSemaphoreHandle stdSemHndl = NULL, htSemHndl = NULL;
xSemaphoreHandle webSemHndl = NULL, ledSemHndl = NULL;
xSemaphoreHandle switchOneSemHndl = NULL;

xTaskHandle stdTaskHndl = NULL, htTaskHndl = NULL, switchOneTaskHndl = NULL;
xTaskHandle webTaskHndl = NULL, aceTaskHndl = NULL, ledTaskHndl = NULL;

/**************************************************************************/
/*Extern Declarations*/
/**************************************************************************/

extern void led_task(void *para);
extern void ace_task(void *para);
extern void web_task(void *para);
extern void standalone_task(void *para);
extern void hyperterminal_task(void *para);
extern void switch_one_task(void *para);

extern void OLED_init(void );
extern void switch_init(void);
extern void led_initialization(void);
extern void ACE_Initialization(void);
extern void oled_welcome_display(void);



void vApplicationMallocFailedHook( void )
{
	/* Called if a call to pvPortMalloc() fails because there is insufficient
	free memory available in the FreeRTOS heap.  pvPortMalloc() is called
	internally by FreeRTOS API functions that create tasks, queues, software
	timers, and semaphores.  The size of the FreeRTOS heap is set by the
	configTOTAL_HEAP_SIZE configuration constant in FreeRTOSConfig.h. */
	for( ;; );
}

unsigned long ulGetRunTimeCounterValue( void )
{
	return 0UL;
}

void vApplicationIdleHook( void )
{
	/* This function is called on each cycle of the idle task.  In this case it
	does nothing useful */

}

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

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

	/* Run time stack overflow checking is performed if
	configconfigCHECK_FOR_STACK_OVERFLOW is defined to 1 or 2.  This hook
	function is called if a stack overflow is detected. */
	for( ;; );
}
/*-----------------------------------------------------------*/

void vMainConfigureTimerForRunTimeStats( void )
{
	/* This function is not used by the Blinky build configuration, but needs
	to be defined as the Blinky and Full build configurations share a
	FreeRTOSConfig.h header file. */
}
/*-----------------------------------------------------------*/


/**************************************************************************/
/*Functions for Interrupt Handlers */
/**************************************************************************/

/**************************************************************************/
/*Interrupt handler for the functionality of switch 01 */
/*Switch 1 push scroll through menu */
/**************************************************************************/
void GPIO8_IRQHandler( void )
{
    static signed portBASE_TYPE xHigherPriorityTaskWoken;

    xSemaphoreGiveFromISR( stdSemHndl, &xHigherPriorityTaskWoken );

    /*Clearing the IRQ requset made by switch01 SW1*/
    MSS_GPIO_clear_irq( MSS_GPIO_8 );
    NVIC_ClearPendingIRQ( GPIO8_IRQn );
}

/**************************************************************************/
/*Interrupt handler for the functionality of switch 02 */
/*Switch 02 selects the functionality of scrolling menu */
/**************************************************************************/

void GPIO9_IRQHandler( void )
{
    static signed portBASE_TYPE xHigherPriorityTaskWoken;

    xSemaphoreGiveFromISR( switchOneSemHndl, &xHigherPriorityTaskWoken );

    /*Clearing the IRQ requset made by switch02 SW2*/
    MSS_GPIO_clear_irq( MSS_GPIO_9 );
    NVIC_ClearPendingIRQ( GPIO9_IRQn );

}

/**************************************************************************/
/* Function to initialization all necessary hardware components for this*/
/* demo*/
/**************************************************************************/

void init_system()
{

    /* Initialize the GPIO */
    MSS_GPIO_init();
    /* Initialize and configure UART0. */
    MSS_UART_init
    (
        &g_mss_uart0,
        MSS_UART_57600_BAUD,
        MSS_UART_DATA_8_BITS | MSS_UART_NO_PARITY | MSS_UART_ONE_STOP_BIT
    );
    /* Initialize the OLED */
    OLED_init();
    /* GPIO inits for the LEDs */
    led_initialization();
    /* ACE Initialization */
    ACE_init();
    /* Configuring the GPIOs for the SWITCHES SW1 and SW2 */
    switch_init();

}

/****************************************************************/
/* Entry to Main form user bootcode                             */
/****************************************************************/

int main()
{
    /* Initialization all necessary hardware components */
    init_system();

    /******************************************************************************
     * Interrupt Priority settings
     *
     * All the interrupts priorities are set to zero (highest priority)by default,
     * interrupts can’t be disabled at this interrupt priority and hence it’s
     * applications responsibility to set to the proper required priority levels.
     * This interrupt priority settings can be done using NVIC APIs.
     * Interrupts priorities and overall system functionality has to be taken
     * care by the overall application architecture”
     *****************************************************************************/

    # if 1
        NVIC_SetPriority( GPIO8_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
        NVIC_EnableIRQ( GPIO8_IRQn );

        NVIC_SetPriority( GPIO9_IRQn, configLIBRARY_MAX_SYSCALL_INTERRUPT_PRIORITY );
         NVIC_EnableIRQ( GPIO9_IRQn );

    #endif

    /* Display the welcome string on OLED */
    oled_welcome_display();
    /* Creating the semaphores for the flow control of the demo */
    stdSemHndl       = xSemaphoreCreateCounting( 1, 0);
    webSemHndl       = xSemaphoreCreateCounting( 1, 0);
    ledSemHndl       = xSemaphoreCreateCounting( 1, 0);
    switchOneSemHndl = xSemaphoreCreateCounting( 1, 0);

    /* Creating the tasks for the functional requirement of the demo */
    /* This task is responsibile for controlling the demo using the
     * SW1 and SW2 switch inputs from the user */
    xTaskCreate( standalone_task,
                 ( signed portCHAR * ) "standalone_task",
                 configMINIMAL_STACK_SIZE,
                 NULL,
                 tskIDLE_PRIORITY + 1,
                 &stdTaskHndl );
    /* This task is responsibile for controlling the demo using the
     * Hyperterminal inputs from the user */
    xTaskCreate( hyperterminal_task,
                 ( signed portCHAR * ) "hyperterminal_task",
                 configMINIMAL_STACK_SIZE,
                 NULL,
                 tskIDLE_PRIORITY +1,
                 &htTaskHndl );
    /* This task is to test the LED functionality */
    xTaskCreate( led_task,
                 ( signed portCHAR * ) "led_task",
                 configMINIMAL_STACK_SIZE,
                 NULL,
                 tskIDLE_PRIORITY +1,
                 &ledTaskHndl );
    /* This task is to test the ACE functionality */
    xTaskCreate( ace_task,
                 ( signed portCHAR * ) "ace_task",
                 configMINIMAL_STACK_SIZE * 2,
                 NULL,
                 tskIDLE_PRIORITY +1,
                 &aceTaskHndl );
    /* This task is to test the 10/100 Ethernet MAC
     * functionality using the web server*/
    xTaskCreate( web_task,
                 ( signed portCHAR * ) "web_task",
                 configMINIMAL_STACK_SIZE * 2,
                 NULL,
                 tskIDLE_PRIORITY +1,
                 &webTaskHndl );

    /* This task is to test moniter the SW1 input and
     * show the menu to OLED*/
    xTaskCreate( switch_one_task,
                 ( signed portCHAR * ) "Switch_one_task",
                 configMINIMAL_STACK_SIZE,
                 NULL,
                 tskIDLE_PRIORITY +1,
                 &switchOneTaskHndl );

    /* Enable the SYS TICK Timer and provide the divider and clock source
     * this is required to enable the RTOS tick */

    *(volatile unsigned long *)SYS_TICK_CTRL_AND_STATUS_REG = ENABLE_SYS_TICK;
    *(volatile unsigned long *)SYS_TICK_CONFIG_REG          = SYS_TICK_FCLK_DIV_32_NO_REF_CLK;

    /* Start the scheduler. */
    vTaskStartScheduler();

    /* Will only get here if there was not enough heap space to create the
    idle task. */

    printf("\n Test Case End: Should never Come here \n\r");

    return 0;

}
