Я работаю с некоторыми студентами моего университета, разрабатывая простое приложение для Android Bluetooth, которое будет использоваться для последовательной связи (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 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, поддерживаемым документацией, но проблема оказалась чем-то вроде проблемы concurrency между телефоном и последовательной платой. Телефон отправил сообщение, которое, конечно, является блокирующим вызовом, и когда оно вернулось оттуда, оно закрыло соединение. Экран на последовательной плате также закроет соединение, и, следовательно, данные не будут доступны для приложения arduino. Мы поняли это, когда наблюдаем успешную связь в режиме отладки на стороне Android, но сбой в режиме выпуска. Добавление задержки на половину секунды на стороне Android, между передачей и закрытием BluetoothSocket устранило проблему. Я не могу сказать, была ли эта проблема связана с кодом arduino или нет, поскольку я не очень хорошо разбираюсь в архитектуре, но у нас, как у студентов, нет опыта, поэтому меня это не удивит.