Draft reworking of API.
[apps/agl-service-can-low-level.git] / src / obd2 / obd2.h
1 #ifndef __OBD2_H__
2 #define __OBD2_H__
3
4 #include <isotp/isotp.h>
5 #include <stdint.h>
6 #include <stdbool.h>
7
8 #ifdef __cplusplus
9 extern "C" {
10 #endif
11
12 #define MAX_OBD2_PAYLOAD_LENGTH 7
13 #define VIN_LENGTH 17
14
15 typedef struct {
16     uint16_t arbitration_id;
17     uint8_t mode;
18     uint16_t pid;
19     uint8_t pid_length;
20     uint8_t payload[MAX_OBD2_PAYLOAD_LENGTH];
21     uint8_t payload_length;
22 } DiagnosticRequest;
23
24 // TODO I don't like this, it's hard coding isotp library stuff here
25 typedef bool (*SendIsoTpMessageShim)(IsoTpHandler* handler,
26         const uint8_t* payload, uint16_t payload_size);
27
28 // Thanks to
29 // http://www.canbushack.com/blog/index.php?title=scanning-for-diagnostic-data&more=1&c=1&tb=1&pb=1
30 // for the list of NRCs
31 typedef enum {
32     NRC_SUCCESS = 0x0,
33     NRC_SERVICE_NOT_SUPPORTED = 0x11,
34     NRC_SUB_FUNCTION_NOT_SUPPORTED = 0x12,
35     NRC_CONDITIONS_NOT_CORRECT = 0x22,
36     NRC_REQUEST_OUT_OF_RANGE = 0x31,
37     NRC_SECURITY_ACCESS_DENIED = 0x33,
38     NRC_INVALID_KEY = 0x35,
39     NRC_TOO_MANY_ATTEMPS = 0x36,
40     NRC_TIME_DELAY_NOT_EXPIRED = 0x37,
41     NRC_RESPONSE_PENDING = 0x78
42 } DiagnosticNegativeResponseCode;
43
44 typedef enum {
45     OBD2_MODE_POWERTRAIN_DIAGNOSTIC_REQUEST = 0x1,
46     OBD2_MODE_POWERTRAIN_FREEZE_FRAME_REQUEST = 0x2,
47     OBD2_MODE_EMISSIONS_DTC_REQUEST = 0x3,
48     OBD2_MODE_EMISSIONS_DTC_CLEAR = 0x4,
49     // 0x5 is for non-CAN only
50     // OBD2_MODE_OXYGEN_SENSOR_TEST = 0x5,
51     OBD2_MODE_TEST_RESULTS = 0x6,
52     OBD2_MODE_DRIVE_CYCLE_DTC_REQUEST = 0x7,
53     OBD2_MODE_CONTROL = 0x8,
54     OBD2_MODE_VEHICLE_INFORMATION = 0x9,
55     OBD2_MODE_PERMANENT_DTC_REQUEST = 0xa,
56     // this one isn't technically in OBD2, but both of the enhanced standards
57     // have their PID requests at 0x22
58     OBD2_MODE_ENHANCED_DIAGNOSTIC_REQUEST = 0x22
59 } DiagnosticMode;
60
61 typedef enum {
62     DTC_EMISSIONS,
63     DTC_DRIVE_CYCLE,
64     DTC_PERMANENT
65 } DiagnosticTroubleCodeType;
66
67 typedef struct {
68     uint16_t arbitration_id;
69     uint8_t mode;
70     bool success;
71     // if mode is one with a PID, read the correct numbers of PID bytes (1 or 2)
72     // into this field, then store the remainder of the payload in the payload
73     // field
74     uint16_t pid;
75     DiagnosticNegativeResponseCode negative_response_code;
76     // if response mode is a negative response, read first byte of payload into
77     // NRC and store remainder of payload in payload field
78     uint8_t payload[MAX_OBD2_PAYLOAD_LENGTH];
79     uint8_t payload_length;
80 } DiagnosticResponse;
81
82 typedef enum {
83     POWERTRAIN = 0x0,
84     CHASSIS = 0x1,
85     BODY = 0x2,
86     NETWORK = 0x3
87 } DiagnosticTroubleCodeGroup;
88
89 typedef struct {
90     DiagnosticTroubleCodeGroup group;
91     uint8_t group_num;
92     uint8_t code;
93 } DiagnosticTroubleCode;
94
95 typedef void (*DiagnosticResponseReceived)(const DiagnosticResponse* response);
96 typedef void (*DiagnosticMilStatusReceived)(bool malfunction_indicator_status);
97 typedef void (*DiagnosticVinReceived)(uint8_t vin[]);
98 typedef void (*DiagnosticTroubleCodesReceived)(
99         DiagnosticMode mode, DiagnosticTroubleCode* codes);
100 typedef void (*DiagnosticPidEnumerationReceived)(
101         const DiagnosticResponse* response, uint16_t* pids);
102
103 // TODO should we enumerate every OBD-II PID? need conversion formulas, too
104 typedef struct {
105     uint16_t pid;
106     uint8_t bytes_returned;
107     float min_value;
108     float max_value;
109 } DiagnosticParameter;
110
111 typedef enum {
112     DIAGNOSTIC_REQUEST_TYPE_PID,
113     DIAGNOSTIC_REQUEST_TYPE_DTC,
114     DIAGNOSTIC_REQUEST_TYPE_MIL_STATUS,
115     DIAGNOSTIC_REQUEST_TYPE_VIN
116 } DiagnosticRequestType;
117
118 typedef struct {
119     IsoTpHandler isotp_handler;
120     // TODO the Handle may need to keep the original request, otherwise we can't
121     // compare an incoming CAN message to see if it matches the service / PID!
122     // TODO i'm not sure this type/callback in here is too useful - see the
123     // comments in obd2.c:diagnostic_request
124
125     DiagnosticRequestType type;
126     DiagnosticResponseReceived callback;
127     DiagnosticMilStatusReceived mil_status_callback;
128     DiagnosticVinReceived vin_callback;
129     bool status;
130 } DiagnosticRequestHandle;
131
132 typedef enum {
133     DIAGNOSTIC_STANDARD_PID,
134     DIAGNOSTIC_ENHANCED_PID
135 } DiagnosticPidRequestType;
136
137 typedef struct {
138     SetTimerShim set_timer;
139     SendCanMessageShim send_can_message;
140     LogShim log;
141 } DiagnosticShims;
142
143 DiagnosticShims diagnostic_init_shims(LogShim log,
144         SendCanMessageShim send_can_message,
145         SetTimerShim set_timer);
146
147 DiagnosticRequestHandle diagnostic_request(DiagnosticShims* shims,
148         DiagnosticRequest* request, DiagnosticResponseReceived callback);
149
150 // decide mode 0x1 / 0x22 based on pid type
151 DiagnosticRequestHandle diagnostic_request_pid(DiagnosticShims* shims,
152         DiagnosticPidRequestType pid_request_type, uint16_t pid,
153         DiagnosticResponseReceived callback);
154
155 DiagnosticRequestHandle diagnostic_request_malfunction_indicator_status(
156         DiagnosticShims* shims,
157         DiagnosticMilStatusReceived callback);
158
159 DiagnosticRequestHandle diagnostic_request_vin(DiagnosticShims* shims,
160         DiagnosticVinReceived callback);
161
162 DiagnosticRequestHandle diagnostic_request_dtc(DiagnosticShims* shims,
163         DiagnosticTroubleCodeType dtc_type,
164         DiagnosticTroubleCodesReceived callback);
165
166 bool diagnostic_clear_dtc(DiagnosticShims* shims);
167
168 DiagnosticRequestHandle diagnostic_enumerate_pids(DiagnosticShims* shims,
169         DiagnosticRequest* request, DiagnosticPidEnumerationReceived callback);
170
171 // TODO
172 // void diagnostic_receive_isotp_message(DiagnosticRequestHandle* handle,
173         // const IsoTpMessage* message);
174 void diagnostic_receive_isotp_message(const IsoTpMessage* message);
175
176 void diagnostic_receive_can_frame(DiagnosticRequestHandle* handle,
177         const uint16_t arbitration_id, const uint8_t data[],
178         const uint8_t size);
179
180 #ifdef __cplusplus
181 }
182 #endif
183
184 #endif // __OBD2_H__