diff options
-rw-r--r-- | src/uds/uds.c | 83 | ||||
-rw-r--r-- | src/uds/uds.h | 32 | ||||
-rw-r--r-- | tests/test_core.c | 69 |
3 files changed, 145 insertions, 39 deletions
diff --git a/src/uds/uds.c b/src/uds/uds.c index 4e237446..7303677a 100644 --- a/src/uds/uds.c +++ b/src/uds/uds.c @@ -61,7 +61,45 @@ static uint16_t autoset_pid_length(uint8_t mode, uint16_t pid, return pid_length; } -DiagnosticRequestHandle diagnostic_request(DiagnosticShims* shims, +static void send_diagnostic_request(DiagnosticShims* shims, + DiagnosticRequestHandle* handle) { + uint8_t payload[MAX_DIAGNOSTIC_PAYLOAD_SIZE] = {0}; + payload[MODE_BYTE_INDEX] = handle->request.mode; + if(handle->request.has_pid) { + handle->request.pid_length = autoset_pid_length(handle->request.mode, + handle->request.pid, handle->request.pid_length); + handle->request.pid_length = handle->request.pid_length; + set_bitfield(handle->request.pid, PID_BYTE_INDEX * CHAR_BIT, + handle->request.pid_length * CHAR_BIT, payload, + sizeof(payload)); + } + + if(handle->request.payload_length > 0) { + memcpy(&payload[PID_BYTE_INDEX + handle->request.pid_length], + handle->request.payload, handle->request.payload_length); + } + + handle->isotp_send_handle = isotp_send(&handle->isotp_shims, + handle->request.arbitration_id, payload, + 1 + handle->request.payload_length + handle->request.pid_length, + NULL); + if(shims->log != NULL) { + char request_string[128] = {0}; + diagnostic_request_to_string(&handle->request, request_string, + sizeof(request_string)); + shims->log("Sending diagnostic request: %s", request_string); + } +} + +void start_diagnostic_request(DiagnosticShims* shims, + DiagnosticRequestHandle* handle) { + handle->success = false; + handle->completed = false; + send_diagnostic_request(shims, handle); + setup_receive_handle(handle); +} + +DiagnosticRequestHandle generate_diagnostic_request(DiagnosticShims* shims, DiagnosticRequest* request, DiagnosticResponseReceived callback) { DiagnosticRequestHandle handle = { request: *request, @@ -70,37 +108,12 @@ DiagnosticRequestHandle diagnostic_request(DiagnosticShims* shims, completed: false }; - uint8_t payload[MAX_DIAGNOSTIC_PAYLOAD_SIZE] = {0}; - payload[MODE_BYTE_INDEX] = request->mode; - if(request->has_pid) { - request->pid_length = autoset_pid_length(request->mode, - request->pid, request->pid_length); - handle.request.pid_length = request->pid_length; - set_bitfield(request->pid, PID_BYTE_INDEX * CHAR_BIT, - request->pid_length * CHAR_BIT, payload, sizeof(payload)); - } - if(request->payload_length > 0) { - memcpy(&payload[PID_BYTE_INDEX + request->pid_length], - request->payload, request->payload_length); - } - handle.isotp_shims = isotp_init_shims(shims->log, shims->send_can_message, shims->set_timer); handle.isotp_shims.frame_padding = !request->no_frame_padding; - handle.isotp_send_handle = isotp_send(&handle.isotp_shims, - request->arbitration_id, payload, - 1 + request->payload_length + request->pid_length, - NULL); - if(shims->log != NULL) { - char request_string[128] = {0}; - diagnostic_request_to_string(request, request_string, sizeof(request_string)); - shims->log("Sending diagnostic request: %s", request_string); - } - - setup_receive_handle(&handle); - + return handle; // TODO notes on multi frame: // TODO what are the timers for exactly? // @@ -118,6 +131,13 @@ DiagnosticRequestHandle diagnostic_request(DiagnosticShims* shims, // of the information but arg, memory allocation. look at how it's done in // the other library again // +} + +DiagnosticRequestHandle diagnostic_request(DiagnosticShims* shims, + DiagnosticRequest* request, DiagnosticResponseReceived callback) { + DiagnosticRequestHandle handle = generate_diagnostic_request( + shims, request, callback); + start_diagnostic_request(shims, &handle); return handle; } @@ -217,11 +237,14 @@ DiagnosticResponse diagnostic_receive_can_frame(DiagnosticShims* shims, if(message.size > 0) { response.mode = message.payload[0]; if(handle_negative_response(&message, &response, shims) || - handle_positive_response(handle, &message, &response, shims)) { + handle_positive_response(handle, &message, + &response, shims)) { if(shims->log != NULL) { char response_string[128] = {0}; - diagnostic_response_to_string(&response, response_string, sizeof(response_string)); - shims->log("Diagnostic response received: %s", response_string); + diagnostic_response_to_string(&response, + response_string, sizeof(response_string)); + shims->log("Diagnostic response received: %s", + response_string); } handle->success = true; diff --git a/src/uds/uds.h b/src/uds/uds.h index 0d40561a..22ff36af 100644 --- a/src/uds/uds.h +++ b/src/uds/uds.h @@ -26,8 +26,8 @@ DiagnosticShims diagnostic_init_shims(LogShim log, SendCanMessageShim send_can_message, SetTimerShim set_timer); -/* Public: Initiate a diagnostic request and return a handle, ready to completly - * send the request and process the response via +/* Public: Generate a new diagnostic request, send the first CAN message frame + * and set up the handle required to process the response via * diagnostic_receive_can_frame(...). * * shims - Low-level shims required to send CAN messages, etc. @@ -38,11 +38,37 @@ DiagnosticShims diagnostic_init_shims(LogShim log, * Returns a handle to be used with diagnostic_receive_can_frame to complete * sending the request and receive the response. The 'completed' field in the * returned DiagnosticRequestHandle will be true when the message is completely - * sent. + * sent. The first frame of the message will already be sent. */ DiagnosticRequestHandle diagnostic_request(DiagnosticShims* shims, DiagnosticRequest* request, DiagnosticResponseReceived callback); +/* Public: Generate the handle for a new diagnostic request, but do not send any + * data to CAN yet - you must call start_diagnostic_request(...) on the handle + * returned from this function actually kick off the request. + * + * shims - Low-level shims required to send CAN messages, etc. + * request - + * callback - an optional function to be called when the response is receved + * (use NULL if no callback is required). + * + * Returns a handle to be used with start_diagnostic_request and then + * diagnostic_receive_can_frame to complete sending the request and receive the + * response. The 'completed' field in the returned DiagnosticRequestHandle will + * be true when the message is completely sent. + */ +DiagnosticRequestHandle generate_diagnostic_request(DiagnosticShims* shims, + DiagnosticRequest* request, DiagnosticResponseReceived callback); + +/* Public: Send the first frame of the request to CAN for the handle, generated + * by generate_diagnostic_request. + * + * You can also call this method to re-do the request for a handle that has + * already completed. + */ +void start_diagnostic_request(DiagnosticShims* shims, + DiagnosticRequestHandle* handle); + /* Public: Request a PID from the given arbitration ID, determining the mode * automatically based on the PID type. * diff --git a/tests/test_core.c b/tests/test_core.c index 30d19f41..448c0cd6 100644 --- a/tests/test_core.c +++ b/tests/test_core.c @@ -4,6 +4,7 @@ #include <stdio.h> #include <stdbool.h> +extern bool can_frame_was_sent; extern void setup(); extern bool last_response_was_received; extern DiagnosticResponse last_response_received; @@ -77,8 +78,8 @@ START_TEST (test_send_functional_request) for(uint16_t filter = OBD2_FUNCTIONAL_RESPONSE_START; filter < OBD2_FUNCTIONAL_RESPONSE_START + OBD2_FUNCTIONAL_RESPONSE_COUNT; filter++) { - DiagnosticResponse response = diagnostic_receive_can_frame(&SHIMS, &handle, - filter, can_data, sizeof(can_data)); + DiagnosticResponse response = diagnostic_receive_can_frame(&SHIMS, + &handle, filter, can_data, sizeof(can_data)); fail_unless(response.success); fail_unless(response.completed); fail_unless(handle.completed); @@ -151,6 +152,7 @@ START_TEST (test_send_diag_request) response_received_handler); fail_if(handle.completed); + fail_unless(can_frame_was_sent); ck_assert_int_eq(last_can_frame_sent_arb_id, request.arbitration_id); ck_assert_int_eq(last_can_payload_sent[1], request.mode); ck_assert_int_eq(last_can_payload_size, 2); @@ -172,6 +174,57 @@ START_TEST (test_send_diag_request) } END_TEST +START_TEST (test_generate_then_send_request) +{ + DiagnosticRequest request = { + arbitration_id: 0x100, + mode: OBD2_MODE_EMISSIONS_DTC_REQUEST, + no_frame_padding: true + }; + DiagnosticRequestHandle handle = generate_diagnostic_request(&SHIMS, + &request, response_received_handler); + + fail_if(handle.completed); + fail_if(can_frame_was_sent); + + start_diagnostic_request(&SHIMS, &handle); + fail_unless(can_frame_was_sent); + ck_assert_int_eq(last_can_frame_sent_arb_id, request.arbitration_id); + ck_assert_int_eq(last_can_payload_sent[1], request.mode); + ck_assert_int_eq(last_can_payload_size, 2); + + fail_if(last_response_was_received); + const uint8_t can_data[] = {0x2, request.mode + 0x40, 0x23}; + DiagnosticResponse response = diagnostic_receive_can_frame(&SHIMS, &handle, + request.arbitration_id + 0x8, can_data, sizeof(can_data)); + fail_unless(response.success); + fail_unless(response.completed); + fail_unless(handle.completed); + ck_assert(last_response_received.success); + ck_assert_int_eq(last_response_received.arbitration_id, + request.arbitration_id + 0x8); + ck_assert_int_eq(last_response_received.mode, request.mode); + fail_if(last_response_received.has_pid); + ck_assert_int_eq(last_response_received.payload_length, 1); + ck_assert_int_eq(last_response_received.payload[0], can_data[2]); +} +END_TEST + +START_TEST (test_generate_diag_request) +{ + DiagnosticRequest request = { + arbitration_id: 0x100, + mode: OBD2_MODE_EMISSIONS_DTC_REQUEST, + no_frame_padding: true + }; + DiagnosticRequestHandle handle = generate_diagnostic_request(&SHIMS, + &request, response_received_handler); + + fail_if(handle.completed); + fail_if(can_frame_was_sent); +} +END_TEST + START_TEST (test_autoset_pid_length) { uint16_t arb_id = OBD2_MODE_POWERTRAIN_DIAGNOSTIC_REQUEST; @@ -321,7 +374,8 @@ START_TEST (test_negative_response) }; DiagnosticRequestHandle handle = diagnostic_request(&SHIMS, &request, response_received_handler); - const uint8_t can_data[] = {0x3, 0x7f, request.mode, NRC_SERVICE_NOT_SUPPORTED}; + const uint8_t can_data[] = {0x3, 0x7f, request.mode, + NRC_SERVICE_NOT_SUPPORTED}; DiagnosticResponse response = diagnostic_receive_can_frame(&SHIMS, &handle, request.arbitration_id + 0x8, can_data, sizeof(can_data)); fail_unless(response.completed); @@ -333,7 +387,8 @@ START_TEST (test_negative_response) request.arbitration_id + 0x8); ck_assert_int_eq(last_response_received.mode, request.mode); ck_assert_int_eq(last_response_received.pid, 0); - ck_assert_int_eq(last_response_received.negative_response_code, NRC_SERVICE_NOT_SUPPORTED); + ck_assert_int_eq(last_response_received.negative_response_code, + NRC_SERVICE_NOT_SUPPORTED); ck_assert_int_eq(last_response_received.payload_length, 0); } END_TEST @@ -346,8 +401,8 @@ START_TEST (test_payload_to_integer) fail_if(last_response_was_received); const uint8_t can_data[] = {0x4, 0x1 + 0x40, 0x2, 0x45, 0x12}; - DiagnosticResponse response = diagnostic_receive_can_frame(&SHIMS, &handle, arb_id + 0x8, - can_data, sizeof(can_data)); + DiagnosticResponse response = diagnostic_receive_can_frame(&SHIMS, &handle, + arb_id + 0x8, can_data, sizeof(can_data)); ck_assert_int_eq(diagnostic_payload_to_integer(&response), 0x4512); } END_TEST @@ -359,6 +414,8 @@ Suite* testSuite(void) { tcase_add_test(tc_core, test_sent_message_no_padding); tcase_add_test(tc_core, test_sent_message_is_padded); tcase_add_test(tc_core, test_sent_message_is_padded_by_default); + tcase_add_test(tc_core, test_generate_diag_request); + tcase_add_test(tc_core, test_generate_then_send_request); tcase_add_test(tc_core, test_send_diag_request); tcase_add_test(tc_core, test_send_functional_request); tcase_add_test(tc_core, test_send_diag_request_with_payload); |