NRF52832学习笔记(32)——添加微信硬件接入服务AirSync

一、介绍

1.1 AirSync概述

AirSync是微信硬件平台提供的一种微信客户端与蓝牙设备间通讯的技术协议,它允许蓝牙设备与微信客户端之间收发数据,并支持通过微信客户端透传到远程服务器。该技术在支持微信互联的蓝牙手环、血压计、智能秤、血糖仪等设备上有比较多的应用。

AirSync支持经典蓝牙和BLE低功耗蓝牙技术。
AirSync开发文档

  • 主要功能
    该协议打通了设备和厂商服务器之间的数据链路,也就是支持将设备上的数据发送到厂商的服务器上,也支持将厂商的数据发送到设备。厂商的数据对于微信来说,是黑盒,微信不对设备数据做分析。
    该协议也打通了设备和微信服务器之间的数据链路。设备和微信服务器之间的数据格式由微信规定,例如登录,新消息通知等。

1.2 蓝牙广播

为了和微信能够通信,设备的广播包需符合以下的格式:

  • 微信规定的service uuid(0xFEE7
  • 厂商自定义字段里,包含MAC地址(0xFF + company_identifier + MAC

1.3 蓝牙BLE模拟成流

微信规定了蓝牙BLE设备需要先模拟成流(即stream,输入输出流)。经典蓝牙的RFCOMM,就是一个流。流具有的特性有:

  • 可以传输无限长度的数据
  • 双工,读写可以并发,互不干扰

显然,蓝牙BLE无法传输无限长度的数据,为了实现这个目的,需要定义一个规范。

蓝牙设备需暴露两个特征值(Characteristics):Write特征值,Indication特征值。蓝牙设备从Write特征值接受数据,从Indication特征值发送数据。

Indication特征值类型是bytes。

这里我们约定,把一个特征值一次传输的数据,称为一帧(不同类型的特征值一次传输的数据长度是不一样的)。

注意:应用层上的数据包(例如1k大小),会分散成许多帧来传输。

1.3.1 蓝牙设备写过程

  1. 分帧:假设蓝牙手环上有1k数据,要发给手机微信。由于一个特征值长度有限(如20个字节),显然需要分多次才能传输完成。1k数据,要分成1024字节/ 20字节=51 个帧。剩下的4个字节,不足一帧(20个字节),需补齐为一帧并对剩下的16个字节赋0。总共是52帧。
  2. 发送第一个帧:把第一个帧的内容放入特征值里面。然后通知手机读取数据,通知有两种方式,Indication 和notify,这里使用Indication方式,即带响应的通知。当通知完成的时候,可以认为手机已经读完数据。这就完成了发送第一个帧
  3. 按照2的步骤,依次发送剩下的帧。

注意:
蓝牙设备必须等微信app订阅了Characteristics之后,才能indicate数据,否则会造成设备发送数据丢失的问题。

1.3.2 蓝牙设备读过程

当蓝牙设备发现读特征值收到数据的时候,就接收数据,并追加到设备的buf里。

二、AirSync服务添加

Airsync V0.2源码下载地址: https://iot.weixin.qq.com/wiki/new/index.html?page=6-1

2.1 添加文件

创建三个文件夹 wechatappwechatproductwechatservice,然后分别添加以下文件

2.2 添加代码

  • 添加头文件
// WeChat
#include "ble_wechat_service.h"
#include "mpbledemo2.h"
  • 添加声明
extern ble_wechat_t m_ble_wechat;    // 定义微信服务
extern data_handler *m_mpbledemo2_handler;
  • 修改UUID


static ble_uuid_t m_adv_uuids[]          =                                        /**< Universally unique service identifier. */
{
    {BLE_UUID_WECHAT_SERVICE, NUS_SERVICE_UUID_TYPE}
};
  • 修改蓝牙事件处理函数 ble_evt_dispatch()ble_evt_handler()
    在最后添加微信服务事件处理函数

  • 修改服务初始化函数 services_init()
  • 添加获取MAC地址函数
void GetMacAddress(uint8 *pAddress)
{
    uint32 errCode;
    ble_gap_addr_t macAddr;
    
    errCode = sd_ble_gap_addr_get(&macAddr);
    APP_ERROR_CHECK(errCode);
    
    uint8 i;
    for(i = 0; i < 6; i++)
    {
        pAddress[i] = macAddr.addr[5 - i];// 逆序
    }
}
  • 修改广播初始化函数 advertising_init()

static void advertising_init(void)
{
    uint32_t      err_code;
    ble_advdata_t advdata;
    
    // Build and set advertising data
    memset(&advdata, 0, sizeof(advdata));
    advdata.name_type               = BLE_ADVDATA_FULL_NAME;
    advdata.include_appearance      = false;
    advdata.flags                   = BLE_GAP_ADV_FLAGS_LE_ONLY_GENERAL_DISC_MODE;
    advdata.uuids_complete.uuid_cnt = sizeof(m_adv_uuids) / sizeof(m_adv_uuids[0]);
    advdata.uuids_complete.p_uuids  = m_adv_uuids;
    
    uint8 macAddr[6] = {0};
    GetMacAddress(macAddr);
    memcpy(g_advertisingDataCustomData, macAddr, 6);

    ble_advdata_manuf_data_t        manuf_data;
    manuf_data.company_identifier = COMPANY_IDENTIFIER;
    manuf_data.data.size          = 6;
    manuf_data.data.p_data        = macAddr;
    advdata.p_manuf_specific_data = &manuf_data;
    
    ble_adv_modes_config_t options = {0};  
    options.ble_adv_fast_enabled  = BLE_ADV_FAST_ENABLED;  
    options.ble_adv_fast_interval = APP_ADV_INTERVAL;  
    options.ble_adv_fast_timeout  = APP_ADV_TIMEOUT_IN_SECONDS;  
    
    err_code = ble_advertising_init(&advdata, NULL, &options, on_adv_evt, NULL);
    APP_ERROR_CHECK(err_code);
}
  • 添加获取一个事件处理函数的函数
static void data_handler_init(data_handler **p_data_handler, uint8_t product_type)    
{    
    if(*p_data_handler == NULL)     
    {    
        *p_data_handler = get_handler_by_type(product_type);    
    }    
} 
  • 添加一个注册产品函数
static void register_all_products(void) 
{    
    REGISTER(mpbledemo2);    
}
  • main 函数中添加如下代码
register_all_products();   // 注册微信服务应用处理
data_handler_init(&m_mpbledemo2_handler, PRODUCT_TYPE_MPBLEDEMO2);
  • ble_wechat_service.h 中屏蔽掉如下代码
#include <string.h>
#include <stdint.h>
#include "ble.h"
//#include "nrf_gpio.h"
#include "ble_conn_params.h"
//#include "ble_stack_handler.h"
#include "ble_types.h"
#include "ble_wechat_util.h"

#define BLE_UUID_WECHAT_SERVICE                         0xFEE7
#define BLE_UUID_WECHAT_WRITE_CHARACTERISTICS           0xFEC7
#define BLE_UUID_WECHAT_INDICATE_CHARACTERISTICS        0xFEC8
#define BLE_UUID_WECHAT_READ_CHARACTERISTICS            0xFEC9
//#define APP_ADV_INTERVAL                              40                                        
//#define APP_ADV_TIMEOUT_IN_SECONDS                    0                                       
#define BLE_WECHAT_MAX_DATA_LEN                         (GATT_MTU_SIZE_DEFAULT - 3) 
  • ble_wechat_service.c 中屏蔽掉如下代码
#include "ble_wechat_service.h"
#include "nrf_gpio.h"
#include "ble_conn_params.h"
//#include "ble_stack_handler.h"
#include "ble_types.h"
#include "mpbledemo2.h"
#include "ble_wechat_util.h"
  • ble_wechat_service.c 中添加代码
extern mpbledemo2_state mpbledemo2Sta;

• 由 Leung 写于 2020 年 10 月 12 日

• 参考:[Nordic BLE]nRF51822 基于nRF5_SDK_11.0.0移植Airsync到ble_app_uart工程
    微信蓝牙BLE接入调试指引 硬件篇
    以蓝牙开发的视觉解读微信Airsync协议

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,324评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,303评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,192评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,555评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,569评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,566评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,927评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,583评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,827评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,590评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,669评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,365评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,941评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,928评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,159评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,880评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,399评论 2 342