//! IEEE 802.11p C-ITS Capture with ESP32-C5 // ----------------------------- // missing interface definitions // ----------------------------- use alloc::format; use alloc::string::String; use esp_radio::wifi::sniffer; pub type Channel = core::ffi::c_int; unsafe extern "C" { /// Changes the 802.11 PHY channel /// /// C function signature: `void phy_change_channel(int,int,int,int)` /// /// Options: /// - `primary`: Channel frequency in MHz /// - `ignored1`: Ignored (set to 1) /// - `ignored2`: Ignored (set to 0) /// - `ht_mode`: Probably HT mode unsafe fn phy_change_channel( primary: Channel, ignored1: core::ffi::c_int, ignored2: core::ffi::c_int, ht_mode: core::ffi::c_int, ) -> core::ffi::c_int; /// Enables 802.11p mode on the ESP32-C5 /// /// C function signature: `void phy_11p_set(int,int)` /// /// Options: /// - `enable`: Boolean option to enable 802.11p mode /// - `zero`: Unknown, but need to be zero unsafe fn phy_11p_set(enable: u8, zero: u8); } /// Enum values for `wifi_promiscuous_pkt_type_t` used in `esp_radio::wifi::sniffer::PromiscuousPkt::frame_type` /// /// Original value is actually `core::ffi::c_uint`, but that can't be used in `#[repr()]` attributes, /// so we're using `u8` as the smallest suitable type here that can be casted to a bigger type. #[repr(u8)] #[derive(Debug, Clone, Copy)] #[allow(dead_code)] pub(crate) enum PromiscuousPktType { /// Management frame, indicates 'buf' argument is `wifi_promiscuous_pkt_t` Mgmt = 0, /// Control frame, indicates 'buf' argument is `wifi_promiscuous_pkt_t` Ctrl = 1, /// Data frame, indicates 'buf' argument is `wifi_promiscuous_pkt_t` Data = 2, /// Other type, such as MIMO etc. 'buf' argument is `wifi_promiscuous_pkt_t` but the payload is zero length. Misc = 3, } impl PromiscuousPktType { #[allow(dead_code)] pub fn as_repr(self) -> u8 { self as u8 } /// Converts to underlying type of `wifi_promiscuous_pkt_type_t` (used by `esp_radio::wifi::sniffer::PromiscuousPkt::frame_type`) pub fn as_frame_type(self) -> core::ffi::c_uint { core::ffi::c_uint::from(self.as_repr()) } /// Determines if pub fn matches(self, frame_type: core::ffi::c_uint) -> bool { self.as_frame_type() == frame_type } } /// Configure WiFi Sniffer to a certain 802.11p channel pub fn setup_wifi_sniffer( channel: Channel, sniffer: &mut sniffer::Sniffer, callback: fn(sniffer::PromiscuousPkt<'_>), ) -> Result<(), String> { sniffer .set_promiscuous_mode(true) .map_err(|err| format!("Failed to enable promiscuous mode: {err:?}"))?; sniffer.set_receive_cb(callback); // convert channel number to frequency in MHz let primary = 5000 + (channel * 5); unsafe { phy_11p_set(1, 0); match phy_change_channel(primary, 1, 0, 0) { 0 => Ok(()), ret => Err(format!("Failed to change channel: {ret}")), } } }