### Initialize WiFi Driver (`esp_wifi_init`) Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Allocates WiFi resources and starts the driver task. Must be called first. Ensure `wifi_init_config_t` is populated correctly using provided statics. ```rust #![no_std] use esp_wifi_sys_esp32::include::{ esp_wifi_init, wifi_init_config_t, g_wifi_default_wpa_crypto_funcs, g_wifi_osi_funcs, ESP_OK, WIFI_INIT_CONFIG_MAGIC, }; unsafe fn wifi_init() -> i32 { // In practice esp-hal / esp-radio construct this structure for you. // This shows the critical fields that must be set correctly. let mut cfg = core::mem::zeroed::(); cfg.osi_funcs = &mut g_wifi_osi_funcs as *mut _; cfg.wpa_crypto_funcs = g_wifi_default_wpa_crypto_funcs; cfg.static_rx_buf_num = 10; cfg.dynamic_rx_buf_num = 32; cfg.tx_buf_type = 1; // dynamic cfg.dynamic_tx_buf_num = 32; cfg.nvs_enable = 1; cfg.magic = WIFI_INIT_CONFIG_MAGIC as i32; let rc = esp_wifi_init(&cfg as *const _); assert_eq!(rc, ESP_OK as i32, "esp_wifi_init failed: {}", rc); rc } ``` -------------------------------- ### Create and Manage High-Resolution Timers Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Demonstrates creating, starting, stopping, and deleting microsecond-resolution software timers. Ensure callbacks are handled in a dedicated high-priority task. ```rust use esp_wifi_sys_esp32::include::{ esp_timer_create, esp_timer_start_once, esp_timer_start_periodic, esp_timer_stop, esp_timer_delete, esp_timer_create_args_t, esp_timer_handle_t, ESP_OK, }; unsafe extern "C" fn timer_cb(arg: *mut core::ffi::c_void) { // Called from the esp_timer task; arg is user-supplied context let _ = arg; } unsafe fn timer_demo() { let args = esp_timer_create_args_t { callback: Some(timer_cb), arg: core::ptr::null_mut(), name: b"my_timer\0".as_ptr() as *const _, // dispatch_method defaults to task (0) ..core::mem::zeroed() }; let mut handle: esp_timer_handle_t = core::ptr::null_mut(); let rc = esp_timer_create(&args as *const _, &mut handle as *mut _); assert_eq!(rc, ESP_OK as i32); // Fire once after 500 ms esp_timer_start_once(handle, 500_000 /* µs */); // Or fire every 1 s // esp_timer_start_periodic(handle, 1_000_000); // … later … esp_timer_stop(handle); esp_timer_delete(handle); } ``` -------------------------------- ### Start and Stop WiFi Stack (`esp_wifi_start`, `esp_wifi_stop`) Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Activates the configured WiFi mode and tears it down. `esp_wifi_start` requires mode and config to be set. `esp_wifi_stop` preserves initialized state. ```rust use esp_wifi_sys_esp32::include::{ esp_wifi_start, esp_wifi_stop, ESP_OK, }; unsafe fn wifi_lifecycle() { // start (mode + config must already be set) let rc = esp_wifi_start(); assert_eq!(rc, ESP_OK as i32, "start failed: {}", rc); // … run application … // graceful stop (keeps init state) let rc = esp_wifi_stop(); assert_eq!(rc, ESP_OK as i32, "stop failed: {}", rc); } ``` -------------------------------- ### Configure WiFi Mode (`esp_wifi_set_mode`, `esp_wifi_get_mode`) Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Sets the WiFi operating mode (STA, AP, APSTA, NAN) before starting the stack. Retrieves the current mode. ```rust use esp_wifi_sys_esp32::include::{ esp_wifi_set_mode, esp_wifi_get_mode, wifi_mode_t_WIFI_MODE_STA, wifi_mode_t_WIFI_MODE_AP, wifi_mode_t, ESP_OK, }; unsafe fn configure_as_sta() { let rc = esp_wifi_set_mode(wifi_mode_t_WIFI_MODE_STA); assert_eq!(rc, ESP_OK as i32); let mut current_mode: wifi_mode_t = 0; let rc = esp_wifi_get_mode(&mut current_mode as *mut _); assert_eq!(rc, ESP_OK as i32); assert_eq!(current_mode, wifi_mode_t_WIFI_MODE_STA); } ``` -------------------------------- ### Event System Setup Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Create the default ESP event loop for dispatching WiFi, IP, BT, and user-defined events. Register handlers for specific event bases and IDs to process these asynchronous events. ```APIDOC ## `esp_event_loop_create_default` / `esp_event_handler_register` — event system The ESP event loop dispatches WiFi, IP, BT and user-defined events asynchronously. Create the default loop once at startup, then register typed handlers. WiFi events (`WIFI_EVENT`) and IP events (`IP_EVENT`) drive the connection state machine. ### Usage Example ```rust use esp_wifi_sys_esp32::include::{ esp_event_loop_create_default, esp_event_handler_register, esp_event_base_t, ESP_OK, }; unsafe extern "C" fn wifi_event_handler( _arg: *mut core::ffi::c_void, event_base: esp_event_base_t, event_id: i32, _event_data: *mut core::ffi::c_void, ) { // event_id maps to wifi_event_t or ip_event_t constants, e.g.: // WIFI_EVENT_STA_CONNECTED = 4 // WIFI_EVENT_STA_DISCONNECTED = 5 // IP_EVENT_STA_GOT_IP = 0 let _ = (event_base, event_id); } unsafe fn setup_events() { let rc = esp_event_loop_create_default(); assert_eq!(rc, ESP_OK as i32, "event loop: {}", rc); // Register for all WIFI_EVENT events (ESP_EVENT_ANY_ID = -1) let wifi_event_base: esp_event_base_t = b"WIFI_EVENTS\0".as_ptr() as *const _; let rc = esp_event_handler_register( wifi_event_base, -1i32, // ESP_EVENT_ANY_ID Some(wifi_event_handler), core::ptr::null_mut(), // handler argument ); assert_eq!(rc, ESP_OK as i32); } ``` ``` -------------------------------- ### `esp_wifi_init` — initialize the WiFi driver Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Allocates internal WiFi resources and starts the driver task. This function must be called first. It requires a properly constructed `wifi_init_config_t` structure. ```APIDOC ## `esp_wifi_init` — initialize the WiFi driver Allocates all internal WiFi resources (control structures, RX/TX buffers, NVS state) and starts the driver task. Must be the first WiFi call. Always construct `wifi_init_config_t` via `WIFI_INIT_CONFIG_DEFAULT` in C; in Rust, this means passing a config populated via the `g_wifi_default_wpa_crypto_funcs` and `g_wifi_osi_funcs` statics. ### Parameters - **`cfg`** (*`*wifi_init_config_t`*) - Pointer to the WiFi initialization configuration structure. ### Returns - **`ESP_OK`** on success, or an error code on failure. ### Request Example ```rust use esp_wifi_sys_esp32::include::{ esp_wifi_init, wifi_init_config_t, g_wifi_default_wpa_crypto_funcs, g_wifi_osi_funcs, ESP_OK, WIFI_INIT_CONFIG_MAGIC, }; unsafe fn wifi_init() -> i32 { let mut cfg = core::mem::zeroed::(); cfg.osi_funcs = &mut g_wifi_osi_funcs as *mut _; cfg.wpa_crypto_funcs = g_wifi_default_wpa_crypto_funcs; cfg.static_rx_buf_num = 10; cfg.dynamic_rx_buf_num = 32; cfg.tx_buf_type = 1; // dynamic cfg.dynamic_tx_buf_num = 32; cfg.nvs_enable = 1; cfg.magic = WIFI_INIT_CONFIG_MAGIC as i32; let rc = esp_wifi_init(&cfg as *const _); assert_eq!(rc, ESP_OK as i32, "esp_wifi_init failed: {}", rc); rc } ``` ``` -------------------------------- ### `esp_wifi_start` / `esp_wifi_stop` — start and stop the WiFi stack Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Controls the lifecycle of the WiFi stack. `esp_wifi_start` activates the configured mode, while `esp_wifi_stop` deactivates it, preserving the initialized state. ```APIDOC ## `esp_wifi_start` / `esp_wifi_stop` — start and stop the WiFi stack `esp_wifi_start` activates the configured mode, creating control blocks and starting internal tasks. `esp_wifi_stop` tears them down but preserves the initialized state (use `esp_wifi_deinit` to free all resources). ### `esp_wifi_start` #### Returns - **`ESP_OK`** on success, or an error code on failure. ### `esp_wifi_stop` #### Returns - **`ESP_OK`** on success, or an error code on failure. ### Request Example ```rust use esp_wifi_sys_esp32::include::{ esp_wifi_start, esp_wifi_stop, ESP_OK, }; unsafe fn wifi_lifecycle() { let rc = esp_wifi_start(); assert_eq!(rc, ESP_OK as i32, "start failed: {}", rc); // … run application … let rc = esp_wifi_stop(); assert_eq!(rc, ESP_OK as i32, "stop failed: {}", rc); } ``` ``` -------------------------------- ### Set and Get Maximum Transmit Power Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Caps the transmit power of the Wi-Fi interface after it has started. The value is in units of 0.25 dBm, with a valid range of 8–84 (approx. 2–20 dBm). Hardware quantizes values to the nearest supported step. Use `esp_wifi_set_max_tx_power` to set and `esp_wifi_get_max_tx_power` to retrieve. ```rust use esp_wifi_sys_esp32::include::{ esp_wifi_set_max_tx_power, esp_wifi_get_max_tx_power, ESP_OK, }; unsafe fn reduce_tx_power() { // Set max TX power to 13 dBm (52 × 0.25 = 13.0 dBm) let rc = esp_wifi_set_max_tx_power(52_i8); assert_eq!(rc, ESP_OK as i32); let mut actual: i8 = 0; esp_wifi_get_max_tx_power(&mut actual as *mut _); // actual will be the quantized value closest to 52 (e.g. 52) } ``` -------------------------------- ### Regenerate Bindings with `xtask` Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Use this command to regenerate Rust FFI bindings for all supported chips when updating Espressif IDF or toolchain versions. Ensure the Espressif toolchain is installed or `ESP_TOOLS_DIR` is set. ```bash # Prerequisites: Espressif toolchain installed at ~/.espressif/tools # OR set ESP_TOOLS_DIR to the tools directory. # Run from the workspace root to regenerate all chip bindings: cargo xtask # The tool iterates all chips, runs bindgen with the correct # --sysroot, --target, and -I include paths, writes each # esp-wifi-sys-/src/include.rs, then appends: # unsafe impl Sync for wifi_init_config_t {} # unsafe impl Sync for wifi_osi_funcs_t {} # and formats the output with rustfmt. # After regeneration, strip .eh_frame from libs if you see linker errors: riscv32-esp-elf-objcopy --remove-section=.eh_frame \ esp-wifi-sys-esp32c61/libs/libphy.a ``` -------------------------------- ### Transmit Power Control Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Caps the transmit power after WiFi is started. The unit is 0.25 dBm, with a valid range of 8–84. Values are quantized to the nearest supported hardware step. ```APIDOC ## `esp_wifi_set_max_tx_power` / `esp_wifi_get_max_tx_power` — TX power control Caps the transmit power after WiFi is started. The unit is 0.25 dBm; the valid range is 8–84 (corresponding to approximately 2–20 dBm). Values are quantized to the nearest supported step by the hardware. ### Usage Example ```rust use esp_wifi_sys_esp32::include::{ esp_wifi_set_max_tx_power, esp_wifi_get_max_tx_power, ESP_OK, }; unsafe fn reduce_tx_power() { // Set max TX power to 13 dBm (52 × 0.25 = 13.0 dBm) let rc = esp_wifi_set_max_tx_power(52_i8); assert_eq!(rc, ESP_OK as i32); let mut actual: i8 = 0; esp_wifi_get_max_tx_power(&mut actual as *mut _); // actual will be the quantized value closest to 52 (e.g. 52) } ``` ``` -------------------------------- ### Add esp-wifi-sys to Project Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Select the crate matching your hardware target. The `sys-logs` feature requires nightly and enables driver log forwarding. ```toml # Cargo.toml (bare-metal ESP32-C3 project) [package] name = "my-firmware" version = "0.1.0" edition = "2021" [dependencies] # Pick the crate that matches your chip: esp-wifi-sys-esp32c3 = { version = "0.2.0", features = [] } # For driver log output (requires nightly): # esp-wifi-sys-esp32c3 = { version = "0.2.0", features = ["sys-logs", "log"] } [profile.release] opt-level = 3 debug = true # rust-toolchain.toml — the ESP toolchain is required # [toolchain] # channel = "esp" ``` -------------------------------- ### ESP-NOW Peer-to-Peer Messaging Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Initialize ESP-NOW, register callbacks, add peers, and send messages. Ensure callbacks are registered before adding peers. ```rust use esp_wifi_sys_esp32::include::{ esp_now_init, esp_now_deinit, esp_now_register_recv_cb, esp_now_register_send_cb, esp_now_add_peer, esp_now_send, esp_now_peer_info, esp_now_recv_info, wifi_interface_t_WIFI_IF_STA, ESP_OK, }; // Callback invoked on send completion (called from WiFi task) unsafe extern "C" fn send_cb(mac_addr: *const u8, status: u32) { // status: 0 = sent OK, 1 = failed let _ = (mac_addr, status); } // Callback invoked on receive (called from WiFi task) unsafe extern "C" fn recv_cb( recv_info: *const esp_now_recv_info, data: *const u8, len: i32, ) { let _slice = core::slice::from_raw_parts(data, len as usize); // process payload… } unsafe fn espnow_demo() { assert_eq!(esp_now_init(), ESP_OK as i32); esp_now_register_send_cb(Some(send_cb)); esp_now_register_recv_cb(Some(recv_cb)); // Register a unicast peer let mut peer = core::mem::zeroed::(); peer.peer_addr = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]; // broadcast peer.channel = 0; // current channel peer.ifidx = wifi_interface_t_WIFI_IF_STA as u8; peer.encrypt = false; esp_now_add_peer(&peer as *const _); // Send 10 bytes to broadcast address let payload = [0x01u8, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A]; let rc = esp_now_send( [0xFF; 6].as_ptr(), payload.as_ptr(), payload.len(), ); assert_eq!(rc, ESP_OK as i32); // Cleanup when done esp_now_deinit(); } ``` -------------------------------- ### Configure Station Credentials (`esp_wifi_set_config`) Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Sets SSID, password, and other parameters for the station interface. Configuration is persisted to NVS. ```rust use esp_wifi_sys_esp32::include::{ esp_wifi_set_config, wifi_config_t, wifi_sta_config_t, wifi_interface_t_WIFI_IF_STA, ESP_OK, }; unsafe fn set_sta_credentials(ssid: &[u8; 32], password: &[u8; 64]) { let mut sta_cfg = core::mem::zeroed::(); sta_cfg.ssid.copy_from_slice(ssid); sta_cfg.password.copy_from_slice(password); // Enable 802.11r/802.11k neighbour reporting sta_cfg.set_rm_enabled(1); sta_cfg.set_btm_enabled(1); // wifi_config_t is a C union; set the `sta` variant let mut cfg = core::mem::zeroed::(); cfg.sta = sta_cfg; let rc = esp_wifi_set_config(wifi_interface_t_WIFI_IF_STA, &mut cfg as *mut _); assert_eq!(rc, ESP_OK as i32, "set_config failed: {}", rc); } ``` -------------------------------- ### Station Connection Lifecycle (`esp_wifi_connect`, `esp_wifi_disconnect`) Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Initiates a connection to an AP and disconnects from it. Connection status is reported via the event loop. Must be called after `esp_wifi_start`. ```rust use esp_wifi_sys_esp32::include::{ esp_wifi_connect, esp_wifi_disconnect, ESP_OK, }; unsafe fn connect_and_later_disconnect() { let rc = esp_wifi_connect(); // ESP_ERR_WIFI_CONN: WiFi not started // ESP_ERR_WIFI_SSID: SSID invalid assert_eq!(rc, ESP_OK as i32, "connect request failed: {}", rc); // … wait for WIFI_EVENT_STA_CONNECTED via event loop … let rc = esp_wifi_disconnect(); assert_eq!(rc, ESP_OK as i32, "disconnect failed: {}", rc); } ``` -------------------------------- ### ESP-NOW Peer-to-Peer Messaging Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Initialize ESP-NOW for connectionless direct messaging between devices. Register callbacks for send and receive events, add peer information including MAC addresses, and send data. Deinitialize when done. ```APIDOC ## `esp_now_init` / `esp_now_send` / `esp_now_add_peer` — ESP-NOW peer-to-peer messaging ESP-NOW is a connectionless protocol for direct unicast/broadcast messaging between Espressif devices without an infrastructure AP. Initialize with `esp_now_init`, register a receive callback, add peer entries describing each remote MAC address, then send with `esp_now_send`. ### Usage Example ```rust use esp_wifi_sys_esp32::include::{ esp_now_init, esp_now_deinit, esp_now_register_recv_cb, esp_now_register_send_cb, esp_now_add_peer, esp_now_send, esp_now_peer_info, esp_now_recv_info, wifi_interface_t_WIFI_IF_STA, ESP_OK, }; // Callback invoked on send completion (called from WiFi task) unsafe extern "C" fn send_cb(mac_addr: *const u8, status: u32) { // status: 0 = sent OK, 1 = failed let _ = (mac_addr, status); } // Callback invoked on receive (called from WiFi task) unsafe extern "C" fn recv_cb( recv_info: *const esp_now_recv_info, data: *const u8, len: i32, ) { let _slice = core::slice::from_raw_parts(data, len as usize); // process payload… } unsafe fn espnow_demo() { assert_eq!(esp_now_init(), ESP_OK as i32); esp_now_register_send_cb(Some(send_cb)); esp_now_register_recv_cb(Some(recv_cb)); // Register a unicast peer let mut peer = core::mem::zeroed::(); peer.peer_addr = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]; // broadcast peer.channel = 0; // current channel peer.ifidx = wifi_interface_t_WIFI_IF_STA as u8; peer.encrypt = false; esp_now_add_peer(&peer as *const _); // Send 10 bytes to broadcast address let payload = [0x01u8, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0A]; let rc = esp_now_send( [0xFF; 6].as_ptr(), payload.as_ptr(), payload.len(), ); assert_eq!(rc, ESP_OK as i32); // Cleanup when done esp_now_deinit(); } ``` ``` -------------------------------- ### Bluetooth Controller Lifecycle Management Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Initialize, enable, disable, and deinitialize the dual-mode Bluetooth controller. Ensure correct configuration parameters are used, potentially referencing defaults from esp-hal. ```rust use esp_wifi_sys_esp32::include::{ esp_bt_controller_init, esp_bt_controller_enable, esp_bt_controller_disable, esp_bt_controller_deinit, esp_bt_controller_config_t, esp_bt_mode_t_ESP_BT_MODE_BLE, ESP_OK, }; unsafe fn ble_controller_start() { let mut bt_cfg = core::mem::zeroed::(); // bt_cfg.magic and .version must match the binary blob's expectations; // in practice, use BT_CONTROLLER_INIT_CONFIG_DEFAULT from esp-hal. bt_cfg.controller_task_stack_size = 4096; bt_cfg.controller_task_prio = 110; bt_cfg.hci_uart_no = 1; let rc = esp_bt_controller_init(&mut bt_cfg as *mut _); assert_eq!(rc, ESP_OK as i32, "bt init: {}", rc); let rc = esp_bt_controller_enable(esp_bt_mode_t_ESP_BT_MODE_BLE); assert_eq!(rc, ESP_OK as i32, "bt enable: {}", rc); // … register HCI callbacks and use BLE stack … esp_bt_controller_disable(); esp_bt_controller_deinit(); } ``` -------------------------------- ### Configure Wi-Fi Power-Save Mode Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Controls the modem sleep or power-save mode for the station interface. Use `esp_wifi_set_ps` to enable or disable power saving. `WIFI_PS_NONE` disables it, `WIFI_PS_MIN_MODEM` (default) wakes at every DTIM, and `WIFI_PS_MAX_MODEM` wakes at the listen interval. `esp_wifi_get_ps` retrieves the current setting. ```rust use esp_wifi_sys_esp32::include::{ esp_wifi_set_ps, esp_wifi_get_ps, wifi_ps_type_t_WIFI_PS_NONE, wifi_ps_type_t_WIFI_PS_MIN_MODEM, wifi_ps_type_t, ESP_OK, }; unsafe fn configure_power_save() { // Disable power saving for maximum throughput let rc = esp_wifi_set_ps(wifi_ps_type_t_WIFI_PS_NONE); assert_eq!(rc, ESP_OK as i32); // Re-enable default modem-sleep to reduce current draw let rc = esp_wifi_set_ps(wifi_ps_type_t_WIFI_PS_MIN_MODEM); assert_eq!(rc, ESP_OK as i32); let mut ps: wifi_ps_type_t = 0; esp_wifi_get_ps(&mut ps as *mut _); assert_eq!(ps, wifi_ps_type_t_WIFI_PS_MIN_MODEM); } ``` -------------------------------- ### ESP Event Loop and Handler Registration Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Create the default event loop and register handlers for WiFi and IP events. Use `ESP_EVENT_ANY_ID` to register for all events of a specific base. ```rust use esp_wifi_sys_esp32::include::{ esp_event_loop_create_default, esp_event_handler_register, esp_event_base_t, ESP_OK, }; unsafe extern "C" fn wifi_event_handler( _arg: *mut core::ffi::c_void, event_base: esp_event_base_t, event_id: i32, _event_data: *mut core::ffi::c_void, ) { // event_id maps to wifi_event_t or ip_event_t constants, e.g.: // WIFI_EVENT_STA_CONNECTED = 4 // WIFI_EVENT_STA_DISCONNECTED = 5 // IP_EVENT_STA_GOT_IP = 0 let _ = (event_base, event_id); } unsafe fn setup_events() { let rc = esp_event_loop_create_default(); assert_eq!(rc, ESP_OK as i32, "event loop: {}", rc); // Register for all WIFI_EVENT events (ESP_EVENT_ANY_ID = -1) let wifi_event_base: esp_event_base_t = b"WIFI_EVENTS\0".as_ptr() as *const _; let rc = esp_event_handler_register( wifi_event_base, -1i32, // ESP_EVENT_ANY_ID Some(wifi_event_handler), core::ptr::null_mut(), // handler argument ); assert_eq!(rc, ESP_OK as i32); } ``` -------------------------------- ### Bluetooth Controller Lifecycle Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Initialize and enable the dual-mode Bluetooth controller. This function is available on chips with Bluetooth support. Configuration includes task stack size, priority, and HCI UART number. ```APIDOC ## `esp_bt_controller_init` / `esp_bt_controller_enable` — Bluetooth controller lifecycle Initializes and enables the dual-mode Bluetooth controller (Classic BT + BLE, or BLE-only depending on mode). Only available on chips with BT support (esp32, esp32c3, esp32c6, etc.). `esp_bt_controller_config_t` contains resource allocation parameters analogous to WiFi's init config. ### Usage Example ```rust use esp_wifi_sys_esp32::include::{ esp_bt_controller_init, esp_bt_controller_enable, esp_bt_controller_disable, esp_bt_controller_deinit, esp_bt_controller_config_t, esp_bt_mode_t_ESP_BT_MODE_BLE, ESP_OK, }; unsafe fn ble_controller_start() { let mut bt_cfg = core::mem::zeroed::(); // bt_cfg.magic and .version must match the binary blob's expectations; // in practice, use BT_CONTROLLER_INIT_CONFIG_DEFAULT from esp-hal. bt_cfg.controller_task_stack_size = 4096; bt_cfg.controller_task_prio = 110; bt_cfg.hci_uart_no = 1; let rc = esp_bt_controller_init(&mut bt_cfg as *mut _); assert_eq!(rc, ESP_OK as i32, "bt init: {}", rc); let rc = esp_bt_controller_enable(esp_bt_mode_t_ESP_BT_MODE_BLE); assert_eq!(rc, ESP_OK as i32, "bt enable: {}", rc); // … register HCI callbacks and use BLE stack … esp_bt_controller_disable(); esp_bt_controller_deinit(); } ``` ``` -------------------------------- ### Manage MAC Address for Wi-Fi Interface Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Allows reading or overriding the MAC address for a specific Wi-Fi interface (STA or AP). The MAC address must be set before `esp_wifi_start`. Ensure the unicast bit (LSB of the first byte) is 0 and that STA and AP MAC addresses differ. Use `esp_wifi_set_mac` to set and `esp_wifi_get_mac` to retrieve. ```rust use esp_wifi_sys_esp32::include::{ esp_wifi_set_mac, esp_wifi_get_mac, wifi_interface_t_WIFI_IF_STA, ESP_OK, }; unsafe fn override_sta_mac() { let new_mac: [u8; 6] = [0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x01]; let rc = esp_wifi_set_mac( wifi_interface_t_WIFI_IF_STA, new_mac.as_ptr(), ); assert_eq!(rc, ESP_OK as i32, "set_mac failed: {}", rc); let mut read_mac = [0u8; 6]; esp_wifi_get_mac(wifi_interface_t_WIFI_IF_STA, read_mac.as_mut_ptr()); assert_eq!(read_mac, new_mac); } ``` -------------------------------- ### High-Resolution Timers Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Provides microsecond-resolution software timers backed by the ESP timer infrastructure. Timers fire callbacks from a dedicated high-priority task. Used internally by the WiFi driver and available for application use. ```APIDOC ## `esp_timer_create` / `esp_timer_start_once` / `esp_timer_start_periodic` — high-resolution timer Provides microsecond-resolution software timers backed by the ESP timer infrastructure. Timers fire callbacks from a dedicated high-priority task. Used internally by the WiFi driver and available for application use. ```rust use esp_wifi_sys_esp32::include::{ esp_timer_create, esp_timer_start_once, esp_timer_start_periodic, esp_timer_stop, esp_timer_delete, esp_timer_create_args_t, esp_timer_handle_t, ESP_OK, }; unsafe extern "C" fn timer_cb(arg: *mut core::ffi::c_void) { // Called from the esp_timer task; arg is user-supplied context let _ = arg; } unsafe fn timer_demo() { let args = esp_timer_create_args_t { callback: Some(timer_cb), arg: core::ptr::null_mut(), name: b"my_timer\0".as_ptr() as *const _, // dispatch_method defaults to task (0) ..core::mem::zeroed() }; let mut handle: esp_timer_handle_t = core::ptr::null_mut(); let rc = esp_timer_create(&args as *const _, &mut handle as *mut _); assert_eq!(rc, ESP_OK as i32); // Fire once after 500 ms esp_timer_start_once(handle, 500_000 /* µs */); // Or fire every 1 s // esp_timer_start_periodic(handle, 1_000_000); // … later … esp_timer_stop(handle); esp_timer_delete(handle); } ``` ``` -------------------------------- ### `esp_wifi_connect` / `esp_wifi_disconnect` — station connection lifecycle Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Manages the connection lifecycle for the WiFi station interface. `esp_wifi_connect` initiates a connection, and `esp_wifi_disconnect` terminates it. Connection status is reported via the event loop. ```APIDOC ## `esp_wifi_connect` / `esp_wifi_disconnect` — station connection lifecycle Initiates connection to the AP described in the station config. Completion (success or failure) is reported asynchronously via the event loop (`WIFI_EVENT_STA_CONNECTED` / `WIFI_EVENT_STA_DISCONNECTED`). Must be called after `esp_wifi_start` in STA or APSTA mode. ### `esp_wifi_connect` #### Returns - **`ESP_OK`** on success, or an error code on failure. ### `esp_wifi_disconnect` #### Returns - **`ESP_OK`** on success, or an error code on failure. ### Request Example ```rust use esp_wifi_sys_esp32::include::{ esp_wifi_connect, esp_wifi_disconnect, ESP_OK, }; unsafe fn connect_and_later_disconnect() { let rc = esp_wifi_connect(); assert_eq!(rc, ESP_OK as i32, "connect request failed: {}", rc); // … wait for WIFI_EVENT_STA_CONNECTED via event loop … let rc = esp_wifi_disconnect(); assert_eq!(rc, ESP_OK as i32, "disconnect failed: {}", rc); } ``` ``` -------------------------------- ### Trigger and Retrieve AP Scan Results Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Initiates an 802.11 scan. Use `esp_wifi_scan_start` to begin the scan, optionally blocking until completion. Retrieve results with `esp_wifi_scan_get_ap_records`. The internal list of AP records is freed automatically after retrieval. ```rust use esp_wifi_sys_esp32::include::{ esp_wifi_scan_start, esp_wifi_scan_stop, esp_wifi_scan_get_ap_num, esp_wifi_scan_get_ap_records, wifi_scan_config_t, wifi_ap_record_t, ESP_OK, }; unsafe fn blocking_scan() { // NULL config → scan all channels with default timing let rc = esp_wifi_scan_start(core::ptr::null(), true /* block */); assert_eq!(rc, ESP_OK as i32); let mut ap_count: u16 = 0; esp_wifi_scan_get_ap_num(&mut ap_count as *mut _); // Allocate storage (on stack for small counts; heap otherwise) const MAX_APS: usize = 20; let mut records = [core::mem::zeroed::(); MAX_APS]; let mut num = ap_count.min(MAX_APS as u16); let rc = esp_wifi_scan_get_ap_records( &mut num as *mut _, records.as_mut_ptr(), ); assert_eq!(rc, ESP_OK as i32); // records[0..num] now contain SSID, BSSID, RSSI, authmode, channel, etc. // After this call the internal list is freed automatically. } ``` -------------------------------- ### `esp_wifi_set_config` — configure station or soft-AP credentials Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Configures the credentials and parameters for either the station or soft-AP interface. This function persists the configuration to NVS. ```APIDOC ## `esp_wifi_set_config` — configure station or soft-AP credentials Writes the SSID/password and other parameters for the specified interface. For `WIFI_IF_STA` the config union field `sta` (`wifi_sta_config_t`) is used; for `WIFI_IF_AP` the `ap` field (`wifi_ap_config_t`) is used. Configuration is persisted to NVS. ### Parameters - **`iface`** (*`wifi_interface_t`*) - The WiFi interface to configure (`WIFI_IF_STA` or `WIFI_IF_AP`). - **`conf`** (*`*wifi_config_t`*) - Pointer to the WiFi configuration structure. ### Returns - **`ESP_OK`** on success, or an error code on failure. ### Request Example ```rust use esp_wifi_sys_esp32::include::{ esp_wifi_set_config, wifi_config_t, wifi_sta_config_t, wifi_interface_t_WIFI_IF_STA, ESP_OK, }; unsafe fn set_sta_credentials(ssid: &[u8; 32], password: &[u8; 64]) { let mut sta_cfg = core::mem::zeroed::(); sta_cfg.ssid.copy_from_slice(ssid); sta_cfg.password.copy_from_slice(password); sta_cfg.set_rm_enabled(1); sta_cfg.set_btm_enabled(1); let mut cfg = core::mem::zeroed::(); cfg.sta = sta_cfg; let rc = esp_wifi_set_config(wifi_interface_t_WIFI_IF_STA, &mut cfg as *mut _); assert_eq!(rc, ESP_OK as i32, "set_config failed: {}", rc); } ``` ``` -------------------------------- ### Use C Primitive Type Aliases Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Use these aliases instead of raw primitives when working with generated bindings. They map common C types to their `core::ffi` equivalents. ```rust #![no_std] use esp_wifi_sys_esp32c3::c_types::{ c_int, c_uint, c_uchar, c_char, c_void, c_long, c_ulong, c_short, c_ushort, c_longlong, c_ulonglong, c_schar, }; // Typical use: casting raw pointers from bindgen-generated structs fn demo(raw_buf: *const c_uchar, len: c_uint) { // c_uchar == u8, c_uint == u32 on all supported ESP32 targets let _slice: &[u8] = unsafe { core::slice::from_raw_parts(raw_buf, len as usize) }; } ``` -------------------------------- ### Bindgen Regeneration Tool Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt An internal workspace utility (`cargo xtask`) that re-generates the `include.rs` bindings for all chips using `bindgen` against the Espressif GCC toolchain sysroot. Useful when updating to a new Espressif IDF / toolchain version or adding chip support. ```APIDOC ## `xtask` — bindgen regeneration tool An internal workspace utility (`cargo xtask`) that re-generates the `include.rs` bindings for all chips using `bindgen` against the Espressif GCC toolchain sysroot. Useful when updating to a new Espressif IDF / toolchain version or adding chip support. ```bash # Prerequisites: Espressif toolchain installed at ~/.espressif/tools # OR set ESP_TOOLS_DIR to the tools directory. # Run from the workspace root to regenerate all chip bindings: cargo xtask # The tool iterates all chips, runs bindgen with the correct # --sysroot, --target, and -I include paths, writes each # esp-wifi-sys-/src/include.rs, then appends: # unsafe impl Sync for wifi_init_config_t {} # unsafe impl Sync for wifi_osi_funcs_t {} # and formats the output with rustfmt. # After regeneration, strip .eh_frame from libs if you see linker errors: riscv32-esp-elf-objcopy --remove-section=.eh_frame \ esp-wifi-sys-esp32c61/libs/libphy.a ``` ``` -------------------------------- ### Strip .eh_frame Segment with objcopy Source: https://github.com/esp-rs/esp-wifi-sys/blob/main/README.md Use this command to strip the .eh_frame segment from binaries when encountering linker errors related to discarded sections. This is a common workaround for specific toolchain versions. ```bash riscv32-esp-elf-objcopy --remove-section=.eh_frame esp-wifi-sys-esp32c61/libs/libphy.a ``` -------------------------------- ### MAC Address Management Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Reads or overrides the MAC address for a specific WiFi interface (STA or AP). The MAC address must be set before `esp_wifi_start`. Ensure the unicast bit is 0 and addresses differ between interfaces. ```APIDOC ## `esp_wifi_set_mac` / `esp_wifi_get_mac` — MAC address management Reads or overrides the MAC address of a specific WiFi interface. The MAC must be set before `esp_wifi_start`. Unicast bit (LSB of first byte) must be 0 and the address must differ between STA and AP interfaces. ### Usage Example ```rust use esp_wifi_sys_esp32::include::{ esp_wifi_set_mac, esp_wifi_get_mac, wifi_interface_t_WIFI_IF_STA, ESP_OK, }; unsafe fn override_sta_mac() { let new_mac: [u8; 6] = [0xDE, 0xAD, 0xBE, 0xEF, 0x00, 0x01]; let rc = esp_wifi_set_mac( wifi_interface_t_WIFI_IF_STA, new_mac.as_ptr(), ); assert_eq!(rc, ESP_OK as i32, "set_mac failed: {}", rc); let mut read_mac = [0u8; 6]; esp_wifi_get_mac(wifi_interface_t_WIFI_IF_STA, read_mac.as_mut_ptr()); assert_eq!(read_mac, new_mac); } ``` ``` -------------------------------- ### Query Connected AP Information Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Retrieves details of the currently associated Access Point, including SSID, BSSID, channel, RSSI, and security. `esp_wifi_sta_get_rssi` provides a quick RSSI-only read. Note that the SSID is a null-terminated C string within a fixed-size array. ```rust use esp_wifi_sys_esp32::include::{ esp_wifi_sta_get_ap_info, esp_wifi_sta_get_rssi, wifi_ap_record_t, ESP_OK, }; use core::ffi::CStr; unsafe fn print_connected_ap_info() { let mut info = core::mem::zeroed::(); let rc = esp_wifi_sta_get_ap_info(&mut info as *mut _); if rc == ESP_OK as i32 { // SSID is a null-terminated C string inside a [u8; 33] let ssid = CStr::from_ptr(info.ssid.as_ptr() as *const _); let _ = ssid; // use e.g. defmt::info!("SSID: {}", ssid.to_str().unwrap()) // info.rssi: i8 — current signal strength in dBm // info.primary: u8 — channel number // info.authmode: wifi_auth_mode_t } let mut rssi: core::ffi::c_int = 0; esp_wifi_sta_get_rssi(&mut rssi as *mut _); // rssi is the RSSI value from the most recent beacon } ``` -------------------------------- ### Handle esp_err_t Errors Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Check return codes against `ESP_OK`, `ESP_FAIL`, and specific error constants. Use `esp_err_to_name` to convert error codes to human-readable strings. ```rust #![no_std] use esp_wifi_sys_esp32::include::{ esp_err_t, ESP_OK, ESP_FAIL, ESP_ERR_NO_MEM, esp_err_to_name, }; use core::ffi::CStr; unsafe fn check(rc: esp_err_t) { if rc == ESP_OK as esp_err_t { // success } else if rc == ESP_ERR_NO_MEM as esp_err_t { // out of memory } else { // generic failure — convert to name for debug output let name_ptr = esp_err_to_name(rc); // Safety: pointer is to a static string inside the driver blob let _name: &str = CStr::from_ptr(name_ptr).to_str().unwrap_or("?"); // e.g. "ESP_FAIL", "ESP_ERR_WIFI_NOT_INIT", … } } ``` -------------------------------- ### Query Connected AP Information Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Retrieves detailed information about the currently associated Access Point, including SSID, BSSID, channel, and RSSI. `esp_wifi_sta_get_rssi` provides a quick RSSI-only read. ```APIDOC ## `esp_wifi_sta_get_ap_info` / `esp_wifi_sta_get_rssi` — query connected AP Retrieves the `wifi_ap_record_t` for the currently associated AP (SSID, BSSID, channel, RSSI, cipher suite, 802.11 capabilities). `esp_wifi_sta_get_rssi` provides a quick RSSI-only read. ### Usage Example ```rust use esp_wifi_sys_esp32::include::{ esp_wifi_sta_get_ap_info, esp_wifi_sta_get_rssi, wifi_ap_record_t, ESP_OK, }; use core::ffi::CStr; unsafe fn print_connected_ap_info() { let mut info = core::mem::zeroed::(); let rc = esp_wifi_sta_get_ap_info(&mut info as *mut _); if rc == ESP_OK as i32 { // SSID is a null-terminated C string inside a [u8; 33] let ssid = CStr::from_ptr(info.ssid.as_ptr() as *const _); let _ = ssid; // use e.g. defmt::info!("SSID: {}", ssid.to_str().unwrap()) // info.rssi: i8 — current signal strength in dBm // info.primary: u8 — channel number // info.authmode: wifi_auth_mode_t } let mut rssi: core::ffi::c_int = 0; esp_wifi_sta_get_rssi(&mut rssi as *mut _); // rssi is the RSSI value from the most recent beacon } ``` ``` -------------------------------- ### `esp_wifi_set_mode` / `esp_wifi_get_mode` — WiFi operating mode Source: https://context7.com/esp-rs/esp-wifi-sys/llms.txt Sets and retrieves the WiFi operating mode. Available modes include Station, Soft-AP, concurrent Station+AP, and NAN. ```APIDOC ## `esp_wifi_set_mode` / `esp_wifi_get_mode` — WiFi operating mode Sets the operating mode before calling `esp_wifi_start`. Available modes are `wifi_mode_t_WIFI_MODE_STA` (station), `wifi_mode_t_WIFI_MODE_AP` (soft-AP), `wifi_mode_t_WIFI_MODE_APSTA` (concurrent station+AP), and `wifi_mode_t_WIFI_MODE_NAN`. ### `esp_wifi_set_mode` #### Parameters - **`mode`** (*`wifi_mode_t`*) - The desired WiFi operating mode. #### Returns - **`ESP_OK`** on success, or an error code on failure. ### `esp_wifi_get_mode` #### Parameters - **`current_mode`** (*`*wifi_mode_t`*) - Pointer to a variable where the current WiFi mode will be stored. #### Returns - **`ESP_OK`** on success, or an error code on failure. ### Request Example ```rust use esp_wifi_sys_esp32::include::{ esp_wifi_set_mode, esp_wifi_get_mode, wifi_mode_t_WIFI_MODE_STA, wifi_mode_t, ESP_OK, }; unsafe fn configure_as_sta() { let rc = esp_wifi_set_mode(wifi_mode_t_WIFI_MODE_STA); assert_eq!(rc, ESP_OK as i32); let mut current_mode: wifi_mode_t = 0; let rc = esp_wifi_get_mode(&mut current_mode as *mut _); assert_eq!(rc, ESP_OK as i32); assert_eq!(current_mode, wifi_mode_t_WIFI_MODE_STA); } ``` ```