Draft reworking of API.
[apps/agl-service-can-low-level.git] / src / obd2 / obd2.c
1 #include <obd2/obd2.h>
2
3 #define MAX_DIAGNOSTIC_PAYLOAD_SIZE 6
4 #define MODE_BYTE_INDEX 0
5 #define PID_BYTE_INDEX 1
6
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,
12         set_timer: set_timer,
13         log: log
14     };
15     return shims;
16 }
17
18 DiagnosticRequestHandle diagnostic_request(DiagnosticShims* shims,
19         DiagnosticRequest* request, DiagnosticResponseReceived callback) {
20     DiagnosticRequestHandle handle = {
21         type: DIAGNOSTIC_REQUEST_TYPE_PID,
22         callback: callback,
23         status: true
24     };
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));
30     }
31     if(request->payload_length > 0) {
32         memcpy(payload[PID_BYTE_INDEX + request->pid_length],
33                 request->payload, request->payload_length);
34     }
35
36     IsoTpShims isotp_shims = isotp_init_shims(shims->log,
37             shims->send_can_message,
38             shims->set_timer);
39     handle.status = isotp_send(&isotp_shims, request->arbitration_id,
40             payload, 1 + request->payload_length + request->pid_length,
41             diagnostic_receive_isotp_message);
42
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:
47     //
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)
54     //
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
59     //
60     // so the diagnostic request needs 2 isotp handles and they should both be
61     // hidden from the user
62     //
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
65     // isottp send handle
66     // if we have sent it, give it to the isotp rx handle
67     // if we've received properly, mark this request as completed
68     return handle;
69 }
70
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,
76         pid: pid
77     };
78
79     return diagnostic_request(shims, &request, callback);
80 }
81
82 void diagnostic_receive_isotp_message(const IsoTpMessage* message) {
83     // TODO
84 }
85
86 void diagnostic_receive_can_frame(DiagnosticRequestHandle* handle,
87         const uint16_t arbitration_id, const uint8_t data[],
88         const uint8_t size) {
89     isotp_receive_can_frame(handle->isotp_handler, arbitration_id, data, size);
90 }
91
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
94
95
96
97 // TODO everything below here is for future work...not critical for now.
98
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
104 }
105
106 DiagnosticRequestHandle diagnostic_request_vin(DiagnosticShims* shims,
107         DiagnosticVinReceived callback) {
108 }
109
110 DiagnosticRequestHandle diagnostic_request_dtc(DiagnosticShims* shims,
111         DiagnosticTroubleCodeType dtc_type,
112         DiagnosticTroubleCodesReceived callback) {
113 }
114
115 bool diagnostic_clear_dtc(DiagnosticShims* shims) {
116 }
117
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
123 }