When creating the application, we are faced with many choices, problems, and so on, with which we will try to introduce you in this article. As it turned out with the car, you can carry on a dialogue, and quite a productive one. Naturally, in order to organize communication with the car, it is necessary to “make contact”, “ask the right question” and correctly understand the “answer” received from the car. Accordingly, the article will be aimed at explaining in an accessible language the organization of the dialogue, and also tell you what mistakes you may encounter on the way and how to deal with them.
Connection selection
Initially, it is necessary to clarify that an ELM327 adapter will be used to connect to the car. ELM327 is a microcircuit that allows you to convert the protocols used in car diagnostic tires into the RS232 protocol, to which we will transmit data. Due to the fact that data transmission via the RS232 protocol occurs consistently, the first problem arises - the data transfer speed, which we will try to circumvent in one of the following points.
There are several variations of the ELM327 adapter, which are classified by the method of data transfer - Bluetooth, WIFI, USB. Based on the fact that the purpose of the development is a mobile device under the Android operating system, you can choose two most suitable versions of ELM327, such as Bluetooth and WIFI. Since the method of receiving and processing data is one, and they differ only in the connection options to the adapter, you can choose only one, organize a dialogue with it, and then add the remaining connection options.
ELM327 1.5 vs ELM327 2.1

')
One of the first problems that could be encountered was the problem of choosing the adapter itself, in our case Bluetooth. It turns out that if you need to support all (at least most) cars, you need to choose version v1.5 instead of v2.1, which in fact needs to be clarified several times when buying an adapter, because the sellers are trying to give the version of the adapter not the one that is in fact, because they are not much different. In fact, in version v2.1, there is no support for the J1850 PWM and J1850 VPW protocols, which means that you will not be able to connect to vehicles that use these protocols.
Connection
Connection to the adapter occurs in several stages:
- Connection to the adapter (Bluetooth, WIFI)
- Sending initialization commands (initialization string)
If the connection is all clear. The principle of operation is the same as that of any Bluetooth / WIFI chat. In order to understand how to send an initialization string, it is necessary to study which commands exist, as well as what functions they perform.
AT Z [reset all]
Reset adapter settings to factory condition.
AT L1-0Enable / Disable newline characters.
AT E1-0Echo on - off
AT H1-0Headers on - off
AT AT0-1-2Adaptive Timing Off - adaptive Timing Auto1 - adaptive Timing Auto2
AT ST FFSet the timeout to maximum.
AT D [set all to Default]
Reset settings to their original, user-configured state.
AT DP [Describe the current Protocol]
The scanner is able to independently determine the protocol of the car to which it is connected.
AT IB10 [set the ISO rate to 10400]
The command sets the baud rate for ISO 9141-2 and
ISO 14230-4 10400
AT IB96 [set the ISO rate to 9600]
The command sets the baud rate for ISO 9141-2 and
ISO 14230-4 9600 for protocols 3,4,5.
AT SP h [Set Protocol h]
The command to select the protocol h, where h:
0 - Automatic;
1 - SAE J1850 PWM (41.6 Kbaud);
2 - SAE J1850 VPW (10.4 Kbaud);
3 - ISO 9141-2 (5 baud init, 10.4 Kbaud);
4 - ISO 14230-4 KWP (5 baud init, 10.4 Kbaud);
5 - ISO 14230-4 KWP (fast init, 10.4 Kbaud);
6 - ISO 15765-4 CAN (11 bit ID, 500 Kbaud);
7 - ISO 15765-4 CAN (29 bit ID, 500 Kbaud);
8 - ISO 15765-4 CAN (11 bit ID, 250 Kbaud);
9 - ISO 15765-4 CAN (29 bit ID, 250 Kbaud);
AT SP Ah [Set Protocol h with Auto]
The command sets the default protocol h, if the connection via the protocol h fails, then the adapter starts automatic protocol selection.
Based on the commands described above, we form the initialization string.
initializeCommands = Arrays.asList("ATZ", "ATL0", "ATE1", "ATH1", "ATAT1", "ATSTFF", "ATDP", "ATSP0");
It is desirable to allow the user to change the initialization commands, because in order to select the “key” for some cars, it is necessary to select more suitable adapter settings. In our case, settings are used that are suitable for most standard protocols.
It is also desirable to pay attention to the APSP0 command, so we set the default protocol auto selection, it may take some time.
Accordingly, if the user knows what his auto protocol is, then using the ability to change the connection protocol, he can change 0 to his protocol number.
Read diagnostic data
PID's special commands are used to read diagnostic data.
PID (Parameter id's - On-Board Diagnostic Parameter Identifiers) - codes that are used to query the performance of certain vehicle sensors.
Basic pida can be found on Wikipedia, there is a complete set of basic commands that should support all cars. There are also sets of commands for certain brands and types of cars, these sets are available for a fee. In our case, the application is sharpened on the basic diagnostics of cars, respectively, we use the basic set of commands.
It is also possible to receive current data from the car while the command to receive data from the car will have
01 at the beginning, indicating that we want to receive real data. If we want to retrieve the saved vehicle data, then the command first must specify
02 . For example, the command to get the current vehicle speed is
010D , and to get the saved speed,
020D .
If you look closely at the number of commands that are provided by open resources, then you can just notice the problem that I wrote about at the very beginning, namely the problem of the speed of the adapter response. Since the sending and receiving of commands goes sequentially, in order to get the sensor readings at the current time, you must wait for the response to all previous commands. Accordingly, if you request to receive all the commands, then it is highly likely that the actual data will be updated very slowly. But this problem can be solved if we use the commands that reflect only those commands that exist in the car. For example:
0100 - PIDs supported [01 - 20]
0120 - PIDs supported [21 - 40]
0140 - PIDs supported [41 - 60]
0160 - PIDs supported [61 - 80]
0180 - PIDs supported [81 - A0]
01A0 - PIDs supported [A1 - C0]
I will demonstrate how to determine which sensors are present in the car using one of the pids. For example:
- 0100 \\ request
- BB1E3211 \\ answer from the car
We translate the answer from the car to the binary number system
BB1E3211(16) > 10111011000111100011001000010001(2)
Using the following table we can determine which pida are supported by our car, ranging from 01 to 20:

Based on the resulting data, we can determine that our car supports the following pida:
01, 03, 04, 05, 07, 08, 0C, 0D, 0E, 0F, 13, 14, 17, 1C, 20
Now, instead of sending all 32 commands and waiting for a response to them, although some may be missing, we will use only 15 commands. But this is not the limit of the so-called optimization. In order for the data to be updated even faster, I advise you to request only data on those sensors that are displayed on the screen. Although this limits some functionality of the application. For example, a history record.
Reading and decoding car errors
Car mistakes can also be different and there are separate commands for them too. For example:
- 03 - To display stored error codes
- 0A - To display permanent error codes.
As with the rest of the teams, the errors of the car come in a coded form, respectively, as in the rest of the teams, they need to be decoded to get the necessary information. I will give an example of the error decoding operation Code:
private final static char[] dtcLetters = {'P', 'C', 'B', 'U'}; private final static char[] hexArray = "0123456789ABCDEF".toCharArray(); private void performCalculations(String fault) { final String result = fault; String workingData = ""; int startIndex = 0; troubleCodesArray.clear(); try { if (result.contains("43")) { workingData = result.replaceAll("^43|[\r\n]43|[\r\n]", ""); } else if (result.contains("47")) { workingData = result.replaceAll("^47|[\r\n]47|[\r\n]", ""); } for(int begin=startIndex; begin < workingData.length(); begin += 4) { String dtc = ""; byte b1 = Utility.hexStringToByteArray(workingData.charAt(begin)); int ch1 = ((b1 & 0xC0) >> 6); int ch2 = ((b1 & 0x30) >> 4); dtc += dtcLetters[ch1]; dtc += hexArray[ch2]; dtc += workingData.substring(begin + 1, begin + 4); if (dtc.equals("P0000")) { continue; } troubleCodesArray.add(dtc); } } catch (Exception e) { Log.e(TAG, "Error: " + e.getMessage()); } }
And now an explanation.
Based on the response received, we can get the error code, for this we decode the received message using the following labels.
First character:

Second character:

3, 4, 5 characters are formed according to this table:

Based on this, we can try to parse the following answer: 0001000000111110

Error Code: P103E
Epilogue
At this stage, we figured out how to organize a dialogue with the adapter, send him commands, receive and decrypt his answers. This is a big part of the work, if you consider how much time it takes to study the material, but at the same time, it’s still quite interesting. Outside of this article, there are many problems associated with the visual interface, as well as many additional functions, such as adding new types of files from the file, standard and advanced ways to connect to the adapter and graphing.
Matvienko Alexander, Hossein Fakhr.