8 extern bool last_response_was_received;
9 extern DiagnosticResponse last_response_received;
10 extern DiagnosticShims SHIMS;
11 extern uint16_t last_can_frame_sent_arb_id;
12 extern uint8_t last_can_payload_sent[8];
13 extern uint8_t last_can_payload_size;
15 void response_received_handler(const DiagnosticResponse* response) {
16 last_response_was_received = true;
17 last_response_received = *response;
20 START_TEST (test_receive_wrong_arb_id)
22 DiagnosticRequest request = {
23 arbitration_id: OBD2_FUNCTIONAL_BROADCAST_ID,
24 mode: OBD2_MODE_POWERTRAIN_DIAGNOSTIC_REQUEST
26 DiagnosticRequestHandle handle = diagnostic_request(&SHIMS, &request,
27 response_received_handler);
29 fail_if(last_response_was_received);
30 const uint8_t can_data[] = {0x2, request.mode + 0x40, 0x23};
31 diagnostic_receive_can_frame(&SHIMS, &handle, request.arbitration_id,
32 can_data, sizeof(can_data));
33 fail_if(last_response_was_received);
37 START_TEST (test_send_diag_request_with_payload)
39 DiagnosticRequest request = {
40 arbitration_id: OBD2_FUNCTIONAL_BROADCAST_ID,
41 mode: OBD2_MODE_POWERTRAIN_DIAGNOSTIC_REQUEST,
42 payload: {0x12, 0x34},
45 DiagnosticRequestHandle handle = diagnostic_request(&SHIMS, &request,
46 response_received_handler);
48 fail_if(handle.completed);
49 // TODO it'd be better to check the ISO-TP message instead of the CAN frame,
50 // but we don't have a good way to do that
51 ck_assert_int_eq(last_can_frame_sent_arb_id, request.arbitration_id);
52 ck_assert_int_eq(last_can_payload_sent[1], request.mode);
53 ck_assert_int_eq(last_can_payload_size, 4);
54 ck_assert_int_eq(last_can_payload_sent[2], request.payload[0]);
55 ck_assert_int_eq(last_can_payload_sent[3], request.payload[1]);
59 START_TEST (test_send_diag_request)
61 DiagnosticRequest request = {
62 arbitration_id: OBD2_FUNCTIONAL_BROADCAST_ID,
63 mode: OBD2_MODE_EMISSIONS_DTC_REQUEST
65 DiagnosticRequestHandle handle = diagnostic_request(&SHIMS, &request,
66 response_received_handler);
68 fail_if(handle.completed);
69 ck_assert_int_eq(last_can_frame_sent_arb_id, request.arbitration_id);
70 ck_assert_int_eq(last_can_payload_sent[1], request.mode);
71 ck_assert_int_eq(last_can_payload_size, 2);
73 fail_if(last_response_was_received);
74 const uint8_t can_data[] = {0x2, request.mode + 0x40, 0x23};
75 DiagnosticResponse response = diagnostic_receive_can_frame(&SHIMS, &handle,
76 request.arbitration_id + 0x8, can_data, sizeof(can_data));
77 fail_unless(response.success);
78 fail_unless(response.completed);
79 fail_unless(handle.completed);
80 ck_assert(last_response_received.success);
81 ck_assert_int_eq(last_response_received.arbitration_id,
82 request.arbitration_id + 0x8);
83 ck_assert_int_eq(last_response_received.mode, request.mode);
84 ck_assert_int_eq(last_response_received.pid, 0);
85 ck_assert_int_eq(last_response_received.payload_length, 1);
86 ck_assert_int_eq(last_response_received.payload[0], can_data[2]);
90 START_TEST (test_request_pid_standard)
92 uint16_t arb_id = OBD2_MODE_POWERTRAIN_DIAGNOSTIC_REQUEST;
93 DiagnosticRequestHandle handle = diagnostic_request_pid(&SHIMS,
94 DIAGNOSTIC_STANDARD_PID, arb_id, 0x2, response_received_handler);
96 fail_if(last_response_was_received);
97 const uint8_t can_data[] = {0x3, 0x1 + 0x40, 0x2, 0x45};
98 diagnostic_receive_can_frame(&SHIMS, &handle, arb_id + 0x8,
99 can_data, sizeof(can_data));
100 fail_unless(last_response_was_received);
101 ck_assert(last_response_received.success);
102 ck_assert_int_eq(last_response_received.arbitration_id,
104 ck_assert_int_eq(last_response_received.mode, 0x1);
105 ck_assert_int_eq(last_response_received.pid, 0x2);
106 ck_assert_int_eq(last_response_received.payload_length, 1);
107 ck_assert_int_eq(last_response_received.payload[0], can_data[3]);
111 START_TEST (test_request_pid_enhanced)
113 uint16_t arb_id = OBD2_FUNCTIONAL_BROADCAST_ID;
114 DiagnosticRequestHandle handle = diagnostic_request_pid(&SHIMS,
115 DIAGNOSTIC_ENHANCED_PID, arb_id, 0x2, response_received_handler);
117 fail_if(last_response_was_received);
118 const uint8_t can_data[] = {0x4, 0x22 + 0x40, 0x0, 0x2, 0x45};
119 diagnostic_receive_can_frame(&SHIMS, &handle, arb_id + 0x8, can_data,
121 fail_unless(last_response_was_received);
122 ck_assert(last_response_received.success);
123 ck_assert_int_eq(last_response_received.arbitration_id,
125 ck_assert_int_eq(last_response_received.mode, 0x22);
126 ck_assert_int_eq(last_response_received.pid, 0x2);
127 ck_assert_int_eq(last_response_received.payload_length, 1);
128 ck_assert_int_eq(last_response_received.payload[0], can_data[4]);
132 START_TEST (test_wrong_mode_response)
134 uint16_t arb_id = OBD2_FUNCTIONAL_BROADCAST_ID;
135 DiagnosticRequestHandle handle = diagnostic_request_pid(&SHIMS,
136 DIAGNOSTIC_ENHANCED_PID, arb_id, 0x2, response_received_handler);
138 fail_if(last_response_was_received);
139 const uint8_t can_data[] = {0x4, 0x1 + 0x40, 0x0, 0x2, 0x45};
140 diagnostic_receive_can_frame(&SHIMS, &handle, arb_id + 0x8, can_data,
142 // TODO change this if we even re-request a message receipt on a mode or PID
144 fail_unless(last_response_was_received);
145 fail_unless(handle.completed);
146 fail_if(last_response_received.success);
150 START_TEST (test_handle_completed)
152 DiagnosticRequest request = {
153 arbitration_id: OBD2_FUNCTIONAL_BROADCAST_ID,
154 mode: OBD2_MODE_POWERTRAIN_DIAGNOSTIC_REQUEST
156 DiagnosticRequestHandle handle = diagnostic_request(&SHIMS, &request,
157 response_received_handler);
159 fail_if(handle.completed);
161 const uint8_t can_data[] = {0x2, request.mode + 0x40, 0x23};
162 DiagnosticResponse response = diagnostic_receive_can_frame(&SHIMS, &handle,
163 request.arbitration_id + 0x8, can_data, sizeof(can_data));
164 fail_unless(response.success);
165 fail_unless(response.completed);
166 fail_unless(handle.completed);
168 response = diagnostic_receive_can_frame(&SHIMS, &handle,
169 request.arbitration_id + 0x8, can_data, sizeof(can_data));
170 fail_if(response.success);
171 fail_if(response.completed);
172 fail_unless(handle.completed);
174 ck_assert(last_response_received.success);
175 ck_assert_int_eq(last_response_received.arbitration_id,
176 request.arbitration_id + 0x8);
177 ck_assert_int_eq(last_response_received.mode, request.mode);
178 ck_assert_int_eq(last_response_received.pid, 0);
179 ck_assert_int_eq(last_response_received.payload_length, 1);
180 ck_assert_int_eq(last_response_received.payload[0], can_data[2]);
184 START_TEST (test_negative_response)
186 DiagnosticRequest request = {
187 arbitration_id: OBD2_FUNCTIONAL_BROADCAST_ID,
188 mode: OBD2_MODE_POWERTRAIN_DIAGNOSTIC_REQUEST
190 DiagnosticRequestHandle handle = diagnostic_request(&SHIMS, &request,
191 response_received_handler);
192 const uint8_t can_data[] = {0x3, 0x7f, request.mode, NRC_SERVICE_NOT_SUPPORTED};
193 DiagnosticResponse response = diagnostic_receive_can_frame(&SHIMS, &handle,
194 request.arbitration_id + 0x8, can_data, sizeof(can_data));
195 fail_unless(response.completed);
196 fail_if(response.success);
197 fail_unless(handle.completed);
199 fail_if(last_response_received.success);
200 ck_assert_int_eq(last_response_received.arbitration_id,
201 request.arbitration_id + 0x8);
202 ck_assert_int_eq(last_response_received.mode, request.mode);
203 ck_assert_int_eq(last_response_received.pid, 0);
204 ck_assert_int_eq(last_response_received.negative_response_code, NRC_SERVICE_NOT_SUPPORTED);
205 ck_assert_int_eq(last_response_received.payload_length, 0);
209 Suite* testSuite(void) {
210 Suite* s = suite_create("obd2");
211 TCase *tc_core = tcase_create("core");
212 tcase_add_checked_fixture(tc_core, setup, NULL);
213 tcase_add_test(tc_core, test_send_diag_request);
214 tcase_add_test(tc_core, test_send_diag_request_with_payload);
215 tcase_add_test(tc_core, test_receive_wrong_arb_id);
216 tcase_add_test(tc_core, test_request_pid_standard);
217 tcase_add_test(tc_core, test_request_pid_enhanced);
218 tcase_add_test(tc_core, test_wrong_mode_response);
219 tcase_add_test(tc_core, test_handle_completed);
220 tcase_add_test(tc_core, test_negative_response);
222 // TODO these are future work:
223 // TODO test request MIL
224 // TODO test request VIN
225 // TODO test request DTC
226 // TODO test clear DTC
227 // TODO test enumerate PIDs
228 suite_add_tcase(s, tc_core);
235 Suite* s = testSuite();
236 SRunner *sr = srunner_create(s);
237 // Don't fork so we can actually use gdb
238 srunner_set_fork_status(sr, CK_NOFORK);
239 srunner_run_all(sr, CK_NORMAL);
240 numberFailed = srunner_ntests_failed(sr);
242 return (numberFailed == 0) ? 0 : 1;