558 lines
17 KiB
C
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();
|
|
}
|
|
|