【背景】
手上有个android设备:
- 平板PAD:三星的Galaxy Tab 3 10.1 GT-P5210
- 其中带有蓝牙模块。
- 另外有个蓝牙的HART猫:
- 【记录】折腾蓝牙接口的HART猫:MACTek的Viator蓝牙HART猫
- 是对应的CSR8510 A10的芯片的。
- HART设备
- 蓝牙HART猫已连接好的
现在希望可以在PAD上通过蓝牙去连接蓝牙的HART猫,然后再去操作HART的设备。
现在就是去android中写对应的蓝牙模块的程序,此处暂且叫做蓝牙驱动吧。
其中此处的开发环境是ADT。
【折腾过程】
1.参考:
Bluetooth | Android Developers
去添加权限:
添加好了:
2.
参考代码期间,遇到:
【已解决】Android的蓝牙实例代码中找不到REQUEST_ENABLE_BT
然后再去用BluetoothAdapter去检测是否支持蓝牙,且支持的话去打开:
private final int REQUEST_ENABLE_BT = 1;
private BluetoothAdapter mBluetoothAdapter;
private void testBluetooth() {
mBluetoothAdapter= BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
// Device does not support Bluetooth
Toast.makeText(getApplicationContext(), "Device does not support Bluetooth", Toast.LENGTH_LONG).show();
}
else{
//android.bluetooth.BluetoothAdapter@211120b0
Toast.makeText(getApplicationContext(), "Device support Bluetooth", Toast.LENGTH_SHORT).show();
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
else{
scanOrDiscoverBtDevices();
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == REQUEST_ENABLE_BT)
{
if(resultCode == RESULT_OK){
Toast.makeText(getApplicationContext(), "Enabled Bluetooth now", Toast.LENGTH_LONG).show();
scanOrDiscoverBtDevices();
}
else{
Toast.makeText(getApplicationContext(), "Not enable Bluetooth !", Toast.LENGTH_LONG).show();
}
}
}3.关于检测蓝牙状态变化,而去实现蓝牙被打开还是关闭了,可以参考:
Optionally, your application can also listen for the ACTION_STATE_CHANGED broadcast Intent, which the system will broadcast whenever the Bluetooth state has changed. This broadcast contains the extra fields EXTRA_STATE and EXTRA_PREVIOUS_STATE, containing the new and old Bluetooth states, respectively. Possible values for these extra fields are STATE_TURNING_ON, STATE_ON, STATE_TURNING_OFF, and STATE_OFF. Listening for this broadcast can be useful to detect changes made to the Bluetooth state while your app is running. |
4.另外,看到提示了:
| Tip: Enabling discoverability will automatically enable Bluetooth. If you plan to consistently enable device discoverability before performing Bluetooth activity, you can skip step 2 above. Read about enabling discoverability, below. |
这也就是我之前疑惑的:
别的那个android的app,可以点击开启蓝牙,而无需弹出请求权限的对话框。
就是通过这个discovery功能实现的。
提示:
后来又遇到:
【已解决】Android中运行startActivityForResult后但是onActivityResult不执行
5.目前已经实现了,既可以scan那些paired,也可以discover搜寻当前附近的蓝牙设备。
代码如下:
private final int REQUEST_ENABLE_BT = 1;
private BluetoothAdapter mBluetoothAdapter;
private void testBluetooth() {
mBluetoothAdapter= BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
// Device does not support Bluetooth
Toast.makeText(getApplicationContext(), "Device does not support Bluetooth", Toast.LENGTH_LONG).show();
}
else{
//android.bluetooth.BluetoothAdapter@211120b0
Toast.makeText(getApplicationContext(), "Device support Bluetooth", Toast.LENGTH_SHORT).show();
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
else{
scanOrDiscoverBtDevices();
}
}
}
private void scanOrDiscoverBtDevices(){
//scanBtDevices();
discoverBtDevices();
}
// Create a BroadcastReceiver for ACTION_FOUND
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice btDev = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
//mArrayAdapter.add(btDev.getName() + "\n" + btDev.getAddress());
Toast.makeText(getApplicationContext(), btDev.getName() + "\n" + btDev.getAddress(), Toast.LENGTH_LONG).show();
}
}
};
private void discoverBtDevices(){
// Register the BroadcastReceiver
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy
mBluetoothAdapter.startDiscovery();
}
private void scanBtDevices(){
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices(); //[BC:85:1F:96:99:C9, 00:06:66:4C:75:FE]
// If there are paired devices
if (pairedDevices.size() > 0) {
//ArrayAdapter mArrayAdapter = new ArrayAdapter();
// Loop through paired devices
for (BluetoothDevice btDev : pairedDevices) {
//mArrayAdapter.add(btDev.getName() + "\n" + btDev.getAddress());
Toast.makeText(getApplicationContext(), btDev.getName() + "\n" + btDev.getAddress(), Toast.LENGTH_LONG).show();
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == REQUEST_ENABLE_BT)
{
if(resultCode == RESULT_OK){
Toast.makeText(getApplicationContext(), "Enabled Bluetooth now", Toast.LENGTH_LONG).show();
scanOrDiscoverBtDevices();
}
else{
Toast.makeText(getApplicationContext(), "Not enable Bluetooth !", Toast.LENGTH_LONG).show();
}
}
}6.继续折腾。
对于可以被搜索“Enabling discoverability”暂时就不去关心了。毕竟当前android设备能搜到HART猫即可。暂时无需考虑被搜索到。
7.再去建立连接,期间出现UUID和connect失败方面的问题:
【已解决】Android中连接蓝牙设备时遇到createRfcommSocketToServiceRecord的UUID问题和BluetoothSocket的connect失败
最终,用如下代码:
private String mactekHartModemName;
private UUID mactekHartModemUuid;
//void afterFoundBtHartModem(BluetoothDevice btDev, Parcelable[] btDevUuid){
void afterFoundBtHartModem(BluetoothDevice btDev, UUID btDevUuid){
if(null != btDevUuid){
}
//mactekHartModemName = btDev.getName(); //"MACTekViator75FE"
//mactekHartModemUuid = UUID.fromString(mactekHartModemName);
String uuidValue;
//http://www.guidgenerator.com/online-guid-generator.aspx
//uuidValue = "e214d9ae-c3ba-4e25-abb5-299041353bc3";
//https://groups.google.com/forum/#!topic/android-developers/vyTEJOXELos
//uuidValue = "00001101-0000-1000-8000-00805F9B34FB";
//uuidValue = "00000003-0000-1000-8000-00805F9B34FB";
uuidValue = "00001101-0000-1000-8000-00805F9B34FB";
mactekHartModemUuid = UUID.fromString(uuidValue);
ConnectThread connectBtThread = new ConnectThread(btDev);
connectBtThread.start();
}
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to mmSocket,
// because mmSocket is final
BluetoothSocket tmp = null;
mmDevice = device;
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
// MY_UUID is the app's UUID string, also used by the server code
tmp = device.createRfcommSocketToServiceRecord(mactekHartModemUuid);//00001101-0000-1000-8000-00805F9B34FB
} catch (IOException e) { }
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it will slow down the connection
mBluetoothAdapter.cancelDiscovery();
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mmSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and get out
try {
mmSocket.close();
} catch (IOException closeException) { }
return;
}
// Do work to manage the connection (in a separate thread)
manageConnectedSocket(mmSocket);
}
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}可以正常触发android系统打开配对窗口,输入密码:
后,是可以配对成功的:
8.然后接着再去试试发送数据给蓝牙HART猫是否成功,能否收到返回的数据。
最后所用代码为:
private final int REQUEST_ENABLE_BT = 1;
private BluetoothAdapter mBluetoothAdapter;
private void testBluetooth() {
mBluetoothAdapter= BluetoothAdapter.getDefaultAdapter();
if (mBluetoothAdapter == null) {
// Device does not support Bluetooth
Toast.makeText(getApplicationContext(), "Device does not support Bluetooth", Toast.LENGTH_LONG).show();
}
else{
//android.bluetooth.BluetoothAdapter@211120b0
Toast.makeText(getApplicationContext(), "Device support Bluetooth", Toast.LENGTH_SHORT).show();
if (!mBluetoothAdapter.isEnabled()) {
Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
}
else{
scanOrDiscoverBtDevices();
}
}
}
private void scanOrDiscoverBtDevices(){
//scanBtDevices();
discoverBtDevices();
}
// Create a BroadcastReceiver for ACTION_FOUND
private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
// When discovery finds a device
if (BluetoothDevice.ACTION_FOUND.equals(action)) {
// Get the BluetoothDevice object from the Intent
BluetoothDevice btDev = intent.getParcelableExtra(BluetoothDevice.EXTRA_DEVICE);
//mArrayAdapter.add(btDev.getName() + "\n" + btDev.getAddress());
String btDevName = btDev.getName();
String btDevMacAddr = btDev.getAddress();
Toast.makeText(getApplicationContext(), btDevName + "\n" + btDevMacAddr, Toast.LENGTH_LONG).show();
if(btDevName.contains("MACTekViator")){ //MACTekViator75FE
afterFoundBtHartModem(btDev);
}
}
}
};
private void discoverBtDevices(){
// Register the BroadcastReceiver
IntentFilter filter = new IntentFilter(BluetoothDevice.ACTION_FOUND);
registerReceiver(mReceiver, filter); // Don't forget to unregister during onDestroy
mBluetoothAdapter.startDiscovery();
}
private void scanBtDevices(){
Set<BluetoothDevice> pairedDevices = mBluetoothAdapter.getBondedDevices();
//[BC:85:1F:96:99:C9, 00:06:66:4C:75:FE]
// If there are paired devices
if (pairedDevices.size() > 0) {
// Loop through paired devices
for (BluetoothDevice btDev : pairedDevices) {
//mArrayAdapter.add(btDev.getName() + "\n" + btDev.getAddress());
//Toast.makeText(getApplicationContext(), btDev.getName() + "\n" + btDev.getAddress(), Toast.LENGTH_LONG).show();
String btDevName = btDev.getName();
String btDevMacAddr = btDev.getAddress();
Toast.makeText(getApplicationContext(), btDevName + "\n" + btDevMacAddr, Toast.LENGTH_LONG).show();
if(btDevName.contains("MACTekViator")){ //found our concerned Bluetooth HART Modem
afterFoundBtHartModem(btDev);
break;
}
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if(requestCode == REQUEST_ENABLE_BT)
{
if(resultCode == RESULT_OK){
Toast.makeText(getApplicationContext(), "Enabled Bluetooth now", Toast.LENGTH_LONG).show();
scanOrDiscoverBtDevices();
}
else{
Toast.makeText(getApplicationContext(), "Not enable Bluetooth !", Toast.LENGTH_LONG).show();
}
}
}
private UUID mactekHartModemUuid;
void afterFoundBtHartModem(BluetoothDevice btDev){
String sspUuid;
//http://developer.android.com/reference/android/bluetooth/BluetoothDevice.html#createRfcommSocketToServiceRecord%28java.util.UUID%29
//Hint: If you are connecting to a Bluetooth serial board then try using the well-known SPP UUID 00001101-0000-1000-8000-00805F9B34FB.
//However if you are connecting to an Android peer then please generate your own unique UUID.
sspUuid = "00001101-0000-1000-8000-00805F9B34FB";
mactekHartModemUuid = UUID.fromString(sspUuid);
ConnectThread connectBtThread = new ConnectThread(btDev);
connectBtThread.start();
}
private class ConnectThread extends Thread {
private final BluetoothSocket mmSocket;
private final BluetoothDevice mmDevice;
public ConnectThread(BluetoothDevice device) {
// Use a temporary object that is later assigned to mmSocket,
// because mmSocket is final
BluetoothSocket tmp = null;
mmDevice = device;
// Get a BluetoothSocket to connect with the given BluetoothDevice
try {
// MY_UUID is the app's UUID string, also used by the server code
tmp = device.createRfcommSocketToServiceRecord(mactekHartModemUuid);//00001101-0000-1000-8000-00805F9B34FB
} catch (IOException e) { }
mmSocket = tmp;
}
public void run() {
// Cancel discovery because it will slow down the connection
mBluetoothAdapter.cancelDiscovery();
try {
// Connect the device through the socket. This will block
// until it succeeds or throws an exception
mmSocket.connect();
} catch (IOException connectException) {
// Unable to connect; close the socket and get out
try {
mmSocket.close();
} catch (IOException closeException) { }
return;
}
// Do work to manage the connection (in a separate thread)
manageConnectedSocket(mmSocket);
}
/** Will cancel an in-progress connection, and close the socket */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
private void manageConnectedSocket(BluetoothSocket socket){
//Toast.makeText(getApplicationContext(), "Bluetooth HART Modem Connected", Toast.LENGTH_LONG).show();
ConnectedThread connectedThread = new ConnectedThread(socket);
connectedThread.start();
//command 0
String command0Str = "FFFFFFFFFF0280000082";
byte[] commnd0Bytes = HexString2Bytes(command0Str);
connectedThread.write(commnd0Bytes);
//read out command 0 response
byte[] readoutBuffer = new byte[1024];
//Note: here use DEBUG, so will take some time, so follow can read out real response data
//if no DEBUG, just run through, will only get -1
//readoutBuffer = connectedThread.read(); //[-1,
readoutBuffer = connectedThread.read(); //[-1, -1, -1, -1, 6, -128, 0, 14, 0, 69, -2, 54, 2, 5, 5, 2, 13, 1, 3, 43, -11, -82, 122, 0, 0, 0, 0,
parseHartCommand0Resp(readoutBuffer);
//readoutBuffer = connectedThread.read();
}
private void parseHartCommand0Resp(byte[] command0RespBytes){
//-1, -1, -1, -1, 6, -128, 0, 14, 0, 69, -2, 54, 2, 5, 5, 2, 13, 1, 3, 43, -11, -82, 122,
//FF FF FF FF 06 80 00 0E 00 45 FE 36 02 05 02 0D 01 03 2B F5 AE 7A
//(hex value) --->
//FF FF FF FF 06 80 00 0E 00 45
//FE ==254(expansion)
//ManufactureIdentificationCode=36==Yamatake
//ManufactureDeviceType=02
//PreampleNumber=5
//UniversalCommandRevision=5==HART5
//DeviceSpecificCommandRevision=2
//SoftwareRevision=13
//HardwareRevision=1
//DeviceFunctionFlag=3
//DeviceIdNumber=2B F5 AE
//CommonPracticeCommandRevision=7A
}
private boolean isReadoutRespOk = false;
private class ConnectedThread extends Thread {
private final BluetoothSocket mmSocket;
private final InputStream mmInStream;
private final OutputStream mmOutStream;
public ConnectedThread(BluetoothSocket socket) {
mmSocket = socket;
InputStream tmpIn = null;
OutputStream tmpOut = null;
// Get the input and output streams, using temp objects because
// member streams are final
try {
tmpIn = socket.getInputStream();
tmpOut = socket.getOutputStream();
} catch (IOException e) { }
mmInStream = tmpIn;
mmOutStream = tmpOut;
}
public void run() {
// byte[] buffer = new byte[1024]; // buffer store for the stream
// int bytes; // bytes returned from read()
//
// // Keep listening to the InputStream until an exception occurs
// while (true) {
// try {
// // Read from the InputStream
// bytes = mmInStream.read(buffer);
// // Send the obtained bytes to the UI activity
// //mHandler.obtainMessage(MESSAGE_READ, bytes, -1, buffer).sendToTarget();
// if(bytes > 0){
// //Toast.makeText(getApplicationContext(), "Got HART Command 0 resp data: " + buffer.toString(), Toast.LENGTH_LONG).show();
// isReadoutRespOk = true;
//
// //-1, -1, -1, -1, 6, -128, 0, 14, 0, 69, -2, 54, 2, 5, 5, 2, 13, 1, 3, 43, -11, -82, 122,
// //parseHartCommand0ResponseData();
// }
// else{
// isReadoutRespOk = false;
// }
//
// } catch (IOException e) {
// break;
// }
// }
}
/* Call this from the main activity to send data to the remote device */
public void write(byte[] bytes) {
try {
mmOutStream.write(bytes);
} catch (IOException e) { }
}
public byte[] read() {
byte[] buffer = new byte[1024]; // buffer store for the stream
int bytes;
try {
bytes = mmInStream.read(buffer);
} catch (IOException e) {
}
return buffer;
}
/* Call this from the main activity to shutdown the connection */
public void cancel() {
try {
mmSocket.close();
} catch (IOException e) { }
}
}
//copy from other code
// string to hex array
public byte[] HexString2Bytes(String hexStr) {
if (null == hexStr || 0 == hexStr.length()) {
return null;
}
byte[] ret = new byte[hexStr.length() / 2];
byte[] tmp = hexStr.getBytes();
for (int i = 0; i < (tmp.length / 2); i++) {
ret[i] = uniteBytes(tmp[i * 2], tmp[i * 2 + 1]);
}
return ret;
}
private byte uniteBytes(byte src0, byte src1) {
byte _b0 = Byte.decode("0x" + new String(new byte[] { src0 }))
.byteValue();
_b0 = (byte) (_b0 << 4);
byte _b1 = Byte.decode("0x" + new String(new byte[] { src1 }))
.byteValue();
byte result = (byte) (_b0 | _b1);
return result;
}
【总结】
至此,终于算是跑通了,可以通过:
平板上面的蓝牙,扫描找到蓝牙HART猫,然后通过HART猫发送command 0给HART设备,获得对应的信息:
注:
此处所用的HART设备和这里:
【记录】试用通过蓝牙操作HART设备的Android的程序:teknikol COMMANDER
是一样的:
![]()
所以上述代码解析后的信息,也是和之前一致的。
转载请注明:在路上 » 【记录】编写Android中的蓝牙模块驱动和底层HART设备