/*
 *
 * Copyright (c) 2018 Texas Instruments Incorporated
 *
 * All rights reserved not granted herein.
 *
 * Limited License.
 *
 * Texas Instruments Incorporated grants a world-wide, royalty-free, non-exclusive
 * license under copyrights and patents it now or hereafter owns or controls to make,
 * have made, use, import, offer to sell and sell ("Utilize") this software subject to the
 * terms herein.  With respect to the foregoing patent license, such license is granted
 * solely to the extent that any such patent is necessary to Utilize the software alone.
 * The patent license shall not apply to any combinations which include this software,
 * other than combinations with devices manufactured by or for TI ("TI Devices").
 * No hardware patent is licensed hereunder.
 *
 * Redistributions must preserve existing copyright notices and reproduce this license
 * (including the above copyright notice and the disclaimer and (if applicable) source
 * code license limitations below) in the documentation and/or other materials provided
 * with the distribution
 *
 * Redistribution and use in binary form, without modification, are permitted provided
 * that the following conditions are met:
 *
 * *       No reverse engineering, decompilation, or disassembly of this software is
 * permitted with respect to any software provided in binary form.
 *
 * *       any redistribution and use are licensed by TI for use only with TI Devices.
 *
 * *       Nothing shall obligate TI to provide you with source code for the software
 * licensed and provided to you in object code.
 *
 * If software source code is provided to you, modification and redistribution of the
 * source code are permitted provided that the following conditions are met:
 *
 * *       any redistribution and use of the source code, including any resulting derivative
 * works, are licensed by TI for use only with TI Devices.
 *
 * *       any redistribution and use of any object code compiled from the source code
 * and any resulting derivative works, are licensed by TI for use only with TI Devices.
 *
 * Neither the name of Texas Instruments Incorporated nor the names of its suppliers
 *
 * may be used to endorse or promote products derived from this software without
 * specific prior written permission.
 *
 * DISCLAIMER.
 *
 * THIS SOFTWARE IS PROVIDED BY TI AND TI'S LICENSORS "AS IS" AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
 * IN NO EVENT SHALL TI AND TI'S LICENSORS BE LIABLE FOR ANY DIRECT, INDIRECT,
 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
 * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 * OF THE POSSIBILITY OF SUCH DAMAGE.
 *
 */

#include <app.h>
#include <utils/console_io/include/app_log.h>
#include <utils/timer/include/app_timer.h>
#include <utils/sciserver/include/app_sciserver.h>
#include <utils/rtos/include/app_rtos.h>
#include <stdio.h>
#include <string.h>
#include <ti/osal/osal.h>
#include <app_ipc_rsctable.h>
#include <utils/perf_stats/include/app_perf_stats.h>
#include <ti/csl/csl_mcan.h>
#include <ti/csl/hw_types.h>
#include <ti/csl/soc.h>
#include <ti/csl/example/utils/uart_console/inc/uartConfig.h>
#include <ti/board/board.h>
#ifdef UNITY_INCLUDE_CONFIG_H
#include <ti/build/unit-test/Unity/src/unity.h>
#include <ti/build/unit-test/config/unity_config.h>
#endif

/**< SCI Server Init Task stack size */
#define APP_SCISERVER_INIT_TSK_STACK        (32U * 1024U)
/* SCI Server Init Task Priority - must be higher than High priority Sciserver task */
#define INIT_SCISERVER_TASK_PRI         (6)

/* Sciserver Init Task stack */
static uint8_t  gSciserverInitTskStack[APP_SCISERVER_INIT_TSK_STACK]
#if defined(SAFERTOS)
__attribute__ ((aligned(APP_SCISERVER_INIT_TSK_STACK)));
#else
__attribute__ ((aligned(8192)));
#endif
#ifndef BAUD_RATE
#define BAUD_RATE       BAUD_RATE_115200
#endif

#ifndef WORD_LENGTH
#define WORD_LENGTH     UART_WORD_LENGTH_8
#endif

#ifndef STOP_BIT
#define STOP_BIT        UART_STOP_BIT_1
#endif

#ifndef PARITY
#define PARITY          UART_NO_PARITY
#endif

#ifndef UART_MODE
#define UART_MODE       UART_16x_MODE
#endif

#define UART_INST_NUM                    (1U)
uint32_t uartBaseAddr;

void padConfig_prcmEnable()
{
#if defined (SOC_AM574x) || defined (SOC_AM572x) || defined (SOC_AM571x)
    /*Pad configurations */
    Board_initCfg boardCfg;
    boardCfg = BOARD_INIT_UNLOCK_MMR | BOARD_INIT_UART_STDIO |
               BOARD_INIT_MODULE_CLOCK | BOARD_INIT_PINMUX_CONFIG;
    Board_init(boardCfg);
#endif
#if defined (SOC_TDA2XX) || defined (SOC_TDA2PX) || defined (SOC_TDA2EX) || defined (SOC_DRA72x) || defined (SOC_DRA75x)
    /*Pad configurations */
    HW_WR_REG32(SOC_CORE_PAD_IO_REGISTERS_BASE+CTRL_CORE_PAD_UART1_RXD,0x00040000);
    HW_WR_REG32(SOC_CORE_PAD_IO_REGISTERS_BASE+CTRL_CORE_PAD_UART1_TXD,0x00000000);
    /* Set the UART Parameters */
    UARTConfigInit(uartBaseAddr, BAUD_RATE, WORD_LENGTH, STOP_BIT, PARITY,
                    UART_MODE);
#endif
#if defined (SOC_TDA3XX) || defined (SOC_DRA78x)
    /*Pad configurations */
    HW_WR_REG32(SOC_CORE_PAD_IO_REGISTERS_BASE+CTRL_CORE_PAD_IO_SPI1_SCLK,0x00040001);
    HW_WR_REG32(SOC_CORE_PAD_IO_REGISTERS_BASE+CTRL_CORE_PAD_IO_SPI1_CS0,0x00000001);
    /* Set the UART Parameters */
    UARTConfigInit(uartBaseAddr, BAUD_RATE, WORD_LENGTH, STOP_BIT, PARITY,
                    UART_MODE);
#endif
//#if defined (SOC_AM65XX) || defined (SOC_J721E) || defined (SOC_J7200) || defined (SOC_AM64X) || defined (SOC_J721S2) || defined (SOC_J784S4) || defined (SOC_J742S2)
    Board_initCfg boardCfg;
    Board_STATUS  boardStatus;

    boardCfg = BOARD_INIT_PINMUX_CONFIG |
               BOARD_INIT_UART_STDIO;
    boardStatus = Board_init(boardCfg);
    if (boardStatus != BOARD_SOK)
    {
        printf("[Error] Board init failed!!\n");
    }

    /* Set the UART Parameters */
    UARTConfigInit(uartBaseAddr, BAUD_RATE, WORD_LENGTH, STOP_BIT, PARITY,
                    UART_MODE);
//#endif
}

void test_csl_uart_test_app(void)
{
    char     dataBuffer[100];
#if defined (SOC_AM65XX) || defined (SOC_J721E) || defined (SOC_J7200)
  #if defined (__aarch64__)
    uartBaseAddr = CSL_UART0_BASE;
  #else
    uartBaseAddr = CSL_MCU_UART0_BASE;
  #endif
#elif defined (SOC_AM64X)
  #if defined (__aarch64__)
    uartBaseAddr = CSL_UART1_BASE;
  #else
    uartBaseAddr = CSL_UART0_BASE;
  #endif
#elif defined (SOC_J721S2) || defined (SOC_J784S4) || defined (SOC_J742S2)
  #if defined (__aarch64__)
    uartBaseAddr = CSL_UART8_BASE;
  #else
    uartBaseAddr = CSL_MCU_UART0_BASE;
  #endif
#else
    uartBaseAddr = SOC_UART1_BASE;
#endif

#if defined (SOC_TDA3XX) || defined (SOC_DRA78x)
    uartBaseAddr = SOC_UART3_BASE;
#endif
#if (defined (SOC_AM574x) || defined (SOC_AM572x)) || (defined (SOC_AM571x))
    uartBaseAddr = SOC_UART3_BASE;
#endif

uartBaseAddr = CSL_MCU_UART0_BASE;
    /*Pad configuration and PRCM enable*/
    padConfig_prcmEnable();
    
    UARTConfigPuts(uartBaseAddr, "\nUART Console Test App", -1);
    UARTConfigPuts(uartBaseAddr, "\nUser needs to enter input string", -1);
    UARTConfigPuts(uartBaseAddr, "\nOutput can be observed on UART console ", -1);
    UARTConfigPuts(uartBaseAddr, "\nTest is marked as PASS if input and output matches", -1);
    UARTConfigPuts(uartBaseAddr, "\nTest uses below parameters: ", -1);
    UARTConfigPuts(uartBaseAddr, "\n  -BAUD_RATE    = 115200", -1);
    UARTConfigPuts(uartBaseAddr, "\n  -WORD_LENGTH  = 8Bits", -1);
    UARTConfigPuts(uartBaseAddr, "\n  -STOP_BIT     = 1", -1);
    UARTConfigPuts(uartBaseAddr, "\n  -PARITY       = None", -1);
    UARTConfigPuts(uartBaseAddr, "\n\n", -1);
    UARTConfigPuts(uartBaseAddr, "\nUART Test has started", -1);
    
    /* UART receive and transmit operation */
    UARTConfigPuts(uartBaseAddr, "\nUART Test", -1);

    UARTConfigPuts(uartBaseAddr, "\nEnter some data to transmit:", -1);

    UARTConfigGets(uartBaseAddr, &dataBuffer[0], -1);

    UARTConfigPuts(uartBaseAddr, "\nData Received:", -1);

    UARTConfigPuts(uartBaseAddr, &dataBuffer[0], -1);

    UARTConfigPuts(uartBaseAddr, "\nAll tests have passed.", -1);

#if defined (UNITY_INCLUDE_CONFIG_H)
    TEST_PASS();
#endif
    return;
}
static void appMain(void* arg0, void* arg1)
{
    app_rtos_task_handle_t sciserverInitTask;
    app_rtos_task_params_t sciserverInitTaskParams;

    appSciserverSciclientInit();

    /* Initialize SCI Client Server */
    appRtosTaskParamsInit(&sciserverInitTaskParams);
    sciserverInitTaskParams.priority     = INIT_SCISERVER_TASK_PRI;
    sciserverInitTaskParams.stack        = gSciserverInitTskStack;
    sciserverInitTaskParams.stacksize    = sizeof (gSciserverInitTskStack);
    sciserverInitTaskParams.taskfxn = &appSciserverInit;

    sciserverInitTask = appRtosTaskCreate(&sciserverInitTaskParams);
    if(NULL == sciserverInitTask)
    {
        OS_stop();
    }

    //printf("hello world from mcu1_0\r\n");
    appInit();
    appRun();
    //mcan_main();
    //UART_init();
    //appLogPrintf(".....###Uart init");
    test_csl_uart_test_app();
    #if 1
    while(1)
    {
        appLogWaitMsecs(100u);
    }
    #else
    appDeInit();
    #endif
}

void StartupEmulatorWaitFxn (void)
{
    volatile uint32_t enableDebug = 0;
    do
    {
    }while (enableDebug);
}

/**< SCI Server Init Task stack size */
#define APP_MCU1_0_TASK_STACK        (64U * 1024U)

static uint8_t gTskStackMain[APP_MCU1_0_TASK_STACK]
__attribute__ ((section(".bss:taskStackSection")))
#if defined(SAFERTOS)
__attribute__ ((aligned(APP_MCU1_0_TASK_STACK)));
#else
__attribute__ ((aligned(8192)));
#endif
    ;

int main(void)
{
    app_rtos_task_params_t tskParams;
    app_rtos_task_handle_t task;

#if defined FREERTOS
    /* Relocate FreeRTOS Reset Vectors from BTCM*/
    void _freertosresetvectors (void);
    memcpy((void *)0x0, (void *)_freertosresetvectors, 0x40);
#endif

#if defined SAFERTOS
    /* Relocate SafeRTOS Reset Vectors from BTCM*/
    void _axSafeRTOSresetVectors (void);
    memcpy((void *)0x0, (void *)_axSafeRTOSresetVectors, 0x40);
#endif

    /* This is for debug purpose - see the description of function header */
    StartupEmulatorWaitFxn();

    OS_init();

    appPerfStatsInit();

    /* Initialize the task params */
    appRtosTaskParamsInit(&tskParams);
    /* Set the task priority higher than the default priority (1) */
    tskParams.priority     = 2;
    tskParams.stack        = gTskStackMain;
    tskParams.stacksize    = sizeof (gTskStackMain);
    tskParams.taskfxn = &appMain;
    task = appRtosTaskCreate(&tskParams);
    if(NULL == task)
    {
        OS_stop();
    }
    OS_start();    /* does not return */

    return 0;
}

uint32_t appGetDdrSharedHeapSize()
{
    return DDR_SHARED_MEM_SIZE;

}

uint64_t appTarget2SharedConversion(const uint64_t virtAddr)
{
  uint64_t phyAddr = (uint64_t)virtAddr;

  if ( ((uint64_t)virtAddr >= (uint64_t)DDR_SHARED_MEM_ADDR) &&
       ((uint64_t)virtAddr < ((uint64_t)DDR_SHARED_MEM_ADDR + (uint64_t)DDR_SHARED_MEM_SIZE)) )
  {
        if ((uint64_t)DDR_SHARED_MEM_PHYS_ADDR >= (uint64_t)DDR_SHARED_MEM_ADDR)
        {
            phyAddr = (uint64_t)virtAddr + ((uint64_t)DDR_SHARED_MEM_PHYS_ADDR - (uint64_t)DDR_SHARED_MEM_ADDR);
        }
        else
        {
            phyAddr = (uint64_t)virtAddr - ((uint64_t)DDR_SHARED_MEM_ADDR - (uint64_t)DDR_SHARED_MEM_PHYS_ADDR);
        }
  }

  return phyAddr;
}

uint64_t appUdmaVirtToPhyAddrConversion(const void *virtAddr,
                                      uint32_t chNum,
                                      void *appData)
{
    return appTarget2SharedConversion((uint64_t)virtAddr);
}

uint64_t appShared2TargetConversion(const uint64_t shared_ptr)
{
    uint64_t target_ptr;

    /* Note: I think this is correct but needs review */
    if ( ((uint64_t)shared_ptr >= (uint64_t)DDR_SHARED_MEM_PHYS_ADDR) &&
         ((uint64_t)shared_ptr < ((uint64_t)DDR_SHARED_MEM_PHYS_ADDR + (uint64_t)DDR_SHARED_MEM_PHYS_SIZE)) )
    {
        if ((uint64_t)DDR_SHARED_MEM_PHYS_ADDR >= (uint64_t)DDR_SHARED_MEM_ADDR)
        {
            target_ptr = (uint64_t)shared_ptr - ((uint64_t)DDR_SHARED_MEM_PHYS_ADDR - (uint64_t)DDR_SHARED_MEM_ADDR);
        }
        else
        {
            target_ptr = (uint64_t)shared_ptr + ((uint64_t)DDR_SHARED_MEM_ADDR - (uint64_t)DDR_SHARED_MEM_PHYS_ADDR);
        }
    }
    else
    {
        target_ptr = (uint64_t)shared_ptr;
    }

    return target_ptr;
}
