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 CSI measurement needs two things: energy in the channel, and something to measure the channel’s response to that energy. Those are the two roles, and they are exhaustive:

  • An emitter puts known RF energy into the channel and never captures. It forces its transmit PHY to a fixed format and loop-injects a raw sounding frame, without associating to anything.
  • A collector captures the channel’s response and delivers it.

Because an emitter’s frames carry no meaning — they exist to be measured, not read — it needs no peer, no handshake, and no protocol. That is what lets the two roles compose freely into whatever arrangement a deployment needs.

How a collector obtains frames to measure is a separate question from what it is for, so the three capture paths are variants of the collector role, not roles of their own:

Capture pathHow it gets frames
SnifferLocks a channel in promiscuous mode and measures every frame overheard
StationAssociates to an AP or commercial router and measures what it receives
Access PointRuns a softAP with DHCP so an associated station generates uplink traffic

A third topology sits alongside these: an ESP-NOW pair, a central and a peripheral exchanging connectionless frames with no AP and no association. Either end can collect, or both can. It keeps the Central / Peripheral spelling it has always had.

On a rename you will run into. A collector delivers its CSI by default, and delivery can be switched off while capture keeps running. That setting used to be called collection-mode, with values collector and listener. Once “collector” became the name of the receive role, it could no longer also name a delivery setting, so the control was renamed: in the library it is CSINode::set_csi_output_enabled, in the CLI it is set-csi-output, and over HTTP it is POST /config/csi-output. If you find collection-mode or --mode=listener in an older document or script, this is its replacement.

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 two exhaustive node roles, emitter and collector, and the three collector capture paths — sniffer, station, and access point.
  • The collection-modecsi-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.