ISOTP-C
A platform-agnostic ISOTP implementation in C.
isotp.h File Reference
#include <stdio.h>
#include <string.h>
#include "isotp_defines.h"
#include "isotp_config.h"
#include "isotp_user.h"
Include dependency graph for isotp.h:
This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Data Structures

struct  IsoTpLink
 Struct containing the data for linking an application to a CAN instance. The data stored in this struct is used internally and may be used by software programs using this library. More...
 

Typedefs

typedef struct IsoTpLink IsoTpLink
 Struct containing the data for linking an application to a CAN instance. The data stored in this struct is used internally and may be used by software programs using this library. More...
 

Functions

void isotp_init_link (IsoTpLink *link, uint32_t sendid, uint8_t *sendbuf, uint16_t sendbufsize, uint8_t *recvbuf, uint16_t recvbufsize)
 Initialises the ISO-TP library. More...
 
void isotp_poll (IsoTpLink *link)
 Polling function; call this function periodically to handle timeouts, send consecutive frames, etc. More...
 
void isotp_on_can_message (IsoTpLink *link, uint8_t *data, uint8_t len)
 Handles incoming CAN messages. Determines whether an incoming message is a valid ISO-TP frame or not and handles it accordingly. More...
 
int isotp_send (IsoTpLink *link, const uint8_t payload[], uint16_t size)
 Sends ISO-TP frames via CAN, using the ID set in the initialising function. More...
 
int isotp_send_with_id (IsoTpLink *link, uint32_t id, const uint8_t payload[], uint16_t size)
 See isotp_send, with the exception that this function is used only for functional addressing. More...
 
int isotp_receive (IsoTpLink *link, uint8_t *payload, const uint16_t payload_size, uint16_t *out_size)
 Receives and parses the received data and copies the parsed data in to the internal buffer. More...
 

Typedef Documentation

◆ IsoTpLink

typedef struct IsoTpLink IsoTpLink

Struct containing the data for linking an application to a CAN instance. The data stored in this struct is used internally and may be used by software programs using this library.

Function Documentation

◆ isotp_init_link()

void isotp_init_link ( IsoTpLink link,
uint32_t  sendid,
uint8_t *  sendbuf,
uint16_t  sendbufsize,
uint8_t *  recvbuf,
uint16_t  recvbufsize 
)

Initialises the ISO-TP library.

Parameters
linkThe
instance used for transceiving data.
sendidThe ID used to send data to other CAN nodes.
sendbufA pointer to an area in memory which can be used as a buffer for data to be sent.
sendbufsizeThe size of the buffer area.
recvbufA pointer to an area in memory which can be used as a buffer for data to be received.
recvbufsizeThe size of the buffer area.

Definition at line 450 of file isotp.c.

450 {
451 memset(link, 0, sizeof(*link));
454 link->send_arbitration_id = sendid;
455 link->send_buffer = sendbuf;
456 link->send_buf_size = sendbufsize;
457 link->receive_buffer = recvbuf;
458 link->receive_buf_size = recvbufsize;
459
460 return;
461}
@ ISOTP_RECEIVE_STATUS_IDLE
Definition: isotp_defines.h:62
@ ISOTP_SEND_STATUS_IDLE
Definition: isotp_defines.h:55

References ISOTP_RECEIVE_STATUS_IDLE, ISOTP_SEND_STATUS_IDLE, IsoTpLink::receive_buf_size, IsoTpLink::receive_buffer, IsoTpLink::receive_status, IsoTpLink::send_arbitration_id, IsoTpLink::send_buf_size, IsoTpLink::send_buffer, and IsoTpLink::send_status.

◆ isotp_on_can_message()

void isotp_on_can_message ( IsoTpLink link,
uint8_t *  data,
uint8_t  len 
)

Handles incoming CAN messages. Determines whether an incoming message is a valid ISO-TP frame or not and handles it accordingly.

Parameters
linkThe instance used for transceiving data.
dataThe data received via CAN.
lenThe length of the data received.

Definition at line 281 of file isotp.c.

281 {
282 IsoTpCanMessage message;
283 int ret;
284
285 if (len < 2 || len > 8) {
286 return;
287 }
288
289 memcpy(message.as.data_array.ptr, data, len);
290 memset(message.as.data_array.ptr + len, 0, sizeof(message.as.data_array.ptr) - len);
291
292 switch (message.as.common.type) {
294 /* update protocol result */
297 } else {
299 }
300
301 /* handle message */
302 ret = isotp_receive_single_frame(link, &message, len);
303
304 if (ISOTP_RET_OK == ret) {
305 /* change status */
307 }
308 break;
309 }
311 /* update protocol result */
314 } else {
316 }
317
318 /* handle message */
319 ret = isotp_receive_first_frame(link, &message, len);
320
321 /* if overflow happened */
322 if (ISOTP_RET_OVERFLOW == ret) {
323 /* update protocol result */
325 /* change status */
327 /* send error message */
329 break;
330 }
331
332 /* if receive successful */
333 if (ISOTP_RET_OK == ret) {
334 /* change status */
336 /* send fc frame */
339 /* refresh timer cs */
341 }
342
343 break;
344 }
346 /* check if in receiving status */
349 break;
350 }
351
352 /* handle message */
353 ret = isotp_receive_consecutive_frame(link, &message, len);
354
355 /* if wrong sn */
356 if (ISOTP_RET_WRONG_SN == ret) {
359 break;
360 }
361
362 /* if success */
363 if (ISOTP_RET_OK == ret) {
364 /* refresh timer cs */
366
367 /* receive finished */
368 if (link->receive_offset >= link->receive_size) {
370 } else {
371 /* send fc when bs reaches limit */
372 if (0 == --link->receive_bs_count) {
375 }
376 }
377 }
378
379 break;
380 }
382 /* handle fc frame only when sending in progress */
384 break;
385 }
386
387 /* handle message */
388 ret = isotp_receive_flow_control_frame(link, &message, len);
389
390 if (ISOTP_RET_OK == ret) {
391 /* refresh bs timer */
393
394 /* overflow */
398 }
399
400 /* wait */
401 else if (PCI_FLOW_STATUS_WAIT == message.as.flow_control.FS) {
402 link->send_wtf_count += 1;
403 /* wait exceed allowed count */
407 }
408 }
409
410 /* permit send */
411 else if (PCI_FLOW_STATUS_CONTINUE == message.as.flow_control.FS) {
412 if (0 == message.as.flow_control.BS) {
414 } else {
415 link->send_bs_remain = message.as.flow_control.BS;
416 }
417 uint32_t message_st_min_us = isotp_st_min_to_us(message.as.flow_control.STmin);
418 link->send_st_min_us = message_st_min_us > ISO_TP_DEFAULT_ST_MIN_US ? message_st_min_us : ISO_TP_DEFAULT_ST_MIN_US; // prefer as much st_min as possible for stability?
419 link->send_wtf_count = 0;
420 }
421 }
422 break;
423 default:
424 break;
425 };
426
427 return;
428}
static int isotp_receive_first_frame(IsoTpLink *link, IsoTpCanMessage *message, uint8_t len)
Definition: isotp.c:154
static int isotp_receive_consecutive_frame(IsoTpLink *link, IsoTpCanMessage *message, uint8_t len)
Definition: isotp.c:186
static int isotp_receive_flow_control_frame(IsoTpLink *link, IsoTpCanMessage *message, uint8_t len)
Definition: isotp.c:215
static int isotp_send_flow_control(IsoTpLink *link, uint8_t flow_status, uint8_t block_size, uint32_t st_min_us)
Definition: isotp.c:29
static uint32_t isotp_st_min_to_us(uint8_t st_min)
Definition: isotp.c:20
static int isotp_receive_single_frame(IsoTpLink *link, IsoTpCanMessage *message, uint8_t len)
Definition: isotp.c:140
#define ISO_TP_MAX_WFT_NUMBER
Definition: isotp_config.h:17
#define ISO_TP_DEFAULT_ST_MIN_US
Definition: isotp_config.h:12
#define ISO_TP_DEFAULT_RESPONSE_TIMEOUT_US
Definition: isotp_config.h:22
#define ISO_TP_DEFAULT_BLOCK_SIZE
Definition: isotp_config.h:7
@ ISOTP_RECEIVE_STATUS_FULL
Definition: isotp_defines.h:64
@ ISOTP_RECEIVE_STATUS_INPROGRESS
Definition: isotp_defines.h:63
#define ISOTP_PROTOCOL_RESULT_BUFFER_OVFLW
#define ISOTP_PROTOCOL_RESULT_UNEXP_PDU
#define ISOTP_INVALID_BS
Definition: isotp_defines.h:51
#define ISOTP_PROTOCOL_RESULT_OK
#define ISOTP_RET_OVERFLOW
Definition: isotp_defines.h:40
@ ISOTP_SEND_STATUS_ERROR
Definition: isotp_defines.h:57
@ ISOTP_SEND_STATUS_INPROGRESS
Definition: isotp_defines.h:56
#define ISOTP_RET_WRONG_SN
Definition: isotp_defines.h:41
#define ISOTP_PROTOCOL_RESULT_WFT_OVRN
@ PCI_FLOW_STATUS_OVERFLOW
@ PCI_FLOW_STATUS_WAIT
@ PCI_FLOW_STATUS_CONTINUE
#define ISOTP_RET_OK
Definition: isotp_defines.h:37
@ TSOTP_PCI_TYPE_CONSECUTIVE_FRAME
@ ISOTP_PCI_TYPE_SINGLE
@ ISOTP_PCI_TYPE_FIRST_FRAME
@ ISOTP_PCI_TYPE_FLOW_CONTROL_FRAME
#define ISOTP_PROTOCOL_RESULT_WRONG_SN
uint32_t isotp_user_get_us(void)
user implemented, gets the amount of time passed since the last call in microseconds
IsoTpDataArray data_array
IsoTpPciType common
union IsoTpCanMessage::@0 as
IsoTpFlowControl flow_control
uint8_t ptr[8]

References IsoTpCanMessage::common, IsoTpCanMessage::data_array, IsoTpCanMessage::flow_control, ISOTP_PCI_TYPE_FIRST_FRAME, ISOTP_PCI_TYPE_FLOW_CONTROL_FRAME, ISOTP_PCI_TYPE_SINGLE, isotp_receive_consecutive_frame(), isotp_receive_first_frame(), isotp_receive_flow_control_frame(), isotp_receive_single_frame(), ISOTP_RECEIVE_STATUS_FULL, ISOTP_RECEIVE_STATUS_IDLE, ISOTP_RECEIVE_STATUS_INPROGRESS, isotp_send_flow_control(), ISOTP_SEND_STATUS_ERROR, ISOTP_SEND_STATUS_INPROGRESS, isotp_st_min_to_us(), isotp_user_get_us(), PCI_FLOW_STATUS_CONTINUE, PCI_FLOW_STATUS_OVERFLOW, PCI_FLOW_STATUS_WAIT, IsoTpDataArray::ptr, IsoTpLink::receive_bs_count, IsoTpLink::receive_offset, IsoTpLink::receive_protocol_result, IsoTpLink::receive_size, IsoTpLink::receive_status, IsoTpLink::receive_timer_cr, IsoTpLink::send_bs_remain, IsoTpLink::send_protocol_result, IsoTpLink::send_st_min_us, IsoTpLink::send_status, IsoTpLink::send_timer_bs, IsoTpLink::send_wtf_count, and TSOTP_PCI_TYPE_CONSECUTIVE_FRAME.

◆ isotp_poll()

void isotp_poll ( IsoTpLink link)

Polling function; call this function periodically to handle timeouts, send consecutive frames, etc.

Parameters
linkThe instance used.

Definition at line 463 of file isotp.c.

463 {
464 int ret;
465
466 /* only polling when operation in progress */
468
469 /* continue send data */
470 if (/* send data if bs_remain is invalid or bs_remain large than zero */
471 (ISOTP_INVALID_BS == link->send_bs_remain || link->send_bs_remain > 0) &&
472 /* and if st_min is zero or go beyond interval time */
474
476 if (ISOTP_RET_OK == ret) {
477 if (ISOTP_INVALID_BS != link->send_bs_remain) {
478 link->send_bs_remain -= 1;
479 }
482
483 /* check if send finish */
484 if (link->send_offset >= link->send_size) {
486 }
487 } else if (ISOTP_RET_NOSPACE == ret) {
488 /* shim reported that it isn't able to send a frame at present, retry on next call */
489 } else {
491 }
492 }
493
494 /* check timeout */
498 }
499 }
500
501 /* only polling when operation in progress */
503
504 /* check timeout */
508 }
509 }
510
511 return;
512}
static int isotp_send_consecutive_frame(IsoTpLink *link)
Definition: isotp.c:103
#define ISOTP_RET_NOSPACE
Definition: isotp_defines.h:45
#define ISOTP_PROTOCOL_RESULT_TIMEOUT_CR
#define ISOTP_PROTOCOL_RESULT_TIMEOUT_BS
#define IsoTpTimeAfter(a, b)
Definition: isotp_defines.h:48

References ISOTP_RECEIVE_STATUS_IDLE, ISOTP_RECEIVE_STATUS_INPROGRESS, isotp_send_consecutive_frame(), ISOTP_SEND_STATUS_ERROR, ISOTP_SEND_STATUS_IDLE, ISOTP_SEND_STATUS_INPROGRESS, isotp_user_get_us(), IsoTpLink::receive_protocol_result, IsoTpLink::receive_status, IsoTpLink::receive_timer_cr, IsoTpLink::send_bs_remain, IsoTpLink::send_offset, IsoTpLink::send_protocol_result, IsoTpLink::send_size, IsoTpLink::send_st_min_us, IsoTpLink::send_status, IsoTpLink::send_timer_bs, and IsoTpLink::send_timer_st.

◆ isotp_receive()

int isotp_receive ( IsoTpLink link,
uint8_t *  payload,
const uint16_t  payload_size,
uint16_t *  out_size 
)

Receives and parses the received data and copies the parsed data in to the internal buffer.

Parameters
linkThe IsoTpLink instance used to transceive data.
payloadA pointer to an area in memory where the raw data is copied from.
payload_sizeThe size of the received (raw) CAN data.
out_sizeA reference to a variable which will contain the size of the actual (parsed) data.
Returns
Possible return values:

Definition at line 430 of file isotp.c.

430 {
431 uint16_t copylen;
432
434 return ISOTP_RET_NO_DATA;
435 }
436
437 copylen = link->receive_size;
438 if (copylen > payload_size) {
439 copylen = payload_size;
440 }
441
442 memcpy(payload, link->receive_buffer, copylen);
443 *out_size = copylen;
444
446
447 return ISOTP_RET_OK;
448}
#define ISOTP_RET_NO_DATA
Definition: isotp_defines.h:42

References ISOTP_RECEIVE_STATUS_FULL, ISOTP_RECEIVE_STATUS_IDLE, IsoTpLink::receive_buffer, IsoTpLink::receive_size, and IsoTpLink::receive_status.

◆ isotp_send()

int isotp_send ( IsoTpLink link,
const uint8_t  payload[],
uint16_t  size 
)

Sends ISO-TP frames via CAN, using the ID set in the initialising function.

Single-frame messages will be sent immediately when calling this function. Multi-frame messages will be sent consecutively when calling isotp_poll.

Parameters
linkThe instance used for transceiving data.
payloadThe payload to be sent. (Up to 4095 bytes).
sizeThe size of the payload to be sent.
Returns
Possible return values:

Sends ISO-TP frames via CAN, using the ID set in the initialising function.

Definition at line 229 of file isotp.c.

229 {
230 return isotp_send_with_id(link, link->send_arbitration_id, payload, size);
231}
int isotp_send_with_id(IsoTpLink *link, uint32_t id, const uint8_t payload[], uint16_t size)
See isotp_send, with the exception that this function is used only for functional addressing.
Definition: isotp.c:233

References isotp_send_with_id(), and IsoTpLink::send_arbitration_id.

◆ isotp_send_with_id()

int isotp_send_with_id ( IsoTpLink link,
uint32_t  id,
const uint8_t  payload[],
uint16_t  size 
)

See isotp_send, with the exception that this function is used only for functional addressing.

Definition at line 233 of file isotp.c.

233 {
234 int ret;
235
236 if (link == 0x0) {
237 isotp_user_debug("Link is null!");
238 return ISOTP_RET_ERROR;
239 }
240
241 if (size > link->send_buf_size) {
242 isotp_user_debug("Message size too large. Increase ISO_TP_MAX_MESSAGE_SIZE to set a larger buffer\n");
243 char message[128];
244 sprintf(&message[0], "Attempted to send %d bytes; max size is %d!\n", size, link->send_buf_size);
245 isotp_user_debug(message);
246 return ISOTP_RET_OVERFLOW;
247 }
248
250 isotp_user_debug("Abort previous message, transmission in progress.\n");
252 }
253
254 /* copy into local buffer */
255 link->send_size = size;
256 link->send_offset = 0;
257 (void) memcpy(link->send_buffer, payload, size);
258
259 if (link->send_size < 8) {
260 /* send single frame */
261 ret = isotp_send_single_frame(link, id);
262 } else {
263 /* send multi-frame */
264 ret = isotp_send_first_frame(link, id);
265
266 /* init multi-frame control flags */
267 if (ISOTP_RET_OK == ret) {
268 link->send_bs_remain = 0;
269 link->send_st_min_us = 0;
270 link->send_wtf_count = 0;
275 }
276 }
277
278 return ret;
279}
static int isotp_send_single_frame(IsoTpLink *link, uint32_t id)
Definition: isotp.c:53
static int isotp_send_first_frame(IsoTpLink *link, uint32_t id)
Definition: isotp.c:79
#define ISOTP_RET_ERROR
Definition: isotp_defines.h:38
void isotp_user_debug(const char *message,...)
user implemented, print debug message

References isotp_send_first_frame(), isotp_send_single_frame(), ISOTP_SEND_STATUS_INPROGRESS, isotp_user_debug(), isotp_user_get_us(), IsoTpLink::send_bs_remain, IsoTpLink::send_buf_size, IsoTpLink::send_buffer, IsoTpLink::send_offset, IsoTpLink::send_protocol_result, IsoTpLink::send_size, IsoTpLink::send_st_min_us, IsoTpLink::send_status, IsoTpLink::send_timer_bs, IsoTpLink::send_timer_st, and IsoTpLink::send_wtf_count.

Referenced by isotp_send().