蓝牙项目开发心得

一,发射器情况:有1个Service,Service下有2个Characteristic,其中1个Characteristic命名为writeCharacteristic(FFF1)具有read,write 2个属性,另外1个Characteristic命名为notifyCharacteristic(FFF2)具有notify属性

以上信息可以在获得Characteristic后用日志查看,代码如下:writeCharacteristic的Properties返回10,说明具有 PROPERTY_READ(和PROPERTY_WRITE (8)

for (BluetoothGattCharacteristic gattCharacteristic : gattCharacteristics) {
    uuidCharac = gattCharacteristic.getUuid().toString();
    if (writeCharacUUID.equals(uuidCharac) ){
        mWiriteCharacteristic=gattCharacteristic;
        System.out.println("s-2 myCharacter + uuid=" + uuidCharac);
        System.out.println("s-3 myCharacter + toString=" + gattCharacteristic.toString());
        System.out.println("s-3 myCharacter + Permissions=" + gattCharacteristic.getPermissions());
        System.out.println("s-3 myCharacter + Properties=" + gattCharacteristic.getProperties());
        System.out.println("s-3 myCharacter + WriteType=" + gattCharacteristic.getWriteType());
        System.out.println("s-3 myCharacter + Value=" + gattCharacteristic.getValue());
        charas.add(gattCharacteristic);
    }
   else if(notifyCharaUUID.equals(uuidCharac)) {
        mNotifyCharacteristic=gattCharacteristic;
        System.out.println("s-2 myCharacter + uuid=" + uuidCharac);
        System.out.println("s-3 myCharacter + toString=" + gattCharacteristic.toString());
        System.out.println("s-3 myCharacter + Permissions=" + gattCharacteristic.getPermissions());
        System.out.println("s-3 myCharacter + Properties=" + gattCharacteristic.getProperties());
        System.out.println("s-3 myCharacter + WriteType=" + gattCharacteristic.getWriteType());
        System.out.println("s-3 myCharacter + Value=" + gattCharacteristic.getValue());
        charas.add(gattCharacteristic);
    }
}输出结果如下:08-14 07:59:02.626 15236-15236/com.klt.kamin.cgmbasedemo I/System.out: s-1 myServices + uuid=0000fff0-0000-1000-8000-00805f9b34fb
08-14 07:59:02.627 15236-15236/com.klt.kamin.cgmbasedemo I/System.out: s-2 myCharacter + uuid=0000fff1-0000-1000-8000-00805f9b34fb
08-14 07:59:02.627 15236-15236/com.klt.kamin.cgmbasedemo I/System.out: s-3 myCharacter + toString=android.bluetooth.BluetoothGattCharacteristic@dee0c13
08-14 07:59:02.627 15236-15236/com.klt.kamin.cgmbasedemo I/System.out: s-3 myCharacter + Permissions=0
08-14 07:59:02.627 15236-15236/com.klt.kamin.cgmbasedemo I/System.out: s-3 myCharacter + Properties=10
08-14 07:59:02.627 15236-15236/com.klt.kamin.cgmbasedemo I/System.out: s-3 myCharacter + WriteType=2
08-14 07:59:02.627 15236-15236/com.klt.kamin.cgmbasedemo I/System.out: s-3 myCharacter + Value=null
08-14 07:59:02.627 15236-15236/com.klt.kamin.cgmbasedemo I/System.out: s-2 myCharacter + uuid=0000fff2-0000-1000-8000-00805f9b34fb
08-14 07:59:02.627 15236-15236/com.klt.kamin.cgmbasedemo I/System.out: s-3 myCharacter + toString=android.bluetooth.BluetoothGattCharacteristic@fbb1e50
08-14 07:59:02.627 15236-15236/com.klt.kamin.cgmbasedemo I/System.out: s-3 myCharacter + Permissions=0
08-14 07:59:02.627 15236-15236/com.klt.kamin.cgmbasedemo I/System.out: s-3 myCharacter + Properties=16
08-14 07:59:02.627 15236-15236/com.klt.kamin.cgmbasedemo I/System.out: s-3 myCharacter + WriteType=2
08-14 07:59:02.627 15236-15236/com.klt.kamin.cgmbasedemo I/System.out: s-3 myCharacter + Value=null

二,任务:手机APP中输入指定命令,发送后,发射器会把执行结果返回到手机APP上显示

1蓝牙连接成功后,把所有Characteristic查找到

2执行下面代码使能notifyCharacteristic的notify, 将会在此通道(FFF2)产生有关命令操作的执行结果通知。

mSCharacteristic=mNotifyCharacteristic;
mBluetoothLeService.setCharacteristicNotification(mNotifyCharacteristic, true);

3执行代码writeCharacteristic对通道FFF1进行写命令操作,每产生一次采集结果后,将会在FFF2通道产生一个 notify 通知事件,附带了本次采集结果, APP 可以直接在回调函数中进行处理和使用。

public void serialSend(String theString){
System.out.println("w-2-1 In CgmLibrary.serialSend(serialSendText),mConnectionState="+mConnectionState.toString());if (mConnectionState == connectionStateEnum.isConnected) {    
    mSCharacteristic=mWiriteCharacteristic;
    mSCharacteristic.setValue(Conversion.hexStringToByteArray(theString));//写之前必须把输入的命令转换为十六进制字符串
    mBluetoothLeService.writeCharacteristic(mSCharacteristic);   
}} mBluetoothLeService.writeCharacteristic(mSCharacteristic)代码如下: public void writeCharacteristic(BluetoothGattCharacteristic characteristic) {if (mBluetoothAdapter == null || mBluetoothGatt == null) {
    Log.w(TAG, "BluetoothAdapter not initialized");
    return;
}
mBluetoothGatt.writeCharacteristic(characteristic);}System.out.println("w-3-1 In BluetoothLeService.writeCharacteristic(characteristic)---->before mBluetoothGatt.writeCharacteristic(characteristic)/**********" );mBluetoothGatt.writeCharacteristic(characteristic);如果把命令成功写到发射器,会触发:BluetoothGattCallback的  onCharacteristicWrite方法:这个方法没有做任何事情可以删除掉  public void onCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status)
        {
            System.out.println("w-5 in onCharacteristicWrite,buttonSerialSend-->serialSend->writeCharacteristic-->status="+status);
            //this block should be synchronized to prevent the function overloading
            synchronized(this)
            {    //CharacteristicWrite success
                if(status == BluetoothGatt.GATT_SUCCESS)
                {
                    System.out.println(" w-6 in onCharacteristicWrite-status == BluetoothGatt.GATT_SUCCESS--characteristicValue:"+ new String(Conversion.byteArrayToHexStr(characteristic.getValue())));
                }
                else     //CharacteristicWrite fail
                {
                    System.out.println("w-7 onCharacteristicWrite fail:"+ new String(characteristic.getValue()));
                    System.out.println(status);
                }
            }
        }每产生一次采集结果后,将会在FFF2通道产生一个 notify 通知事件,附带了本次采集结果,APP 可以直接在回调函数onCharacteristicChanged中进行处理和使用。处理完的结果通过广播返回到界面或者保存到数据库  @Override
    public void onCharacteristicChanged(BluetoothGatt gatt,
                                        BluetoothGattCharacteristic characteristic) {
        System.out.println("w-5-1 In BluetoothLeService.onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic)/$$$$$$$$$$$$");
        System.out.println("w-5-2 onCharacteristicChanged characValue return from emmiter="+characteristic.getValue());
        System.out.println("w-5-2 onCharacteristicChanged characValue return from emmiter with HexString=" + Conversion.byteArrayToHexStr(characteristic.getValue()));
        System.out.println("w-5-2 onCharacteristicChanged characValue return from emmiter with new String=" + new String(characteristic.getValue()));
        broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
        System.out.println("w-5-1 In BluetoothLeService.onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic)$$$$$$$$$$$$/");
    }
}  private void broadcastUpdate(final String action,
                                 final BluetoothGattCharacteristic characteristic) {
        System.out.println("w-6-1 In BluetoothLeService.broadcastUpdate(String action, BluetoothGattCharacteristic characteristic),action=ACTION_DATA_AVAILABLE/@@@@@@@@@@@");
        final Intent intent = new Intent(action);
        final byte[] data = characteristic.getValue();
        if (data != null && data.length > 0) {
            if(Conversion.verifyCommand(data)){
            System.out.println("w-6-2 after Verify and Success in broadcastUpdate,only data,cut first byte and last byte--->DATAascii:"+Conversion.getDataToPrint(data));
            intent.putExtra(EXTRA_DATA,Conversion.getDataToPrint(data));
            }
            sendBroadcast(intent);
        }
        System.out.println("w-6-1 In BluetoothLeService.broadcastUpdate(String action, BluetoothGattCharacteristic characteristic),action=ACTION_DATA_AVAILABLE@@@@@@@@@@@/");
    }

4要考虑十六进制转换

(1)输入的命令转换为十六进制字节数组

mSCharacteristic.setValue(Conversion.hexStringToByteArray(theString));
mBluetoothLeService.writeCharacteristic(mSCharacteristic);

在App输入框中输入执行命令:0155AA00这是个字符串,并不代表你的真实目的,你是把这个字符串看成4个字节的16进制形式的命令:00000001  01010101  10101010  00000000,但由于是String类型,计算机中每个字符是1个字节,所以计算机把你的输入当作11个字节的数据00000000 00000001 00000101 00000101 00001010 00001010 00000000 00000000,显然这是错误的,所以,首先需要把你输入的十六进制形式的命令转换为字节数组,代码如下:

/**
  * Convert hex String to Byte Array
  * example:String str="43474D"; byte[] result=Conversion.hexStringToByteArray(str); for(byte b:result) System.out.print(b+" ");
  * System.out.println(); System.out.println("byteArry to StringAscii----"+new String(result));
  * example result    67 71 77 
  *       byteArry to StringAscii----CGM
  * @param hexString
  * @return byte[]
  */
 public static byte[] hexStringToByteArray(String hexString) {
  hexString=hexString.toUpperCase();
  hexString=hexString.replace(" ", "");
  int len = (hexString.length() / 2);
  byte[] result = new byte[len];
  char[] achar = hexString.toCharArray();
  for (int i = 0; i < len; i++) {
   int pos = i * 2;
   result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
  }
  return result;
 }

(2)获取到的数据需要进行处理

三、执行结果

08-15 23:16:22.287 13742-13742/com.klt.kamin.cgmbasedemo I/System.out: w-1 in MainActivity.onCreate()-->serialSend(serialSendText)/****************************************
08-15 23:16:22.287 13742-13742/com.klt.kamin.cgmbasedemo I/System.out: w-2-1 In CgmLibrary.serialSend(serialSendText),mConnectionState=isConnected
08-15 23:16:22.287 13742-13742/com.klt.kamin.cgmbasedemo I/System.out: w-2-2 CgmLibrary.serialSend(serialSendText),OLD  mSCharacteristicUUID=0000fff2-0000-1000-8000-00805f9b34fb
08-15 23:16:22.287 13742-13742/com.klt.kamin.cgmbasedemo I/System.out: w-2-2 CgmLibrary.serialSend(serialSendText),NOW NEW mSCharacteristicUUID=0000fff1-0000-1000-8000-00805f9b34fb
08-15 23:16:22.289 13742-13742/com.klt.kamin.cgmbasedemo I/System.out: w-2-3 CgmLibrary.serialSend(serialSendText),mSCharacteristicWriteValueHex=0155AA00
08-15 23:16:22.289 13742-13742/com.klt.kamin.cgmbasedemo I/System.out: w-2-3 CgmLibrary.serialSend(serialSendText),mSCharacteristicWriteValueByte=[B@bbc67ba
08-15 23:16:22.289 13742-13742/com.klt.kamin.cgmbasedemo I/System.out: w-2-4 In CgmLibrary.serialSend(serialSendText)---->mBluetoothLeService.writeCharacteristic(mSCharacteristic)/********************
08-15 23:16:22.290 13742-13742/com.klt.kamin.cgmbasedemo I/System.out: w-3-1 In BluetoothLeService.writeCharacteristic(characteristic)---->before mBluetoothGatt.writeCharacteristic(characteristic)/**********
08-15 23:16:22.292 13742-13742/com.klt.kamin.cgmbasedemo I/System.out: w-3-2 In BluetoothLeService.writeCharacteristic(characteristic)---->after mBluetoothGatt.writeCharacteristic(characteristic)**********/
08-15 23:16:22.292 13742-13742/com.klt.kamin.cgmbasedemo I/System.out: w-2-4 In CgmLibrary.serialSend(serialSendText)---->after mBluetoothLeService.writeCharacteristic(mSCharacteristic)********************/
08-15 23:16:22.292 13742-13742/com.klt.kamin.cgmbasedemo I/System.out: w-1 in MainActivity.onCreate() after serialSend()****************************************/
08-15 23:16:23.413 13742-13755/com.klt.kamin.cgmbasedemo I/System.out: w-5-1 In BluetoothLeService.onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic)/$$$$$$$$$$$$
08-15 23:16:23.416 13742-13755/com.klt.kamin.cgmbasedemo I/System.out: w-5-2 onCharacteristicChanged characValue return from emmiter=[B@aaf066b
08-15 23:16:23.417 13742-13755/com.klt.kamin.cgmbasedemo I/System.out: w-5-2 onCharacteristicChanged characValue return from emmiter with HexString=01 53 4E 30 36 31 36 30 30 35 30 34 
08-15 23:16:23.417 13742-13755/com.klt.kamin.cgmbasedemo I/System.out: w-5-2 onCharacteristicChanged characValue return from emmiter with String=�SN061600504
08-15 23:16:23.417 13742-13755/com.klt.kamin.cgmbasedemo I/System.out: w-6-1 In BluetoothLeService.broadcastUpdate(String action, BluetoothGattCharacteristic characteristic),action=ACTION_DATA_AVAILABLE/@@@@@@@@@@@
08-15 23:16:23.418 13742-13755/com.klt.kamin.cgmbasedemo I/System.out: w-6-2 after Verify and Success in broadcastUpdate,only data,cut first byte and last byte--->dataByteWithHex:53 4E 30 36 31 36 30 30 35 30 
08-15 23:16:23.418 13742-13755/com.klt.kamin.cgmbasedemo I/System.out: w-6-2 after Verify and Success in broadcastUpdate,only data,cut first byte and last byte--->dataAscii:SN06160050
08-15 23:16:23.418 13742-13755/com.klt.kamin.cgmbasedemo I/SendBroadcastPermission: action:com.example.bluetooth.le.ACTION_DATA_AVAILABLE, mPermissionType:0
08-15 23:16:23.420 13742-13755/com.klt.kamin.cgmbasedemo I/System.out: w-6-1 In BluetoothLeService.broadcastUpdate(String action, BluetoothGattCharacteristic characteristic),action=ACTION_DATA_AVAILABLE@@@@@@@@@@@/
08-15 23:16:23.420 13742-13755/com.klt.kamin.cgmbasedemo I/System.out: w-5-1 In BluetoothLeService.onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic)$$$$$$$$$$$$/
08-15 23:16:23.421 13742-13742/com.klt.kamin.cgmbasedemo I/System.out: mGattUpdateReceiver->onReceive->action=com.example.bluetooth.le.ACTION_DATA_AVAILABLE
08-15 23:16:23.421 13742-13742/com.klt.kamin.cgmbasedemo I/System.out: w-7-1 In CgmLibrary.BroadcastReceiver.onReceive(Context context, Intent intent),action=ACTION_DATA_AVAILABLE/&&&&&&&&&
08-15 23:16:23.421 13742-13742/com.klt.kamin.cgmbasedemo I/System.out: w-7-1 in BroadcastReceiver, writeuuid=0000fff1-0000-1000-8000-00805f9b34fb
08-15 23:16:23.422 13742-13742/com.klt.kamin.cgmbasedemo I/System.out: w-7-1 displayData: SN06160050
08-15 23:16:23.422 13742-13742/com.klt.kamin.cgmbasedemo I/System.out: w-8 In MainActivity.onSerialReceived
08-15 23:16:23.429 13742-13742/com.klt.kamin.cgmbasedemo I/System.out: w-7-1 In CgmLibrary.BroadcastReceiver.onReceive(Context context, Intent intent),action=ACTION_DATA_AVAILABLE&&&&&&&&&/

四、以上任务卡了3天做不出来,主要原因如下:

1,不清楚每个Characteristic的属性,fff1可读可写,fff2Notify,可以按一查看

2,不清楚流程:

(1)先使能notifyCharacteristic(二、2)

(2)对发射器进行write命令操作(二、3)

(3)子BluetoothGattCallback的onCharacteristicChanged方法里对发射器返回的数据进行处理。

mBluetoothGatt.writeCharacteristic(characteristic);如果把命令成功写到发射器,会触发:BluetoothGattCallback的  onCharacteristicWrite方法,这里面不做什么可以不用要执行代码writeCharacteristic对通道FFF1进行写命令操作,每产生一次采集结果后,将会在FFF2通道产生一个 notify 通知事件,附带了本次采集结果, APP 可以直接在回调函数中进行处理和使用。

3,写到mSCharacteristic的值没有转成十六进制字符串(二、4)导致写进去的值是错误的

五、扫描广播、连接、绑定

1,Android手机为central,GATT client;发射器为peripheral,GATT server

Central vs. peripheral:  中心设备和外围设备的概念针对的是BLE连接本身。Central角色负责scan advertisement。而peripheral角色负责make advertisement。

GATT server vs. GATT client:这两种角色取决于BLE连接成功后,两个设备间通信的方式。两个设备通过BLE通信,首先需要建立GATT连接。这里我们讲的是Android设备作为client端,连接GATT Server。

 问:Client和Server节点是如何定义呢?

答:通俗地说吧,Server(服务器)就是数据中心,Client(客户端)就是访问数据者。特别说明,它与主/从设备是独立的概念:一个主设备既可以充当Server,又可以充当Client;从设备亦然。

为了安全起见,一些数据的访问需要认证,它的完成是这样的:一方(可以是主节点,也可以是从节点)向另一方索要6位数字的密码,之后,两个节点彼此交换安全密钥用于加密和认证,此过程称为配对。认证的过程比较繁琐,BLE协议支持两节点保存认证的安全密钥(一般是非易失性存储器中),以便于两节点下次连接后快速认证,这就是绑定技术

BLE蓝牙4.0经典问答【转】 - 逗不过奇葩 - 博客园  最清晰的关于蓝牙ble的解答,适合初学者

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏源码之家

word如何自动分割成多个文档

3755
来自专栏大内老A

ASP.NET MVC Controller激活系统详解:IoC的应用[下篇]

[上篇]除了通过自定义ControllerFactory的方式引入IoC之外,在使用默认DefaultControllerFactory情况下也可以通过一些扩展...

19710
来自专栏分布式系统进阶

Librdkafka的基础数据结构 2 --- 定时器 原子操作与引用计数

引用了一个新的struct来将引用计数和调用信息结合起来, 使用链表来管理这个struct的对象. 每次对引用计数的操作都要操作这个链表.

881
来自专栏Golang语言社区

Golang中巧用defer进行错误处理

问题引入 毫无疑问,错误处理是程序的重要组成部分,有效且优雅的处理错误是大多数程序员的追求。很多程序员都有C/C++的编程背景,Golang的程序员也不例外,他...

4037
来自专栏小怪聊职场

爬虫课堂(二十七)|使用scrapy-redis框架实现分布式爬虫(2)源码分析

5276
来自专栏我和未来有约会

第2章 对象激活上下文-对象激活

对象激活主要包括 构造字符串 及时激活 对象池 私有组件 1.构造字符串 服务器苏建只能使用默认的构造函数,这样在对...

1979
来自专栏Android 研究

OKHttp源码解析(五)--OKIO简介及FileSystem

okio是由square公司开发的,它补充了java.io和java.nio的不足,以便能够更加方便,快速的访问、存储和处理你的数据。OKHttp底层也是用该库...

1592
来自专栏JavaWeb

Mybatis源码-XXXmapper.xml中的resultMap标签解析过程

1473
来自专栏数据结构与算法

BZOJ1269: [AHOI2006]文本编辑器editor

Descriptio 这些日子,可可不和卡卡一起玩了,原来可可正废寝忘食的想做一个简单而高效的文本编辑器。你能帮助他吗? 为了明确任务目标,可可对“文本编辑器...

2757
来自专栏浪淘沙

HDFS基本操作

一、hadoop搭建     1、修改主机名     2、ip等     3、主机映射     4、关闭防火墙(两种)     5、ssh免密登录(免...

1365

扫码关注云+社区