//*****************************************************************************
//
// uart_to_can.c - Uart bridge for CAN bootloader
//
// Copyright (c) 2020 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.
// 
//*****************************************************************************

#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "inc/hw_can.h"
#include "inc/hw_ints.h"
#include "inc/hw_memmap.h"
#include "inc/hw_types.h"
#include "driverlib/can.h"
#include "driverlib/gpio.h"
#include "driverlib/interrupt.h"
#include "driverlib/pin_map.h"
#include "driverlib/sysctl.h"
#include "driverlib/uart.h"
#include "driverlib/rom.h"
#include "driverlib/rom_map.h"
#include "bl_can.h"
#include "bl_commands.h"
#include "u2c_can.h"
#include "u2c_uart.h"
#include "driverlib/rom_map.h"

uint8_t g_ui8UartBuffer[UART_PACKET_SIZE];
volatile int g_receiveCount;
volatile enum eUartIntState eUartState;

//*****************************************************************************
//
// The error routine that is called if the driver library encounters an error.
//
//*****************************************************************************
#ifdef DEBUG
void
__error__(char *pcFilename, uint32_t ui32Line)
{
}
#endif

#define COMMAND_CAN_UPDATE           0x26

uint32_t g_ui32SysClock;

//*****************************************************************************
//
// Main 'C' Language entry point.
//
//*****************************************************************************
void main(void)
{
    uint8_t status = COMMAND_RET_UNKNOWN_CMD;
    int receiveCount;
    uint8_t ui8UartBuffer[UART_PACKET_SIZE];
    //
    // Setup the system clock to run at 80 Mhz from PLL with crystal reference
    //
    MAP_SysCtlClockSet(SYSCTL_SYSDIV_2_5|SYSCTL_USE_PLL|SYSCTL_XTAL_16MHZ|
                    SYSCTL_OSC_MAIN);
    g_ui32SysClock = MAP_SysCtlClockGet();
    InitConsole();
    InitCan();
    eUartState = waiting;
    MAP_IntMasterEnable();
    while(true)
    {
        if(eUartState == finished)
        {
            // Copy size from UART and re-enable interrupts
            receiveCount = g_receiveCount;
            // skip checksum, copy rest of buffer
            memcpy(ui8UartBuffer, g_ui8UartBuffer + 1, receiveCount);
            eUartState = waiting;
            MAP_IntEnable(INT_UART0);
            switch(ui8UartBuffer[0])
            {
                case COMMAND_PING:
                {
                    SendCANPing();
                    if(GetCANAck() == true)
                    {
                        status = COMMAND_RET_SUCCESS;
                    }
                    break;
                }
                case COMMAND_DOWNLOAD:
                {
                    SendCANDownload(ui8UartBuffer);
                    if(GetCANAck() == true)
                    {
                        status = COMMAND_RET_SUCCESS;
                    }
                    else
                    {
                        status = COMMAND_RET_INVALID_ADR;
                    }
                    break;
                }
                case COMMAND_GET_STATUS:
                {
                    sendStatus(status);
                    status = COMMAND_RET_SUCCESS;
                    break;
                }
                case COMMAND_SEND_DATA:
                {
                    if(sendCANSend(receiveCount, ui8UartBuffer) == true)
                    {
                        status = COMMAND_RET_SUCCESS;
                    }
                    else
                    {
                        status = COMMAND_RET_FLASH_FAIL;
                    }
                    break;
                }
                case COMMAND_RESET:
                {
                    SendCANReset();
                    status = COMMAND_RET_SUCCESS;
                    break;
                }
                case COMMAND_CAN_UPDATE:
                {
                    SendCANUpdate(receiveCount, ui8UartBuffer);
                    status = COMMAND_RET_SUCCESS;
                    break;
                }
                default:
                {
                    status = COMMAND_RET_UNKNOWN_CMD;
                }
            }
        }

    }
}
