iot-fan

联系: iotfan123#163.com
注意:
1,本博客之内容来源于网上收集以及相关技术人员提供,如果有侵犯到您的权益,请电邮我沟通;
2,本博客之内容乃分享,交流,学习,研究之目的,作者不对内容的真实性,有效性,及时性负责,也不对因本博客的任何内容导致的任何后果负责;
3,本博客之内容禁止转发到CSDN网站,转到别的网站请保留出处.

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

本文涉及到ble从机的:

  • 广播相关
  • 连接相关
  • 服务/特征相关
  • 数据收发相关
  • 其他

1.[广播相关]

广播内容:

对于BLE4.x或者兼容模式,广义上的广播分为:广播数据,扫描回复数据,这两个内容的总长度都是31个字节;
对于广播的内容格式, 蓝牙有定义 按照 |1byte长度|1byte类型|n字节内容|循环放,如:

// GAP - SCAN RSP data (max size = 31 bytes)
static uint8_t scanRspData[] = {
    9, // length of this data        //length 
    GAP_ADTYPE_LOCAL_NAME_COMPLETE,  //complete name type
    'b','l','e','_','n','a','m','e', //name
    5,                               //length
    0xff,                            //manufacturer type
    0x00,0x01,0x02,0x03              //manufacturer data
};

设置更新广播内容

//设置/修改扫描回复以及广播数据,这种修改需要重启广播
GAPRole_SetParameter( GAPROLE_SCAN_RSP_DATA, sizeof ( scanRspData ), scanRspData );
GAPRole_SetParameter( GAPROLE_ADVERT_DATA, sizeof( advertData ), advertData );
 
//或者 通过下面方式进行修改,实时生效
bStatus_t GAP_UpdateAdvertisingData( uint8_t taskID,uint8_t adType,uint8_t dataLen,uint8_t *pAdvertData );

广播间隔超时和类型:

//获取当前的广播间隔
//这里的值都是1=0.625ms
uint16_t advInt;
advInt = GAP_GetParamValue( TGAP_DISC_ADV_INT_MIN );
PRINT("min adv %d\r\n",advInt); 
advInt = GAP_GetParamValue( TGAP_DISC_ADV_INT_MAX );
PRINT("max adv %d\r\n",advInt);

//修改广播间隔
 
/*注意,广播的参数修改,需要重启广播,才能生效
 *可以修改后,然后在广播 GAPROLE_WAITING(广播停止)状态产生后,然后立刻开启广播. 不能关闭广播后立刻开启广播.
 */
//1=0.625ms,  160*0.625ms = 100ms
uint16_t advInt = 160;
GAP_SetParamValue( TGAP_DISC_ADV_INT_MIN, advInt );
GAP_SetParamValue( TGAP_DISC_ADV_INT_MAX, advInt );


//获取通用广播超时
//1=0.625ms
uint16_t adv_timeout;
adv_timeout = GAP_GetParamValue(TGAP_GEN_DISC_ADV_MIN);
PRINT("get adv timer TGAP_GEN_DISC_ADV_MIN=%d\r\n",adv_timeout);

//设置通用广播的超时
//1=0.625ms
adv_timeout = 1600; 
GAP_SetParamValue(TGAP_GEN_DISC_ADV_MIN,adv_timeout);
PRINT("set adv timer TGAP_GEN_DISC_ADV_MIN=%d\r\n",adv_timeout);


//修改广播类型
// GAP_ADVERTISEMENT_TYPE_DEFINES GAP Advertising Event Types
#define GAP_ADTYPE_ADV_IND                    0x00  //!< Connectable undirected advertisement
#define GAP_ADTYPE_ADV_HDC_DIRECT_IND         0x01  //!< Connectable high duty cycle directed advertisement
#define GAP_ADTYPE_ADV_SCAN_IND               0x02  //!< Scannable undirected advertisement
#define GAP_ADTYPE_ADV_NONCONN_IND            0x03  //!< Non-Connectable undirected advertisement
#define GAP_ADTYPE_ADV_LDC_DIRECT_IND         0x04  //!< Connectable low duty cycle directed advertisement

//对于只广播的类型,如一些 beacon,可以用 GAP_ADTYPE_ADV_NONCONN_IND 类型,这样不可以连接,会比较省电,但是数据只能放到 GAPROLE_ADVERT_DATA 中不能放到 GAPROLE_SCAN_RSP_DATA 中
uint8 adv_type = GAP_ADTYPE_ADV_IND;
GAPRole_SetParameter( GAPROLE_ADV_EVENT_TYPE,sizeof( uint8_t ),&adv_type);

广播开关:

//获取当前广播状态
//0为非广播,非0为广播
uint8_t adv_status;
GAPRole_GetParameter(GAPROLE_ADVERT_ENABLED, &adv_status );
 
//开启广播
//对应状态上报:GAPROLE_ADVERTISING
uint8_t advertising_enable = true;
GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8_t ), &advertising_enable );

//关闭广播
//  对应的状态上报:
// :GAPROLE_WAITING
// :pEvent->gap.opcode == GAP_END_DISCOVERABLE_DONE_EVENT
advertising_enable = false;
GAPRole_SetParameter( GAPROLE_ADVERT_ENABLED, sizeof( uint8_t ), &advertising_enable );

 
//重启广播
//要先关闭广播,然后在停止广播的状态产生后才能再去使能广播,不能刚执行完关闭广播,就去开启广播
//否则会导致立刻开启失败,如当前在广播状态,执行关闭广播,然后立刻执行开始广播,这时候开始广播是不会调用成功的
//因为这里只是设置协议栈状态机标识位,实际上广播并没有立刻停止,要等协议栈轮询处理后,才会真正关闭,如果现在去启动广播,协议栈会认为当前已经在广播状态

2.[连接相关]

2.1 状态和参数

//连接参数
//设置最大最小连接间隔,最小为6,这里通常是在初始化的时候设置
//这里的最大最小范围要尽量的大,比如6,1000因为主机端连的时候,可能会不断的修改连接间隔,从而实现更快速的服务相关的查询
//后面的连接间隔,通过GAPRole_PeripheralConnParamUpdateReq 函数去更新即可
GAPRole_SetParameter( GAPROLE_MIN_CONN_INTERVAL, sizeof( uint16 ), &desired_min_interval );
GAPRole_SetParameter( GAPROLE_MAX_CONN_INTERVAL, sizeof( uint16 ), &desired_max_interval );

//在从机启动的api里面传入了几个回调函数:
GAPRole_PeripheralStartDevice( Peripheral_TaskID, &Peripheral_BondMgrCBs, &Peripheral_PeripheralCBs );

//其中Peripheral_PeripheralCBs的定义类似下面:
static gapRolesCBs_t Peripheral_PeripheralCBs = {
    peripheralStateNotificationCB,  // Profile State Change Callbacks,广播状态改变,连接断开连上都会调用这个回调
    peripheralRssiCB,               // When a valid RSSI is read from controller (not used by application),当读RSSI后,这里会产生 RSSI的回调,把rssi 值传进来.
    peripheralParamUpdateCB         // 连接参数更新,比如连接 间隔发生改变之类,都会传入到这个函数里
};

//连接参数更新回掉函数
static void peripheralParamUpdateCB( uint16 connHandle, uint16 connInterval, 
                                      uint16 connSlaveLatency, uint16 connTimeout ) {
    if( connHandle == peripheralConnList.connHandle ) {
        peripheralConnList.connInterval = connInterval;
        peripheralConnList.connSlaveLatency = connSlaveLatency;
        peripheralConnList.connTimeout = connTimeout;
        PRINT("param update: connection:%d,interval:%d,latency:%d,timeout:%d\n",connHandle,connInterval,connSlaveLatency,connTimeout);
    }
    else {
        PRINT("peripheralParamUpdateCB err..\n");
    }
}
 

2.2 连接控制相关API

//断开连接
//这里的connHandle 就是在连接的时候传进来的时候的代表一个连接
//在多连接场景,每个链接对应的这个值不同
extern bStatus_t GAPRole_TerminateLink( uint16 connHandle );

//连接参数更新
//这个是从机端,去向主机端请求连接更新
//这里的gapConnHandle 就是在连接的时候传进来的时候的代表一个连接,多连接场景,这个值不同.
//注意下面几个参数值,这几个值要按照ble的规范去写,如果是对接ios,ios的这几个值更为严格.
GAPRole_PeripheralConnParamUpdateReq( gapConnHandle, 
                                      DEFAULT_DESIRED_MIN_CONN_INTERVAL, 
                                      DEFAULT_DESIRED_MAX_CONN_INTERVAL, 
                                      DEFAULT_DESIRED_SLAVE_LATENCY, 
                                      DEFAULT_DESIRED_CONN_TIMEOUT, 
                                      heartRate_TaskID );

2.3 链接断开原因

reason:0x08

在链接参数 timeout到来之前,蓝牙主从一直没有进行通信,可能的原因:

  1. 一方异常断电了,没有通知对方
  2. 代码有有问题,比如代码中有长时间delay 严重影响到协议栈的主循环运行
  3. 定时不准, 蓝牙的定时来自RTC,RTC的定时决定通信的收发窗口
  4. 收发器信号品质问题,导致丢包率大
    • 距离远信号太差
    • 信号倍频时钟误差大,导致丢包率太大
    • 电路板layout的不好,比如GND没处理,或者相关的电容位置不合理,导致信号质量不好,导致丢包率大
### 3.[服务/特征相关]

### 4.[数据传输相关]

### 5.[其他]
#### 修改发射功率
#####初始化时候修改
在协议栈出事时候的config.h文件中修改以下定义:
```c
#ifndef BLE_TX_POWER
#define BLE_TX_POWER								LL_TX_POWEER_0_DBM
#endif
初始化以后修改

这里的传参,和BLE_TX_POWER 中宏的取值范围一致

 extern bStatus_t  LL_SetTxPowerLevel( u8 power );

BLE从机的名称

BLE里面有两个地方涉及到名字:

  1. 广播/扫描回复包中
  2. GAP中

在wch的例程里,分别对应下面两个地方
(规范并没有规定,两个地方的名字必须一致,但是这里建议大家用一致.)
如果程序中修改,上电时候改这两个数组就好了

// GAP - SCAN RSP data (max size = 31 bytes)
static uint8 scanRspData[ ] =
{
  // complete name
  0x12,   // length of this data
  GAP_ADTYPE_LOCAL_NAME_COMPLETE,
  'S',   
  'i',   
  'm',   
  'p',   
  'l',   
  'e',   
  ' ',
  'P',   
  'e',   
  'r',   
  'i',   
  'p',   
  'h',   
  'e',   
  'r',   
  'a',   
  'l',   
  // connection interval range
  0x05,   // length of this data
  GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE,
  LO_UINT16( DEFAULT_DESIRED_MIN_CONN_INTERVAL ),   // 100ms
  HI_UINT16( DEFAULT_DESIRED_MIN_CONN_INTERVAL ),
  LO_UINT16( DEFAULT_DESIRED_MAX_CONN_INTERVAL ),   // 1s
  HI_UINT16( DEFAULT_DESIRED_MAX_CONN_INTERVAL ),

  // Tx power level
  0x02,   // length of this data
  GAP_ADTYPE_POWER_LEVEL,
  0       // 0dBm
};


// GAP GATT Attributes
static uint8 attDeviceName[GAP_DEVICE_NAME_LEN] = "Simple Peripheral";
// Set the GAP Characteristics
GGS_SetParameter( GGS_DEVICE_NAME_ATT, GAP_DEVICE_NAME_LEN, attDeviceName );

IOS中BLE设备的名称问题:

https://developer.apple.com/forums/thread/19381
对于ble设备有两个名称,一个是在广播/扫描回复 的字段中放着,一个是叫ATT device name,需要连接后去通过GATT读取。 并没有明确的要求二者必须一致,但是对于诸如N家,S家的SDK来看,二者是一致的,在IOS 获取BLE设备的名字时, 如果这个设备之前没有连接过,那默认是广播中的名字;当连接后,IOS会通过去读从机的ATT DEVICE NAME,然后私自建立MAC->ATT DEVICE NAME 映射表,当下次再扫描时候,直接根据mac地址匹配自己缓存的BLE设备名字,所以IOS开发者时不时抱怨,为什么广播的名字改了,扫描出来的名字却没变。IOS开发者需要每次都从广播/扫描回复数据中 拿BLE设备广播出来的名称即可。
也可以在开发ble固件时候,强制让广播名字与ATT device name 一致,这样IOS端的代码就不用动.

IOS中的BLE MAC地址问题:

IOS 不提供BLE的MAC地址获取接口,如需要mac地址,通常做法是把mac地址放到广播信息中,比如放到名字中,或者放到自定义信息中

微信小程序中交换mtu问题

微信的小程序的api中提供了 一个设置mtu的api: wx.setBLEMTU(Object object)
具体官方链接:https://developers.weixin.qq.com/miniprogram/dev/api/device/bluetooth-ble/wx.setBLEMTU.html
这个api 有多个返回:

属性 类型 默认值 必填 说明
deviceId string 用于区分设备的 id
mtu number 最大传输单元(22,512) 区间内,单位 bytes
success function 接口调用成功的回调函数
fail function 接口调用失败的回调函数
complete function 接口调用结束的回调函数(调用成功、失败都会执行)

存在问题:当设备的mtu 不支持传入的值时候,会直接返回fail,而不会把从机支持的最大值给报上来。
从微信8.0.9 开始,当mtu交换后,会将最终交互的mtu传出来

posted on 2020-09-06 19:52  iot-fan  阅读(5120)  评论(0编辑  收藏  举报