diff --git a/include/zephyr/canbus/isotp.h b/include/zephyr/canbus/isotp.h index b975837915f..aed5306b16a 100644 --- a/include/zephyr/canbus/isotp.h +++ b/include/zephyr/canbus/isotp.h @@ -11,8 +11,8 @@ * ISO-TP is a transport protocol for CAN (Controller Area Network) */ -#ifndef ZEPHYR_INCLUDE_ISOTP_H_ -#define ZEPHYR_INCLUDE_ISOTP_H_ +#ifndef ZEPHYR_INCLUDE_CANBUS_ISOTP_H_ +#define ZEPHYR_INCLUDE_CANBUS_ISOTP_H_ /** * @brief CAN ISO-TP Protocol @@ -34,10 +34,16 @@ * DLC Data length code * FC Flow Control * FF First Frame + * SF Single Frame * FS Flow Status * AE Address Extension + * SN Sequence Number + * ST Separation time * SA Source Address * TA Target Address + * RX_DL CAN RX LL data size + * TX_DL CAN TX LL data size + * PCI Process Control Information */ /* @@ -147,6 +153,12 @@ extern "C" { /** Message uses extended (29-bit) CAN ID */ #define ISOTP_MSG_IDE BIT(2) +/** Message uses CAN-FD format (FDF) */ +#define ISOTP_MSG_FDF BIT(3) + +/** Message uses CAN-FD Baud Rate Switch (BRS). Only valid in combination with ``ISOTP_MSG_FDF``. */ +#define ISOTP_MSG_BRS BIT(4) + /** @} */ /** @@ -167,6 +179,17 @@ struct isotp_msg_id { }; /** ISO-TP extended address (if used) */ uint8_t ext_addr; + /** + * ISO-TP frame data length (TX_DL for TX address or RX_DL for RX address). + * + * Valid values are 8 for classical CAN or 8, 12, 16, 20, 24, 32, 48 and 64 for CAN-FD. + * + * 0 will be interpreted as 8 or 64 (if ISOTP_MSG_FDF is set). + * + * The value for incoming transmissions (RX_DL) is determined automatically based on the + * received first frame and does not need to be set during initialization. + */ + uint8_t dl; /** Flags. @see @ref ISOTP_MSG_FLAGS. */ uint8_t flags; }; @@ -459,4 +482,4 @@ struct isotp_recv_ctx { } #endif -#endif /* ZEPHYR_INCLUDE_ISOTP_H_ */ +#endif /* ZEPHYR_INCLUDE_CANBUS_ISOTP_H_ */ diff --git a/subsys/canbus/isotp/Kconfig b/subsys/canbus/isotp/Kconfig index b533bf6d1e8..1f9ae2d8a34 100644 --- a/subsys/canbus/isotp/Kconfig +++ b/subsys/canbus/isotp/Kconfig @@ -5,6 +5,7 @@ menuconfig ISOTP bool "ISO-TP Transport [EXPERIMENTAL]" + depends on CAN select NET_BUF select POLL select EXPERIMENTAL @@ -74,11 +75,12 @@ config ISOTP_RX_BUF_COUNT config ISOTP_RX_BUF_SIZE int "Size of one buffer data block" + default 63 if CAN_FD_MODE default 56 help This value defines the size of a single block in the pool. The number of blocks is given by ISOTP_RX_BUF_COUNT. To be efficient use a multiple of - CAN_DL - 1 (for classic can : 8 - 1 = 7). + CAN_MAX_DLEN - 1 (for classic CAN : 8 - 1 = 7, for CAN-FD : 64 - 1 = 63). config ISOTP_RX_SF_FF_BUF_COUNT int "Number of SF and FF data buffers for receiving data" @@ -87,7 +89,7 @@ config ISOTP_RX_SF_FF_BUF_COUNT This buffer is used for first and single frames. It is extra because the buffer has to be ready for the first reception in isr context and therefor is allocated when binding. - Each buffer will occupy CAN_DL - 1 byte + header (sizeof(struct net_buf)) + Each buffer will occupy CAN_MAX_DLEN - 1 byte + header (sizeof(struct net_buf)) amount of data. config ISOTP_USE_TX_BUF diff --git a/subsys/canbus/isotp/isotp.c b/subsys/canbus/isotp/isotp.c index 4a55deb76db..104988bec0a 100644 --- a/subsys/canbus/isotp/isotp.c +++ b/subsys/canbus/isotp/isotp.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2019 Alexander Wachter + * Copyright (c) 2023 Enphase Energy * * SPDX-License-Identifier: Apache-2.0 */ @@ -26,7 +27,7 @@ NET_BUF_POOL_DEFINE(isotp_rx_pool, CONFIG_ISOTP_RX_BUF_COUNT, receive_pool_free); NET_BUF_POOL_DEFINE(isotp_rx_sf_ff_pool, CONFIG_ISOTP_RX_SF_FF_BUF_COUNT, - ISOTP_CAN_DL, sizeof(uint32_t), receive_ff_sf_pool_free); + CAN_MAX_DLEN, sizeof(uint32_t), receive_ff_sf_pool_free); static struct isotp_global_ctx global_ctx = { .alloc_list = SYS_SLIST_STATIC_INIT(&global_ctx.alloc_list), @@ -40,6 +41,24 @@ NET_BUF_POOL_VAR_DEFINE(isotp_tx_pool, CONFIG_ISOTP_TX_BUF_COUNT, static void receive_state_machine(struct isotp_recv_ctx *ctx); +static inline void prepare_frame(struct can_frame *frame, struct isotp_msg_id *addr) +{ + frame->id = addr->ext_id; + frame->flags = ((addr->flags & ISOTP_MSG_IDE) != 0 ? CAN_FRAME_IDE : 0) | + ((addr->flags & ISOTP_MSG_FDF) != 0 ? CAN_FRAME_FDF : 0) | + ((addr->flags & ISOTP_MSG_BRS) != 0 ? CAN_FRAME_BRS : 0); +} + +static inline void prepare_filter(struct can_filter *filter, struct isotp_msg_id *addr, + uint32_t mask) +{ + filter->id = addr->ext_id; + filter->mask = mask; + filter->flags = CAN_FILTER_DATA | + ((addr->flags & ISOTP_MSG_IDE) != 0 ? CAN_FILTER_IDE : 0) | + ((addr->flags & ISOTP_MSG_FDF) != 0 ? CAN_FILTER_FDF : 0); +} + /* * Wake every context that is waiting for a buffer */ @@ -103,12 +122,12 @@ static inline uint32_t receive_get_ff_length(struct net_buf *buf) return len; } -static inline uint32_t receive_get_sf_length(struct net_buf *buf) +static inline uint32_t receive_get_sf_length(struct net_buf *buf, bool fdf) { uint8_t len = net_buf_pull_u8(buf) & ISOTP_PCI_SF_DL_MASK; - /* Single frames > 16 bytes (CAN-FD only) */ - if (IS_ENABLED(ISOTP_USE_CAN_FD) && !len) { + /* Single frames > 8 bytes (CAN-FD only) */ + if (IS_ENABLED(CONFIG_CAN_FD_MODE) && fdf && !len) { len = net_buf_pull_u8(buf); } @@ -117,16 +136,15 @@ static inline uint32_t receive_get_sf_length(struct net_buf *buf) static void receive_send_fc(struct isotp_recv_ctx *ctx, uint8_t fs) { - struct can_frame frame = { - .flags = (ctx->tx_addr.flags & ISOTP_MSG_IDE) != 0 ? CAN_FRAME_IDE : 0, - .id = ctx->tx_addr.ext_id - }; + struct can_frame frame; uint8_t *data = frame.data; uint8_t payload_len; int ret; __ASSERT_NO_MSG(!(fs & ISOTP_PCI_TYPE_MASK)); + prepare_frame(&frame, &ctx->tx_addr); + if ((ctx->tx_addr.flags & ISOTP_MSG_EXT_ADDR) != 0) { *data++ = ctx->tx_addr.ext_addr; } @@ -138,10 +156,11 @@ static void receive_send_fc(struct isotp_recv_ctx *ctx, uint8_t fs) #ifdef CONFIG_ISOTP_ENABLE_TX_PADDING /* AUTOSAR requirement SWS_CanTp_00347 */ - memset(&frame.data[payload_len], 0xCC, ISOTP_CAN_DL - payload_len); - frame.dlc = ISOTP_CAN_DL; + memset(&frame.data[payload_len], ISOTP_PAD_BYTE, + ISOTP_PADDED_FRAME_DL_MIN - payload_len); + frame.dlc = can_bytes_to_dlc(ISOTP_PADDED_FRAME_DL_MIN); #else - frame.dlc = payload_len; + frame.dlc = can_bytes_to_dlc(payload_len); #endif ret = can_send(ctx->can_dev, &frame, K_MSEC(ISOTP_A), @@ -212,8 +231,10 @@ static int receive_alloc_buffer(struct isotp_recv_ctx *ctx) /* Alloc all buffers because we can't wait during reception */ buf = receive_alloc_buffer_chain(ctx->length); } else { - buf = receive_alloc_buffer_chain(ctx->opts.bs * - (ISOTP_CAN_DL - 1)); + /* Alloc the minimum of the remaining length and bytes of one block */ + uint32_t len = MIN(ctx->length, ctx->opts.bs * (ctx->rx_addr.dl - 1)); + + buf = receive_alloc_buffer_chain(len); } if (!buf) { @@ -257,7 +278,8 @@ static void receive_state_machine(struct isotp_recv_ctx *ctx) switch (ctx->state) { case ISOTP_RX_STATE_PROCESS_SF: - ctx->length = receive_get_sf_length(ctx->buf); + ctx->length = receive_get_sf_length(ctx->buf, + (ctx->rx_addr.flags & ISOTP_MSG_FDF) != 0); ud_rem_len = net_buf_user_data(ctx->buf); *ud_rem_len = 0; LOG_DBG("SM process SF of length %d", ctx->length); @@ -371,8 +393,10 @@ static void receive_work_handler(struct k_work *item) static void process_ff_sf(struct isotp_recv_ctx *ctx, struct can_frame *frame) { int index = 0; + uint8_t sf_len; uint8_t payload_len; uint32_t rx_sa; /* ISO-TP fixed source address (if used) */ + uint8_t can_dl = can_dlc_to_bytes(frame->dlc); if ((ctx->rx_addr.flags & ISOTP_MSG_EXT_ADDR) != 0) { if (frame->data[index++] != ctx->rx_addr.ext_addr) { @@ -398,13 +422,14 @@ static void process_ff_sf(struct isotp_recv_ctx *ctx, struct can_frame *frame) switch (frame->data[index] & ISOTP_PCI_TYPE_MASK) { case ISOTP_PCI_TYPE_FF: LOG_DBG("Got FF IRQ"); - if (frame->dlc != ISOTP_CAN_DL) { + if (can_dl < ISOTP_FF_DL_MIN) { LOG_INF("FF DLC invalid. Ignore"); return; } - payload_len = ISOTP_CAN_DL; + payload_len = can_dl; ctx->state = ISOTP_RX_STATE_PROCESS_FF; + ctx->rx_addr.dl = can_dl; ctx->sn_expected = 1; break; @@ -412,16 +437,27 @@ static void process_ff_sf(struct isotp_recv_ctx *ctx, struct can_frame *frame) LOG_DBG("Got SF IRQ"); #ifdef CONFIG_ISOTP_REQUIRE_RX_PADDING /* AUTOSAR requirement SWS_CanTp_00345 */ - if (frame->dlc != ISOTP_CAN_DL) { + if (can_dl < ISOTP_PADDED_FRAME_DL_MIN) { LOG_INF("SF DLC invalid. Ignore"); return; } #endif + sf_len = frame->data[index] & ISOTP_PCI_SF_DL_MASK; - payload_len = index + 1 + (frame->data[index] & - ISOTP_PCI_SF_DL_MASK); + /* Single frames > 8 bytes (CAN-FD only) */ + if (IS_ENABLED(CONFIG_CAN_FD_MODE) && (ctx->rx_addr.flags & ISOTP_MSG_FDF) != 0 && + can_dl > ISOTP_4BIT_SF_MAX_CAN_DL) { + if (sf_len != 0) { + LOG_INF("SF DL invalid. Ignore"); + return; + } + sf_len = frame->data[index + 1]; + payload_len = index + 2 + sf_len; + } else { + payload_len = index + 1 + sf_len; + } - if (payload_len > frame->dlc) { + if (payload_len > can_dl) { LOG_INF("SF DL does not fit. Ignore"); return; } @@ -464,6 +500,7 @@ static void process_cf(struct isotp_recv_ctx *ctx, struct can_frame *frame) uint32_t *ud_rem_len = (uint32_t *)net_buf_user_data(ctx->buf); int index = 0; uint32_t data_len; + uint8_t can_dl = can_dlc_to_bytes(frame->dlc); if ((ctx->rx_addr.flags & ISOTP_MSG_EXT_ADDR) != 0) { if (frame->data[index++] != ctx->rx_addr.ext_addr) { @@ -490,16 +527,24 @@ static void process_cf(struct isotp_recv_ctx *ctx, struct can_frame *frame) #ifdef CONFIG_ISOTP_REQUIRE_RX_PADDING /* AUTOSAR requirement SWS_CanTp_00346 */ - if (frame->dlc != ISOTP_CAN_DL) { + if (can_dl < ISOTP_PADDED_FRAME_DL_MIN) { LOG_ERR("CF DL invalid"); receive_report_error(ctx, ISOTP_N_ERROR); return; } #endif + /* First frame defines the RX data length, consecutive frames + * must have the same length (except the last frame) + */ + if (can_dl != ctx->rx_addr.dl && ctx->length > can_dl - index) { + LOG_ERR("CF DL invalid"); + receive_report_error(ctx, ISOTP_N_ERROR); + return; + } + LOG_DBG("Got CF irq. Appending data"); - data_len = (ctx->length > frame->dlc - index) ? frame->dlc - index : - ctx->length; + data_len = MIN(ctx->length, can_dl - index); receive_add_mem(ctx, &frame->data[index], data_len); ctx->length -= data_len; LOG_DBG("%d bytes remaining", ctx->length); @@ -555,6 +600,7 @@ static void receive_can_rx(const struct device *dev, struct can_frame *frame, vo static inline int attach_ff_filter(struct isotp_recv_ctx *ctx) { + struct can_filter filter; uint32_t mask; if ((ctx->rx_addr.flags & ISOTP_MSG_FIXED_ADDR) != 0) { @@ -563,12 +609,7 @@ static inline int attach_ff_filter(struct isotp_recv_ctx *ctx) mask = CAN_EXT_ID_MASK; } - struct can_filter filter = { - .flags = CAN_FILTER_DATA | - ((ctx->rx_addr.flags & ISOTP_MSG_IDE) != 0 ? CAN_FILTER_IDE : 0), - .id = ctx->rx_addr.ext_id, - .mask = mask - }; + prepare_filter(&filter, &ctx->rx_addr, mask); ctx->filter_id = can_add_rx_filter(ctx->can_dev, receive_can_rx, ctx, &filter); @@ -586,6 +627,7 @@ int isotp_bind(struct isotp_recv_ctx *ctx, const struct device *can_dev, const struct isotp_fc_opts *opts, k_timeout_t timeout) { + can_mode_t cap; int ret; __ASSERT(ctx, "ctx is NULL"); @@ -605,6 +647,14 @@ int isotp_bind(struct isotp_recv_ctx *ctx, const struct device *can_dev, ctx->opts = *opts; ctx->state = ISOTP_RX_STATE_WAIT_FF_SF; + if ((rx_addr->flags & ISOTP_MSG_FDF) != 0 || (tx_addr->flags & ISOTP_MSG_FDF) != 0) { + ret = can_get_capabilities(can_dev, &cap); + if (ret != 0 || (cap & CAN_MODE_FD) == 0) { + LOG_ERR("CAN controller does not support FD mode"); + return ISOTP_N_ERROR; + } + } + LOG_DBG("Binding to addr: 0x%x. Responding on 0x%x", ctx->rx_addr.ext_id, ctx->tx_addr.ext_id); @@ -770,7 +820,7 @@ static void send_process_fc(struct isotp_send_ctx *ctx, #ifdef CONFIG_ISOTP_REQUIRE_RX_PADDING /* AUTOSAR requirement SWS_CanTp_00349 */ - if (frame->dlc != ISOTP_CAN_DL) { + if (frame->dlc < ISOTP_PADDED_FRAME_DL_MIN) { LOG_ERR("FC DL invalid. Ignore"); send_report_error(ctx, ISOTP_N_ERROR); return; @@ -854,15 +904,14 @@ static void pull_data_ctx(struct isotp_send_ctx *ctx, size_t len) static inline int send_sf(struct isotp_send_ctx *ctx) { - struct can_frame frame = { - .flags = (ctx->tx_addr.flags & ISOTP_MSG_IDE) != 0 ? CAN_FRAME_IDE : 0, - .id = ctx->tx_addr.ext_id - }; + struct can_frame frame; size_t len = get_ctx_data_length(ctx); int index = 0; int ret; const uint8_t *data; + prepare_frame(&frame, &ctx->tx_addr); + data = get_data_ctx(ctx); pull_data_ctx(ctx, len); @@ -870,22 +919,34 @@ static inline int send_sf(struct isotp_send_ctx *ctx) frame.data[index++] = ctx->tx_addr.ext_addr; } - frame.data[index++] = ISOTP_PCI_TYPE_SF | len; + if (IS_ENABLED(CONFIG_CAN_FD_MODE) && (ctx->tx_addr.flags & ISOTP_MSG_FDF) != 0 && + len > ISOTP_4BIT_SF_MAX_CAN_DL - 1 - index) { + frame.data[index++] = ISOTP_PCI_TYPE_SF; + frame.data[index++] = len; + } else { + frame.data[index++] = ISOTP_PCI_TYPE_SF | len; + } - if (len > ISOTP_CAN_DL - index) { + if (len > ctx->tx_addr.dl - index) { LOG_ERR("SF len does not fit DL"); return -ENOSPC; } memcpy(&frame.data[index], data, len); -#ifdef CONFIG_ISOTP_ENABLE_TX_PADDING - /* AUTOSAR requirement SWS_CanTp_00348 */ - memset(&frame.data[index + len], 0xCC, ISOTP_CAN_DL - len - index); - frame.dlc = ISOTP_CAN_DL; -#else - frame.dlc = len + index; -#endif + if (IS_ENABLED(CONFIG_ISOTP_ENABLE_TX_PADDING) || + (IS_ENABLED(CONFIG_CAN_FD_MODE) && (ctx->tx_addr.flags & ISOTP_MSG_FDF) != 0 && + len + index > ISOTP_PADDED_FRAME_DL_MIN)) { + /* AUTOSAR requirements SWS_CanTp_00348 / SWS_CanTp_00351. + * Mandatory for ISO-TP CAN-FD frames > 8 bytes. + */ + frame.dlc = can_bytes_to_dlc( + MAX(ISOTP_PADDED_FRAME_DL_MIN, len + index)); + memset(&frame.data[index + len], ISOTP_PAD_BYTE, + can_dlc_to_bytes(frame.dlc) - len - index); + } else { + frame.dlc = can_bytes_to_dlc(len + index); + } ctx->state = ISOTP_TX_SEND_SF; ret = can_send(ctx->can_dev, &frame, K_MSEC(ISOTP_A), @@ -895,16 +956,16 @@ static inline int send_sf(struct isotp_send_ctx *ctx) static inline int send_ff(struct isotp_send_ctx *ctx) { - struct can_frame frame = { - .flags = (ctx->tx_addr.flags & ISOTP_MSG_IDE) != 0 ? CAN_FRAME_IDE : 0, - .id = ctx->tx_addr.ext_id, - .dlc = ISOTP_CAN_DL - }; + struct can_frame frame; int index = 0; size_t len = get_ctx_data_length(ctx); int ret; const uint8_t *data; + prepare_frame(&frame, &ctx->tx_addr); + + frame.dlc = can_bytes_to_dlc(ctx->tx_addr.dl); + if ((ctx->tx_addr.flags & ISOTP_MSG_EXT_ADDR) != 0) { frame.data[index++] = ctx->tx_addr.ext_addr; } @@ -926,8 +987,8 @@ static inline int send_ff(struct isotp_send_ctx *ctx) */ ctx->sn = 1; data = get_data_ctx(ctx); - pull_data_ctx(ctx, ISOTP_CAN_DL - index); - memcpy(&frame.data[index], data, ISOTP_CAN_DL - index); + pull_data_ctx(ctx, ctx->tx_addr.dl - index); + memcpy(&frame.data[index], data, ctx->tx_addr.dl - index); ret = can_send(ctx->can_dev, &frame, K_MSEC(ISOTP_A), send_can_tx_cb, ctx); @@ -936,16 +997,15 @@ static inline int send_ff(struct isotp_send_ctx *ctx) static inline int send_cf(struct isotp_send_ctx *ctx) { - struct can_frame frame = { - .flags = (ctx->tx_addr.flags & ISOTP_MSG_IDE) != 0 ? CAN_FRAME_IDE : 0, - .id = ctx->tx_addr.ext_id, - }; + struct can_frame frame; int index = 0; int ret; int len; int rem_len; const uint8_t *data; + prepare_frame(&frame, &ctx->tx_addr); + if ((ctx->tx_addr.flags & ISOTP_MSG_EXT_ADDR) != 0) { frame.data[index++] = ctx->tx_addr.ext_addr; } @@ -954,18 +1014,24 @@ static inline int send_cf(struct isotp_send_ctx *ctx) frame.data[index++] = ISOTP_PCI_TYPE_CF | ctx->sn; rem_len = get_ctx_data_length(ctx); - len = MIN(rem_len, ISOTP_CAN_DL - index); + len = MIN(rem_len, ctx->tx_addr.dl - index); rem_len -= len; data = get_data_ctx(ctx); memcpy(&frame.data[index], data, len); -#ifdef CONFIG_ISOTP_ENABLE_TX_PADDING - /* AUTOSAR requirement SWS_CanTp_00348 */ - memset(&frame.data[index + len], 0xCC, ISOTP_CAN_DL - len - index); - frame.dlc = ISOTP_CAN_DL; -#else - frame.dlc = len + index; -#endif + if (IS_ENABLED(CONFIG_ISOTP_ENABLE_TX_PADDING) || + (IS_ENABLED(CONFIG_CAN_FD_MODE) && (ctx->tx_addr.flags & ISOTP_MSG_FDF) != 0 && + len + index > ISOTP_PADDED_FRAME_DL_MIN)) { + /* AUTOSAR requirements SWS_CanTp_00348 / SWS_CanTp_00351. + * Mandatory for ISO-TP CAN-FD frames > 8 bytes. + */ + frame.dlc = can_bytes_to_dlc( + MAX(ISOTP_PADDED_FRAME_DL_MIN, len + index)); + memset(&frame.data[index + len], ISOTP_PAD_BYTE, + can_dlc_to_bytes(frame.dlc) - len - index); + } else { + frame.dlc = can_bytes_to_dlc(len + index); + } ret = can_send(ctx->can_dev, &frame, K_MSEC(ISOTP_A), send_can_tx_cb, ctx); @@ -1116,12 +1182,9 @@ static void send_work_handler(struct k_work *item) static inline int attach_fc_filter(struct isotp_send_ctx *ctx) { - struct can_filter filter = { - .flags = CAN_FILTER_DATA | - ((ctx->rx_addr.flags & ISOTP_MSG_IDE) != 0 ? CAN_FILTER_IDE : 0), - .id = ctx->rx_addr.ext_id, - .mask = CAN_EXT_ID_MASK - }; + struct can_filter filter; + + prepare_filter(&filter, &ctx->rx_addr, CAN_EXT_ID_MASK); ctx->filter_id = can_add_rx_filter(ctx->can_dev, send_can_rx_cb, ctx, &filter); @@ -1138,6 +1201,7 @@ static int send(struct isotp_send_ctx *ctx, const struct device *can_dev, const struct isotp_msg_id *rx_addr, isotp_tx_callback_t complete_cb, void *cb_arg) { + can_mode_t cap; size_t len; int ret; @@ -1145,6 +1209,14 @@ static int send(struct isotp_send_ctx *ctx, const struct device *can_dev, __ASSERT_NO_MSG(can_dev); __ASSERT_NO_MSG(rx_addr && tx_addr); + if ((rx_addr->flags & ISOTP_MSG_FDF) != 0 || (tx_addr->flags & ISOTP_MSG_FDF) != 0) { + ret = can_get_capabilities(can_dev, &cap); + if (ret != 0 || (cap & CAN_MODE_FD) == 0) { + LOG_ERR("CAN controller does not support FD mode"); + return ISOTP_N_ERROR; + } + } + if (complete_cb) { ctx->fin_cb.cb = complete_cb; ctx->fin_cb.arg = cb_arg; @@ -1163,10 +1235,39 @@ static int send(struct isotp_send_ctx *ctx, const struct device *can_dev, k_work_init(&ctx->work, send_work_handler); k_timer_init(&ctx->timer, send_timeout_handler, NULL); + switch (ctx->tx_addr.dl) { + case 0: + if ((ctx->tx_addr.flags & ISOTP_MSG_FDF) == 0) { + ctx->tx_addr.dl = 8; + } else { + ctx->tx_addr.dl = 64; + } + __fallthrough; + case 8: + break; + case 12: + case 16: + case 20: + case 24: + case 32: + case 48: + case 64: + if ((ctx->tx_addr.flags & ISOTP_MSG_FDF) == 0) { + LOG_ERR("TX_DL > 8 only supported with FD mode"); + return ISOTP_N_ERROR; + } + break; + default: + LOG_ERR("Invalid TX_DL: %u", ctx->tx_addr.dl); + return ISOTP_N_ERROR; + } + len = get_ctx_data_length(ctx); LOG_DBG("Send %zu bytes to addr 0x%x and listen on 0x%x", len, ctx->tx_addr.ext_id, ctx->rx_addr.ext_id); - if (len > ISOTP_CAN_DL - ((ctx->tx_addr.flags & ISOTP_MSG_EXT_ADDR) != 0 ? 2 : 1)) { + /* Single frames > 8 bytes use an additional byte for length (CAN-FD only) */ + if (len > ctx->tx_addr.dl - (((tx_addr->flags & ISOTP_MSG_EXT_ADDR) != 0) ? 2 : 1) - + ((ctx->tx_addr.dl > ISOTP_4BIT_SF_MAX_CAN_DL) ? 1 : 0)) { ret = attach_fc_filter(ctx); if (ret) { LOG_ERR("Can't attach fc filter: %d", ret); diff --git a/subsys/canbus/isotp/isotp_internal.h b/subsys/canbus/isotp/isotp_internal.h index 24db459a2ec..ac7c28f1ba2 100644 --- a/subsys/canbus/isotp/isotp_internal.h +++ b/subsys/canbus/isotp/isotp_internal.h @@ -4,38 +4,12 @@ * SPDX-License-Identifier: Apache-2.0 */ -#ifndef ZEPHYR_SUBSYS_NET_CAN_ISOTP_INTERNAL_H_ -#define ZEPHYR_SUBSYS_NET_CAN_ISOTP_INTERNAL_H_ - +#ifndef ZEPHYR_SUBSYS_CANBUS_ISOTP_ISOTP_INTERNAL_H_ +#define ZEPHYR_SUBSYS_CANBUS_ISOTP_ISOTP_INTERNAL_H_ #include #include -/* - * Abbreviations - * BS Block Size - * CAN_DL CAN LL data size - * CF Consecutive Frame - * CTS Continue to send - * DLC Data length code - * FC Flow Control - * FF First Frame - * SF Single Frame - * FS Flow Status - * AE Adders Extension - * SN Sequence Number - * ST Separation time - * PCI Process Control Information - */ - -/* This is for future use when we have CAN-FD */ -#ifdef ISOTP_USE_CAN_FD -/* #define ISOTP_CAN_DL CONFIG_ISOTP_TX_DL* */ -#define ISOTP_CAN_DL 8 -#else -#define ISOTP_CAN_DL 8 -#endif/*ISOTP_USE_CAN_FD*/ - /* Protocol control information*/ #define ISOTP_PCI_SF 0x00 /* Single frame*/ #define ISOTP_PCI_FF 0x01 /* First frame */ @@ -67,7 +41,9 @@ #define ISOTP_PCI_SN_MASK 0x0F -#define ISOTP_FF_DL_MIN (ISOTP_CAN_DL) +#define ISOTP_FF_DL_MIN 8 +#define ISOTP_PADDED_FRAME_DL_MIN 8 +#define ISOTP_PAD_BYTE 0xCC #define ISOTP_STMIN_MAX 0xFA #define ISOTP_STMIN_MS_MAX 0x7F @@ -76,6 +52,8 @@ #define ISOTP_WFT_FIRST 0xFF +#define ISOTP_4BIT_SF_MAX_CAN_DL 8 + #define ISOTP_BS (CONFIG_ISOTP_BS_TIMEOUT) #define ISOTP_A (CONFIG_ISOTP_A_TIMEOUT) #define ISOTP_CR (CONFIG_ISOTP_CR_TIMEOUT) @@ -121,4 +99,4 @@ struct isotp_global_ctx { } #endif -#endif /* ZEPHYR_SUBSYS_NET_CAN_ISOTP_INTERNAL_H_ */ +#endif /* ZEPHYR_SUBSYS_CANBUS_ISOTP_ISOTP_INTERNAL_H_ */