我正在和我大学的一些学生合作,开发一个简单的蓝牙Android应用程序,用于串行通信(RFCOMM)到连接蓝牙模块的Arduino微控制器。
据我所知,我正在为RFCOMM/SPP 00001101-0000-1000-8000-00805F9B34FB
使用正确的蓝牙地址和UUID。我的应用程序启动了一个尝试使用BluetoothDevice.createRfcommSocketToServiceRecord(UUID)
连接到设备的线程。但由于某种原因,我们没有看到成功的联系。在对来自上面调用的结果connect()
调用BluetoothSocket
时,操作总是失败。
在我的HTC Evo上运行,运行HTC的Gingerbread变体时,connect()
调用通常会失败,并显示异常消息“无法启动服务发现”。我做了一些阅读,发现有人说HTC在蓝牙堆栈中对RFCOMM的实现是错误的,所以我们决定在另一个学生Samsung Galaxy S上尝试。代码第一次运行时,一切都运行良好。 Arduino微控制器连接到一个小电动机,开始按预期工作。我还没有排除问题是否存在于微控制器方面。
随后在Samsung设备上使用该应用程序失败,现在显示“Service Discovery Failed”消息。对我来说,似乎设备端的蓝牙模块可能认为RFCOMM服务仍在使用中。但是我们重新启动了微控制器并且仍然看到了相同的结果。
我刚刚列出了线程代码,因为它是真正相关的。我已经读过使用反射这些问题有一个非常常见的解决方法(hack)。我对它的尝试也失败了但是在那里并且被注释掉了。希望有人能引导我朝着正确的方向前进。另请注意,我确实在清单中启用了必要的权限,在这两种情况下,设备都使用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不在官方文档中,因为它是隐藏的,但您可以阅读它here。我还没有尝试使用文档支持的API,但问题似乎是手机和串行板之间的并发问题。手机发送了一条消息,这当然是一个阻塞呼叫,当它从那里返回时,关闭了连接。然后,串行板上的屏蔽也将关闭连接,因此arduino应用程序无法获得数据。我们在android端调试模式下见证成功通信时意识到这一点,但在发布模式下失败了。在android端添加半秒延迟,在BluetoothSocket的传输和关闭之间修复了这个问题。我不能说这个问题是否归因于arduino代码,因为我对这个架构不是很熟悉,但是我们学生们缺乏经验,所以我不会感到惊讶。
答案 0 :(得分:1)
Communication Between Android And Arduino With Bluetooth(1)
我认为这会对你有所帮助。 你能提供一些细节吗。我看过一个链接,你也可以看到这个。让我知道这是有帮助还是没有? How to create Insecure RFCOMM Socket in Android?
答案 1 :(得分:0)
Amarino Toolkit专门用于促进Android设备和带蓝牙的Arduino之间的串行蓝牙通信。