拓展功能

更新时间:2024-11-20 02:13:24下载pdf

除了必要的基础功能外,蓝牙通用串口协议还提供了很多拓展功能,包括模组低功耗、MCU 固件 OTA 升级、产测、时间查询等多个实用功能。

本文展示的 功能协议示例 均由模组调试助手展示。推荐您使用 涂鸦模组调试助手 协助调试,可快速了解协议实现流程。

蓝牙低功耗

通过 MCU 给蓝牙模组发送低功耗配置,可以让模组进入低功耗状态。MCU 根据蓝牙通用串口协议配置模组参数,如修改广播间隔、关闭模组计时器等可以让模组的功耗进一步降低,满足电池类对功耗要求较高的产品使用需求。

功能介绍

在硬件设计时若不使用低功耗功能,只需接 TX、RX 两根引脚,即可完成基本的协议交互。若要使用低功耗模式,您还需要接上模组的低功耗控制脚。

拓展功能
  • 模组唤醒引脚:模组的低功耗状态唤醒引脚,需要 MCU 接上配合使用。使能模组低功耗,且将模组低功耗引脚拉低后,模组串口不再接收数据,但是蓝牙通信和串口下发仍然正常工作。引脚拉高后,模组串口接收正常使用。

    模组型号 模组低功耗控制引脚 低功耗对应的电平 非低功耗对应的电平
    BT3L-A1、BT3L、BT3L-A、BT3L-G、BT7L-G、BT7L、BT7L-IPEX、BT2S 模组丝印 TL_B5 引脚
    BT5S 模组丝印 TL_C3 引脚

    当模组从低功耗模式下唤醒时,需要延时 10 ms,模组串口才能接收到 MCU 数据。当模组处于深度睡眠模式,唤醒模组后,将重启模组,此时需要延时 600 ms,串口才能接受数据。

  • MCU 唤醒引脚:在低功耗模式下,当模组需要发送数据给 MCU 时,模组会改变 MCU 唤醒脚的电平 10 ms,然后再发送数据,发送完成后恢复默认电平。

    模组说明 模组唤醒 MCU 引脚 发数据时电平 空闲时电平
    BT3L-A1、BT3L、BT3L-A、BT3L-G、BT7L-G、BT7L、BT7L-IPEX、BT2S 模组丝印 TL_D2 引脚
    BT5S 模组丝印 TL_D2 引脚

    功能说明:唤醒脚各平台默认上下拉情况可能存在差异,MCU 端与模组唤醒脚对接的引脚不要使用悬空状态。部分模组不支持该功能,详情请参考 蓝牙通用串口协议低功耗说明章节

  • 每次连接后模组将自动查询App时间以校准蓝牙模组内部时间,Telink 模组没有使用外部 RTC,时钟精度不是很高,24 小时低于 1 分钟。如果您对时钟精度要求高,可以在 MCU 上外接 RTC 模块计时。
  • 当供电电压低于正常工作电压时,芯片内部 Flash 操作将有出错的风险,造成固件或者用户数据被异常修改。有两种方法可以避免:
    1. 当 MCU 检测到电池电压过低时,切断模组工作电源。
    2. 当 MCU 检测到电池电压过低时,可以关闭广播和系统计时,让芯片处于深度睡眠模式,从而不会工作。Telink 模组最低工作电压为 1.8V,MCU 可以设置在 2.0V (要略高于 1.8V) 关闭模组。

使用场景

对于功耗要求较高的蓝牙设备,比如电池供电,需要降低设备使用过程的功耗,以延长设备的使用时间。这种情况下就可以使用蓝牙低功耗方案。

通过 MCU 发送使能低功耗指令到模组,让模组进入低功耗状态,可大幅降低模组功耗,若需要将模组唤醒,只需要拉高模组唤醒引脚即可恢复通信。

相关指令说明

低功耗方案涉及多个协议指令:

  • 使能低功耗功能指令:命令字 0xE5
  • 修改低功耗模式下的广播间隔指令:命令字 0xE2
  • 关闭系统计时器指令:命令字 0xE4
  • 主动断开蓝牙连接指令:命令字 0xE7
  • 模组唤醒引脚配置指令:命令字 0xE3
  • MCU低功耗唤醒配置指令:命令字 0xB0
  • 蓝牙连接间隔设置指令:命令字 0xB1

指令详情介绍,请参考 蓝牙通用串口协议-低功耗功能附加协议

使能低功耗功能指令 0xE5

指令作用:MCU 发送该指令到模组,使能模组低功耗。

应用场景:模组出厂时为非低功耗模组,需要通过该指令使能低功耗功能,然后才能通过拉低低功耗引脚,使模组进入低功耗状态,该设置将永久储存。

  • 使能低功耗并不是让模组立即进入低功耗模式,模式具体使用哪种功耗模式运行取决于当前模组功耗控制管脚的高低电平。
  • 门锁类通用固件暂不支持(TYBN1 通用固件和 BK3431Q 通用固件)。

修改低功耗模式下的广播间隔指令 0xE2

指令作用:低功耗状态下,可通过该指令修改蓝牙广播间隔,进一步降低模组功耗。

应用场景:为降低休眠时的功耗,可以通过该指令修改广播间隔,广播参数将永久保存,当设置为 0 时,将关闭广播,该设置将永久存储。

  • 广播间隔可设置数值范围为 0 到 20,单位为 100ms,即实际广播间隔范围为 100ms 到 2 秒,当设置数值为 0 时将关闭广播。低功耗状态下广播间隔默认 1s,广播间隔越大连接所需要的时间越长,甚至某些性能差的手机可能很难连接上,不建议修改更大的广播间隔值。
  • BK3432 健康类通用固件暂不支持。

关闭系统计时器指令 0xE4

指令作用:MCU 发送该指令到模组,通知模组关闭内部计时器。

应用场景:为降低 Telink 芯片休眠时的功耗,可以通过该指令关闭蓝牙模组内部计时器功能,如果 MCU 不需要时间功能,可以关闭该功能,当计时功能和广播功能都关闭后,然后拉低模组唤醒脚,模组将进入深度睡眠,功耗降低至 3uA,唤醒后,模组重启运行,该设置将永久存储。

BK3431Q 和 TYBN1 中,由于单纯计时功耗比较低,主要耗电的是存储 Flash 操作,这里只是关闭了 Flash 存储操作。打开后,时钟可周期性(1min)存 Flash,可解决重启后模组 RTC 时钟时间重置的问题。(默认为关闭)

主动断开蓝牙连接指令 0xE7

指令作用:MCU 发送该指令到模组,通知模组主动断开蓝牙连接。

应用场景:为降低休眠时的功耗,MCU 在不需要蓝牙连接的时间,可以先断开模组蓝牙连接,再控制模组进入低功耗,以达到模组最低功耗状态。

低功耗与非低功耗状态下都可使用该指令主动断开蓝牙连接。

模组唤醒引脚配置指令 0xE3

指令作用:修改模组低功耗状态唤醒引脚

应用场景:主要用于芯片对接自定义模组低功耗唤醒引脚。需要使用非默认引脚外的引脚进行唤醒模组,建议在 MCU 初始化串口后立即通过该指令对模组低功耗唤醒引脚进行配置。该设置永久存储。

由于模组进入低功耗后串口不可上行,所以 MCU 需要在模组上电 1s 内(模组上电 1s 内不会进入低功耗)进行设置或者在开低功耗使能之前设置(模组默认是关低功耗使能的)。

目前该指令仅适用于 BK3432 固件。

MCU低功耗唤醒配置指令 0xB0

指令作用:MCU 可通过该指令设置 MCU 自身从低功耗唤醒所需的时间。

应用场景:该指令适用于 TYBN1 门锁通用固件 6.2 以上版本支持,BK3431Q 门锁通用固件 3.3 以上版本支持。该指令用于配置低功耗模式下模组向 MCU 发送数据时拉高 MCU 唤醒引脚的时间,默认 200ms,即模组要给 MCU 发送数据时,先把 MCU 唤醒脚拉高 200ms,再发送串口数据,发送数据完成后又将 MCU 唤醒脚拉低。

  • MCU 唤醒时间:该时间取值范围 1~20。即目前设定最小支持 10ms,最大支持 200ms。MCU 修改后需测试唤醒时间是否能正常唤醒 MCU,如果不能则需调大。如果对于该延迟时间不是特别在意,建议不设置,使用默认值。
  • 调用时机:建议在 MCU 收到请求模组工作模式指令 0x02 后,调用该接口设置 MCU 低功耗配置(该设置非永久存储,模组上电或者重启后恢复默认值 200ms)。

蓝牙连接间隔设置指令 0xB1

指令作用:MCU 向模组发送配置连接模式。

目前该指令仅适用于 BT2S、BT5S、BT3L、BT7L(Telink 825x 通用固件 8.10+ 版本支持)。

功能协议示例

  • 使能低功耗功能

    拓展功能

  • 修改低功耗模式下的广播间隔

    拓展功能

  • 关闭系统计时器

    拓展功能

  • 主动断开蓝牙连接

    拓展功能

MCU SDK 示例

使能低功耗函数说明

使能低功耗函数 bt_enable_lowpoer_req() 定义在 protocol.c 文件中,作用是 MCU 通过该指令使能模组低功耗。

应用步骤

  1. 打开 TUYA_BCI_UART_COMMON_ENANBLE_LOWER_POWER 宏定义,开启 MCU 使能低功耗功能。

  2. MCU 自行调用使能低功耗函数 bt_enable_lowpoer_req(),发送使能低功耗功能指令 0xE5 到模组,使能低功耗。

  3. 在串口接收数据处理函数 data_handle() 中,收到模组发送的低功耗使能结果通知,SDK 调用使能低功耗结果处理函数 bt_enable_lowpoer_result() 接收处理,该函数逻辑代码需要用户自行完成。

    #define TUYA_BCI_UART_COMMON_ENANBLE_LOWER_POWER	 0xE5	//Low power enable
    
    /*****************************************************************************
    Function name: bt_enable_lowpoer_req
    Function description: send a request to enable low power consumption to the module (currently only applicable to telink platform)
    Input parameters: value 0 off, 1 on
    Return parameter: none
    *****************************************************************************/
    void bt_enable_lowpoer_req(unsigned char value)
    {
    	unsigned short length = 0;
    	length = set_bt_uart_byte(length,value);
    	bt_uart_write_frame(TUYA_BCI_UART_COMMON_ENANBLE_LOWER_POWER,length);
    }
    
    void data_handle(unsigned short offset)
    {
    	......
    	#ifdef TUYA_BCI_UART_COMMON_ENANBLE_LOWER_POWER
    	case TUYA_BCI_UART_COMMON_ENANBLE_LOWER_POWER:
    		bt_enable_lowpoer_result(bt_uart_rx_buf[offset + DATA_START]);
    		break;
    	#endif
    	......
    }
    
    /*****************************************************************************
    Function name: bt_enable_lowpoer_result
    Function description: processing result
    Input parameters: 0 successful, other failed
    
    Return parameter: none
    Instructions: MCU needs to improve the function on its own.
    *****************************************************************************/
    void bt_enable_lowpoer_result(unsigned char result)
    {
    	#error "Please improve the function by yourself and delete the line after completion"
    	if(result == 0x00)
    	{
    		//success
    	}
    	else
    	{
    		//failed
    	}
    }
    

修改广播间隔函数说明

修改广播间隔函数 bt_modify_adv_interval_req() 定义在 protocol.c 文件中,作用是 MCU 通过该指令修改模组低功耗模式下的广播间隔。

应用步骤

  1. 打开 TUYA_BCI_UART_COMMON_MODIFY_ADV_INTERVAL 宏定义,开启 MCU 修改广播间隔功能。

  2. MCU自行调用修改广播间隔函数 bt_modify_adv_interval_req(),配置广播间隔后发送使能低功耗功能指令 0xE2 到模组,修改低功耗模式下的广播间隔。

  3. 在串口接收数据处理函数 data_handle() 中,收到模组发送的低功耗模式下的广播间隔修改结果通知,SDK 调用修改广播间隔结果处理函数 bt_modify_adv_interval_result() 接收处理,该函数逻辑代码需要用户自行完成。

    #define TUYA_BCI_UART_COMMON_MODIFY_ADV_INTERVAL 0xE2//Modify the sleep mode broadcast interval
    
    /*****************************************************************************
    Function name: bt_modify_adv_interval_req
    Function description: send a request to the module to modify the broadcast interval of the module at low power consumption
    Input parameter: value * 100ms equals the broadcast interval, value (0-20 to be modified)
    Return parameter: none
    Instructions for use:
    *****************************************************************************/
    void bt_modify_adv_interval_req(unsigned char value)
    {
    	unsigned short length = 0;
    	length = set_bt_uart_byte(length,value);
    	bt_uart_write_frame(TUYA_BCI_UART_COMMON_MODIFY_ADV_INTERVAL,length);
    }
    
    void data_handle(unsigned short offset)
    {
    	......
    	#ifdef TUYA_BCI_UART_COMMON_MODIFY_ADV_INTERVAL
    	case TUYA_BCI_UART_COMMON_MODIFY_ADV_INTERVAL:
    		bt_modify_adv_interval_result(bt_uart_rx_buf[offset + DATA_START]);
    		break;
    	#endif
    	......
    }
    
    /*****************************************************************************
    Function name: bt_modify_adv_interval_result
    Function description:Processing the result of modifying the broadcast interval
    Input parameters: result synchronization result 0 successful, other failed
    Return parameter: none
    Instructions: MCU needs to improve the function on its own.
    *****************************************************************************/
    void bt_modify_adv_interval_result(unsigned char result)
    {
    	#error "Please improve the function by yourself and delete the line after completion"
    	if(result == 0x00)
    	{
    		//success
    	}
    	else
    	{
    		//failed
    	}
    }
    

关闭系统计时器函数说明

关闭系统计时器函数 bt_close_timer_req() 定义在 protocol.c 文件中,作用是 MCU 通过该指令使能模组低功耗。

应用步骤

  1. 打开 TUYA_BCI_UART_COMMON_TURNOFF_SYSTEM_TIME 宏定义,开启 MCU 关闭模组计时器功能。

  2. MCU 自行调用关闭系统计时器函数 bt_close_timer_req(),发送使能低功耗功能指令 0xE4 到模组,关闭模组计时器。

  3. 在串口接收数据处理函数 data_handle() 中,收到模组发送的关闭计时器结果通知,SDK 调用关闭计时器结果处理函数 bt_close_timer_result() 接收处理,该函数逻辑代码需要用户自行完成。

    #define TUYA_BCI_UART_COMMON_TURNOFF_SYSTEM_TIME 0xE4//Turn off the system clock function
    
    /*****************************************************************************
    Function name: bt_close_timer_req
    Function description: send a request to the module to turn off the system clock (currently available on telink platform only)
    Input parameters: value 0 off, 1 on
    Return parameter: none
    Instructions for use:
    *****************************************************************************/
    void bt_close_timer_req(unsigned char value)
    {
    	unsigned short length = 0;
    	length = set_bt_uart_byte(length,value);
    	bt_uart_write_frame(TUYA_BCI_UART_COMMON_TURNOFF_SYSTEM_TIME,length);
    }
    
    void data_handle(unsigned short offset)
    {
    	......
    	#ifdef TUYA_BCI_UART_COMMON_TURNOFF_SYSTEM_TIME
    	case TUYA_BCI_UART_COMMON_TURNOFF_SYSTEM_TIME:
    	bt_close_timer_result(bt_uart_rx_buf[offset + DATA_START]);
    	break;
    	#endif
    	......
    }
    
    /*****************************************************************************
    Function name: bt_close_timer_result
    Function description: processing result
    Input parameters: 0 successful, other failed
    Return parameter: none
    Instructions: MCU needs to improve the function on its own.
    *****************************************************************************/
    void bt_close_timer_result(unsigned char result)
    {
    	#error "Please improve the function by yourself and delete the line after completion"
    	if(result == 0x00)
    	{
    		//success
    	}
    	else
    	{
    		//failed
    	}
    }
    

主动断开蓝牙函数说明

主动断开蓝牙函数 bt_enable_lowpoer_req() 定义在 protocol.c 文件中,作用是 MCU 通过该指令主动断开蓝牙连接。

应用步骤

  1. 打开 TUYA_BCI_UART_COMMON_ACTIVE_DISCONNECT 宏定义,开启 MCU 主动断开蓝牙连接功能。

  2. MCU 自行调用主动断开蓝牙函数 bt_disconnect_req(),发送主动断开蓝牙指令 0xE7 到模组,主动断开蓝牙连接。

  3. 在串口接收数据处理函数 data_handle() 中,收到模组发送的主动断开蓝牙结果通知,SDK 调用主动断开蓝牙结果处理函数 bt_disconnect_result() 接收处理,该函数逻辑代码需要用户自行完成。

    #define TUYA_BCI_UART_COMMON_ACTIVE_DISCONNECT 0xE7 //Disconnect device Bluetooth connection
    
    /*****************************************************************************
    Function name: bt_disconnect_req
    Function description: send a request to disconnect the Bluetooth connection to the module
    Input parameters: value 0 off, 1 on
    Return parameter: none
    Instructions for use:
    *****************************************************************************/
    void bt_disconnect_req(void)
    {
    	bt_uart_write_frame(TUYA_BCI_UART_COMMON_ACTIVE_DISCONNECT,0);
    }
    
    void data_handle(unsigned short offset)
    {
    	......
    	#ifdef TUYA_BCI_UART_COMMON_ACTIVE_DISCONNECT
    	case TUYA_BCI_UART_COMMON_ACTIVE_DISCONNECT:
    		bt_disconnect_result(bt_uart_rx_buf[offset + DATA_START]);
    		break;
    	#endif
    	......
    }
    
    /*****************************************************************************
    Function name: bt_disconnect_result
    Function description: receive the result that the module is disconnected from Bluetooth
    Input parameters: result result 0 successful, other failed
    
    Return parameter: none
    Instructions: MCU needs to improve the function on its own.
    *****************************************************************************/
    void bt_disconnect_result(unsigned char result)
    {
    	#error "Please improve the function by yourself and delete the line after completion"
    	if(result == 0x00)
    	{
    		//success
    	}
    	else
    	{
    		//failed
    	}
    }
    

固件 OTA 升级

OTA(Over-the-Air)即空中下载技术,通过网络远程为设备更新和升级软件程序。

功能介绍

蓝牙通用串口协议支持 MCU OTA 功能,通过涂鸦开发者平台,先将需要更新的固件文件上传至涂鸦,然后通过蓝牙网关或手机 App(如涂鸦智能)等载体下载固件并透传给蓝牙模组。蓝牙模组再通过涂鸦协议对文件进行分包传输,最后 MCU 接收升级包并写入本地闪存,最终实现固件的升级。

详细说明请参考 OTA 升级说明

OTA流程图

MCU OTA 功能需要设备 MCU 资源支持,设备配网成功后,通过平台配置或升级检测,可以启动 OTA 流程,升级流程如下:

拓展功能

使用场景

设备不论是在调试阶段还是出厂阶段,都可以使用 MCU OTA 功能进行 MCU 固件的更新迭代,实现设备功能的优化升级。在 MCU 硬件资源支持的情况下,建议增加 OTA 功能。

固件管理:使用 MCU OTA 功能需要先将验证正确的 MCU 固件上传到涂鸦,固件上传及管理操作,请参考 固件管理

  • 根据是否移植涂鸦协议的 MCU SDK 分为移植 SDK 和自行对接,这两种方式,都需要自行完成 BootLoader 开发。

    • 移植 SDK:使用 MCU SDK 提供的函数,回复固件分包传输大小启动升级过程,并接收模组发送的固件包,接收到的固件包需要 MCU 自行处理,可参考下文 SDK 示例介绍。
    • 自行对接:需要自行实现 OTA 功能相关协议指令,完成固件传输配置及固件包接收处理
  • 设备需要先完成协议基础功能对接,MCU RAM 建议大于 512 Byte。

相关指令说明

OTA 流程涉及多个协议指令:

  • MCU OTA 升级请求指令:命令字 0xEA
  • MCU OTA 升级文件信息指令:命令字 0xEB
  • MCU OTA 升级文件偏移请求指令:命令字 0xEC
  • MCU OTA 升级数据指令:命令字 0xED
  • MCU OTA 升级结束指令:命令字 0xEE

MCU OTA 升级请求指令 0xEA

指令作用:模组发送该指令到 MCU,查询 MCU 串口能传输的最大单包长度。

应用场景:启动 OTA 升级后,模组首先会使用 0xEA 指令向 MCU 确认传输升级包分包大小。

指令详细介绍,请参考 蓝牙通用串口协议-MCU OTA 升级请求

MCU OTA 升级文件信息指令 0xEB

指令作用:模组通过该指令发送升级文件信息到 MCU,包括产品 PID、文件版本、文件 MD5、文件长度及 CRC32。MCU 查询后可比较升级信息决定是否升级。

应用场景:启动 OTA 升级后,模组首先会使用 0xEA 指令向 MCU 确认传输升级包分包大小,确认后模组会使用 0xEB 指令向 MCU 发送升级文件信息,MCU 收到后可比较升级信息决定是否升级。

MCU OTA 升级文件偏移请求指令 0xEC

指令作用:模组和 MCU 协商文件起始传输偏移量。

应用场景:在 MCU 回复模组发送的升级文件信息确认指令 0xEB,确认升级后,模组发送升级文件偏移请求指令到 MCU,与 MCU 协商文件传输的偏移地址。

MCU OTA 升级数据指令 0xED

指令作用:模组通过该指令将升级包分包传输给 MCU。

应用场景:模组与 MCU 协商完文件传输的偏移地址后,模组通过升级数据指令给 MCU 传输升级包分包。

指令详细介绍,请参考 蓝牙通用串口协议-MCU OTA 升级数据

MCU OTA 升级结束指令 0xEE

指令作用:OTA 结束时,模组向 MCU 确认升级结果。

应用场景:模组给 MCU 传输完升级包分包后,发送升级结束指令到 MCU 确认本次升级结果。

指令详细介绍,请参考 蓝牙通用串口协议-MCU OTA 升级结束

功能协议示例

拓展功能

拓展功能

拓展功能

MCU SDK 示例

升级请求回复函数说明

升级请求回复函数mcu_ota_start_req() 定义在 mcu_ota_handler.c 文件中,作用是回复模组发送的升级请求,商定升级最大单包长度。

应用步骤

  1. 打开 SUPPORT_MCU_FIRM_UPDATE 宏定义,开启 MCU 固件升级功能。

  2. 在串口接收数据处理函数 data_handle() 中,收到模组发送的最大单包数据请求升级,SDK 调用 OTA 处理函数 mcu_ota_proc() 接收处理。

  3. OTA 处理函数 mcu_ota_proc() 判断是升级请求指令,调用升级请求回复函数 mcu_ota_start_req() 发送升级标志位、MCU 当前固件版本号和 MCU 可接受的最大单包长度。

    #define         SUPPORT_MCU_FIRM_UPDATE         //Enable MCU firmware upgrade (default)
    /*  Firmware package size selection  */
    #ifndef SUPPORT_MCU_FIRM_UPDATE
    #define BT_UART_QUEUE_LMT             16              //The size of the data receiving queue can be reduced if the RAM of MCU is not enough.
    #define BT_UART_RECV_BUF_LMT          128              //According to the size of the user's DP data, it must be greater than 32
    #else
    #define BT_UART_QUEUE_LMT             512             //The size of the data receiving queue can be reduced if the RAM of MCU is not enough.
    #define BT_UART_RECV_BUF_LMT          256             //Firmware upgrade buffer, large cache required, must be greater than 260
    #endif
    
    void data_handle(unsigned short offset)
    {
    	......
    	#ifdef SUPPORT_MCU_FIRM_UPDATE
    	case TUYA_BCI_UART_COMMON_MCU_OTA_REQUEST:
    	case TUYA_BCI_UART_COMMON_MCU_OTA_FILE_INFO:
    	case TUYA_BCI_UART_COMMON_MCU_OTA_FILE_OFFSET:
    	case TUYA_BCI_UART_COMMON_MCU_OTA_DATA:
    	case TUYA_BCI_UART_COMMON_MCU_OTA_END:
    		total_len = bt_uart_rx_buf[offset + LENGTH_HIGH] * 0x100;
    		total_len += bt_uart_rx_buf[offset + LENGTH_LOW];
    		mcu_ota_proc(cmd_type,&bt_uart_rx_buf[offset + DATA_START],total_len);
    		break;
    	#endif
    	......
    }
    
    void mcu_ota_proc(uint16_t cmd,uint8_t*recv_data,uint32_t recv_len)
    {
    ......
    	case TUYA_BCI_UART_COMMON_MCU_OTA_REQUEST:
    		mcu_ota_start_req(recv_data,recv_len);
    		break;
    ......
    }
    
    static void mcu_ota_start_req(uint8_t*recv_data,uint32_t recv_len)
    {
    	uint8_t p_buf[12];
    	uint8_t payload_len = 0;
    	uint32_t current_version = MCU_OTA_VERSION;
    	uint16_t length = 0;
    
    	if(mcu_ota_status_get()!=MCU_OTA_STATUS_NONE)
    	{
    		TUYA_OTA_LOG("current ota status is not MCU_OTA_STATUS_NONE  and is : %d !",mcu_ota_status_get());
    		return;
    	}
    	p_buf[0] = MCU_OTA_TYPE;
    	p_buf[1] = (current_version>>16)&0xff;
    	p_buf[2] = (current_version>>8)&0xff;
    	p_buf[3] = current_version&0xff;
    	p_buf[4] = MAX_DFU_DATA_LEN>>8;
    	p_buf[5] = MAX_DFU_DATA_LEN;
    
    	mcu_ota_status_set(MCU_OTA_STATUS_START);
    	payload_len = 6;
    	length = set_bt_uart_buffer(length,(unsigned char *)p_buf,payload_len);
    	bt_uart_write_frame(TUYA_BCI_UART_COMMON_MCU_OTA_REQUEST,length);
    }
    

升级文件信息确认函数说明

升级文件信息确认函数 mcu_ota_file_info_req() 定义在 mcu_ota_handler.c 文件中,作用是回复模组发送的升级文件信息指令 0xEB,确认当前升级状态及升级文件信息。

应用步骤

  1. 打开 SUPPORT_MCU_FIRM_UPDATE 宏定义,开启 MCU 固件升级功能。

  2. 在串口接收数据处理函数 data_handle() 中,收到模组发送的升级文件信息,SDK 调用OTA处理函数 mcu_ota_proc() 接收处理。

  3. OTA 处理函数 mcu_ota_proc() 判断是升级文件信息指令 0xEB,调用升级文件信息确认函数 mcu_ota_file_info_req() 发送当前升级状态和升级文件信息。

    void data_handle(unsigned short offset)
    {
    	......
    	#ifdef SUPPORT_MCU_FIRM_UPDATE
    	case TUYA_BCI_UART_COMMON_MCU_OTA_REQUEST:
    	case TUYA_BCI_UART_COMMON_MCU_OTA_FILE_INFO:
    	case TUYA_BCI_UART_COMMON_MCU_OTA_FILE_OFFSET:
    	case TUYA_BCI_UART_COMMON_MCU_OTA_DATA:
    	case TUYA_BCI_UART_COMMON_MCU_OTA_END:
    		total_len = bt_uart_rx_buf[offset + LENGTH_HIGH] * 0x100;
    		total_len += bt_uart_rx_buf[offset + LENGTH_LOW];
    		mcu_ota_proc(cmd_type,&bt_uart_rx_buf[offset + DATA_START],total_len);
    		break;
    	#endif
    	......
    }
    
    void mcu_ota_proc(uint16_t cmd,uint8_t*recv_data,uint32_t recv_len)
    {
    ......
    case TUYA_BCI_UART_COMMON_MCU_OTA_FILE_INFO:
    		mcu_ota_file_info_req(recv_data,recv_len);
    		break;
    ......
    }
    
    static void mcu_ota_file_info_req(uint8_t*recv_data,uint32_t recv_len)
    {
    	uint8_t p_buf[30];
    	uint8_t payload_len = 0;
    	uint32_t file_version;
    	uint32_t file_length;
    	uint32_t file_crc;
    	uint8_t file_md5;
    	// uint8_t file_md5[16];
    	uint16_t length = 0;
    	uint8_t state;
    
    	if(mcu_ota_status_get()!=MCU_OTA_STATUS_START)
    	{
    		TUYA_OTA_LOG("current ota status is not MCU_OTA_STATUS_START  and is : %d !",mcu_ota_status_get());
    		return;
    	}
    	file_version = recv_data[0+8]<<16;
    	file_version += recv_data[1+8]<<8;
    	file_version += recv_data[2+8];
    	if(memcmp(s_dfu_settings.progress.firmware_file_md5,&recv_data[3+8],16)==0)
    	{
    		file_md5 = TRUE;
    	}
    	else
    	{
    		file_md5 = FALSE;
    	}
    	file_length = recv_data[27]<<24;
    	file_length += recv_data[28]<<16;
    	file_length += recv_data[29]<<8;
    	file_length += recv_data[30];
    	file_crc = recv_data[31]<<24;
    	file_crc += recv_data[32]<<16;
    	file_crc += recv_data[33]<<8;
    	file_crc += recv_data[34];
    	if (memcmp(&recv_data[0], PRODUCT_KEY, 8) == 0)
    	{
    		if((file_version > MCU_OTA_VERSION)&&(file_length <= APP_NEW_FW_MAX_SIZE))
    		{
    			if(file_md5&&(s_dfu_settings.progress.firmware_file_version==file_version)&&(s_dfu_settings.progress.firmware_file_length==file_length)
    					&&(s_dfu_settings.progress.firmware_file_crc==file_crc))
    			{
    				state = 0;
    			}
    			else
    			{
    				memset(&s_dfu_settings.progress, 0, sizeof(dfu_progress_t));
    				s_dfu_settings.progress.firmware_image_crc_last = 0;
    				s_dfu_settings.progress.firmware_file_version = file_version;
    				s_dfu_settings.progress.firmware_file_length = file_length;
    				s_dfu_settings.progress.firmware_file_crc = file_crc;
    				memcpy(s_dfu_settings.progress.firmware_file_md5,&recv_data[3+8],16);
    				s_dfu_settings.write_offset = s_dfu_settings.progress.firmware_image_offset_last;
    				state = 0;
    				mcu_flash_write(DFU_SETTING_SAVE_ADDR,(uint8_t*)&s_dfu_settings,sizeof(s_dfu_settings));
    			}
    			m_firmware_start_addr = APP_NEW_FW_START_ADR;
    			m_firmware_size_req = s_dfu_settings.progress.firmware_file_length;
    		}
    		else
    		{
    			if(file_version <= MCU_OTA_VERSION)
    			{
    				TUYA_OTA_LOG("ota file version error !");
    				state = 2;
    			}
    			else
    			{
    				TUYA_OTA_LOG("ota file length is bigger than rev space !");
    				state = 3;
    			}
    		}
    	}
    	else
    	{
    		TUYA_OTA_LOG("ota pid error !");
    		state = 1;
    	}
    	memset(p_buf,0,sizeof(p_buf));
    	p_buf[0] = state;
    	if(state==0)
    	{
    		uint32_t crc_temp  = 0; if(file_crc_check_in_flash(s_dfu_settings.progress.firmware_image_offset_last,&crc_temp)==0)
    		{
    			if(crc_temp != s_dfu_settings.progress.firmware_image_crc_last)
    			{
    				s_dfu_settings.progress.firmware_image_offset_last = 0;
    				s_dfu_settings.progress.firmware_image_crc_last = 0;
    				s_dfu_settings.write_offset = s_dfu_settings.progress.firmware_image_offset_last;
    				mcu_flash_write(DFU_SETTING_SAVE_ADDR,(uint8_t*)&s_dfu_settings,sizeof(s_dfu_settings));
    			}
    		}
    		p_buf[1] = s_dfu_settings.progress.firmware_image_offset_last>>24;
    		p_buf[2] = s_dfu_settings.progress.firmware_image_offset_last>>16;
    		p_buf[3] = s_dfu_settings.progress.firmware_image_offset_last>>8;
    		p_buf[4] = (uint8_t)s_dfu_settings.progress.firmware_image_offset_last;
    		p_buf[5] = s_dfu_settings.progress.firmware_image_crc_last>>24;
    		p_buf[6] = s_dfu_settings.progress.firmware_image_crc_last>>16;
    		p_buf[7] = s_dfu_settings.progress.firmware_image_crc_last>>8;
    		p_buf[8] = (uint8_t)s_dfu_settings.progress.firmware_image_crc_last;
    		mcu_ota_status_set(MCU_OTA_STATUS_FILE_INFO);
    		current_package = 0;
    		last_package = 0;
    
    		TUYA_OTA_LOG("ota file length  : 0x%04x",s_dfu_settings.progress.firmware_file_length);
    		TUYA_OTA_LOG("ota file  crc    : 0x%04x",s_dfu_settings.progress.firmware_file_crc);
    		TUYA_OTA_LOG("ota file version : 0x%04x",s_dfu_settings.progress.firmware_file_version);
    		TUYA_OTA_LOG("ota firmware_image_offset_last : 0x%04x",s_dfu_settings.progress.firmware_image_offset_last);
    		TUYA_OTA_LOG("ota firmware_image_crc_last    : 0x%04x",s_dfu_settings.progress.firmware_image_crc_last);
    		TUYA_OTA_LOG("ota firmware   write offset    : 0x%04x",s_dfu_settings.write_offset);
    	}
    	payload_len = 25;
    	length = set_bt_uart_buffer(length,(unsigned char *)p_buf,payload_len);
    	bt_uart_write_frame(TUYA_BCI_UART_COMMON_MCU_OTA_FILE_INFO,length);
    }
    

升级文件偏移函数说明

升级请求回复函数 mcu_ota_offset_req() 定义在 mcu_ota_handler.c 文件中,作用是回复模组发送的升级文件偏移请求,商定起始传输文件偏移量。

应用步骤

  1. 打开 SUPPORT_MCU_FIRM_UPDATE 宏定义,开启 MCU 固件升级功能。

  2. 在串口接收数据处理函数 data_handle() 中,收到模组发送的升级文件偏移请求,SDK 调用 OTA 处理函数 mcu_ota_proc() 接收处理。

  3. OTA 处理函数 mcu_ota_proc() 判断是升级文件偏移请求指令 0xEC,调用升级文件偏移函数 mcu_ota_offset_req() 发送 MCU 要求的起始传输文件偏移量。

    void data_handle(unsigned short offset)
    {
    	......
    	#ifdef SUPPORT_MCU_FIRM_UPDATE
    	case TUYA_BCI_UART_COMMON_MCU_OTA_REQUEST:
    	case TUYA_BCI_UART_COMMON_MCU_OTA_FILE_INFO:
    	case TUYA_BCI_UART_COMMON_MCU_OTA_FILE_OFFSET:
    	case TUYA_BCI_UART_COMMON_MCU_OTA_DATA:
    	case TUYA_BCI_UART_COMMON_MCU_OTA_END:
    		total_len = bt_uart_rx_buf[offset + LENGTH_HIGH] * 0x100;
    		total_len += bt_uart_rx_buf[offset + LENGTH_LOW];
    		mcu_ota_proc(cmd_type,&bt_uart_rx_buf[offset + DATA_START],total_len);
    		break;
    	#endif
    	......
    }
    
    void mcu_ota_proc(uint16_t cmd,uint8_t*recv_data,uint32_t recv_len)
    {
    ......
    	case TUYA_BCI_UART_COMMON_MCU_OTA_FILE_OFFSET:
    		mcu_ota_offset_req(recv_data,recv_len);
    		break;
    ......
    }
    
    static void mcu_ota_offset_req(uint8_t*recv_data,uint32_t recv_len)
    {
    	uint8_t p_buf[5];
    	uint8_t payload_len = 0;
    	uint32_t offset;
    	uint16_t length = 0;
    
    	if(mcu_ota_status_get()!=MCU_OTA_STATUS_FILE_INFO)
    	{
    		TUYA_OTA_LOG("current ota status is not MCU_OTA_STATUS_FILE_INFO  and is : %d !",mcu_ota_status_get());
    		return;
    	}
    
    	offset  = recv_data[0]<<24;
    	offset += recv_data[1]<<16;
    	offset += recv_data[2]<<8;
    	offset += recv_data[3];
    
    	if((offset==0)&&(s_dfu_settings.progress.firmware_image_offset_last!=0))
    	{
    		s_dfu_settings.progress.firmware_image_crc_last = 0;
    		s_dfu_settings.progress.firmware_image_offset_last = 0;
    		s_dfu_settings.write_offset = s_dfu_settings.progress.firmware_image_offset_last;
    		mcu_flash_write(DFU_SETTING_SAVE_ADDR,(uint8_t*)&s_dfu_settings,sizeof(s_dfu_settings));
    	}
    	p_buf[0] = s_dfu_settings.progress.firmware_image_offset_last>>24;
    	p_buf[1] = s_dfu_settings.progress.firmware_image_offset_last>>16;
    	p_buf[2] = s_dfu_settings.progress.firmware_image_offset_last>>8;
    	p_buf[3] = (uint8_t)s_dfu_settings.progress.firmware_image_offset_last;
    	mcu_ota_status_set(MCU_OTA_STATUS_FILE_OFFSET);
    	payload_len = 4;
    	length = set_bt_uart_buffer(length,(unsigned char *)p_buf,payload_len);
    	bt_uart_write_frame(TUYA_BCI_UART_COMMON_MCU_OTA_FILE_OFFSET,length);
    }
    

升级数据处理函数说明

升级数据处理函数 mcu_ota_data_req() 定义在 mcu_ota_handler.c 文件中,作用是回复模组发送的升级请求,商定升级最大单包长度。

应用步骤

  1. 打开 SUPPORT_MCU_FIRM_UPDATE 宏定义,开启 MCU 固件升级功能。

  2. 在串口接收数据处理函数 data_handle() 中,收到模组发送的OTA升级传输数据包,SDK 调用 OTA 处理函数 mcu_ota_proc() 接收处理。

  3. OTA 处理函数 mcu_ota_proc() 判断是升级数据指令 0xED,调用升级数据处理函数 mcu_ota_data_req() 回复数据包接收情况。

    void data_handle(unsigned short offset)
    {
    	......
    	#ifdef SUPPORT_MCU_FIRM_UPDATE
    	case TUYA_BCI_UART_COMMON_MCU_OTA_REQUEST:
    	case TUYA_BCI_UART_COMMON_MCU_OTA_FILE_INFO:
    	case TUYA_BCI_UART_COMMON_MCU_OTA_FILE_OFFSET:
    	case TUYA_BCI_UART_COMMON_MCU_OTA_DATA:
    	case TUYA_BCI_UART_COMMON_MCU_OTA_END:
    		total_len = bt_uart_rx_buf[offset + LENGTH_HIGH] * 0x100;
    		total_len += bt_uart_rx_buf[offset + LENGTH_LOW];
    		mcu_ota_proc(cmd_type,&bt_uart_rx_buf[offset + DATA_START],total_len);
    		break;
    	#endif
    	......
    }
    
    void mcu_ota_proc(uint16_t cmd,uint8_t*recv_data,uint32_t recv_len)
    {
    ......
    case TUYA_BCI_UART_COMMON_MCU_OTA_DATA:
    		mcu_ota_data_req(recv_data,recv_len);
    		break;
    ......
    }
    
    static void mcu_ota_data_req(uint8_t*recv_data,uint32_t recv_len)
    {
    	TUYA_OTA_LOG("%s",__func__);
    	uint8_t p_buf[2];
    	uint8_t payload_len = 0;
    	uint8_t state = 0;
    	uint16_t len;
    	uint8_t p_balloc_buf[256];
    	uint16_t length = 0;
    
    	if((mcu_ota_status_get()!=MCU_OTA_STATUS_FILE_OFFSET)&&(mcu_ota_status_get()!=MCU_OTA_STATUS_FILE_DATA))
    	{
    		TUYA_OTA_LOG("current ota status is not MCU_OTA_STATUS_FILE_OFFSET  or MCU_OTA_STATUS_FILE_DATA and is : %d !",mcu_ota_status_get());
    		return;
    	}
    	state = 0;
    	current_package = (recv_data[0]<<8)|recv_data[1];
    	len = (recv_data[2]<<8)|recv_data[3];
    
    	if((current_package!=(last_package+1))&&(current_package!=0))
    	{
    		TUYA_OTA_LOG("ota received package number error.received package number : %d",current_package);
    		state = 1;
    	}
    	else  if(len>MAX_DFU_DATA_LEN)
    	{
    		TUYA_OTA_LOG("ota received package data length error : %d",len);
    		state = 5;
    	}
    	else
    	{
    		uint32_t const write_addr = APP_NEW_FW_START_ADR +  s_dfu_settings.write_offset;
    		if(write_addr>=APP_NEW_FW_END_ADR)
    		{
    			TUYA_OTA_LOG("ota write addr error.");
    			state = 1;
    		}
    		if(write_addr%CODE_PAGE_SIZE==0)
    		{
    			if (mcu_flash_erase(write_addr,4096)!= 0)
    			{
    				TUYA_OTA_LOG("ota Erase page operation failed");
    				state = 4;
    			}
    		}
    		if(state==0)
    		{
    			len = (recv_data[2]<<8)|recv_data[3];
    			memcpy(p_balloc_buf, &recv_data[6], len);
    			uint8_t ret = mcu_flash_write(write_addr, p_balloc_buf, len);
    			TUYA_OTA_LOG("ota save len :%d",len);
    
    			if (ret != 0)
    			{
    				state = 4;
    			}
    			else
    			{
    				s_dfu_settings.progress.firmware_image_crc_last = crc32_compute(p_balloc_buf, len, &s_dfu_settings.progress.firmware_image_crc_last);
    				s_dfu_settings.write_offset    += len;
    				s_dfu_settings.progress.firmware_image_offset_last += len;
    
    				if((current_package+1)%32==0)
    				{
    					mcu_flash_write(DFU_SETTING_SAVE_ADDR,(uint8_t*)&s_dfu_settings,sizeof(s_dfu_settings));
    				}
    			}
    		}
    	}
    	p_buf[0] = state;
    	mcu_ota_status_set(MCU_OTA_STATUS_FILE_DATA);
    	payload_len = 1;
    	length = set_bt_uart_buffer(length,(unsigned char *)p_buf,payload_len);
    	bt_uart_write_frame(TUYA_BCI_UART_COMMON_MCU_OTA_DATA,length);
    
    	if(state!=0)
    	{
    		TUYA_OTA_LOG("ota error so free!");
    		mcu_ota_status_set(MCU_OTA_STATUS_NONE);
    		mcu_ota_init_disconnect();
    		memset(&s_dfu_settings, 0, sizeof(dfu_settings_t));
    		mcu_flash_write(DFU_SETTING_SAVE_ADDR,(uint8_t*)&s_dfu_settings,sizeof(s_dfu_settings));
    	}
    	else
    	{
    		last_package = current_package;
    	}
    }
    

升级结束处理函数说明

升级结束处理函数 mcu_ota_end_req() 定义在 mcu_ota_handler.c 文件中,作用是回复模组发送的升级结束通知。

应用步骤

  1. 打开 SUPPORT_MCU_FIRM_UPDATE 宏定义,开启 MCU 固件升级功能。

  2. 在串口接收数据处理函数 data_handle() 中,收到模组发送的升级结束通知,SDK 调用 OTA 处理函数 mcu_ota_proc() 接收处理。

  3. OTA 处理函数 mcu_ota_proc() 判断是升级结束指令 0xEE,调用升级结束处理函数 mcu_ota_end_req() 回复升级完成的结果。

    void data_handle(unsigned short offset)
    {
    	......
    	#ifdef SUPPORT_MCU_FIRM_UPDATE
    	case TUYA_BCI_UART_COMMON_MCU_OTA_REQUEST:
    	case TUYA_BCI_UART_COMMON_MCU_OTA_FILE_INFO:
    	case TUYA_BCI_UART_COMMON_MCU_OTA_FILE_OFFSET:
    	case TUYA_BCI_UART_COMMON_MCU_OTA_DATA:
    	case TUYA_BCI_UART_COMMON_MCU_OTA_END:
    		total_len = bt_uart_rx_buf[offset + LENGTH_HIGH] * 0x100;
    		total_len += bt_uart_rx_buf[offset + LENGTH_LOW];
    		mcu_ota_proc(cmd_type,&bt_uart_rx_buf[offset + DATA_START],total_len);
    		break;
    	#endif
    	......
    }
    
    void mcu_ota_proc(uint16_t cmd,uint8_t*recv_data,uint32_t recv_len)
    {
    ......
    case TUYA_BCI_UART_COMMON_MCU_OTA_END:
    		mcu_ota_end_req(recv_data,recv_len);
    		break;
    ......
    }
    
    static void mcu_ota_end_req(uint8_t*recv_data,uint32_t recv_len)
    {
    	if(mcu_ota_status_get()==MCU_OTA_STATUS_NONE)
    	{
    		TUYA_OTA_LOG("current ota status is MCU_OTA_STATUS_NONE!");
    		return;
    	}
    	on_data_write_request_sched(NULL);
    }
    

设备产测

功能介绍

蓝牙通用串口协议提供了 RF 射频测试功能。

使用场景

设备完成基础功能后,若需要对模组进行 RF 射频测试,或者把模组产测结合到整机产测中,可使用模组的 RF 射频测试功能,触发测试的方式可由 MCU 端自定义。

相关指令说明

RF 射频测试指令 0x0E

蓝牙产测功能是指 MCU 发起产测,模组内部扫描指定的蓝牙信标: ty_mdev,若扫描成功,返回信号强度。

应用场景:准备一个蓝牙信标,释放信标信号:ty_mdev。测试时建议将路由与设备距离控制在较近(0.5米左右),然后通过串口发送该RF射频测试指令,模组会搜索蓝牙信标并返回信号强度值,一般信号强度大于 -70db 认为模组射频工作正常。

一些特殊芯片/模组,目前只有 BK3431Q、BK3432,这类模组不支持扫描信标的方式,测试 RSSI 需要使用以下工具:

  • 测试工具:
    • 由涂鸦提供的蓝牙适配器(Dongle)
    • 作用:连接被测设备并返回 RSSI。
  • 测试步骤:首先将 Dongle 放在距离模组较近(0.5米左右) 的地方。然后通过串口向模组发送该 RF 射频测试指令,Dongle 会连接模组并返回信号强度值,一般信号强度大于 -70db 认为模组射频工作正常。

功能协议示例

RF 射频测试

拓展功能

MCU SDK 示例

RF 射频测试函数说明

RF 射频测试函数 bt_rf_test_req() 定义在 protocol.c 文件中,作用是发送 RF 射频测试指令 0x0E 到模组,启动 RF 射频测试。

应用步骤

  1. 打开 TUYA_BCI_UART_COMMON_RF_TEST 宏定义,开启 RF 射频测试功能。

  2. MCU 自行调用 bt_rf_test_req() 函数,发送RF射频测试指令 0x0E 到模组,启动 RF 射频测试。

  3. 在串口接收数据处理函数 data_handle() 中,当收到模组发来的产测结果时,MCU 主动调用测试结果处理函数 bt_rf_test_result() 接收并做下一步处理,bt_rf_test_result() 的代码逻辑需要用户自行完成。

    #define TUYA_BCI_UART_COMMON_RF_TEST 	    0x0E		//rf radio frequency test
    
    /*****************************************************************************
    Function name: bt_rf_test_req
    Function description: transmit frequency test request to the module
    Input parameters: None
    Return parameter: none
    Instructions for use:
    *****************************************************************************/
    void bt_rf_test_req(void)
    {
    	bt_uart_write_frame(TUYA_BCI_UART_COMMON_RF_TEST,0);
    }
    
    void data_handle(unsigned short offset)
    {
    	......
    	#ifdef TUYA_BCI_UART_COMMON_RF_TEST
    	case TUYA_BCI_UART_COMMON_RF_TEST:
    		if(my_memcmp((unsigned char *)bt_uart_rx_buf + offset + DATA_START+7,"true",4)==0)
    		{
    			bt_rssi = (bt_uart_rx_buf[offset + DATA_START+21]-'0')*10 + (bt_uart_rx_buf[offset + DATA_START+22]-'0');
    			bt_rssi = -bt_rssi;
    			bt_rf_test_result(1,bt_rssi);
    		}
    		else
    		{
    			bt_rf_test_result(0,0);
    		}
    		break;
    #endif
    	......
    }
    
    /*****************************************************************************
    Function name: bt_rf_test_result
    Function description: Bluetooth RF test feedback
    Input parameter: Result: Bluetooth RF test result;0: failure /1: success
    		Rssi: Successful test indicates that the Bluetooth signal strength/test failure value is meaningless
    Return parameter: none
    Instructions: The MCU needs to improve the function itself
    *****************************************************************************/
    void bt_rf_test_result(unsigned char result,signed char rssi)
    {
    #error "Please improve the function by yourself and delete the line after completion"
    if(result == 0)
    {
    	// The test failed
    }
    else
    {
    	// The test was successful
    	// RSSI is the signal strength, which is generally greater than -70dbM and within the normal range of Bluetooth signals
    }
    }
    

查询模组工作状态

功能介绍

MCU 主动向模组查询模组当前工作状态。

使用场景

模组在检测到 MCU 重启或 MCU 断线再上线,会通过报告设备工作状态指令 0x03 主动下发蓝牙工作状态给到 MCU,如果 MCU 需要主动查询蓝牙模组的工作状态,可通过发送查询蓝牙工作状态指令请求模组发送当前工作状态到 MCU。

相关指令说明

查询模组连接状态指令 0x0A

指令作用:用于 MCU 主动查询模组的工作状态。模组收到查询后将通过命令字 0x03 发送模组工作状态。

指令详细介绍,请参考 蓝牙通用串口协议-查询模组工作状态

功能协议示例

拓展功能