Приложение OBD II в Visual Studio (C#) с Xamarin

Я работаю над приложением для Android, которое получает данные от Bluetooth-адаптера OBD II. Настройка соединения между приложением и адаптером работает, но когда я отправляю команды адаптеру, я не получаю правильных результатов. Он либо возвращает:

+СОЕДИНЕНИЕ‹

или команду, которую я только что отправил адаптеру.

Приложение написано в Visual Studio с использованием Xamarin для разработки под Android. Код показывает только упрощенную версию приложения и просто отправляет код для поддерживаемых PID от 01 до 1f.

BluetoothAdapter myAdapter;
BluetoothSocket socket = null; 
string rawData;
public BluetoothConnect()
    {

        myAdapter = BluetoothAdapter.DefaultAdapter;
        if (myAdapter == null)
        {
            //Device has no Bluetooth
        }
        if (!myAdapter.IsEnabled)
        {
            myAdapter.Enable();
        }
        BluetoothDevice d = myAdapter.GetRemoteDevice("AA:BB:CC:11:22:33");
        socket = d.CreateRfcommSocketToServiceRecord(UUID.FromString("00001101-0000-1000-8000-00805F9B34FB"));
        socket.Connect();

        byte[] cmd = Encoding.ASCII.GetBytes("AT D");
        socket.OutputStream.Write(cmd, 0, cmd.Length);
        ReadAnswer();
        socket.OutputStream.Flush();

        cmd = Encoding.ASCII.GetBytes("AT Z");
        socket.OutputStream.Write(cmd, 0, cmd.Length);
        socket.OutputStream.Flush();

        cmd = Encoding.ASCII.GetBytes("AT E0");
        socket.OutputStream.Write(cmd, 0, cmd.Length);
        ReadAnswer();
        socket.OutputStream.Flush();

        cmd = Encoding.ASCII.GetBytes("AT L0");
        socket.OutputStream.Write(cmd, 0, cmd.Length);
        ReadAnswer();
        socket.OutputStream.Flush();

        cmd = Encoding.ASCII.GetBytes("AT S0");
        socket.OutputStream.Write(cmd, 0, cmd.Length);
        ReadAnswer();
        socket.OutputStream.Flush();

        cmd = Encoding.ASCII.GetBytes("AT H0");
        socket.OutputStream.Write(cmd, 0, cmd.Length);
        ReadAnswer();
        socket.OutputStream.Flush();

        cmd = Encoding.ASCII.GetBytes("AT SP 0");
        socket.OutputStream.Write(cmd, 0, cmd.Length);
        ReadAnswer();
        socket.OutputStream.Flush();




        cmd = Encoding.ASCII.GetBytes("0100");
        socket.OutputStream.Write(cmd, 0, cmd.Length);

        ReadAnswer();


    }

    private void ReadAnswer() {
        try {
            rawData = "";
            int a = 0;

            System.Text.StringBuilder b = new   System.Text.StringBuilder();
            char c;
            while (((a = (byte)socket.InputStream.ReadByte()) > -1)) 
            {

                c = (char)a;
                if (c == '>')
                {
                    break;
                }
                b.Append(c);
            }

            rawData = b.ToString();
            Log.Info("-----------------------------------", "RawData: " + rawData);
            socket.InputStream.Flush();
        }
        catch(System.Exception e)
        {
            Log.Info("", "" + e.Message);
        }



    } 

Я уже пробовал разные комбинации команд инициализации.

Я мог предположить, что проблема связана либо с моим методом чтения входного потока, либо с отправкой команд, но я не могу понять, что делать, так как я новичок в разработке Visual Studio, Xamarin и Android.

Надеюсь, вы, ребята, можете дать мне несколько предложений!


person Caspar    schedule 25.06.2016    source источник
comment
Попробуйте обернуть код включения bluetooth и инициализации сокета в try catchs.   -  person Terrance    schedule 25.06.2016
comment
Убедитесь, что у вас есть правильные разрешения для Bluetooth, или используйте это, чтобы включить его без явного согласия. developer.android.com/reference/android/bluetooth/ Является ли ASCII правильной кодировкой?   -  person Terrance    schedule 25.06.2016
comment
@Terrance Спасибо за быстрый ответ! Только что попробовал ваши предложения. Конструкция try catch работает нормально - без исключений. Проверил разрешение (включить Bluetooth и Bluetooth_Admin) - должно быть все, что мне нужно для отправки и получения. Пробовал метод ASCII в отдельном классе, и кажется, что метод работает как предполагалось.   -  person Caspar    schedule 26.06.2016


Ответы (1)


Это слишком старое сейчас, но, возможно, кому-то нужно. приведенный ниже код протестирован с ELM327, разработанным в Xamarin.

 public void SendCommand( string command , Action<string> onDataRecevied )
    {
        if ( BthSocket.IsConnected )
        {
            byte[] cmd = Encoding.ASCII.GetBytes( command + " \r" );
            BthSocket.OutputStream.Write( cmd , 0 , cmd.Length );
            BthSocket.OutputStream.Flush();


            ReadData( out string d );
            if ( d != "" )
            {
                onDataRecevied( d );
            }



        }
    }

и читать данные

public void ReadData( out string data )
    {
        StringBuilder res = new StringBuilder();

        try
        {
            byte b = 0;


            // read until '>' arrives OR end of stream reached
            char c;
            // -1 if the end of the stream is reached
            while ( ( b = ( ( byte )BthSocket.InputStream.ReadByte() ) ) > -1 )
            {
                c = ( char )b;
                if ( c == '>' ) // read until '>' arrives
                {
                    break;
                }
                res.Append( c );
            }

        }
        catch ( Exception e )
        {
            System.Console.WriteLine( e.ToString() );
        }

      data = res.ToString().Replace( "SEARCHING" , "" );

        /*
         * Data may have echo or informative text like "INIT BUS..." or similar.
         * The response ends with two carriage return characters. So we need to take
         * everything from the last carriage return before those two (trimmed above).
         */

        data = data.Replace( "\\s" , "" );

    }

и для инициализации устройства ниже команды

 obd2.SendCommand( "AT Z" , ( obj ) => { LogMessage( txtData , obj ); } );
             obd2.SendCommand( "AT E0" , ( obj ) => { LogMessage( txtData , obj ); } );
             obd2.SendCommand( "AT E0" , ( obj ) => { LogMessage( txtData , obj ); } );
             obd2.SendCommand( "AT L0" , ( obj ) => { LogMessage( txtData , obj ); } );
             obd2.SendCommand( "AT S0" , ( obj ) => { LogMessage( txtData , obj ); } );
             obd2.SendCommand( "ATD" , ( obj ) => { LogMessage( txtData , obj ); } );
             obd2.SendCommand( "AT SP 6" , ( obj ) => { LogMessage( txtData , obj ); } );
             obd2.SendCommand( "AT H0" , ( obj ) => { LogMessage( txtData , obj ); } );
             obd2.SendCommand( "AT 1" , ( obj ) => { LogMessage( txtData , obj ); } );
             obd2.SendCommand( "ATST 96" , ( obj ) => { LogMessage( txtData , obj ); } );
             obd2.SendCommand( "AT H1" , ( obj ) => { LogMessage( txtData , obj ); } );
             obd2.SendCommand( "AT H0" , ( obj ) => { LogMessage( txtData , obj ); } );

данные этой строки = res.ToString().Replace("ПОИСК", ""); представьте себе следующий ответ 41 0c 00 0d. ELM отправляет строки!! Итак, ELM ставит пробелы между каждым «байтом». И обратите внимание на то, что я взял слово байт в кавычки, потому что 41 на самом деле ДВА байта (два символа) в сокете. Итак, мы должны сделать еще некоторую обработку.

Надеюсь это поможет.

person Adeel Rizvi    schedule 11.04.2019
comment
Все эти команды необходимы для инициализации устройства перед отправкой на него других команд? - person perozzo; 29.03.2021
comment
@perozzo, да, это начальные команды устройства, вы можете пропустить несколько, если не хотите зависеть от версии ELM. вот PDF-файл, который расскажет вам, что делает каждая команда: Виджеты/ELM327_AT_Commands.pdf - person Adeel Rizvi; 18.04.2021