AliOS Things提供支持符合Bluetooth 4.0/4.2/5.0核心协议规范的BLE host软件协议栈,功能框图如下图红色部分:

主要支持功能有:

  • Generic Access Profile(GAP)多角色支持
    • Peripheral&Central
    • Observer&Broadcaster
  • Generic Attribute Profile(GATT)多连接支持
    • GATT client
    • GATT server
  • Security Manager(SM)支持
    • Legacy Pairing
    • 多安全等级设定Security Level 1, 2, 3, 4
    • 安全连接Security Connection
    • LE Privacy(RPA地址生成)
  • HCI接口支持
    • 标准HCI接口,支持host-only,host通过HCI和controller对接(如MCU+controller)
    • 虚拟HCI接口,支持host+controller,适合SOC的硬件平台(如nrf52832)

API列表

bt_enable BLE协议栈初始化
bt_le_adv_start BLE 广播开始
bt_le_adv_stop BLE 广播停止
bt_le_scan_start BLE scan开始
bt_le_scan_stop BLE scan停止
bt_gatt_service_register GATT服务注册接口
bt_gatt_service_unregister GATT服务注销
bt_gatt_foreach_attr GATT在指定handle范围内服务搜索
bt_gatt_attr_next GATT获取下一个attribute接口
bt_gatt_attr_read GATT读取attribute接口
bt_gatt_attr_read_service GATT读取attribute包含服务接口
bt_gatt_attr_read_included GATT读取包含属性接口
bt_gatt_attr_read_chrc GATT读取包含characteristic接口
bt_gatt_attr_read_ccc GATT读Client Configuration Characteristic接口
bt_gatt_attr_write_ccc GATT写Client Configuration Characteristic接口
bt_gatt_attr_read_cep GATT读写CEP attribute
bt_gatt_attr_read_cud GATT读写CUD attribute
bt_gatt_attr_read_cpf GATT读写CPF attribute
bt_gatt_notify GATT发送notify接口
bt_gatt_indicate GATT发送indicate接口
bt_gatt_discover GATT client发现服务接口
bt_gatt_read GATT client读GATT server属性
bt_gatt_write GATT client写GATT server属性
bt_gatt_write_without_response GATT client写GATT server,不需回复
bt_gatt_subscribe GATT client订阅notification
bt_gatt_unsubscribe GATT client取消订阅notification
bt_conn_security 设置security安全等级
bt_conn_enc_key_size 获取加密key大小
bt_conn_cb_register 注册连接相关回调函数,用以返回连接各状态
bt_conn_auth_cb_register 注册认证相关函数回调函数
bt_conn_auth_passkey_entry passkey回复
bt_conn_auth_cancel 取消认证配对
bt_conn_auth_passkey_confirm passkey匹配回复函数
bt_conn_auth_pairing_confirm pairing请求回复函数
bt_conn_auth_pincode_entry PIN code回复函数

使用

添加该组件

aos.mk中引入

$(NAME)_COMPONENTS += bt_host

包含头文件

对外头文件代码位于include/wireless/bluetooth/bluetooth,在应用的文件中添加头文件

#include <bluetooth/bluetooth.h>
#include <bluetooth/conn.h>

使用示例

  • 蓝牙广播示例,参考application/example/example_legacy/bluetooth/bleadv,演示了如何开启协议栈,并广播特定数据的示例。
  • 蓝牙做GATT server,参考application/example/example_legacy/bluetooth/bleperipheral,演示了GATT注册服务(DIS, HRS, BAS),并在服务发现之后推送模拟的应用数据至GATT client端。

API详情

bt_enable

BLE模块初始化,包含协议栈初始化和HCI driver初始化。

函数原型

int bt_enable(bt_ready_cb_t cb)

输入参数

cb bt_ready_cb_t 初始化结束回调函数。

返回参数

0:成功, 其他值:失败。

调用示例

static void bt_ready(int err)
{
   if (err) {
        printf("BLE not ready (err %d)", err);
        return;
    }
  //协议栈异步初始化之后的回调函数,可以在这里增加用户逻辑,如开启广播等。
  //...


}
void ble_sample(void)
{
    int err = bt_enable(bt_ready);
    if (err) {
        printf("Bluetooth init failed (err %d)\n", err);
        return;
    }
}

bt_le_adv_start

开启蓝牙BLE广播。

函数原型

int bt_le_adv_start(const struct bt_le_adv_param *param,
                    const struct bt_data *ad, size_t ad_len,
                    const struct bt_data *sd, size_t sd_len)

输入参数

param struct bt_le_adv_param* 广播参数如广播interval、广播地址等。
ad struct bt_data* 广播数据。
ad_len size_t 广播数据长度。
sd struct bt_data* Scan response 数据。
sd_len size_t Scan response 数据长度。

返回参数

0:成功, 其他值:失败。

调用示例


static void bt_ready(int err)
{
    if (err) {
        printf("Bluetooth init failed (err %d)\n", err);
        return;
    }
    /*开启蓝牙广播具体步骤*/
    /* 1.广播参数设置,包含interval,地址等*/
    bt_addr_t addr = {.val = { 0x80, 0x81, 0x82, 0x83, 0x84, 0x05 }};
    struct bt_le_adv_param adv_param = {
        .options = 0, \
        .interval_min = BT_GAP_ADV_FAST_INT_MIN_2, \
        .interval_max = BT_GAP_ADV_FAST_INT_MAX_2, \
        .own_addr = &addr, \
    };
  /* 2.广播payload填充*/
   const struct bt_data adv_data[] = {
        BT_DATA(BT_DATA_FLAGS, data, 1),
        BT_DATA(BT_DATA_NAME_COMPLETE, adv_name, strlen(adv_name))
    };
  /* 3.填充scan response内容*/
  static const struct bt_data sd[] = {
    BT_DATA(BT_DATA_NAME_COMPLETE, CONFIG_BT_DEVICE_NAME,
            sizeof(CONFIG_BT_DEVICE_NAME) - 1),
  };
   /*4. 开启广播*/
    err = bt_le_adv_start(&adv_param, adv_data, ARRAY_SIZE(adv_data),
                         sd, ARRAY_SIZE(sd));
    if (err) {
        printf("Advertising failed to start (err %d)\n", err);
        return;
    }
    printf("Advertising successfully started\n");
}

bt_le_adv_stop

停止蓝牙BLE广播。

函数原型

int bt_le_adv_stop(void)

输入参数

返回参数

0:成功, 其他值:失败。

调用示例

int err = bt_le_adv_stop();
if (err) {
    printf("Advertising failed to stop (err %d)\n", err);
    return;
 }

bt_le_scan_start

开启蓝牙scan。

函数原型

int bt_le_scan_start(const struct bt_le_scan_param *param, bt_le_scan_cb_t cb)

输入参数

param struct bt_le_scan_param* BLE扫描参数:如广播类型, duplicate filtering, scan interval 和 scan windows等。
cb bt_le_scan_cb_t 收到scan到的数据回调函数。

返回参数

0:成功, 其他值:失败。

调用示例


static void device_found(const bt_addr_le_t *addr, s8_t rssi, u8_t type, struct net_buf_simple *ad)
{
    char addr_str[BT_ADDR_LE_STR_LEN];
    /* 处理发现的广播数据类型 */
    if (type != BT_LE_ADV_IND && type != BT_LE_ADV_DIRECT_IND) {
        return;
    }
    if(rssi < -70){
        return;
    }
    /*这里可以对scan到的数据包作进一步解析*/
 }
static void bt_scan_example(int err)
{

    int err = bt_le_scan_start(BT_LE_SCAN_ACTIVE, device_found);
    if(err){
        printf("failed to start scan(%d)\n");
    }
    printf("Bluetooth start scan\n");
}

bt_le_scan_stop

停止BLE scan接口。

函数原型

int bt_le_scan_stop(void)

输入参数

返回参数

0:成功, 其他值:失败。

bt_gatt_service_register

GATT server端注册GATT服务接口。

函数原型

int bt_gatt_service_register(struct bt_gatt_service *svc)

输入参数

svc struct bt_gatt_service GATT service 结构体。

返回参数

0:成功, 其他值:失败。

调用示例

/* Heart Rate 服务定义 */
static struct bt_gatt_attr attrs[] = {
    BT_GATT_PRIMARY_SERVICE(BT_UUID_HRS),
    BT_GATT_CHARACTERISTIC(BT_UUID_HRS_MEASUREMENT, BT_GATT_CHRC_NOTIFY),
    BT_GATT_DESCRIPTOR(BT_UUID_HRS_MEASUREMENT, BT_GATT_PERM_READ, NULL,
               NULL, NULL),
    BT_GATT_CCC(hrmc_ccc_cfg, hrmc_ccc_cfg_changed),
    BT_GATT_CHARACTERISTIC(BT_UUID_HRS_BODY_SENSOR, BT_GATT_CHRC_READ),
    BT_GATT_DESCRIPTOR(BT_UUID_HRS_BODY_SENSOR, BT_GATT_PERM_READ,
               read_blsc, NULL, NULL),
    BT_GATT_CHARACTERISTIC(BT_UUID_HRS_CONTROL_POINT, BT_GATT_CHRC_WRITE),
    BT_GATT_DESCRIPTOR(BT_UUID_HRS_CONTROL_POINT, BT_GATT_PERM_READ, NULL,
               NULL, NULL),
};

static struct bt_gatt_service hrs_svc = BT_GATT_SERVICE(attrs);
void hrs_init(u8_t blsc)
{
    hrs_blsc = blsc;
    /*注册定义的HRS服务*/
    bt_gatt_service_register(&hrs_svc);
}

bt_gatt_service_unregister

GATT server端注销服务接口。

函数原型

int bt_gatt_service_unregister(struct bt_gatt_service *svc)

输入参数

svc struct bt_gatt_service GATT service 结构体。

返回参数

0:成功, 其他值:失败。

bt_gatt_foreach_attr

通过指定一定范围handle获取GATT server属性。

函数原型

void bt_gatt_foreach_attr(u16_t start_handle, u16_t end_handle,
                          bt_gatt_attr_func_t func, void *user_data)

输入参数

start_handle u16_t 开始handle。
end_hanlde u16_t 结束handle。
func bt_gatt_attr_func_t 回调函数。
user_data void* 用户数据。

返回参数

无。

bt_gatt_attr_next

获取GATT server下一个属性。

函数原型

struct bt_gatt_attr *bt_gatt_attr_next(const struct bt_gatt_attr *attr)

输入参数

attr struct bt_gatt_service GATT service 结构体。

返回参数

下一个属性结构体指针:成功,NULL:失败。

bt_gatt_attr_read

读取GATT属性接口。

函数原型

ssize_t bt_gatt_attr_read(struct bt_conn *conn, const struct bt_gatt_attr *attr, 
                            void *buf, u16_t buf_len, u16_t offset,
                            const void *value, u16_t value_len)

输入参数

conn struct bt_conn * BLE连接。
attr struct bt_gatt_attr * 要读取的GATT属性。
buf void* 存储地址,read的内容会存在此buffer中。
buf_len u16_t 存储buffer长度。
offset u16_t 开始的偏移。
value void* 属性值。
value_len u16_t 属性长度。

返回参数

读取到的属性长度:成功,负值:失败。

bt_gatt_attr_read_included

读取GATT server包含的服务并存储,当attribute的user_data是bt_gatt_include时使用。

函数原型

ssize_t bt_gatt_attr_read_included(struct bt_conn *conn,
                                   const struct bt_gatt_attr *attr,
                                   void *buf, u16_t len, u16_t offset)

输入参数

conn struct bt_conn * BLE连接。
attr struct bt_gatt_attr * 要读取的属性。
buf void* 存储buffer空间。
len u16_t 存储buffer的大小。
offset u16_t 开始偏移。

返回参数

读取到的属性长度:成功,负值:错误码。

bt_gatt_attr_read_chrc

读取GATT server包含的服务,当attribute的user_data是bt_gatt_chrc时使用。

函数原型

ssize_t bt_gatt_attr_read_chrc(struct bt_conn *conn,
                               const struct bt_gatt_attr *attr, void *buf,
                               u16_t len, u16_t offset)

输入参数

conn struct bt_conn * BLE连接。
attr struct bt_gatt_attr * 要读取的属性。
buf void* 读取到的包含character存储的buffer空间。
len u16_t 存储buffer的大小。
offset u16_t 开始偏移。

返回参数

读取到的属性长度:成功,负值:失败。

bt_gatt_attr_read_ccc

读取GATT server包含的服务,当attribute的user_data是_bt_gatt_ccc时使用。

函数原型

ssize_t bt_gatt_attr_read_ccc(struct bt_conn *conn,
                              const struct bt_gatt_attr *attr, void *buf,
                              u16_t len, u16_t offset)

输入参数

conn struct bt_conn * BLE连接。
attr struct bt_gatt_attr * 要读取的属性。
buf void* 存储读取到CCC的buffer空间。
len u16_t 存储buffer的大小。
offset u16_t 开始偏移。

返回参数

读取到的属性长度:成功,负值:失败。

bt_gatt_attr_write_ccc

写Client Characteristic Configuration (CCC)属性。

函数原型

ssize_t bt_gatt_attr_write_ccc(struct bt_conn *conn,
                               const struct bt_gatt_attr *attr, const void *buf,
                               u16_t len, u16_t offset, u8_t flags)

输入参数

conn struct bt_conn * BLE连接。
attr struct bt_gatt_attr * 要读取的属性。
buf void* 存储buffer空间。
len u16_t 存储buffer的大小。
offset u16_t 开始偏移。
flags u8_t 写入标志

返回参数

读取到的属性长度:成功,负值:失败。

bt_gatt_attr_read_cep

获取Characteristic Extended Properties (CEP)属性。

函数原型

ssize_t bt_gatt_attr_read_cep(struct bt_conn *conn,
                              const struct bt_gatt_attr *attr, void *buf,
                              u16_t len, u16_t offset)

输入参数

conn struct bt_conn * BLE连接。
attr struct bt_gatt_attr * 要读取的属性。
buf void* 读取到的CEP存储buffer空间。
len u16_t 存储buffer的大小。
offset u16_t 开始偏移。

返回参数

读取到的属性长度:成功,负值:失败。

bt_gatt_attr_read_cud

读取Characteristic User Description (CUD)属性并存储结。

函数原型

ssize_t bt_gatt_attr_read_cud(struct bt_conn *conn,
                              const struct bt_gatt_attr *attr, void *buf,
                              u16_t len, u16_t offset)

输入参数

conn struct bt_conn * BLE连接。
attr struct bt_gatt_attr * 要读取的属性。
buf void* 获取到的CUD存储到buffer。
len u16_t 存储buffer的大小。
offset u16_t 开始偏移。

返回参数

读取到的属性长度:成功,负值:失败。

bt_gatt_attr_read_cpf

获取Characteristic Presentation Format (CPF)属性并存储结果。

函数原型

ssize_t bt_gatt_attr_read_cpf(struct bt_conn *conn,
                              const struct bt_gatt_attr *attr, void *buf,
                              u16_t len, u16_t offset)

输入参数

conn struct bt_conn * BLE连接。
attr struct bt_gatt_attr * 要读取的属性。
buf void* 获取到的CPF存储到buffer地址。
len u16_t 存储buffer的大小。
offset u16_t 开始偏移。

返回参数

读取到的属性长度:成功,负值:失败。

bt_gatt_notify

GATT server发送notify API。如果连接参数为NULL,将通知所有使能ccc的peer,否则指定connection发送notify。

函数原型

int bt_gatt_notify(struct bt_conn *conn, const struct bt_gatt_attr *attr,
                   const void *data, u16_t len)

输入参数

conn struct bt_conn * BLE连接。
attr struct bt_gatt_attr * GATT属性。
data void* 要发送的notify数据。
len u16_t 要发送的notify数据长度。

返回参数

0:成功, 其它负值:失败。

调用事例

/* HRS服务定义 */
static struct bt_gatt_attr attrs[] = {
    BT_GATT_PRIMARY_SERVICE(BT_UUID_HRS),
    BT_GATT_CHARACTERISTIC(BT_UUID_HRS_MEASUREMENT, BT_GATT_CHRC_NOTIFY),
    BT_GATT_DESCRIPTOR(BT_UUID_HRS_MEASUREMENT, BT_GATT_PERM_READ, NULL,
               NULL, NULL),
    BT_GATT_CCC(hrmc_ccc_cfg, hrmc_ccc_cfg_changed),
    BT_GATT_CHARACTERISTIC(BT_UUID_HRS_BODY_SENSOR, BT_GATT_CHRC_READ),
    BT_GATT_DESCRIPTOR(BT_UUID_HRS_BODY_SENSOR, BT_GATT_PERM_READ,
               read_blsc, NULL, NULL),
    BT_GATT_CHARACTERISTIC(BT_UUID_HRS_CONTROL_POINT, BT_GATT_CHRC_WRITE),
    BT_GATT_DESCRIPTOR(BT_UUID_HRS_CONTROL_POINT, BT_GATT_PERM_READ, NULL,
               NULL, NULL),
};
void hrs_notify(void)
{
    static u8_t hrm[2];
    hrm[0] = 0x06; 
    hrm[1] = heartrate;
    /*调用bt_gatt_notify接口*/
    bt_gatt_notify(NULL, &attrs[2], &hrm, sizeof(hrm));
}

bt_gatt_indicate

GATT server 发送Indicate 给GATT client的API。

函数原型

int bt_gatt_indicate(struct bt_conn *conn,
                     struct bt_gatt_indicate_params *params)

输入参数

conn struct bt_conn * BLE 连接。
params struct bt_gatt_indicate_params * GATT indicate结构体,数据段填充需要的indication数据。

返回参数

0:成功, 其它值:失败。

bt_gatt_discover

发现GATT service, 或者发现GATT character,通过指定params中的参数类型

函数原型

int bt_gatt_discover(struct bt_conn *conn,
                     struct bt_gatt_discover_params *params)

输入参数

conn struct bt_conn * BLE连接。
params struct bt_gatt_discover_params * GATT discover结构体,包含发现类型,服务或者characteristic的UUID数据。

返回参数

0:成功, 其它值:失败。

调用事例


static void connected(struct bt_conn *conn, uint8_t err)
{
 
    default_conn = bt_conn_ref(conn);
    //发现GATT服务
    uuid.val = 0xffa0;
    static struct bt_gatt_discover_params discov_param;
    discov_param.uuid = &uuid.uuid;
    discov_param.func = discover_func;
    discov_param.start_handle = 0x0001;
    discov_param.end_handle = 0xffff;
     /*指定BT_GATT_DISCOVER_PRIMARY为发现gatt serice,需要指定start_handle和end_handle*/
    discov_param.type = BT_GATT_DISCOVER_PRIMARY;
    int err = bt_gatt_discover(default_conn, &discov_param);
    if (err) {
        printf("Discover failed (err %d)\n", err);
        return;
    }
}
static u8_t discover_char_func(struct bt_conn *conn,
              const struct bt_gatt_attr *attr,
              struct bt_gatt_discover_params *param)
{
        uuid.val = 0xffa1;
        static struct bt_gatt_discover_params discov_param;
        discov_param.uuid = &uuid.uuid;
        discov_param.start_handle = attr->handle + 1;
       /*指定BT_GATT_DISCOVER_CHARACTERISTIC为发现character*/
        discov_param.type = BT_GATT_DISCOVER_CHARACTERISTIC;
        int err = bt_gatt_discover(conn, &discov_param);
        if (err) {
            printk("Char Discovery failed (err %d)\n", err);
        }
}
			

bt_gatt_read

GATT client读GATT server服务的API。

函数原型

int bt_gatt_read(struct bt_conn *conn, struct bt_gatt_read_params *params)

输入参数

conn BTstruct bt_conn * BLE连接。
params struct bt_gatt_read_params * GATT read服务的结构体,包括读的句柄,回调函数等。

返回参数

0:成功, 其它负值:失败。

bt_gatt_write

GATT client调用此接口向GATT server写服务,GATT server需要write response,并通过回调告知。

函数原型

int bt_gatt_write(struct bt_conn *conn, struct bt_gatt_write_params *params)

输入参数

conn struct bt_conn * BLE连接。
params struct bt_gatt_write_params * BLE gatt write服务的结构体,包括句柄,写的数据,长度等。

返回参数

0:成功, 其它负值:失败。

调用事例


static void write_cb(struct bt_conn *conn, u8_t err,
              struct bt_gatt_write_params *params)
{
   //write之后的回调函数
}
void gatt_write_example(void)
{
           static struct bt_gatt_write_params write_params;
           write_params.handle =  m_ctx.write_hdl;//write的handle,从character服务发现获取
           write_params.func = write_cb;//写成功之后的回调函数
           write_params.offset = 0;
           write_params.data = m_ctx.data;//write的数据
           write_params.length = m_ctx.mtu;//write的数据长度
           int ret = bt_gatt_write(default_conn , &write_params); //default_conn是ble建立连接的
           if(0 != ret){
              printf("gatt write failed(%d)\n", ret)
	      return;
           }
}

bt_gatt_write_without_response

GATT client调用此接口向GATT server写服务,相比于bt_gatt_write无需response 。

函数原型

int bt_gatt_write_without_response(struct bt_conn *conn, u16_t handle,
                                   const void *data, u16_t length,
                                   bool sign)

输入参数

conn struct bt_conn * BT连接。
handle u16_t 属性句柄。
data void* 属性值。
len u16_t 属性值长度。
sign bool 是否签名。

返回参数

0:成功, 其它负值:失败。

bt_gatt_subscribe

GATT client订阅GATT server的Indication/Notification,当GATT服务端Indication/Notification有对应的消息推送时,对应的订阅类型的回调函数会有产生。

函数原型

int bt_gatt_subscribe(struct bt_conn *conn,
                      struct bt_gatt_subscribe_params *params)

输入参数

conn struct bt_le_adv_param* BLE连接。
params struct bt_gatt_subscribe_params * 订阅参数,如订阅类型,对应的回调函数等。

返回参数

0:成功, 其它负值:失败。

bt_gatt_unsubscribe

GATT client取消订阅GATT server的Indication/Notification。

函数原型

int bt_gatt_unsubscribe(struct bt_conn *conn,
                        struct bt_gatt_subscribe_params *params)

输入参数

conn struct bt_le_adv_param* BLE连接。
params struct bt_gatt_subscribe_params * 取消订阅参数。如订阅类型,对应的回调函数等。

返回参数

0:成功, 其它负值:失败。

配置说明

配置项说明

  • ENABLE BLE SMP使能蓝牙加密模块,在需要配对认证情况下需要使能。
  • 开启SMP会增加代码和内存使用大小,可以配合设置安全等级,用户的IO capability来决定开启或者关闭。

标准宏和结构体说明

bt_ready_cb_t

蓝牙协议栈初始化成功回调函数

typedef void (*bt_ready_cb_t)(int err);

bt_data

蓝牙广播数据格式字段,在bt_le_adv_start会将这些字段广播出去。

struct bt_data {
    u8_t type;
    u8_t data_len;
    const u8_t *data;
};

BT_DATA

bt_data类型的宏定义。

#define BT_DATA(_type, _data, _data_len) 
    { 
        .type = (_type), 
        .data_len = (_data_len), 
        .data = (const u8_t *)(_data), 
    }

BT_LE_ADV_PARAM

广播参数的宏定义。

#define BT_LE_ADV_PARAM(_options, _int_min, _int_max) \
        (&(struct bt_le_adv_param) { \
            .options = (_options), \
            .interval_min = (_int_min), \
            .interval_max = (_int_max), \
         })

BT_LE_SCAN_PARAM

LE扫描的参数宏。

#define BT_LE_SCAN_PARAM(_type, _filter, _interval, _window) \
        (&(struct bt_le_scan_param) { \
            .type = (_type), \
            .filter_dup = (_filter), \
            .interval = (_interval), \
            .window = (_window), \
         })

广播选项

广播配置选项,BT_LE_ADV_OPT_CONNECTABLE为可连接广播包;BT_LE_ADV_OPT_ONE_TIME位在开启之后,从连接状态断开后需要重新开启。

enum {
    BT_LE_ADV_OPT_NONE = 0,
    BT_LE_ADV_OPT_CONNECTABLE = BIT(0),
    BT_LE_ADV_OPT_ONE_TIME = BIT(1),
};

struct bt_le_adv_param

广播参数结构体,依次是广播选项,广播的最小间隔,最大间隔,非连接广播包NRPA地址。

struct bt_le_adv_param {
    u8_t  options;
    u16_t interval_min;
    u16_t interval_max;
    const bt_addr_t *own_addr;
};

struct bt_le_scan_param

BLE广播的选项配置。

  • type,主动扫描或者被动扫描。
  • filter_dup,相同地址过滤是否开启。
  • interval,scan的interval,0.625ms*interval。
  • window,扫描的窗口大小,真实时间大小为0.625ms*window。

struct bt_le_scan_param {
    u8_t  type;
    u8_t  filter_dup;
    u16_t interval;
    u16_t window;
};