赞
踩
在Android蓝牙协议栈fluoride(五) - 设备管理(bt application)中描述了设备管理中的API、状态机以及事件处理,接下来将描述设备管理中的功耗管理和上报到上层的事件。
蓝牙设备有很大比例都是带电池的产品,那么功耗的高低直接决定了使用时间的长短,蓝牙在工作时有时候需要连续传输数据或者实时的传输数据(如播放音乐/通话等),有时仅仅建立了连接并没有业务处理(如音乐暂停但连接并未断开),那么就希望有业务时能实时的传输数据,没有业务时保持连接的同时有较低的功耗,因此就产生以下模式(策略):
所以在在蓝牙设备使用过程中,在有业务时将链接策略设置为active模式,在没有业务的时候设置为sniff模式或者hold模式节省功耗。
在代码中,系统管理器提供了以下几个接口设置链接策略:
// 设置/清除策略
void bta_sys_set_policy(uint8_t id, uint8_t policy, const RawAddress& peer_addr);
void bta_sys_clear_policy(uint8_t id, uint8_t policy, const RawAddress& peer_addr);
// 设置/清除默认设置
void bta_sys_set_default_policy(uint8_t id, uint8_t policy);
void bta_sys_clear_default_policy(uint8_t id, uint8_t policy);
以上接口都是调用设备管理中的bta_dm_policy_cback
回调,该回调通过 bta_sys_policy_register
注册。这个回调中分别调用BTM_SetLinkPolicy
和BTM_SetDefaultLinkPolicy
实现。
各个的profile在不同状态下设置不同参数,在设备管理器中按照生成以下几个表,每个表之间建立映射关系,设置参数时查表设置。
typedef struct { uint8_t id; //模块ID uint8_t app_id; //App ID uint8_t spec_idx; // tBTA_DM_PM_SPEC表中的index } tBTA_DM_PM_CFG; typedef struct { tBTA_DM_PM_ACTION power_mode; // 连接策略 uint16_t timeout; // 当前策略的超时时间 } tBTA_DM_PM_ACTN; typedef struct { uint8_t allow_mask; //运行的策略的mask uint8_t ssr; tBTA_DM_PM_ACTN actn_tbl[BTA_DM_PM_NUM_EVTS][2]; // 各个profile不同状态下的策略和超时时间,策略的参数在tBTM_PM_PWR_MD中 } tBTA_DM_PM_SPEC; typedef struct { uint16_t max; uint16_t min; uint16_t attempt; uint16_t timeout; tBTM_PM_MODE mode; } tBTM_PM_PWR_MD;
注: Core 5.3删除了park模式,本系列文章不再介绍,有文章中有出现请忽略
代码中这三个表格实现如下:
tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_CFG bta_dm_pm_cfg[BTA_DM_NUM_PM_ENTRY + 1] = { {BTA_ID_SYS, BTA_DM_NUM_PM_ENTRY, 0}, /* reserved: specifies length of this table. */ {BTA_ID_AG, BTA_ALL_APP_ID, 0}, /* ag uses first spec table for app id 0 */ {BTA_ID_CT, 1, 1}, /* ct (BTA_ID_CT,APP ID=1) spec table */ {BTA_ID_CG, BTA_ALL_APP_ID, 1}, /* cg resue ct spec table */ ... }; tBTA_DM_PM_TYPE_QUALIFIER tBTA_DM_PM_SPEC bta_dm_pm_spec[BTA_DM_NUM_PM_SPEC] = { /* AG : 0 */ {(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */ (BTA_DM_PM_SSR2), /* the SSR entry */ { {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open sniff */ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ {{BTA_DM_PM_SNIFF_SCO_OPEN_IDX, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open, active */ {{BTA_DM_PM_SNIFF_A2DP_IDX, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close sniff */ {{BTA_DM_PM_SNIFF, 7000}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ {{BTA_DM_PM_ACTIVE, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ {{BTA_DM_PM_RETRY, 7000}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ }}, /* CT, CG : 1 */ {(BTA_DM_PM_SNIFF | BTA_DM_PM_PARK), /* allow park & sniff */ (BTA_DM_PM_SSR2), /* the SSR entry */ { {{BTA_DM_PM_PARK, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn open park */ {{BTA_DM_PM_NO_PREF, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* conn close */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app open */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* app close */ {{BTA_DM_PM_SNIFF_A2DP_IDX, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco open sniff */ {{BTA_DM_PM_PARK, 5000}, {BTA_DM_PM_NO_ACTION, 0}}, /* sco close park */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* idle */ {{BTA_DM_PM_NO_ACTION, 0}, {BTA_DM_PM_NO_ACTION, 0}}, /* busy */ {{BTA_DM_PM_RETRY, 5000}, {BTA_DM_PM_NO_ACTION, 0}} /* mode change retry */ }}, ... }; tBTA_DM_PM_TYPE_QUALIFIER tBTM_PM_PWR_MD bta_dm_pm_md[] = { /* sniff modes: max interval, min interval, attempt, timeout */ {BTA_DM_PM_SNIFF_MAX, BTA_DM_PM_SNIFF_MIN, BTA_DM_PM_SNIFF_ATTEMPT, BTA_DM_PM_SNIFF_TIMEOUT, BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF - A2DP */ {BTA_DM_PM_SNIFF1_MAX, BTA_DM_PM_SNIFF1_MIN, BTA_DM_PM_SNIFF1_ATTEMPT, BTA_DM_PM_SNIFF1_TIMEOUT, BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF1 */ {BTA_DM_PM_SNIFF2_MAX, BTA_DM_PM_SNIFF2_MIN, BTA_DM_PM_SNIFF2_ATTEMPT, BTA_DM_PM_SNIFF2_TIMEOUT, BTM_PM_MD_SNIFF}, /* for BTA_DM_PM_SNIFF2- HD idle */ ... }; const tBTA_DM_PM_CFG* p_bta_dm_pm_cfg = &bta_dm_pm_cfg[0]; const tBTA_DM_PM_SPEC* p_bta_dm_pm_spec = &bta_dm_pm_spec[0]; const tBTM_PM_PWR_MD* p_bta_dm_pm_md = &bta_dm_pm_md[0];
触发修改参数的动作有3个:
bta_sys_pm_register(bta_dm_pm_cback)
向系统管理注册回调,系统管理中对应的API以及状态如下:extern void bta_sys_conn_open(uint8_t id, uint8_t app_id, const RawAddress& peer_addr); extern void bta_sys_conn_close(uint8_t id, uint8_t app_id, const RawAddress& peer_addr); extern void bta_sys_app_open(uint8_t id, uint8_t app_id, const RawAddress& peer_addr); extern void bta_sys_app_close(uint8_t id, uint8_t app_id, const RawAddress& peer_addr); extern void bta_sys_sco_open(uint8_t id, uint8_t app_id, const RawAddress& peer_addr); extern void bta_sys_sco_close(uint8_t id, uint8_t app_id, const RawAddress& peer_addr); extern void bta_sys_sco_use(uint8_t id, uint8_t app_id, const RawAddress& peer_addr); extern void bta_sys_sco_unuse(uint8_t id, uint8_t app_id, const RawAddress& peer_addr); extern void bta_sys_idle(uint8_t id, uint8_t app_id, const RawAddress& peer_addr); extern void bta_sys_busy(uint8_t id, uint8_t app_id, const RawAddress& peer_addr); #define BTA_SYS_CONN_OPEN 0x00 #define BTA_SYS_CONN_CLOSE 0x01 #define BTA_SYS_APP_OPEN 0x02 #define BTA_SYS_APP_CLOSE 0x03 #define BTA_SYS_SCO_OPEN 0x04 #define BTA_SYS_SCO_CLOSE 0x05 #define BTA_SYS_CONN_IDLE 0x06 #define BTA_SYS_CONN_BUSY 0x07
设备管理器中的处理函数是bta_dm_pm_cback
,首先根据id和app id在bta_dm_pm_cfg
中查找到bta_dm_pm_spec
的index,根据index从bta_dm_pm_spec
获取到当前状态的策略,如果是BTA_DM_PM_NO_ACTION
则直接返回,否则根据id、app id、对端地址查找连接信息;根据index从bta_dm_pm_spec
获取当前状态的策略,如果是BTA_DM_PM_NO_PREF
则删除连接信息,否则判断是否找到连接信息,如果找到则更新状态,否则添加新的连接信息;最后调用bta_dm_pm_set_mode
更新连接策略。
功耗管理是按设备划分的,不是按照连接的profile划分,即一个设备可能连接多个profile(通过id区分),只要有一个profile是active则整个通信都是active,所以当某个profile的power_mode为BTA_DM_PM_NO_PREF
时会删除这个profile记录的信息,即这个profile不再决定通信的策略。
btm
初始化时会调用BTM_PmRegister((BTM_PM_REG_SET | BTM_PM_REG_NOTIF), &bta_dm_cb.pm_id,bta_dm_pm_btm_cback)
向BTM注册回调,当策略发生变化时通过bta_dm_pm_btm_cback
回调通知设备管理器。根据当前状态判断是否需要调用bta_dm_pm_set_mode
更新策略。
定时器
在bta_dm_pm_set_mode
中会启动一些定时器,当定时器超时后会触发调用bta_dm_pm_timer_cback
,回调中首先会清除不使用的定时器,然后根据定时器记录的策略调用bta_dm_pm_set_mode
。
bta_dm_pm_set_mode
是链接策略更新的核心函数,首先找到所有连接的profile中策略优先级最高的策略(ACTIVE > SNIFF > NO_PREF > NO_ACTIVE),如果需要启动定时器且定时器的超时时间大于0,则启动一个定时器(超时时间在bta_dm_pm_spec
中获取)。如果设置的策略优先级低于当前的策略则直接返回,否则根据设置相应的策略。
设置Park策略和Sniff策略时获取bta_dm_pm_md
表中的策略参数。
在fluoride中上报事件大多是通过回调上报,启动蓝牙时(BTA_EnableBluetooth
)注册了tBTA_DM_SEC_CBACK
原型的回调,bta中设备管理的大多数事件都是通过这个回调向上层上报事件,此外BTA_DmSearch
和BTA_DmDiscover
时也注册了tBTA_DM_SEARCH_CBACK
原型的回调,用于上报发现设备/服务的事件。
// 原型 typedef void(tBTA_DM_SEC_CBACK)(tBTA_DM_SEC_EVT event, tBTA_DM_SEC* p_data); /* 上报的事件 */ #define BTA_DM_ENABLE_EVT 0 /* Enable Event */ #define BTA_DM_DISABLE_EVT 1 /* Disable Event */ #define BTA_DM_PIN_REQ_EVT 2 /* PIN request. */ #define BTA_DM_AUTH_CMPL_EVT 3 /* Authentication complete indication. */ #define BTA_DM_AUTHORIZE_EVT 4 /* Authorization request. */ #define BTA_DM_LINK_UP_EVT 5 /* Connection UP event */ #define BTA_DM_LINK_DOWN_EVT 6 /* Connection DOWN event */ #define BTA_DM_SIG_STRENGTH_EVT 7 /* Signal strength for bluetooth connection */ #define BTA_DM_BUSY_LEVEL_EVT 8 /* System busy level */ #define BTA_DM_BOND_CANCEL_CMPL_EVT 9 /* Bond cancel complete indication */ #define BTA_DM_SP_CFM_REQ_EVT 10 /* Simple Pairing User Confirmation request. */ #define BTA_DM_SP_KEY_NOTIF_EVT 11 /* Simple Pairing Passkey Notification */ #define BTA_DM_SP_RMT_OOB_EVT 12 /* Simple Pairing Remote OOB Data request. */ #define BTA_DM_SP_KEYPRESS_EVT 13 /* Key press notification event. */ #define BTA_DM_ROLE_CHG_EVT 14 /* Role Change event. */ #define BTA_DM_BLE_KEY_EVT 15 /* BLE SMP key event for peer device keys */ #define BTA_DM_BLE_SEC_REQ_EVT 16 /* BLE SMP security request */ #define BTA_DM_BLE_PASSKEY_NOTIF_EVT 17 /* SMP passkey notification event */ #define BTA_DM_BLE_PASSKEY_REQ_EVT 18 /* SMP passkey request event */ #define BTA_DM_BLE_OOB_REQ_EVT 19 /* SMP OOB request event */ #define BTA_DM_BLE_LOCAL_IR_EVT 20 /* BLE local IR event */ #define BTA_DM_BLE_LOCAL_ER_EVT 21 /* BLE local ER event */ #define BTA_DM_BLE_NC_REQ_EVT 22 /* SMP Numeric Comparison request event */ #define BTA_DM_SP_RMT_OOB_EXT_EVT 23 /* Simple Pairing Remote OOB Extended Data request. */ #define BTA_DM_BLE_AUTH_CMPL_EVT 24 /* BLE Auth complete */ #define BTA_DM_DEV_UNPAIRED_EVT 25 #define BTA_DM_HW_ERROR_EVT 26 /* BT Chip H/W error */ #define BTA_DM_LE_FEATURES_READ 27 /* Cotroller specific LE features are read */ #define BTA_DM_ENER_INFO_READ 28 /* Energy info read */ #define BTA_DM_BLE_SC_OOB_REQ_EVT 29 /* SMP SC OOB request event */ #define BTA_DM_BLE_CONSENT_REQ_EVT 30 /* SMP consent request event */ // 原型 typedef void(tBTA_DM_SEARCH_CBACK)(tBTA_DM_SEARCH_EVT event, tBTA_DM_SEARCH* p_data); /* 上报的事件 */ #define BTA_DM_INQ_RES_EVT 0 /* Inquiry result for a peer device. */ #define BTA_DM_INQ_CMPL_EVT 1 /* Inquiry complete. */ #define BTA_DM_DISC_RES_EVT 2 /* Discovery result for a peer device. */ #define BTA_DM_DISC_BLE_RES_EVT 3 /* Discovery result for BLE GATT based servoce on a peer device. */ #define BTA_DM_DISC_CMPL_EVT 4 /* Discovery complete. */ #define BTA_DM_DI_DISC_CMPL_EVT 5 /* Discovery complete. */ #define BTA_DM_SEARCH_CANCEL_CMPL_EVT 6 /* Search cancelled */
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。