Я работаю с некоторыми студентами в моем университете над разработкой простого приложения Bluetooth для Android, которое будет использоваться для последовательной связи (RFCOMM) с микроконтроллером Arduino с подключенным модулем Bluetooth.
Насколько мне известно, я использую правильный адрес Bluetooth и UUID для RFCOMM/SPP 00001101-0000-1000-8000-00805F9B34FB
. Мое приложение запускает поток, который пытается подключиться к устройству, используя BluetoothDevice.createRfcommSocketToServiceRecord(UUID)
. Но по той или иной причине мы не видим успешной связи. Операция всегда завершается ошибкой при вызове connect()
для результирующего BluetoothSocket
, полученного из вызова выше.
При тестировании на моем HTC Evo , работающем с вариантом HTC Gingerbread , вызов connect()
обычно завершается ошибкой с сообщением об исключении «Обнаружение службы не может быть запущено». Я немного почитал и обнаружил, что некоторые говорят, что реализация HTC для RFCOMM в стеке Bluetooth глючит, поэтому мы решили попробовать его на 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 / Arduino, который работал. Он сказал, что когда мое приложение было установлено, другое приложение не смогло когда-либо подключиться к модулю BT, что заставило меня поверить, что система продолжала думать, что ресурс был выделен для моего приложения. После того как он удалил мое приложение, другой смог подключиться. У него нет исходного кода для другого приложения, но я собираюсь попробовать App Inventor самостоятельно, чтобы увидеть, не делает ли исходный код, который он генерирует, что-то другое. Насколько мне известно, я соблюдаю большинство стандартных практик, определенных в документации Android, поэтому, возможно, что-то странное в модуле BT или в том факте, что код arduino не обязательно программно контролирует модуль BT.
ДРУГОЕ РЕДАКТИРОВАНИЕ:Я не эксперт по Bluetooth, но мы смогли обойти это.Некоторые знают, что существует множество открытых API BluetoothDevice, которые скрыты во время компиляции, но юридически публичны во время выполнения с использованием отражения.Одним из них является createRfCommSocket (int).Этот API отсутствует в официальной документации, так как он скрыт, но вы можете прочитать его здесь .Я еще не пробовал это с API, поддерживаемым документацией, но проблема, казалось, была чем-то вроде проблемы параллелизма между телефоном и последовательной платой.Трубка отправила сообщение, которое, конечно, является блокирующим вызовом, и когда она оттуда вернулась, закрыла соединение.Экран на последовательной плате также закроет соединение, и, следовательно, данные не будут доступны для приложения Arduino.Мы поняли это, когда стали свидетелями успешного общения в режиме отладки на стороне андроида, но с ошибкой в режиме выпуска.Добавление полсекундной задержки на стороне Android между передачей и закрытием BluetoothSocket решило проблему.Я не могу сказать, была ли эта проблема связана с кодом Arduino или нет, поскольку я не очень знаком с архитектурой, но у нас, как у студентов, нет опыта, поэтому меня это не удивит.