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: 0x7df,
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: 0x7df,
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: 0x7df,
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 // TODO need a constant for the 7df broadcast functional request
93 uint16_t arb_id = 0x7df;
94 DiagnosticRequestHandle handle = diagnostic_request_pid(&SHIMS,
95 DIAGNOSTIC_STANDARD_PID, arb_id, 0x2, response_received_handler);
97 fail_if(last_response_was_received);
98 const uint8_t can_data[] = {0x3, 0x1 + 0x40, 0x2, 0x45};
99 diagnostic_receive_can_frame(&SHIMS, &handle, arb_id + 0x8,
100 can_data, sizeof(can_data));
101 fail_unless(last_response_was_received);
102 ck_assert(last_response_received.success);
103 ck_assert_int_eq(last_response_received.arbitration_id,
105 ck_assert_int_eq(last_response_received.mode, 0x1);
106 ck_assert_int_eq(last_response_received.pid, 0x2);
107 ck_assert_int_eq(last_response_received.payload_length, 1);
108 ck_assert_int_eq(last_response_received.payload[0], can_data[3]);
112 START_TEST (test_request_pid_enhanced)
114 uint16_t arb_id = 0x7df;
115 DiagnosticRequestHandle handle = diagnostic_request_pid(&SHIMS,
116 DIAGNOSTIC_ENHANCED_PID, arb_id, 0x2, response_received_handler);
118 fail_if(last_response_was_received);
119 const uint8_t can_data[] = {0x4, 0x22 + 0x40, 0x0, 0x2, 0x45};
120 diagnostic_receive_can_frame(&SHIMS, &handle, arb_id + 0x8, can_data,
122 fail_unless(last_response_was_received);
123 ck_assert(last_response_received.success);
124 ck_assert_int_eq(last_response_received.arbitration_id,
126 ck_assert_int_eq(last_response_received.mode, 0x22);
127 ck_assert_int_eq(last_response_received.pid, 0x2);
128 ck_assert_int_eq(last_response_received.payload_length, 1);
129 ck_assert_int_eq(last_response_received.payload[0], can_data[4]);
133 START_TEST (test_wrong_mode_response)
135 uint16_t arb_id = 0x7df;
136 DiagnosticRequestHandle handle = diagnostic_request_pid(&SHIMS,
137 DIAGNOSTIC_ENHANCED_PID, arb_id, 0x2, response_received_handler);
139 fail_if(last_response_was_received);
140 const uint8_t can_data[] = {0x4, 0x1 + 0x40, 0x0, 0x2, 0x45};
141 diagnostic_receive_can_frame(&SHIMS, &handle, arb_id + 0x8, can_data,
143 // TODO change this if we even re-request a message receipt on a mode or PID
145 fail_unless(last_response_was_received);
146 fail_unless(handle.completed);
147 fail_if(last_response_received.success);
151 START_TEST (test_handle_completed)
153 DiagnosticRequest request = {
154 arbitration_id: 0x7df,
155 mode: OBD2_MODE_POWERTRAIN_DIAGNOSTIC_REQUEST
157 DiagnosticRequestHandle handle = diagnostic_request(&SHIMS, &request,
158 response_received_handler);
160 fail_if(handle.completed);
162 const uint8_t can_data[] = {0x2, request.mode + 0x40, 0x23};
163 DiagnosticResponse response = diagnostic_receive_can_frame(&SHIMS, &handle,
164 request.arbitration_id + 0x8, can_data, sizeof(can_data));
165 fail_unless(response.success);
166 fail_unless(response.completed);
167 fail_unless(handle.completed);
169 response = diagnostic_receive_can_frame(&SHIMS, &handle,
170 request.arbitration_id + 0x8, can_data, sizeof(can_data));
171 fail_if(response.success);
172 fail_if(response.completed);
173 fail_unless(handle.completed);
175 ck_assert(last_response_received.success);
176 ck_assert_int_eq(last_response_received.arbitration_id,
177 request.arbitration_id + 0x8);
178 ck_assert_int_eq(last_response_received.mode, request.mode);
179 ck_assert_int_eq(last_response_received.pid, 0);
180 ck_assert_int_eq(last_response_received.payload_length, 1);
181 ck_assert_int_eq(last_response_received.payload[0], can_data[2]);
185 START_TEST (test_negative_response)
187 DiagnosticRequest request = {
188 arbitration_id: 0x7df,
189 mode: OBD2_MODE_POWERTRAIN_DIAGNOSTIC_REQUEST
191 DiagnosticRequestHandle handle = diagnostic_request(&SHIMS, &request,
192 response_received_handler);
193 const uint8_t can_data[] = {0x3, 0x7f, request.mode, NRC_SERVICE_NOT_SUPPORTED};
194 DiagnosticResponse response = diagnostic_receive_can_frame(&SHIMS, &handle,
195 request.arbitration_id + 0x8, can_data, sizeof(can_data));
196 fail_unless(response.completed);
197 fail_if(response.success);
198 fail_unless(handle.completed);
200 fail_if(last_response_received.success);
201 ck_assert_int_eq(last_response_received.arbitration_id,
202 request.arbitration_id + 0x8);
203 ck_assert_int_eq(last_response_received.mode, request.mode);
204 ck_assert_int_eq(last_response_received.pid, 0);
205 ck_assert_int_eq(last_response_received.negative_response_code, NRC_SERVICE_NOT_SUPPORTED);
206 ck_assert_int_eq(last_response_received.payload_length, 0);
210 Suite* testSuite(void) {
211 Suite* s = suite_create("obd2");
212 TCase *tc_core = tcase_create("core");
213 tcase_add_checked_fixture(tc_core, setup, NULL);
214 tcase_add_test(tc_core, test_send_diag_request);
215 tcase_add_test(tc_core, test_send_diag_request_with_payload);
216 tcase_add_test(tc_core, test_receive_wrong_arb_id);
217 tcase_add_test(tc_core, test_request_pid_standard);
218 tcase_add_test(tc_core, test_request_pid_enhanced);
219 tcase_add_test(tc_core, test_wrong_mode_response);
220 tcase_add_test(tc_core, test_handle_completed);
221 tcase_add_test(tc_core, test_negative_response);
223 // TODO these are future work:
224 // TODO test request MIL
225 // TODO test request VIN
226 // TODO test request DTC
227 // TODO test clear DTC
228 // TODO test enumerate PIDs
229 suite_add_tcase(s, tc_core);
236 Suite* s = testSuite();
237 SRunner *sr = srunner_create(s);
238 // Don't fork so we can actually use gdb
239 srunner_set_fork_status(sr, CK_NOFORK);
240 srunner_run_all(sr, CK_NORMAL);
241 numberFailed = srunner_ntests_failed(sr);
243 return (numberFailed == 0) ? 0 : 1;