Skip to content

Commit 6e6ffb3

Browse files
author
Zac Nelson
authored
Multi frame (openxc#6)
* increase payload size just for diag responses to support multi-frame responses. limited to 255 bytes for now. * not all diag requests with modes greater than 0xa have a 2 byte pid. need to check was pid_length should be based on the size of the pid. * remove line that does nothing. * add multi_frame field to DiagnosticResponse and update based on IsoTpMessage. Need this upstream for timeout calls specific to multi frame. * update isotp-c submodule. * update autoset_pid tests. check that pid_length is dynamically set based on pid value. adjust other tests to use 2-byte pid for enhanced diagnostic mode requests. * add test for multi-frame response. * update changelog.
1 parent b2033dd commit 6e6ffb3

File tree

5 files changed

+104
-21
lines changed

5 files changed

+104
-21
lines changed

CHANGELOG.mkd

+4
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# OBD-II Support Library in C
22

3+
## v0.2
4+
5+
* Add support for multi-frame diagnostic responses.
6+
37
## v0.1
48

59
* Initial release

src/uds/uds.c

+5-2
Original file line numberDiff line numberDiff line change
@@ -53,7 +53,9 @@ static void setup_receive_handle(DiagnosticRequestHandle* handle) {
5353
static uint16_t autoset_pid_length(uint8_t mode, uint16_t pid,
5454
uint8_t pid_length) {
5555
if(pid_length == 0) {
56-
if(pid > 0xffff || (mode != 0x3e && mode > 0xa)) {
56+
if(mode <= 0xa || mode == 0x3e ) {
57+
pid_length = 1;
58+
} else if(pid > 0xffff || ((pid & 0xFF00) > 0x0)) {
5759
pid_length = 2;
5860
} else {
5961
pid_length = 1;
@@ -69,7 +71,6 @@ static void send_diagnostic_request(DiagnosticShims* shims,
6971
if(handle->request.has_pid) {
7072
handle->request.pid_length = autoset_pid_length(handle->request.mode,
7173
handle->request.pid, handle->request.pid_length);
72-
handle->request.pid_length = handle->request.pid_length;
7374
set_bitfield(handle->request.pid, PID_BYTE_INDEX * CHAR_BIT,
7475
handle->request.pid_length * CHAR_BIT, payload,
7576
sizeof(payload));
@@ -233,6 +234,7 @@ DiagnosticResponse diagnostic_receive_can_frame(DiagnosticShims* shims,
233234

234235
DiagnosticResponse response = {
235236
arbitration_id: arbitration_id,
237+
multi_frame: false,
236238
success: false,
237239
completed: false
238240
};
@@ -246,6 +248,7 @@ DiagnosticResponse diagnostic_receive_can_frame(DiagnosticShims* shims,
246248
IsoTpMessage message = isotp_continue_receive(&handle->isotp_shims,
247249
&handle->isotp_receive_handles[i], arbitration_id, data,
248250
size);
251+
response.multi_frame = message.multi_frame;
249252

250253
if(message.completed) {
251254
if(message.size > 0) {

src/uds/uds_types.h

+9-5
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,10 @@
99
extern "C" {
1010
#endif
1111

12-
// TODO This isn't true for multi frame messages - we may need to dynamically
13-
// allocate this in the future
14-
#define MAX_UDS_PAYLOAD_LENGTH 7
12+
// TODO This still doesn't have enough space for the largest possible
13+
// multiframe response. May need to dynamically allocate in the future.
14+
#define MAX_UDS_RESPONSE_PAYLOAD_LENGTH 255
15+
#define MAX_UDS_REQUEST_PAYLOAD_LENGTH 7
1516
#define MAX_RESPONDING_ECU_COUNT 8
1617
#define VIN_LENGTH 17
1718

@@ -54,7 +55,7 @@ typedef struct {
5455
bool has_pid;
5556
uint16_t pid;
5657
uint8_t pid_length;
57-
uint8_t payload[MAX_UDS_PAYLOAD_LENGTH];
58+
uint8_t payload[MAX_UDS_REQUEST_PAYLOAD_LENGTH];
5859
uint8_t payload_length;
5960
bool no_frame_padding;
6061
DiagnosticRequestType type;
@@ -92,6 +93,8 @@ typedef enum {
9293
* field isn't valid if 'completed' isn't true. If this is 'false', check
9394
* the negative_response_code field for the reason.
9495
* arbitration_id - The arbitration ID the response was received on.
96+
* multi_frame - True if this response (whether completed or not) required
97+
* multi-frame CAN support. Can be used for updating time-out functions.
9598
* mode - The OBD-II mode for the original request.
9699
* has_pid - If this is a response to a PID request, this will be true and the
97100
* 'pid' field will be valid.
@@ -106,12 +109,13 @@ typedef enum {
106109
typedef struct {
107110
bool completed;
108111
bool success;
112+
bool multi_frame;
109113
uint32_t arbitration_id;
110114
uint8_t mode;
111115
bool has_pid;
112116
uint16_t pid;
113117
DiagnosticNegativeResponseCode negative_response_code;
114-
uint8_t payload[MAX_UDS_PAYLOAD_LENGTH];
118+
uint8_t payload[MAX_UDS_RESPONSE_PAYLOAD_LENGTH];
115119
uint8_t payload_length;
116120
} DiagnosticResponse;
117121

tests/test_core.c

+85-13
Original file line numberDiff line numberDiff line change
@@ -242,14 +242,26 @@ START_TEST (test_autoset_pid_length)
242242
arbitration_id: 0x100,
243243
mode: 0x22,
244244
has_pid: true,
245-
pid: 2,
245+
pid: 0x1234,
246246
no_frame_padding: true
247247
};
248248
diagnostic_request(&SHIMS, &request, response_received_handler);
249249

250250
ck_assert_int_eq(last_can_frame_sent_arb_id, request.arbitration_id);
251251
ck_assert_int_eq(last_can_payload_sent[1], request.mode);
252+
ck_assert_int_eq(last_can_payload_sent[2], (request.pid & 0xFF00) >> 8);
253+
ck_assert_int_eq(last_can_payload_sent[3], request.pid & 0xFF);
252254
ck_assert_int_eq(last_can_payload_size, 4);
255+
256+
request.arbitration_id = 0x101;
257+
request.pid = 0x12;
258+
259+
diagnostic_request(&SHIMS, &request, response_received_handler);
260+
261+
ck_assert_int_eq(last_can_frame_sent_arb_id, request.arbitration_id);
262+
ck_assert_int_eq(last_can_payload_sent[1], request.mode);
263+
ck_assert_int_eq(last_can_payload_sent[2], request.pid);
264+
ck_assert_int_eq(last_can_payload_size, 3);
253265
}
254266
END_TEST
255267

@@ -279,10 +291,10 @@ START_TEST (test_request_pid_enhanced)
279291
{
280292
uint16_t arb_id = 0x100;
281293
DiagnosticRequestHandle handle = diagnostic_request_pid(&SHIMS,
282-
DIAGNOSTIC_ENHANCED_PID, arb_id, 0x2, response_received_handler);
294+
DIAGNOSTIC_ENHANCED_PID, arb_id, 0x1234, response_received_handler);
283295

284296
fail_if(last_response_was_received);
285-
const uint8_t can_data[] = {0x4, 0x22 + 0x40, 0x0, 0x2, 0x45};
297+
const uint8_t can_data[] = {0x4, 0x22 + 0x40, 0x12, 0x34, 0x45};
286298
diagnostic_receive_can_frame(&SHIMS, &handle, arb_id + 0x8, can_data,
287299
sizeof(can_data));
288300
fail_unless(last_response_was_received);
@@ -291,7 +303,7 @@ START_TEST (test_request_pid_enhanced)
291303
arb_id + 0x8);
292304
ck_assert_int_eq(last_response_received.mode, 0x22);
293305
fail_unless(last_response_received.has_pid);
294-
ck_assert_int_eq(last_response_received.pid, 0x2);
306+
ck_assert_int_eq(last_response_received.pid, 0x1234);
295307
ck_assert_int_eq(last_response_received.payload_length, 1);
296308
ck_assert_int_eq(last_response_received.payload[0], can_data[4]);
297309
}
@@ -301,10 +313,10 @@ START_TEST (test_wrong_mode_response)
301313
{
302314
uint16_t arb_id = 0x100;
303315
DiagnosticRequestHandle handle = diagnostic_request_pid(&SHIMS,
304-
DIAGNOSTIC_ENHANCED_PID, arb_id, 0x2, response_received_handler);
316+
DIAGNOSTIC_ENHANCED_PID, arb_id, 0x1234, response_received_handler);
305317

306318
fail_if(last_response_was_received);
307-
const uint8_t can_data[] = {0x4, 0x1 + 0x40, 0x0, 0x2, 0x45};
319+
const uint8_t can_data[] = {0x4, 0x1 + 0x40, 0x12, 0x34, 0x45};
308320
diagnostic_receive_can_frame(&SHIMS, &handle, arb_id + 0x8, can_data,
309321
sizeof(can_data));
310322
fail_if(last_response_was_received);
@@ -316,7 +328,7 @@ START_TEST (test_missing_pid)
316328
{
317329
uint16_t arb_id = 0x100;
318330
DiagnosticRequestHandle handle = diagnostic_request_pid(&SHIMS,
319-
DIAGNOSTIC_ENHANCED_PID, arb_id, 0x2, response_received_handler);
331+
DIAGNOSTIC_ENHANCED_PID, arb_id, 0x1234, response_received_handler);
320332

321333
fail_if(last_response_was_received);
322334
const uint8_t can_data[] = {0x1, 0x22 + 0x40};
@@ -331,10 +343,10 @@ START_TEST (test_wrong_pid_response)
331343
{
332344
uint16_t arb_id = 0x100;
333345
DiagnosticRequestHandle handle = diagnostic_request_pid(&SHIMS,
334-
DIAGNOSTIC_ENHANCED_PID, arb_id, 0x2, response_received_handler);
346+
DIAGNOSTIC_ENHANCED_PID, arb_id, 0x1234, response_received_handler);
335347

336348
fail_if(last_response_was_received);
337-
const uint8_t can_data[] = {0x4, 0x22 + 0x40, 0x0, 0x3, 0x45};
349+
const uint8_t can_data[] = {0x4, 0x22 + 0x40, 0x12, 0x33, 0x45};
338350
diagnostic_receive_can_frame(&SHIMS, &handle, arb_id + 0x8, can_data,
339351
sizeof(can_data));
340352
fail_if(last_response_was_received);
@@ -346,23 +358,23 @@ START_TEST (test_wrong_pid_then_right_completes)
346358
{
347359
uint16_t arb_id = 0x100;
348360
DiagnosticRequestHandle handle = diagnostic_request_pid(&SHIMS,
349-
DIAGNOSTIC_ENHANCED_PID, arb_id, 0x2, response_received_handler);
361+
DIAGNOSTIC_ENHANCED_PID, arb_id, 0x1234, response_received_handler);
350362

351363
fail_if(last_response_was_received);
352-
uint8_t can_data[] = {0x4, 0x22 + 0x40, 0x0, 0x3, 0x45};
364+
uint8_t can_data[] = {0x4, 0x22 + 0x40, 0x12, 0x33, 0x45};
353365
diagnostic_receive_can_frame(&SHIMS, &handle, arb_id + 0x8, can_data,
354366
sizeof(can_data));
355367
fail_if(last_response_was_received);
356368
fail_if(handle.completed);
357369

358-
can_data[3] = 0x2;
370+
can_data[3] = 0x34;
359371
diagnostic_receive_can_frame(&SHIMS, &handle, arb_id + 0x8, can_data,
360372
sizeof(can_data));
361373
fail_unless(last_response_was_received);
362374
fail_unless(handle.completed);
363375
fail_unless(handle.success);
364376
fail_unless(last_response_received.success);
365-
ck_assert_int_eq(last_response_received.pid, 0x2);
377+
ck_assert_int_eq(last_response_received.pid, 0x1234);
366378
}
367379
END_TEST
368380

@@ -407,6 +419,65 @@ START_TEST (test_payload_to_integer)
407419
}
408420
END_TEST
409421

422+
START_TEST (test_response_multi_frame)
423+
{
424+
DiagnosticRequest request = {
425+
arbitration_id: 0x100,
426+
mode: OBD2_MODE_VEHICLE_INFORMATION,
427+
has_pid: true,
428+
pid: 0x2
429+
};
430+
DiagnosticRequestHandle handle = diagnostic_request(&SHIMS, &request,
431+
response_received_handler);
432+
433+
const uint8_t can_data[] = {0x10, 0x14, 0x9 + 0x40, 0x2, 0x1, 0x31, 0x46, 0x4d};
434+
DiagnosticResponse response = diagnostic_receive_can_frame(&SHIMS, &handle,
435+
request.arbitration_id + 0x8, can_data, sizeof(can_data));
436+
437+
fail_unless(can_frame_was_sent);
438+
fail_unless(!response.success);
439+
fail_unless(!response.completed);
440+
fail_unless(response.multi_frame);
441+
ck_assert_int_eq(last_can_frame_sent_arb_id, request.arbitration_id);
442+
ck_assert_int_eq(last_can_payload_sent[0], 0x30);
443+
444+
const uint8_t can_data_1[] = {0x21, 0x43, 0x55, 0x39, 0x4a, 0x39, 0x34, 0x48};
445+
response = diagnostic_receive_can_frame(&SHIMS, &handle,
446+
request.arbitration_id + 0x8, can_data_1, sizeof(can_data_1));
447+
fail_unless(!response.success);
448+
fail_unless(!response.completed);
449+
fail_unless(response.multi_frame);
450+
451+
const uint8_t can_data_2[] = {0x22, 0x55, 0x41, 0x30, 0x34, 0x35, 0x32, 0x34};
452+
response = diagnostic_receive_can_frame(&SHIMS, &handle,
453+
request.arbitration_id + 0x8, can_data_2, sizeof(can_data_2));
454+
fail_unless(response.success);
455+
fail_unless(response.completed);
456+
fail_unless(response.multi_frame);
457+
ck_assert_int_eq(response.mode, OBD2_MODE_VEHICLE_INFORMATION);
458+
ck_assert_int_eq(response.pid, 0x2);
459+
ck_assert_int_eq(response.payload_length, 18);
460+
ck_assert_int_eq(response.payload[0], 0x01);
461+
ck_assert_int_eq(response.payload[1], 0x31);
462+
ck_assert_int_eq(response.payload[2], 0x46);
463+
ck_assert_int_eq(response.payload[3], 0x4d);
464+
ck_assert_int_eq(response.payload[4], 0x43);
465+
ck_assert_int_eq(response.payload[5], 0x55);
466+
ck_assert_int_eq(response.payload[6], 0x39);
467+
ck_assert_int_eq(response.payload[7], 0x4a);
468+
ck_assert_int_eq(response.payload[8], 0x39);
469+
ck_assert_int_eq(response.payload[9], 0x34);
470+
ck_assert_int_eq(response.payload[10], 0x48);
471+
ck_assert_int_eq(response.payload[11], 0x55);
472+
ck_assert_int_eq(response.payload[12], 0x41);
473+
ck_assert_int_eq(response.payload[13], 0x30);
474+
ck_assert_int_eq(response.payload[14], 0x34);
475+
ck_assert_int_eq(response.payload[15], 0x35);
476+
ck_assert_int_eq(response.payload[16], 0x32);
477+
ck_assert_int_eq(response.payload[17], 0x34);
478+
}
479+
END_TEST
480+
410481
Suite* testSuite(void) {
411482
Suite* s = suite_create("uds");
412483
TCase *tc_core = tcase_create("core");
@@ -429,6 +500,7 @@ Suite* testSuite(void) {
429500
tcase_add_test(tc_core, test_wrong_pid_then_right_completes);
430501
tcase_add_test(tc_core, test_negative_response);
431502
tcase_add_test(tc_core, test_payload_to_integer);
503+
tcase_add_test(tc_core, test_response_multi_frame);
432504

433505
// TODO these are future work:
434506
// TODO test request MIL

0 commit comments

Comments
 (0)