Rust嵌入式WiFi开发库esp-wifi-sys的使用:ESP32/ESP8266低层WiFi驱动与系统集成

Rust嵌入式WiFi开发库esp-wifi-sys的使用:ESP32/ESP8266低层WiFi驱动与系统集成

简介

esp-wifi-sys 是用于Wi-Fi/蓝牙LE无线电所需的二进制blob的低级不安全绑定。这些库和头文件来自ESP-IDF,绑定是通过bindgen生成的。

许可证

该库采用双许可证:

  • Apache License, Version 2.0
  • MIT license

您可以任选其一使用。

安装

在项目目录中运行以下Cargo命令:

cargo add esp-wifi-sys

或在Cargo.toml中添加以下行:

esp-wifi-sys = "0.7.1"

使用示例

以下是一个完整的示例代码,展示如何使用esp-wifi-sys库进行基本的WiFi初始化:

use esp_wifi_sys as sys;

fn main() {
    // 初始化WiFi底层驱动
    unsafe {
        // 初始化TCP/IP协议栈
        sys::esp_netif_init();
        
        // 创建默认事件循环
        sys::esp_event_loop_create_default();
        
        // 初始化WiFi
        let ret = sys::esp_wifi_init(&sys::wifi_init_config_t {
            // 配置参数
            event_handler: Some(wifi_event_handler),
            osi_funcs: std::ptr::null_mut(),
            wpa_crypto_funcs: std::ptr::null_mut(),
            static_rx_buf_num: 16,
            dynamic_rx_buf_num: 32,
            tx_buf_type: 1,
            static_tx_buf_num: 16,
            dynamic_tx_buf_num: 32,
            cache_tx_buf_num: 16,
            csi_enable: 0,
            ampdu_rx_enable: 1,
            ampdu_tx_enable: 1,
            nvs_enable: 1,
            nano_enable: 1,
            rx_ba_win: 6,
            wifi_task_core_id: 0,
            beacon_max_len: 0,
            mgmt_sbuf_num: 32,
            feature_caps: sys::CONFIG_FEATURE_CACHE_TX_BUF_BIT,
            magic: sys::WIFI_INIT_CONFIG_MAGIC,
        });
        
        if ret != sys::ESP_OK as i32 {
            panic!("Failed to initialize WiFi");
        }
        
        // 设置WiFi为STA模式
        sys::esp_wifi_set_mode(sys::wifi_mode_t_WIFI_MODE_STA);
        
        // 启动WiFi
        sys::esp_wifi_start();
    }
}

// WiFi事件处理回调函数
extern "C" fn wifi_event_handler(
    ctx: *mut std::ffi::c_void,
    event: sys::system_event_t,
) {
    match event.event_id {
        sys::SYSTEM_EVENT_WIFI_READY => {
            println!("WiFi ready");
        }
        sys::SYSTEM_EVENT_STA_START => {
            println!("STA start");
        }
        sys::SYSTEM_EVENT_STA_CONNECTED => {
            println!("STA connected");
        }
        sys::SYSTEM_EVENT_STA_GOT_IP => {
            println!("STA got IP");
        }
        _ => {}
    }
}

完整示例demo

以下是一个更完整的示例,展示如何使用esp-wifi-sys连接WiFi网络:

use esp_wifi_sys as sys;
use std::ffi::CString;

fn main() {
    unsafe {
        // 1. 初始化网络堆栈和事件循环
        sys::esp_netif_init();
        sys::esp_event_loop_create_default();

        // 2. 初始化WiFi
        let ret = sys::esp_wifi_init(&sys::wifi_init_config_t {
            event_handler: Some(wifi_event_handler),
            osi_funcs: std::ptr::null_mut(),
            wpa_crypto_funcs: std::ptr::null_mut(),
            static_rx_buf_num: 16,
            dynamic_rx_buf_num: 32,
            tx_buf_type: 1,
            static_tx_buf_num: 16,
            dynamic_tx_buf_num: 32,
            cache_tx_buf_num: 16,
            csi_enable: 0,
            ampdu_rx_enable: 1,
            ampdu_tx_enable: 1,
            nvs_enable: 1,
            nano_enable: 1,
            rx_ba_win: 6,
            wifi_task_core_id: 0,
            beacon_max_len: 0,
            mgmt_sbuf_num: 32,
            feature_caps: sys::CONFIG_FEATURE_CACHE_TX_BUF_BIT,
            magic: sys::WIFI_INIT_CONFIG_MAGIC,
        });

        if ret != sys::ESP_OK as i32 {
            panic!("Failed to initialize WiFi");
        }

        // 3. 配置WiFi为STA模式
        sys::esp_wifi_set_mode(sys::wifi_mode_t_WIFI_MODE_STA);

        // 4. 配置WiFi连接参数
        let ssid = CString::new("YourSSID").unwrap();
        let password = CString::new("YourPassword").unwrap();
        
        let wifi_config = sys::wifi_config_t {
            sta: sys::wifi_sta_config_t {
                ssid: [0; 32],
                password: [0; 64],
                scan_method: sys::WIFI_FAST_SCAN,
                bssid_set: 0,
                bssid: [0; 6],
                channel: 0,
                listen_interval: 0,
                sort_method: sys::WIFI_CONNECT_AP_BY_SIGNAL,
                threshold: sys::wifi_scan_threshold_t {
                    rssi: 0,
                    authmode: sys::WIFI_AUTH_WPA2_PSK as u8,
                },
                ..Default::default()
            },
        };

        // 复制SSID和密码到配置结构体
        std::ptr::copy_nonoverlapping(
            ssid.as_ptr(),
            wifi_config.sta.ssid.as_mut_ptr(),
            ssid.as_bytes().len(),
        );
        std::ptr::copy_nonoverlapping(
            password.as_ptr(),
            wifi_config.sta.password.as_mut_ptr(),
            password.as_bytes().len(),
        );

        // 5. 设置WiFi配置
        sys::esp_wifi_set_config(sys::wifi_interface_t_WIFI_IF_STA, &wifi_config);

        // 6. 启动WiFi
        sys::esp_wifi_start();

        // 7. 连接WiFi网络
        sys::esp_wifi_connect();

        // 主循环
        loop {
            // 保持程序运行
            std::thread::sleep(std::time::Duration::from_secs(1));
        }
    }
}

// WiFi事件处理回调函数
extern "C" fn wifi_event_handler(
    ctx: *mut std::ffi::c_void,
    event: sys::system_event_t,
) {
    match event.event_id {
        sys::SYSTEM_EVENT_WIFI_READY => println!("WiFi ready"),
        sys::SYSTEM_EVENT_STA_START => println!("STA started"),
        sys::SYSTEM_EVENT_STA_CONNECTED => println!("Connected to AP"),
        sys::SYSTEM_EVENT_STA_GOT_IP => {
            let event_info = unsafe { event.event_info };
            let ip_info = unsafe { event_info.got_ip.ip_info };
            println!(
                "Got IP: {}.{}.{}.{}",
                (ip_info.ip.addr >> 0) & 0xff,
                (ip_info.ip.addr >> 8) & 0xff,
                (ip_info.ip.addr >> 16) & 0xff,
                (ip_info.ip.addr >> 24) & 0xff
            );
        }
        sys::SYSTEM_EVENT_STA_DISCONNECTED => {
            println!("Disconnected from AP, attempting to reconnect...");
            unsafe { sys::esp_wifi_connect() };
        }
        _ => {}
    }
}

注意事项

  1. 该库提供的是低级不安全绑定,使用时需要特别注意内存安全和线程安全
  2. 使用时需要依赖ESP-IDF提供的二进制blob
  3. 所有操作都需要在unsafe块中进行
  4. 需要正确配置ESP32/ESP8266的开发环境

贡献

除非您明确声明,否则任何有意提交的作品都将按照Apache-2.0许可证双重许可,如上所述,没有任何附加条款或条件。

适用领域

该库适用于:

  • 无标准库环境(No standard library)
  • 嵌入式开发(Embedded development)
  • 硬件支持(Hardware support)

1 回复

Rust嵌入式WiFi开发库esp-wifi-sys的使用指南

完整示例Demo

下面是一个结合STA模式连接、AP模式创建和WiFi事件处理的完整示例:

use esp_wifi_sys::{
    wifi_init_config_t, wifi_config_t, wifi_mode_t,
    esp_wifi_init, esp_wifi_set_mode, esp_wifi_set_config, 
    esp_wifi_start, esp_wifi_connect, esp_wifi_scan_start,
    esp_event_base_t, system_event_t, esp_event_handler_register,
    WIFI_EVENT, IP_EVENT, WIFI_EVENT_STA_START, 
    WIFI_EVENT_STA_CONNECTED, WIFI_EVENT_STA_DISCONNECTED,
    IP_EVENT_STA_GOT_IP, wifi_scan_config_t
};

// WiFi事件处理回调函数
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,
) {
    match (event_base, event_id) {
        (WIFI_EVENT, WIFI_EVENT_STA_START) => {
            println!("[事件] WiFi STA模式已启动");
        }
        (WIFI_EVENT, WIFI_EVENT_STA_CONNECTED) => {
            println!("[事件] 已连接到AP");
        }
        (WIFI_EVENT, WIFI_EVENT_STA_DISCONNECTED) => {
            println!("[事件] 从AP断开连接");
            // 这里可以添加重连逻辑
        }
        (IP_EVENT, IP_EVENT_STA_GOT_IP) => {
            let event = &*(event_data as *const system_event_t);
            println!("[事件] 获取到IP: {:?}", event.event_info.got_ip.ip_info.ip);
        }
        _ => {}
    }
}

// 初始化WiFi并注册事件处理器
fn init_wifi() {
    // 初始化默认配置
    let init_config = wifi_init_config_t::default();
    unsafe {
        esp_wifi_init(&init_config).unwrap();
    }
    
    // 注册WiFi事件处理器
    unsafe {
        esp_event_handler_register(
            WIFI_EVENT,
            esp_wifi_sys::ESP_EVENT_ANY_ID,
            Some(wifi_event_handler),
            core::ptr::null_mut(),
        ).unwrap();
        
        esp_event_handler_register(
            IP_EVENT,
            IP_EVENT_STA_GOT_IP,
            Some(wifi_event_handler),
            core::ptr::null_mut(),
        ).unwrap();
    }
}

// 连接到指定WiFi网络
fn connect_to_wifi(ssid: &str, password: &str) {
    // 设置为STA模式
    unsafe {
        esp_wifi_set_mode(wifi_mode_t::WIFI_MODE_STA).unwrap();
    }
    
    // 配置网络参数
    let mut wifi_config = wifi_config_t::default();
    let ssid_slice = ssid.as_bytes();
    let pass_slice = password.as_bytes();
    
    // 复制SSID和密码到配置结构
    wifi_config.sta.ssid[..ssid_slice.len()].copy_from_slice(ssid_slice);
    wifi_config.sta.password[..pass_slice.len()].copy_from_slice(pass_slice);
    
    // 设置配置并启动WiFi
    unsafe {
        esp_wifi_set_config(wifi_mode_t::WIFI_MODE_STA, &wifi_config).unwrap();
        esp_wifi_start().unwrap();
        esp_wifi_connect().unwrap();
    }
}

// 创建AP热点
fn create_ap(ssid: &str, password: Option<&str>) {
    // 设置为AP模式
    unsafe {
        esp_wifi_set_mode(wifi_mode_t::WIFI_MODE_AP).unwrap();
    }
    
    let mut wifi_config = wifi_config_t::default();
    let ssid_slice = ssid.as_bytes();
    wifi_config.ap.ssid[..ssid_slice.len()].copy_from_slice(ssid_slice);
    wifi_config.ap.ssid_len = ssid_slice.len() as u8;
    
    // 设置密码或开放网络
    if let Some(pass) = password {
        let pass_slice = pass.as_bytes();
        wifi_config.ap.password[..pass_slice.len()].copy_from_slice(pass_slice);
        wifi_config.ap.authmode = wifi_auth_mode_t::WIFI_AUTH_WPA2_PSK;
    } else {
        wifi_config.ap.authmode = wifi_auth_mode_t::WIFI_AUTH_OPEN;
    }
    
    unsafe {
        esp_wifi_set_config(wifi_mode_t::WIFI_MODE_AP, &wifi_config).unwrap();
        esp_wifi_start().unwrap();
    }
}

// 扫描附近WiFi网络
fn scan_networks() {
    let scan_config = wifi_scan_config_t {
        ssid: None,
        bssid: None,
        channel: 0,
        show_hidden: true,
        scan_type: wifi_scan_type_t::WIFI_SCAN_TYPE_ACTIVE,
        scan_time: wifi_scan_time_t::default(),
    };
    
    unsafe {
        println!("开始扫描WiFi网络...");
        esp_wifi_scan_start(&scan_config, true).unwrap();
        
        let mut ap_num = 0;
        esp_wifi_scan_get_ap_num(&mut ap_num).unwrap();
        println!("发现 {} 个网络", ap_num);
        
        let mut ap_records = vec![wifi_ap_record_t::default(); ap_num as usize];
        esp_wifi_scan_get_ap_records(&mut ap_num, ap_records.as_mut_ptr()).unwrap();
        
        for (i, record) in ap_records.iter().enumerate() {
            let ssid = core::str::from_utf8(&record.ssid).unwrap_or("[无效SSID]");
            println!("{}. SSID: {}, 信号强度: {}dBm, 信道: {}", 
                    i+1, ssid, record.rssi, record.primary);
        }
    }
}

fn main() {
    // 初始化WiFi
    init_wifi();
    
    // 示例1: 连接到WiFi网络
    println!("正在连接到WiFi网络...");
    connect_to_wifi("your_ssid", "your_password");
    
    // 等待连接完成
    std::thread::sleep(std::time::Duration::from_secs(5));
    
    // 示例2: 扫描附近网络
    scan_networks();
    
    // 示例3: 创建AP热点
    println!("正在创建AP热点...");
    create_ap("MyESP32AP", Some("ap_password"));
    
    // 保持程序运行
    loop {
        std::thread::sleep(std::time::Duration::from_secs(1));
    }
}

代码说明

  1. 事件处理:通过wifi_event_handler函数处理各种WiFi事件,如连接、断开、获取IP等
  2. STA模式connect_to_wifi函数实现了连接到指定WiFi网络的功能
  3. AP模式create_ap函数创建了一个WiFi热点,支持设置密码或开放网络
  4. 网络扫描scan_networks函数扫描并显示附近的WiFi网络信息
  5. 初始化init_wifi函数初始化WiFi驱动并注册事件处理器

使用建议

  1. 在实际应用中,应该添加更完善的错误处理
  2. 对于嵌入式设备,考虑添加看门狗定时器防止程序卡死
  3. 可以根据需要扩展事件处理逻辑,如自动重连机制
  4. 生产环境中应该避免硬编码WiFi凭据,建议使用配置系统

这个完整示例展示了esp-wifi-sys库的主要功能,包括STA和AP模式的操作、网络扫描以及事件处理,可以作为开发嵌入式WiFi应用的起点。

回到顶部