Как правильно подключить приложение Android к сокету RFCOMM на микроконтроллере Arduino с поддержкой Bluetooth?


Answers

Amarino Toolkit был создан специально для облегчения последовательной связи Bluetooth между устройством Android и Arduino с Bluetooth.

Question

Я работаю с некоторыми студентами моего университета, разрабатывая простое приложение для Android Bluetooth, которое будет использоваться для последовательной связи (RFCOMM) на микроконтроллере Arduino с подключенным к нему модулем Bluetooth.

Насколько я знаю, я использую правильный адрес Bluetooth и UUID для RFCOMM/SPP 00001101-0000-1000-8000-00805F9B34FB . Мое приложение запускает поток, который пытается подключиться к устройству с помощью BluetoothDevice.createRfcommSocketToServiceRecord(UUID) . Но по той или иной причине мы не видим успешной связи. Операция всегда терпит неудачу при вызове connect() на полученном BluetoothSocket который исходит из вызова выше.

При тестировании на моем HTC Evo , использующем вариант Gingerbread от HTC, вызов connect() обычно терпит неудачу с сообщением об исключении «Обнаружение службы не может быть запущено». Я немного читал и обнаружил, что некоторые говорят, что реализация HTC для RFCOMM в стеке Bluetooth была ошибкой, поэтому мы решили попробовать ее на другом Samsung Samsung Galaxy S. При первом запуске кода все работало отлично. Микроконтроллер Arduino подключен к небольшому электродвигателю, который начал работать, как ожидалось. Я не исключаю, может ли проблема быть на стороне микроконтроллера.

Последующие применения приложения на устройстве Samsung потерпели неудачу, теперь с сообщением «Ошибка обнаружения службы». Для меня кажется, что, возможно, модуль Bluetooth на стороне устройства считает, что служба RFCOMM все еще используется. Но мы перезапустили микроконтроллер и все еще видели тот же результат.

Я только что перечислил код потока, так как все это действительно актуально. Я читал, что есть довольно распространенное обходное решение (взлома) для этих проблем с использованием отражения. Мои попытки на это также потерпели неудачу, но они там и прокомментированы. Надеюсь, кто-то может направить меня в правильном направлении. Также обратите внимание, что у меня есть необходимые разрешения, разрешенные в манифесте, и в обоих случаях устройство было успешно сопряжено с Arduino с помощью пользовательского интерфейса Android.

private class ClientThread extends Thread {

    private String _btAddress;

    /**
     * A handle to the local device's Bluetooth adapter hardware.
     */
    private BluetoothAdapter _btAdapter = BluetoothAdapter.getDefaultAdapter();

    /**
     * A handle to the remote device Bluetooth context.
     */
    private BluetoothDevice _btRemoteDevice;

    /**
     * A handle to the Bluetooth serial socket.
     */
    private BluetoothSocket _btSocket;

    /**
     * Constructor.
     * @param btAddress The BluetoothHardware address.
     */
    public ClientThread(String btAddress)
    {
        _btAddress = btAddress;
    }

    public void run()
    {
        // Retrieves the device identified by the _btAddress property.
        _btRemoteDevice = retrieveDevice();
        if ( _btRemoteDevice == null )
            sendUIMessage( CONNECTION_BT_DEVICE_NOT_BONDED );
        else
            sendBeacon();
    }

    /**
     * Retrieves the device associated with this client thread.
     * @return
     */
    private BluetoothDevice retrieveDevice()
    {
        Set<BluetoothDevice> btDevices = _btAdapter.getBondedDevices();
        for (BluetoothDevice btd : btDevices)
        {
            String addr = btd.getAddress();
            String name = btd.getName();
            if ( addr.equalsIgnoreCase(_btAddress) )
                return btd;
        }
        return null;
    }

    /**
     * Sends the beacon to the Bluetooth device.
     */
    private void sendBeacon()
    {
        // Holds the output stream of the BluetoothDevice.
        OutputStream os = null;

        try
        {
            _btSocket = _btRemoteDevice.createRfcommSocketToServiceRecord( UUID.fromString( "00001101-0000-1000-8000-00805F9B34FB" ) );

            //Method m = _btRemoteDevice.getClass().getMethod("createInsecureRfcommSocket", new Class[] {int.class});
            //_btSocket = (BluetoothSocket) m.invoke(_btRemoteDevice, 1);
            _btSocket.connect();
            os = _btSocket.getOutputStream();
            os.write('L');
        }
        catch (IOException e)
        {
            String message = e.getMessage();
            e.printStackTrace();
            sendUIMessage(CONNECTION_FAILURE_IO);
        }
        catch (Exception e)
        {
            e.printStackTrace();
            sendUIMessage(CONNECTION_FAILURE_UNKNOWN);
        }
        finally
        {
            try
            {
                if (_btSocket != null)
                    _btSocket.close();
            }
            catch (IOException e)
            {
                System.out.println("Failed closing Bluetooth output stream.");
                e.printStackTrace();
            }
        }
    }
}

EDIT: модуль Bluetooth является MDFLY RF-BT0417CB. Я знаю, что код, который работает на arduino, немного отличается и просто связывается с модулем BT, используя Serial.available () и Serial.read (). Однако у меня есть новая информация, которая может быть более полезной. Когда мое приложение было установлено на устройстве Samsung, оно работало только один раз и не выполнялось при последующих испытаниях. Некоторое время назад, с другим учащимся, с которым я работаю, я использовал Android App Inventor (инструмент для перетаскивания мышью), который также может создавать логические рабочие артефакты), чтобы создать простое приложение, которое соединяет тот же модуль BT module / arduino, который работал. Он сказал, что когда мое приложение было установлено, что другое приложение не смогло подключиться к модулю BT, это заставляет меня полагать, что система осталась, думая, что ресурс был выделен для моего приложения. После того как он удалил мое приложение, другой смог подключиться. У него нет исходного кода для другого приложения, но я собираюсь попробовать App Inventor самостоятельно, чтобы узнать, генерирует ли он его исходный код, делает что-то другое. Насколько я знаю, я соблюдаю большинство стандартных практик, определенных в документации Android, поэтому, возможно, это что-то странное в модуле BT или тот факт, что код arduino не обязательно программно управляет модулем BT.

ДРУГОЙ РЕДАКТОР: Я не эксперт по Bluetooth, но мы смогли разобраться в работе. Как известно некоторым, существует куча общедоступных API BluetoothDevice, скрытых во время компиляции, но они юридически доступны во время работы с использованием отражения. Одним из них является createRfCommSocket (int). Этот API не находится в официальной документации, так как он скрыт, но вы можете прочитать его здесь . Я еще не пробовал это с API, поддерживающим документацию, но проблема, похоже, была проблемой параллелизма между телефоном и последовательной платой. Телефон отправил сообщение, которое, конечно, является блокирующим вызовом, и когда оно вернулось оттуда, оно закрыло соединение. Экран на последовательной плате также закроет соединение, и, следовательно, данные не будут доступны для приложения arduino. Мы поняли это, когда наблюдаем успешную связь в режиме отладки на стороне Android, но сбой в режиме выпуска. Добавление задержки на половину секунды на стороне Android, между передачей и закрытием BluetoothSocket устранило проблему. Я не могу сказать, была ли эта проблема связана с кодом arduino или нет, поскольку я не очень хорошо разбираюсь в архитектуре, но у нас, как у студентов, нет опыта, поэтому меня это не удивит.