1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 package org.diyefi.openlogviewer.decoder;
24
25
26 import java.io.File;
27 import java.io.FileInputStream;
28 import java.io.IOException;
29 import java.util.Arrays;
30
31 import org.diyefi.openlogviewer.decoder.LogField.types;
32 import org.diyefi.openlogviewer.genericlog.GenericLog;
33
34
35
36
37
38
39
40
41 public class FreeEMSBin implements Runnable {
42
43 private final int minimumPacketLength = 3;
44 private final int maximumPacketLength = 0x0820;
45 private final int payloadIDToParse = 0x0191;
46
47
48 private final short ESCAPE_BYTE = 0xBB;
49 private final short START_BYTE = 0xAA;
50 private final short STOP_BYTE = 0xCC;
51 private final short ESCAPED_ESCAPE_BYTE = 0x44;
52 private final short ESCAPED_START_BYTE = 0x55;
53 private final short ESCAPED_STOP_BYTE = 0x33;
54
55 private boolean startFound;
56 private File logFile;
57 private FileInputStream logStream;
58 private short[] packetBuffer;
59 private GenericLog decodedLog;
60 private Thread t;
61 private int packetLength;
62
63 String[] coreStatusAFlagNames = {
64 "CS-FuelPumpPrime",
65 "CS-unused1",
66 "CS-unused2",
67 "CS-unused3",
68 "CS-unused4",
69 "CS-unused5",
70 "CS-unused6",
71 "CS-unused7"
72 };
73
74 String[] decoderFlagsFlagNames = {
75 "DF-CombustionSync",
76 "DF-CrankSync",
77 "DF-CamSync",
78 "DF-LAST_TIMESTAMP_VALID",
79 "DF-LAST_PERIOD_VALID",
80 "DF-LAST_MATCH_VALID",
81 "DF-Spare-6",
82 "DF-Spare-7"
83 };
84
85 String[] flaggableFlagsNames = {
86 "FF-callsToUISRs",
87 "FF-lowVoltageConditions",
88 "FF-decoderSyncLosses",
89 "FF-decoderSyncCorrections",
90 "FF-decoderSyncStateClears",
91 "FF-serialNoiseErrors",
92 "FF-serialFramingErrors",
93 "FF-serialParityErrors",
94 "FF-serialOverrunErrors",
95 "FF-serialEscapePairMismatches",
96 "FF-serialStartsInsideAPacket",
97 "FF-serialPacketsOverLength",
98 "FF-serialChecksumMismatches",
99 "FF-serialPacketsUnderLength",
100 "FF-commsDebugMessagesNotSent",
101 "FF-commsErrorMessagesNotSent"
102 };
103
104 private LogField[] fields = {
105
106 new LogField("IAT", 100),
107 new LogField("CHT", 100),
108 new LogField("TPS", 640),
109 new LogField("EGO", 32768),
110 new LogField("MAP", 100),
111 new LogField("AAP", 100),
112 new LogField("BRV", 1000),
113 new LogField("MAT", 100),
114 new LogField("EGO2", 32768),
115 new LogField("IAP", 100),
116 new LogField("MAF"),
117 new LogField("DMAP"),
118 new LogField("DTPS"),
119 new LogField("RPM", 2),
120 new LogField("DRPM"),
121 new LogField("DDRPM"),
122
123
124 new LogField("LoadMain", 512),
125 new LogField("VEMain", 512),
126 new LogField("Lambda", 32768),
127 new LogField("AirFlow"),
128 new LogField("densityAndFuel"),
129 new LogField("BasePW", 1250),
130 new LogField("ETE", (100.0/32768.0)),
131 new LogField("TFCTotal", 1250),
132 new LogField("EffectivePW", 1250),
133 new LogField("IDT", 1250),
134 new LogField("RefPW", 1250),
135 new LogField("Advance", 50),
136 new LogField("Dwell", 1250),
137
138
139 new LogField("tempClock"),
140 new LogField("coreStatusA", types.BITS8, coreStatusAFlagNames),
141 new LogField("decoderFlags", types.BITS8, decoderFlagsFlagNames),
142 new LogField("flaggableFlags", types.BITS16, flaggableFlagsNames),
143 new LogField("currentEvent", types.UINT8),
144 new LogField("syncLostWithThisID", types.UINT8),
145 new LogField("syncLostOnThisEvent", types.UINT8),
146 new LogField("syncCaughtOnThisEvent", types.UINT8),
147 new LogField("syncResetCalls", types.UINT8),
148 new LogField("primaryTeethSeen", types.UINT8),
149 new LogField("secondaryTeethSeen", types.UINT8),
150 new LogField("serialOverrunErrors", types.UINT8),
151 new LogField("serialHardwareErrors", types.UINT8),
152 new LogField("serialAndCommsCodeErrors", types.UINT8),
153 new LogField("inputEventTimeTolerance"),
154 new LogField("zsp10"),
155 new LogField("zsp9"),
156 new LogField("zsp8"),
157 new LogField("zsp7"),
158 new LogField("zsp6"),
159 new LogField("zsp5"),
160 new LogField("zsp4"),
161 new LogField("zsp3"),
162 new LogField("clockInMilliSeconds"),
163 new LogField("clock8thMSsInMillis", 8)
164 };
165
166
167
168
169
170
171
172
173 public FreeEMSBin(String path) {
174 this(new File(path));
175 }
176
177
178
179
180
181 public FreeEMSBin(File f) {
182 logFile = f;
183 startFound = false;
184 packetBuffer = new short[6000];
185 packetLength = 0;
186
187
188 String[] headers = new String[fields.length * 32];
189 int headersPosition = 0;
190 for(int i=0;i<fields.length;i++){
191 if((fields[i].type == types.BITS8) || (fields[i].type == types.BITS16) || (fields[i].type == types.BITS32)){
192 for(int j=0;j<fields[i].bitFieldNames.length;j++){
193 String flagID = fields[i].bitFieldNames[j] + "-" + fields[i].ID + "-B"+ j;
194 headers[headersPosition] = flagID;
195 headersPosition++;
196 }
197 }else{
198 headers[headersPosition] = fields[i].ID;
199 headersPosition++;
200 }
201 }
202
203 decodedLog = new GenericLog(Arrays.copyOfRange(headers, 0, headersPosition));
204
205 t = new Thread(this, "FreeEMSBin Loading");
206 t.setPriority(Thread.MAX_PRIORITY);
207 t.start();
208 }
209
210
211
212
213
214
215 @Override
216 public void run() {
217 try {
218
219 byte[] readByte = new byte[1];
220 short uByte = 0;
221
222
223 int escapePairMismatches = 0;
224 int startsInsideAPacket = 0;
225 int packetsOverLength = 0;
226 int packetsUnderLength = 0;
227 int checksumMismatches = 0;
228 int packetsParsedFully = 0;
229 int packetLengthWrong = 0;
230 int strayBytesLost = 0;
231 int payloadIDWrong = 0;
232
233 startFound = false;
234 logStream = new FileInputStream(logFile);
235 decodedLog.setLogStatus(GenericLog.LOG_LOADING);
236 while (logStream.read(readByte) != -1) {
237 uByte = unsignedValueOf(readByte[0]);
238 if (uByte == START_BYTE) {
239 if (!startFound) {
240 startFound = true;
241 } else {
242 startsInsideAPacket++;
243 }
244 packetLength = 0;
245 } else if (startFound) {
246 if (uByte == STOP_BYTE) {
247 if(packetLength < minimumPacketLength){
248 packetsUnderLength++;
249 }else if(packetLength > maximumPacketLength){
250 packetsOverLength++;
251 }else{
252 short[] justThePacket = new short[packetLength];
253 for(int i=0;i<packetLength;i++){
254 justThePacket[i] = packetBuffer[i];
255 }
256 if (checksum(justThePacket)){
257 if(decodeBasicLogPacket(justThePacket, payloadIDToParse)){
258 packetsParsedFully++;
259 }else{
260 packetLengthWrong++;
261 payloadIDWrong++;
262 }
263 }else{
264 checksumMismatches++;
265 }
266 }
267 startFound = false;
268 } else if (uByte == ESCAPE_BYTE) {
269 if (logStream.read(readByte) != -1) {
270 uByte = unEscape(unsignedValueOf(readByte[0]));
271 if (uByte != (short) -1) {
272 packetBuffer[packetLength] = uByte;
273 packetLength++;
274 } else {
275 startFound = false;
276 escapePairMismatches++;
277 }
278 }
279 } else {
280 packetBuffer[packetLength] = uByte;
281 packetLength++;
282 }
283 }else{
284 strayBytesLost++;
285 }
286 }
287 decodedLog.setLogStatus(GenericLog.LOG_LOADED);
288
289 System.out.println(System.getProperty("line.separator") + "Binary Parsing Statistics:" + System.getProperty("line.separator"));
290
291 System.out.println("Value: " + escapePairMismatches + " Incremented when an escape is found but not followed by an escapee");
292 System.out.println("Value: " + startsInsideAPacket + " Incremented when a start byte is found inside a packet");
293 System.out.println("Value: " + packetsOverLength + " Incremented when the buffer fills up before the end");
294 System.out.println("Value: " + packetsUnderLength + " Incremented when a packet is found that is too short");
295 System.out.println("Value: " + checksumMismatches + " Incremented when calculated checksum did not match the received one");
296 System.out.println("Value: " + packetsParsedFully + " Number of packets that matched all requirements and got into the log");
297 System.out.println("Value: " + packetLengthWrong + " The length should match the ID passed in, if not, fail.");
298 System.out.println("Value: " + strayBytesLost + " How many bytes were not in a packet! (should be low, ie, under one packet");
299 System.out.println("Value: " + payloadIDWrong + " Requests to parse packet as A when packet was of type B");
300
301 System.out.println(System.getProperty("line.separator") + "Thank you for choosing FreeEMS!");
302
303 } catch (IOException IOE) {
304 System.out.println(IOE.getMessage());
305
306 }
307 }
308
309
310
311
312
313
314
315 private boolean decodeBasicLogPacket(short[] packet, int payloadIDToParse) {
316 final int HEADER_HAS_LENGTH_INDEX = 0;
317 final int HEADER_IS_NACK_INDEX = 1;
318 final int HEADER_HAS_SEQUENCE_INDEX = 2;
319 final int HEADER_RESERVED_E_INDEX = 3;
320 final int HEADER_RESERVED_D_INDEX = 4;
321 final int HEADER_RESERVED_C_INDEX = 5;
322 final int HEADER_RESERVED_B_INDEX = 6;
323 final int HEADER_RESERVED_A_INDEX = 7;
324
325
326 int position = 0;
327
328 short flags = packet[position];
329 position++;
330
331 short payloadIdUpper = packet[position];
332 position++;
333 short payloadIdLower = packet[position];
334 position++;
335 int payloadId = (payloadIdUpper * 256) + payloadIdLower;
336
337 if(payloadId != payloadIDToParse){
338 return false;
339 }
340
341 int[] flagValues = processFlagBytes(flags, 8);
342
343 if(flagValues[HEADER_HAS_SEQUENCE_INDEX] == 1){
344 position++;
345 }
346
347 if(flagValues[HEADER_HAS_LENGTH_INDEX] == 1){
348 position += 2;
349 }
350
351 int lengthOfFields = 0;
352 for(int i=0;i<fields.length;i++){
353 lengthOfFields += fields[i].type.width;
354 }
355
356 int payloadLength = ((packet.length - position) - 1);
357 if(payloadLength != lengthOfFields){
358 System.out.print(" Fields length is: " + lengthOfFields);
359 System.out.print(" Packet length is: " + packet.length);
360 System.out.println(" Payload length is: " + payloadLength);
361 return false;
362 }
363
364 for(int i=0;i<fields.length;i++){
365 LogField field = fields[i];
366
367 int rawValue = 0;
368 for(int j=0;j<field.type.width;j++){
369 rawValue = (rawValue * 256) + packet[position];
370 position++;
371 }
372
373 if((field.type == types.UINT8) || (field.type == types.UINT16) || (field.type == types.UINT32)){
374 double scaledValue = (double)rawValue/field.divBy;
375 double finalValue = scaledValue + field.addTo;
376 decodedLog.addValue(field.ID, finalValue);
377 }else if((field.type == types.BITS8) || (field.type == types.BITS16) || (field.type == types.BITS32)){
378 int[] processedFlags = processFlagBytes(rawValue, (8 * field.type.width));
379 for(int j=0;j<processedFlags.length;j++){
380 String flagID = field.bitFieldNames[j] + "-" + field.ID + "-B"+ j;
381 decodedLog.addValue(flagID, processedFlags[j]);
382 }
383 }else if(field.type == types.SINT8){
384 decodedLog.addValue(field.ID, rawValue);
385 }else if(field.type == types.SINT16){
386 decodedLog.addValue(field.ID, rawValue);
387 }else if(field.type == types.SINT32){
388 decodedLog.addValue(field.ID, rawValue);
389 }
390 }
391 return true;
392 }
393
394 int[] processFlagBytes(long valueOfFlags, int numberOfFlags){
395 if((numberOfFlags != 8) && (numberOfFlags != 16) && (numberOfFlags != 32)){
396 throw new IllegalArgumentException("Basic units of computer sciene apply, embedded flags are never " + numberOfFlags + " wide!");
397 }
398
399 int[] flagValues = new int[numberOfFlags];
400 int comparison = 1;
401 for(int i=0;i<numberOfFlags;i++){
402 if((valueOfFlags % (2 * comparison)) == comparison){
403 flagValues[i] = 1;
404 valueOfFlags -= comparison;
405 }
406 comparison *= 2;
407 }
408
409 return flagValues;
410 }
411
412
413
414
415
416
417
418 private boolean checksum(short[] packet) {
419 if(packetLength > 0){
420 short includedSum = packet[packetLength -1];
421 long veryBIGsum = 0;
422 for(int x=0;x<packetLength-1;x++){
423 veryBIGsum += packet[x];
424 }
425 short calculatedSum = (short)(veryBIGsum % 256);
426 return (calculatedSum == includedSum);
427 }else{
428 return false;
429 }
430 }
431
432
433
434
435
436
437
438 private short unEscape(short uByte) {
439 if (uByte == ESCAPED_START_BYTE) {
440 return START_BYTE;
441 } else if (uByte == ESCAPED_STOP_BYTE) {
442 return STOP_BYTE;
443 } else if (uByte == ESCAPED_ESCAPE_BYTE) {
444 return ESCAPE_BYTE;
445 } else {
446 return (short) -1;
447 }
448 }
449
450
451
452
453
454
455
456 private short unsignedValueOf(byte uInt8){
457 return (short)(0xFF & uInt8);
458 }
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478 @Override
479 public String toString() {
480 return super.toString();
481 }
482 }