• After 15+ years, we've made a big change: Android Forums is now Early Bird Club. Learn more here.

App Inventor OBD java inputstream infinite loop

Alatriste

Lurker
Jan 19, 2019
4
0
I'm writing simple OBD communicator. I'm running OBDSim (latest version) from cmd (with Administrator rights) `obdsim.exe -g gui_fltk -w COM5` (I found that COM5 port in Windows Bluetooth settings.) Then I'm launching my app with debug mode in Android Studio. I'm working in Windows 7 OS.

MainActivity.java

Code:
com.example.bluetoothchatapp;

import android.Manifest;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.content.Intent;
import android.content.IntentFilter;
import android.widget.*;
import android.view.*;
import android.os.Build;
import android.os.Handler;
import android.os.Message;

import java.util.ArrayList;
import java.util.Set;


public class MainActivity extends AppCompatActivity implements         AdapterView.OnItemClickListener
{

private TextView txvAdapterInfo;
private ListView lstBondedList;

private TextView txtEngineRpm;

ArrayList<String> bondedDevList = new ArrayList<>();
ArrayAdapter<String> bondedAdapter;


private BluetoothAdapter mBAdapter;

private ArrayList<BluetoothDevice> mBDeviceList;

private BluetoothDevice mBDevice;

Client client;

final Handler mHandler = new Handler()
{
    public void handleMessage(Message msg)
    {
        Bundle b;

        b = msg.getData();

        txtEngineRpm.setText(String.valueOf(b.getInt("rpm")));

        super.handleMessage(msg);
    }
};


@Override
protected void onCreate(Bundle savedInstanceState)
{
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);

    txvAdapterInfo = findViewById(R.id.txvAdapterInfo);
    lstBondedList = findViewById(R.id.lstBondedList);

    bondedAdapter = new ArrayAdapter<String>(this,
            android.R.layout.simple_list_item_activated_1, bondedDevList);
    lstBondedList.setAdapter(bondedAdapter);

    lstBondedList.setOnItemClickListener(MainActivity.this);

    txtEngineRpm = findViewById(R.id.txtEngineRpm);
    txtSpeed = findViewById(R.id.txtSpeedLog);

    mBDeviceList = new ArrayList<>();

    initBluetoothAdapter();
}


@Override
protected void onDestroy()
{
    super.onDestroy();

    unregisterReceiver(mBroadCastReceiver);
}


@Override
public void onItemClick(AdapterView<?> adapterView, View view, int i, long l)
{
    mBAdapter.cancelDiscovery();

    if(Build.VERSION.SDK_INT > Build.VERSION_CODES.JELLY_BEAN_MR2 && i <= mBDeviceList.size())
    {
        mBDevice = mBDeviceList.get(i);

        client = new Client(mBDevice, mHandler);

        client.run();
    }
}

public int getBondedDevicesList()
{
    Set<BluetoothDevice> pairedDevices = mBAdapter.getBondedDevices();

    if(pairedDevices.size() > 0)
    {
        for(BluetoothDevice device : pairedDevices)
        {
            mBDeviceList.add(device);
            bondedDevList.add(device.getName());
            bondedAdapter.notifyDataSetChanged();
        }
    }

    return 1;
}



public int initBluetoothAdapter()
{
    mBAdapter = BluetoothAdapter.getDefaultAdapter();

    if(mBAdapter == null)
    {
        return -1;
    }

    if(!mBAdapter.isEnabled())
    {
        mBAdapter.enable();
    }

    String adapterMACAdress = mBAdapter.getAddress();
    String adapterName = mBAdapter.getName();

    txvAdapterInfo.setText(adapterMACAdress + " , " + adapterName);

    getBondedDevicesList();

    return 1;
}
}

Client.java
Code:
package com.example.bluetoothchatapp;

import android.bluetooth.BluetoothDevice;

import com.github.pires.obd.commands.SpeedCommand;
import com.github.pires.obd.commands.protocol.*;
import com.github.pires.obd.enums.ObdProtocols;
import com.github.pires.obd.commands.engine.*;
import android.bluetooth.BluetoothSocket;
import android.os.Handler;
import android.os.Message;
import android.os.Bundle;

import java.io.IOException;
import java.io.InputStream;
import java.io_OutputStream;
import java.lang.InterruptedException;
import java.lang.reflect.InvocationTargetException;
import java.util.UUID;

public class Client implements Runnable , OBDCommands
{
    private Handler clHandler_;

    private BluetoothDevice clbDevice_;
    private BluetoothSocket clientSocket_;
    private InputStream inputStream_;
    private OutputStream outputStream_;

    StringBuilder obdReadResult_;

    private Bundle transferBundle_;
 
    public Client(BluetoothDevice device, Handler handler)
    {
        clbDevice_ = device;
        clHandler_ = handler;

        transferBundle_ = new Bundle(1);
        obdReadResult_ = new StringBuilder();
    }

 
    public void initOBDAdapter() throws InterruptedException
    {
        try
        {

            UUID uuid = UUID.fromString("00001101-0000-1000-8000-00805F9B34FB");

            try
            {
                clientSocket_ = clbDevice_.createInsecureRfcommSocketToServiceRecord(uuid);

            }
            catch (IOException  e)
            {
                e.printStackTrace();
            }

            try
            {
                clientSocket_.connect();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }

            InputStream tmpIn = null;
            OutputStream tmpOut = null;

            try
            {
                tmpIn = clientSocket_.getInputStream();
                tmpOut = clientSocket_.getOutputStream();
            }
            catch (IOException e)
            {
                e.printStackTrace();
            }

            inputStream_ = tmpIn;
            outputStream_ = tmpOut;

            synchronized (Client.class)
            {
                // String ATZ = "AT Z\r"; define in simple OBDCommands interface

                writeToOBD(ATZ.getBytes());
                readFromOBD();
            }
        }
        catch (IOException e)
        {
            e.printStackTrace();
        }

    }

    public void writeToOBD(byte[] data) throws IOException
    {
        outputStream_.write(data);
        outputStream_.flush();

        try
        {
            Thread.sleep(200);
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }
    }

    public void readFromOBD() throws IOException
    {
        try
        {
            obdReadResult_.setLength(0);

            byte data;

            while((data = (byte) inputStream_.read()) > -1)
            {
                char c = (char) data;
                if(c == '>')
                {
                    break;
                }

                obdReadResult_.append(c);
            }

        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    public void logEngine() throws  InterruptedException
    {
        try
        {
            writeToOBD(ERPM.getBytes());
            readFromOBD();

        }
        catch (IOException e)
        {
            e.printStackTrace();
        }
    }

    public void run()
    {
        try
        {
            initOBDAdapter();
        }
        catch (InterruptedException e)
        {
            e.printStackTrace();
        }

        while (true)
        {
            try
            {
                logEngine();
            }
            catch (InterruptedException e)
            {
                e.printStackTrace();
            }

            String tmpStrValue = obdReadResult_.toString().replaceAll("(\\r|\\n)", ""); 

            int rpmValue = Integer.parseInt(tmpStrValue.substring(4, tmpStrValue.length()), 16) / 4;

            transferBundle_.putInt("rmp", rpmValue);

            Message msg = clHandler_.obtainMessage();

            msg.setData(transferBundle_);

            clHandler_.sendMessage(msg);
        }
    }
}


I have strange infinite loops.
When I'm debugging app first time, then it works fine, but SECOND debug launch puts thread in infinite loop on `while((data = (byte) inputStream_.read()) > -1)` line i.e every second launch freezes
1st OK
2nd FAIL
3rd OK
4th FAIL
....

I also saw that when it works ok, then socket's mPort value is always 4, but when it fails, then socket's mPort value is 2.

P.S I tried use
`clientSocket_ = (BluetoothSocket)clbDevice_.getClass().getMethod("createRfcommSocket", new Class[] {int.class}).invoke(clbDevice_,1);` , but then socket connection puts thread into the infinite loop .

I also used OBDII Java API , but same result. Simple EchoOffCommand's inputstream read call puts thread into the infinite loop.

What I'm doing wrong?
 

BEST TECH IN 2023

We've been tracking upcoming products and ranking the best tech since 2007. Thanks for trusting our opinion: we get rewarded through affiliate links that earn us a commission and we invite you to learn more about us.

Smartphones