- 通信
- 网络
- 硬件开发
- 嵌入式
【免费下载链接】openwifi
open-source IEEE 802.11 WiFi baseband FPGA (chip) design: driver, software
openwifi 在传统 CSI(Channel State Information,信道状态信息)概念之上做了巧妙的语义扩展,将其延伸为Chip State Information(芯片状态信息),通过 FPGA 内置的side channel(侧信道)基础设施,把 WiFi OFDM 接收机在解码每个数据包时产生的频率偏移、信道响应(Channel State/Response)与均衡器输出实时导流到上位机。本文基于 doc/app_notes/csi.md 应用笔记,结合 driver/side_ch/ 内核驱动与 user_space/side_ch_ctl_src/ 用户态工具源码,完整讲解 CSI 的快速上手、数据格式、条件捕获配置、均衡器输出数量(num_eq)配置、编译部署,以及如何借助 TSF 时间戳把 CSI 精确定位到每一个 WiFi 数据包。读完本文,你可以独立完成一次从 SDR 板到上位机的端到端 CSI 采集,并掌握离线分析 CSI 数据的完整工作流。
本文聚焦“通用 CSI 采集”。若希望利用 openwifi 全双工能力采集**自身发送(self-Tx)**信号的 CSI 实现类似雷达的感知功能,请参考姊妹篇 WiFi CSI radar via self CSI capturing。
快速开始:5 步拿到第一份 CSI
CSI 采集的全流程分成“板上采集”和“电脑显示”两段,二者通过以太网连接。前提条件如下:
- SDR 板已上电,并通过网线直连一台电脑;
- 电脑配置静态 IP
192.168.10.1(该地址同时是 side_ch_ctl.c 中默认的远端服务器地址,见其server_ip = "192.168.10.1"定义); - 板上已按 openwifi 常规流程加载 FPGA 镜像、内核模块与无线驱动。
第 1 步:登录 SDR 板并启动通信栈。
ssh root@192.168.10.122 (password: openwifi) cd openwifi ./wgd.sh (Wait for the script completed)wgd.sh完成 WiFi 驱动(sdr.ko 等)与 FPGA 镜像的加载初始化,是后续一切操作的前提。
第 2 步:进入监控模式并监听一个繁忙信道。
./monitor_ch.sh sdr0 11 (Monitor on channel 11. You can change 11 to other channel that is busy)monitor_ch.sh 把网卡sdr0设为 monitor 模式并切换到指定信道(如 11 号信道),同时调用./agc_settings.sh 1打开自动增益控制,保证接收机以合适的增益捕获环境中的 WiFi 信号。
第 3 步:加载侧信道内核模块并开始采集。
insmod side_ch.ko ./side_ch_ctl gside_ch.ko是 CSI 数据从 FPGA 到 Linux 用户态的桥梁(源码见 driver/side_ch/side_ch.c),side_ch_ctl g则以默认100ms周期反复向内核请求“侧信息”(side info)。板上终端会出现类似输出:
loop 64 side info count 61 loop 128 side info count 99 ...其中每行第一个数字是请求循环次数(每 64 次打印一次),第二个数字是累计收到的有效侧信息条数。只要第二个数字非零且持续增长,就说明 CSI 数据正在顺畅地从板卡流向电脑——因为side_ch_ctl每收到一批有效数据,就会通过 UDP 4000 端口把它们推送到电脑端(对应sendto()逻辑见 side_ch_ctl.c)。
第 4 步:在电脑端(注意不是在 ssh 会话里!)启动实时显示。
cd openwifi/user_space/side_ch_ctl_src python3 side_info_display.py首次运行前可能需要安装依赖:sudo apt install python3-numpy python3-matplotlib python3-tk。脚本启动后监听本机192.168.10.1:4000(见 side_info_display.py),实时绘制3 张图:
- 频率偏移(freq offset):随数据包索引变化的频偏(单位 Hz);
- 信道状态/响应(channel state/response):CSI 的幅值与相位随子载波索引的变化曲线;
- 均衡器输出星座图(constellation from equalizer):均衡后 I/Q 符号的星座分布。
同时脚本在终端持续打印每条侧信息携带的timestamp(TSF 时间戳),并把所有原始数据追加写入side_info.txt文件。
第 5 步:离线分析。
采集过程中产生的side_info.txt可用仓库自带的 MATLAB 脚本 test_side_info_file_display.m 做离线解析与绘图,便于对 Chip State Information 做深入分析(如逐包观察 CSI 相位、频率偏移的时序变化)。
理解 CSI 特性:side channel 的架构与数据格式
架构:从 FPGA 到电脑的完整数据链路
CSI 信息是通过 openwifi 的side channel 基础设施提取出来的。整条链路可以概括为:
- FPGA 侧:WiFi OFDM 接收机(openwifi 基带 IP)在解码每个数据包时,把解码副产品(频率偏移、信道响应、均衡器输出)连同 TSF 时间戳打包成“侧信息”,交给 FPGA 中的
side_ch逻辑模块; - DMA 传输:侧信息通过 DMA 从可编程逻辑(PL)搬运到处理系统(PS)的内存。在 side_ch.c 的
get_side_info()中,驱动先读取 FPGA 的SIDE_CH_REG_M_AXIS_DATA_COUNT_ADDR得到待搬运数据量,再通过 DMA 通道tx_dma_s2mm一次性拉取(每次搬运最多MAX_NUM_DMA_SYMBOL(8192)个 64bit DMA symbol); - 内核侧:
side_ch.ko(driver/side_ch/side_ch.c)是平台驱动,负责 FPGA 寄存器读写、DMA 搬运,并通过Netlink(NETLINK_USERSOCK)与用户态程序交互——收到ACTION_SIDE_INFO_GET请求即执行一次采集并回传数据; - 用户态 + 网络:板上
side_ch_ctl把收到的侧信息通过 UDP(目标端口 4000)发送到电脑; - 上位机:
side_info_display.py接收 UDP 数据包并解析、绘图、落盘side_info.txt,MATLAB 脚本test_side_info_file_display.m负责离线分析。
驱动侧与 FPGA 侧的所有寄存器地址都在 driver/side_ch/side_ch.h 中定义,例如配置寄存器SIDE_CH_REG_CONFIG_ADDR(索引 1)、num_eq 寄存器SIDE_CH_REG_NUM_EQ_ADDR(索引 4)、FC 匹配目标SIDE_CH_REG_FC_TARGET_ADDR(索引 5)、addr1/addr2 匹配目标(索引 6/7)等——这些正是下文side_ch_ctl whXhY命令操作的硬件寄存器。
数据格式:每条侧信息的 64bit 元素结构
每条侧信息的布局与长度定义在源码中以宏的形式统一维护(side_ch.h 与 side_info_display.py 保持一致):
HEADER_LEN = 2:timestamp 与频率偏移;CSI_LEN = 56:单条 CSI 的长度;EQUALIZER_LEN = 56 - 4 = 52:单组均衡器输出长度,其中非 HT(802.11a/g)模式只有 48 个子载波有效,末尾 4 个用{32767, 32767}填充补齐到 52;- 每组“传输单元”(一次采集携带的一条侧信息)总长为
HEADER_LEN + CSI_LEN + num_eq*EQUALIZER_LEN个 DMA symbol,每个 DMA symbol 实际大小为64bit。
具体到每个字段(每元素 64bit):
| 字段 | 占用说明 | 含义 |
|---|---|---|
| timestamp | 64bit TSF 定时器值 | 与 tcpdump、wireshark、dmesg 中 openwifi 打印的时间戳是同一个值,是 CSI 与 WiFi 数据包匹配的唯一身份标识 |
| freq_offset | 仅使用低 16bit | 频率偏移估计值 |
| csi(信道状态/响应) | 仅使用前两个 16bit(I/Q) | 56 个子载波上的信道响应,剩余两个 16bit 为未来多天线场景预留 |
| equalizer | 仅使用前两个 16bit(I/Q) | 均衡器输出,剩余两个 16bit 预留 |
关于子载波有效性:802.11n 下 56 个子载波全部有效;802.11a/g 下仅 52 个子载波有效,均衡器输出仅 48 个子载波有效(其余以填充值补足 52)。
理解数据包格式最精确的方式是阅读并运行附带的 Python 与 MATLAB 脚本:side_info_display.py 中的
parse_side_info()逐条解析出 timestamp(由 4 个 16bit 拼成 64bit TSF)、freq_offset、csi 与 equalizer 数组;MATLAB 侧test_side_info_file_display.m的b = reshape(a, [4, length(a)/4])'同理完成解析。
配置捕获条件:只采集你关心的数据包
快速开始默认采集 OFDM 接收机解码的所有数据包的 CSI。如果只想采集满足特定条件的数据包,需要在执行./side_ch_ctl g之前下发配置命令。配置通过向side_ch_ctl传入不同参数实现,参数格式为:
whXhY其中:
w:写入(write);h:硬件寄存器(hardware register);X:寄存器索引;h:十六进制(hex);Y:十六进制格式的寄存器值。
其余字符保持原样。这套语法由 side_ch_ctl.c 中的parse_para_string()解析,命令最终经 Netlink 到达内核驱动,由side_ch_nl_recv_msg()执行reg_write(reg_idx*4, reg_val)写入 FPGA 寄存器(见 side_ch.c)。对应关系(寄存器索引在 side_ch.h 中定义):
| 寄存器索引 X | 含义 | 用途 |
|---|---|---|
| 1 | CONFIG 配置寄存器 | 开关条件匹配:bit12=FC 匹配开关、bit13=addr1 匹配开关、bit14=addr2 匹配开关;bit11~bit0 应保持001 |
| 5 | FC 匹配目标寄存器 | 指定 FC(Frame Control)匹配值 |
| 6 | addr1 匹配目标寄存器 | 指定目标 MAC(addr1)匹配值 |
| 7 | addr2 匹配目标寄存器 | 指定源 MAC(addr2)匹配值 |
打开/关闭条件捕获(寄存器 1)
Y的 bit 含义:
- bit11~bit0:应为
001(十六进制); - bit12:FC 匹配开关(1=开);
- bit13:addr1 匹配开关(1=开);
- bit14:addr2 匹配开关(1=开)。
# 仅匹配 FC ./side_ch_ctl wh1h1001 # (1001 为十六进制值) # 仅匹配 addr2(源地址) ./side_ch_ctl wh1h4001 # 同时匹配 FC 和 addr1(目标地址) ./side_ch_ctl wh1h3001 # 关闭条件捕获(采集所有数据包) ./side_ch_ctl wh1h0001指定匹配目标(寄存器 5/6/7)
当某种匹配被上面的命令打开后,用下列命令指定匹配目标:
# 指定 FC 匹配目标 ./side_ch_ctl wh5hY # (Y 为十六进制 FC 值) # 指定 addr1(目标地址)匹配目标 ./side_ch_ctl wh6hY # 指定 addr2(源地址)匹配目标 ./side_ch_ctl wh7hY # (Y 为十六进制 MAC 地址,只需 MAC 的后 32 位。 # 例:对 56:5b:01:ec:e2:8f,应输入 01ece28f)完整示例:只采集 MAC 地址为56:5b:01:ec:e2:8f的设备发出的数据包的 CSI:
./side_ch_ctl wh1h4001 ./side_ch_ctl wh7h01ece28f (01ece28f are the last 32 bits of MAC address 56:5b:01:ec:e2:8f) ./side_ch_ctl g说明:驱动
dev_probe()初始化时会把 CONFIG 寄存器写为0x7001(同时打开 FC/addr1/addr2 匹配这一“最严格条件”以在启动阶段抑制侧信道动作),随后再写回0x0001允许所有数据包(见 side_ch.c),因此用户在下发g之前的配置命令会按顺序覆盖该寄存器。
自定义采集周期
side_ch_ctl g默认每100ms采集一次,直到按Ctrl+C退出。如需其他周期:
side_ch_ctl gN周期即为N*1ms(例如g400表示每 400ms 采集一次;g0表示尽可能连续采集,雷达自 CSI 场景即使用此参数)。解析逻辑见 side_ch_ctl.c:未带参数时默认 100ms,非法输入也会回退到 100ms。
配置 num_eq:按需裁剪均衡器输出
num_eq(均衡器输出组数)决定每条侧信息携带多少组均衡器输出(每组 52 个)。如果不需要这么多均衡器信息,可以调小以降低单条数据量与网络/存储开销。合法取值范围是0~8。
关键约束:num_eq必须在三处保持一致——内核模块side_ch.ko、Python 脚本side_info_display.py、MATLAB 脚本test_side_info_file_display.m,否则解析会错位。
- 加载内核模块时:
insmod side_ch.ko num_eq_init=3可把 3 换成 0~8 中的任意数。8 是默认值(快速开始一节无需显式指定)。该参数对应驱动中的模块参数num_eq_init(默认 8,声明见 side_ch.c),dev_probe()会把它写入 FPGA 的SIDE_CH_REG_NUM_EQ_ADDR寄存器,并在每次get_side_info()中用它计算单次传输所需 DMA symbol 数:HEADER_LEN + CSI_LEN + num_eq*EQUALIZER_LEN(见 side_ch.c)。
- 启动 Python 脚本时:
side_info_display.py 3脚本第一个位置参数即 num_eq(默认 8),见 side_info_display.py 的参数解析。
- 使用 MATLAB 脚本时:修改 test_side_info_file_display.m 中的
num_eq变量(默认 8)为对应值(3 仅为例)。
编译 side channel 驱动与用户态程序
CSI 功能需要自行编译两个组件:
1. 内核模块side_ch.ko
$OPENWIFI_DIR/driver/side_ch/make_driver.sh $OPENWIFI_DIR $XILINX_DIR ARCH_BIT其中$OPENWIFI_DIR是 openwifi 仓库根目录,$XILINX_DIR是 Xilinx 安装目录,ARCH_BIT取 32 或 64:Zynq 7000 平台填 32,Zynq MPSoC 平台填 64。脚本内部会设置内核源码目录(KDIR)并调用 driver/side_ch/Makefile 完成模块编译。
2. 用户态程序side_ch_ctl
side_ch_ctl需要在 SDR 板上编译,源码为 user_space/side_ch_ctl_src/side_ch_ctl.c:
gcc -o side_ch_ctl side_ch_ctl.c在 monitor 之外的模式下运行 CSI
CSI 功能并不局限于 monitor 模式。openwifi 的 CSI 采集可以与AP-Client(AP/STA)模式、ad-hoc 模式等正常通信模式同时运行:先把通信功能在相应模式下完全建立起来,然后照常执行板上两步——insmod side_ch.ko与./side_ch_ctl g——即可在正常收发数据的同时把 CSI 提取到电脑端。这为“联合通信与感知”(joint radar and communication)类应用提供了便利,例如在 AP 模式下为某个关联站点持续采集其数据包的信道响应。
将 CSI 映射到具体的 WiFi 数据包
CSI 与 WiFi 数据包的对应关系,是分析(如信道探测、感知)时最常遇到的问题。
- 如果要在采集 CSI 的同时关联到具体 WiFi 数据包,需要用tcpdump / wireshark 等工具同步抓包;
- 然后以timestamp(TSF 定时器值)作为唯一关联键,把 WiFi 数据包与 CSI 信息匹配起来——因为 TSF 时间戳是同一个 WiFi 数据包与其对应 CSI 信息的唯一共同身份标识;
- 具体逐包提取 CSI 的方法,请学习 Python 脚本 side_info_display.py 的
parse_side_info()与 MATLAB 脚本 test_side_info_file_display.m(后者的idx_to_check参数即可用于查看指定索引单包的 CSI 曲线),按需定制自己的解析逻辑。
关于该映射机制的更详细讨论,可参考 openwifi 社区讨论串(docs/discussions 中亦有引用,详见 doc/app_notes/csi.md 原文)。
小结与延伸
通过本文你应该已经掌握:openwifi 如何以 side channel 为骨架把 FPGA 解码过程中的频率偏移、信道响应与均衡器输出实时搬运到上位机;64bit 元素的 CSI 数据格式与side_ch.h/脚本中的长度宏如何一一对应;如何用whXhY参数串完成 FC/addr1/addr2 条件捕获与gN周期配置;如何用num_eq_init裁剪数据量并在三处工具间保持一致性;以及如何借助 TSF 时间戳把 CSI 关联到具体 WiFi 包。仓库中的 doc/app_notes/csi.md、driver/side_ch/side_ch.c、user_space/side_ch_ctl_src/side_ch_ctl.c 与两个解析脚本是进一步深挖的第一手资料。若想利用本平台的全双工自收自发能力,把 self-Tx CSI 用于雷达感知,请继续阅读 WiFi CSI radar via self CSI capturing。
- 通信
- 网络
- 硬件开发
- 嵌入式
【免费下载链接】openwifi
open-source IEEE 802.11 WiFi baseband FPGA (chip) design: driver, software
相关推荐
openwifi CSI技术实战:信道状态信息采集与雷达感知应用终极指南
openwifi CSI技术实战:信道状态信息采集与雷达感知应用终极指南 在无线通信领域, 信道状态信息(CSI) 已成为WiFi感知和雷达应用的关键技术。op
通信网络硬件开发嵌入式MicroPython ESP32 Wi-Fi CSI 实战指南:从固件配置到信道状态信息采集与湍流监测
MicroPython ESP32 Wi Fi CSI 实战指南:从固件配置到信道状态信息采集与湍流监测 本篇指南以 MicroPython 仓库中 examp
嵌入式语言运行时编程语言解释器编译器物联网系统编程Loop:5 分钟用径向菜单搞定 macOS 窗口管理的完整指南
Loop:5 分钟用径向菜单搞定 macOS 窗口管理的完整指南 1. 30 秒看懂 Loop 是什么、适合谁 一句话说清楚:Loop 是一款免费开源的 mac
桌面应用
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考