BLE

1. BLE介绍

  • 定义:BLE(Bluetooth Low Energy)是一种短距离、低成本、低功耗的无线技术。

  • 支持功能:支持主模式、从模式及多连接,暂不支持 BLE Mesh。

  • 文档范围:主要介绍 BLE 相关接口及使用方法。

2. 使能/关闭BLE功能

  • 打开方式:在menuconfig中开启"BLUETOOTH"宏,并按需配置其他功能:

  • 关闭方式:在menuconfig中关闭"BLUETOOTH"宏。 BLE功能配置

3. HCI功能

HCI(Host Controller Interface)是Host与Controller的通信接口,用于控制蓝牙芯片动作(如inquiry,connect,disconnect),主要用于调试分析。

3.1 配置与控制

  1. 在menuconfig中开启HCI配置:
    HCI配置

  2. 通过finsh命令开关(需重启设备):

    nvds update hci_log 1  // 1:打开HCI;0:关闭HCI
    

3.2 打印说明

  • 52X系列的HCI信息在HCPU打印,其他系列在LCPU打印。

  • 需按如下串口配置才能正常显示HCI数据(HCI回放需对应.bin和.bintime文件):
    HCI串口配置

    1. HCI全显示:HCI数据会完整显示

    2. HCI无数据:仅显示HCI数据的头信息,不显示具体内容

    3. HCI隐藏:不显示HCI数据(抓取HCI数据时建议采用此模式,便于分析)

4. BLE连接

BLE连接速度(首次连接或回连)仅由两个参数决定:设备的广播间隔手机的扫描窗口/间隔比例

4.1 设备的广播间隔

  • 快广播(100-200ms):
    连接速度快(以100ms为例,通常3秒内,多数情况1秒内可连接),功耗相对较高。

  • 慢广播(800-1000ms):
    更省电,但连接速度较慢,且受手机扫描间隔影响显著。

建议的广播切换策略

  1. 基础策略
    开机或BLE断开后,先快广播30秒至1分钟,超时后自动切换为慢广播。适用于拉距或异常断开后快速重连。

  2. 优化策略
    开机、BLE断开、设备亮屏时触发快广播,超时后切换为慢广播。实现较复杂,但能进一步加速连接。

4.2 手机的扫描窗口/间隔比例

扫描窗口是手机在一个扫描间隔内的实际扫描时间,该比例越接近1:1,扫描速度越快。

  • IOS系统
    系统自动扫描,扫描窗口与间隔比例通常为1:1或1:2(如30ms窗口+30ms间隔,或30ms窗口+60ms间隔)。

  • 安卓/鸿蒙系统
    分为APK发起和系统发起两种扫描方式:

    1. APK主动扫描:建议使用SCAN_MODE_LOW_LATENCY标志,此时扫描比例通常为1:1或1:2。

    2. 系统发起扫描:配对并使能HID时,部分手机会像IOS一样主动发起连接。

5. BLE回连

BLE回连通常由手机主动发起,设备端仅通过广播等待连接,不同系统的回连机制存在差异。

5.1 IOS系统

  • 自动回连特性:与IOS配对并激活ANCS后,IOS会持续尝试回连,即使APK未发起连接,设备端也可能显示已连接。

  • 异常排查

    1. 若APK显示未连接,但设备端显示已连接,可通过手机设置确认连接状态,判断是APK问题还是BLE连接异常。

    2. 若设备清除本地LinkKey但手机未删除配对,会导致iPhone频繁连接后断开(因无配对信息)。解决方案:

      • 设备恢复出厂时,提示用户同步删除手机端配对信息;

      • 或设备恢复出厂时保留BLE配对信息(需APK配合处理,避免被非预期iPhone连接)。

5.2 安卓/鸿蒙系统

  • 主动回连场景:仅在配对并使能HID时,部分手机会主动发起回连,但可能效率低且覆盖APK连接,导致连接缓慢。

  • 常规回连逻辑:需APK主动发起连接。若APK被杀死,将无法发起连接,导致蓝牙始终无法连上。

6. BLE相关API

函数原型

功能描述

uint16_t get_mtu_size()

获取当前MTU(最大传输单元)大小

bool ble_get_ble_status(uint8_t type)

获取BLE状态:
- CONNECT_STATUS:连接状态
- ADV_STATUS:广播状态

void ble_start_advertising(void)

开启BLE广播

void ble_stop_advertising(void)

关闭BLE广播

void ble_update_advertising(ble_roadcast_mode_t mode)

切换广播模式(可自定义不同模式的广播信息)

void ble_enter_low_power(uint8_t conn_idx)

使指定连接进入低功耗模式(低速模式)

void ble_exit_low_power(uint8_t conn_idx)

使指定连接退出低功耗模式(进入快速模式)

void ble_switch_onoff(uint8_t switch_on)

开关BLE功能:
- 1:开启
- 0:关闭

uint8_t sibles_exchange_mtu(uint8_t conn_idx)

与对端设备交互MTU大小(建议在连接成功时调用)

uint8_t ble_gap_scan_start(ble_gap_scan_start_t *scan_param)

开始搜索周围BLE设备

uint8_t ble_gap_scan_stop(void)

停止搜索BLE设备

uint8_t ble_gap_create_connection(ble_gap_connection_create_param_t *conn_param)

主动创建与其他BLE设备的连接(主模式下使用)

uint8_t ble_gap_update_conn_param(ble_gap_update_conn_param_t *conn_para)

更新当前连接的参数(如间隔、超时等)

uint8_t connection_manager_delete_all_bond(void)

删除所有已保存的BLE配对绑定信息

uint8_t connection_manager_get_addr_by_conn_idx(uint8_t conn_idx, bd_addr_t *data)

通过连接索引获取对端设备的蓝牙地址

uint8_t ble_gap_disconnect(ble_gap_disconnect_t *conn)

断开指定的BLE连接

函数原型

功能描述

uint16_t get_mtu_size()

获取当前MTU(最大传输单元)大小

bool ble_get_ble_status(uint8_t type)

获取BLE状态: - CONNECT_STATUS:连接状态 - ADV_STATUS:广播状态

void ble_start_advertising(void)

开启BLE广播

void ble_stop_advertising(void)

关闭BLE广播

void ble_update_advertising(ble_roadcast_mode_t mode)

切换广播模式(可自定义不同模式的广播信息)

void ble_enter_low_power(uint8_t conn_idx)

使指定连接进入低功耗模式(低速模式)

void ble_exit_low_power(uint8_t conn_idx)

使指定连接退出低功耗模式(进入快速模式)

void ble_switch_onoff(uint8_t switch_on)

开关BLE功能: - 1:开启 - 0:关闭

uint8_t sibles_exchange_mtu(uint8_t conn_idx)

与对端设备交互MTU大小(建议在连接成功时调用)

uint8_t ble_gap_scan_start(ble_gap_scan_start_t *scan_param)

开始搜索周围BLE设备

uint8_t ble_gap_scan_stop(void)

停止搜索BLE设备

uint8_t ble_gap_create_connection(ble_gap_connection_create_param_t *conn_param)

主动创建与其他BLE设备的连接(主模式下使用)

uint8_t ble_gap_update_conn_param(ble_gap_update_conn_param_t *conn_para)

更新当前连接的参数(如间隔、超时等)

uint8_t connection_manager_delete_all_bond(void)

删除所有已保存的BLE配对绑定信息

uint8_t connection_manager_get_addr_by_conn_idx(uint8_t conn_idx, bd_addr_t *data)

通过连接索引获取对端设备的蓝牙地址

uint8_t ble_gap_disconnect(ble_gap_disconnect_t *conn)

断开指定的BLE连接

7. BLE 相应事件

BLE 相关事件统一在 ble_connect.c 文件的 ble_event_handler 函数中处理,主要事件如下:

事件名

描述

BLE_GAP_CONNECTED_IND

连接成功事件

BLE_GAP_DISCONNECTED_IND

断开连接事件

BLE_GAP_UPDATE_CONN_PARAM_IND

连接参数更新事件

SIBLES_MTU_EXCHANGE_IND

MTU 交互事件(上报当前 MTU 值)

BLE_GAP_SCAN_START_CNF

搜索开始事件(可清除上一次搜索结果)

BLE_GAP_EXT_ADV_REPORT_IND

搜索结果事件

8. 增加一个service uuid

客户增加自己的UUID时可参考"ble_app_msg.c"中的信息,"ble_app_msg.c"文件是与我们APP对应的UUID,客户如不使用时,可直接使用此文件进行修改。 其中如果客户增加增加了UUID,相应的初始化函数要在“notify_ble_start_adv”函数中有调用。 其中权限设置,对应如下代码所示,用户根据自己的需要设置对应的权限。

PERM(WRITE_REQ, ENABLE) | PERM(WRITE_COMMAND, ENABLE) | PERM(RD, ENABLE) | PERM(NTF, ENABLE) | PERM(IND, ENABLE), PERM(UUID_LEN, UUID_128) | PERM(RI, ENABLE)

/**
 *   15   14   13   12   11   10    9    8    7    6    5    4    3    2    1    0
 * +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 * |EXT | WS | I  | N  | WR | WC | RD | B  |    NP   |    IP   |   WP    |    RP   |
 * +----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+----+
 *
 * Bit [0-1]  : Read Permission         (0 = NO_AUTH, 1 = UNAUTH, 2 = AUTH, 3 = SEC_CON)
 * Bit [2-3]  : Write Permission        (0 = NO_AUTH, 1 = UNAUTH, 2 = AUTH, 3 = SEC_CON)
 * Bit [4-5]  : Indication Permission   (0 = NO_AUTH, 1 = UNAUTH, 2 = AUTH, 3 = SEC_CON)
 * Bit [6-7]  : Notification Permission (0 = NO_AUTH, 1 = UNAUTH, 2 = AUTH, 3 = SEC_CON)
 *
 * Bit [8]    : Extended properties present (only relevant for a characteristic value)
 * Bit [9]    : Broadcast permission        (only relevant for a characteristic value)
 * Bit [10]   : Write Command accepted
 * Bit [11]   : Write Signed accepted
 * Bit [12]   : Write Request accepted
 * Bit [13]   : Encryption key Size must be 16 bytes
 */
enum attm_perm_mask
{
    /// retrieve all permission info
    PERM_MASK_ALL           = 0x0000,
    /// Read Permission Mask
    PERM_MASK_RP            = 0x0003,
    PERM_POS_RP             = 0,
    /// Write Permission Mask
    PERM_MASK_WP            = 0x000C,
    PERM_POS_WP             = 2,
    /// Indication Access Mask
    PERM_MASK_IP            = 0x0030,
    PERM_POS_IP             = 4,
    /// Notification Access Mask
    PERM_MASK_NP            = 0x00C0,
    PERM_POS_NP             = 6,
    /// Broadcast descriptor present
    PERM_MASK_BROADCAST     = 0x0100,
    PERM_POS_BROADCAST      = 8,
    /// Read Access Mask
    PERM_MASK_RD            = 0x0200,
    PERM_POS_RD             = 9,
    /// Write Command Enabled attribute Mask
    PERM_MASK_WRITE_COMMAND = 0x0400,
    PERM_POS_WRITE_COMMAND  = 10,
    /// Write Request Enabled attribute Mask
    PERM_MASK_WRITE_REQ     = 0x0800,
    PERM_POS_WRITE_REQ      = 11,
    /// Notification Access Mask
    PERM_MASK_NTF           = 0x1000,
    PERM_POS_NTF            = 12,
    /// Indication Access Mask
    PERM_MASK_IND           = 0x2000,
    PERM_POS_IND            = 13,
    /// Write Signed Enabled attribute Mask
    PERM_MASK_WRITE_SIGNED  = 0x4000,
    PERM_POS_WRITE_SIGNED   = 14,
    /// Extended properties descriptor present
    PERM_MASK_EXT           = 0x8000,
    PERM_POS_EXT            = 15,

    /// Properties
    PERM_MASK_PROP          = 0xFF00,
    PERM_POS_PROP           = 8,
};

初始化时Sercurity level for service如下代码所示,可根据实际需要进行设置

svc.sec_lvl = PERM(SVC_AUTH, SEC_CON) | PERM(SVC_UUID_LEN, UUID_128) | PERM(SVC_MI, ENABLE);
/**
 * Service permissions
 *
 *    7    6    5    4    3    2    1    0
 * +----+----+----+----+----+----+----+----+
 * |SEC |UUID_LEN |DIS |  AUTH   |EKS | MI |
 * +----+----+----+----+----+----+----+----+
 *
 * Bit [0]  : Task that manage service is multi-instantiated (Connection index is conveyed)
 * Bit [1]  : Encryption key Size must be 16 bytes
 * Bit [2-3]: Service Permission      (0 = NO_AUTH, 1 = UNAUTH, 2 = AUTH, 3 = Secure Connect)
 * Bit [4]  : Disable the service
 * Bit [5-6]: UUID Length             (0 = 16 bits, 1 = 32 bits, 2 = 128 bits, 3 = RFU)
 * Bit [7]  : Secondary Service       (0 = Primary Service, 1 = Secondary Service)
 */
enum attm_svc_perm_mask
{
    /// Task that manage service is multi-instantiated
    PERM_MASK_SVC_MI        = 0x01,
    PERM_POS_SVC_MI         = 0,
    /// Check Encryption key size for service Access
    PERM_MASK_SVC_EKS       = 0x02,
    PERM_POS_SVC_EKS        = 1,
    /// Service Permission authentication
    PERM_MASK_SVC_AUTH      = 0x0C,
    PERM_POS_SVC_AUTH       = 2,
    /// Disable the service
    PERM_MASK_SVC_DIS       = 0x10,
    PERM_POS_SVC_DIS        = 4,
    /// Service UUID Length
    PERM_MASK_SVC_UUID_LEN  = 0x60,
    PERM_POS_SVC_UUID_LEN   = 5,
    /// Service type Secondary
    PERM_MASK_SVC_SECONDARY = 0x80,
    PERM_POS_SVC_SECONDARY  = 7,
};

9. BLE数据接收和发送

/**
  * @brief  Send new service attribute to remote using gatt notify.
  * @param[in]  conn_idx Connection index for the service.
  * @param[in]  value Attribute content buffer.
  */
int sibles_write_value(uint8_t conn_idx, sibles_value_t *value);

/**
  * @brief  Register GATT service callback.
  * @param[in]  hdl Service handle.
  * @param[in]  gcbk Service attribute get callback.
  * @param[in]  scbk Service attribute set callback.
  */
void sibles_register_cbk(sibles_hdl hdl, sibles_get_cbk gcbk, sibles_set_cbk scbk);

其中接收函数在初始化时设置的"scbk"函数中,可参考"ble_msg.c"文件中的对应函数。

10. BLE作为master连接其他设备

打开ble做主设备功能如下图所示:

可参考此参数"diss scan start 1 500 50 60000 -60"搜索设备

搜索得到的结果事件如下,其值没往UI传,需要自定义添加一个对应的事件。

连接设备,其中地址类型和地址在搜索结果中有。
其他操作参考如下命令

ble做主和多连接可参考“sdk\example\ble\central_and_peripheral\src\main.c"文件

11. BLE修改广播参数

如果要修改ble广播参数可在"ble_advertising_start"函数中更新"para"变化中的各个参数即可。

void ble_advertising_start(ble_roadcast_control_t control, ble_roadcast_mode_t mode)

12. BLE修改连接参数

我们发布的版本中,ble的速度会在“sibles_acquire_tx_pkts_hook”函数当数据包大于3(if (buffer_num >= BLE_SPEED_ADAPT_TX_COUNT))时更新为快速模式,连续30秒没数据传输时,自动更新为低速模式。OTA及表盘传输时速度也是自动控制的,不用客户控制。如客户想自行控制ble连接参考,可以参考下面的的对应函数实现。

//进入low power 命令,调此函数时ble进入低速模式
void ble_enter_low_power(uint8_t conn_idx);

//退出low power 命令,调此函数时ble进入快速模式
void ble_exit_low_power(uint8_t conn_idx);

/**
 * @brief update conneciton parameters. 此函数可任意更新连接参数
 * @param[conn_idx] connection index.
 * @param[interval_level] interval level to be set, @see connection_manager_update_conneciton.
 * @param[data] conneciton parameters vlaue, @see cm_conneciont_parameter_value_t.
 * @return set status @see connection_manager_state
 */
uint8_t connection_manager_update_parameter(uint8_t conn_idx, uint8_t interval_level, uint8_t *data);

13. BLE修改MTU

在ble连接成功时可调用“sibles_exchange_mtu”函数交互MTU,或是对端设置MTU成功后“SIBLES_MTU_EXCHANGE_IND”事件上报设置的MTU值。

/**
  * @brief  Exchange MTU size.
  * @param[in]  conn_idx connection index.
  * @retval result.
  */
uint8_t sibles_exchange_mtu(uint8_t conn_idx);

/**
  * @brief  User implmentation function. Stack will call this function to get max mtu.
  *         if not implmentation, stack will use default value as 1024.
  * @param
  * @return Maximum MTU value you want to use,
  *         should greater than or equal to 23, less than or equal to 1024.
  */
uint16_t ble_max_mtu_get();

14. BLE配对

ble在与手机进行配对时支持弹窗,只需打开“BLE_USING_PAIRING_CONFIRMATION”宏即可。

事件名称

描述

BLE_APP_PAIRING_CONFIRMATION

弹窗事件

BLE_APP_PAIRING_FAILED

配对失败事件

BLE_APP_PAIRING_SUCCEED

配对成功事件

//弹窗时用户点击“确定”或“取消”时需要调用的函数
uint8_t connection_manager_bond_ack_reply(uint8_t conn_idx, uint8_t command, bool accept);

15. BLE对接客户的BLE应用协议到solution

我们发布的ble通信协议中使用了nanopb协议进行编码和解码,客户如不需要可在menuconfig中关闭“PKG_USING_NANOPB”宏。
客户对接自己的协议时首先将"ble_msg.c"文件中的UUID修改为客户需要的UUID,然后在ble接收到数据后去调用我们提供的对应函数(如设置时间,设置自动心率等)可参考"protocol_setting.c"文件中的对应函数。

16. ANCS

ANCS(Apple Notification Center Service)是IOS系统中的一个通知服务,使用该服务的方式为,设备连接手机后,设备上的GATT客户端发现IOS手机端上的ANCS服务,并且使能其通知源Characteristics的notifys功能,之后IOS系统就会通过ble推送消息给设备。

ANCS消息入口函数为“app_ancs_notification”最终调用“message_send_to_gui_thread”函数进行处理。
如需要增加ANCS的消息类型则在“app_ancs.c”文件中增加对应的类型即可。

static message_item_t message_item[] =
{
    {"com.apple.MobileSMS",     MESSAGE_TYPE_MESSAGE        },
    {"com.tencent.mqq",         MESSAGE_TYPE_QQ             },
    {"com.tencent.xin",         MESSAGE_TYPE_WECHAT         },
    {"net.whatsapp.WhatsApp",   MESSAGE_TYPE_WHATSAPP       },
    {"com.facebook.Messenger",  MESSAGE_TYPE_MESSENGER      },
    {"com.atebits.Tweetie2",    MESSAGE_TYPE_TWITTER        },
    {"com.linkedin.Zephyr",     MESSAGE_TYPE_LINKEDIN       },
    {"com.burbn.instagram",     MESSAGE_TYPE_INSTAGRAM      },
    {"com.facebook.Facebook",   MESSAGE_TYPE_FACEBOOK       },
    {"com.apple.mobilephone",   MESSAGE_TYPE_INCOMINGCALL   },
};

17. AMS

AMS全称Apple Media Service(苹果媒体服务),是提供给BLE设备的一种简单控制媒体应用程序的方式,并且用于获取已连接的 IOS 设备的媒体状态信息。 除了标准的通用属性配置文件(GATT)子程序集外,AMS没有任何依赖性。作为GATT客户端的设备在使用AMS时,可以自己访问和使用IOS设备提供的其他服务。

17.1 术语

Apple Media Service 称为 AMS AMS 服务的发布者(也就是我们的 ios 设备)应被称为媒体源(MS)。 AMS 服务的客户端(也就是我们的蓝牙设备)应被称为媒体控制器(MR)。 下面统一使用 媒体源 和 媒体控制 来描 IOS 设备和蓝牙设备。

17.2 AMS Service UUID

AMS 主服务(Service) UUID 为 89D3502B-0F36-433A-8EF4-C502AD55F8DC
AMS 服务下的三个特征(Characteristic) UUID:
远程命令(Remote Command)(writeable,notifiable)
9B3C81D8-57B1-4A8A-B8DF-0E56F7CA51C2
实体更新(Entity Update)(writeable with response,notifiable)
2F7CABCE-808D-411F-9A0C-BB92BA96C102
实体属性(Entity Attribute)(readable, writeable)
C6B2F38C-23AB-46D8-A6AB-A3A870BBD5D7

下图展示了媒体源和媒体控制器间的服务设置:

  • 1.媒体控制器发现媒体源的 AMS 服务和特征

  • 2.媒体控制器订阅媒体源实体更新

  • 3.媒体控制器向媒体源写入需要监听的实体(EntityID),例如监听歌曲变化等

  • 4.当媒体源监听的实体(EntityID)有变动时,会通知其变动内容

17.3AMS Characteristic

实体
AMS 定义了 3 个不同的实体,每个实体都有一组不同的属性:
播放器 (Player): 当前活跃的媒体应用。该实体属性包括其名称、播放状态和播放音量等
队列 (Queue): 当前加载的播放队列。该实体的属性包括其队列数及其随机和重复模式等
音轨 (Track): 当前加载的音轨。该实体的属性包括其艺术家、标题和总的播放时间等。

播放器 (Player)属性表

// 获取播放器属性函数
app_ams_player_t *app_ams_get_player(void)
{
    return app_ams_player;
}

通过播放器属性,我们可以获取 PlaverAttributelDName 当前音乐播放器的字符串,例如 IOS 手机使用的网易云音乐,那么媒体源推送的字符串转换为 unicode 编码后再转成中文,实际上就是“网易云音乐”,同理其他的音乐 APP,也会显示其相应的名称,非音乐APP 是不会有推送的。
PlayerAttributelDPlaybacklnfo 可以获取对应的播放状态、播放速率以及歌曲经过的时间,例如接收到推送为 49 44 49 46 48 44 55 49 46 49 52 55 表示 1,1.0,71.147,当前状态为播放、速率 1.0、已过时间 71.147 秒
PlaverAtributelDvolume 用于获取当前的音量浮点值,音量最大时为 1,最小时为 0,IOS 按一次音量按键,每次递进 0.0625。
注: 通过上面的信息,我们可以计算出当前经过的时间,公式如下:
CurrentElapsedTime = ElapsedTime + ((TimeNow-TimePlaybacklnfoWasReceived)* PlaybackRate)
上方展示的音乐进度条,也是依靠该方式和歌曲总长度计算的
队列 (Queue) 属性表

// 获取队列属性函数
app_ams_queue_t *app_ams_get_queue(void)
{
    return app_ams_queue;
}

这一块为切换播放器播放模式时,会通知对应的模式变化。
音轨 (Track)属性表

// 获取音轨属性函数
app_ams_track_t *app_ams_get_track(void)
{
    return app_ams_track;
}

这一块包含了歌曲名、歌手名、专辑名称以及当前音乐总时长。假设音乐时长03:08,那么媒体控制器接收到的则是188.000秒。

若媒体控制器订阅了Track属性,那么当媒体源播放音乐时,会将A音乐的曲名和歌手名推送给媒体控制器,每次有变动时,都会通知媒体控制器。
代码中对应事件为“BLE_APP_AMS_NOTI_IND”

/**
 * @brief EntityID values.
 */
typedef enum
{
    BLE_AMS_ENTITY_ID_PLAYER,         /**< Player entity. The attribute is @ref ble_ams_entity_player_attribute_t. */
    BLE_AMS_ENTITY_ID_QUEUE,          /**< Queue entity. The attribute is @ref ble_ams_entity_queue_attribute_t. */
    BLE_AMS_ENTITY_ID_TRACK,          /**< Track entity. The attribute is @ref ble_ams_entity_queue_attribute_t. */
} ble_ams_entity_id_t;

/**
 * @brief The structure of #BLE_AMS_ENTITY_ATTRIBUTE_PAIR_IND.
 */
typedef struct
{
    uint8_t entity_id;       /**< @see enum ble_ams_entity_id_t */
    uint8_t attr_id;         /**< Associated attribute ID for an dedicated entityID. */
    uint8_t entity_up_flag;  /**< Entity update flag. 1 is truncated. */
    uint16_t len;            /**< length of attribute value. */
    uint8_t value[0];        /**< Attribute value. */
} ble_ams_entity_attr_value_t;

ble_ams_entity_attr_value_t *value = (ble_ams_entity_attr_value_t *)data;
ipc_send_msg_from_ble_to_app(BLE_APP_AMS_NOTI_IND, sizeof(ble_ams_entity_attr_value_t) + value->len, (uint8_t *)value);
//当收到“BLE_APP_AMS_NOTI_IND”事件时可依据 value->entity_id 值确定当前是什么属性发生了变化。

17.4 远程命令(Remote Command)

远程命令这个特征值是用于 媒体控制器 发送给 媒体源 的播放状态特征,例如播放/暂停、音量加/减、上/下首、循环播放等。
媒体控制器 发送命令格式如下:


媒体控制器 发现 媒体源 AMS 服务后,可以通过发送控制命令,播放/暂停、音量加减等操作媒体源播放器。
此特性还用于向 媒体控制器 报告当前 媒体源 支持的命令集,当媒体播放器支持的命令列表发生变化时,媒体源 会使用如下所示的格式,在该特征生产一条通知,通知中包括了支持的命令集:


通过该命令集,我们的蓝牙设备就可以对 IOS 设备的媒体播放器进行控制,该方式的音乐控制,相比较 HID,我觉得更优,因为 HID 控制只能在媒体播放器界面进行控制,模拟按键的方式去控制播放,并且 HID 的方式不能获取歌曲名、歌曲进度等,所以相较下,如果用于控制IOS 媒体播放器,那么便用 AMS 是最优的方式。
对应代码中命令及函数如下:

/**
 * @brief Remote commandID values.
 */
typedef enum
{
    BLE_AMS_CMD_PLAY,                     /**< Play command. */
    BLE_AMS_CMD_PAUSE,                    /**< Pause command. */
    BLE_AMS_CMD_TOGGLE_PLAY_PAUSE,        /**< Toggle command. */
    BLE_AMS_CMD_NEXT,                     /**< Next command. */
    BLE_AMS_CMD_PREV,                     /**< Previous command. */
    BLE_AMS_CMD_VOL_UP,                   /**< Voloume up command. */
    BLE_AMS_CMD_VOL_DOWN,                 /**< Volume down command. */
    BLE_AMS_CMD_REPEAT_MODE,              /**< Repeat mode command. */
    BLE_AMS_CMD_SHUFFLE_MODE,             /**< Shuffle mode command. */
    BLE_AMS_CMD_SKIP_FWD,                 /**< Skip forward command. */
    BLE_AMS_CMD_SKIP_BACKWD,              /**< Skip backward command. */
    BLE_AMS_CMD_LIKE_TRACK,               /**< Like track command. */
    BLE_AMS_CMD_DISLIKE_TRACK,            /**< Dislike track command. */
    BLE_AMS_CMD_BOOKMARK_TRACK,           /**< Bookmark track command. */
    BLE_AMS_CMD_TOTAL                     /**< Total commands number. */
} ble_ams_cmd_t;

void app_ams_remote_cmd(ble_ams_cmd_t cmd);