forked from donaloconnor/automon
-
Notifications
You must be signed in to change notification settings - Fork 0
/
dtchelper.cpp
341 lines (274 loc) · 10.3 KB
/
dtchelper.cpp
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
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
/*
==================================================================================================
| dtchelper.cpp |
| Part of the Automon application. |
| |
| Final Year Project - "An Embedded Automotive Monitoring Device" |
| |
| By Donal O' Connor for completion of B.Sc (Hons) Software Development and Computer Networking |
| Email: [email protected] |
| Website/Blog: http://automon.killarneyonline.eu |
| |
| Cork Institute of Technology, Cork, Ireland - http://www.cit.ie/ |
| |
| Copyright © 2009 Donal O'Connor <[email protected]> |
==================================================================================================
Implementation of the DTC Helper. More details below
*/
#include <QFile>
#include "automon.h"
using namespace AutomonKernel;
DTCHelper::DTCHelper(SerialHelper * serialHelper)
: m_serialHelper(serialHelper)
{
/* Assume MIL not on first and no DTC codes present. These will get set in the init stage below */
m_milOn = false;
m_numCodes = 0;
}
void DTCHelper::loadCodes()
{
/*
This method is responsible for opening the code database file and adding each code to the code DB in ram
*/
/* Open DTC Code file */
QFile file(DTCCODEFILE);
if (!file.open(QIODevice::ReadOnly | QIODevice::Text))
return;
/* Create an input stream from the file */
QTextStream in(&file);
while (!in.atEnd())
{
/* While not at end of file, read the line. Split on the tab delimiter */
QString line = in.readLine();
QStringList attributes = line.split("\t");
/* Ensure that size is 2, one for code, another for english meaning */
if (attributes.size() == 2)
m_codeDB.append(new DTC(attributes[0], attributes[1],"")); /* Append a new DTC to code database */
}
}
void DTCHelper::init()
{
/*
This method is responsible for checking the number of codes and setting what codes avaiable in ECU
and if MIL is on/off
*/
/* Set number codes found */
setNumCodes();
/* Load code DB */
loadCodes();
if (m_numCodes > 0)
loadFoundCodes(); /* Only load found codes if codes are present in the ECU */
}
void DTCHelper::setNumCodes()
{
/*
This method is responsible for setting the number of codes on the ECU.
To do this it must send a command to the ELM327 which in turn will query the ECU
*/
/* Create command and send it */
Command mode0101;
mode0101.setCommand("0101");
m_serialHelper->sendCommand(mode0101);
/* Read back bytes in integer format */
QList<int> bytes = Automon::getBytes(mode0101);
/* Do a bit wise and to check if the MIL is on / off as it is bit encoded */
if ((int)(bytes[2] & 0x80) == 128)
m_milOn = true;
/* The number of codes is specified by the lower bytes */
m_numCodes = ((int)(bytes[2] & 0x7F));
}
QList<DTC*> DTCHelper::getCodesFound() const
{
/* Return a list of DTC pointers of the codes found */
return m_codesFound;
}
int DTCHelper::getNumberOfCodes() const
{
/* Return number of codes present in ECU */
return m_numCodes;
}
bool DTCHelper::checkMil() const
{
/* Return a bool, stating if MIL on or off */
return m_milOn;
}
void DTCHelper::refreshDTCInformation()
{
/*
This method is responsible for re checking the ECU for new codes and if MIL set
*/
/* Update number of codes found */
setNumCodes();
if (m_numCodes > 0)
loadFoundCodes(); /* If 1 or more codes, update the DTC code list */
}
void DTCHelper::loadFoundCodes()
{
/*
This method is responsible for creating the list of DTCs found
*/
/* Clear list incase old ones still present */
m_codesFound.clear();
if (m_numCodes == 0)
return;
/*
This is a complicated process since multiple ECU's may exist and '43' is a valid part of a command
so we don't know for sure where our codes are in the returned string
This means we must turn headers on. Capture the header part - Checksum and then use this as a delimiter.
So now we have each string in a QString list, and next read each consecutive bytes.
*/
/* Turn headers on */
Command turnHeadersOn;
turnHeadersOn.setCommand("ATH1");
m_serialHelper->sendCommand(turnHeadersOn);
/* Next send mode3 request */
Command mode3Command;
mode3Command.setCommand("03");
m_serialHelper->sendCommand(mode3Command);
/* Now we must parse the buffer and remove spaces */
QString bufferResponse = mode3Command.getBuffer();
QRegExp removeSpaces( " " );
bufferResponse.replace(removeSpaces, "");
QRegExp removeLineBreak( "\x0D" );
bufferResponse.replace(removeLineBreak, "");
QList<QString> bytes;
QList<QString> unParsedCodes;
if (bufferResponse.at(bufferResponse.size()-1) != '>')
qDebug() << "No prompt character found!";
else
{
/* Remove prompt character */
bufferResponse = bufferResponse.section("",0,bufferResponse.size()-1);
/* Check if buffer is even bytes */
if ((bufferResponse.size() % 2) != 0)
{
#ifdef DEBUGAUTOMON
qDebug() << "Uneven number of bytes, error!";
#endif
}
else
{
/* Get delimiter, ie the header of the message */
QString delimiter = bufferResponse.section("",0,8);
/* Split on header to get lines of codes */
QStringList codeLines = bufferResponse.split(delimiter);
int numCodesAdded = 0;
for (int i = 0; i < codeLines.size(); i++)
{
/* Now for each line we continue reading until we reach the number of codes reported by m_numCodes */
codeLines[i] = codeLines[i].section("",0,codeLines[i].size()-2);
for(int k = 0; k < codeLines[i].size(); k+=4)
{
/* Break if we've reached the number of codes found */
if (++numCodesAdded > m_numCodes)
break;
/* Get code */
QString byte1 = codeLines[i].section("",k+1,k+2);
QString byte2 = codeLines[i].section("",k+3, k+4);
/* Add to unparsed codes. This don't include the P,U prefixes */
unParsedCodes.append(QString(byte1+byte2));
}
}
}
}
/* Now it is time to parse the codes and do a check against our code DB and add them to the foundList if matched */
for(int i = 0; i < unParsedCodes.size(); i++)
{
/* for each code found... do a match against our db */
QByteArray codeType = unParsedCodes[i].section("",0,1).toLatin1();
char codeTypeChar;
qstrcpy(&codeTypeChar,codeType);
QString firstChar;
/* Set the first char of each code depending on its first number */
switch (codeTypeChar)
{
case '0':
firstChar = "P0";
break;
case '1':
firstChar = "P1";
break;
case '2':
firstChar = "P2";
break;
case '3':
firstChar = "P3";
break;
case '4':
firstChar = "C0";
break;
case '5':
firstChar = "C1";
break;
case '6':
firstChar = "C2";
break;
case '7':
firstChar = "C3";
break;
case '8':
firstChar = "B0";
break;
case '9':
firstChar = "B1";
break;
case 'A':
firstChar = "B2";
break;
case 'B':
firstChar = "B3";
break;
case 'C':
firstChar = "U0";
break;
case 'D':
firstChar = "U1";
break;
case 'E':
firstChar = "U2";
break;
case 'F':
firstChar = "U3";
break;
default:
firstChar = "XX";
break;
}
/* Get the remaining part of the DTC */
QString remainingPart = unParsedCodes[i].section("",2,4);
/* Create the full code */
QString thisCode = QString(firstChar+remainingPart);
/* Assume code not foun d*/
bool found = false;
for (int k = 0; k < m_codeDB.size(); k++)
{
if (thisCode.compare(m_codeDB[k]->getCode()) == 0)
{
/* Code is found. Add it to the codes found list */
m_codesFound.append(m_codeDB[k]);
found = true;
break;
}
}
if (!found)
{
/* Now if we did not find a match for all codes, we will still add this code and give unknown english meaning */
m_codesFound.append(new DTC(thisCode,"Unknown Code. Not found in Code DB", "Unknown Solution"));
}
}
/* Turn off headers again */
Command turnHeadersOff;
turnHeadersOff.setCommand("ATH0");
m_serialHelper->sendCommand(turnHeadersOff);
}
bool DTCHelper::resetMilAndClearCodes()
{
/*
This method is responsible for clearing the DTCs and resetting MIL.
This is a simple mode 4 command so create this command and send it to ELM327
*/
Command mode4Reset;
mode4Reset.setCommand("04");
m_serialHelper->sendCommand(mode4Reset);
return true;
}