/****************************************************************
*
* lin_config.c
*
* LIN処理
*
*
*
*
*                                                     2026/04/15
*                                                     DNC S.Tasaka
*
******************************************************************/
// MSPM0 LINスレーブ実装
// 以下のLIN 2.2Aレスポンダ機能を実装
// - ブレークフィールドの検出と検証
// - 同期フィールドの測定と自動ボーレート同期
// - PID受信とメッセージテーブル参照
// - チェックサム検証付きデータフィールドの送受信
// - 不完全なフレームのタイムアウト処理
// UART拡張およびUNICOMM UARTペリフェラルの両方をサポートします。

// インクルードファイル
#include "lin_config.h"
#include "timer.h"
#include "lin_message.h"
#include "intr_check.h"

// グローバル変数
//(デバッグおよびエラー追跡のための診断情報)
LIN_diag_t gLINDiag = { 0 };

//(タイミングと自動ボーレートのコンテキスト（デフォルト値付き）)
volatile Lin_timing_t gLINT = {
    // ブレークフィールドタイミング
    .brkW       = 0,
    .brkCmp     = LIN_0_COUNTER_COMPARE_VALUE,
    // Syncフィールド計測
    .syncStart  = true,
    .syncBt     = { 0 },
    .syncOkCnt  = 0,
    .syncErrCnt = 0,
    // ビット時間計算
    .btSum      = 0,
    .btAvg      = 0,
    .btWidth    = LIN_0_TBIT_WIDTH,
    .btWMax     = LIN_0_TBIT_WIDTH * LIN_AUTO_BAUD_MAX / 100,
    .btWMin     = LIN_0_TBIT_WIDTH * LIN_AUTO_BAUD_MIN / 100,
    // ボーレートトラッキング
    .brMeas     = 0,
    .brPrev     = LIN_0_BAUD_RATE,
    .brCurr     = LIN_0_BAUD_RATE,
    // 自動ボーレート状態
    .autoBaud   = false,
    // レスポインすタイミング
    .respDelay  = LIN_RESPONSE_LAPSE
};

//(デフォルト値を使用したLIN送受信コンテキスト)
Lin_TxRxCtx_t gLIN = {
    .state          = LIN_STATE_WAIT_FOR_BREAK,
    .respMsgTbl     = (LIN_table_record_t*)gMessageTable,
    .msgTblIdx      = 0,
    .rxIdx          = 0,
    .txIdx          = 1,
    .rxBuf          = { 0 },
    .txBuf          = { 0 },
    .chkSum.word    = 0,
    .isNoErr1500ms  = true,
    .timing         = &gLINT,
};

extern uint8_t gLinDataItems[LIN_RESPONDER_NUM_MSGS][LIN_DATA_MAX_BUFFER_SIZE];  // 起動時のみ初期化

// Syncフィールド測定用にLINカウンタを設定
// 比較一致を無効にし、両方のキャプチャチャネルを有効にし、
// カウンタを立ち上がりエッジでゼロになるように設定します。
// param[in] peripheral LIN 周辺インスタンスへのポインタ
__STATIC_INLINE void LIN_switchCounterToSyncMode(LIN_Peripheral_t peripheral)
{
    DL_UART_enableLINSyncFieldValidationCounterControl(peripheral);
    DL_UART_enableLINFallingEdgeCapture(peripheral);
    DL_UART_disableLINCountWhileLow(peripheral);
}

// LINカウンタをブレークフィールド検出用に設定
// ブレーク検出のための比較一致を有効にし、
// 立ち下がりエッジのキャプチャを無効にし、
// RXがローの間カウンタをカウントするように設定します。
// param[in] peripheral  LIN周辺機器インスタンスへのポインタ
__STATIC_INLINE void LIN_switchCounterToBreakMode(LIN_Peripheral_t peripheral)
{
    DL_UART_enableLINCounterCompareMatch(peripheral);
    DL_UART_Extend_enableLINCountWhileLow(peripheral);
    DL_UART_Extend_enableLINCounterClearOnFallingEdge(peripheral);
}

bool lin_check_pid(uint8_t pid, LIN_diag_t *lin_diag);
bool LIN_Responder_transmitMessageBitCheck(LIN_Peripheral_t peripheral, uint8_t checkData, LIN_diag_t *lin_diag);
static void LIN_Responder_resetState(LIN_Peripheral_t peripheral, Lin_TxRxCtx_t *lin);
static void LIN_prepareForNextFrame(LIN_Peripheral_t peripheral);

/****************************************************************
*【関数名】lin_enable
*【説  明】LINの有効化
*【引  数】なし
*【戻り値】なし
******************************************************************/
void lin_enable(void)
{
    // LIN利用時のワーククリア
    LIN_Responder_resetState(LIN_0_INST, &gLIN);

    // LIN0割込設定クリア
    NVIC_ClearPendingIRQ(LIN_0_INST_INT_IRQN);

    // 割込有効
    NVIC_EnableIRQ(LIN_0_INST_INT_IRQN);    // LIN割込有効

    timer0_1p5ms_enable();                  // TIMER割込有効
}

/****************************************************************
*【関数名】lin_disable
*【説  明】LINの有効化
*【引  数】なし
*【戻り値】なし
******************************************************************/
void lin_disable(void)
{
    // 割込無効
    NVIC_DisableIRQ(LIN_0_INST_INT_IRQN);   // LIN割込有効

    // LIN0割込設定クリア
    NVIC_ClearPendingIRQ(LIN_0_INST_INT_IRQN);

    timer0_1p5ms_disable();                 // TIMER割込有効
}

// LINステートマシンをリセットしてブレーク（クリーン終了）を待機
// この関数は、あらゆるエラー状態から正常に終了することを保証
//   - 誤ったPIDを受信しました
//   - 受信データなし（タイムアウト）
//   - ボーレートの不一致
//   - 同期/データ処理中にカウンターがオーバーフロー
// すべてのコンテキストをリセットし、FIFOをフラッシュし、ブレーク検出のために再構成します。
// param[in] peripheral  LIN周辺機器インスタンスへのポインタ
// param[in] lin         LINコンテキスト構造体へのポインタ
static void LIN_Responder_resetState(LIN_Peripheral_t peripheral, Lin_TxRxCtx_t *lin)
{
    // ステートマシンをリセット
    lin->state          = LIN_STATE_WAIT_FOR_BREAK;
    lin->rxIdx          = 0;
    lin->txIdx          = 1;
    lin->chkSum.word    = 0;

    // タイミングコンテキストをリセット
    gLINT.brkW          = 0;
    gLINT.syncOkCnt     = 0;
    gLINT.syncErrCnt    = 0;
    gLINT.btSum         = 0;
    gLINT.syncStart     = true;

    // RX FIFOをフラッシュ
    while (!DL_UART_Extend_isRXFIFOEmpty(peripheral)){
        DL_UART_Extend_receiveData(peripheral);
    }

    // データ/同期割り込みをすべて無効
    DL_UART_Extend_disableInterrupt(peripheral, DL_UART_EXTEND_INTERRUPT_RX|DL_UART_INTERRUPT_FRAMING_ERROR);
    DL_UART_Extend_disableInterrupt(peripheral, DL_UART_EXTEND_INTERRUPT_TX);
    DL_UART_Extend_disableInterrupt(peripheral, DL_UART_EXTEND_INTERRUPT_RXD_NEG_EDGE);
    DL_UART_Extend_disableInterrupt(peripheral, DL_UART_EXTEND_INTERRUPT_RXD_POS_EDGE);
    DL_UART_Extend_disableInterrupt(peripheral, DL_UART_EXTEND_INTERRUPT_LIN_RISING_EDGE);

    // LINカウンタを再構成して、ブレーク検出を行う
    LIN_switchCounterToBreakMode(     peripheral);
    DL_UART_setLINCounterCompareValue(peripheral, gLINT.brkCmp);

    // ブレーク検出割り込みを再度有効
    DL_UART_Extend_clearInterruptStatus(peripheral, DL_UART_EXTEND_INTERRUPT_LIN_FALLING_EDGE);
    DL_UART_Extend_enableInterrupt(     peripheral, DL_UART_EXTEND_INTERRUPT_LIN_FALLING_EDGE);

    // タイムアウトタイマーを停止
    DL_Timer_stopCounter(TIMER_0_INST);
}

// フレームが正常に完了したら、ブレーク検出の準備
// 次のブレークフィールド検出のために、LINカウンタと割り込みを再構成
// param[in] peripheral  LIN周辺機器インスタンスへのポインタ
static void LIN_prepareForNextFrame(LIN_Peripheral_t peripheral)
{
    LIN_switchCounterToBreakMode(peripheral);
    DL_UART_setLINCounterCompareValue(peripheral, gLINT.brkCmp);
    DL_UART_Extend_clearInterruptStatus(peripheral, DL_UART_EXTEND_INTERRUPT_LIN_FALLING_EDGE);
    DL_UART_Extend_enableInterrupt(peripheral, DL_UART_EXTEND_INTERRUPT_LIN_FALLING_EDGE);
    DL_Timer_stopCounter(TIMER_0_INST);
}

// Protected Identifier (PID)受信処理
// メッセージテーブル内で一致するPIDを検索。見つかった場合は、受信または送信のために
// DATA_FIELD状態に遷移。見つからなかった場合は、正常に終了して次のブレークを待ちます。
// param[in] peripheral  LIN周辺機器インスタンスへのポインタ
// param[in] rxByte      受信したPID
// param[in] lin         LINコンテキスト構造体へのポインタ
void LIN_Responder_receivePID(LIN_Peripheral_t peripheral, uint8_t rxByte, Lin_TxRxCtx_t *lin, LIN_diag_t *lin_diag)
{
    uint8_t tableIndex;
    uint8_t ID = rxByte&LIN_PID_MASK;
    bool parity_ret = true;
    LIN_function_ptr_t  callbackFunction;   // 送信コールバック関数

    // 一致するPIDをメッセージテーブルで検索します
    for (tableIndex = 0; tableIndex < LIN_RESPONDER_NUM_MSGS; tableIndex++){
        if (lin->respMsgTbl[tableIndex].msgID == ID){//一致?
            lin->msgTblIdx = tableIndex;
            break;
        }
    }

    // 一致するPIDが見つからない - 正常に終了
    if (tableIndex == LIN_RESPONDER_NUM_MSGS||(parity_ret = lin_check_pid(rxByte,lin_diag))==false){//見つからない?
        LIN_Responder_resetState(peripheral, lin);
        return;
    }

    // 送受信選択
    if (lin->respMsgTbl[tableIndex].isMsgRecv != false){//受信用データ?
        // 受信モード
        lin->state = LIN_STATE_DATA_FIELD;
    }
    else {//コールバック無し

        // 送信モード
        lin->state = LIN_STATE_DATA_FIELD;

        // 受信割込禁止
        DL_UART_Extend_disableInterrupt(peripheral, DL_UART_EXTEND_INTERRUPT_RX|DL_UART_INTERRUPT_FRAMING_ERROR);
        delay_cycles(lin->timing->respDelay);

        // 有効なメッセージ受信した
        timer1_4s_clear();

        //送信データ取得
        callbackFunction = lin->respMsgTbl[tableIndex].callbackFunction;
        callbackFunction((void*)lin, tableIndex, false);

        // RX FIFOデータ読捨て
        while (!DL_UART_Extend_isRXFIFOEmpty(peripheral)){
            DL_UART_Extend_receiveData(peripheral);
        }

        // 送信データ1byte送信
        DL_UART_Extend_transmitData(peripheral, lin->txBuf[0]);

        // 送信割込クリア＆有効
        DL_UART_Extend_clearInterruptStatus(peripheral, DL_UART_EXTEND_INTERRUPT_TX);
        DL_UART_Extend_enableInterrupt(     peripheral, DL_UART_EXTEND_INTERRUPT_TX);

        // 受信タイマー停止
        DL_Timer_setTimerCount( TIMER_0_INST, TIMEOUT);
        DL_Timer_stopCounter(   TIMER_0_INST);
    }
}

/****************************************************************
*【関数名】lin_check_pid
*【説  明】PIDのパリティチェックを行う
*【引  数】rxByte            受信データ
*【戻り値】true:正常 false:異常
******************************************************************/
bool lin_check_pid(uint8_t pid, LIN_diag_t *lin_diag)
{
    uint8_t id = pid & 0x3F;      // ID6bit
    uint8_t p = pid >> 6;         // p0 = bit0, p1 = bit1
    bool    ret;

    // P0 = ID0 ^ ID1 ^ ID2 ^ ID4
    uint8_t calc_p0 = ((id >> 0) ^ (id >> 1) ^ (id >> 2) ^ (id >> 4)) & 1;
    // P1 = NOT (ID1 ^ ID3 ^ ID4 ^ ID5)
    uint8_t calc_p1 = (~((id >> 1) ^ (id >> 3) ^ (id >> 4) ^ (id >> 5))) & 1;

    ret = (p & 1) == calc_p0 && ((p >> 1) & 1) == calc_p1;

    if (ret==false){
#ifdef LIN_PARITY_ERROR_SET
        if (timer1_1500ms_is_passd!=false){//1500ms経過?
            lin_diag->error |= LIN_ERROR_IDENTIFIER_PARITY;
        }
#endif
    }

    return ret;
}

// データバイトを受信し、チェックサムを検証
// 受信したデータバイトを蓄積し、すべてのバイトを受信した後、拡張チェックサムを検証。
// 受信が成功すると、登録済みのコールバック関数を呼び出します。
// @param[in] peripheral  LIN周辺機器インスタンスへのポインタ
// @param[in] rxByte      Received data byte
// @param[in] lin         Pointer to LIN context structure
void LIN_Responder_receiveMessage(LIN_Peripheral_t peripheral, uint8_t rxByte, Lin_TxRxCtx_t *lin, LIN_diag_t *lin_diag)
{
    uint8_t             checksum;
    uint8_t             rxChecksum;
    LIN_function_ptr_t  callbackFunction;

    // 受信データバイト処理
    if (lin->rxIdx < lin->respMsgTbl[lin->msgTblIdx].msgSize){//メッセージ長以内の受信?
        lin->rxBuf[lin->rxIdx]  = rxByte;
        lin->chkSum.word        += lin->rxBuf[lin->rxIdx++];
        return;
    }

    // 受信チェックサム計算
    rxChecksum                  = rxByte;   //受信したチェックサムを格納
    DL_UART_Extend_disableInterrupt(peripheral, DL_UART_EXTEND_INTERRUPT_RX|DL_UART_INTERRUPT_FRAMING_ERROR);   // 受信割込停止

    // 拡張チェックサム計算（LIN 2.x）
    if (lin->respMsgTbl[lin->msgTblIdx].msgID != LINMSG_MASTERREQ_SID){//MC Sleep 特別仕様?
        // クラシックチェックサム計算（LIN 1.x）
        lin->chkSum.word += lin->respMsgTbl[lin->msgTblIdx].msgIDWithParity;
    }
    lin->chkSum.word  = lin->chkSum.byte[0] + lin->chkSum.byte[1];
    checksum          = lin->chkSum.byte[0];
    checksum         += lin->chkSum.byte[1];
    checksum          = 0xFF - checksum;

    // チェックサム比較
    if (rxChecksum == checksum){//一致した?

        // 有効なメッセージ受信
        timer1_4s_clear();

        // 受信コールバック関数取得、コール
        callbackFunction = lin->respMsgTbl[lin->msgTblIdx].callbackFunction;
        callbackFunction((void*)lin, lin->msgTblIdx, false);
    }
    else{//チェックサムエラー
        if (timer1_1500ms_is_passd()!=false){//1500ms経過?
            lin_diag->error     |= LIN_ERROR_CHECKSUM;
        }
    }

    // 次フレームに向けリセット
    lin->rxIdx          = 0;
    lin->chkSum.word    = 0;
    lin->state          = LIN_STATE_WAIT_FOR_BREAK;
    LIN_prepareForNextFrame(peripheral);
}

// データバイトとチェックサムを送信
// TXバッファからデータバイトを送信し、その後に拡張チェックサムを送信します。
// 送信完了後、TXコールバックを呼び出します。
// param[in] peripheral  LIN周辺機器インスタンスへのポインタ
// param[in] lin         LINコンテキスト構造体へのポインタ
void LIN_Responder_transmitMessage(LIN_Peripheral_t peripheral, Lin_TxRxCtx_t *lin, LIN_diag_t *lin_diag)
{
    bool isBeforOK = true;
    uint8_t checksum;
    LIN_function_ptr_t  callbackFunction;

    // 送信データがあるか確認
    if (lin->txIdx < lin->respMsgTbl[lin->msgTblIdx].msgSize){//送信データあり?

        // チェックサム計算用SUM
        lin->chkSum.word += lin->txBuf[lin->txIdx];

#if 0   // DEBUG 
        // １つ前の送信データをチェック
        if ((isBeforOK=LIN_Responder_transmitMessageBitCheck(peripheral, lin->txBuf[lin->txIdx-1], lin_diag))==false){
            goto LIN_Responder_transmitMessage_Error;
        }
#endif

        // データ送信
        DL_UART_Extend_transmitData(peripheral, lin->txBuf[lin->txIdx]);

        // インデックス更新
        lin->txIdx++;

        // 終了
        return;
    }

    // チェックサム送信
    if (lin->txIdx == lin->respMsgTbl[lin->msgTblIdx].msgSize){//送信メッセージ長送信?

        // チェックサム計算
        lin->chkSum.word = lin->chkSum.word  + lin->respMsgTbl[lin->msgTblIdx].msgIDWithParity + lin->txBuf[0];
        lin->chkSum.word = lin->chkSum.byte[0] + lin->chkSum.byte[1];
        checksum  = lin->chkSum.byte[0];
        checksum += lin->chkSum.byte[1];
        checksum  = 0xFF - checksum;

#if 0   // DEBUG 
        // １つ前の送信データをチェック
        if ((isBeforOK = LIN_Responder_transmitMessageBitCheck(peripheral, lin->txBuf[lin->txIdx-1], lin_diag))==false){
            goto LIN_Responder_transmitMessage_Error;
        }
#endif

        // チェックサム送信
        DL_UART_Extend_transmitData(peripheral, checksum);

        // チェックサム保存
        lin->sendChkSum = checksum;

        // Index加算
        lin->txIdx++;

        // 終了
        return;
    }

#if 1
    isBeforOK = true;
#else
    // 送信したチェックサムをチェック
    isBeforOK = LIN_Responder_transmitMessageBitCheck(peripheral, lin->sendChkSum, lin_diag);
#endif

    // チェックサム送信済み - 送信完了
    DL_UART_Extend_disableInterrupt(peripheral, DL_UART_EXTEND_INTERRUPT_TX);

LIN_Responder_transmitMessage_Error:;

    lin->txIdx          = 1;
    lin->chkSum.word    = 0;
    lin->sendChkSum     = 0;

    // RX FIFOデータ読捨て
    while (!DL_UART_Extend_isRXFIFOEmpty(peripheral)){
        DL_UART_Extend_receiveData(peripheral);
    }

    // ブレーク検出状態へ遷移
    lin->state = LIN_STATE_WAIT_FOR_BREAK;
    LIN_prepareForNextFrame(peripheral);

    // 送信完了処理へ
    if (isBeforOK==true){
        // 送信完了コールバック
        callbackFunction = lin->respMsgTbl[lin->msgTblIdx].callbackFunction;
        callbackFunction((void*)lin, lin->msgTblIdx, true);
    }
}

bool LIN_Responder_transmitMessageBitCheck(LIN_Peripheral_t peripheral, uint8_t checkData, LIN_diag_t *lin_diag)
{
    uint8_t sendedData;
    bool isOK = false;

    // １つ前の送信データをチェック
    if (DL_UART_Extend_isRXFIFOEmpty(peripheral) == false){
        sendedData = DL_UART_Extend_receiveData(peripheral);
        if (sendedData == checkData){//送信データと一致
            isOK = true;
        }
    }

    if (isOK==false){
        if (timer1_1500ms_is_passd()!=false){//1500ms経過?
            lin_diag->error     |= LIN_ERROR_BIT;
        }
    }

    return false;
}

// LIN UART 割り込みサービス処理
// LIN関連のすべての割込を処理
//   - Breakフィールド検出(falling edge)
//   - Breakフィールド検証(rising edge)
//   - Syncフィールド計測(negative/positive edges)
//   - データ送受信
void LIN_0_INST_IRQHandler(void)
{
    static uint8_t rxByte; // 受信データ
    bool    is_ir_cheching;

    // 割込要因分岐
    switch (DL_UART_Extend_getPendingInterrupt(LIN_0_INST)){
    case DL_UART_EXTEND_IIDX_LIN_FALLING_EDGE:  //----- Breakフィールド検出(falling edge) -----//
        if (gLIN.state != LIN_STATE_WAIT_FOR_BREAK){//ブレーク待ちでない?
            break;
        }
        // ブレーク開始状態へ
        gLIN.state = LIN_STATE_BREAK_FIELD;
        // rising edge検出設定
        DL_UART_enableLINRisingEdgeCapture(LIN_0_INST);
        // 受信データクリア
        while (!DL_UART_Extend_isRXFIFOEmpty(LIN_0_INST)){
            DL_UART_Extend_receiveData(LIN_0_INST);
        }
        // rising edge割込有効
        DL_UART_Extend_clearInterruptStatus(LIN_0_INST, DL_UART_EXTEND_INTERRUPT_LIN_RISING_EDGE);
        DL_UART_Extend_enableInterrupt(     LIN_0_INST, DL_UART_EXTEND_INTERRUPT_LIN_RISING_EDGE);
        break;

    case DL_UART_EXTEND_IIDX_LIN_RISING_EDGE:  //----- Breakフィールド検証(rising edge) -----//
        if (gLIN.state != LIN_STATE_BREAK_FIELD){// ブレーク開始状態でない?
            break;
        }
        // ブレーク長検証
        gLINT.brkW += DL_UART_Extend_getLINRisingEdgeCaptureValue(LIN_0_INST);
        if ((gLINT.brkW < (gLINT.btWidth * LIN_TBIT_BREAK_FIELD_MAX)) || (AUTO_BAUD_ENABLED)){//ブレークフィールドが20Tbit以内か、オートボーレート設定?

            // 有効なブレークフィールド - 同期フィールド測定の準備
            gLINT.brkW          = 0;
            gLINT.syncOkCnt     = 0;
            gLINT.syncErrCnt    = 0;
            gLINT.btSum         = 0;
            gLINT.syncStart     = true;

            // フォーリングエッジ無効
            DL_UART_Extend_disableInterrupt(    LIN_0_INST, DL_UART_EXTEND_INTERRUPT_LIN_FALLING_EDGE);

            // NEGエッジ有効
            DL_UART_Extend_clearInterruptStatus(LIN_0_INST, DL_UART_EXTEND_INTERRUPT_RXD_NEG_EDGE);
            DL_UART_Extend_enableInterrupt(     LIN_0_INST, DL_UART_EXTEND_INTERRUPT_RXD_NEG_EDGE);

            // RX有効
            DL_UART_Extend_clearInterruptStatus(LIN_0_INST, DL_UART_EXTEND_INTERRUPT_RX|DL_UART_INTERRUPT_FRAMING_ERROR);
            DL_UART_Extend_enableInterrupt(     LIN_0_INST, DL_UART_EXTEND_INTERRUPT_RX|DL_UART_INTERRUPT_FRAMING_ERROR);

            // Sync検出用に初期化
            LIN_switchCounterToSyncMode(LIN_0_INST);

            // Sync NEG検出へ
            gLIN.state = LIN_STATE_SYNC_FIELD_NEG_EDGE;
        }
        else {//ブレーク長エラーか、オートボーレートでない

            // FALLING EDGEは無効化されていない

            // 無効なブレークフィールド
            gLINT.brkW = 0;
            gLIN.state = LIN_STATE_WAIT_FOR_BREAK;  // ブレークフィールド検出状態へ
        }

        // Breakフィールド検証(rising edge)用の割込無効化
        DL_UART_Extend_disableInterrupt(LIN_0_INST, DL_UART_EXTEND_INTERRUPT_LIN_RISING_EDGE);
        break;

    case DL_UART_EXTEND_IIDX_LIN_COUNTER_OVERFLOW:  //----- カウンタオーバーフロー検出 ----- 一種のブレーク長タイムアウト処理
                                                    // Compare 値（LIN Counter Compare Value）に到達
        if (gLIN.state == LIN_STATE_BREAK_FIELD){//ブレーク検出状態?

            // オーバーフロー分加算
            gLINT.brkW += 65536;
            if (gLINT.brkW > (65536 * 2)){//異常なブレーク長?

                // ブレーク待ちに戻す
                gLINT.brkW = 0;
                gLIN.state = LIN_STATE_WAIT_FOR_BREAK;

                // Breakフィールド検証(rising edge)用の割込無効化
                DL_UART_Extend_disableInterrupt(LIN_0_INST, DL_UART_EXTEND_INTERRUPT_LIN_RISING_EDGE);
            }
        }
        else{// Sync/Data処理中にカウンタオーバーフローが発生
        
            // リセット終了
            LIN_Responder_resetState(LIN_0_INST, &gLIN);
        }
        break;

    case DL_UART_EXTEND_IIDX_RXD_NEG_EDGE:          //----- Syncフィールド計測(negative edges) -----
        if (gLIN.state != LIN_STATE_SYNC_FIELD_NEG_EDGE){//Sync Neg処理状態以外?
            break;
        }

        // Rise/Fallカウンタ値取得
        gLINT.syncBt[gLINT.syncOkCnt].posEdge = DL_UART_Extend_getLINRisingEdgeCaptureValue( LIN_0_INST);
        gLINT.syncBt[gLINT.syncOkCnt].negEdge = DL_UART_Extend_getLINFallingEdgeCaptureValue(LIN_0_INST);

        if ((gLINT.syncBt[gLINT.syncOkCnt].negEdge >> 1) > gLINT.btWMin &&  // (2Tbit)/2がMinより大きい　かつ
            (gLINT.syncBt[gLINT.syncOkCnt].negEdge >> 1) < gLINT.btWMax ){  // (2Tbit)/2がMax未満?

            gLINT.syncOkCnt++;                                      // Sync OK++
        }
        else if (!gLINT.syncStart){//Sync開始ではない?

            // エラー
            gLINT.syncErrCnt++;                                     // Sync Err++
            gLINT.btSum += gLINT.syncBt[gLINT.syncOkCnt].negEdge;   // 2TBit SUM計算
        }
        else{//初回は無視(2Tbit時間経過前なので)
            gLINT.syncStart = false;    // Sync開始ではない
        }

        // Sync4回計測完了0x55  Break(00...0)-BreakID(1)-| StartBit(0)-1 | 0-1 | 0-1 | 0-1| 0-Stop(1) '|'がNEG
        if ((gLINT.syncErrCnt + gLINT.syncOkCnt) == LIN_RESPONDER_SYNC_CYCLES){// 計測が4回され、SyncErr + SyncOK ==4回になった?

            // NEG割込無効
            DL_UART_Extend_disableInterrupt(LIN_0_INST,     DL_UART_EXTEND_INTERRUPT_RXD_NEG_EDGE);
            // POS割込クリア・有効
            DL_UART_Extend_clearInterruptStatus(LIN_0_INST, DL_UART_EXTEND_INTERRUPT_RXD_POS_EDGE);
            DL_UART_Extend_enableInterrupt(LIN_0_INST,      DL_UART_EXTEND_INTERRUPT_RXD_POS_EDGE);

            if (gLINT.syncOkCnt == LIN_RESPONDER_SYNC_CYCLES){//Sync OK 4回?

                gLINT.brPrev    = gLINT.brCurr;                 // 現在のビットレート保存
                gLINT.autoBaud  = false;                        // 自動ビットレート無効
            }

            // POS検出状態へ
            gLIN.state = LIN_STATE_SYNC_FIELD_POS_EDGE;
        }
        else if ((gLINT.syncErrCnt == AUTO_BAUD_THRESHOLD) && AUTO_BAUD_ENABLED){//計測が3回され、Syncエラー==3回かつ自動ボーレート調整有効?

            //
            // 自動ボーレート再調整がトリガー
            //

            // 新しいクロック数計算
            gLINT.btAvg     = (gLINT.btSum   >> 1) / gLINT.syncErrCnt;      // 1Tbitの平均産出(SUMは2TBitx3回)
            gLINT.brMeas    = LIN_0_INST_FREQUENCY / gLINT.btAvg;           // クロック数に変換

            // UART停止
            DL_UART_Extend_disable(     LIN_0_INST);            // UART停止
            delay_cycles(AUTO_BAUD_CONFIG_DELAY);               // UART停止待ち
            DL_UART_Extend_disableFIFOs(LIN_0_INST);            // FIFO無効

            // ボーレート関連値を更新
            gLINT.respDelay = LIN_0_INST_FREQUENCY / (2 * gLINT.brMeas);
            gLINT.btWidth   = gLINT.btAvg;
            gLINT.btWMin    = (uint16_t)(gLINT.btWidth * LIN_AUTO_BAUD_MIN / 100);
            gLINT.btWMax    = (uint16_t)(gLINT.btWidth * LIN_AUTO_BAUD_MAX / 100);
            gLINT.brkCmp    = (uint16_t)(gLINT.btWidth * LIN_0_TBIT_COUNTER_COEFFICIENT);

            // UARTへボーレート設定
            DL_UART_Extend_configBaudRate(LIN_0_INST, LIN_0_INST_FREQUENCY, gLINT.brMeas);
            DL_UART_Extend_enable(LIN_0_INST);                  // UART再開

            gLINT.brPrev    = gLINT.brCurr;                     // 現在のビットレート保存
            gLINT.brCurr    = gLINT.brMeas;                     // 現在のビットレート更新
            gLINT.autoBaud  = true;                             // 自動ボーレート完了

            // この後4回目のSyncが検出されれば、上の処理でPosEdgeになる。
        }
        break;

    case DL_UART_EXTEND_IIDX_RXD_POS_EDGE:          //----- Syncフィールド計測(positive edges) -----　NEGでSync4回検出後に有効にされる
                                                    // Break(00...0)-BreakID(1)-| StartBit(0)-1 | 0-1 | 0-1 | 0-1| 0-^Stop(1) '|'がNEG '^'がPOSエッジ
        if (gLIN.state != LIN_STATE_SYNC_FIELD_POS_EDGE){//POSエッジ検出状態ではない?
            break;
        }

        if ((gLINT.brCurr > gLINT.brPrev) && DL_UART_getErrorStatus(LIN_0_INST, DL_UART_ERROR_OVERRUN)){//現在ボーレート>前回ボーレートかつオーバーRUN発生?
            // LINカウンタをクリア
            DL_UART_Extend_disableLINCounter(LIN_0_INST);   // LIN Counter無効
            DL_UART_Extend_enableLINCounter( LIN_0_INST);   // LIN Counter有効
        }
        else if (gLINT.brCurr < gLINT.brPrev){//前回よりビットレートが小さい?
            // 受信読捨て
            DL_UART_Extend_receiveData(     LIN_0_INST);
        }

        // LINをブレーク用に設定(受信中に中断して、Breakが来たらBreakを検出するため。LINCounterを見れるようにする。ただしTIMOUTもしないとBreak状態遷移されない)
        LIN_switchCounterToBreakMode(       LIN_0_INST);
        DL_UART_setLINCounterCompareValue(  LIN_0_INST, gLINT.brkCmp);

        // LIN FALLエッジ有効(Break用)
        DL_UART_Extend_clearInterruptStatus(LIN_0_INST, DL_UART_EXTEND_INTERRUPT_LIN_FALLING_EDGE);
        DL_UART_Extend_enableInterrupt(     LIN_0_INST, DL_UART_EXTEND_INTERRUPT_LIN_FALLING_EDGE);
        // LIN POSエッジ無効
        DL_UART_Extend_disableInterrupt(    LIN_0_INST, DL_UART_EXTEND_INTERRUPT_RXD_POS_EDGE);

        DL_Timer_setLoadValue( TIMER_0_INST, TIMEOUT);  // タイムアウトロード値設定
        DL_Timer_setTimerCount(TIMER_0_INST, TIMEOUT);  // タイムアウトカウンタを即時更新反映
        DL_Timer_startCounter( TIMER_0_INST);           // タイムアウトタイマー開始
        break;

    case DL_UART_EXTEND_IIDX_RX:                    //----- RX処理 -----

        // 割込機能チェック
        is_ir_cheching = intr_check_ir_process(INTR_CHECK_UART0_ID);
        if (is_ir_cheching==true){//割込チェック中ではない?
            break;
        }

        // データ受信
        rxByte = DL_UART_Extend_receiveData(LIN_0_INST);

        // TimeOut更新
        DL_Timer_setTimerCount(TIMER_0_INST, TIMEOUT);

        if (gLIN.state == LIN_STATE_SYNC_FIELD_POS_EDGE){//POS Edge状態で受信?

            gLIN.state = LIN_STATE_PID_FIELD;               //PID取得状態へ
        }
        else if (gLIN.state == LIN_STATE_SYNC_FIELD_NEG_EDGE){//NEG Edge状態で受信できた?

            if (!AUTO_BAUD_ENABLED){//自動ボーレート有効でない?　 = Sync4回の検出中ができていないので、NEGで来ている。
                                    //がSyncを受信できていると思われる。POS Edge同党の処理をする。

                // Break検出可能にセット(POS EDGEと同様の処理をして、受信途中切れからのBreakを検出できるようにする)
                LIN_switchCounterToBreakMode(       LIN_0_INST);
                DL_UART_setLINCounterCompareValue(  LIN_0_INST, gLINT.brkCmp);
                DL_UART_Extend_clearInterruptStatus(LIN_0_INST, DL_UART_EXTEND_INTERRUPT_LIN_FALLING_EDGE);
                DL_UART_Extend_enableInterrupt(     LIN_0_INST, DL_UART_EXTEND_INTERRUPT_LIN_FALLING_EDGE);
                DL_UART_Extend_disableInterrupt(    LIN_0_INST, DL_UART_EXTEND_INTERRUPT_RXD_NEG_EDGE);

                gLIN.state = LIN_STATE_PID_FIELD;            //PID取得状態へ
            }
        }
        else if (gLIN.state == LIN_STATE_PID_FIELD){//PID取得状態?

            // PID受信処理
            LIN_Responder_receivePID(LIN_0_INST, rxByte, &gLIN, &gLINDiag);
        }
        else if (gLIN.state == LIN_STATE_DATA_FIELD){//受信状態?

            // データ受信処理
            LIN_Responder_receiveMessage(LIN_0_INST, rxByte, &gLIN, &gLINDiag);
        }
        break;

    case DL_UART_EXTEND_IIDX_TX:                    //----- Tx処理 -----

        // データ送信処理
        LIN_Responder_transmitMessage(LIN_0_INST, &gLIN, &gLINDiag);
        break;

    case DL_UART_EXTEND_IIDX_FRAMING_ERROR:         //---- Framing Error -----
        if (gLIN.state == LIN_STATE_PID_FIELD || gLIN.state == LIN_STATE_DATA_FIELD){

            if (timer1_1500ms_is_passd()!=false){//1500ms経過?
                gLINDiag.error |= LIN_ERROR_FRAME;
            }

            // リセット
            LIN_Responder_resetState(LIN_0_INST, &gLIN);
        }
        break;

    default:
        break;
    }
}

/****************************************************************
*【関数名】lin_reset_response_error
*【説  明】LIN ERROR リセット
*【引  数】なし
*【戻り値】なし
******************************************************************/
void lin_reset_response_error(void)
{
    gLINDiag.error = 0;
}
/****************************************************************
*【関数名】lin_get_response_error
*【説  明】LIN ERROR取得
*【引  数】なし
*【戻り値】uint8_t
******************************************************************/
uint8_t lin_get_response_error(void)
{
    return gLINDiag.error;
}
/****************************************************************
*【関数名】lin_timer0_1p5ms_Handler
*【説  明】タイマータイムアウト割込ハンドラ
* フレームタイムアウトを処理 - 想定された期間内にデータが受信されない場合はステートマシンをリセット
*【引  数】なし
*【戻り値】なし
******************************************************************/
#if 1
void lin_timer0_1p5ms_Handler(void)
{
    // タイムアウト発生 - いずれの状態からも正常に復帰
    if (gLIN.state != LIN_STATE_WAIT_FOR_BREAK){//ブレーク待ちでない?

        // LINをリセット
        LIN_Responder_resetState(LIN_0_INST, &gLIN);
    }
}
#else
//void TIMER_0_INST_IRQHandler(void)
{
    switch (DL_Timer_getPendingInterrupt(TIMER_0_INST)){
    case DL_TIMER_IIDX_ZERO:

        // タイムアウト発生 - いずれの状態からも正常に復帰
        if (gLIN.state != LIN_STATE_WAIT_FOR_BREAK){//ブレーク待ちでない?

            // LINをリセット
            LIN_Responder_resetState(LIN_0_INST, &gLIN);
        }
        break;

    default:
        break;
    }
}
#endif

/* EOF */
