diff --git a/include/canbus/isotp.h b/include/canbus/isotp.h index 60ad12edcee..6fda2525aa4 100644 --- a/include/canbus/isotp.h +++ b/include/canbus/isotp.h @@ -35,7 +35,9 @@ * FC Flow Control * FF First Frame * FS Flow Status - * AE Adders Extension + * AE Address Extension + * SA Source Address + * TA Target Address */ /* @@ -90,6 +92,38 @@ /** Timeout for recv */ #define ISOTP_RECV_TIMEOUT -14 +/* + * CAN ID filtering for ISO-TP fixed addressing according to SAE J1939 + * + * Format of 29-bit CAN identifier: + * ------------------------------------------------------ + * | 28 .. 26 | 25 | 24 | 23 .. 16 | 15 .. 8 | 7 .. 0 | + * ------------------------------------------------------ + * | Priority | EDP | DP | N_TAtype | N_TA | N_SA | + * ------------------------------------------------------ + */ + +/** Position of fixed source address (SA) */ +#define ISOTP_FIXED_ADDR_SA_POS (0U) + +/** Mask to obtain fixed source address (SA) */ +#define ISOTP_FIXED_ADDR_SA_MASK (0xFF << ISOTP_FIXED_ADDR_SA_POS) + +/** Position of fixed target address (TA) */ +#define ISOTP_FIXED_ADDR_TA_POS (8U) + +/** Mask to obtain fixed target address (TA) */ +#define ISOTP_FIXED_ADDR_TA_MASK (0xFF << ISOTP_FIXED_ADDR_TA_POS) + +/** Position of priority in fixed addressing mode */ +#define ISOTP_FIXED_ADDR_PRIO_POS (26U) + +/** Mask for priority in fixed addressing mode */ +#define ISOTP_FIXED_ADDR_PRIO_MASK (0x7 << ISOTP_FIXED_ADDR_PRIO_POS) + +/* CAN filter RX mask to match any priority and source address (SA) */ +#define ISOTP_FIXED_ADDR_RX_MASK (0x03FFFF00) + #ifdef __cplusplus extern "C" { #endif @@ -100,17 +134,24 @@ extern "C" { * Used to pass addresses to the bind and send functions. */ struct isotp_msg_id { - /** Message identifier*/ + /** + * CAN identifier + * + * If ISO-TP fixed addressing is used, isotp_bind ignores SA and + * priority sections and modifies TA section in flow control frames. + */ union { uint32_t std_id : 11; uint32_t ext_id : 29; }; - /** extended address */ + /** ISO-TP extended address (if used) */ uint8_t ext_addr; - /** Indicates the identifier type (standard or extended) */ + /** Indicates the CAN identifier type (standard or extended) */ uint8_t id_type : 1; - /** Indicates if extended addressing is used */ + /** Indicates if ISO-TP extended addressing is used */ uint8_t use_ext_addr : 1; + /** Indicates if ISO-TP fixed addressing (acc. to SAE J1939) is used */ + uint8_t use_fixed_addr : 1; }; /* diff --git a/subsys/canbus/isotp/isotp.c b/subsys/canbus/isotp/isotp.c index f5e8d5f0c3d..e01a62877b5 100644 --- a/subsys/canbus/isotp/isotp.c +++ b/subsys/canbus/isotp/isotp.c @@ -391,6 +391,7 @@ static void process_ff_sf(struct isotp_recv_ctx *ctx, struct zcan_frame *frame) { int index = 0; uint8_t payload_len; + uint32_t rx_sa; /* ISO-TP fixed source address (if used) */ if (ctx->rx_addr.use_ext_addr) { if (frame->data[index++] != ctx->rx_addr.ext_addr) { @@ -398,6 +399,19 @@ static void process_ff_sf(struct isotp_recv_ctx *ctx, struct zcan_frame *frame) } } + if (ctx->rx_addr.use_fixed_addr) { + /* store actual CAN ID used by the sender */ + ctx->rx_addr.ext_id = frame->id; + /* replace TX target address with RX source address */ + rx_sa = (frame->id & ISOTP_FIXED_ADDR_SA_MASK) >> + ISOTP_FIXED_ADDR_SA_POS; + ctx->tx_addr.ext_id &= ~(ISOTP_FIXED_ADDR_TA_MASK); + ctx->tx_addr.ext_id |= rx_sa << ISOTP_FIXED_ADDR_TA_POS; + /* use same priority for TX as in received message */ + ctx->tx_addr.ext_id &= ~(ISOTP_FIXED_ADDR_PRIO_MASK); + ctx->tx_addr.ext_id |= frame->id & ISOTP_FIXED_ADDR_PRIO_MASK; + } + switch (frame->data[index] & ISOTP_PCI_TYPE_MASK) { case ISOTP_PCI_TYPE_FF: LOG_DBG("Got FF IRQ"); @@ -558,12 +572,20 @@ static void receive_can_rx_isr(struct zcan_frame *frame, void *arg) static inline int attach_ff_filter(struct isotp_recv_ctx *ctx) { + uint32_t mask; + + if (ctx->rx_addr.use_fixed_addr) { + mask = ISOTP_FIXED_ADDR_RX_MASK; + } else { + mask = CAN_EXT_ID_MASK; + } + struct zcan_filter filter = { .id_type = ctx->rx_addr.id_type, .rtr = CAN_DATAFRAME, .id = ctx->rx_addr.ext_id, .rtr_mask = 1, - .id_mask = CAN_EXT_ID_MASK + .id_mask = mask }; ctx->filter_id = can_attach_isr(ctx->can_dev, receive_can_rx_isr, ctx, diff --git a/tests/subsys/canbus/isotp/conformance/src/main.c b/tests/subsys/canbus/isotp/conformance/src/main.c index 818c72009da..c78b5466b3c 100644 --- a/tests/subsys/canbus/isotp/conformance/src/main.c +++ b/tests/subsys/canbus/isotp/conformance/src/main.c @@ -110,6 +110,20 @@ const struct isotp_msg_id tx_addr_ext = { .ext_addr = EXT_ADDR }; +const struct isotp_msg_id rx_addr_fixed = { + .ext_id = 0x18DA0201, + .id_type = CAN_EXTENDED_IDENTIFIER, + .use_ext_addr = 0, + .use_fixed_addr = 1 +}; + +const struct isotp_msg_id tx_addr_fixed = { + .ext_id = 0x18DA0102, + .id_type = CAN_EXTENDED_IDENTIFIER, + .use_ext_addr = 0, + .use_fixed_addr = 1 +}; + const struct device *can_dev; struct isotp_recv_ctx recv_ctx; struct isotp_send_ctx send_ctx; @@ -173,8 +187,6 @@ static void get_sf(struct isotp_recv_ctx *recv_ctx, size_t data_size) zassert_equal(ret, 0, "Data differ"); } -#ifdef CONFIG_ISOTP_REQUIRE_RX_PADDING - static void get_sf_ignore(struct isotp_recv_ctx *recv_ctx) { int ret; @@ -183,8 +195,6 @@ static void get_sf_ignore(struct isotp_recv_ctx *recv_ctx) zassert_equal(ret, ISOTP_RECV_TIMEOUT, "recv returned %d", ret); } -#endif - static void send_test_data(const uint8_t *data, size_t len) { int ret; @@ -229,7 +239,8 @@ static void send_frame_series(struct frame_desired *frames, size_t length, { int i, ret; struct zcan_frame frame = { - .id_type = CAN_STANDARD_IDENTIFIER, + .id_type = (id > 0x7FF) ? CAN_EXTENDED_IDENTIFIER : + CAN_STANDARD_IDENTIFIER, .rtr = CAN_DATAFRAME, .id = id }; @@ -274,15 +285,16 @@ static void check_frame_series(struct frame_desired *frames, size_t length, zassert_equal(ret, -EAGAIN, "Expected timeout, but received %d", ret); } -static int attach_msgq(uint32_t id) +static int attach_msgq(uint32_t id, uint32_t mask) { int filter_id; struct zcan_filter filter = { - .id_type = CAN_STANDARD_IDENTIFIER, + .id_type = (id > 0x7FF) ? CAN_EXTENDED_IDENTIFIER : + CAN_STANDARD_IDENTIFIER, .rtr = CAN_DATAFRAME, .id = id, .rtr_mask = 1, - .id_mask = CAN_STD_ID_MASK + .id_mask = mask }; filter_id = can_attach_msgq(can_dev, &frame_msgq, &filter); @@ -326,7 +338,7 @@ static void test_send_sf(void) memcpy(&des_frame.data[1], random_data, DATA_SIZE_SF); des_frame.length = DATA_SIZE_SF + 1; - filter_id = attach_msgq(rx_addr.std_id); + filter_id = attach_msgq(rx_addr.std_id, CAN_STD_ID_MASK); zassert_true((filter_id >= 0), "Negative filter number [%d]", filter_id); @@ -378,7 +390,7 @@ static void test_send_sf_ext(void) memcpy(&des_frame.data[2], random_data, DATA_SIZE_SF_EXT); des_frame.length = DATA_SIZE_SF_EXT + 2; - filter_id = attach_msgq(rx_addr_ext.std_id); + filter_id = attach_msgq(rx_addr_ext.std_id, CAN_STD_ID_MASK); zassert_true((filter_id >= 0), "Negative filter number [%d]", filter_id); @@ -424,6 +436,62 @@ static void test_receive_sf_ext(void) isotp_unbind(&recv_ctx); } +static void test_send_sf_fixed(void) +{ + int filter_id, ret; + struct frame_desired des_frame; + + des_frame.data[0] = SF_PCI_BYTE_1; + memcpy(&des_frame.data[1], random_data, DATA_SIZE_SF); + des_frame.length = DATA_SIZE_SF + 1; + + /* mask to allow any priority and source address (SA) */ + filter_id = attach_msgq(rx_addr_fixed.ext_id, 0x03FFFF00); + zassert_true((filter_id >= 0), "Negative filter number [%d]", + filter_id); + + ret = isotp_send(&send_ctx, can_dev, random_data, DATA_SIZE_SF, + &rx_addr_fixed, &tx_addr_fixed, send_complette_cb, + ISOTP_N_OK); + zassert_equal(ret, 0, "Send returned %d", ret); + + check_frame_series(&des_frame, 1, &frame_msgq); + + can_detach(can_dev, filter_id); +} + +static void test_receive_sf_fixed(void) +{ + int ret; + struct frame_desired single_frame; + + single_frame.data[0] = SF_PCI_BYTE_1; + memcpy(&single_frame.data[1], random_data, DATA_SIZE_SF); + single_frame.length = DATA_SIZE_SF + 1; + + ret = isotp_bind(&recv_ctx, can_dev, &rx_addr_fixed, &tx_addr_fixed, + &fc_opts_single, K_NO_WAIT); + zassert_equal(ret, ISOTP_N_OK, "Binding failed [%d]", ret); + + /* default source address */ + send_frame_series(&single_frame, 1, rx_addr_fixed.ext_id); + get_sf(&recv_ctx, DATA_SIZE_SF); + + /* different source address */ + send_frame_series(&single_frame, 1, rx_addr_fixed.ext_id | 0xFF); + get_sf(&recv_ctx, DATA_SIZE_SF); + + /* different priority */ + send_frame_series(&single_frame, 1, rx_addr_fixed.ext_id | (7U << 26)); + get_sf(&recv_ctx, DATA_SIZE_SF); + + /* different target address (should fail) */ + send_frame_series(&single_frame, 1, rx_addr_fixed.ext_id | 0xFF00); + get_sf_ignore(&recv_ctx); + + isotp_unbind(&recv_ctx); +} + static void test_send_data(void) { struct frame_desired fc_frame, ff_frame; @@ -446,7 +514,7 @@ static void test_send_data(void) prepare_cf_frames(des_frames, ARRAY_SIZE(des_frames), data_ptr, remaining_length); - filter_id = attach_msgq(rx_addr.std_id); + filter_id = attach_msgq(rx_addr.std_id, CAN_STD_ID_MASK); zassert_true((filter_id >= 0), "Negative filter number [%d]", filter_id); @@ -487,7 +555,7 @@ static void test_send_data_blocks(void) remaining_length = DATA_SEND_LENGTH; - filter_id = attach_msgq(rx_addr.std_id); + filter_id = attach_msgq(rx_addr.std_id, CAN_STD_ID_MASK); zassert_true((filter_id >= 0), "Negative filter number [%d]", filter_id); @@ -548,7 +616,7 @@ static void test_receive_data(void) prepare_cf_frames(des_frames, ARRAY_SIZE(des_frames), data_ptr, remaining_length); - filter_id = attach_msgq(tx_addr.std_id); + filter_id = attach_msgq(tx_addr.std_id, CAN_STD_ID_MASK); ret = isotp_bind(&recv_ctx, can_dev, &rx_addr, &tx_addr, &fc_opts_single, K_NO_WAIT); @@ -594,7 +662,7 @@ static void test_receive_data_blocks(void) remaining_frames = CEIL(remaining_length, DATA_SIZE_CF); - filter_id = attach_msgq(tx_addr.std_id); + filter_id = attach_msgq(tx_addr.std_id, CAN_STD_ID_MASK); zassert_true((filter_id >= 0), "Negative filter number [%d]", filter_id); @@ -741,7 +809,7 @@ static void test_stmin(void) fc_frame.data[2] = FC_PCI_BYTE_3(STMIN_VAL_1); fc_frame.length = DATA_SIZE_FC; - filter_id = attach_msgq(rx_addr.std_id); + filter_id = attach_msgq(rx_addr.std_id, CAN_STD_ID_MASK); zassert_true((filter_id >= 0), "Negative filter number [%d]", filter_id); @@ -796,7 +864,7 @@ void test_receiver_fc_errors(void) fc_frame.data[2] = FC_PCI_BYTE_3(fc_opts.stmin); fc_frame.length = DATA_SIZE_FC; - filter_id = attach_msgq(tx_addr.std_id); + filter_id = attach_msgq(tx_addr.std_id, CAN_STD_ID_MASK); zassert_true((filter_id >= 0), "Negative filter number [%d]", filter_id); @@ -836,7 +904,7 @@ void test_sender_fc_errors(void) memcpy(&ff_frame.data[2], random_data, DATA_SIZE_FF); ff_frame.length = DATA_SIZE_FF + 2; - filter_id = attach_msgq(tx_addr.std_id); + filter_id = attach_msgq(tx_addr.std_id, CAN_STD_ID_MASK); /* invalid flow status */ fc_frame.data[0] = FC_PCI_BYTE_1(3); @@ -866,7 +934,7 @@ void test_sender_fc_errors(void) zassert_equal(ret, ISOTP_N_BUFFER_OVERFLW, "Expected overflow but got %d", ret); isotp_unbind(&recv_ctx); - filter_id = attach_msgq(tx_addr.std_id); + filter_id = attach_msgq(tx_addr.std_id, CAN_STD_ID_MASK); k_sem_reset(&send_compl_sem); ret = isotp_send(&send_ctx, can_dev, random_data, DATA_SEND_LENGTH, @@ -918,6 +986,8 @@ void test_main(void) ztest_unit_test(test_receive_sf), ztest_unit_test(test_send_sf_ext), ztest_unit_test(test_receive_sf_ext), + ztest_unit_test(test_send_sf_fixed), + ztest_unit_test(test_receive_sf_fixed), ztest_unit_test(test_send_data), ztest_unit_test(test_send_data_blocks), ztest_unit_test(test_receive_data),