Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Crates & Libraries

The esp-csi-rs ecosystem is a collection of Rust crates for Espressif SoCs that build upon the esp-hal and esp-radio crates to provide a no_std CSI data collection and logging suite. esp-csi-rs provides both a low-level API for building your own CSI-related applications, as well as a variety of out-of-the-box tools for logging, visualizing, and controlling CSI data collection.

In this chapter, we will walk through the crates that make up the esp-csi-rs ecosystem, their use case, their role in the csi-rs data collection pipeline, and later on in the ecosystem walkthrough chapter, we will provide a hands-on example of getting started with CSI data collection to tie together all of the tools and concepts discussed.

Two Roles: Emitter and Collector

Before any of the crates make sense, one piece of vocabulary has to be settled, because every crate in the ecosystem uses it and it is the thing most likely to confuse a reader coming from older CSI tooling.

A node in a CSI collection network is described by four independent attributes. They are independent because they vary independently — the node that keeps a channel busy and the node that produces the dataset need not be the same one, and usually are not.

AttributeValuesQuestion it answers
Network roleCentral, PeripheralWho sources the traffic?
Collection modeCollector, ListenerDo this node’s measurements leave it?
Operational modesix, belowHow does it reach the channel?
Session roleInitiator, ResponderWho starts and stops the run?

Older CSI tooling — and older versions of these crates — collapsed the first two into a single binary: active/passive, transmitter/receiver, emitter/collector. That loses configurations a deployment actually uses. A node that both sources traffic and measures it has no name; neither does a node that measures without reporting, which is what you want when you are separating the cost of acquiring CSI from the cost of delivering it.

Operational modeHow the node participates
Wi-Fi snifferPromiscuous capture on a locked channel; the traffic is already there
Wi-Fi stationAssociates to an AP or a commercial router
Wi-Fi access pointSelf-contained softAP with DHCP; associated stations generate uplink
EmitterUnassociated transmit-only sounding; needs no peer and no handshake
ESP-NOWConnectionless symmetric exchange; either end can collect
ESP-NOW simplexConnectionless asymmetric; one end floods, the other only measures

Not every mode admits every combination — a sniffer never transmits, so it cannot be a central — and the combinations a mode does not admit are not offered. Where an attribute is fixed there is no setter to call, so a central sniffer or a collecting emitter cannot be built. That is why you will not find a “role” argument on most constructors: the mode carries it.

The model is written down once, in esp-csi-rs/docs/network-model.md, which also covers how it relates to IEEE 802.11bf and what the firmware cannot enforce. This book does not restate it.

On two renames you will run into. “Emitter” used to be described as a role, opposite “collector”. It is an operational mode: an emitter’s node is a central listener, which is the description the two-role vocabulary had no way to express. And the delivery switch was once collection-mode, with values collector and listener; it became set-csi-output / POST /config/csi-output. If you find --mode=listener in an older script, that is its replacement — but note it had no effect on firmware before esp-csi-rs 0.11, which stored the flag without reading it.

The Pipeline, and Its Three Tiers

The crates divide cleanly by where they run and how much they decide for you. This book refers to those divisions as tiers:

  • Tier 0 — the library on the device. esp-csi-rs. You write the firmware; the crate handles the radio, the capture path, and the output format.
  • Tier 1 — ready-made firmware on the device. esp-csi-cli-rs, esp-csi-litetui-rs, esp-csi-litegui-rs. Flash a binary, configure it over serial or a touchscreen, and collect without writing embedded Rust.
  • Tier 2 — host-side tooling. csi-webserver, csi-webserver-core, csi-webclient. These run on your computer, take the stream off the serial port, and turn it into something you can drive, watch, and store.

Every tier above 0 is built on the one below it, and none of them is mandatory:

     TIER 0                TIER 1                      TIER 2
┌──────────────┐    ┌──────────────────┐      ┌────────────────────┐
│  esp-csi-rs  │───▶│  esp-csi-cli-rs  │─────▶│    csi-webserver   │
│              │    │  (serial console)│ USB  │  HTTP + WebSocket  │
│ radio, roles │    └──────────────────┘      │    Parquet dumps   │
│ capture path │    ┌──────────────────┐      └─────────┬──────────┘
│ log formats  │───▶│ esp-csi-litetui  │                │
│              │    │ esp-csi-litegui  │                ▼
└──────────────┘    │  (on-device UI)  │      ┌────────────────────┐
       │            └──────────────────┘      │    csi-webclient   │
       │                     │                │  plots, export     │
       ▼                     ▼                └────────────────────┘
 your own firmware      SD card / screen

Inside a Tier 0 device, a captured packet travels a short and deliberately gated path. Knowing its shape explains most of the configuration surface you will meet later:1

esp-radio Wi-Fi driver (CSI event, Wi-Fi task context)
  └─ capture_csi_info()                          [hot path]
       ├─ statistics counters                    (always, `statistics` feature)
       ├─ CSI output enabled? ── no ─▶ return    (the master gate)
       ├─ build CSIDataPacket                    (~640 B, stack; per-chip shape)
       ├─ delivery mode:
       │    Off      → nothing
       │    Callback → your fn(&CSIDataPacket), inline
       │    Async    → lock-free queue + waker, drained by CSINodeClient
       └─ inline logging enabled? → serial output in the configured LogMode

The three gates are independent, which is what makes combinations like “process every packet on-device but do not flood the serial port” a matter of setting two flags rather than rebuilding the firmware.

Supported Espressif SoCs

The capabilities of your sensing network are strictly bound by the RF hardware of the specific SoC. csi-rs supports the following chips, your ideal choice depends on your use case and budget:

ESP32 Series:

  • ESP32:
    • 2.4 GHz Wi-Fi 4 (802.11n), Dual-core Xtensa.

ESP32-C Series:

  • ESP32-C3:
    • 2.4 GHz Wi-Fi 4, Single-core RISC-V.
  • ESP32-C5:
    • Dual-band (2.4/5 GHz) Wi-Fi 6 (802.11ax), Single-core RISC-V.
    • The only dual-band part in this list. That matters for sensing: the 5 GHz band is where the wider channels live, and the two bands see the same room differently, so it is a choice worth having.
  • ESP32-C6:
    • 2.4 GHz Wi-Fi 6 (802.11ax), Single-core RISC-V. It also carries 802.15.4 (Thread/Zigbee), which the CSI path does not use.

ESP32-S Series:

  • ESP32-S3:
    • 2.4 GHz Wi-Fi 4, Dual-core Xtensa with vector SIMD support.

For more information on the ESP SoCs naming conventions, check out this espressif blog post

Every supported chip can act as a collector. Emitter support depends on the part and on the esp-radio version you build against, so if you are buying specifically to run an emitter, check the current status in the esp-csi-rs repository rather than relying on this page.

Summary

In this chapter we looked at:

  • The four independent attributes that describe a node, and why collapsing the first two into a single binary loses configurations deployments actually use.
  • The six operational modes, and why the combinations a mode does not admit are not offered rather than merely documented.
  • The collection-mode → csi-output rename, and why it happened.
  • The three tiers the ecosystem’s crates fall into, and how a CSI packet travels from the radio to your host.
  • Which Espressif parts are supported, and which of them can act as an emitter.

The sections that follow take each crate in turn, starting at Tier 0.


  1. Adapted from specs/crate_architecture_spec.md §5 in the esp-csi-rs repository. ↩