/* USER CODE BEGIN Header */
/* you can remove the copyright */
/*
 *  Copyright 2020-2024 Yuntu Microelectronics co.,ltd
 *  All rights reserved.
 * 
 *  YUNTU Confidential. This software is owned or controlled by YUNTU and may only be
 *  used strictly in accordance with the applicable license terms. By expressly
 *  accepting such terms or by downloading, installing, activating and/or otherwise
 *  using the software, you are agreeing that you have read, and that you agree to
 *  comply with and are bound by, such license terms. If you do not agree to be
 *  bound by the applicable license terms, then you may not retain, install,
 *  activate or otherwise use the software. The production use license in
 *  Section 2.3 is expressly granted for this software.
 * 
 * @file lin_slave.c
 * @brief 
 * 
 */

#include "lin_slave.h"
#include "lin_cfg.h"
#include "lin_sync_api.h"
#include "uart_hw_access.h"

/********************************************************************* Define *****************************************************/
//lin
#define LIN_SLAVE_RECIVE_ID (0x01)
#define LIN_SLAVE_SEND_ID   (0x02)

/********************************************************************* Variable *****************************************************/
static uint8_t g_linTxBuff[8] = {0x55, 0xAA, 0x69, 0x96, 0x96, 0x69, 0xAA, 0x55};
static uint8_t g_linRxBuff[8];
static volatile uint8_t g_linRxCmp = 0, g_linTxCmp = 0;

static volatile uint16_t s_timerOverflowInterruptCount = 0U;
extern UART_Type* g_uartBasePtr[];
 /********************************************************************* Function *****************************************************/
void LinSync_EntryAutobaudMode(void);
void LinSync_QuitAutobaudMode(void);
void LinSync_RestoreDefaultBaudrate(lin_sync_t *linSyncPtr);

void LinSync_CallBackHandler(uint32_t instance, void *lin_State)
{
    (void) instance;
    lin_state_t *linState = (lin_state_t *)lin_State;
    
    /* handle timeout event */
    if(linState->timeoutCounterFlag)
    {
        if (linState->currentNodeState == LIN_NODE_STATE_RECV_SYNC)
        {
// #ifdef TEST_PIN
//         GPIOD->PTOR = 1<<7;
// #endif
            linState->timeoutCounterFlag = false;
            LinSync_QuitAutobaudMode();
        }

        LinSync_RestoreDefaultBaudrate(&g_linSync);

    }else {
    
        switch (linState->currentEventId)
        {
            case LIN_PID_OK:
                /* Set timeout */
                LIN_DRV_SetTimeoutCounter(instance, 180);

                if (LIN_SLAVE_RECIVE_ID == linState->currentId)
                {
                    LIN_DRV_ReceiveFrameData(instance, g_linRxBuff, sizeof(g_linRxBuff));
                }else if (LIN_SLAVE_SEND_ID == linState->currentId)
                {
                    LIN_DRV_SendFrameData(instance, g_linTxBuff, sizeof(g_linTxBuff));
                }else {
                    LIN_DRV_GotoIdleState(instance);
                    LinSync_RestoreDefaultBaudrate(&g_linSync);
                }
                break;
            case LIN_PID_ERROR:
                break;
            case LIN_TX_COMPLETED:
                g_linTxCmp = 1;
                break;
            case LIN_RX_COMPLETED:
                g_linRxCmp = 1;
                break;
            case LIN_CHECKSUM_ERROR:
                break;
            case LIN_READBACK_ERROR:
                break;
            case LIN_FRAME_ERROR:
                break;
            case LIN_RECV_BREAK_FIELD_OK:
                LinSync_EntryAutobaudMode();
#ifdef TEST_PIN
        GPIOD->PTOR = 1<<6;
#endif
                LIN_DRV_SetTimeoutCounter(instance, 40);
                break;
            case LIN_WAKEUP_SIGNAL:
                break;
            case LIN_SYNC_ERROR:
                LinSync_QuitAutobaudMode();
                break;
            case LIN_BAUDRATE_ADJUSTED:
                break;
            case LIN_NO_EVENT:
                break;
            case LIN_SYNC_OK:
                break;
            default:
                /* do nothing */
                break;
        }
    }
    
    if((LIN_SYNC_ERROR == linState->currentEventId) || (LIN_PID_ERROR == linState->currentEventId) || \
       (LIN_FRAME_ERROR == linState->currentEventId) || (LIN_READBACK_ERROR == linState->currentEventId) ||\
       (LIN_CHECKSUM_ERROR == linState->currentEventId) || (LIN_TX_COMPLETED == linState->currentEventId) ||\
       (LIN_RX_COMPLETED == linState->currentEventId) || (LIN_RX_OVERRUN == linState->currentEventId))
    {
        LinSync_RestoreDefaultBaudrate(&g_linSync);
    }
}

/*!
 * @brief Interrupt handler for LPUART Rx pin port event
 * This function will capture the time stamp of the Rx pin
 * level transition and will run Auto Baudrate function
 * if required.
 */
void LinSync_RxPinIrqHandler(void)
{
    volatile uint32_t counterValue = LIN_SYNC_TIMER_GET_COUNTER_VALUE();

    /* Check if the interrupt is triggered by the LPUART Rx Pin */
    if ( (PINS_DRV_GetPortIntFlag(LIN_SYNC_RX_GPIO) & (1U << LIN_SYNC_RX_PIN_INDEX)) )
    {
#ifdef TEST_PIN
        GPIOD->PTOR = 1<<5;
#endif
        /* Clear PIN interrupt register */
        PINS_DRV_ClearPinIntFlagCmd(LIN_SYNC_RX_GPIO, LIN_SYNC_RX_PIN_INDEX);
        /* Capture transition time stamp */
		g_linSync.capturedValue = counterValue;
        if(g_linSync.isSyncing == true)
        {
            switch(LinSync_AutoBaudCapture(&g_linSync))
            {
                case STATUS_SUCCESS:
                    LinSync_QuitAutobaudMode();
                    break;
                case STATUS_ERROR:
                    LinSync_QuitAutobaudMode();
                    LIN_DRV_GotoIdleState(g_linSync.uartInstance);
                    break;
                case STATUS_BUSY:
                    break;
                default:
                    break;
            }
#ifdef TEST_PIN
        GPIOD->PTOR = 1<<7;
#endif
        }
    }
}


void LinSync_EntryAutobaudMode(void)
{
    g_linSync.isSyncing = true;
    //将rx设置成GPIO，去实现自适应波特率
    PINS_DRV_SetMuxModeSel(LIN_SYNC_RX_PORT, LIN_SYNC_RX_PIN_INDEX, PCTRL_MUX_AS_GPIO);
    PINS_DRV_ClearPortIntFlagCmd(LIN_SYNC_RX_GPIO);
    PINS_DRV_SetPinIntSel(LIN_SYNC_RX_GPIO, LIN_SYNC_RX_PIN_INDEX, PCTRL_INT_EITHER_EDGE);
}

void LinSync_QuitAutobaudMode(void)
{
    g_linSync.isSyncing = false;
    PINS_DRV_SetMuxModeSel(LIN_SYNC_RX_PORT, LIN_SYNC_RX_PIN_INDEX, LIN_SYNC_RX_PORT_MUX_ALTx);
    PINS_DRV_SetPinIntSel(LIN_SYNC_RX_GPIO, LIN_SYNC_RX_PIN_INDEX, PCTRL_DMA_INT_DISABLED);
}

/* LPTMR IRQN handler */
void LinSync_lptmrIsrHandler(void)
{
#ifdef TEST_PIN
        // GPIOD->PTOR = 1<<7;
#endif
    /* Clear compare flag */
    lpTMR_DRV_ClearCompareFlag(0);
    /* Timer Interrupt Handler */
    LIN_DRV_TimeoutService(0);
    s_timerOverflowInterruptCount++;
}

/*!
 * @brief Callback function to get time interval in nano seconds
 * @param[out] ns - number of nanoseconds passed since the last call of the function
 * @return dummy value
 */
uint32_t linTimerGetTimeIntervalCallback(uint32_t *ns)
{
    static uint32_t previousCountValue = 0UL;
    uint32_t counterValue;
    counterValue = lpTMR_DRV_GetCounterValueByCount(0);
    *ns = (((uint32_t)(s_timerOverflowInterruptCount * TIMER_TOTAL_TICKS + counterValue - previousCountValue)) * 1000U) / TIMER_TICKS_1US;
    previousCountValue = counterValue;
    s_timerOverflowInterruptCount = 0U;
    return 0UL;
}

void LinSync_RestoreDefaultBaudrate(lin_sync_t *linSyncPtr)
{
    INT_SYS_DisableIRQGlobal();
    UART_SetOversamplingRatio(g_uartBasePtr[linSyncPtr->uartInstance], linSyncPtr->nominalOsr);
    UART_SetBaudRateDivisor(g_uartBasePtr[linSyncPtr->uartInstance], linSyncPtr->nominalSbr);
    INT_SYS_EnableIRQGlobal();
}