3 #define MAX_DIAGNOSTIC_PAYLOAD_SIZE 6
4 #define MODE_BYTE_INDEX 0
5 #define PID_BYTE_INDEX 1
7 DiagnosticShims diagnostic_init_shims(LogShim log,
8 SendCanMessageShim send_can_message,
9 SetTimerShim set_timer) {
10 DiagnosticShims shims = {
11 send_can_message: send_can_message,
18 DiagnosticRequestHandle diagnostic_request(DiagnosticShims* shims,
19 DiagnosticRequest* request, DiagnosticResponseReceived callback) {
20 DiagnosticRequestHandle handle = {
21 type: DIAGNOSTIC_REQUEST_TYPE_PID,
25 uint8_t payload[MAX_DIAGNOSTIC_PAYLOAD_SIZE];
26 payload[MODE_BYTE_INDEX] = request->mode;
27 if(request->pid_length > 0) {
28 copy_bytes_right_aligned(request->pid, sizeof(request->pid),
29 PID_BYTE_INDEX, request->pid_length, payload, sizeof(payload));
31 if(request->payload_length > 0) {
32 memcpy(payload[PID_BYTE_INDEX + request->pid_length],
33 request->payload, request->payload_length);
36 IsoTpShims isotp_shims = isotp_init_shims(shims->log,
37 shims->send_can_message,
39 handle.status = isotp_send(&isotp_shims, request->arbitration_id,
40 payload, 1 + request->payload_length + request->pid_length,
41 diagnostic_receive_isotp_message);
43 // TODO need to set up an isotp receive handler. in isotp, rx and tx are
44 // kind of intermingled at this point. really, there's not explicit link
45 // between send and receveice...well except for flow control. hm, damn.
46 // so there's 2 things:
48 // isotp_send needs to return a handle. if it was a single frame, we
49 // probably sent it right away so the status true and the callback was hit.
50 // the handle needs another flag to say if it was completed or not, so you
51 // know you can destroy it. you will continue to throw can frames at that
52 // handler until it returns completed (either with a flag, or maybe
53 // receive_can_frame returns true if it's complete)
55 // the second thing is that we need to be able to arbitrarly set up to
56 // receive an iso-tp message on a particular arb id. again, you keep
57 // throwing can frames at it until it returns a handle with the status
58 // completed and calls your callback
60 // so the diagnostic request needs 2 isotp handles and they should both be
61 // hidden from the user
63 // when a can frame is received and passes to the diagnostic handle
64 // if we haven't successfuly sent the entire message yet, give it to the
66 // if we have sent it, give it to the isotp rx handle
67 // if we've received properly, mark this request as completed
71 DiagnosticRequestHandle diagnostic_request_pid(DiagnosticShims* shims,
72 DiagnosticPidRequestType pid_request_type, uint16_t pid,
73 DiagnosticResponseReceived callback) {
74 DiagnosticRequest request = {
75 mode: pid_request_type == DIAGNOSTIC_STANDARD_PID ? 0x1 : 0x22,
79 return diagnostic_request(shims, &request, callback);
82 void diagnostic_receive_isotp_message(const IsoTpMessage* message) {
86 void diagnostic_receive_can_frame(DiagnosticRequestHandle* handle,
87 const uint16_t arbitration_id, const uint8_t data[],
89 isotp_receive_can_frame(handle->isotp_handler, arbitration_id, data, size);
92 // TODO argh, we're now saying that user code will rx CAN messages, but who does
93 // it hand them to? isotp handlers are encapsulated in diagnostic handles
97 // TODO everything below here is for future work...not critical for now.
99 DiagnosticRequestHandle diagnostic_request_malfunction_indicator_status(
100 DiagnosticShims* shims,
101 DiagnosticMilStatusReceived callback) {
102 // TODO request malfunction indicator light (MIL) status - request mode 1
103 // pid 1, parse first bit
106 DiagnosticRequestHandle diagnostic_request_vin(DiagnosticShims* shims,
107 DiagnosticVinReceived callback) {
110 DiagnosticRequestHandle diagnostic_request_dtc(DiagnosticShims* shims,
111 DiagnosticTroubleCodeType dtc_type,
112 DiagnosticTroubleCodesReceived callback) {
115 bool diagnostic_clear_dtc(DiagnosticShims* shims) {
118 DiagnosticRequestHandle diagnostic_enumerate_pids(DiagnosticShims* shims,
119 DiagnosticRequest* request, DiagnosticPidEnumerationReceived callback) {
120 // before calling the callback, split up the received bytes into 1 or 2 byte
121 // chunks depending on the mode so the final pid list is actual 1 or 2 byte PIDs
122 // TODO request supported PIDs - request PID 0 and parse 4 bytes in response