843 lines
25 KiB
C
843 lines
25 KiB
C
/*
|
|
* Copyright (c) 2022, Shenzhen CVA Innovation CO.,LTD
|
|
* All rights reserved.
|
|
*
|
|
* Shenzhen CVA Innovation CO.,LTD (CVA chip) is supplying this file for use
|
|
* exclusively with CVA's microcontroller products. This file can be freely
|
|
* distributed within development tools that are supporting such microcontroller
|
|
* products.
|
|
*
|
|
* THIS SOFTWARE IS PROVIDED "AS IS". NO WARRANTIES, WHETHER EXPRESS, IMPLIED
|
|
* OR STATUTORY, INCLUDING, BUT NOT LIMITED TO, IMPLIED WARRANTIES OF
|
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE APPLY TO THIS SOFTWARE.
|
|
* CVA SHALL NOT, IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL,
|
|
* OR CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.
|
|
*/
|
|
|
|
/*******************************************************************************
|
|
* the includes
|
|
******************************************************************************/
|
|
|
|
#include <stdint.h>
|
|
#include <stddef.h>
|
|
#include "isotp.h"
|
|
|
|
/*******************************************************************************
|
|
* the defines
|
|
******************************************************************************/
|
|
|
|
/*! \brief Protocol Control Information (PCI) types, for identifying each frame of an ISO-TP message.
|
|
*/
|
|
#define ISOTP_PCI_TYPE_SINGLE_FRAME (0x0)
|
|
#define ISOTP_PCI_TYPE_FIRST_FRAME (0x1)
|
|
#define ISOTP_PCI_TYPE_CONSECUTIVE_FRAME (0x2)
|
|
#define ISOTP_PCI_TYPE_FLOW_CONTROL_FRAME (0x3)
|
|
|
|
/*! \brief Protocol Control Information (PCI) flow control identifiers.
|
|
*/
|
|
#define ISOTP_PCI_FLOW_STATUS_CONTINUE (0x0)
|
|
#define ISOTP_PCI_FLOW_STATUS_WAIT (0x1)
|
|
#define ISOTP_PCI_FLOW_STATUS_OVERFLOW (0x2)
|
|
|
|
/* invalid bs */
|
|
#define ISOTP_INVALID_BS 0xFFFF
|
|
|
|
/*! \brief Network layer result code
|
|
*/
|
|
#define ISOTP_PROTOCOL_RESULT_OK (0)
|
|
#define ISOTP_PROTOCOL_RESULT_TIMEOUT_A (-1)
|
|
#define ISOTP_PROTOCOL_RESULT_TIMEOUT_BS (-2)
|
|
#define ISOTP_PROTOCOL_RESULT_TIMEOUT_CR (-3)
|
|
#define ISOTP_PROTOCOL_RESULT_WRONG_SN (-4)
|
|
#define ISOTP_PROTOCOL_RESULT_INVALID_FS (-5)
|
|
#define ISOTP_PROTOCOL_RESULT_UNEXP_PDU (-6)
|
|
#define ISOTP_PROTOCOL_RESULT_WFT_OVRN (-7)
|
|
#define ISOTP_PROTOCOL_RESULT_BUFFER_OVFLW (-8)
|
|
#define ISOTP_PROTOCOL_RESULT_ERROR (-9)
|
|
|
|
/*! \brief Return logic true if 'a' is after 'b'
|
|
*/
|
|
#define IsoTp_TimeAfter(a, b) ((int64_t)((int64_t)(b) - (int64_t)(a)) < 0)
|
|
|
|
#define IsoTp_SetPciType(byte, type) (byte[0] = (0xFF & ((((uint8_t)type) << 4) | 0x0f)))
|
|
#define IsoTp_GetPciType(byte) ((uint8_t)(byte[0] >> 4))
|
|
|
|
/*! \brief single frame
|
|
* +-------------------------+-----+
|
|
* | byte #0 | ... |
|
|
* +-------------------------+-----+
|
|
* | nibble #0 | nibble #1 | ... |
|
|
* +-------------+-----------+ ... +
|
|
* | PCIType = 0 | SF_DL | ... |
|
|
* +-------------+-----------+-----+
|
|
*/
|
|
#define IsoTp_SetSFDataLen(byte, len) (byte[0] &= (((uint8_t)len) | 0xf0))
|
|
#define IsoTp_GetSFDataLen(byte) (byte[0] & 0x0f)
|
|
|
|
/*! \brief first frame
|
|
* +-------------------------+-----------------------+-----+
|
|
* | byte #0 | byte #1 | ... |
|
|
* +-------------------------+-----------+-----------+-----+
|
|
* | nibble #0 | nibble #1 | nibble #2 | nibble #3 | ... |
|
|
* +-------------+-----------+-----------+-----------+-----+
|
|
* | PCIType = 1 | FF_DL | ... |
|
|
* +-------------+-----------+-----------------------+-----+
|
|
*/
|
|
#define IsoTp_SetFFDataLen(byte, len) \
|
|
do \
|
|
{ \
|
|
byte[0] &= ((len >> 8) | 0xf0); \
|
|
byte[1] = (len & 0xff); \
|
|
} while(0)
|
|
#define IsoTp_GetFFDataLen(byte) (((((uint16_t)byte[0]) & 0x0f) << 8) + byte[1])
|
|
|
|
/*! \brief consecutive frame
|
|
* +-------------------------+-----+
|
|
* | byte #0 | ... |
|
|
* +-------------------------+-----+
|
|
* | nibble #0 | nibble #1 | ... |
|
|
* +-------------+-----------+ ... +
|
|
* | PCIType = 2 | SN | ... |
|
|
* +-------------+-----------+-----+
|
|
*/
|
|
#define IsoTp_SetCFSn(byte, sn) (byte[0] &= (((uint8_t)sn) | 0xf0))
|
|
#define IsoTp_GetCFSn(byte) (byte[0] & 0x0f)
|
|
|
|
/*! \brief flow control frame
|
|
* +-------------------------+-----------------------+-----------------------+-----+
|
|
* | byte #0 | byte #1 | byte #2 | ... |
|
|
* +-------------------------+-----------+-----------+-----------+-----------+-----+
|
|
* | nibble #0 | nibble #1 | nibble #2 | nibble #3 | nibble #4 | nibble #5 | ... |
|
|
* +-------------+-----------+-----------+-----------+-----------+-----------+-----+
|
|
* | PCIType = 1 | FS | BS | STmin | ... |
|
|
* +-------------+-----------+-----------------------+-----------------------+-----+
|
|
*/
|
|
#define IsoTp_SetFCFlowState(byte, fs) (byte[0] &= (((uint8_t)fs) | 0xf0))
|
|
#define IsoTp_GetFCFlowState(byte) (byte[0] & 0x0f)
|
|
#define IsoTp_SetFCBlockSize(byte, bs) (byte[1] = bs)
|
|
#define IsoTp_GetFCBlockSize(byte) (byte[1])
|
|
#define IsoTp_SetFCStmin(byte, STmin) (byte[2] = STmin)
|
|
#define IsoTp_GetFCStmin(byte) (byte[2])
|
|
|
|
/*******************************************************************************
|
|
* the typedefs
|
|
******************************************************************************/
|
|
|
|
/*! \brief ISOTP sender status
|
|
*/
|
|
typedef enum
|
|
{
|
|
ISOTP_SEND_STATUS_IDLE,
|
|
ISOTP_SEND_STATUS_INPROGRESS,
|
|
ISOTP_SEND_STATUS_ERROR,
|
|
} IsoTp_SendStatusType;
|
|
|
|
/*! \brief ISOTP receiver status
|
|
*/
|
|
typedef enum
|
|
{
|
|
ISOTP_RECEIVE_STATUS_IDLE,
|
|
ISOTP_RECEIVE_STATUS_INPROGRESS,
|
|
ISOTP_RECEIVE_STATUS_FULL,
|
|
} IsoTp_ReceiveStatusType;
|
|
|
|
/*! \brief ISOTP message
|
|
*/
|
|
typedef struct _IsoTp_MsgType_
|
|
{
|
|
uint8_t byte[8];
|
|
} IsoTp_MsgType;
|
|
|
|
/*******************************************************************************
|
|
* the globals
|
|
******************************************************************************/
|
|
|
|
/*******************************************************************************
|
|
* the functions
|
|
******************************************************************************/
|
|
|
|
/* st_min to microsecond */
|
|
static uint8_t IsoTp_MsToStMin(uint8_t ms)
|
|
{
|
|
uint8_t stMin;
|
|
|
|
stMin = ms;
|
|
if(stMin > 0x7F)
|
|
{
|
|
stMin = 0x7F;
|
|
}
|
|
|
|
return stMin;
|
|
}
|
|
|
|
/* st_min to msec */
|
|
static uint8_t IsoTp_StMinToMs(uint8_t stMin)
|
|
{
|
|
uint8_t ms;
|
|
|
|
if(stMin >= 0xF1 && stMin <= 0xF9)
|
|
{
|
|
ms = 1; /* Actually it should be 0.1 - 0.9 ms */
|
|
}
|
|
else if(stMin <= 0x7F)
|
|
{
|
|
ms = stMin;
|
|
}
|
|
else
|
|
{
|
|
ms = 0;
|
|
}
|
|
|
|
return ms;
|
|
}
|
|
|
|
static int8_t IsoTp_SendFlowControl(IsoTpType *obj, uint8_t flow_status, uint8_t block_size, uint8_t st_min_ms)
|
|
{
|
|
int8_t ret;
|
|
uint8_t index = 0;
|
|
IsoTp_MsgType msg;
|
|
|
|
/* Setup message */
|
|
IsoTp_SetPciType(msg.byte, ISOTP_PCI_TYPE_FLOW_CONTROL_FRAME);
|
|
IsoTp_SetFCFlowState(msg.byte, flow_status);
|
|
IsoTp_SetFCBlockSize(msg.byte, block_size);
|
|
IsoTp_SetFCStmin(msg.byte, IsoTp_MsToStMin(st_min_ms));
|
|
|
|
/* Send message */
|
|
if(obj->framePadding)
|
|
{
|
|
/* All pad with 0 */
|
|
for(index = 3; index < 8; ++index)
|
|
{
|
|
msg.byte[index] = 0;
|
|
}
|
|
ret = obj->sendCanMsg(obj->sendArbitrationId, msg.byte, 8);
|
|
}
|
|
else
|
|
{
|
|
ret = obj->sendCanMsg(obj->sendArbitrationId, msg.byte, 3);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int8_t IsoTp_SendSingleFrame(IsoTpType *obj)
|
|
{
|
|
int8_t ret;
|
|
uint8_t i = 0;
|
|
uint8_t index = 0;
|
|
IsoTp_MsgType msg;
|
|
|
|
/* Setup message */
|
|
IsoTp_SetPciType(msg.byte, ISOTP_PCI_TYPE_SINGLE_FRAME);
|
|
IsoTp_SetSFDataLen(msg.byte, (uint8_t)obj->sendSize);
|
|
for(index = 0; index < obj->sendSize; ++index)
|
|
{
|
|
msg.byte[index + 1] = obj->sendBuffer[index];
|
|
}
|
|
|
|
/* Send message */
|
|
if(obj->framePadding)
|
|
{
|
|
/* All pad with 0 */
|
|
for(i = 0; i < 7 - obj->sendSize; ++i)
|
|
{
|
|
msg.byte[i + obj->sendSize + 1] = 0;
|
|
}
|
|
ret = obj->sendCanMsg(obj->sendArbitrationId, msg.byte, 8);
|
|
}
|
|
else
|
|
{
|
|
ret = obj->sendCanMsg(obj->sendArbitrationId, msg.byte, obj->sendSize + 1);
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int8_t IsoTp_SendFirstFrame(IsoTpType *obj)
|
|
{
|
|
int8_t ret;
|
|
IsoTp_MsgType msg;
|
|
|
|
/* Setup message */
|
|
IsoTp_SetPciType(msg.byte, ISOTP_PCI_TYPE_FIRST_FRAME);
|
|
IsoTp_SetFFDataLen(msg.byte, obj->sendSize);
|
|
uint8_t index = 0;
|
|
for(index = 0; index < 6; ++index) /* 6 data bytes for the first frame */
|
|
{
|
|
msg.byte[index + 2] = obj->sendBuffer[index];
|
|
}
|
|
|
|
/* Send message */
|
|
ret = obj->sendCanMsg(obj->sendArbitrationId, msg.byte, 8);
|
|
if(ISOTP_RET_OK == ret)
|
|
{
|
|
obj->sendOffset += 6; /* 6 data bytes for the first frame */
|
|
obj->sendSN = 1;
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int8_t IsoTp_SendConsecutiveFrame(IsoTpType *obj)
|
|
{
|
|
int8_t ret;
|
|
IsoTp_MsgType msg;
|
|
uint16_t dataLength;
|
|
uint8_t index = 0;
|
|
|
|
/* setup message */
|
|
IsoTp_SetPciType(msg.byte, ISOTP_PCI_TYPE_CONSECUTIVE_FRAME);
|
|
IsoTp_SetCFSn(msg.byte, obj->sendSN);
|
|
dataLength = obj->sendSize - obj->sendOffset;
|
|
if(dataLength > 7) /* Max 7 data bytes for the consecutive frame */
|
|
{
|
|
dataLength = 7;
|
|
}
|
|
for(index = 0; index < dataLength; ++index)
|
|
{
|
|
msg.byte[index + 1] = obj->sendBuffer[obj->sendOffset + index];
|
|
}
|
|
|
|
/* Send message */
|
|
if(obj->framePadding)
|
|
{
|
|
/* All pad with 0 */
|
|
uint8_t i = 0;
|
|
for(i = 0; i < 7 - dataLength; ++i)
|
|
{
|
|
msg.byte[i + 1 + dataLength] = 0;
|
|
}
|
|
ret = obj->sendCanMsg(obj->sendArbitrationId, msg.byte, 8);
|
|
}
|
|
else
|
|
{
|
|
ret = obj->sendCanMsg(obj->sendArbitrationId, msg.byte, dataLength + 1);
|
|
}
|
|
|
|
if(ISOTP_RET_OK == ret)
|
|
{
|
|
obj->sendOffset += dataLength;
|
|
if(++(obj->sendSN) > 0x0F)
|
|
{
|
|
obj->sendSN = 0;
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
static int8_t IsoTp_ReceiveSingleFrame(IsoTpType *obj, const IsoTp_MsgType *pMsg, uint8_t len)
|
|
{
|
|
uint8_t index = 0;
|
|
|
|
/* Check data length */
|
|
if((0 == IsoTp_GetSFDataLen(pMsg->byte))
|
|
|| (IsoTp_GetSFDataLen(pMsg->byte) > (len - 1)))
|
|
{
|
|
if(obj->debug != NULL)
|
|
{
|
|
obj->debug("Single-frame length too small or too large.");
|
|
}
|
|
return ISOTP_RET_LENGTH;
|
|
}
|
|
|
|
/* Copying data */
|
|
/* polyspace-begin DEFECT:OUT_BOUND_ARRAY [No action planned:High] "Still keep default because one frame max length is 8" */
|
|
obj->receiveSize = IsoTp_GetSFDataLen(pMsg->byte);
|
|
for(index = 0; index < obj->receiveSize; ++index)
|
|
{
|
|
obj->receiveBuffer[index] = pMsg->byte[index + 1];
|
|
}
|
|
/* polyspace-end DEFECT:OUT_BOUND_ARRAY [No action planned:High] "Still keep default because one frame max length is 8" */
|
|
|
|
return ISOTP_RET_OK;
|
|
}
|
|
|
|
static int8_t IsoTp_ReceiveFirstFrame(IsoTpType *obj, const IsoTp_MsgType *pMsg, uint8_t len)
|
|
{
|
|
uint16_t payloadLength;
|
|
uint8_t index = 0;
|
|
|
|
if(8 != len)
|
|
{
|
|
if(obj->debug != NULL)
|
|
{
|
|
obj->debug("First frame should be 8 bytes in length.");
|
|
}
|
|
return ISOTP_RET_LENGTH;
|
|
}
|
|
|
|
/* Check data length */
|
|
payloadLength = IsoTp_GetFFDataLen(pMsg->byte);
|
|
|
|
/* Should not use multiple frame transmission */
|
|
if(payloadLength <= 7)
|
|
{
|
|
if(obj->debug != NULL)
|
|
{
|
|
obj->debug("First frame should not use multiple frame transmission.");
|
|
}
|
|
return ISOTP_RET_LENGTH;
|
|
}
|
|
|
|
if(payloadLength > obj->receiveBufferSize)
|
|
{
|
|
if(obj->debug != NULL)
|
|
{
|
|
obj->debug("Multi-frame response too large for receiving buffer.");
|
|
}
|
|
return ISOTP_RET_OVERFLOW;
|
|
}
|
|
|
|
/* Copying data */
|
|
obj->receiveSize = payloadLength;
|
|
for(index = 0; index < 6; ++index) /* 6 data bytes for the first frame */
|
|
{
|
|
obj->receiveBuffer[index] = pMsg->byte[index + 2];
|
|
}
|
|
obj->receiveOffset = 6; /* 6 data bytes for the first frame */
|
|
obj->receiveSN = 1;
|
|
|
|
return ISOTP_RET_OK;
|
|
}
|
|
|
|
static int8_t IsoTp_ReceiveConsecutiveFrame(IsoTpType *obj, const IsoTp_MsgType *pMsg, uint8_t len)
|
|
{
|
|
uint16_t remaining_bytes;
|
|
uint8_t index = 0;
|
|
|
|
/* Check SN */
|
|
if(obj->receiveSN != IsoTp_GetCFSn(pMsg->byte))
|
|
{
|
|
return ISOTP_RET_WRONG_SN;
|
|
}
|
|
|
|
/* Check data length */
|
|
remaining_bytes = obj->receiveSize - obj->receiveOffset;
|
|
if(remaining_bytes > 7) /* Max 7 data bytes for the consecutive frame */
|
|
{
|
|
remaining_bytes = 7;
|
|
}
|
|
if(remaining_bytes > len - 1)
|
|
{
|
|
if(obj->debug != NULL)
|
|
{
|
|
obj->debug("Consecutive frame too short.");
|
|
}
|
|
return ISOTP_RET_LENGTH;
|
|
}
|
|
|
|
/* Copying data */
|
|
for(index = 0; index < remaining_bytes; ++index)
|
|
{
|
|
obj->receiveBuffer[index + obj->receiveOffset] = pMsg->byte[index + 1];
|
|
}
|
|
|
|
obj->receiveOffset += remaining_bytes;
|
|
if(++(obj->receiveSN) > 0x0F)
|
|
{
|
|
obj->receiveSN = 0;
|
|
}
|
|
|
|
return ISOTP_RET_OK;
|
|
}
|
|
|
|
static int8_t IsoTp_ReceiveFlowControlFrame(IsoTpType *obj, const IsoTp_MsgType *pMsg, uint8_t len)
|
|
{
|
|
/* Check message length */
|
|
if(len < 3)
|
|
{
|
|
if(obj->debug != NULL)
|
|
{
|
|
obj->debug("Flow control frame too short.");
|
|
}
|
|
return ISOTP_RET_LENGTH;
|
|
}
|
|
|
|
return ISOTP_RET_OK;
|
|
}
|
|
|
|
int8_t IsoTp_Send(IsoTpType *obj, const uint8_t payload[], uint16_t size)
|
|
{
|
|
return IsoTp_SendWithId(obj, obj->sendArbitrationId, payload, size);
|
|
}
|
|
|
|
int8_t IsoTp_SendWithId(IsoTpType *obj, uint32_t id, const uint8_t payload[], uint16_t size)
|
|
{
|
|
int8_t ret;
|
|
uint8_t i = 0;
|
|
|
|
if(obj == NULL)
|
|
{
|
|
return ISOTP_RET_ERROR;
|
|
}
|
|
|
|
if(size > obj->sendBufferSize)
|
|
{
|
|
if(obj->debug != NULL)
|
|
{
|
|
obj->debug("Message size too large. Set a larger send buffer\n");
|
|
}
|
|
return ISOTP_RET_OVERFLOW;
|
|
}
|
|
|
|
if(ISOTP_SEND_STATUS_INPROGRESS == obj->sendStatus)
|
|
{
|
|
if(obj->debug != NULL)
|
|
{
|
|
obj->debug("Abort previous message, transmission in progress.\n");
|
|
}
|
|
return ISOTP_RET_INPROGRESS;
|
|
}
|
|
|
|
/* Copy into local buffer */
|
|
obj->sendSize = size;
|
|
obj->sendOffset = 0;
|
|
for(i = 0; i < size; ++i)
|
|
{
|
|
obj->sendBuffer[i] = payload[i];
|
|
}
|
|
|
|
if(obj->sendSize < 8)
|
|
{
|
|
/* Send single frame */
|
|
ret = IsoTp_SendSingleFrame(obj);
|
|
}
|
|
else
|
|
{
|
|
/* Send multiple frames */
|
|
ret = IsoTp_SendFirstFrame(obj);
|
|
|
|
/* Initialize multi-frame control flags */
|
|
if(ISOTP_RET_OK == ret)
|
|
{
|
|
obj->sendBsRemain = 0;
|
|
obj->sendSTMin = 0;
|
|
obj->sendWaitFrameCount = 0;
|
|
obj->sendTimerSeptime = obj->getTimeMs();
|
|
/* Refresh BS timer */
|
|
obj->sendTimerBlockSize = obj->getTimeMs() + ISOTP_DEFAULT_RESPONSE_TIMEOUT;
|
|
obj->sendProtocolResult = ISOTP_PROTOCOL_RESULT_OK;
|
|
obj->sendStatus = ISOTP_SEND_STATUS_INPROGRESS;
|
|
}
|
|
}
|
|
/* polyspace-end DEFECT:NULL_PTR [No action planned:High] "Still keep default because the null pointer is handled" */
|
|
|
|
return ret;
|
|
}
|
|
|
|
void IsoTp_HandleIncomingCanMsg(IsoTpType *obj, uint32_t id, const uint8_t *data, uint8_t len)
|
|
{
|
|
int8_t ret;
|
|
IsoTp_MsgType msg;
|
|
|
|
if(len < 2 || len > 8)
|
|
{
|
|
return;
|
|
}
|
|
|
|
uint8_t i = 0;
|
|
for(i = 0; i < len; ++i)
|
|
{
|
|
msg.byte[i] = data[i];
|
|
}
|
|
for(i = 0; i < 8 - len; ++i) /* len will NOT > 8 */
|
|
{
|
|
msg.byte[i + len] = 0; /* Padding */
|
|
}
|
|
|
|
switch(IsoTp_GetPciType(msg.byte))
|
|
{
|
|
case ISOTP_PCI_TYPE_SINGLE_FRAME:
|
|
{
|
|
/* Update protocol result */
|
|
if(ISOTP_RECEIVE_STATUS_INPROGRESS == obj->receiveStatus)
|
|
{
|
|
obj->receiveProtocolResult = ISOTP_PROTOCOL_RESULT_UNEXP_PDU;
|
|
}
|
|
else
|
|
{
|
|
obj->receiveProtocolResult = ISOTP_PROTOCOL_RESULT_OK;
|
|
}
|
|
|
|
/* Handle message */
|
|
ret = IsoTp_ReceiveSingleFrame(obj, &msg, len);
|
|
|
|
if(ISOTP_RET_OK == ret)
|
|
{
|
|
obj->receiveArbitrationId = id;
|
|
/* Change status */
|
|
obj->receiveStatus = ISOTP_RECEIVE_STATUS_FULL;
|
|
}
|
|
break;
|
|
}
|
|
case ISOTP_PCI_TYPE_FIRST_FRAME:
|
|
{
|
|
/* Update protocol result */
|
|
if(ISOTP_RECEIVE_STATUS_INPROGRESS == obj->receiveStatus)
|
|
{
|
|
obj->receiveProtocolResult = ISOTP_PROTOCOL_RESULT_UNEXP_PDU;
|
|
}
|
|
else
|
|
{
|
|
obj->receiveProtocolResult = ISOTP_PROTOCOL_RESULT_OK;
|
|
}
|
|
|
|
/* Handle message */
|
|
ret = IsoTp_ReceiveFirstFrame(obj, &msg, len);
|
|
|
|
/* If overflow happened */
|
|
if(ISOTP_RET_OVERFLOW == ret)
|
|
{
|
|
/* Update protocol result */
|
|
obj->receiveProtocolResult = ISOTP_PROTOCOL_RESULT_BUFFER_OVFLW;
|
|
/* Change status */
|
|
obj->receiveStatus = ISOTP_RECEIVE_STATUS_IDLE;
|
|
/* Send error message */
|
|
IsoTp_SendFlowControl(obj, ISOTP_PCI_FLOW_STATUS_OVERFLOW, 0, 0);
|
|
break;
|
|
}
|
|
|
|
/* If receive successful */
|
|
if(ISOTP_RET_OK == ret)
|
|
{
|
|
obj->receiveArbitrationId = id;
|
|
/* Change status */
|
|
obj->receiveStatus = ISOTP_RECEIVE_STATUS_INPROGRESS;
|
|
/* Send FC frame */
|
|
obj->receiveBlockSizeCount = obj->blockSize;
|
|
IsoTp_SendFlowControl(obj, ISOTP_PCI_FLOW_STATUS_CONTINUE, obj->receiveBlockSizeCount, ISOTP_DEFAULT_ST_MIN);
|
|
/* Refresh timer CR */
|
|
obj->receiveTimerCr = obj->getTimeMs() + ISOTP_DEFAULT_RESPONSE_TIMEOUT;
|
|
}
|
|
|
|
break;
|
|
}
|
|
case ISOTP_PCI_TYPE_CONSECUTIVE_FRAME:
|
|
{
|
|
/* Check if in receiving status */
|
|
if(ISOTP_RECEIVE_STATUS_INPROGRESS != obj->receiveStatus)
|
|
{
|
|
obj->receiveProtocolResult = ISOTP_PROTOCOL_RESULT_UNEXP_PDU;
|
|
break;
|
|
}
|
|
|
|
if(id != obj->receiveArbitrationId)
|
|
{
|
|
break;
|
|
}
|
|
|
|
/* Handle message */
|
|
ret = IsoTp_ReceiveConsecutiveFrame(obj, &msg, len);
|
|
|
|
/* If wrong SN */
|
|
if(ISOTP_RET_WRONG_SN == ret)
|
|
{
|
|
obj->receiveProtocolResult = ISOTP_PROTOCOL_RESULT_WRONG_SN;
|
|
obj->receiveStatus = ISOTP_RECEIVE_STATUS_IDLE;
|
|
break;
|
|
}
|
|
|
|
/* If success */
|
|
if(ISOTP_RET_OK == ret)
|
|
{
|
|
/* Refresh timer CR */
|
|
obj->receiveTimerCr = obj->getTimeMs() + ISOTP_DEFAULT_RESPONSE_TIMEOUT;
|
|
|
|
/* Receive finished */
|
|
if(obj->receiveOffset >= obj->receiveSize)
|
|
{
|
|
obj->receiveStatus = ISOTP_RECEIVE_STATUS_FULL;
|
|
}
|
|
else
|
|
{
|
|
/* Send FC when BS reaches limit */
|
|
if(0 == --obj->receiveBlockSizeCount)
|
|
{
|
|
obj->receiveBlockSizeCount = obj->blockSize;
|
|
IsoTp_SendFlowControl(obj, ISOTP_PCI_FLOW_STATUS_CONTINUE, obj->receiveBlockSizeCount, ISOTP_DEFAULT_ST_MIN);
|
|
}
|
|
}
|
|
}
|
|
|
|
break;
|
|
}
|
|
case ISOTP_PCI_TYPE_FLOW_CONTROL_FRAME:
|
|
{
|
|
/* Handle fc frame only when sending in progress */
|
|
if(ISOTP_SEND_STATUS_INPROGRESS != obj->sendStatus)
|
|
{
|
|
break;
|
|
}
|
|
|
|
/* Handle message */
|
|
ret = IsoTp_ReceiveFlowControlFrame(obj, &msg, len);
|
|
|
|
if(ISOTP_RET_OK == ret)
|
|
{
|
|
/* Refresh BS timer */
|
|
obj->sendTimerBlockSize = obj->getTimeMs() + ISOTP_DEFAULT_RESPONSE_TIMEOUT;
|
|
|
|
/* Overflow */
|
|
if(ISOTP_PCI_FLOW_STATUS_OVERFLOW == IsoTp_GetFCFlowState(msg.byte))
|
|
{
|
|
obj->sendProtocolResult = ISOTP_PROTOCOL_RESULT_BUFFER_OVFLW;
|
|
obj->sendStatus = ISOTP_SEND_STATUS_ERROR;
|
|
}
|
|
|
|
/* Wait */
|
|
else if(ISOTP_PCI_FLOW_STATUS_WAIT == IsoTp_GetFCFlowState(msg.byte))
|
|
{
|
|
obj->sendWaitFrameCount += 1;
|
|
/* Wait exceed allowed count */
|
|
if(obj->sendWaitFrameCount > ISOTP_MAX_WFT_NUMBER)
|
|
{
|
|
obj->sendProtocolResult = ISOTP_PROTOCOL_RESULT_WFT_OVRN;
|
|
obj->sendStatus = ISOTP_SEND_STATUS_ERROR;
|
|
}
|
|
}
|
|
|
|
/* Permit send */
|
|
else if(ISOTP_PCI_FLOW_STATUS_CONTINUE == IsoTp_GetFCFlowState(msg.byte))
|
|
{
|
|
if(0 == IsoTp_GetFCBlockSize(msg.byte))
|
|
{
|
|
obj->sendBsRemain = ISOTP_INVALID_BS;
|
|
}
|
|
else
|
|
{
|
|
obj->sendBsRemain = IsoTp_GetFCBlockSize(msg.byte);
|
|
}
|
|
obj->sendSTMin = IsoTp_StMinToMs(IsoTp_GetFCStmin(msg.byte));
|
|
obj->sendWaitFrameCount = 0;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
default:
|
|
break;
|
|
};
|
|
|
|
return;
|
|
}
|
|
|
|
int8_t IsoTp_Receive(IsoTpType *link, bool *IsFuncAddr, uint8_t *payload, uint16_t payload_size, uint16_t *out_size)
|
|
{
|
|
uint16_t copylen;
|
|
uint16_t i = 0;
|
|
|
|
if(ISOTP_RECEIVE_STATUS_FULL != link->receiveStatus)
|
|
{
|
|
return ISOTP_RET_NO_DATA;
|
|
}
|
|
|
|
*IsFuncAddr = (link->receiveArbitrationId == link->funcId) ? true : false;
|
|
|
|
copylen = link->receiveSize;
|
|
if(copylen > payload_size)
|
|
{
|
|
copylen = payload_size;
|
|
}
|
|
|
|
for(i = 0; i < copylen; ++i)
|
|
{
|
|
payload[i] = link->receiveBuffer[i];
|
|
}
|
|
*out_size = copylen;
|
|
|
|
link->receiveStatus = ISOTP_RECEIVE_STATUS_IDLE;
|
|
|
|
return ISOTP_RET_OK;
|
|
}
|
|
|
|
void IsoTp_Init(IsoTpType *obj, const IsoTp_Params *pParams)
|
|
{
|
|
obj->framePadding = pParams->framePadding;
|
|
obj->blockSize = pParams->blockSize;
|
|
obj->physId = pParams->recvPhysId;
|
|
obj->funcId = pParams->recvFuncId;
|
|
obj->sendArbitrationId = pParams->sendid;
|
|
obj->sendBuffer = pParams->sendBuf;
|
|
obj->sendBufferSize = pParams->sendBufSize;
|
|
obj->sendSize = 0;
|
|
obj->sendOffset = 0;
|
|
obj->sendSN = 0;
|
|
obj->sendBsRemain = 0;
|
|
obj->sendSTMin = 0;
|
|
obj->sendWaitFrameCount = 0;
|
|
obj->sendTimerSeptime = 0;
|
|
obj->sendTimerBlockSize = 0;
|
|
obj->sendProtocolResult = 0;
|
|
obj->sendStatus = ISOTP_SEND_STATUS_IDLE;
|
|
obj->receiveBuffer = pParams->recvBuf;
|
|
obj->receiveBufferSize = pParams->recvBufSize;
|
|
obj->receiveSize = 0;
|
|
obj->receiveOffset = 0;
|
|
obj->receiveSN = 0;
|
|
obj->receiveBlockSizeCount = 0;
|
|
obj->receiveTimerCr = 0;
|
|
obj->receiveProtocolResult = ISOTP_PROTOCOL_RESULT_OK;
|
|
obj->receiveStatus = ISOTP_RECEIVE_STATUS_IDLE;
|
|
|
|
obj->debug = pParams->debug;
|
|
obj->sendCanMsg = pParams->sendCanMsg;
|
|
obj->getTimeMs = pParams->getTimeMs;
|
|
}
|
|
|
|
void IsoTp_Poll(IsoTpType *obj)
|
|
{
|
|
int8_t ret;
|
|
|
|
/* Only polling when operation in progress */
|
|
if(ISOTP_SEND_STATUS_INPROGRESS == obj->sendStatus)
|
|
{
|
|
/* Continue send data */
|
|
if((ISOTP_INVALID_BS == obj->sendBsRemain || obj->sendBsRemain > 0) /* send data if bs_remain is invalid or bs_remain large than zero */
|
|
&& (0 == obj->sendSTMin || (0 != obj->sendSTMin && IsoTp_TimeAfter(obj->getTimeMs(), obj->sendTimerSeptime))))
|
|
{ /* st_min is zero or go beyond interval time */
|
|
ret = IsoTp_SendConsecutiveFrame(obj);
|
|
if(ISOTP_RET_OK == ret)
|
|
{
|
|
if(ISOTP_INVALID_BS != obj->sendBsRemain)
|
|
{
|
|
obj->sendBsRemain -= 1;
|
|
}
|
|
/* Refresh BS timer */
|
|
obj->sendTimerBlockSize = obj->getTimeMs() + ISOTP_DEFAULT_RESPONSE_TIMEOUT;
|
|
obj->sendTimerSeptime = obj->getTimeMs() + obj->sendSTMin;
|
|
|
|
/* Check if send finish */
|
|
if(obj->sendOffset >= obj->sendSize)
|
|
{
|
|
obj->sendStatus = ISOTP_SEND_STATUS_IDLE;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
obj->sendStatus = ISOTP_SEND_STATUS_ERROR;
|
|
}
|
|
}
|
|
|
|
/* Check timeout */
|
|
if(IsoTp_TimeAfter(obj->getTimeMs(), obj->sendTimerBlockSize))
|
|
{
|
|
obj->sendProtocolResult = ISOTP_PROTOCOL_RESULT_TIMEOUT_BS;
|
|
obj->sendStatus = ISOTP_SEND_STATUS_ERROR;
|
|
}
|
|
}
|
|
|
|
/* Only polling when operation in progress */
|
|
if(ISOTP_RECEIVE_STATUS_INPROGRESS == obj->receiveStatus)
|
|
{
|
|
/* check timeout */
|
|
if(IsoTp_TimeAfter(obj->getTimeMs(), obj->receiveTimerCr))
|
|
{
|
|
obj->receiveProtocolResult = ISOTP_PROTOCOL_RESULT_TIMEOUT_CR;
|
|
obj->receiveStatus = ISOTP_RECEIVE_STATUS_IDLE;
|
|
}
|
|
}
|
|
|
|
return;
|
|
}
|