Realtek sdk ble profile架构概览

1 bluetooth 蓝牙协议

  什么是蓝牙呢?蓝牙是频率为2.4GHz的特高频无线通讯标准;按协议制定的时间将其分为两种类型;

  1.1 经典蓝牙BT:以点对点方式创建一对一通信;使用蓝牙3.0标准协议;

  1.2 低功耗蓝牙BLE :以广播(一对多)和网格(多对多)等通信; 使用蓝牙4.0标准协议,兼容3.0;

2 ( C/S client server )架构

  c/s架构通信的双方总是由client客户端的主机发起,server服务端的从机响应;gatt协议使用c/s架构;

  2.1 client客户端: 使用数据服务的设备,即主机设备;

  2.2 server服务端:提供数据服务的设备,即从机设备; 数据服务:即service服务;

  2.3 gatt协议传输

    attribute指令在发送出去之后,会一直等待直到收到回复的ack包,直到超时或断开ble;杜绝了空中丢包的可能性;

    attribute指令可以选择request/ack的模式,也可以选择request/respond的模式;

3 蓝牙协议栈架构

  蓝牙协议栈主要分为三层;

  其中GAP协议后文介绍了其广播包部分,其中GATT协议后文介绍了其attribute table部分;application层等价于profile协议部分;

  3.1 controller层

    由芯片厂编写的硬件层,包括射频电路,将HCI数据按空中包的格式调制解调的链路层,以及规范通信的hci接口;

  3.2 host层

    由各公司配置的驱动层,用于连接硬件与应用层的通信,需要配置的主要是配置gatt和gap;

    3.2.1 GAP generic access profile 通用连接协议

      当从机还未建立连接的时候,通过GAP协议单向向外广播数据,该协议通常由芯片产商写好;

      从机广播间隔约20ms-10s,主机扫描间隔约2.5ms-10s;广播间隔越长越省电,同时也不容易被扫描到;

    3.2.2 GATT generic attribute profile 通用属性协议

      当从机和主机建立一对一连接,通过GATT协议进行通信,该协议结构即后文的attribute profile;

      GATT连接属于一对一连接,从机和主机建立连接之后,就会停止向外广播使得对其他设备不可见;当设备断开后设备又开始广播;

  3.3 application层

    由各公司编写的的应用层,每个代码功能都可视为profile;蓝牙联盟也定义了相关功能的标准profiles,看情况使用;

4 广播数据

  4.1 广播包 adv_data[ ]

    广播包的主要作用是用来广播蓝牙设备名称,以及广播部分需要广播的类型数据;

    广播包的数据单元可以切分为[ length、type、data ]的格式进行广播,广播包的数据长度最大31bytes;

    4.1.1 type类型

//gap_le_types.h  广播包type类型
#define GAP_ADTYPE_FLAGS                        0x01 //!< The Flags data type contains one bit Boolean flags. Please reference @ref ADV_TYPE_FLAGS for details.
#define GAP_ADTYPE_16BIT_MORE                   0x02 //!< Service: More 16-bit UUIDs available
#define GAP_ADTYPE_16BIT_COMPLETE               0x03 //!< Service: Complete list of 16-bit UUIDs
#define GAP_ADTYPE_32BIT_MORE                   0x04 //!< Service: More 32-bit UUIDs available
#define GAP_ADTYPE_32BIT_COMPLETE               0x05 //!< Service: Complete list of 32-bit UUIDs
#define GAP_ADTYPE_128BIT_MORE                  0x06 //!< Service: More 128-bit UUIDs available
#define GAP_ADTYPE_128BIT_COMPLETE              0x07 //!< Service: Complete list of 128-bit UUIDs
#define GAP_ADTYPE_LOCAL_NAME_SHORT             0x08 //!< Shortened local name
#define GAP_ADTYPE_LOCAL_NAME_COMPLETE          0x09 //!< Complete local name
#define GAP_ADTYPE_POWER_LEVEL                  0x0A //!< TX Power Level: 0xXX: -127 to +127 dBm
#define GAP_ADTYPE_OOB_CLASS_OF_DEVICE          0x0D //!< Simple Pairing OOB Tag: Class of device (3 octets)
#define GAP_ADTYPE_OOB_SIMPLE_PAIRING_HASHC     0x0E //!< Simple Pairing OOB Tag: Simple Pairing Hash C (16 octets)
#define GAP_ADTYPE_OOB_SIMPLE_PAIRING_RANDR     0x0F //!< Simple Pairing OOB Tag: Simple Pairing Randomizer R (16 octets)
#define GAP_ADTYPE_SM_TK                        0x10 //!< Security Manager TK Value
#define GAP_ADTYPE_SM_OOB_FLAG                  0x11 //!< Secutiry Manager OOB Flags
#define GAP_ADTYPE_SLAVE_CONN_INTERVAL_RANGE    0x12 //!< Min and Max values of the connection interval (2 octets Min, 2 octets Max)
                                                     //  (0xFFFF indicates no conn interval min or max)
#define GAP_ADTYPE_SIGNED_DATA                  0x13 //!< Signed Data field
#define GAP_ADTYPE_SERVICES_LIST_16BIT          0x14 //!< Service Solicitation: list of 16-bit Service UUIDs
#define GAP_ADTYPE_SERVICES_LIST_128BIT         0x15 //!< Service Solicitation: list of 128-bit Service UUIDs
#define GAP_ADTYPE_SERVICE_DATA                 0x16 //!< Service Data
#define GAP_ADTYPE_PUBLIC_TGT_ADDR              0x17 //!< Public Target Address
#define GAP_ADTYPE_RANDOM_TGT_ADDR              0x18 //!< Random Target Address
#define GAP_ADTYPE_APPEARANCE                   0x19 //!< Appearance
#define GAP_ADTYPE_ADV_INTERVAL                 0x1A //!< Advertising Interval
#define GAP_ADTYPE_LE_BT_ADDR                   0x1B //!< LE Bluetooth Device Address
#define GAP_ADTYPE_LE_ROLE                      0x1C //!< LE Role
#define GAP_ADTYPE_SP_HASH_C256                 0x1D //!< Simple Pairing Hash C-256
#define GAP_ADTYPE_SP_RAND_R256                 0x1E //!< Simple Pairing Randomizer R-256
#define GAP_ADTYPE_LIST_32BIT_SILI              0x1F //!< List of 32-bit Service Solicitation UUIDs
#define GAP_ADTYPE_SERVICE_DATA_32BIT           0x20 //!< Service Data - 32-bit UUID
#define GAP_ADTYPE_SERVICE_DATA_128BIT          0x21 //!< Service Data - 128-bit UUID
#define GAP_ADTYPE_SC_CONF_VALUE                0x22 //!< LE Secure Connections Confirmation Value
#define GAP_ADTYPE_SC_RAND_VALUE                0x23 //!< LE Secure Connections Random Value
#define GAP_ADTYPE_URI                          0x24 //!< URI
#define GAP_ADTYPE_INDOOR_POSITION              0x25 //!< Indoor Positioning
#define GAP_ADTYPE_TRANSPORT_DISCOVERY_DATA     0x26 //!< Transport Discovery Data
#define GAP_ADTYPE_LE_SUPPORTED_FEATURES        0x27 //!< LE Supported Features
#define GAP_ADTYPE_CHAN_MAP_UPDATE_IND          0x28 //!< Channel Map Update Indication
#define GAP_ADTYPE_MESH_PB_ADV                  0x29 //!< Mesh Pb-Adv
#define GAP_ADTYPE_MESH_PACKET                  0x2A //!< Mesh Packet
#define GAP_ADTYPE_MESH_BEACON                  0x2B //!< Mesh Beacon
#define GAP_ADTYPE_3D_INFO_DATA                 0x3D //!< 3D Information Data
#define GAP_ADTYPE_MANUFACTURER_SPECIFIC        0xFF //!< Manufacturer Specific Data: first 2 octets contain the Company Identifier Code
                                                     //   followed by the additional manufacturer specific data

// type=ADV_TYPE_FLAGS,data如下:
#define GAP_ADTYPE_FLAGS_LIMITED                            0x01 //!< Discovery Mode: LE Limited Discoverable Mode
#define GAP_ADTYPE_FLAGS_GENERAL                            0x02 //!< Discovery Mode: LE General Discoverable Mode
#define GAP_ADTYPE_FLAGS_BREDR_NOT_SUPPORTED                0x04 //!< Discovery Mode: BR/EDR Not Supported
#define GAP_ADTYPE_FLAGS_SIMULTANEOUS_LE_BREDR_CONTROLLER   0x08 //!< Discovery Mode: Simultaneous LE and BR/EDR Controller Supported
#define GAP_ADTYPE_FLAGS_SIMULTANEOUS_LE_BREDR_HOST         0x10 //!< Discovery Mode: Simultaneous LE and BR/EDR Host Supported

    4.1.2 广播包

// GAP Advertisement data (max size = 31 bytes,best kept short to conserve power while advertisting)
SHM_DATA_SECTION uint8_t adv_data[] ={
    /* Core spec. Vol. 3, Part C, Chapter 18 */
    /* Flags */
    /* place holder for Local Name, filled by BT stack. if not present */
    /* BT stack appends Local Name.                                    */
    0x02,                        //length
    GAP_ADTYPE_FLAGS,            //type
    GAP_ADTYPE_FLAGS_GENERAL ,   //data
    
//    0x03,                      //length
//    GAP_ADTYPE_16BIT_MORE,     //type:16bit uuid
//    0x59,                      //data
//    0xD4,    

    0x0F                         //length
    0x09,                        //type:Complete local name 
    'C', 'M', 'B', '5', '9', '0', '9', '6', '8', '-', 'X', 'X', 'X', 'X',//data	
    
    0x08,                        //length
    0xFF,                        //type:Manufacture specified data
    'L','B',                     //data:company identifier
    0x20,0x15,0x09,0x14,0x14,    //data:mac addr
};

  4.2 广播回复包

//main.c    GAP - SCAN RSP data (max size = 31 bytes) 数据格式同广播包一样
SHM_DATA_SECTION static uint8_t scan_rsp_data[] ={
    0x0F,           //length
    0x09,           //type 
    'C', 'M', 'B', '5', '9', '0', '9', '6', '8', '-', 'X', 'X', 'X', 'X',//data	
};

  4.3 广播包初始化

//main.c
void app_le_gap_init(void){
    //... 广播包adv_data[] 和广播回复包scan_rsp_data[]的初始化
    le_adv_set_param(GAP_PARAM_ADV_DATA, sizeof(adv_data), (void *)adv_data);
    le_adv_set_param(GAP_PARAM_SCAN_RSP_DATA, sizeof(scan_rsp_data), (void *)scan_rsp_data);
}

//main.c
static void app_bt_gap_init(void){
    //...
    app_le_gap_init();
}

//src\app\watch\watch_app\main.c
int main(void){
    //...
    app_bt_gap_init();
}

5 ATT attribute 协议

  5.1 attribute 数据段

    attribute数据段格式如下,是后续提供给gatt使用的服务数据源;gatt将其归纳为gatt的格式同应用层交互;

    

    attribute handle:由蓝牙底层生成,是ATT PDU(protocol data unit)的句柄,不是代码中的attrib_index;

               属性句柄虽然也起到标识和管理作用,但不是通道索引序号,这属性句柄体现在什么代码中呢?先放着;

  5.2 attribute 结构体

    5.2.1 attribute 结构体

//gatt.h
//brief GATT attribute definition.  profile中通过 type_value 来区分通道的,具体逻辑边界先放着;
typedef struct
{
    uint16_t    flags;              // flags 
    uint8_t     type_value[2 + 14]; // UUID charecteristic 特征值属性
    uint16_t    value_len;          // Length of value
    void        *p_value_context;   // service data addr
    uint32_t    permissions;        // 属性权限,可以组合属性;
} T_ATTRIB_APPL;

    5.2.2 flags 属性

// flags:标识service的其他属性,比如UUID长度、支持广播、CCCD使能、指示等;不同蓝牙厂商的功能应该会有所不同;
#define ATTRIB_FLAG_VOID           0x0000 /**< Attribute value neither supplied by application
                                           nor included following 16bit UUID. Attribute value is pointed by p_value_context
                                           and value_len shall be set to the length of attribute value. */
#define ATTRIB_FLAG_UUID_128BIT    0x0001 /**< Attribute uses 128 bit UUID */
#define ATTRIB_FLAG_VALUE_INCL     0x0002 /**< Attribute value is included following 16 bit UUID */
#define ATTRIB_FLAG_VALUE_APPL     0x0004 /**< Application has to supply write value */
#define ATTRIB_FLAG_ASCII_Z        0x0008 /**< Attribute value is ASCII_Z string */
#define ATTRIB_FLAG_CCCD_APPL      0x0010 /**< Application will be informed about CCCD value is changed */
#define ATTRIB_FLAG_CCCD_NO_FILTER 0x0020 /**< Application will be informed about CCCD value
                                           when CCCD is write by client, no matter it is changed or not */
#define ATTRIB_FLAG_INCLUDE_MULTI  0x0040
#define ATTRIB_FLAG_LE             0x0800 /**< Used only for primary service declaration attributes if GATT over BLE is supported */
#define ATTRIB_FLAG_BREDR          0x0400 /**< Used only for primary service declaration attributes if GATT over BR/EDR is supported */

    5.2.3 permissions 属性

//permissions:标识service的访问属性,比如读写,加密读写、认证读写、签名读写
#define GATT_PERM_NONE                   0x00
#define GATT_PERM_ALL                    0x01  /**< bits 0..1 (rd), 4..5 (wr), 8..9 (notif/ind) */
#define GATT_PERM_AUTHEN_REQ             0x02
#define GATT_PERM_AUTHEN_MITM_REQ        0x03
#define GATT_PERM_AUTHOR_REQ             0x04  /**< bits 2 (rd), 6 (wr), 10 (notif/ind) */
#define GATT_PERM_ENCRYPTED_REQ          0x08  /**< bits 3 (rd), 7 (wr), 11 (notif/ind) */
#define GATT_PERM_AUTHEN_SC_REQ          0x00010000
#define GATT_PERM_READ                   GATT_PERM_ALL
#define GATT_PERM_READ_AUTHEN_GET(x)     (x & 0x03)
#define GATT_PERM_WRITE                  (GATT_PERM_ALL << 4)
#define GATT_PERM_WRITE_AUTHEN_GET(x)    ((x >> 4) & 0x03)
#define GATT_PERM_NOTIF_IND              (GATT_PERM_ALL << 8)
#define GATT_PERM_NOTIF_IND_AUTHEN_GET(x) ((x >> 8) & 0x03)
//...
//flags和permissions具有关联性,没有因果性;比如ATTRIB_FLAG_VALUE_APPL flag会有notify permission;
//上面这句话真是总结的太准确了,我真是小聪明;

    5.2.4 characteristic属性

//这里还有一个相关概念老是在网文中出现的,那就是characteristic特征值属性;
//是用于描述characteristic的访问权限;说句大白话就是用于描述特征值的permissions的;为什么要费这劲再定义呢?先放着;
//write属性:          该从机可以被写入
//read属性:          该从机可以被读取
//notify属性:        该从机可以主动发送通知消息;
//authenticated属性: 该从机需要验证才能读写


//虽然不是蓝牙规范的标准用法,但是notify通知也可以用来实现service指令传输;

    5.2.5 uuid 通用唯一标识码

      UUID: universally unique identifier 通用唯一标识码,通过不同的uuid来区分不同的service服务;

      蓝牙技术联盟定义基本的UUID标识码如右:0000xxxx-0000-1000-8000-00805F9B34FB;

      蓝牙技术联盟定义基本的UUID标识码中xxxx为属性的uuid;使用uuid标识service的characteristic属性;

      蓝牙技术联盟定义基本的UUID标识码只是官方提供的,实际上多数公司都会重新定义自己的UUID特征值通道;

      蓝牙广播的中uuid格式:xxxx,0000xxxx,0000xxxx-0000-1000-8000-00805F9B34FB;2bytes、4bytes、16bytes;

  5.3 attribute table

//wristband_private_service.c 
const T_ATTRIB_APPL bwps_service_tbl[] ={
    {   // attrib_index 0
        (ATTRIB_FLAG_VOID | ATTRIB_FLAG_LE),     //flag:0x0800, 仅用于primary service;
        {   LO_WORD(GATT_UUID_PRIMARY_SERVICE),  //uuid:0x2800
            HI_WORD(GATT_UUID_PRIMARY_SERVICE),
        },
        UUID_16BIT_SIZE,                         //valueLength
        (void *)GATT_UUID16_BWPS,                //pvalue:&[0x59,0xd4] 
                                                 //这个是service的uuid,后面的几个都是这个service的characteristic;
                                                 //添加service就是重新添加一个当前attrib_index和后面几个特征值的attrib_index;
        GATT_PERM_READ                           //permission
    },
    {   // attrib_index 1
        ATTRIB_FLAG_VALUE_INCL,                  //flag:0x0002, 使用16bit uuid 
        {   LO_WORD(GATT_UUID_CHARACTERISTIC),   //uuid:0x2803
            HI_WORD(GATT_UUID_CHARACTERISTIC),
            GATT_CHAR_PROP_WRITE|GATT_CHAR_PROP_WRITE_NO_RSP, //???
        },
        1,                                       //valueLength
        NULL,                                    //pvalue
        GATT_PERM_READ                           //permission
    },
    {   // attrib_index 2
        ATTRIB_FLAG_VALUE_APPL,                     //flag:0x0004, 支持写数据
        {   LO_WORD(BLE_UUID_CM_TX_CHARACTERISTIC), //uuid:0x0013
            HI_WORD(BLE_UUID_CM_TX_CHARACTERISTIC),
        },
        0,                                           //valueLength
        NULL,                                        //pvalue
        GATT_PERM_WRITE                              //permission
    },
        // attrib_index 3 ...
    {   // attrib_index 4
        ATTRIB_FLAG_VALUE_APPL,                      //flag:0x0004, 支持写数据
        {   LO_WORD(BLE_UUID_CM_RXN_CHARACTERISTIC), //uuid:0x0014
            HI_WORD(BLE_UUID_CM_RXN_CHARACTERISTIC),
        },		
        0,                                           //valueLength
        NULL,                                        //pvalue
        GATT_PERM_NOTIF_IND                          //permission
    },
    {   // attrib_index 5
        (ATTRIB_FLAG_VALUE_INCL | ATTRIB_FLAG_CCCD_APPL), 
        {
            LO_WORD(GATT_UUID_CHAR_CLIENT_CONFIG),  //uuid:0x2902
            HI_WORD(GATT_UUID_CHAR_CLIENT_CONFIG),
            LO_WORD(GATT_CLIENT_CHAR_CONFIG_DEFAULT),     
            HI_WORD(GATT_CLIENT_CHAR_CONFIG_DEFAULT)
        },
        2,                                           //valueLength
        NULL,                                        //pvalue
        (GATT_PERM_READ | GATT_PERM_WRITE)           //permission
    },
        // attrib_index 6 ...
    {   // attrib_index 7
        ATTRIB_FLAG_VALUE_APPL,                      //flag
        {   LO_WORD(BLE_UUID_CM_RXC_CHARACTERISTIC), //uuid:0x0015
            HI_WORD(BLE_UUID_CM_RXC_CHARACTERISTIC),
        },		
        0,                                            //valueLength
        NULL,                                         //pvalue
        GATT_PERM_NOTIF_IND                           //permission
    },
}

6 profile 

  蓝牙规范冗余繁杂,所以蓝牙设备通常只实现所需协议;这部分协议好比蓝牙规范的剪影,所以称为profile; 

  每个attribute_table可视为一个profile协议,每个profile协议中包含多个service服务;每个service服务中包含多个characteristic特征值服务;

  这些 service 和 characteristic 体现在bwps_service_tbl 中都是一条service服务,都有自己的attrib_index id;是并列存在而非包含的关系;

  6.1 私有协议 profile 举例

    对于当前sdk而言,其中包含了LB私有profile、CM私有profile,两个私有协议的profile;

    此处以LB私有profile为例来分析,将实现代码与profile定义对应上;

    私有profile协议的特征值service为ffb0,ffb0 service的特征值有ffb1,ffb2,ffb3,ffb4,ffb6;

   

  6.2 私有协议 profile 流程

    profile是如何通过service和characteristics来接收数据服务的呢?

    通信由提前约定好service和characteristics,在bwps_service_tbl中为其添加对应的 T_ATTRIB_APPL  attrib_index数据服务;

    设备接收到数据之后,characteristic会调用对应permissions的回调函数;

    回调函数中通过判断attrib_index来区分如何传递服务数据的何去何从;

    根据代码推断出来的逻辑大致如上;那么是否可以根据特征值来反推attrib_index呢?它们通过permissions联系起来没法反推;

  6.3 常见 service

    除去传输数据的service attribute之外,还要一些数据服务由协议栈实现,概述部分如下,具体先放着;

    6.3.1 uuid 1800 service attribute

      GAP Generic Access服务,为必须service,包含characteristic:2a00、2a01、2a04、2a06;

      包含device name;appearance;PPCP;CAR等characteristic;由GAP协议层实现的;

    6.3.2 uuid 1801 service attribute

      GATT Generic attribute,为必须service,包含characteristic:2a05、2902、2b3a;

      包含service change等characteristic;由GAP协议层实现的;

    6.3.3 uuid 2902 characteristic attribute;

      CCCD使能:server允许发送notify或indicate类型的characteristic给client;

      CCCD禁能:server禁止发送notify或indicate类型的characteristic给client;

      所以如果蓝牙有notify或者indicate特征值的功能,那么就应该添加CCCD 特征值attribute

7 realtek sdk ble service初始化

  以下是瑞昱sdk中对gatt协议的初始化逻辑流程,本文则是对如下代码进行的内容扩展;

//main.c
int main(void){
    //...
    app_ble_service_init();
}
    
//app_ble_service.c
//注册4个gatt service服务,然后返回注册id,通过service id来标识不同的服务;
//这个需要看数据手册和sdk文档,相关资料我都没有也不知道怎么找,先放着;
//先以sdk处理的profile数据源的service为例继续往下走;
void app_ble_service_init(void){
    server_init(4);
    wristband_ser_id = bwps_service_add_service((void *)app_profile_callback);//sdk data src profile service;
    ota_ser_id = ota_add_service((void *)app_profile_callback);		//xx? profile service
    dfu_ser_id = dfu_add_service((void *)app_profile_callback);		//xx? profile service
    hid_kb_ser_id = hids_add_service((void *)app_profile_callback);	//xx? profile serveice

    //理论上这里应该给每个service都注册自己的回调函数的,但是下面用同一个回调函数来注册;所以所有service都在这个模块中处理了;
    server_register_app_cb(app_profile_callback); 
    client_init(2);
    ancs_init(1);
    ams_init(1); 
}

//wristband_private_service.c  
//seivice的attribute table  >> bwps_service_tbl[]
const T_ATTRIB_APPL bwps_service_tbl[] ={
    //...前文4.3小节attribute table
}
//seivice的回调函数 >> bwps_service_cbs
const T_FUN_GATT_SERVICE_CBS bwps_service_cbs =
{
    bwps_service_attr_read_cb,   // Read callback function pointer
    bwps_service_attr_write_cb,  // Write callback function pointer
    bwps_service_cccd_update_cb  // CCCD update callback function pointer
                                 //*** 重写这三个函数作为应用层profile数据的处理开始;***
};

//wristband_private_service.c   
//service map>> bwps_service_tbl[]、bwps_service_cbs;
//所以这里的回调函数应该是由蓝牙底层驱动中断来触发的回调处理;
uint8_t bwps_service_add_service(void *app_profile_callback){
    uint8_t bwps_service_id;
    server_add_service(&bwps_service_id, 
                       (uint8_t *)bwps_service_tbl, 
                       sizeof(bwps_service_tbl),
                       bwps_service_cbs);
    pfn_wristband_service_cb = (P_FUN_SERVER_GENERAL_CB)app_profile_callback;
    return bwps_service_id;   
}

//wristband_private_service.c 
//回调系列之 write callback sample;
T_APP_RESULT bwps_service_attr_write_cb(uint8_t conn_id, 
                                        T_SERVER_ID service_id,
                                        uint16_t attrib_index, 
                                        T_WRITE_TYPE write_type, 
                                        uint16_t length, 
                                        uint8_t *p_value,
                                        P_FUN_WRITE_IND_POST_PROC *p_write_ind_post_proc)
{
    //这个attrib_index是attrib_table中的序号,没有直接对应上,推导可知;
    switch(attrib_index){
        case GATT_ATTRIB_INDEX_BG_DATA:        
            memcpy(receive_temp + 1, p_value, length);
            //...大数据接收
        break;
        case GATT_ATTRIB_INDEX_AT_DATA:    
            memcpy(receive_at_temp + 1, p_value, length);
            //...at指令接收,at指令设置完毕之后直接往通道回复,没有发送msg;
        break;
    }
}

//数据接收完毕后,send cmd msg queue to l1send_queue_handle;
//另起一应用层task,阻塞等待 recv msg queue from l1send_queue_handle;
//因为使用的是阻塞等待,所以没收到msg的话task就会一直被挂起,这样就不会占用资源,这个构思挺巧的;

  7.1 接收数据后续的应用层task处理逻辑补充,即profile具体代码;

//sdk\LW107-10701\src\app\watch\watch_app\main.c
int main(void){
    //...
    task_init();
}

static void task_init(void){
    //...
    communicate_task_init();
}

//sdk\LW107-10701\src\app\watch\communicate\communicate_task.c
//l1send_task线程创建;
void communicate_task_init(){
    os_task_create(&l1send_task_handle, "l1send", l1send_task, 0, L1SEND_TASK_STACK_SIZE, L1SEND_TASK_PRIORITY);
}

//l1send_task线程:创建了消息队列 l1send_queue_handle; 
void l1send_task(void *pvParameters){
    //参数名称:os_msg_queue_create(pp_handle, p_name, msg_num, msg_size);
    os_msg_queue_create(&l1send_queue_handle, "l1sendQ", 0x10, sizeof(uint16_t));
     while (true){
        //while(true)搭配永久阻塞等待,觉得哪里怪怪的,但是又十分自洽。。。==!
         if (os_msg_recv(l1send_queue_handle, &event, 0xFFFFFFFF) == true){
            switch(event){
                case CMD_xx:
                    cp_xx();
                    //cp_xx()处理完数据后,调用sendRespondPacket(NB_RET_CMD rs);
                break;
                //...
            }
        }
     }
}

8 小节

  本文结构由上至下为循序渐进,从下往上查阅则方便追踪;

  参考博文先放着:深入浅出低功耗蓝牙(BLE)协议栈 - iini - 博客园 (cnblogs.com)

posted @ 2023-10-24 00:01  caesura_k  阅读(306)  评论(0编辑  收藏  举报