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