Wi-Fi CSI 概述
Wi-Fi CSI (Channel State Information,信道状态信息)是一种用于描述无线信道特性的技术,旨在通过上报完整的 CSI 信息来量化无线现象(如干扰、多径、多普勒频移)在给定环境中对无线信号的总体影响。可用于人类活动分析、Wi-Fi 室内定位、手势识别等。
Realtek Wi-Fi CSI 根据 Realtek 设备(STA 模式或 SoftAP 模式)是否参与传输 CSI 触发帧分为 Active CSI 和 Passive CSI 两种方案。
Active CSI: Realtek 设备需要主动传输 CSI 触发帧
Active CSI 根据 CSI 触发帧的类型分为两种模式:单播模式和广播模式。具体信息参考 Active CSI: 单播模式 和 Active CSI: 广播模式.
Active CSI 使用 Public Action 帧作为 CSI 触发帧。
Passive CSI: Realtek 设备不要求传输 CSI 触发帧
具体信息参考 Passive CSI.
Active CSI: 单播模式
方法一: Realtek STA 向 AP 发送单播 CSI 触发帧,并通过解码上一 CSI 触发帧的 ACK 响应帧以获取采集 CSI(一对一通信)。
方法一衍生版: Realtek STA 向其他 STAx 设备发送单播 CSI 触发帧,并通过解码上一 CSI 触发帧的 ACK 响应帧以获取 CSI(通过轮询实现一对多通信)。
方法二: Realtek SoftAP 向关联设备发送单播 CSI 触发帧,并通过解码上一 CSI 触发帧的 ACK 响应帧以获取 CSI(通过轮询实现一对多通信)。
基于 ACK 响应报文的 CSI 采集(Rx Response Mode)
Active CSI: 广播模式
方法三: Realtek SoftAP 发送广播 CSI 触发帧,Realtek STAs 解码以获取 CSI。
方法四: 一个 Realtek STA 发送广播 CSI 触发帧,其他邻近 Realtek STAs 解码以获取 CSI。
基于广播报文的 CSI 采集(Rx Normal Mode)
Passive CSI
方法五: Realtek STA/SoftAP 通过对目标接收报文解码以获取 CSI(一对一通信)。
基于接收报文的 CSI 采集(Rx Normal Mode)
Wi-Fi CSI 架构
Wi-Fi CSI 功能主要由三个模块组成:
配置并启用 Wi-Fi CSI
应用程序必须调用 API 以按需配置 Wi-Fi CSI 参数,并启用 Wi-Fi CSI 功能。
启用 Wi-Fi CSI 功能后若弃用则应用程序必须调用 API 禁用 Wi-Fi CSI 功能。
注册/注销 Wi-Fi CSI 回调函数
启用 Wi-Fi CSI 时注册回调函数,Wi-Fi 驱动将通过该回调函数在每个 CSI 报文准备就绪时向应用程序发送通知标志。
禁用 Wi-Fi CSI 时注销回调函数。
上报 Wi-Fi CSI 数据
应用程序应运行独立线程以等待 Wi-Fi CSI 报文就绪标志,随后调用 API 读取 Wi-Fi CSI 报文。
Wi-Fi CSI 功能框架图
Wi-Fi CSI 相关 APIs
wifi_csi_config
函数原型:
int wifi_csi_config(struct _rtw_csi_action_parm_t *act_param)
用途: Wi-Fi CSI 参数配置和功能启停
act =
CSI_ACT_CFG
: 配置 Wi-Fi CSI 参数(如侦测频率、精度等)act =
CSI_ACT_EN
:启用/停用 Wi-Fi CSI 功能停用后操作:若需重新启用,需先调用
act = CSI_ACT_CFG
重新配置参数
参数定义
参数名 |
类型 |
描述 |
---|---|---|
group_num |
unsigned char |
指定 CSI 信息子载波抽取方式
|
accuracy |
unsigned char |
指定 CSI 原始数据 (CH I/Q) 精度
|
alg_opt |
unsigned char |
保留 |
ch_opt |
unsigned char |
配置 CSI 来源于解码传统训练序列部分还是非传统的训练序列部分 |
csi_role |
unsigned char |
指定使能 Wi-Fi CSI 的设备扮演的角色 |
mode |
unsigned char |
指定获取 Wi-Fi CSI 的模式
|
act |
unsigned char |
用以区分 Wi-Fi CSI 参数配置和启用/停用 W-Fi CSI 功能 |
trig_frame_mgnt |
unsigned short |
指定 CSI 触发帧的管理帧类型 (用于 Rx Normal Mode,Rx Response Mode 下无效) |
trig_frame_ctrl |
unsigned short |
指定 CSI 触发帧的控制帧类型 (用于 Rx Normal Mode,Rx Response Mode 下无效) |
trig_frame_data |
unsigned short |
指定 CSI 触发帧的数据帧类型 (用于 Rx Normal Mode,Rx Response Mode 下无效) |
enable |
unsigned char |
|
trig_period |
unsigned char |
Wi-Fi CSI 侦测频率,单位: 320us (建议值: 15~255) |
data_rate |
unsigned char |
指定 CSI 触发帧的传输速率,但在 Rx Response Mode 中无效,因为 Wi-Fi CSI 取决于 ACK 响应帧的速率
|
data_bw |
unsigned char |
指定 CSI 触发帧的带宽
|
mac_addr[6] |
unsigned char |
指定 CSI 触发帧的目的地址
|
multi_type |
unsigned char |
指定 CSI 触发帧是单播还是广播,仅在 Active CSI 中有效
|
trig_flag |
unsigned char |
方法四中作为传输 CSI 触发帧角色的标识符,方法一衍生版中作为传输 ACK 响应帧角色的标识符,其他保留
|
参数名 |
类型 |
描述 |
---|---|---|
group_num |
unsigned char |
指定 CSI 信息子载波抽取方式
|
accuracy |
unsigned char |
指定 CSI 原始数据 (CH I/Q) 精度
|
alg_opt |
unsigned char |
保留 |
ch_opt |
unsigned char |
配置 CSI 来源于解码传统训练序列部分还是非传统的训练序列部分 |
csi_role |
unsigned char |
指定使能 Wi-Fi CSI 的设备扮演的角色 |
mode |
unsigned char |
指定获取 Wi-Fi CSI 的模式
|
act |
unsigned char |
用以区分 Wi-Fi CSI 参数配置和启用/停用 W-Fi CSI 功能 |
trig_frame_mgnt |
unsigned short |
指定 CSI 触发帧的管理帧类型 (用于 Rx Normal Mode,Rx Response Mode 下无效) |
trig_frame_ctrl |
unsigned short |
指定 CSI 触发帧的控制帧类型 (用于 Rx Normal Mode,Rx Response Mode 下无效) |
trig_frame_data |
unsigned short |
指定 CSI 触发帧的数据帧类型 (用于 Rx Normal Mode,Rx Response Mode 下无效) |
enable |
unsigned char |
|
trig_period |
unsigned char |
Wi-Fi CSI 侦测频率,单位: 320us (建议值: 15~255) |
data_rate |
unsigned char |
指定 CSI 触发帧的传输速率,但在 Rx Response Mode 中无效,因为 Wi-Fi CSI 取决于 ACK 响应帧的速率
|
data_bw |
unsigned char |
指定 CSI 触发帧的带宽,仅支持 20MHz
|
mac_addr[6] |
unsigned char |
指定 CSI 触发帧的目的地址
|
multi_type |
unsigned char |
指定 CSI 触发帧是单播还是广播,仅在 Active CSI 中有效
|
trig_flag |
unsigned char |
方法四中作为传输 CSI 触发帧角色的标识符,方法一衍生版中作为传输 ACK 响应帧角色的标识符,其他保留
|
参数名 |
类型 |
描述 |
---|---|---|
group_num |
unsigned char |
指定 CSI 信息子载波抽取方式
|
accuracy |
unsigned char |
指定 CSI 原始数据 (CH I/Q) 精度
|
alg_opt |
unsigned char |
保留 |
ch_opt |
unsigned char |
配置 CSI 来源于解码传统训练序列部分还是非传统的训练序列部分 |
csi_role |
unsigned char |
指定使能 Wi-Fi CSI 的设备扮演的角色 |
mode |
unsigned char |
指定获取 Wi-Fi CSI 的模式
|
act |
unsigned char |
用以区分 Wi-Fi CSI 参数配置和启用/停用 W-Fi CSI 功能 |
trig_frame_mgnt |
unsigned short |
指定 CSI 触发帧的管理帧类型 (用于 Rx Normal Mode,Rx Response Mode 下无效) |
trig_frame_ctrl |
unsigned short |
指定 CSI 触发帧的控制帧类型 (用于 Rx Normal Mode,Rx Response Mode 下无效) |
trig_frame_data |
unsigned short |
指定 CSI 触发帧的数据帧类型 (用于 Rx Normal Mode,Rx Response Mode 下无效) |
enable |
unsigned char |
|
trig_period |
unsigned char |
Wi-Fi CSI 侦测频率,单位: 320us (建议值: 15~255) |
data_rate |
unsigned char |
指定 CSI 触发帧的传输速率,但在 Rx Response Mode 中无效,因为 Wi-Fi CSI 取决于 ACK 响应帧的速率
|
data_bw |
unsigned char |
指定 CSI 触发帧的带宽,仅支持 20MHz
|
mac_addr[6] |
unsigned char |
指定 CSI 触发帧的目的地址
|
multi_type |
unsigned char |
指定 CSI 触发帧是单播还是广播,仅在 Active CSI 中有效
|
trig_flag |
unsigned char |
方法四中作为传输 CSI 触发帧角色的标识符,方法一衍生版中作为传输 ACK 响应帧角色的标识符,其他保留
|
参数名 |
类型 |
描述 |
---|---|---|
group_num |
unsigned char |
指定 CSI 信息子载波抽取方式
|
accuracy |
unsigned char |
指定 CSI 原始数据 (CH I/Q) 精度
|
alg_opt |
unsigned char |
保留 |
ch_opt |
unsigned char |
配置 CSI 来源于解码传统训练序列部分还是非传统的训练序列部分 |
csi_role |
unsigned char |
指定使能 Wi-Fi CSI 的设备扮演的角色 |
mode |
unsigned char |
指定获取 Wi-Fi CSI 的模式
|
act |
unsigned char |
用以区分 Wi-Fi CSI 参数配置和启用/停用 W-Fi CSI 功能 |
trig_frame_mgnt |
unsigned short |
指定 CSI 触发帧的管理帧类型 (用于 Rx Normal Mode,Rx Response Mode 下无效) |
trig_frame_ctrl |
unsigned short |
指定 CSI 触发帧的控制帧类型 (用于 Rx Normal Mode,Rx Response Mode 下无效) |
trig_frame_data |
unsigned short |
指定 CSI 触发帧的数据帧类型 (用于 Rx Normal Mode,Rx Response Mode 下无效) |
enable |
unsigned char |
|
trig_period |
unsigned char |
Wi-Fi CSI 侦测频率,单位: 320us (建议值: 15~255) |
data_rate |
unsigned char |
指定 CSI 触发帧的传输速率,但在 Rx Response Mode 中无效,因为 Wi-Fi CSI 取决于 ACK 响应帧的速率
|
data_bw |
unsigned char |
指定 CSI 触发帧的带宽,仅支持 20MHz
|
mac_addr[6] |
unsigned char |
指定 CSI 触发帧的目的地址
|
multi_type |
unsigned char |
指定 CSI 触发帧是单播还是广播,仅在 Active CSI 中有效
|
trig_flag |
unsigned char |
方法四中作为传输 CSI 触发帧角色的标识符,方法一衍生版中作为传输 ACK 响应帧角色的标识符,其他保留
|
参数取值
group_num
取值如下:/** * @brief csi group num. */ enum { CSI_GROUP_NUM_1 = 0, /**< per tone */ CSI_GROUP_NUM_2, /**< per 2tone */ CSI_GROUP_NUM_4, /**< per 4tone */ CSI_GROUP_NUM_8_16, /**< per 8tone for dplus; per 16tone for others */ CSI_GROUP_NUM_MAX };
accuracy
取值如下:/** * @brief csi accuracy. */ enum { CSI_ACCU_1BYTE = 0, /**< CSI_ACCU_1BYTE: S(8,3) for dplus and S(8,4) for others */ CSI_ACCU_2BYTES, /**< CSI_ACCU_2BYTE: S(16,11) for dplus and S(16,12) for others */ CSI_ACCU_MAX };
ch_opt
取值如下:/** * @brief csi ch_opt. */ enum { CSI_CH_LEGACY = 0, /**< legacy part(L-LTF) channel estmation result */ CSI_CH_NON_LEGACY, /**< non-legacy(HT-LTF) part */ CSI_CH_MAX };
csi_role
取值如下:/** * @brief csi csi_role. */ enum { CSI_OP_ROLE_TRX = 0, /**< both trx */ CSI_OP_ROLE_TX = 1, /**< only tx csi triggering frame */ CSI_OP_ROLE_RX = 2, /**< only rx csi triggering frame for fetching csi report */ CSI_OP_ROLE_MAX };
mode
取值如下:/** * @brief csi mode. */ enum { CSI_MODE_NORMAL = 0, /**< rx normal mode */ CSI_MODE_NDP, /**< rx ndp mode: not support */ CSI_MODE_RX_RESP, /**< rx response mode */ CSI_MODE_MAX, };
act
取值如下:/** * @brief csi enable or config. */ enum { CSI_ACT_EN, /**< enable or disable csi func */ CSI_ACT_CFG, /**< config csi parameters */ CSI_ACT_MAX };
trig_frame_mgnt
取值如下:/** * @brief csi trig management frame subtype. */ enum { CSI_TRIG_ASSOCREQ = BIT(0), CSI_TRIG_ASSOCRSP = BIT(1), CSI_TRIG_REASSOCREQ = BIT(2), CSI_TRIG_REASSOCRSP = BIT(3), CSI_TRIG_PROBEREQ = BIT(4), CSI_TRIG_PROBERSP = BIT(5), CSI_TRIG_BEACON = BIT(8), CSI_TRIG_ATIM = BIT(9), CSI_TRIG_DISASSOC = BIT(10), CSI_TRIG_AUTH = BIT(11), CSI_TRIG_DEAUTH = BIT(12), CSI_TRIG_ACTION = BIT(13) };
trig_frame_ctrl
取值如下:/** * @brief csi trig control frame subtype. */ enum { CSI_TRIG_TRIGGER = BIT(2), CSI_TRIG_BA = BIT(9), CSI_TRIG_PSPOLL = BIT(10), CSI_TRIG_RTS = BIT(11), CSI_TRIG_CTS = BIT(12), CSI_TRIG_ACK = BIT(13), CSI_TRIG_CFEND = BIT(14), CSI_TRIG_CFEND_CFACK = BIT(15) };
trig_frame_data
取值如下:/** * @brief csi trig data frame subtype. */ enum { CSI_TRIG_DATA = BIT(0), CSI_TRIG_DATA_CFACK = BIT(1), CSI_TRIG_DATA_CFPOLL = BIT(2), CSI_TRIG_DATA_CFACKPOLL = BIT(3), CSI_TRIG_DATA_NULL = BIT(4), CSI_TRIG_CF_ACK = BIT(5), CSI_TRIG_CF_POLL = BIT(6), CSI_TRIG_CF_ACKPOLL = BIT(7), CSI_TRIG_QOS_DATA = BIT(8), CSI_TRIG_QOS_DATA_NULL = BIT(12) };
data_rate
取值如下:/** * @brief The enumeration lists the BIT 7 HT Rate. */ enum { MGN_1M = 0x02, /**< 0x02 */ MGN_2M = 0x04, /**< 0x04 */ MGN_5_5M = 0x0B, /**< 0x0B */ MGN_6M = 0x0C, /**< 0x0C */ MGN_9M = 0x12, /**< 0x12 */ MGN_11M = 0x16, /**< 0x16 */ MGN_12M = 0x18, /**< 0x18 */ MGN_18M = 0x24, /**< 0x24 */ MGN_24M = 0x30, /**< 0x30 */ MGN_36M = 0x48, /**< 0x48 */ MGN_48M = 0x60, /**< 0x60 */ MGN_54M = 0x6C, /**< 0x6C */ MGN_MCS0 = 0x80, /**< 0x80 */ MGN_MCS1, /**< 0x81 */ MGN_MCS2, /**< 0x82 */ MGN_MCS3, /**< 0x83 */ MGN_MCS4, /**< 0x84 */ MGN_MCS5, /**< 0x85 */ MGN_MCS6, MGN_MCS7, MGN_UNKNOWN = 0x100 };
/** * @brief The enumeration lists the BIT 7 HT Rate. */ enum { MGN_1M = 0x02, /**< 0x02 */ MGN_2M = 0x04, /**< 0x04 */ MGN_5_5M = 0x0B, /**< 0x0B */ MGN_6M = 0x0C, /**< 0x0C */ MGN_9M = 0x12, /**< 0x12 */ MGN_11M = 0x16, /**< 0x16 */ MGN_12M = 0x18, /**< 0x18 */ MGN_18M = 0x24, /**< 0x24 */ MGN_24M = 0x30, /**< 0x30 */ MGN_36M = 0x48, /**< 0x48 */ MGN_48M = 0x60, /**< 0x60 */ MGN_54M = 0x6C, /**< 0x6C */ MGN_MCS0 = 0x80, /**< 0x80 */ MGN_MCS1, /**< 0x81 */ MGN_MCS2, /**< 0x82 */ MGN_MCS3, /**< 0x83 */ MGN_MCS4, /**< 0x84 */ MGN_MCS5, /**< 0x85 */ MGN_MCS6, MGN_MCS7, MGN_HE1SS_MCS0 = 0xD0, /**< 0xD0 */ MGN_HE1SS_MCS1, MGN_HE1SS_MCS2, MGN_HE1SS_MCS3, MGN_HE1SS_MCS4, MGN_HE1SS_MCS5, MGN_HE1SS_MCS6, MGN_HE1SS_MCS7, MGN_HE1SS_MCS8, MGN_HE1SS_MCS9, MGN_UNKNOWN = 0x100 };
/** * @brief The enumeration lists the BIT 7 HT Rate. */ enum { MGN_1M = 0x02, /**< 0x02 */ MGN_2M = 0x04, /**< 0x04 */ MGN_5_5M = 0x0B, /**< 0x0B */ MGN_6M = 0x0C, /**< 0x0C */ MGN_9M = 0x12, /**< 0x12 */ MGN_11M = 0x16, /**< 0x16 */ MGN_12M = 0x18, /**< 0x18 */ MGN_18M = 0x24, /**< 0x24 */ MGN_24M = 0x30, /**< 0x30 */ MGN_36M = 0x48, /**< 0x48 */ MGN_48M = 0x60, /**< 0x60 */ MGN_54M = 0x6C, /**< 0x6C */ MGN_MCS0 = 0x80, /**< 0x80 */ MGN_MCS1, /**< 0x81 */ MGN_MCS2, /**< 0x82 */ MGN_MCS3, /**< 0x83 */ MGN_MCS4, /**< 0x84 */ MGN_MCS5, /**< 0x85 */ MGN_MCS6, MGN_MCS7, MGN_HE1SS_MCS0 = 0xD0, /**< 0xD0 */ MGN_HE1SS_MCS1, MGN_HE1SS_MCS2, MGN_HE1SS_MCS3, MGN_HE1SS_MCS4, MGN_HE1SS_MCS5, MGN_HE1SS_MCS6, MGN_HE1SS_MCS7, MGN_HE1SS_MCS8, MGN_HE1SS_MCS9, MGN_UNKNOWN = 0x100 };
/** * @brief The enumeration lists the BIT 7 HT Rate. */ enum { MGN_1M = 0x02, /**< 0x02 */ MGN_2M = 0x04, /**< 0x04 */ MGN_5_5M = 0x0B, /**< 0x0B */ MGN_6M = 0x0C, /**< 0x0C */ MGN_9M = 0x12, /**< 0x12 */ MGN_11M = 0x16, /**< 0x16 */ MGN_12M = 0x18, /**< 0x18 */ MGN_18M = 0x24, /**< 0x24 */ MGN_24M = 0x30, /**< 0x30 */ MGN_36M = 0x48, /**< 0x48 */ MGN_48M = 0x60, /**< 0x60 */ MGN_54M = 0x6C, /**< 0x6C */ MGN_MCS0 = 0x80, /**< 0x80 */ MGN_MCS1, /**< 0x81 */ MGN_MCS2, /**< 0x82 */ MGN_MCS3, /**< 0x83 */ MGN_MCS4, /**< 0x84 */ MGN_MCS5, /**< 0x85 */ MGN_MCS6, MGN_MCS7, MGN_VHT1SS_MCS0 = 0xA0, /**< 0xA0 */ MGN_VHT1SS_MCS1, MGN_VHT1SS_MCS2, MGN_VHT1SS_MCS3, MGN_VHT1SS_MCS4, MGN_VHT1SS_MCS5, MGN_VHT1SS_MCS6, MGN_VHT1SS_MCS7, MGN_VHT1SS_MCS8, MGN_VHT1SS_MCS9, MGN_HE1SS_MCS0 = 0xD0, /**< 0xD0 */ MGN_HE1SS_MCS1, MGN_HE1SS_MCS2, MGN_HE1SS_MCS3, MGN_HE1SS_MCS4, MGN_HE1SS_MCS5, MGN_HE1SS_MCS6, MGN_HE1SS_MCS7, MGN_HE1SS_MCS8, MGN_HE1SS_MCS9, MGN_UNKNOWN = 0x100 };
wifi_csi_report
函数原型:
int wifi_csi_report(u32 buf_len, u8 *csi_buf, u32 *len)
用途: 获取 Wi-Fi CSI 报文(包括头部信息和原始数据)
参数定义
参数 |
类型 |
描述 |
---|---|---|
buf_len |
u32 |
应用程序指定存储 CSI 报文的缓冲区大小 |
csi_buf |
u8* |
应用程序指定存储 CSI 报文的缓冲区地址 |
len |
u32* |
CSI 原始数据大小 |
CSI 缓冲区布局
CSI 缓冲区分为两个部分: CSI 报文头部信息 和 CSI 原始数据。原始数据的大小由 CSI 报文头部信息中的 csi_data_length 字段指定。
CSI 缓冲区布局
CSI 报文头信息
CSI 报文头信息格式由一组按固定顺序排列的预定义字段构成,下图展示了 CSI 报文头信息的布局。
CSI 报文头信息格式
以下列表描述了各字段的定义:
子字段 |
大小(字节) |
定义 |
---|---|---|
csi_signature |
2 |
用于定位新的 CSI 报文的标识符,固定值 0xABCD |
hdr_len |
1 |
CSI 报文头信息长度(不包括 csi_signature 和 hdr_len) |
mac_addr |
6 |
设备 MAC 地址
|
trig_addr |
6 |
设备 MAC 地址
|
hw_assigned_timestamp |
4 |
CSI 时间戳,单位:微秒 |
csi_sequence |
4 |
CSI 报文序列号(方法四中无效) |
csi_data_length |
4 |
CSI 原始数据长度,单位:字节 |
csi_valid |
1 |
标识当前 CSI 原始数据是否有效 |
channel |
1 |
设备当前工作信道 |
bandwidth |
1 |
工作带宽
|
rx_rate |
1 |
获取 CSI 的无线报文的传输速率 |
protocol_mode |
1 |
获取 CSI 的无线报文的协议模式
|
num_sub_carrier |
2 |
CSI 原始数据的子载波数量 |
num_bit_per_tone |
1 |
CSI 报文的 I 和 Q 总字长 精度: S(8,X) 或 S(16,X) |
rssi[2] |
2 |
接收信号强度(dBm),rssi[1] 保留 |
evm[2] |
2 |
误差矢量幅度(dB),均保留 |
rxsc |
1 |
指示数据包传输使用的 20MHz 子信道 |
n_rx |
1 |
保留字段 |
n_sts |
1 |
保留字段 |
trig_flag |
1 |
指示触发 CSI 的源角色
|
rsvd |
5 |
保留字段 |
CSI 报文头信息和原始数据示例
如下是一组 CSI 报文缓存区内容和解译出来的 CSI 头部信息对比结果:
CSI 缓冲区数据和解析出来的 CSI 头信息比较图
CSI 原始数据布局
子载波索引与频段对应关系:-20MHz~0 对应 64:127, 0~20MHz 对应 0:63。
各模式子载波分布:
传统 20MHz 模式: 子载波索引 (102, 103, …, 127, 1, 2, …, 26)
非传统 20MHz 模式: 子载波索引 (100, 101, 102, 103, …, 127, 1, 2, …, 26, 27, 28)
传统 40MHz 模式: 子载波索引 (70, 71, …, 94, 95, 97, 98, …, 122, 6, 7, …, 30, 31, 33, 34, …, 57, 58)
非传统 40MHz 模式: 子载波索引 (71, 72, …, 127, 1, 2, …, 56, 57)
CSI原始数据示例(无抽样):20MHz
每个子载波包含 Nrx*Nsts 维 CSI 矩阵。以 VHT MIMO 1x2 矩阵为例(group_num
: 1 + accuracy
: 0), H 的排列顺序为 H11、 H12。对应的 CSI 原始数据布局如图所示:
CSI 原始数据布局图(无抽样)
CSI原始数据示例(带抽样):20MHz
每个子载波包含 Nrx*Nsts 维 CSI 矩阵。以 VHT MIMO 1x2 矩阵为例(group_num
: 3 + accuracy
: 0), H 的排列顺序为 H11、 H12。根据 tone_idx%group_num==0 的原则选择子载波索引。对应的 CSI 原始数据布局如图所示:
CSI 原始数据布局图(带抽样)
子载波索引与频段对应关系:0~20MHz 对应 0:63。
CSI原始数据示例(无抽样)
每个子载波包含 Nrx*Nsts 维 CSI 矩阵。以 HT MIMO 1x2 矩阵为例(group_num
: 1 + accuracy
: 0), H 的排列顺序为 H11、 H12。对应的 CSI 原始数据布局如图所示:
CSI 原始数据布局图(无抽样)
CSI原始数据示例(带抽样)
每个子载波包含 Nrx*Nsts 维 CSI 矩阵。以 HT MIMO 1x2 矩阵为例(group_num
: 3 + accuracy
: 0), H 的排列顺序为 H11、 H12。总的子载波数为 ceil((tone_num/2)/group_num) * 2 = ceil(56/2/16)*2 = 4。对应的 CSI 原始数据布局如图所示:
CSI 原始数据布局图(带抽样)
子载波索引与频段对应关系:0~20MHz 对应 0:63。
CSI原始数据示例(无抽样)
每个子载波包含 Nrx*Nsts 维 CSI 矩阵。以 HT MIMO 1x2 矩阵为例(group_num
: 1 + accuracy
: 0), H 的排列顺序为 H11、 H12。对应的 CSI 原始数据布局如图所示:
CSI 原始数据布局图(无抽样)
CSI原始数据示例(带抽样)
每个子载波包含 Nrx*Nsts 维 CSI 矩阵。以 HT MIMO 1x2 矩阵为例(group_num
: 3 + accuracy
: 0), H 的排列顺序为 H11、 H12。总的子载波数为 ceil((tone_num/2)/group_num) * 2 = ceil(56/2/16)*2 = 4。对应的 CSI 原始数据布局如图所示:
CSI 原始数据布局图(带抽样)
子载波索引与频段对应关系:0~20MHz 对应 0:63。
CSI原始数据示例(无抽样)
每个子载波包含 Nrx*Nsts 维 CSI 矩阵。以 HT MIMO 1x2 矩阵为例(group_num
: 1 + accuracy
: 0), H 的排列顺序为 H11、 H12。对应的 CSI 原始数据布局如图所示:
CSI 原始数据布局图(无抽样)
CSI原始数据示例(带抽样)
每个子载波包含 Nrx*Nsts 维 CSI 矩阵。以 HT MIMO 1x2 矩阵为例(group_num
: 3 + accuracy
: 0), H 的排列顺序为 H11、 H12。总的子载波数为 ceil((tone_num/2)/group_num) * 2 = ceil(56/2/16)*2 = 4。对应的 CSI 原始数据布局如图所示:
CSI 原始数据布局图(带抽样)
CSI 原始数据子载波数目
BW |
1 |
1/2 |
1/4 |
1/8 |
|
---|---|---|---|---|---|
Non-HT |
20M |
52 |
26 |
12 |
6 |
HT |
20M |
56 |
28 |
14 |
6 |
VHT |
20M |
56 |
28 |
14 |
6 |
Non-HT |
40M |
104 |
52 |
24 |
12 |
HT |
40M |
114 |
56 |
28 |
14 |
VHT |
40M |
114 |
56 |
28 |
14 |
1 |
1/2 |
1/4 |
1/16 |
|
---|---|---|---|---|
Non-HT |
52 |
26 |
14 |
4 |
HT |
56 |
28 |
14 |
4 |
HE |
242 |
122 |
62 |
16 |
1 |
1/2 |
1/4 |
1/16 |
|
---|---|---|---|---|
Non-HT |
52 |
26 |
14 |
4 |
HT |
56 |
28 |
14 |
4 |
HE |
242 |
122 |
62 |
16 |
1 |
1/2 |
1/4 |
1/16 |
|
---|---|---|---|---|
Non-HT |
52 |
26 |
14 |
4 |
HT |
56 |
28 |
14 |
4 |
VHT |
56 |
28 |
14 |
4 |
HE |
242 |
122 |
62 |
16 |
wifi_reg_event_handler
函数原型:
void wifi_reg_event_handler(unsigned int event_cmds, void (*handler_func)(char *buf, int len, int flag, void *user_data), void *handler_user_data)
用途:注册回调函数
- event_cmds:
输入参数,无符号整型,Wi-Fi CSI 功能下赋值为
WIFI_EVENT_CSI_DONE
- handler_func:
输入参数,函数指针类型,需绑定具体的函数名
- handler_user_data:
输入参数,空指针类型,一般指向用户数据,通常设定为
NULL
示例如下:
/* 回调函数示例 */ void example_callback_func(char *buf, int buf_len, int flags, void *userdata) { UNUSED(buf); UNUSED(buf_len); UNUSED(flags); UNUSED(userdata); /* 函数相关处理动作 */ return; } /* 注册 Wi-Fi 事件回调函数 */ wifi_reg_event_handler(Element_ID, example_callback_func, NULL);
wifi_unreg_event_handler
函数原型:
void wifi_unreg_event_handler(unsigned int event_cmds, void (*handler_func)(char *buf, int len, int flag, void *user_data))
用途:释放已注册的回调函数
- event_cmds:
输入参数,无符号整型,Wi-Fi CSI 功能下赋值为
WIFI_EVENT_CSI_DONE
- handler_func:
输入参数,函数指针类型,需绑定具体的函数名
示例如下:
/* 释放 Wi-Fi 事件回调函数 */ wifi_unreg_event_handler(WIFI_EVENT_CSI_DONE, example_callback_func);
Wi-Fi CSI 使用须知
基本要求
不同 CSI 方法的参数配置请依照 基于 ACK 响应报文的 CSI 采集(Rx Response Mode), 基于广播报文的 CSI 采集(Rx Normal Mode) 和 基于接收报文的 CSI 采集(Rx Normal Mode) 中示例进行。
启用 Wi-Fi CSI 功能前必须 关闭省电模式。
关闭省电模式方法:定位到
component/soc/amebaxxx/usrcfg/ameba_wificfg.c
目录,找到函数wifi_set_user_config()
后修改如下:wifi_user_config.lps_enable = 0; wifi_user_config.lps_mode = PS_MODE_ACTIVE;
必需参数: data_rate 且要求设置为 OFDM 速率及以上。
可选参数: group_num, accuarcy, ch_opt, csi_role, trig_period, data_bw, trig_frame_xx, trig_flag, multi_type, 按照需求配置即可。
方法四设计考量
方法一, 方法二, 方法三 和 方法五 属于基础设施模式下 STA 和 AP 之间的正常交互,Realtek 驱动软件将遵循无线协议标准来构造 CSI 触发帧的 MAC 地址。
例如:如果 Ameba 芯片作为 STA 角色,无线协议标准定义的帧格式如下图所示:
基础设施模式下 STA 和 AP 之间的交互
然而, 方法四 为基础设施模式下 STAs 之间的交互,并不完全兼容无线协议标准。为了保证其他 STAs 可以收下来自目标 STA 的数据报文,Ameba 芯片将会伪造 CSI 触发帧,通过修改 CSI 触发帧的地址字段为 A1=broadcast address
和 A2=BSSID
以保证 Realtek 接收设备的 MAC 层不会将其过滤掉。
备注
只有 Realtek MAC 层接收到这笔封包后才会触发 CSI 电路获取 CSI 报文。
基础设施模式下 STA 和 STA 之间的交互
其次 方法四 还存在一个问题,如上图所示 Ameba2 接收到的来自 Ameba3 和 Ameba1 的无线报文具有完全相同的内容,所以 Ameba2 不能区分这笔无线报文触发的 CSI 报文属于 Ameba1 还是 Ameba3。为了解决这一问题,我们将唯一标识符 trig_flag
写入无线报文序列控制字段的“片段号”子栏位,未来这个标识符将会携带在 CSI 报文中,应用程序将可以根据 trig_flag
区分该笔 CSI 报文属于哪一个设备。
trig_flag 和 STAx 的映射关系
编译 Wi-Fi CSI 固件
导航至
{SDK}/amebaxxx_gcc_project
目录执行以下指令:./menuconfig.py
找到
,选择 后保存退出。----Connectivity config---- CONFIG WHC INTF ---> CONFIG WIFI ---> SDK MODE (NORMAL INIC) ---> [ ] Enable WPS [*] Enable CSI [ ] Enable ANTDIV --- CONFIG BT ---> ... --->
再次定位到
{SDK}/amebaxxx_gcc_project
目录并执行以下指令:./build.py -p -a wifi_csi /* compile image with Wi-Fi CSI example */ ./build.py -p /* compile image without Wi-Fi CSI example */
编译结束后固件(xxx_app.bin & xxx_boot_all.bin)可以在 {SDK}/amebaxxx_gcc_project
目录下找到。
Wi-Fi CSI 应用示例
本节描述了 Wi-Fi CSI 示例的框架和实现细节。CSI 示例文件路径为 {SDK}\component\example\wifi\wifi_csi
。
Wi-Fi CSI 示例概述
Wi-Fi CSI 示例实现框图
Wi-Fi CSI 示例详解
示例如何嵌入 Ameba SDK 以及如何编译他们可参考 应用示例,下面详述 Wi-Fi CSI 示例的具体实现。
示例初始化
app_example()
中定义了 Wi-Fi CSI 示例的入口函数。
void app_example(void)
{
example_wifi_csi(); /* 调用 Wi-Fi CSI 示例的入口函数 */
}
Wi-Fi CSI 入口函数
Wi-Fi CSI 示例入口函数执行后创建了一个 CSI 处理线程。
void example_wifi_csi(void)
{
if (rtos_task_create(NULL, ((const char *)"wifi_csi_thread"), wifi_csi_thread, NULL, 1024 * 4, 0) != SUCCESS) {
RTK_LOGA(NOTAG, "\n\r%s rtos_task_create(wifi_csi_thread) failed", __FUNCTION__);
}
return;
}
Wi-Fi CSI 处理线程
等待 Wi-Fi 上电并且连线成功。
如果启用 Softap 角色,无论 STA 角色是否处于连线状态,Wi-Fi CSI 只会由 Softap 角色发起。等到其它设备关联上 Softap 角色后选择第一台连上该 Softap 的设备与之启用 Wi-Fi CSI 功能。
如果没有其他设备关联上 Softap 角色,执行
rtos_time_delay_ms(2000)
。如果未启用 Softap 角色,将会在 STA 角色关联上 realAP 后启用 Wi-Fi CSI 功能。
如果 STA 角色未连线成功,执行
rtos_time_delay_ms(2000)
。
while (1) { NEXT: if (wifi_is_running(SOFTAP_WLAN_INDEX)) { wifi_get_associated_client_list(&client_info); if (client_info.count) { memcpy(act_param.mac_addr, client_info.mac_list[0].octet, 6); RTK_LOGA(NOTAG, "### SOFTAP Break ###\r\n"); break; } rtos_time_delay_ms(2000); /* 2s */ goto NEXT; } if (wifi_is_running(STA_WLAN_INDEX) && (wifi_get_join_status() == RTW_JOINSTATUS_SUCCESS) && (*(u32 *)LwIP_GetIP(0) != IP_ADDR_INVALID)) { rtos_time_delay_ms(2000); /* 2s */ RTK_LOGA(NOTAG, "### STA Break ###\r\n"); break; } rtos_time_delay_ms(2000); /* 2s */ }
注册一个 Wi-Fi CSI 回调函数
example_wifi_csi_report_cb()
。/* 注册 Wi-Fi 事件回调函数 */ wifi_reg_event_handler(WIFI_EVENT_CSI_DONE, example_wifi_csi_report_cb, NULL);
初始化一个信号量
wc_ready_sema
,并使用改信号量来指示 Wi-Fi CSI 事件的发生。/** * 建议使用信号量来指示 Wi-Fi 事件的发生,示例使用信号量 wc_ready_sema 来标识 Wi-Fi CSI 报文准备就绪 */ rtos_sema_create(&wc_ready_sema, 0, 0xFFFFFFFF); if (!wc_ready_sema) { RTK_LOGE(NOTAG, "\r\nInit wc_ready_sema failed\r\n\n"); }
Wi-Fi CSI 相关参数进行赋值(示例给出 方法一/方法二 的配置)。
/* Wi-Fi CSI 参数赋值 */ act_param.group_num = CSI_GROUP_NUM_1; act_param.mode = CSI_MODE_RX_RESP; act_param.accuracy = CSI_ACCU_1BYTE; act_param.trig_period = 200; /* 单位: 320 微秒 */ act_param.data_rate = MGN_6M; /* OFDM 6 Mbps */ act_param.trig_frame_mgnt = 0; /* Rx Resp Mode 无需配置,默认设 0 */ act_param.trig_frame_ctrl = 0; /* Rx Resp Mode 无需配置,默认设 0 */ act_param.trig_frame_data = 0; /* Rx Resp Mode 无需配置,默认设 0 */ act_param.csi_role = CSI_OP_ROLE_TRX;
配置参数并启用 Wi-Fi CSI 功能。
/* Wi-Fi CSI 参数配置和功能启用 */ act_param.act = CSI_ACT_CFG; /* 参数配置 */ wifi_csi_config(&act_param); act_param.act = CSI_ACT_EN; /* 功能启用 */ act_param.enable = 1; wifi_csi_config(&act_param);
等待信号量
wc_ready_sema
就绪后调用 APIwifi_csi_report()
获取 Wi-Fi CSI 报文。while (1) { /* 示例:获取到 Wi-Fi CSI 报文后,针对报文做一些相关处理 */ if (rtos_sema_take(wc_ready_sema, 0xFFFFFFFF) != SUCCESS) { rtos_sema_delete(wc_ready_sema); act_param.act = CSI_ACT_EN; /* csi dis */ act_param.enable = 0; wifi_csi_config(&act_param); break; } csi_buf = rtos_mem_malloc(csi_data_len); if (csi_buf != NULL) { wifi_csi_report(csi_data_len, csi_buf, &len); /* Wi-Fi CSI 报文处理:例如数据打印 */ wifi_csi_show(csi_buf); } else { RTK_LOGE(NOTAG, "\r\n csi_buf malloc fail\r\n"); } if (csi_buf != NULL) { rtos_mem_free(csi_buf); } }
结束
停用 Wi-Fi CSI 并释放 Wi-Fi CSI 回调函数
销毁信号量
wc_ready_sema
任务删除
/* 释放 Wi-Fi 事件回调函数 */ wifi_unreg_event_handler(WIFI_EVENT_CSI_DONE, example_wifi_csi_report_cb); if (wc_ready_sema) { rtos_sema_delete(wc_ready_sema); } rtos_task_delete(NULL);
Wi-Fi CSI 回调函数
当 Wi-Fi 驱动程序准备好一笔 CSI 报文后,将会借助 Wi-Fi CSI 回调函数向应用程序发送一个信号。例如,应用程序可以在回调函数中释放一个信号量以触发 wifi_csi_thread()
来获取 Wi-Fi CSI 报文。
备注
尽量避免回调函数中进行大量耗时的操作,否则会影响到接收性能。
应用程序可以使用参数
flags
,这个参数指示 Wi-Fi CSI 报文的大小。
void example_wifi_csi_report_cb(char *buf, int buf_len, int flags, void *userdata)
{
(void)buf;
(void)buf_len;
(void)userdata;
rtos_sema_give(wc_ready_sema); /* 触发线程执行 */
csi_data_len = flags; /* 应用程序参考 flags 来申请缓存大小 */
return;
}