RFCOMM/SPP 00001101-0000-1000-8000-00805F9B34FB
。我的应用程序启动了一个线程,尝试使用BluetoothDevice.createRfcommSocketToServiceRecord(UUID)
连接到设备。但出于某种原因,我们没有看到成功的连接。在上面的调用中得到的BluetoothSocket
调用connect()
时,操作总是失败。在我的HTC Evo上测试时,运行HTC的Gingerbread变体,connect()
调用通常会出现异常消息“无法启动服务发现”。我阅读了一些资料,并发现有人说HTC的蓝牙堆栈中RFCOMM的实现存在缺陷,因此我们决定在另一个学生的Samsung Galaxy S上尝试。代码第一次运行时,一切正常。Arduino微控制器连接到一个小电机上,该电机按预期工作。我还没有排除问题可能在微控制器方面的可能性。在三星设备上后续使用该应用程序失败,显示“服务发现失败”消息。对我来说,似乎设备端的蓝牙模块认为RFCOMM服务仍在使用中。但是我们已经重新启动了微控制器,仍然看到了相同的结果。
我只列出了线程代码,因为这是真正相关的内容。我读到有一种常见的解决方法(黑客)可以使用反射解决这些问题。我的尝试也失败了,但注释中有尝试的代码。希望有人能引导我正确的方向。还请注意,我已经在清单中启用了必要的权限,并且在两种情况下,设备都成功地使用Android的用户界面与Arduino配对。
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();
}
}
}
}
编辑: 蓝牙模块是MDFLY RF-BT0417CB。我知道在Arduino上运行的代码不多,只是使用Serial.available()和Serial.read()与BT模块通信。然而,我有一个新的信息可能更有用。当我的应用程序安装在三星设备上时,它只工作了一次,在后续尝试中失败了。之前,我和另一个学生一起工作,他使用Android App Inventor(一个拖放GUI工具,也可以创建逻辑工件)创建了一个连接相同BT模块/arduino板的简单应用程序,它能够正常工作。他说,当我的应用程序被安装后,其他应用程序无法连接到BT模块,这让我相信系统仍然认为该资源被分配给了我的应用程序。在卸载我的应用程序后,其他应用程序能够连接。他没有其他应用程序的源代码,但我打算自己尝试App Inventor,看看它生成的源代码是否有任何不同。据我所知,我遵守了Android文档中定义的大多数标准实践,因此可能是BT模块或Arduino代码并非以编程方式控制BT模块的某些奇怪因素。
另一个编辑: 我不是蓝牙专家,但我们成功找到了解决方法。正如某些人所知,有许多公共的BluetoothDevice API,在编译时被隐藏起来,但在运行时使用反射是合法的。其中之一是createRfCommSocket(int)。这个API没有出现在官方文档中,因为它是隐藏的,但你可以在这里阅读到它。我还没有尝试过文档支持的API,但问题似乎是手机和串口板之间的并发问题。手机发送消息,当然是阻塞调用,当它从那里返回时,关闭连接。串口板上的Shield将关闭连接,因此数据不可用于arduino应用程序。当我们在Android端的调试模式下观察到成功的通信,但发布模式下失败时,我们意识到了这一点。在传输和关闭BluetoothSocket之间在android端添加半秒延迟可以解决这个问题。我不能确定这个问题是否归因于arduino代码,因为我对架构不太熟悉,但我们作为学生缺乏经验,这并不会让我感到惊讶。