esp_csi_rs_core/profile.rs
1//! Radio-profile seam.
2//!
3//! The node orchestrator ([`crate::node::CSINode`]) drives Wi-Fi bring-up
4//! through a small set of hooks so that alternative PHY back-ends can be
5//! supplied out-of-tree without forking the engine. The crate ships a no-op
6//! [`StandardProfile`] that performs only the generic, chip-level radio tuning;
7//! specialised profiles override the hooks they need.
8
9use crate::node::Node;
10#[cfg(feature = "esp32c5")]
11use crate::node::{CentralOpMode, PeripheralOpMode};
12use esp_radio::wifi::csi::CsiConfig as RadioCsiConfig;
13use esp_radio::wifi::{Protocol, Protocols, WifiController};
14
15/// Pluggable Wi-Fi bring-up back-end.
16///
17/// Every method has a default so profiles only override what they need and new
18/// hooks can be added without breaking existing implementors. Object-safe: the
19/// node stores it as `&'static dyn RadioProfile`.
20pub trait RadioProfile: Sync {
21 /// Whether this profile takes over the extended bring-up sequence
22 /// (bandwidth lock / pre-config forcing / post-config re-apply) for the
23 /// given node and requested protocol. `false` keeps the plain path.
24 fn wants_bringup(&self, _kind: &Node, _protocol: Option<Protocol>) -> bool {
25 false
26 }
27
28 /// Adjust the protocol set before it is applied. `base` is
29 /// `Protocols::default().with_2_4(only(protocol))`; return it unchanged to
30 /// keep the default, or rebuild it entirely.
31 fn tune_protocols(&self, _kind: &Node, _protocol: Protocol, base: Protocols) -> Protocols {
32 base
33 }
34
35 /// Lock/adjust bandwidth just before station bring-up (only called when
36 /// [`Self::wants_bringup`] is `true`).
37 fn apply_bandwidth(&self, _controller: &mut WifiController<'_>) {}
38
39 /// Fired inside `sta_init`, immediately before `set_config(Station)`.
40 fn before_sta_config(&self) {}
41
42 /// Fired inside `ap_init`'s recv-suspended closure, immediately before
43 /// `set_config(AccessPoint)`.
44 fn before_ap_config(&self) {}
45
46 /// Re-apply protocols after a `set_config` restart (station and AP paths).
47 fn apply_protocols_post(&self, _controller: &mut WifiController<'_>) {}
48
49 /// Radio setup for the promiscuous sniffer path after the channel lock.
50 fn apply_sniffer_radio(&self, _controller: &mut WifiController<'_>) {}
51
52 /// Mutate the raw esp-radio CSI config before it is applied, e.g. to enable
53 /// additional acquisition modes. Default leaves it untouched.
54 fn tune_csi_acquisition(&self, _raw: &mut RadioCsiConfig) {}
55}
56
57/// Default profile: generic chip-level radio tuning only, no extended bring-up.
58pub struct StandardProfile;
59
60impl RadioProfile for StandardProfile {
61 fn tune_protocols(&self, kind: &Node, _protocol: Protocol, base: Protocols) -> Protocols {
62 // Generic, chip-level tuning shared by every deployment. Kept free of
63 // any 5 GHz high-throughput advertising the plain path does not need.
64 #[cfg(feature = "esp32c5")]
65 {
66 // ESP-NOW peer-rate config misbehaves beyond A/N on 5 GHz, and the
67 // plain AP/STA path advertises A/N there as well.
68 if matches!(
69 kind,
70 Node::Central(CentralOpMode::EspNow(_))
71 | Node::Central(CentralOpMode::EspNowFastCollector(_))
72 | Node::Central(CentralOpMode::WifiStation(_))
73 | Node::Central(CentralOpMode::WifiAccessPoint(_))
74 | Node::Peripheral(PeripheralOpMode::EspNow(_))
75 | Node::Peripheral(PeripheralOpMode::EspNowFastSource(_))
76 ) {
77 return base.with_5(Protocol::A | Protocol::N);
78 }
79 }
80 let _ = kind;
81 base
82 }
83}