前言
本文档详细介绍了WS63V100 Wi-Fi、BLE&SLE接口功能以及开发流程。
与本文档对应的产品版本如下。
本文档主要适用以下工程师:
技术支持工程
软件开发工程师
在本文中可能出现下列标志,它们所代表的含义如下。
概述
WS63V100 通过API(Application Programming Interface)面向开发者提供Wi-Fi功能的开发和应用接口,包括芯片初始化、资源配置、Station创建和配置、扫描、关联以及去关联、状态查询等一系列功能,框架结构如图1所示。
各功能模块说明如下:
业务层:用户基于API接口的二次开发。
应用层协议:应用层网络协议。
LWIP协议栈:TCP/IP协议栈。
WiFi APIs:提供基于SDK的WiFi通用接口。
BLE APIs:提供基于SDK的BLE通用接口。
SLE APIs:提供基于SDK的SLE通用接口。
感知 APIs: 提供基于SDK的感知通用接口。
BSP Driver:芯片和外围设备驱动。
WLAN Driver:802.11协议实现模块。
BLE&SLE Driver:BLE及星闪协议实现模块。
说明: 该文档描述各个模块功能的开发流程。
Wi-Fi 软件开发
驱动加载与卸载
概述
在完成芯片上电后,驱动加载实现对芯片寄存器的初始配置、校准参数读取与写入、软件资源的申请和配置;驱动卸载实现软件资源的释放。
开发流程
Wi-Fi驱动初始化为Wi-Fi功能提供基本资源配置和芯片初始化,是Wi-Fi功能实现的第一步。当需要配置Wi-Fi功能时,必须先完成驱动的初始化,Wi-Fi功能使用完成后,可以使用去初始化完成资源释放也可以使用软复位来完成资源释放。
Wi-Fi驱动加载与卸载提供的接口如表1所示。
表 1 Wi-Fi驱动加载与卸载接口描述
使用驱动加载与卸载的典型流程:
调用wifi_init,完成Wi-Fi驱动初始化。
参考“STA功能”或“SoftAp功能”配置Wi-Fi功能。
调用wifi_deinit,完成Wi-Fi驱动去初始化。
Wi-Fi驱动加载与卸载的返回值如表2所示。
表 2 Wi-Fi驱动加载与卸载返回值说明
编程实例
示例1:基于LiteOS的app_main函数,在系统初始化时已自动完成Wi-Fi驱动的加载,此加载方式无须执行,系统reboot时自动完成驱动卸载和加载。
代码示例
td_void app_main(td_void)
{
td_u32 ret;
ret = wifi_init();
if (ret != 0) {
printf("fail to init wifi\n");
} else {
printf("wifi init success\n");
}
//此处添加测试代码
ret = wifi_deinit();
if (ret != 0) {
printf("fail to deinit wifi\n");
} else {
printf("wifi deinit success\n");
}
return;
}
结果验证
wifi init success
wifi deinit success
STA功能
概述
STA功能即Station功能,实现驱动STA设备的创建、扫描、关联以及DHCP,完成通信链路的建立。开发STA功能前,须完成驱动加载。
开发流程
当需要接入某个网络并与该网络通信时,需要启动STA功能。
驱动STA功能提供的接口如表1所示。
表 1 驱动STA功能接口描述
STA功能开发的典型流程:
调用wifi_sta_enable,启动STA。
(可选,根据需要配置)调用wifi_sta_set_reconnect_policy,设置自动重连。
调用wifi_sta_scan(或调用aich_wifi_sta_advance_scan,执行带参数扫描),触发STA扫描。
调用wifi_sta_get_scan_info,获取扫描结果。
根据接入网络需求,自定义筛选扫描结果,调用wifi_sta_connect,进行连接。
调用wifi_sta_get_ap_info,查询Wi-Fi连接状态。
连接成功后,调用netifapi_dhcp_start,启动DHCP客户端,获取IP地址。
调用wifi_sta_disconnect,离开当前连接的网络。
(可选)调用netifapi_dhcps_stop,停止DHCP客户端。
调用wifi_sta_disable,关闭STA(会自动关闭DHCP客户端)。
STA功能的返回值如表2所示。
表 2 STA功能返回值说明
注意事项
扫描为非阻塞式接口,扫描命令下发成功后需要延迟一段时间后再获取扫描结果,全信道扫描延迟时间建议设置为1s。
可通过指定SSID、BSSID、信道等带指定参数的扫描,实现更精准地扫描,缩短扫描时间。
已知待连接网络的参数时,可省去扫描过程,直接发起连接。
连接为非阻塞式接口,连接命令下发成功后,需要通过命令获取连接状态。
注册事件回调函数后,Wi-Fi相关的事件会通过该回调上报用户,用户可根据事件执行后续动作。
不支持重复启动STA,再次启动STA时须先执行关闭STA。
关闭STA步骤为可选,设备所处的网络地位不变,不需要执行关闭STA。
STA默认支持发送和接收AMPDU聚合帧。
Sample用例
说明:
STA Sample文件位于application\samples\wifi\sta_sample目录。
实现当STA Sample软件版本成功烧录后,单板启动时会自启动STA,并不停的扫描,直到发现存在SSID为“my_softAP”的目标AP,然后会通过密码“my_password”进行连接,若连接失败,则重复扫描动作,若连接成功,则进一步获取动态IP地址,获取IP成功后,串口会打印“STA connect success.”。
在SDK包的根目录下,执行命令“python3 build.py ws63-liteos-app menuconfig”进入menuconfig。
依次选择Application -> Enable Sample -> Enable the Sample of WIFI -> Sample -> Support WIFI STA Sample,并按S键保存,然后通过Esc键退出menuconfig。
在SDK包的根目录下,执行命令“python3 build.py ws63-liteos-app”,即可编译STA Sample软件版本。
SoftAp功能
概述
SoftAp功能提供网络接入点供其他STA接入,并对接入的STA提供DHCP Server服务。
开发流程
当需要创建一个网络接入点,供其他设备接入并共享网络内的数据时,需要使用SoftAp功能。
驱动SoftAp功能提供的接口如表1所示。
表 1 驱动SoftAp功能接口描述
SoftAp功能开发的典型流程:
(可选)调用wifi_set_softap_config_advance,设置SoftAp协议模式、beacon周期、dtim周期、秘钥更新时间、是否隐藏SSID、GI参数。
调用wifi_softap_start,启动SoftAp。
调用netifapi_netif_set_addr,配置DHCP服务器。
调用netifapi_dhcps_start,启动DHCP服务器。
(可选)调用netifapi_dhcps_stop,停止DHCP服务器。
调用aich_wifi_softap_stop,关闭SoftAp(会自动关闭DHCP服务器)。
SoftAp功能的返回值如表2所示。
表 2 SoftAp功能返回值说明
注意事项
SoftAp的网络参数为可选配置,无特殊要求均可使用初始默认值。
SoftAp默认启动20M带宽SoftAp。
SoftAp的网络参数在关闭SoftAp时不会重置,会继续沿用上一次配置,重启单板可恢复至初始默认值。
SoftAp模式下最大关联用户数限制:
最大关联用户不超过6个。
Sample用例
说明:
“SoftAp Sample”文件位于“application\samples\wifi\softap_sample目录”。
实现当SoftAP Sample软件版本成功烧录后,单板启动时会自启动SoftAp,其加密方式为wpa/wpa2,SSID为“my_softAP”,密码为“my_password”,IP地址默认设置为192.168.43.1,网关地址默认设置为192.168.43.2。
在SDK包的根目录下,执行命令“python3 build.py ws63-liteos-app menuconfig”进入menuconfig。
依次选择Application -> Enable Sample -> Enable the Sample of WIFI -> Sample -> Support WIFI SoftAP Sample,并按S键保存,然后通过Esc键退出menuconfig。
在SDK包的根目录下,下发命令“python3 build.py ws63-liteos-app”,即可编译SoftAP Sample软件版本。
STA&SoftAp共存
概述
STA&SoftAp共存即STA功能和SoftAp功能同时工作,仅支持同信道共存。
开发流程
配网时,产品先启动SoftAp,手机关联SoftAp后发送家居网络的SSID和密码给产品,产品获取到家居网络的连接参数后启动STA关联家居网络,完成产品联网,产品联网成功后,关闭SoftAp,只保留STA作为端侧长期保持连接。共存场景可视产品形态和需求自行使用。
共存功能分别使用STA功能和SoftAp功能的API接口,无额外新增API接口。
配网模式下共存功能开发的典型流程:
创建SoftAp网络接口(详细内容请参见“SoftAp功能”)。
手机关联SoftAp,并通过手机APP发送家居网络SSID和密码。
创建STA网络接口,并根据SSID和密码完成关联(详细内容请参见“STA功能”)。
关闭SoftAp(详细内容请参见“SoftAp功能”)。
返回值请参见对应模块功能的返回值说明。
编程实例
请参考STA和SoftAp功能的编程实例(详细内容请参见“STA功能”或“SoftAp功能”)。
Wi-Fi&蓝牙共存
概述
蓝牙(BT,Bluetooth)和Wi-Fi均可能工作在2.4G ISM,因此可能互相干扰。分时是利用蓝牙和Wi-Fi间的握手信号,使蓝牙和Wi-Fi分时在2.4G工作,这样可以避免噪音干扰和阻塞干扰。
802.15.2规定仲裁方式和信号(PTA,Packet Traffic Arbitration)的框架,在蓝牙或Wi-Fi有收发业务时,提交申请给PTA controller(集成在Wi-Fi中),由PTA controller进行许可。
蓝牙和Wi-Fi间的握手信号定义如下:
Wi-Fi给PTA信号wl_tx_status:Wi-Fi有发包业务。
Wi-Fi给PTA信号wl_rx_status:Wi-Fi有收包业务。
Wi-Fi给PTA信号wl_priority:Wi-Fi业务状态,Wi-Fi高优先级。
Wi-Fi给PTA信号wl_occupied:Wi-Fi业务状态,Wi-Fi最高优先级。
蓝牙给PTA信号bt_status:蓝牙有收发业务。
蓝牙给PTA信号bt_priority:蓝牙业务状态,指示蓝牙优先级。
开发流程
需要同时使用Wi-Fi和蓝牙时,开启Wi-Fi&BT共存功能。
Wi-Fi&BT共存功能开发的典型流程:
加载蓝牙后,执行蓝牙共存初始化函数
创建STA网络接口(详细内容请参见“STA功能”)。
创建蓝牙业务(详情内容请参见“BLE&SLE 软件开发”)
注意事项
Wi-Fi与BT共存支持STA模式、支持SoftAp模式。
模组或产品内同时集成了Wi-Fi芯片和蓝牙芯片,常开Wi-Fi&BT共存功能。
不支持外部共存
国家码功能配置
使用背景
对于发货给不同国家的用户,希望使用同一套固件,可以通过修改NV中的管制域信息(包括国家码,信道, 发射功率等)实现。
使用指南
在NV配置文件middleware/chips/ws63/nv/nv_config/cfg/acore/app.json中,NV ID ="0x2003" 的表项用于确定国家码,value的含义是国家码对应ASIC码,例如:十进制67,78分别对应ASIC码中的 'C', 'N'
"country":{ "key_id": "0x2003", "key_status": "alive", "structure_type": "country_type_t", "attributions": 2, "value": [[67,78]] },
国家码与四个区域管制域的对应关系如下。
RU,AU,MY,ID,TR,PL,FR,PT,IT,DE,ES,AR,ZA,MA,PH,TH,GB,CO,MX,EC,PE,CL,SA,EG,AE
基于1确定的对应关系,刷新对应的发射功率表项,支持调整不同速率的目标功率,以及调整在不同工作信道下的最大功率。
刷新0x2053,0x2054,0x2055,0x2056表项:
"fe_tx_power_fcc":{ "key_id": "0x2053", "key_status": "alive", "structure_type": "fe_tx_power_type_t", "attributions": 2, "value": [ [230], [46, 46, 46, 43, 42, 42, 42, 42, 42, 42, 40, 38, 40, 40, 40, 37, 37, 37, 37, 36, 33, 30, 40, 40, 40, 37, 37, 37, 37, 36, 33, 30, 22], [60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60], [60, 60, 60] ] },
"fe_tx_power_etsi":{ "key_id": "0x2054", "key_status": "alive", "structure_type": "fe_tx_power_type_t", "attributions": 2, "value": [ [230], [46, 46, 46, 43, 42, 42, 42, 42, 42, 42, 40, 38, 40, 40, 40, 37, 37, 37, 37, 36, 33, 30, 40, 40, 40, 37, 37, 37, 37, 36, 33, 30, 22], [60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60], [60, 60, 60] ] },
"fe_tx_power_japan":{ "key_id": "0x2055", "key_status": "alive", "structure_type": "fe_tx_power_type_t", "attributions": 2, "value": [ [230], [46, 46, 46, 43, 42, 42, 42, 42, 42, 42, 40, 38, 40, 40, 40, 37, 37, 37, 37, 36, 33, 30, 40, 40, 40, 37, 37, 37, 37, 36, 33, 30, 22], [60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60], [60, 60, 60] ] },
"fe_tx_power_common":{ "key_id": "0x2056", "key_status": "alive", "structure_type": "fe_tx_power_type_t", "attributions": 2, "value": [ [230], [46, 46, 46, 43, 42, 42, 42, 42, 42, 42, 40, 38, 40, 40, 40, 37, 37, 37, 37, 36, 33, 30, 40, 40, 40, 37, 37, 37, 37, 36, 33, 30, 22], [60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60, 60], [60, 60, 60] ] },
对于上述发射功率的每个表项中的参数值结构参见 fe_tx_power_type_t:
#define WLAN_RF_FE_MAX_POWER_NUM 1 #define WLAN_RF_FE_TARGET_POWER_NUM 33 #define WLAN_RF_FE_LIMIT_POWER_NUM 56 #define WLAN_RF_FE_SAR_POWER_NUM 3 typedef struct { uint8_t chip_max_power[WLAN_RF_FE_MAX_POWER_NUM]; uint8_t target_power[WLAN_RF_FE_TARGET_POWER_NUM]; uint8_t limit_power[WLAN_RF_FE_LIMIT_POWER_NUM]; uint8_t sar_power[WLAN_RF_FE_SAR_POWER_NUM]; } fe_tx_power_type_t;
其中:
chip_max_power 是最大发射功率,当前已更新为芯片实际能力。单位0.1dB。
target_power 是不同协议速率下的目标功率,依次分别是11b协议(1M,2M,5.5M,11M),11g协议(6M,9M,12M,18M,24M,36M,48M,54M),11n/11ax协议20M(mcs0~mcs9),11n/11ax协议40M(mcs0~mcs9以及mcs32)。单位0.5dB。
limit_power 是按信道划分的限制功率,总共14个信道,每个信道4个限制功率值,分别对应11b协议、11g协议、11n/11ax协议20M、11n/11ax协议40M。单位0.5dB。
sar_power 是比吸收率功率限制值,共三个值用于选择。单位0.5dB。
刷新NV配置文件后重新编译NV固件并加载。NV支持配置四个区域的发射功率。用户可以调用 AT命令AT+CC=${COUNTRY} 实现国家码变更,从而按照国家码所处的区域更新功率表。
其中${COUNTRY} 从步骤1 中的region_country_map中取。
说明:
最大发射功率不支持修改,已按照芯片能力配置,修改可能导致发射功率异常。
用户自定义发射功率表项时, 不得超过最大的射频发射功率。
11n支持20M和40M,最大支持速率mcs7,不支持mcs32;11ax 不支持40M。
AT+CC命令需要在上电之后,并且关联上用户之前进行调用。
频偏温度补偿功能
使用背景
由于射频频偏在不同工作温度下会发生变化,为了满足发射信号的频偏在规格范围内,可开启频偏温度补偿功能来针对特定温度出现频偏过大的情况进行补偿,使得频偏能够继续保持在规格范围内。
使用指南
参见《WS63V100 产线工装 用户指南》完成软件版本加载,并参考“STA模式冒烟测试”章节中测试步骤4完成WiFi初始化,再参考步骤5第1节完成常发。
获取常温下频偏调节的能力Favg。参考WS63V100 产线工装 用户指南的章节2.2.2的步骤5第4节配置细调频偏值,分别配置value为0和127,记录下value为0时的频偏值F0,value为127时的频偏值F127。计算得到频偏补偿能力Favg=(F127 - F0) / 127。
记录工作温度下的频偏值。重新启动单板,并按步骤1完成常发。再调节温箱温度,从低温遍历到高温,可按实际使用场景确认温度范围,在不同温箱温度下,观察信号频偏随温度变化,记录芯片温度Ti(参考《WS63V100 产线工装 用户指南》的“产测测试流程”章节)以及频偏值Fi。Ti值推荐T0=-30,T1=-10,T2=10,T3=30,T4=50,T5=70,T6=90,T7=110。
计算频偏温度补偿值并使用补偿。根据步骤3中得到的频偏值Fi,确认需要补偿的温度Ti,计算补偿值FCi=Fi / Favg(对于不需要补偿的温度点,FCi=0),结果四舍五入取整,并保证在取值范围内[-127,127],超过范围的按范围边界值配置。将计算得到的FCi填写至NV表项key_id为0x7对应结构中,并使能key_id为0x6的补偿开关。
"xo_trim_temp_param":{ "key_id": "0x7", "key_status": "alive", "structure_type": "xo_trim_temp_type_t", "attributions": 1, "value": [[FC0,FC1,FC2,FC3,FC4,FC5,FC6,FC7]] }, "xo_trim_temp_sw":{ "key_id": "0x6", "key_status": "alive", "structure_type": "uint8_t", "attributions": 1, "value": 1 },
说明:
频偏温度补偿功能是基于产线频偏校准的,是作为优化功能,请保证已完成产线频偏校准,具体流程可参考《WS63V100 产线工装 用户指南》的“产测测试流程”章节。
获取频偏温度补偿值时请使用温箱并保持温度稳定。
频偏补偿值可基于同一批次单板的平均数据获取。
FAQ
频偏修正
若遇到信号频偏较大,在没有频偏产测校准的情况下,可以考虑通过修改默认的频偏补偿值来修正频偏。请参考以下流程:
在频偏补偿配置所在文件application/ws63/ws63_liteos_application/clock_init.c中找到频偏补偿宏。
“RG_CMU_XO_TRIM_COARSE”。
根据当前频偏的情况,如果频偏为正,则将频偏补偿宏的低8位调大;反之则调小。
修改后确认信号频偏,满足要求则可以按新的配置值更新频偏补偿宏。
BLE&SLE 软件开发
BLE开发流程
概述
WS63V100通过API(Application Programming Interface)面向开发者提供BLE功能的开发和应用接口,包括GAP、GATT server和GATT client接口。
各组件功能说明如下:
GAP:通用访问协议(Generic Access Profile),包含蓝牙本地设置和低功耗蓝牙的发现和连接接口。
GATT:通用属性协议(Generic Attribute Profile),包含服务注册、服务发现等功能相关接口。
说明: 该文档描述各个模块功能的基本流程和API接口描述。
GAP接口
概述
GAP实现蓝牙设备开关控制、设备信息管理、广播管理、主动连接和断开连接等功能。
开发流程
打开蓝牙设备开关是使用蓝牙功能的首要条件,蓝牙启动后可进行设备信息管理,包括获取与设置本地设备名称、获取本地设备地址、获取配对信息、获取远端设备名称/设备类型/接收信号强度等。
当蓝牙设备需要被动与对端设备建立连接时,可设置广播参数并启动广播等待对端连接;当蓝牙设备需要主动与对端设备建立连接时,可向对端发起主动连接;当对端地址已知时,用户可直接向对端发起主动连接;当对端地址未知时,可打开蓝牙设备的扫描功能,获取正在广播的设备信息,并向对端发起主动连接;当蓝牙设备处于连接状态时,可获取设备连接信息;当蓝牙设备不需要与对端设备保持连接时,可主动断开连接。
GAP提供的接口如下表所示。
注: 若需使用NV或eFuse里的地址, 调用'get_dev_addr'接口获取当前已存储的地址, 然后调用本接口将地址设置到BTH与BTC。 |
|||
具体操作流程:
GAP开发的具体编程实例可参考application/samples/bt。
GAP开发的典型流程(指令中的数据可根据按照AT命令使用指南自行修改):
Slave:
调用gap_ble_register_callbacks注册用户回调函数。
调用enable_ble,打开蓝牙开关。
调用gap_ble_set_local_addr,设置本地蓝牙地址。
调用gap_ble_set_local_name,设置本地设备名称。
调用gap_ble_set_adv_param,设置广播参数。
调用gap_ble_set_adv_data,设置广播数据。
调用gap_ble_start_adv,启动广播。
Master:
调用gap_ble_register_callbacks注册用户回调函数。
调用enable_ble,打开蓝牙开关。
调用gap_ble_set_local_addr,设置本地蓝牙地址。
调用gap_ble_set_local_name,设置本地设备名称。
调用gap_ble_set_scan_parameters,设置扫描参数。
调用gap_ble_start_scan,启动扫描。
调用gap_connect_remote_device,连接到目标设备。
调用gap_ble_pair_remote_device,与目标设备配对
返回值
获取配对状态返回值如下所示。
注意事项
WS63V100产品可支持8路蓝牙连接。
若扫描不到设备,请先检查设备是否已在配对设备列表中,或者设备是否已与其他设备配对(此情况下需要先清除设备端配对信息)。
GATT server接口
概述
GATT是一个基于蓝牙GAP连接的发送和接收数据的通用规范,支持在两个蓝牙设备间进行数据传输。
开发流程
GATT server主要接收对端设备的命令和请求,给对端设备发送响应、指示或者通知。
GATT server提供的接口如下表所示。
GATT server开发具体编程实例可参考application/samples/bt。
GATT server开发的典型流程:添加服务和特征及描述信息并启动服务。
调用gatts_register_callbacks,注册GATT server用户回调函数。
调用enable_ble,打开蓝牙开关。
调用gatts_register_server,创建一个server。
调用gatts_add_service,根据UUID创建service。
调用gatts_add_characteristic,对创建的服务添加特征值。
调用gatts_add_descriptor,对服务中的特征添加描述信息。
调用gatts_start_service,启动service。
启动广播,等待对端连接。
被对端使能为“可通知”后,调用gatts_notify_indicate或gatts_notify_indicate_by_uuid向对端发起特征值通知。
GATT client接口
概述
GATT是一个基于蓝牙GAP连接的发送和接收数据的通用规范,支持在两个蓝牙设备间进行数据传输。
开发流程
GATT client主要给对端发送命令和请求,接收对端回复的响应、指示和通知。
GATT client提供的接口如下表所示。
GATT client开发的具体编程实例可参考application/samples/bt。
GATT client开发的典型流程:连接对端设备,发现对端设备的服务,读写对端特征值,订阅对端的通知或者指示。
调用gattc_register_callbacks,注册GATT client用户回调函数。
调用enable_ble,打开蓝牙开关。
调用gattc_register_client,创建一个client。
递归调用gattc_discovery_service,gattc_discovery_character和gattc_discovery_descriptor,获取对端的属性数据库。
调用gattc_write_req或gattc_write_cmd将关注的对端特征的客户端特征配置写为0x0001或0x0002,设置为前者时可收到关注特征的特征通知,设置为后者时可收到关注特征的特征指示。
调用相应读写接口操作GATT server的特征和描述符。
错误码
BLE错误码返回值如下表所示。
sample示例
ble_speed_client使用指导
在SDK根目录下执行命令“python3 build.py ws63-liteos-app menuconfig”,并按下图配置对应编译选项进行配置。
完成配置后执行命令python3 build.py ws63-liteos-app,将生成的镜像通过BurnTool烧录进单板中。
扫描:sample会在首次运行、断连时自动启动扫描,在连接后停止扫描。用户可在ble_gatt_client_scan_result_cbk接口中处理扫描到的蓝牙设备,每扫描到一个BLE设备都会回调一次ble_gatt_client_scan_result_cbk接口。
连接:可在扫描到蓝牙设备时,使用gap_ble_connect_remote_device接口连接对端设备,不要求必须在ble_gatt_client_scan_result_cbk接口中连接对端蓝牙设备,但需要保证对端蓝牙设备正在发广播。连接状态的改变会在ble_gatt_client_conn_state_change_cbk回调中上报,当前sample会在连接后停止扫描、配对、服务发现等操作。
数据发送:可以调用gattc_write_req或者gattc_write_cmd接口发送数据给server。
数据接收:在ble_gatt_client_notification_cbk回调或者ble_gatt_client_indication_cbk回调中处理接收到的server数据。
说明: 对于回调中的入参,不需要主动释放内存,回调结束后,协议栈自身会进行释放。
ble_speed_server使用指导
在SDK根目录下执行命令“python3 build.py ws63-liteos-app menuconfig”,并按下图配置对应编译选项进行配置。
完成配置后执行命令python3 build.py ws63-liteos-app,将生成的镜像通过BurnTool烧录进单板中。
默认编译选项时,ble_speed_server sample会自动打流测速。用户也可在配置编译选项时,取消选择Set the sample support speed test,使sample将收到的数据自动发回给client以验证数据互通。
具体使用nRF Connect工具进行连接测试,下载连接为"https://github.com/NordicSemiconductor/Android-nRF-Connect"。
启动广播:调用ble_start_adv接口启动广播。当前sample会在首次运行、server非主动断连时自动启动广播。
停止广播:连接后会自动停止广播,并在ble_uuid_server_adv_terminate_cbk中上报。
接收数据:在ble_uuid_server_receive_write_req_cbk接口中处理client发送的数据。
发送数据:调用ble_uuid_server_send_report_by_handle或者ble_uuid_server_send_report_by_uuid接口发送数据。并不要求server向client发送数据必须在ble_uuid_server_receive_write_req_cbk中进行。
自定义服务、特征设置:自定义服务、特征、描述符的UUID定义在"ble_speed_server/inc/ble_speed_server.h"中。当前sample定义了一个私有服务BLE_UUID_UUID_SERVER_SERVICE,该服务下面存在一个特征BLE_UUID_UUID_SERVER_REPORT。UUID需要根据客户自身需求更改。UUID的详细介绍如下所示。
表 1 server UUID介绍
若UUID的16字节全为自定义的(比如为ABCDEFGH-IJKL-MNOP-QRST-UVWXYZ012345),需要在UUID注册时,参考下面代码将字节数组转换为bt_uuid_t。
void stream_data_to_uuid(bt_uuid_t *out_uuid)
{
char uuids[] = {0x45, 0x23, 0x01, 0xYZ, 0xWX, 0xUV, 0xST, 0xQR, 0xOP, 0xMN, 0xKL, 0xIJ, 0xGH, 0xEF, 0xCD, 0xAB};
out_uuid->uuid_len = 16;
if (memcpy_s(out_uuid->uuid, out_uuid->uuid_len, uuids, 16) != EOK) {
return;
}
}
用户可根据自身需求更改特征的properties,具体枚举定义在"bts_gatt_stru.h"的gatt_characteristic_property_t中。
此外,默认的MTU大小为23字节,若数传的数据长度超过20字节(其中3字节为GATT包头),需要客户端主动发起MTU协商。
说明: 对于回调中的入参,不需要主动释放内存,回调结束后,协议栈自身会进行释放。
注意事项
异常断连时,需要重启广播以及重启扫描,以保证业务在干扰场景下能够尽可能自愈(建议在断连原因为非本端断链、以及配对失败时需要自愈)。
星闪开发流程
概述
WS63V100通过API(Application Programming Interface)面向开发者提供SLE功能的开发和应用接口,包括Device Discovery, Connection Manager, SSAP等。
各组件功能说明如下:
Device Discovery:星闪设备发现协议,包括设备管理、设备公开和设备发现接口。
Connection Manager:星闪连接管理协议,包括设备连接、配对相关接口。
SSAP:星闪服务交互协议(SparkLink Service Access Protocol),包含服务注册、服务发现、属性数据读写等功能相关接口。
Low Latency:低时延初始化和低时延数据收发接口。
说明: 该文档描述各个模块功能的基本流程和API接口描述。
Device Discovery接口
概述
Device Discovery接口是星闪设备发现协议的软件实现,主要功能有SLE设备开关、设备管理、设备公开和设备发现。
开发流程
打开SLE设备开关是使用SLE功能的首要条件,SLE启动后可进行设备信息管理,包括获取与设置本地设备名称、获取与设置本地设备地址和设置本地设备外观。
当SLE设备需要进行设备公开时,可先设置设备公开参数、设备公开数据,然后使能设备公开。
当SLE设备需要进行设备发现时,可先设置设备发现参数,然后使能设备发现,并通过回调函数观察发现到的设备公开数据包。
Device Discovery提供的接口如下表所示。
注: 若需使用NV或eFuse里的地址, 调用'get_dev_addr'接口获取当前已存储的地址, 然后调用本接口将地址设置到BTH与BTC。 |
|||
Device Discovery开发的典型流程如下,具体编程实例可参考application/samples/bt。
Terminal Node:
调用enable_sle,打开SLE开关。
调用sle_announce_seek_register_callbacks,注册设备公开和设备发现回调函数。
调用sle_set_local_addr,设置本地设备地址。
调用sle_set_local_name,设置本地设备名称。
调用sle_set_announce_param,设置设备公开参数
调用sle_set_announce_data,设置设备公开数据
调用sle_start_announce,启动设备公开。
Grant Node:
调用enable_sle,打开SLE开关。
调用sle_announce_seek_register_callbacks,注册设备公开和设备发现回调函数。
调用sle_set_local_addr,设置本地设备地址。
调用sle_set_local_name,设置本地设备名称。
调用sle_set_seek_param,设置设备发现参数。
调用sle_start_seek,启动设备发现,并在回调函数中获得正在进行设备公开的设备信息。
注意事项
WS63V100支持8路星闪连接,可同时作为BLE和星闪设备工作。
若扫描不到设备,请先检查设备是否已在配对设备列表中,或者设备是否已与其他设备配对(此情况下需要先清除设备端配对信息)。
Connection Manager接口
概述
Connection Manager接口是星闪连接管理协议的软件实现,主要功能有连接、配对和读远端设备RSSI值。
开发流程
当设备需要与对端设备建立连接时,可向对端设备发起连接请求。在连接过程中,设备可读取远端设备RSSI值,当设备需要更新连接参数时,可向对端设备发起连接参数更新请求,当设备需要与对端设备配对时,可向对端设备发起配对请求。在配对过程中,可获取当前本端设备与指定对端设备的配对状态。设备可获取当前配对设备数量以及当前配对设备信息链表。
Connection Manager提供的接口如下表所示。
Connection Manager开发的典型流程如下,具体编程实例可参考application/samples/bt。
Terminal Node:
调用enable_sle,打开SLE开关。
调用sle_announce_seek_register_callbacks,注册设备公开和设备发现回调函数。
调用sle_connection_register_callbacks,注册连接管理回调函数。
调用sle_set_local_addr,设置本地设备地址。
调用sle_set_local_name,设置本地设备名称。
调用sle_set_announce_param,设置设备公开参数
调用sle_set_announce_data,设置设备公开数据
调用sle_start_announce,启动设备公开。
Grant Node:
调用enable_sle,打开SLE开关。
调用sle_announce_seek_register_callbacks,注册设备公开和设备发现回调函数。
调用sle_connection_register_callbacks,注册连接管理回调函数。
调用sle_set_local_addr,设置本地设备地址。
调用sle_set_local_name,设置本地设备名称。
调用sle_set_seek_param,设置设备发现参数。
调用sle_start_seek,启动设备发现,并在回调函数中获得正在进行设备公开的设备信息。
调用sle_connect_remote_device,向对端设备发起连接请求。
调用sle_pair_remote_device,向对端设备发起配对请求。
调用sle_get_paired_devices_num,获取当前配对设备数量。
调用sle_get_paired_devices,获取当前配对设备信息。
调用sle_get_pair_state,获取配对状态。
SSAP server接口
概述
SSAP是SLE发送和接收数据的通用规范,支持在两个SLE设备间进行数据传输。
开发流程
SSAP Server主要接收对端的请求和命令,向对端发送响应、通知和指示。
SSAP Server提供的接口如下表所示。
SSAP server开发的典型流程:注册SSAP server,注册本端属性数据库,接收对端的请求和命令,向对端发送通知和指示,具体编程实例可参考application/samples/bt。
调用enable_sle,打开SLE开关。
调用ssaps_register_callbacks,注册SSAP server回调。
调用sle_announce_seek_register_callbacks,注册设备公开和设备发现回调函数。
调用ssaps_register_server,创建一个server实体。
调用ssaps_add_service_sync、ssaps_add_property_sync、ssaps_add_descriptor_sync和ssaps_start_service注册本端属性数据库,每一个服务及其内容添加完成后调用ssaps_start_service启动服务。
调用sle_set_local_addr,设置本地设备地址。
调用sle_set_local_name,设置本地设备名称。
调用sle_set_announce_param,设置设备公开参数。
调用sle_set_announce_data,设置设备公开数据。
调用sle_start_announce,启动设备公开。
连接建立。
接收对端设备的读写请求,当对端设备读写需要授权的特征或描述符时,调用ssaps_send_response向对端发送响应并修改本端特征值。
当某个特征的客户端特征配置描述符为0x0001时,在特征值变化时向对端设备发送通知,当某个特征的客户端特征配置描述符为0x0002时,在特征值变化时向对端设备发送指示。
SSAP client接口
概述
SSAP是SLE发送和接收数据的通用规范,支持在两个SLE设备间进行数据传输。
开发流程
SSAP Client主要向对端发送请求和命令,接收对端的响应、通知和指示。
SSAP Client提供的接口如下表所示。
SSAP Client开发的典型流程:注册SSAP Client,查找对端属性数据库,向对端发送请求和命令,接收对端的通知和指示,具体编程实例可参考application/samples/bt。
SSAP Server:
调用enable_sle,打开SLE开关。
调用ssaps_register_callbacks,注册SSAP server回调。
调用sle_announce_seek_register_callbacks,注册设备公开和设备发现回调函数。
调用ssaps_register_server,创建一个server实体。
调用ssaps_add_service_sync、ssaps_add_property_sync、ssaps_add_descriptor_sync和ssaps_start_service注册本端属性数据库,每一个服务及其内容添加完成后调用ssaps_start_service启动服务。
调用sle_set_local_addr,设置本地设备地址。
调用sle_set_local_name,设置本地设备名称。
调用sle_set_announce_param,设置设备公开参数。
调用sle_set_announce_data,设置设备公开数据。
调用sle_start_announce,启动设备公开。
连接建立。
接收对端设备的读写请求,当对端设备读写需要授权的特征或描述符时,调用ssaps_send_response向对端发送响应并修改本端特征值。
当某个特征的客户端特征配置描述符为0x0001时,在特征值变化时向对端设备发送通知,当某个特征的客户端特征配置描述符为0x0002时,在特征值变化时向对端设备发送指示。
SSAP Client:
调用enable_sle,打开SLE开关。
调用ssapc_register_callbacks,注册SSAP client回调。
调用sle_announce_seek_register_callbacks,注册设备公开和设备发现回调函数。
调用ssapc_register_client,创建一个client实体。
递归调用ssapc_find_structure查找对端属性数据库。
如果关注对端某个特征,可调用ssapc_write_req或ssapc_write_cmd将该特征的客户端特征配置描述符写为0x0001或0x0002,前者可使能对端特征通知,后者可使能对端特征指示。
调用读写接口操作对端属性数据库。
错误码
SLE sdk使用错误码指示用户当前任务执行结果,如下表所示。
sample示例
sle_speed_client使用指导
在SDK根目录下执行命令“python3 build.py ws63-liteos-app menuconfig”,并按下图配置对应编译选项进行配置。
完成配置后执行命令python3 build.py ws63-liteos-app,将生成的镜像通过BurnTool烧录进单板中。
扫描:sample会在首次运行、断连时自动启动扫描,在连接后停止扫描。用户可在sle_sample_seek_result_info_cbk接口中处理扫描到的星闪设备,每扫描到一个星闪设备都会回调一次sle_sample_seek_result_info_cbk接口。
连接:可在扫描到蓝牙设备时,使用sle_connect_remote_device接口连接对端设备,不要求必须在sle_sample_seek_result_info_cbk接口中连接对端星闪设备,但需要保证对端星闪设备正在发广播。连接状态的改变会在sle_sample_connect_state_changed_cbk回调中上报,当前sample会在连接后停止扫描、配对、服务发现等操作。
数据发送:可以调用ssapc_write_req或者ssapc_write_cmd接口发送数据给server。
数据接收:在sle_speed_notification_cb回调或者sle_speed_indication_cb回调中处理接收到的server数据。
说明: 对于回调中的入参,不需要主动释放内存,回调结束后,协议栈自身会进行释放。
sle_speed_server使用指导
在SDK根目录下执行命令“python3 build.py ws63-liteos-app menuconfig”,并按下图配置对应编译选项进行配置。
完成配置后执行命令python3 build.py ws63-liteos-app,将生成的镜像通过BurnTool烧录进单板中。
启动广播:调用sle_start_announce接口启动广播。当前sample会在首次运行、server非主动断连时自动启动广播。
停止广播:连接后会自动停止广播,并在sle_announce_terminal_cbk中上报。
接收数据:在ssaps_write_request_cbk接口中处理client发送的数据。
发送数据:调用sle_uuid_server_send_report_by_handle_id接口发送数据。
自定义服务、特征设置:自定义服务、特征、描述符的UUID定义在"sle_speed_server/inc/sle_speed_server.h"中。当前sample定义了一个私有服务SLE_UUID_SERVER_SERVICE,该服务下面存在一个特征SLE_UUID_SERVER_NTF_REPORT。UUID需要根据客户自身需求更改。UUID的详细介绍如下所示。
表 1 server UUID介绍
说明: 对于回调中的入参,不需要主动释放内存,回调结束后,协议栈自身会进行释放。
注意事项
异常断连时,需要重启广播以及重启扫描,以保证业务在干扰场景下能够尽可能自愈(建议在断连原因为非本端断链、以及配对失败时需要自愈)。
BLE&SLE功率档位定制
在NV配置文件middleware/chips/ws63/nv/nv_config/cfg/acore/app.json中,NV ID ="0x20A0" 的表项用于设置BLE&SLE的最大功率档位,value的含义是BLE&SLE的最大功率档位。当前各个档位的发射功率为-6, -2, 2, 6, 10, 14, 16, 20。
如果设置为7,那么可以使用的档位是0~7,每档对应-6, -2, 2, 6, 10, 14, 16, 20;
如果设置为5,那么可以使用的档位是0~5,每档对应-6, -2, 2, 6, 10, 14。
"bt_txpower":{ "key_id": "0x20A0", "key_status": "alive", "structure_type": "btc_power_type_t", "attributions": 1, "value": [7] },
感知软件开发
概述
感知特性为周期性地收发感知信号以检测运动目标的功能特性,用户可以调用感知APIs接口使用该特性。
开发流程
数据结构
感知状态设置枚举定义:
typedef enum {
RADAR_STATUS_STOP = 0, /* 感知状态配置停止 */
RADAR_STATUS_START, /* 感知状态配置启动 */
RADAR_STATUS_RESET, /* 感知状态配置复位 */
RADAR_STATUS_RESUME, /* 感知状态配置状态恢复 */
} radar_set_sts_t;
感知软件状态查询枚举定义:
typedef enum {
RADAR_STATUS_IDLE = 0, /* 感知软件状态未工作 */
RADAR_STATUS_RUNNING, /* 感知软件状态工作 */
} radar_get_sts_t;
感知硬件状态查询枚举定义:
ypedef enum {
RADAR_STATUS_HW_FAULT = 0, /* 感知硬件状态故障 */
RADAR_STATUS_HW_NORMAL, /* 感知硬件状态正常 */
} radar_get_hardware_sts_t;
感知结果上报结构体定义:
typedef struct {
uint32_t lower_boundary; /* 感知结果靠近检测下边界 */
uint32_t upper_boundary; /* 感知结果靠近检测上边界 */
uint8_t is_human_presence; /* 感知结果有无人体存在 */
uint8_t reserved_0;
uint8_t reserved_1;
uint8_t reserved_2;
} radar_result_t;
雷达单帧结果结构体定义:
typedef struct {
uint8_t gear_one_flag; /* 感知当前帧结果,1档位置(默认距感知模组水平距离1米处)是否有人运动 */
uint8_t gear_two_flag; /* 感知当前帧结果,2档位置(默认距感知模组水平距离2米处)是否有人运动 */
uint8_t gear_three_flag; /* 感知当前帧结果,3档位置(默认距感知模组水平距离6米处)是否有人运动 */
uint8_t ai_flag; /* 感知当前帧AI结果,是否为人体运动 */
} radar_current_frame_result_t;
感知结果回调函数数据结构定义:
typedef void (*radar_result_cb_t)(radar_result_t *result);
感知维测信息回调函数数据结构定义:
typedef void (*radar_debug_info_cb_t)(int16_t *arr, uint8_t len);
每一个感知帧计算完成后的回调函数数据结构定义:
typedef void (*radar_current_frame_result_cb_t)(radar_current_frame_result_t *result);
感知维测参数结构体定义:
typedef struct {
uint8_t times; // 子帧发送次数, 默认值0, 一直发送, 范围0~20
uint8_t loop; // 单个子帧感知波形循环发送次数, 默认值为8
uint8_t ant; // 接收通路选择, 默认值为0
uint8_t wave; // 感知发射波形类型选择, 默认值为2
uint8_t dbg_type; // 维测信息输出选择, 默认值为0, 只打印基础流程日志, 范围0~4
uint16_t period; // 感知子帧间隔,单位us,默认值为5000, 范围3000~100000
} radar_dbg_para_t;
感知算法参数套选择参数结构体定义:
typedef struct {
uint8_t height; // 模组安装架高信息: 1/2/3米
uint8_t scenario; // 场景: 家居/空旷
uint8_t material; // 模组视距方向遮挡材料: 塑料/金属
uint8_t fusion_track; // 是否融合距离跟踪结果
uint8_t fusion_ai; // 是否融合AI结果
} radar_sel_para_t;
感知算法参数结构体定义:
typedef struct {
uint8_t d_th_1m; // 靠近1米档门限
uint8_t d_th_2m; // 靠近2米档门限
uint8_t p_th; // 存在6米档门限
uint8_t t_th_1m; // 距离跟踪1米档门限
uint8_t t_th_2m; // 距离跟踪2米档门限
uint8_t b_th_ratio; // 抗频谱对称干扰比例门限
uint8_t b_th_cnt; // 抗频谱对称干扰数量门限
uint8_t a_th; // AI人体识别相似度门限
} radar_alg_para_t;
APIs
感知 APIs接口如下表所示。
错误码
注意事项
感知特性需要在WiFi信道上进行工作,所以需注意打开雷达前,需要确保WiFi信道有配置,WiFi进入softAP或STA模式即可。
编程实例
typedef void (*radar_result_cb_t)(radar_result_t *result);
#define WIFI_IFNAME_MAX_SIZE 16
#define WIFI_MAX_SSID_LEN 33
#define WIFI_SCAN_AP_LIMIT 64
#define WIFI_MAC_LEN 6
#define WIFI_INIT_WAIT_TIME 500 // 5s
#define WIFI_START_STA_DELAY 100 // 1s
#define RADAR_STATUS_START 1
#define RADAR_STATUS_QUERY_DELAY 1000 // 10s
#define RADAR_QUIT_DELAY_TIME 12 // 12s
#define RADAR_DEFAULT_TIMES 0
#define RADAR_DEFAULT_LOOP 8
#define RADAR_DEFAULT_ANT 0
#define RADAR_DEFAULT_PERIOD 5000
#define RADAR_DEFAULT_DBG_TYPE 3
#define RADAR_DEFAULT_WAVE 2
#define RADAR_API_NO_HUMAN 0
#define RADAR_API_RANGE_CLOSE 50
#define RADAR_API_RANGE_NEAR 100
#define RADAR_API_RANGE_MEDIUM 200
#define RADAR_API_RANGE_FAR 600
#define RADAR_DBG_INFO_RPT_COEF 100
#define RADAR_DBG_INFO_LEN 16
// WiFi启动STA模式实现样例
td_s32 radar_start_sta(td_void)
{
(void)osDelay(WIFI_INIT_WAIT_TIME); /* 500: 延时0.5s, 等待wifi初始化完毕 */
PRINT("STA try enabl旨e.\r\n");
/* 创建STA接口 */
if (wifi_sta_enable() != 0) {
PRINT("sta enbale fail !\r\n");
return -1;
}
/* 连接成功 */
PRINT("STA connect success.\r\n");
return 0;
}
// 感知结果回调函数实现样例
static void radar_print_res(radar_result_t *res)
{
PRINT("[RADAR_SAMPLE] lb:%u, ub:%u, hm:%u\r\n", res->lower_boundary, res->upper_boundary, res->is_human_presence);
}
static void radar_print_cur_frame_res(radar_current_frame_result_t *res)
{
PRINT("[RADAR_SAMPLE] gear1:%u, gear2:%u, gear3:%u, ai:%u\r\n",
res->gear_one_flag, res->gear_two_flag, res->gear_three_flag, res->ai_flag);
}
// 维测信息依次为:
// 1.告知上层是否需要写入flash
// 2.LNA * 10 + VGA
// 3.原始回波峰值
// 4.过去period帧的平均MO1底噪
// 5.过去period帧的平均MO2底噪
// 6.过去period帧的平均DP底噪
// 7.过去period帧的平均帧间隔
// 8.过去period帧中帧间隔超过Xms的帧数
// 9.过去period帧中bitmap数量超过X门限的帧数
// 10.过去period帧中bitmap比例超过X门限的帧数
// 11.过去period帧中是在参与统计的帧数
// 12.过去period帧中帧间隔最大值
// 13.过去period帧中帧间隔最大值下标
// 14.当前所使用的算法参数MO1门限
// 15.当前所使用的算法参数MO2门限
// 16.当前所使用的算法参数DP门限
static void radar_print_dbg_info(int16_t *arr, uint8_t len)
{
if (len > RADAR_DBG_INFO_LEN || len == 0) {
return;
}
PRINT("dbg_info: %d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d\r\n",
arr[0], arr[1], arr[2], arr[3], arr[4], arr[5], arr[6], arr[7], arr[8], arr[9], arr[10],
arr[11], arr[12], arr[13], arr[14], arr[15]);
}
static void radar_init_para(void)
{
radar_dbg_para_t dbg_para;
dbg_para.times = RADAR_DEFAULT_TIMES;
dbg_para.loop = RADAR_DEFAULT_LOOP;
dbg_para.ant = RADAR_DEFAULT_ANT;
dbg_para.wave = RADAR_DEFAULT_WAVE;
dbg_para.dbg_type = RADAR_DEFAULT_DBG_TYPE;
dbg_para.period = RADAR_DEFAULT_PERIOD;
uapi_radar_set_debug_para(&dbg_para);
int16_t dly_time = RADAR_QUIT_DELAY_TIME;
uapi_radar_set_delay_time(dly_time);
radar_sel_para_t sel_para;
sel_para.height = RADAR_HEIGHT_2M;
sel_para.scenario = RADAR_SCENARIO_TYPE_HOME;
sel_para.material = RADAR_MATERIAL_SINGLE;
sel_para.fusion_track = true;
sel_para.fusion_ai = true;
uapi_radar_select_alg_para(&sel_para);
// 算法门限, 前三个使用tools/bin/radar_tool/radar_para_gen_tool工具标定, 后面五个使用本sample给出的默认值即可
radar_alg_para_t alg_para;
alg_para.d_th_1m = 32;
alg_para.d_th_2m = 25;
alg_para.p_th = 25;
alg_para.t_th_1m = 13;
alg_para.t_th_2m = 26;
alg_para.b_th_ratio = 20;
alg_para.b_th_cnt = 4;
alg_para.a_th = 70;
uapi_radar_set_alg_para(&alg_para, 0);
}
int radar_demo_init(void *param)
{
PRINT("[RADAR_SAMPLE] radar_demo_init sta!\r\n");
param = param;
// WiFi启动STA模式
radar_start_sta();
// 注册感知结果回调函数
uapi_radar_register_result_cb(radar_print_res);
uapi_radar_register_current_frame_result_cb(radar_print_cur_frame_res);
uapi_radar_register_debug_info_cb(radar_print_dbg_info, RADAR_DBG_INFO_RPT_COEF);
// 启动感知
(void)osDelay(WIFI_START_STA_DELAY);
uapi_radar_set_status(RADAR_STATUS_SET_START);
radar_init_para();
// 感知查询接口示例
while(1) {
(void)osDelay(RADAR_STATUS_QUERY_DELAY);
uint8_t sts;
uapi_radar_get_status(&sts);
uint16_t time;
uapi_radar_get_delay_time(&time);
uint16_t iso;
uapi_radar_get_isolation(&iso);
radar_result_t res = {0};
uapi_radar_get_result(&res);
radar_current_frame_result_t cur_frame_res = {0};
uapi_radar_get_current_frame_result(&cur_frame_res);
int16_t arr[RADAR_DBG_INFO_LEN] = {0};
uapi_radar_get_debug_info(arr, RADAR_DBG_INFO_LEN);
radar_print_dbg_info(arr, RADAR_DBG_INFO_LEN);
}
return 0;
}
注意事项
看门狗
WS63V100默认提供看门狗功能,看门狗功能是一个指定时间(可编程)的定时器,用于系统异常恢复,如果未得到更新则当定时器到期时会产生一个系统复位信号,当看门狗在到期之前关闭或进行踢狗动作(即刷新定时器),则不会产生复位信号。
看门狗提供接口如下表所示。
看门狗功能的作用是为了暴露业务中出现卡死或无意义死循环的问题,正常业务流程中应当周期性进行踢狗操作,而当业务异常卡死或进入死循环时,踢狗操作得不到调度,便会在看门狗时间到期后触发复位信号。
修改看门狗定时时间步骤如下:
调用uapi_watchdog_disable,去使能看门狗。(初始化时已默认使能)。
调用uapi_watchdog_set_time,设置定时时间。
调用uapi_watchdog_enable,重新使能看门狗。
踢狗步骤如下:
调用uapi_watchdog_kick,刷新看门狗定时器时间为设置的定时时间。
当前看门狗功能默认开启,定时时间为15s,仅在liteOS的IDLE线程中保留踢狗动作,因此在进行WiFi打流等较占用CPU和系统资源的上层应用场景下,IDLE线程可能无法得到调度,需要应用主动调用踢狗接口进行踢狗操作。
若不希望底层踢狗,存在上层业务喂狗需求,则可通过watchdog_port_idle_kick_register接口注册IDLE线程中踢狗动作函数,接管喂狗动作。watchdog_port_idle_kick_register函数需要包含drivers\chips\ws63\porting\liteos\riscv31\idle_config.h头文件。
IPERF打流业务功能(kernel/liteos/liteos_v207.0.0/Huawei_LiteOS/net/los_iperf/src/los_iperf.c)进行踢狗动作示例代码:
static void IperfFeedWdg(void)
{
UINT32 ret = LOS_HistoryTaskCpuUsage(OsGetIdleTaskId(), CPUP_LAST_ONE_SECONDS);
if (ret < IPERF_MIN_IDEL_RATE) {
uapi_watchdog_kick();
}
}
void IperfServerPhase2(IperfContext *context)
{
int32_t recvLen;
struct sockaddr peer;
struct sockaddr *from = &peer;
socklen_t slen = sizeof(struct sockaddr);
socklen_t *fromLen = &slen;
BOOL firstData = FALSE;
IperfUdpHdr *udpHdr = (IperfUdpHdr *)context->param.buffer;
#ifdef LOSCFG_NET_IPERF_JITTER
if (IPERF_IS_UDP(context->param.mask)) {
context->udpStat->lastID = -1;
}
#endif
while ((context->isFinish == FALSE) && (context->isKilled == FALSE)) {
recvLen = recvfrom(context->trafficSock, context->param.buffer,
context->param.bufLen, 0, from, fromLen);
if (recvLen < 0) {
if ((firstData == FALSE) && (errno == EAGAIN)) {
continue;
}
IPERF_PRINT("recv failed %d\r\n", errno);
break;
} else if (recvLen == 0) { /* tcp connection closed by peer side */
context->isFinish = TRUE;
break;
} else {
if (firstData == FALSE) {
firstData = TRUE;
IperfServerFirstDataProcess(context, from, *fromLen);
from = NULL;
fromLen = NULL;
}
context->param.total += (uint32_t)recvLen;
if (IperfServerDataProcess(context, (uint32_t)recvLen) && ((int32_t)ntohl(udpHdr->id) < 0)) {
context->isFinish = TRUE;
break;
}
UNUSED(udpHdr);
#ifdef IPERF_FEED_WDG
IperfFeedWdg();
#endif /* IPERF_FEED_WDG */
}
}
gettimeofday(&context->end, NULL);
}