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 触发帧

  • Passive CSI: Realtek 设备不要求传输 CSI 触发帧

Active CSI: 单播模式

  • 方法一: Realtek STA 向 AP 发送单播 CSI 触发帧,并通过解码上一 CSI 触发帧的 ACK 响应帧以获取采集 CSI(一对一通信)。

  • 方法一衍生版: Realtek STA 向其他 STAx 设备发送单播 CSI 触发帧,并通过解码上一 CSI 触发帧的 ACK 响应帧以获取 CSI(通过轮询实现一对多通信)。

  • 方法二: Realtek SoftAP 向关联设备发送单播 CSI 触发帧,并通过解码上一 CSI 触发帧的 ACK 响应帧以获取 CSI(通过轮询实现一对多通信)。

../../_images/collecting_csi_from_rx_ack_packet_response_mode.svg

基于 ACK 响应报文的 CSI 采集(Rx Response Mode)

Active CSI: 广播模式

  • 方法三: Realtek SoftAP 发送广播 CSI 触发帧,Realtek STAs 解码以获取 CSI。

  • 方法四: 一个 Realtek STA 发送广播 CSI 触发帧,其他邻近 Realtek STAs 解码以获取 CSI。

../../_images/collecting_csi_from_rx_broadcast_packet_normal_mode.svg

基于广播报文的 CSI 采集(Rx Normal Mode)

Passive CSI

  • 方法五: Realtek STA/SoftAP 通过对目标接收报文解码以获取 CSI(一对一通信)。

../../_images/collecting_csi_from_rx_packet_normal_mode.svg

基于接收报文的 CSI 采集(Rx Normal Mode)

Wi-Fi CSI 架构

Wi-Fi CSI 功能主要由三个模块组成:

  1. 配置并启用 Wi-Fi CSI

    • 应用程序必须调用 API 以按需配置 Wi-Fi CSI 参数,并启用 Wi-Fi CSI 功能。

    • 启用 Wi-Fi CSI 功能后若弃用则应用程序必须调用 API 禁用 Wi-Fi CSI 功能。

  2. 注册/注销 Wi-Fi CSI 回调函数

    • 启用 Wi-Fi CSI 时注册回调函数,Wi-Fi 驱动将通过该回调函数在每个 CSI 报文准备就绪时向应用程序发送通知标志。

    • 禁用 Wi-Fi CSI 时注销回调函数。

  3. 上报 Wi-Fi CSI 数据

    • 应用程序应运行独立线程以等待 Wi-Fi CSI 报文就绪标志,随后调用 API 读取 Wi-Fi CSI 报文。

../../_images/csi_architecture.svg

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 信息子载波抽取方式

  • 0: 逐个子载波数据获取

  • 1: 每两个子载波抽取一组数据

  • 2: 每四个子载波抽取一组数据

  • 3: 每八个子载波抽取一组数据

accuracy

unsigned char

指定 CSI 原始数据 (CH I/Q) 精度

  • 0: S(8,3) → 有符号数,8 位总长(3 位小数)

  • 1: S(16,11) → 有符号数,16 位总长(11 位小数)

alg_opt

unsigned char

保留

ch_opt

unsigned char

配置 CSI 来源于解码传统训练序列部分还是非传统的训练序列部分

csi_role

unsigned char

指定使能 Wi-Fi CSI 的设备扮演的角色

mode

unsigned char

指定获取 Wi-Fi CSI 的模式

  • 0: Rx Normal Mode (通过解码当前收到的报文以获取 CSI)

  • 2: Rx Response Mode (通过解码上一 CSI 触发帧的 ACK 报文以获取 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

  • 0: 停用 Wi-Fi CSI 功能

  • 1: 启用 Wi-Fi CSI 功能

trig_period

unsigned char

Wi-Fi CSI 侦测频率,单位: 320us (建议值: 15~255)

data_rate

unsigned char

指定 CSI 触发帧的传输速率,但在 Rx Response Mode 中无效,因为 Wi-Fi CSI 取决于 ACK 响应帧的速率

  • 仅支持 OFDM/HT 速率

data_bw

unsigned char

指定 CSI 触发帧的带宽

  • 0: 20MHz

  • 1: 40MHz

  • 其他:保留

mac_addr[6]

unsigned char

指定 CSI 触发帧的目的地址

  • 如果 multi_type 等于 1, 则 mac_addr 保留。

multi_type

unsigned char

指定 CSI 触发帧是单播还是广播,仅在 Active CSI 中有效

  • 0: 单播 (使用单播帧且通过解码单播帧的 ACK 报文以获取 CSI)

  • 1: 广播 (使用广播帧且另一方通过解码该广播帧以获取 CSI )

trig_flag

unsigned char

方法四中作为传输 CSI 触发帧角色的标识符,方法一衍生版中作为传输 ACK 响应帧角色的标识符,其他保留

  • 取值范围:1 ~ 15 (0 保留)

参数取值

  • 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
    };
    

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 字段指定。

../../_images/csi_buffer_layout.svg

CSI 缓冲区布局

CSI 报文头信息

CSI 报文头信息格式由一组按固定顺序排列的预定义字段构成,下图展示了 CSI 报文头信息的布局。

../../_images/csi_header_information_format.svg

CSI 报文头信息格式

以下列表描述了各字段的定义:

子字段

大小(字节)

定义

csi_signature

2

用于定位新的 CSI 报文的标识符,固定值 0xABCD

hdr_len

1

CSI 报文头信息长度(不包括 csi_signaturehdr_len

mac_addr

6

设备 MAC 地址

  • Active CSI 中表示 CSI 触发帧的发射地址

  • Passive CSI 中表示 CSI 触发帧的接收地址

trig_addr

6

设备 MAC 地址

  • Active CSI 中表示 CSI 触发帧的目的地址

  • Passive CSI 中表示 CSI 触发帧的源地址

  • 方法四保留

hw_assigned_timestamp

4

CSI 时间戳,单位:微秒

csi_sequence

4

CSI 报文序列号(方法四中无效)

csi_data_length

4

CSI 原始数据长度,单位:字节

csi_valid

1

标识当前 CSI 原始数据是否有效

channel

1

设备当前工作信道

bandwidth

1

工作带宽

  • 0: 20MHz

  • 1: 40MHz

rx_rate

1

获取 CSI 的无线报文的传输速率

protocol_mode

1

获取 CSI 的无线报文的协议模式

  • 0: OFDM

  • 1: HT

  • 2: VHT

  • 3: HE

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 头部信息对比结果:

../../_images/comparison_between_parsed_csi_header_information_data_and_csi_buffer_data.svg

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 原始数据布局如图所示:

../../_images/csi_raw_data_layout_without_decimation_dplus.svg

CSI 原始数据布局图(无抽样)

CSI原始数据示例(带抽样):20MHz

每个子载波包含 Nrx*Nsts 维 CSI 矩阵。以 VHT MIMO 1x2 矩阵为例(group_num: 3 + accuracy: 0), H 的排列顺序为 H11、 H12。根据 tone_idx%group_num==0 的原则选择子载波索引。对应的 CSI 原始数据布局如图所示:

../../_images/csi_raw_data_layout_with_decimation_dplus.svg

CSI 原始数据布局图(带抽样)

CSI 原始数据子载波数目

{N_tone(BW) * group_num}

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

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 使用须知

基本要求

方法四设计考量

方法一方法二方法三方法五 属于基础设施模式下 STA 和 AP 之间的正常交互,Realtek 驱动软件将遵循无线协议标准来构造 CSI 触发帧的 MAC 地址。

例如:如果 Ameba 芯片作为 STA 角色,无线协议标准定义的帧格式如下图所示:

../../_images/interaction_between_sta_and_ap_infrastructure_mode.svg

基础设施模式下 STA 和 AP 之间的交互

然而, 方法四 为基础设施模式下 STAs 之间的交互,并不完全兼容无线协议标准。为了保证其他 STAs 可以收下来自目标 STA 的数据报文,Ameba 芯片将会伪造 CSI 触发帧,通过修改 CSI 触发帧的地址字段为 A1=broadcast addressA2=BSSID 以保证 Realtek 接收设备的 MAC 层不会将其过滤掉。

备注

只有 Realtek MAC 层接收到这笔封包后才会触发 CSI 电路获取 CSI 报文。

../../_images/interaction_between_sta_and_sta_infrastructure_mode.svg

基础设施模式下 STA 和 STA 之间的交互

其次 方法四 还存在一个问题,如上图所示 Ameba2 接收到的来自 Ameba3 和 Ameba1 的无线报文具有完全相同的内容,所以 Ameba2 不能区分这笔无线报文触发的 CSI 报文属于 Ameba1 还是 Ameba3。为了解决这一问题,我们将唯一标识符 trig_flag 写入无线报文序列控制字段的“片段号”子栏位,未来这个标识符将会携带在 CSI 报文中,应用程序将可以根据 trig_flag 区分该笔 CSI 报文属于哪一个设备。

../../_images/mapping_trig_flag_with_sta.svg

trig_flag 和 STAx 的映射关系

编译 Wi-Fi CSI 固件

  1. 导航至 {SDK}/amebaxxx_gcc_project 目录执行以下指令:

    ./menuconfig.py
    
  2. 找到 CONFIG WIFI > Enable CSI,选择 Enable CSI 后保存退出。

    ----Connectivity config----
        CONFIG WHC INTF --->
        CONFIG WIFI --->
                 SDK MODE (NORMAL INIC)  --->
          [ ]    Enable WPS
          [*]    Enable CSI
          [ ]    Enable ANTDIV
          ---
        CONFIG BT --->
        ... --->
    
  3. 再次定位到 {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 示例概述

../../_images/csi_example_flowchart.svg

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 处理线程

  1. 等待 Wi-Fi 上电并且连线成功。

    1. 如果启用 Softap 角色,无论 STA 角色是否处于连线状态,Wi-Fi CSI 只会由 Softap 角色发起。等到其它设备关联上 Softap 角色后选择第一台连上该 Softap 的设备与之启用 Wi-Fi CSI 功能。

      如果没有其他设备关联上 Softap 角色,执行 rtos_time_delay_ms(2000)

    2. 如果未启用 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 */
    }
    
  2. 注册一个 Wi-Fi CSI 回调函数 example_wifi_csi_report_cb()

    /* 注册 Wi-Fi 事件回调函数 */
    wifi_reg_event_handler(WIFI_EVENT_CSI_DONE, example_wifi_csi_report_cb, NULL);
    
  3. 初始化一个信号量 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");
    }
    
  4. 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;
    
  5. 配置参数并启用 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);
    
  6. 等待信号量 wc_ready_sema 就绪后调用 API wifi_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);
       }
    }
    
  7. 结束

    1. 停用 Wi-Fi CSI 并释放 Wi-Fi CSI 回调函数

    2. 销毁信号量 wc_ready_sema

    3. 任务删除

    /* 释放 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;
}