2025-04-11 10:46:09 +08:00

558 lines
17 KiB
C

/*******************************************************************************
* the includes
******************************************************************************/
#include "LIN_Master.h"
/*******************************************************************************
* the defines
******************************************************************************/
/* the LIN baud rate */
#define LIN_BAUD_RATE (19200u)
/* one lin frame data size */
#define LIN_DATA_SIZE (8u)
/* lin frame sync header */
#define LIN_SYNC_HEADER (0x55)
/* the client requests ID */
#define LIN_ID_DIAG_MASTER_REQ (0x3C)
/* the server response ID */
#define LIN_ID_DIAG_SLAVE_RESP (0x3D)
#define LIN_FRAME_NUM (5u)
/* add parity for frame id */
#define MAKE_PARITY (0u)
/* check parity for frame pid */
#define CHECK_PARITY (1u)
#define GETBIT(A,B) ((A >> B) & 0x01) //get bit B in A
#define TIMER_UNIT_US (1000u)
/*******************************************************************************
* the typedefs
******************************************************************************/
typedef enum {
LIN_STATE_IDLE = 0u,
LIN_STATE_BREAK,
LIN_STATE_SYNC_HEDADER,
LIN_STATE_PID,
LIN_STATE_TX_DATA,
LIN_STATE_RX_DATA,
LIN_STATE_CHECKSUM
}Lin_StateType;
typedef enum {
LINSTACK_CHECKSUM_CLASSIC = 0,
LINSTACK_CHECKSUM_ENHANCED,
LINSTACK_CHECKSUM_NUM
}Lin_CheckSumType;
typedef enum
{
LIN_RES_PUB = 0x00U, /*!< Publisher response */
LIN_RES_SUB = 0x01U /*!< Subscriber response */
} lin_ResponseType;
typedef enum
{
LIN_FRM_UNCD = 0x00U, /*!< Unconditional frame */
LIN_FRM_EVNT = 0x01U, /*!< Event triggered frame */
LIN_FRM_SPRDC = 0x10U, /*!< Sporadic frame */
LIN_FRM_DIAG = 0x11U /*!< Diagnostic frame */
} lin_FrameType;
typedef struct {
uint8_t data[LIN_DATA_SIZE];
uint8_t checkSum;
}Lin_FrameDataType;
typedef struct {
uint8_t frameId; /*!< frame identifier */
lin_FrameType frameType; /*!< frame type */
uint8_t frameLen; /*!< frame data length */
lin_ResponseType resType; /*!< response type */
uint8_t *pFrameData; /*!< frame data buffer point */
uint8_t updatingFlag; /*!< frame data updating flag */
}Lin_FrameInfoType;
/*******************************************************************************
* the globals
******************************************************************************/
extern McuType mcu;
static Lin_FrameDataType linTxData;
static Lin_FrameDataType linRxData;
static uint8_t linTxDataCnt = 0;
static uint8_t linRxDataCnt = 0;
static uint8_t linFrameData[LIN_FRAME_NUM][LIN_DATA_SIZE];
static uint8_t linFrameDataBackup[LIN_DATA_SIZE];
static Lin_FrameInfoType linFrameInfoTab[LIN_FRAME_NUM] = {
{0x10, LIN_FRM_UNCD, 4, LIN_RES_PUB, &linFrameData[0][0], 0x00},
{0x20, LIN_FRM_UNCD, 8, LIN_RES_SUB, &linFrameData[1][0], 0x00},
{0x21, LIN_FRM_UNCD, 8, LIN_RES_SUB, &linFrameData[2][0], 0x00},
{0x30, LIN_FRM_UNCD, 8, LIN_RES_SUB, &linFrameData[3][0], 0x00},
{0x31, LIN_FRM_UNCD, 8, LIN_RES_SUB, &linFrameData[4][0], 0x00},
};
uint8_t gCurFrameIdx = 0;
Lin_StateType linState = LIN_STATE_IDLE;
/* time stamp variable unit 1ms */
volatile uint32_t gTime1msCnt = 0;
/* the timeout counter of lin communication */
volatile uint32_t linComTimeoutCnt = 0;
uint32_t linMaxHeaderTimeout = 0;
uint32_t linMaxFrameResTimeout = 0;
/*******************************************************************************
* the const
******************************************************************************/
/*******************************************************************************
* the functions
******************************************************************************/
/*! \brief Computes maximum header timeout
*
* Theader_Maximum = 1.4 * THeader_Nominal, THeader_Nominal = 34 * TBit,
* (13 nominal bits of break; 1 nominal bit of break delimiter; 10 bits for SYNC and 10 bits of PID)
* TIMER_UNIT_US is in micro second
*
* \param[in] baudRate LIN network baud rate
*
* \return maximum timeout for the selected baud rate
*
* Implements : lin_calc_max_header_timeout_cnt_Activity
*/
static uint32_t Lin_CalcMaxHeaderTimeoutCnt(uint32_t baudRate)
{
return ((14U * 34U * 100000U / (TIMER_UNIT_US * baudRate)) + 1U);
}
/*! \brief Computes the maximum response timeout
*
* TResponse_Maximum = 1.4 * TResponse_Nominal, TResponse_Nominal = 10 * (NData+ 1) * TBit
*
* \param[in] baudRate LIN network baud rate
* size frame size in bytes
*
* \return maximum response timeout for the given baud rate and frame size
*
* Implements : lin_calc_max_res_timeout_cnt_Activity
*/
static uint32_t Lin_CalcMaxResTimeoutCnt(uint32_t baudRate, uint8_t size)
{
uint32_t bitNum = 14U * (1U + size);
return ((bitNum * 1000000U / (TIMER_UNIT_US * baudRate)) + 1U);
}
/*! \brief The lin PID parity.
* \param[in] PID:Pid or Id
* typeAction:
* 0 : make parity
* 1 : check parity
* \return none
*/
uint8_t Lin_PidParity(uint8_t PID, uint8_t typeAction)
{
uint8_t parity;
uint8_t retVal;
parity = (uint8_t)(((0xFFU & (GETBIT(PID, 0U) ^ GETBIT(PID, 1U) ^ GETBIT(PID, 2U) ^ GETBIT(PID, 4U))) << 6U) |
((0xFFU ^ (GETBIT(PID, 1U) ^ GETBIT(PID, 3U) ^ GETBIT(PID, 4U) ^ GETBIT(PID, 5U))) << 7U));
/* Check if action is checking parity bits */
if (CHECK_PARITY == typeAction)
{
/* If parity bits are incorrect */
if ((PID & 0xC0U) != parity)
{
/* Return 0xFF if parity bits are incorrect */
retVal = 0xFFU;
}
/* If parity bits are correct */
else
{
/* Return ID if parity bits are correct */
retVal = (uint8_t)(PID & 0x3FU);
}
}
/* If action is making parity bits */
else
{
/* Return PID in case of making parity bits */
retVal = (uint8_t)(PID | parity);
}
return retVal;
}
/*! \brief get lin frame index.
* \param[in] frameId: lin frame identifier
* \return frame index
*/
uint8_t Lin_GetFrameIndex(uint8_t frameId)
{
uint8_t i = 0;
uint8_t retVal = 0xFF;
for(i = 0; i < LIN_FRAME_NUM; i++)
{
if(frameId == linFrameInfoTab[i].frameId)
{
retVal = i;
break;
}
}
return retVal;
}
/*! \brief The lin data checksum function.
* \param[in] CheckSumType:
* 0: standard checksum
* 1: enhanced checksum
* pid: frame pid
* pData: pointer to the data of Lin_FrameType
* dataLen: data length
* \return none
*/
uint8_t Lin_CalculateChecksum(Lin_CheckSumType checkSumType, const uint8_t frameId, const uint8_t* pData, uint8_t dataLen)
{
uint16_t tCheckSum = 0;
uint8_t i = 0;
if ((checkSumType == LINSTACK_CHECKSUM_ENHANCED) && \
(frameId != LIN_ID_DIAG_MASTER_REQ) && (frameId != LIN_ID_DIAG_SLAVE_RESP))
{
tCheckSum = Lin_PidParity(frameId, MAKE_PARITY);
}
for (i = 0; i < dataLen; i++)
{
tCheckSum += pData[i];
tCheckSum = tCheckSum > 0xFF ? ((tCheckSum + 1) & 0x00FF) : tCheckSum;
}
tCheckSum = ~tCheckSum;
return (uint8_t)(tCheckSum & 0xFF);
}
/*! \brief set lin response data.
* \param[in] pFrameInfoFromTab: point to the data will be send
* pFrame: point to send structure
* \return none
*/
void lin_SetResponse(Lin_FrameInfoType *pFrameInfoFromTab, Lin_FrameDataType *pFrame)
{
uint8_t i = 0;
for(i = 0; i < pFrameInfoFromTab->frameLen; i++)
{
if(0 != (pFrameInfoFromTab->updatingFlag & (1 << i)))
{
pFrame->data[i] = linFrameDataBackup[i];
}
else
{
pFrame->data[i] = pFrameInfoFromTab->pFrameData[i];
}
}
pFrame->checkSum = Lin_CalculateChecksum(LINSTACK_CHECKSUM_ENHANCED, pFrameInfoFromTab->frameId, &pFrame->data[0], pFrameInfoFromTab->frameLen);
}
/*! \brief The uart0 for lin send request function.
* \param[in] none
* \return none
*/
void LinMastertxIsrRequest(void)
{
if (linState == LIN_STATE_IDLE)
{
UartDrv_SetInterruptReq(&mcu.uartDrv0, UARTDRV_ISR_SRC_TX_SYNC_BREAK, true);
linComTimeoutCnt = linMaxHeaderTimeout + linMaxFrameResTimeout;
linState = LIN_STATE_BREAK;
UartDrv_SendLinBreakField(&mcu.uartDrv0);
}
}
/*! \brief The uart0 for lin send interrupt handling function.
* \param[in] none
* \return none
*/
void LinMasterTxIsrRoutine(void)
{
if (UartDrv_GetStatus(&mcu.uartDrv0, UARTDRV_STATUS_SBRKD))
{
/* The break signal has been transmitted successfully */
UartDrv_ClearStatus(&mcu.uartDrv0, UARTDRV_STATUS_SBRKD);
linTxDataCnt = 0;
/* send the sync-header(0x55) */
linState = LIN_STATE_SYNC_HEDADER;
UartDrv_TxData(&mcu.uartDrv0, LIN_SYNC_HEADER);
}
}
/*! \brief The uart0 for lin receive interrupt handling function.
* \param[in] none
* \return none
*/
void LinMasterRxIsrRoutine(void)
{
uint8_t i = 0;
uint8_t rcvData = 0;
uint8_t rcvCheckSum = 0;
uint8_t clcCheckSum = 0;
uint8_t pid = 0;
uint8_t frameId = 0;
uint8_t txFreeCnt = 0;
uint8_t rxCnt = 0;
if (UartDrv_GetStatus(&mcu.uartDrv0, UARTDRV_STATUS_RDRF))
{
if (UartDrv_IsInterruptEnabled(&mcu.uartDrv0, UARTDRV_ISR_SRC_RX_FULL) == true)
{
switch(linState)
{
case LIN_STATE_SYNC_HEDADER: /* wait to receive lin sync header */
rcvData = (uint8_t)(UartDrv_RxData(&mcu.uartDrv0) & 0xFF);
/* Check the sync header */
if (rcvData == LIN_SYNC_HEADER)
{
pid = Lin_PidParity(linFrameInfoTab[gCurFrameIdx].frameId, MAKE_PARITY);
UartDrv_TxData(&mcu.uartDrv0, pid);
linState = LIN_STATE_PID;
}
else
{
linState = LIN_STATE_IDLE;
}
break;
case LIN_STATE_PID: /* wait to receive lin pid */
rcvData = (uint8_t)(UartDrv_RxData(&mcu.uartDrv0) & 0xFF);
frameId = Lin_PidParity(rcvData, CHECK_PARITY);
if(frameId != linFrameInfoTab[gCurFrameIdx].frameId)
{
linState = LIN_STATE_IDLE;
break;
}
if(LIN_RES_PUB == linFrameInfoTab[gCurFrameIdx].resType)
{
lin_SetResponse(&linFrameInfoTab[gCurFrameIdx], &linTxData);
linState = LIN_STATE_TX_DATA;
linTxDataCnt = 0;
txFreeCnt = 4u - UartDrv_GetTxCounter(&mcu.uartDrv0);
for(i = 0; i < txFreeCnt; i++)
{
UartDrv_TxData(&mcu.uartDrv0, linTxData.data[linTxDataCnt]);
linTxDataCnt++;
if(linTxDataCnt >= linFrameInfoTab[gCurFrameIdx].frameLen && (linTxDataCnt < 4))
{
UartDrv_TxData(&mcu.uartDrv0, linTxData.checkSum);
linState = LIN_STATE_CHECKSUM;
break;
}
}
}
else if(LIN_RES_SUB == linFrameInfoTab[gCurFrameIdx].resType)
{
linRxDataCnt = 0;
linState = LIN_STATE_RX_DATA;
}
else
{
linState = LIN_STATE_IDLE;
}
break;
case LIN_STATE_TX_DATA:
rxCnt = UartDrv_GetRxCounter(&mcu.uartDrv0);
for(i = 0; i < rxCnt; i++)
{
(uint8_t)(UartDrv_RxData(&mcu.uartDrv0) & 0xFF);
}
txFreeCnt = 4u - UartDrv_GetTxCounter(&mcu.uartDrv0);
for(i = 0; i < txFreeCnt; i++)
{
if(linTxDataCnt >= linFrameInfoTab[gCurFrameIdx].frameLen)
{
UartDrv_TxData(&mcu.uartDrv0, linTxData.checkSum);
linState = LIN_STATE_CHECKSUM;
break;
}
else
{
UartDrv_TxData(&mcu.uartDrv0, linTxData.data[linTxDataCnt]);
linTxDataCnt++;
}
}
break;
case LIN_STATE_RX_DATA:
rxCnt = UartDrv_GetRxCounter(&mcu.uartDrv0);
for(i = 0; i < rxCnt; i++)
{
rcvData = (uint8_t)(UartDrv_RxData(&mcu.uartDrv0) & 0xFF);
linRxData.data[linRxDataCnt] = rcvData;
linRxDataCnt++;
if(linRxDataCnt >= linFrameInfoTab[gCurFrameIdx].frameLen)
{
linState = LIN_STATE_CHECKSUM;
break;
}
}
break;
case LIN_STATE_CHECKSUM: /* wait to receive lin checksum */
rcvCheckSum = (uint8_t)(UartDrv_RxData(&mcu.uartDrv0) & 0xFF);
if(LIN_RES_SUB == linFrameInfoTab[gCurFrameIdx].resType)
{
clcCheckSum = Lin_CalculateChecksum(LINSTACK_CHECKSUM_ENHANCED, linFrameInfoTab[gCurFrameIdx].frameId, &linRxData.data[0], linRxDataCnt);
if (clcCheckSum == rcvCheckSum)
{
memcpy(linFrameInfoTab[gCurFrameIdx].pFrameData, &linRxData.data[0], linRxDataCnt);
}
}
linState = LIN_STATE_IDLE;
break;
default:
UartDrv_ClearRxFifo(&mcu.uartDrv0);
break;
}
}
}
if(linState == LIN_STATE_IDLE)
{
UartDrv_EnableLineBreakDetect(&mcu.uartDrv0, true);
}
}
/*! \brief This is a part of SysTick Interrupt Handler for lin timeout check.
* \param[in] none
* \return none
*/
void Lin_TimeoutService(void)
{
switch(linState)
{
case LIN_STATE_BREAK:
case LIN_STATE_SYNC_HEDADER:
case LIN_STATE_PID:
case LIN_STATE_TX_DATA:
case LIN_STATE_RX_DATA:
case LIN_STATE_CHECKSUM:
linComTimeoutCnt--;
if(0 == linComTimeoutCnt)
{
linState = LIN_STATE_IDLE;
UartDrv_EnableLineBreakDetect(&mcu.uartDrv0, true);
linComTimeoutCnt = linMaxFrameResTimeout;
}
break;
default:
break;
}
}
/*! \brief The uart0 lin master init function.
* \param[in] none
* \return none
*/
void Uart0_LinMaster_Init(void)
{
UartDrv_InitCfgType uartInitCfg;
/* PORT and pins as ALT4 (UART tx rx) */
PinsDrv_SetMuxModeSel(&mcu.ptc, 2, PINSDRV_MUX_ALT4); /* Uart rx */
PinsDrv_SetMuxModeSel(&mcu.ptc, 3, PINSDRV_MUX_ALT4); /* Uart tx */
PinsDrv_SetMuxModeSel(&mcu.ptc, 13, PINSDRV_MUX_AS_GPIO); /* LIN module control */
PinsDrv_SetPinDirection(&mcu.ptc, 13, 1); /* set to output */
PinsDrv_WritePin(&mcu.ptc, 13, 1); /* set to high to active lin transceiver */
/* Configure uart module */
UartDrv_GetDefaultConfig(&uartInitCfg);
uartInitCfg.basicParameters.baudRate = LIN_BAUD_RATE;
uartInitCfg.extendFeatures.cosplayer = UARTDRV_COSPLAY_LIN;
ClockDrv_GetFreq(&mcu.clockDrv, CLOCKDRV_UART0, &uartInitCfg.basicParameters.busClockFreq);
/* Set the configuration */
UartDrv_SetConfig(&mcu.uartDrv0, &uartInitCfg);
UartDrv_SetRxWater(&mcu.uartDrv0, 0);
UartDrv_SetRxWater(&mcu.uartDrv0, 0);
UartDrv_SetInterruptReq(&mcu.uartDrv0, UARTDRV_ISR_SRC_TX_SYNC_BREAK, true);
UartDrv_SetInterruptReq(&mcu.uartDrv0, UARTDRV_ISR_SRC_RX_FULL, true);
/* Enable all the uart0 interrupts in the NVIC interrupt controller */
IrqDrv_EnableIrq(UART0_RxTx_IRQn);
linMaxHeaderTimeout = Lin_CalcMaxHeaderTimeoutCnt(LIN_BAUD_RATE);
linMaxFrameResTimeout = Lin_CalcMaxResTimeoutCnt(LIN_BAUD_RATE, 8);
linComTimeoutCnt = linMaxHeaderTimeout + linMaxFrameResTimeout;
linState = LIN_STATE_IDLE;
}
void LIN_UpdateTxData(uint8_t frameid,uint8_t dataid,uint8_t data)
{
linFrameDataBackup[dataid] = linFrameInfoTab[frameid].pFrameData[dataid];
linFrameInfoTab[frameid].updatingFlag |= (0x01 << dataid);
linFrameInfoTab[frameid].pFrameData[dataid] = data;
linFrameInfoTab[frameid].updatingFlag &= ~(0x01 << dataid);
}
void LIN_Master_task(void)
{
//LIN_UpdateTxData()
/* request send LIN data */
LinMastertxIsrRequest();
/*
gCurFrameIdx++;
if(gCurFrameIdx >= LIN_FRAME_NUM)
{
gCurFrameIdx = 0;
}
*/
}
/*! \brief The uart0 interrupt handling function.
* \param[in] none
* \return none
*/
void UART0_RxTx_Handler(void)
{
LinMasterTxIsrRoutine();
LinMasterRxIsrRoutine();
}