//*****************************************************************************
//
// io.c - I/O routines for the enet_io example application.
//
// Copyright (c) 2013-2017 Texas Instruments Incorporated.  All rights reserved.
// Software License Agreement
// 
// Texas Instruments (TI) is supplying this software for use solely and
// exclusively on TI's microcontroller products. The software is owned by
// TI and/or its suppliers, and is protected under applicable copyright
// laws. You may not combine this software with "viral" open-source
// software in order to form a larger program.
// 
// THIS SOFTWARE IS PROVIDED "AS IS" AND WITH ALL FAULTS.
// NO WARRANTIES, WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT
// NOT LIMITED TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. TI SHALL NOT, UNDER ANY
// CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL, OR CONSEQUENTIAL
// DAMAGES, FOR ANY REASON WHATSOEVER.
// 
// This is part of revision 2.1.4.178 of the EK-TM4C1294XL Firmware Package.
//
//*****************************************************************************
#include <stdbool.h>
#include <stdint.h>
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_pwm.h"
#include "inc/hw_types.h"
#include "driverlib/gpio.h"
#include "driverlib/pwm.h"
#include "driverlib/sysctl.h"
#include "driverlib/timer.h"
#include "driverlib/interrupt.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "utils/ustdlib.h"
#include "io.h"

/* Kernel includes. */
#include "FreeRTOS.h"
#include "task.h"
#include "semphr.h"

/* Definitions for EK-TM4C1294XL on-board LED's  */
#define USER_LED1  CLP_D1
#define USER_LED2  CLP_D2
#define USER_LED3  CLP_D3
#define USER_LED4  CLP_D4

/* Priorities at which the tasks are created. */
#define main_TASK_PRIORITY     ( tskIDLE_PRIORITY + 1 )

/* The notification used by the task */
TaskHandle_t xTaskLedOnHandle = NULL;

/*-----------------------------------------------------------*/
/*
 * The tasks as described in the comments at the top of this file.
 */
static void prvTaskLed( void *pvParameters );


//*****************************************************************************
//
// Hardware connection for the user LED.
//
//*****************************************************************************
#define LED_PORT_BASE GPIO_PORTN_BASE
#define LED_PIN GPIO_PIN_0

//*****************************************************************************
//
// Hardware connection for the animation LED.
//
//*****************************************************************************
#define LED_ANIM_PORT_BASE GPIO_PORTN_BASE
#define LED_ANIM_PIN GPIO_PIN_1

//*****************************************************************************
//
// The system clock speed.
//
//*****************************************************************************
extern uint32_t g_ui32SysClock;

//*****************************************************************************
//
// The current speed of the on-screen animation expressed as a percentage.
//
//*****************************************************************************
volatile unsigned long g_ulAnimSpeed = 10;

//*****************************************************************************
//
// Set the timer used to pace the animation.  We scale the timer timeout such
// that a speed of 100% causes the timer to tick once every 20 mS (50Hz).
//
//*****************************************************************************
static void
io_set_timer(unsigned long ulSpeedPercent)
{
    unsigned long ulTimeout;

    //
    // Turn the timer off while we are mucking with it.
    //
    ROM_TimerDisable(TIMER2_BASE, TIMER_A);

    //
    // If the speed is non-zero, we reset the timeout.  If it is zero, we
    // just leave the timer disabled.
    //
    if(ulSpeedPercent)
    {
        //
        // Set Timeout
        //
        ulTimeout = g_ui32SysClock / 50;
        ulTimeout = (ulTimeout * 100 ) / ulSpeedPercent;

        ROM_TimerLoadSet(TIMER2_BASE, TIMER_A, ulTimeout);
        ROM_TimerEnable(TIMER2_BASE, TIMER_A);
    }
}

//*****************************************************************************
//
// Initialize the IO used in this demo
//
//*****************************************************************************
void
io_init(void)
{
    //
    // Configure Port N0 for as an output for the animation LED.
    //
    ROM_GPIOPinTypeGPIOOutput(LED_ANIM_PORT_BASE, LED_ANIM_PIN);

    //
    // Initialize animation LED to OFF (0)
    //
    ROM_GPIOPinWrite(LED_ANIM_PORT_BASE, LED_ANIM_PIN, LED_ANIM_PIN);

    //
    // Enable the peripherals used by this example.
    //
    ROM_SysCtlPeripheralEnable(SYSCTL_PERIPH_TIMER2);

    //
    // Configure the timer used to pace the animation.
    //
    ROM_TimerConfigure(TIMER2_BASE, TIMER_CFG_PERIODIC);

    //
    // Setup the interrupts for the timer timeouts.
    //
    ROM_IntEnable(INT_TIMER2A);
    ROM_TimerIntEnable(TIMER2_BASE, TIMER_TIMA_TIMEOUT);

    //
    // Set the timer for the current animation speed.  This enables the
    // timer as a side effect.
    //
    io_set_timer(g_ulAnimSpeed);

    /* Start a LED task  */
    xTaskCreate(prvTaskLed,                        /* The function to toggle the LED */
                "Led",                             /* The text name assigned to the task. */
                configMINIMAL_STACK_SIZE,          /* The size of the stack to allocate to the task. */
                NULL,                              /* No parameter passed to the task */
                main_TASK_PRIORITY ,               /* The priority assigned to the task. */
                &xTaskLedOnHandle );               /* The task handle */
}

//*****************************************************************************
//
// Set the status LED on or off.
//
//*****************************************************************************
void
io_set_led(bool bOn)
{
    //
    // Turn the LED on or off as requested.
    //
    ROM_GPIOPinWrite(LED_PORT_BASE, LED_PIN, bOn ? LED_PIN : 0);
}

//*****************************************************************************
//
// Return LED state
//
//*****************************************************************************
void
io_get_ledstate(char * pcBuf, int iBufLen)
{
    //
    // Get the state of the LED
    //
    if(ROM_GPIOPinRead(LED_PORT_BASE, LED_PIN))
    {
        usnprintf(pcBuf, iBufLen, "ON");
    }
    else
    {
        usnprintf(pcBuf, iBufLen, "OFF");
    }

}

//*****************************************************************************
//
// Return LED state as an integer, 1 on, 0 off.
//
//*****************************************************************************
int
io_is_led_on(void)
{
    //
    // Get the state of the LED
    //
    if(ROM_GPIOPinRead(LED_PORT_BASE, LED_PIN))
    {
        return(true);
    }
    else
    {
        return(0);
    }
}

//*****************************************************************************
//
// Set the speed of the animation shown on the display.  In this version, the
// speed is described as a decimal number encoded as an ASCII string.
//
//*****************************************************************************
void
io_set_animation_speed_string(char *pcBuf)
{
    unsigned long ulSpeed;

    //
    // Parse the passed parameter as a decimal number.
    //
    ulSpeed = 0;
    while((*pcBuf >= '0') && (*pcBuf <= '9'))
    {
        ulSpeed *= 10;
        ulSpeed += (*pcBuf - '0');
        pcBuf++;
    }

    //
    // If the number is valid, set the new speed.
    //
    if(ulSpeed <= 100)
    {
        g_ulAnimSpeed = ulSpeed;
        io_set_timer(g_ulAnimSpeed);
    }
}

//*****************************************************************************
//
// Set the speed of the animation shown on the display.
//
//*****************************************************************************
void
io_set_animation_speed(unsigned long ulSpeed)
{
    //
    // If the number is valid, set the new speed.
    //
    if(ulSpeed <= 100)
    {
        g_ulAnimSpeed = ulSpeed;
        io_set_timer(g_ulAnimSpeed);
    }
}

//*****************************************************************************
//
// Get the current animation speed as an ASCII string.
//
//*****************************************************************************
void
io_get_animation_speed_string(char *pcBuf, int iBufLen)
{
    usnprintf(pcBuf, iBufLen, "%d%%", g_ulAnimSpeed);
}

//*****************************************************************************
//
// Get the current animation speed as a number.
//
//*****************************************************************************
unsigned long
io_get_animation_speed(void)
{
    return(g_ulAnimSpeed);
}


/*
 * Task to turn ON LEDs
 */
static void prvTaskLed( void *pvParameters )
{
//    uint32_t ui32LEDState;
    (void) pvParameters;

    while (1)
    {
        if (ulTaskNotifyTake(pdTRUE, portMAX_DELAY) == pdPASS)
        {
//            UARTprintf("Toggle LED\n");
            /* Toggle LED1 on each time through the loop. */
//            LEDRead(&ui32LEDState);
//            LEDWrite(USER_LED1, (ui32LEDState ^ USER_LED1));
            //
            // Toggle the GPIO
            //
            MAP_GPIOPinWrite(GPIO_PORTN_BASE, GPIO_PIN_1,
                    (MAP_GPIOPinRead(GPIO_PORTN_BASE, GPIO_PIN_1) ^
                     GPIO_PIN_1));

        }
    }
}
