Skip to content

Commit 0c8cb05

Browse files
martinjaegernashif
authored andcommitted
canbus: isotp: add fixed addressing feature
Fixed addressing as specified in ISO 15765-2 encodes the source and target address of a device or function inside the CAN ID according to SAE J1939. In order to allow to receive incoming requests from different nodes, the CAN filter mask has to be set such that the source address is ignored in the receive context. In addition to that, flow control frames have to be sent back to the actual source of the request, which requires adjustments to the TX CAN ID. This commit implements above features and thus allows ISO-TP to be used in a network based on SAE J1939 or NMEA-2000. Signed-off-by: Martin Jäger <[email protected]>
1 parent f549614 commit 0c8cb05

File tree

3 files changed

+157
-24
lines changed

3 files changed

+157
-24
lines changed

include/canbus/isotp.h

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,9 @@
3535
* FC Flow Control
3636
* FF First Frame
3737
* FS Flow Status
38-
* AE Adders Extension
38+
* AE Address Extension
39+
* SA Source Address
40+
* TA Target Address
3941
*/
4042

4143
/*
@@ -90,6 +92,38 @@
9092
/** Timeout for recv */
9193
#define ISOTP_RECV_TIMEOUT -14
9294

95+
/*
96+
* CAN ID filtering for ISO-TP fixed addressing according to SAE J1939
97+
*
98+
* Format of 29-bit CAN identifier:
99+
* ------------------------------------------------------
100+
* | 28 .. 26 | 25 | 24 | 23 .. 16 | 15 .. 8 | 7 .. 0 |
101+
* ------------------------------------------------------
102+
* | Priority | EDP | DP | N_TAtype | N_TA | N_SA |
103+
* ------------------------------------------------------
104+
*/
105+
106+
/** Position of fixed source address (SA) */
107+
#define ISOTP_FIXED_ADDR_SA_POS (0U)
108+
109+
/** Mask to obtain fixed source address (SA) */
110+
#define ISOTP_FIXED_ADDR_SA_MASK (0xFF << ISOTP_FIXED_ADDR_SA_POS)
111+
112+
/** Position of fixed target address (TA) */
113+
#define ISOTP_FIXED_ADDR_TA_POS (8U)
114+
115+
/** Mask to obtain fixed target address (TA) */
116+
#define ISOTP_FIXED_ADDR_TA_MASK (0xFF << ISOTP_FIXED_ADDR_TA_POS)
117+
118+
/** Position of priority in fixed addressing mode */
119+
#define ISOTP_FIXED_ADDR_PRIO_POS (26U)
120+
121+
/** Mask for priority in fixed addressing mode */
122+
#define ISOTP_FIXED_ADDR_PRIO_MASK (0x7 << ISOTP_FIXED_ADDR_PRIO_POS)
123+
124+
/* CAN filter RX mask to match any priority and source address (SA) */
125+
#define ISOTP_FIXED_ADDR_RX_MASK (0x03FFFF00)
126+
93127
#ifdef __cplusplus
94128
extern "C" {
95129
#endif
@@ -100,17 +134,24 @@ extern "C" {
100134
* Used to pass addresses to the bind and send functions.
101135
*/
102136
struct isotp_msg_id {
103-
/** Message identifier*/
137+
/**
138+
* CAN identifier
139+
*
140+
* If ISO-TP fixed addressing is used, isotp_bind ignores SA and
141+
* priority sections and modifies TA section in flow control frames.
142+
*/
104143
union {
105144
uint32_t std_id : 11;
106145
uint32_t ext_id : 29;
107146
};
108-
/** extended address */
147+
/** ISO-TP extended address (if used) */
109148
uint8_t ext_addr;
110-
/** Indicates the identifier type (standard or extended) */
149+
/** Indicates the CAN identifier type (standard or extended) */
111150
uint8_t id_type : 1;
112-
/** Indicates if extended addressing is used */
151+
/** Indicates if ISO-TP extended addressing is used */
113152
uint8_t use_ext_addr : 1;
153+
/** Indicates if ISO-TP fixed addressing (acc. to SAE J1939) is used */
154+
uint8_t use_fixed_addr : 1;
114155
};
115156

116157
/*

subsys/canbus/isotp/isotp.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -391,13 +391,27 @@ static void process_ff_sf(struct isotp_recv_ctx *ctx, struct zcan_frame *frame)
391391
{
392392
int index = 0;
393393
uint8_t payload_len;
394+
uint32_t rx_sa; /* ISO-TP fixed source address (if used) */
394395

395396
if (ctx->rx_addr.use_ext_addr) {
396397
if (frame->data[index++] != ctx->rx_addr.ext_addr) {
397398
return;
398399
}
399400
}
400401

402+
if (ctx->rx_addr.use_fixed_addr) {
403+
/* store actual CAN ID used by the sender */
404+
ctx->rx_addr.ext_id = frame->id;
405+
/* replace TX target address with RX source address */
406+
rx_sa = (frame->id & ISOTP_FIXED_ADDR_SA_MASK) >>
407+
ISOTP_FIXED_ADDR_SA_POS;
408+
ctx->tx_addr.ext_id &= ~(ISOTP_FIXED_ADDR_TA_MASK);
409+
ctx->tx_addr.ext_id |= rx_sa << ISOTP_FIXED_ADDR_TA_POS;
410+
/* use same priority for TX as in received message */
411+
ctx->tx_addr.ext_id &= ~(ISOTP_FIXED_ADDR_PRIO_MASK);
412+
ctx->tx_addr.ext_id |= frame->id & ISOTP_FIXED_ADDR_PRIO_MASK;
413+
}
414+
401415
switch (frame->data[index] & ISOTP_PCI_TYPE_MASK) {
402416
case ISOTP_PCI_TYPE_FF:
403417
LOG_DBG("Got FF IRQ");
@@ -558,12 +572,20 @@ static void receive_can_rx_isr(struct zcan_frame *frame, void *arg)
558572

559573
static inline int attach_ff_filter(struct isotp_recv_ctx *ctx)
560574
{
575+
uint32_t mask;
576+
577+
if (ctx->rx_addr.use_fixed_addr) {
578+
mask = ISOTP_FIXED_ADDR_RX_MASK;
579+
} else {
580+
mask = CAN_EXT_ID_MASK;
581+
}
582+
561583
struct zcan_filter filter = {
562584
.id_type = ctx->rx_addr.id_type,
563585
.rtr = CAN_DATAFRAME,
564586
.id = ctx->rx_addr.ext_id,
565587
.rtr_mask = 1,
566-
.id_mask = CAN_EXT_ID_MASK
588+
.id_mask = mask
567589
};
568590

569591
ctx->filter_id = can_attach_isr(ctx->can_dev, receive_can_rx_isr, ctx,

tests/subsys/canbus/isotp/conformance/src/main.c

Lines changed: 88 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,20 @@ const struct isotp_msg_id tx_addr_ext = {
110110
.ext_addr = EXT_ADDR
111111
};
112112

113+
const struct isotp_msg_id rx_addr_fixed = {
114+
.ext_id = 0x18DA0201,
115+
.id_type = CAN_EXTENDED_IDENTIFIER,
116+
.use_ext_addr = 0,
117+
.use_fixed_addr = 1
118+
};
119+
120+
const struct isotp_msg_id tx_addr_fixed = {
121+
.ext_id = 0x18DA0102,
122+
.id_type = CAN_EXTENDED_IDENTIFIER,
123+
.use_ext_addr = 0,
124+
.use_fixed_addr = 1
125+
};
126+
113127
const struct device *can_dev;
114128
struct isotp_recv_ctx recv_ctx;
115129
struct isotp_send_ctx send_ctx;
@@ -173,8 +187,6 @@ static void get_sf(struct isotp_recv_ctx *recv_ctx, size_t data_size)
173187
zassert_equal(ret, 0, "Data differ");
174188
}
175189

176-
#ifdef CONFIG_ISOTP_REQUIRE_RX_PADDING
177-
178190
static void get_sf_ignore(struct isotp_recv_ctx *recv_ctx)
179191
{
180192
int ret;
@@ -183,8 +195,6 @@ static void get_sf_ignore(struct isotp_recv_ctx *recv_ctx)
183195
zassert_equal(ret, ISOTP_RECV_TIMEOUT, "recv returned %d", ret);
184196
}
185197

186-
#endif
187-
188198
static void send_test_data(const uint8_t *data, size_t len)
189199
{
190200
int ret;
@@ -229,7 +239,8 @@ static void send_frame_series(struct frame_desired *frames, size_t length,
229239
{
230240
int i, ret;
231241
struct zcan_frame frame = {
232-
.id_type = CAN_STANDARD_IDENTIFIER,
242+
.id_type = (id > 0x7FF) ? CAN_EXTENDED_IDENTIFIER :
243+
CAN_STANDARD_IDENTIFIER,
233244
.rtr = CAN_DATAFRAME,
234245
.id = id
235246
};
@@ -274,15 +285,16 @@ static void check_frame_series(struct frame_desired *frames, size_t length,
274285
zassert_equal(ret, -EAGAIN, "Expected timeout, but received %d", ret);
275286
}
276287

277-
static int attach_msgq(uint32_t id)
288+
static int attach_msgq(uint32_t id, uint32_t mask)
278289
{
279290
int filter_id;
280291
struct zcan_filter filter = {
281-
.id_type = CAN_STANDARD_IDENTIFIER,
292+
.id_type = (id > 0x7FF) ? CAN_EXTENDED_IDENTIFIER :
293+
CAN_STANDARD_IDENTIFIER,
282294
.rtr = CAN_DATAFRAME,
283295
.id = id,
284296
.rtr_mask = 1,
285-
.id_mask = CAN_STD_ID_MASK
297+
.id_mask = mask
286298
};
287299

288300
filter_id = can_attach_msgq(can_dev, &frame_msgq, &filter);
@@ -326,7 +338,7 @@ static void test_send_sf(void)
326338
memcpy(&des_frame.data[1], random_data, DATA_SIZE_SF);
327339
des_frame.length = DATA_SIZE_SF + 1;
328340

329-
filter_id = attach_msgq(rx_addr.std_id);
341+
filter_id = attach_msgq(rx_addr.std_id, CAN_STD_ID_MASK);
330342
zassert_true((filter_id >= 0), "Negative filter number [%d]",
331343
filter_id);
332344

@@ -378,7 +390,7 @@ static void test_send_sf_ext(void)
378390
memcpy(&des_frame.data[2], random_data, DATA_SIZE_SF_EXT);
379391
des_frame.length = DATA_SIZE_SF_EXT + 2;
380392

381-
filter_id = attach_msgq(rx_addr_ext.std_id);
393+
filter_id = attach_msgq(rx_addr_ext.std_id, CAN_STD_ID_MASK);
382394
zassert_true((filter_id >= 0), "Negative filter number [%d]",
383395
filter_id);
384396

@@ -424,6 +436,62 @@ static void test_receive_sf_ext(void)
424436
isotp_unbind(&recv_ctx);
425437
}
426438

439+
static void test_send_sf_fixed(void)
440+
{
441+
int filter_id, ret;
442+
struct frame_desired des_frame;
443+
444+
des_frame.data[0] = SF_PCI_BYTE_1;
445+
memcpy(&des_frame.data[1], random_data, DATA_SIZE_SF);
446+
des_frame.length = DATA_SIZE_SF + 1;
447+
448+
/* mask to allow any priority and source address (SA) */
449+
filter_id = attach_msgq(rx_addr_fixed.ext_id, 0x03FFFF00);
450+
zassert_true((filter_id >= 0), "Negative filter number [%d]",
451+
filter_id);
452+
453+
ret = isotp_send(&send_ctx, can_dev, random_data, DATA_SIZE_SF,
454+
&rx_addr_fixed, &tx_addr_fixed, send_complette_cb,
455+
ISOTP_N_OK);
456+
zassert_equal(ret, 0, "Send returned %d", ret);
457+
458+
check_frame_series(&des_frame, 1, &frame_msgq);
459+
460+
can_detach(can_dev, filter_id);
461+
}
462+
463+
static void test_receive_sf_fixed(void)
464+
{
465+
int ret;
466+
struct frame_desired single_frame;
467+
468+
single_frame.data[0] = SF_PCI_BYTE_1;
469+
memcpy(&single_frame.data[1], random_data, DATA_SIZE_SF);
470+
single_frame.length = DATA_SIZE_SF + 1;
471+
472+
ret = isotp_bind(&recv_ctx, can_dev, &rx_addr_fixed, &tx_addr_fixed,
473+
&fc_opts_single, K_NO_WAIT);
474+
zassert_equal(ret, ISOTP_N_OK, "Binding failed [%d]", ret);
475+
476+
/* default source address */
477+
send_frame_series(&single_frame, 1, rx_addr_fixed.ext_id);
478+
get_sf(&recv_ctx, DATA_SIZE_SF);
479+
480+
/* different source address */
481+
send_frame_series(&single_frame, 1, rx_addr_fixed.ext_id | 0xFF);
482+
get_sf(&recv_ctx, DATA_SIZE_SF);
483+
484+
/* different priority */
485+
send_frame_series(&single_frame, 1, rx_addr_fixed.ext_id | (7U << 26));
486+
get_sf(&recv_ctx, DATA_SIZE_SF);
487+
488+
/* different target address (should fail) */
489+
send_frame_series(&single_frame, 1, rx_addr_fixed.ext_id | 0xFF00);
490+
get_sf_ignore(&recv_ctx);
491+
492+
isotp_unbind(&recv_ctx);
493+
}
494+
427495
static void test_send_data(void)
428496
{
429497
struct frame_desired fc_frame, ff_frame;
@@ -446,7 +514,7 @@ static void test_send_data(void)
446514
prepare_cf_frames(des_frames, ARRAY_SIZE(des_frames), data_ptr,
447515
remaining_length);
448516

449-
filter_id = attach_msgq(rx_addr.std_id);
517+
filter_id = attach_msgq(rx_addr.std_id, CAN_STD_ID_MASK);
450518
zassert_true((filter_id >= 0), "Negative filter number [%d]",
451519
filter_id);
452520

@@ -487,7 +555,7 @@ static void test_send_data_blocks(void)
487555

488556
remaining_length = DATA_SEND_LENGTH;
489557

490-
filter_id = attach_msgq(rx_addr.std_id);
558+
filter_id = attach_msgq(rx_addr.std_id, CAN_STD_ID_MASK);
491559
zassert_true((filter_id >= 0), "Negative filter number [%d]",
492560
filter_id);
493561

@@ -548,7 +616,7 @@ static void test_receive_data(void)
548616
prepare_cf_frames(des_frames, ARRAY_SIZE(des_frames), data_ptr,
549617
remaining_length);
550618

551-
filter_id = attach_msgq(tx_addr.std_id);
619+
filter_id = attach_msgq(tx_addr.std_id, CAN_STD_ID_MASK);
552620

553621
ret = isotp_bind(&recv_ctx, can_dev, &rx_addr, &tx_addr,
554622
&fc_opts_single, K_NO_WAIT);
@@ -594,7 +662,7 @@ static void test_receive_data_blocks(void)
594662

595663
remaining_frames = CEIL(remaining_length, DATA_SIZE_CF);
596664

597-
filter_id = attach_msgq(tx_addr.std_id);
665+
filter_id = attach_msgq(tx_addr.std_id, CAN_STD_ID_MASK);
598666
zassert_true((filter_id >= 0), "Negative filter number [%d]",
599667
filter_id);
600668

@@ -741,7 +809,7 @@ static void test_stmin(void)
741809
fc_frame.data[2] = FC_PCI_BYTE_3(STMIN_VAL_1);
742810
fc_frame.length = DATA_SIZE_FC;
743811

744-
filter_id = attach_msgq(rx_addr.std_id);
812+
filter_id = attach_msgq(rx_addr.std_id, CAN_STD_ID_MASK);
745813
zassert_true((filter_id >= 0), "Negative filter number [%d]",
746814
filter_id);
747815

@@ -796,7 +864,7 @@ void test_receiver_fc_errors(void)
796864
fc_frame.data[2] = FC_PCI_BYTE_3(fc_opts.stmin);
797865
fc_frame.length = DATA_SIZE_FC;
798866

799-
filter_id = attach_msgq(tx_addr.std_id);
867+
filter_id = attach_msgq(tx_addr.std_id, CAN_STD_ID_MASK);
800868
zassert_true((filter_id >= 0), "Negative filter number [%d]",
801869
filter_id);
802870

@@ -836,7 +904,7 @@ void test_sender_fc_errors(void)
836904
memcpy(&ff_frame.data[2], random_data, DATA_SIZE_FF);
837905
ff_frame.length = DATA_SIZE_FF + 2;
838906

839-
filter_id = attach_msgq(tx_addr.std_id);
907+
filter_id = attach_msgq(tx_addr.std_id, CAN_STD_ID_MASK);
840908

841909
/* invalid flow status */
842910
fc_frame.data[0] = FC_PCI_BYTE_1(3);
@@ -866,7 +934,7 @@ void test_sender_fc_errors(void)
866934
zassert_equal(ret, ISOTP_N_BUFFER_OVERFLW,
867935
"Expected overflow but got %d", ret);
868936
isotp_unbind(&recv_ctx);
869-
filter_id = attach_msgq(tx_addr.std_id);
937+
filter_id = attach_msgq(tx_addr.std_id, CAN_STD_ID_MASK);
870938

871939
k_sem_reset(&send_compl_sem);
872940
ret = isotp_send(&send_ctx, can_dev, random_data, DATA_SEND_LENGTH,
@@ -918,6 +986,8 @@ void test_main(void)
918986
ztest_unit_test(test_receive_sf),
919987
ztest_unit_test(test_send_sf_ext),
920988
ztest_unit_test(test_receive_sf_ext),
989+
ztest_unit_test(test_send_sf_fixed),
990+
ztest_unit_test(test_receive_sf_fixed),
921991
ztest_unit_test(test_send_data),
922992
ztest_unit_test(test_send_data_blocks),
923993
ztest_unit_test(test_receive_data),

0 commit comments

Comments
 (0)