Share My Creation OBD2 USB

App uses OBD2 to USB from Ebay, it has ELM327 V1.5 IC that connects to all OBDII protocols. The app reads common PIDs, DTC (faults) and VID. To add PID you can use https://en.wikipedia.org/wiki/OBD-II_PIDs#Bitwise_encoded_PIDs Code uses felUsbSerial lib.
The USB diagnostic plug with ELM327 v1.5, connected to Android device via OTG adaptor.
https://www.ebay.co.uk/itm/195165625444

Edit: Code changed to include more OBD2 plugs.

obd_usb_b4a.png
 

Attachments

  • obd_usb405.png
    obd_usb405.png
    22.8 KB · Views: 122
  • obd_usb.zip
    10 KB · Views: 113
Last edited:

emexes

Expert
Licensed User
In case you feel the need for speed: I vaguely recall that you could speed up the ELM request-response rate by sending the next request as soon as you'd received the expected number of bytes for the previous response, ie not wait for the ELM prompt to reappear.

I don't have access to a car to try it out on right now though. My 2002 Subaru has an OBD port, but OBDII only became mandatory here in Australia in 2005 so I think I'm stuck with some earlier incompatible protocol.
 

moty22

Active Member
Licensed User
Thanks for the advice. The main delay is the car ECU, the diagnostic device gets the lowest priority. The second difficulty is b4a function 'Sub serial_DataAvailable' I can't tell how many bytes arrived.
I test the app using a simulator program I wrote in VB, I rarely test it in the car. If you wish I can send you the app.
 

emexes

Expert
Licensed User
The second difficulty is b4a function 'Sub serial_DataAvailable' I can't tell how many bytes arrived.

Maybe something like (not tested, but should be pretty close except for ELM prompt and line and packet terminators):

B4X:
Sub Globalz()
    Dim ExpectedReplyLength As Int = 0    ' > 0 if short-circuit fast mode, or 0 for normal parsing using packet terminator character
End Sub

Private Sub serial_DataAvailable (Buffer() As Byte)
    reply = reply & BytesToString(Buffer, 0, Buffer.Length, "ISO-8859-1")    'ISO-8559-1 is 1:1 byte=character mapping, cf microcontroller unlikely to emit UTF-8
    
    Dim P As Int = reply.IndexOf(">")    'or CR or LF?
    If P < 0  Then
        If ExpectedReplyLength > 0 Then    'if short-circuit fast mode
            If reply.Length >= ExpectedReplyLength Then    'if we have received expected packet
                P = ExpectedReplyLength
            End If
        End If
    End If

    'at this point, P is the number of characters in the reply, or -1 if no reply ready
    'the reply could conceivably be 0 bytes long, if receive adjacent packet terminator characters (">>"?)

    If P >= 0 Then
        Dim TheReplyTheWholeReplyAndNothingButTheReply As String = reply.SubString2(0, P)
        reply = reply.SubString(P)    'what about also removing ">" or CR or LF?
        HandleReply(TheReplyTheWholeReplyAndNothingButTheReply)
        SendNextRequest()    'includes setting ExpectedReplyLength according to next requested data (or 0 if expected length unknown = rely on line terminator)
    End If
End Sub
 

emexes

Expert
Licensed User
Instead of:

B4X:
reply = reply & BytesToString(Buffer, 0, Buffer.Length, "ISO-8859-1")

consider using existing built-in function:

B4X:
dim bc as ByteConverter
reply = reply & bc.StringFromBytes(Buffer, "ISO-8859-1")

Erel might whack us on the knuckles and say we should be using StringBuilder (or even that we shouldn't be using Strings at all) and if StringBuilder had a .IndexOf function/method then I'd probably agree with that.
 

moty22

Active Member
Licensed User
Maybe something like
Your code example inspired me to change mine based on yours, now I process the received data when it's the size and contains characters I expect, and then make the next request.
I know only about 1% of b4x language so I'm limited to what I can do. It also looks like b4x is mainly for home and office apps, no much for engineers. The serial lib has only 2 functions, 'send' and 'data arrived'. Most libs have functions of receive 1 byte, how many bytes arrived, etc. The input buffer size is about 2K bytes so you need to know what's going on in there.
Normal packet from ELM327 looks like:
0104
41 04 0C

>
The data is 0C is 2 bytes representing hexadecimal value (decimal 12). The only way I can convert this message to integers is by manipulating strings.
Next I'll try ISO-8859-1.
 

Attachments

  • obd2_u3.zip
    10 KB · Views: 133

emexes

Expert
Licensed User
The serial lib has only 2 functions, 'send' and 'data arrived'.

I think that's a reflection of Android and event-driven programming. Also, what else do you do with a serial port, besides send and receive?

Most libs have functions of receive 1 byte, how many bytes arrived, etc.

I cheerfully concede that you have to take the data Android gives you, when it gives it to you, ie you can't meter it out by asking for it in quantities and at times that suit you. But that's no big deal: you just add it to your own buffer, which can be as big as a B4X String can be eg MB+ and then dice it off from that as you need it.

The input buffer size is about 2K bytes so you need to know what's going on in there.

I wouldn't know about that, I think I've always had my own buffers. Although maybe I do that instinctively because I got burned early on relying on third-party buffers, and I've been blissfully and unknowingly dodging that bullet ever since. I do vaguely remember fighting some battles with Turbo Basic in 1987, before jumping ship to Turbo C.

In BASIC the buffer is usually a String, or in the case of fixed (or known maximum) length binary packets coming in fast, I'll use an array of bytes.

The only way I can convert this message to integers is by manipulating strings.

Because the ELM device is talking to you in text (eg "2C" being ASCII characters Chr(0x32) & Chr(0x43) rather than a single byte 0x2C, I agree that strings are an entirely reasonable way to go here.

Next I'll try ISO-8859-1.

When you're receiving byte-size data from machines that don't use Unicode anyway, ISO-8859-1 is the decoding to use:

it maps byte value 0 = Chr(0), byte value 1 = Chr(1), etc all the way to byte value 255 = Chr(255).

Windows 1252 does some oddball mappings in the high-bit area, to maximise the number of useful characters available for day-to-day real-life typing eg the Euro symbol which is Chr(8364), and smart single and double quotes.
 
Last edited:
Top