#[cfg(feature = "peripheral-esp32")]
use super::board_profile::ESP32_PROFILE;
#[cfg(feature = "peripheral-esp32")]
use super::i2c::{I2cReadTool, I2cScanTool, I2cWriteTool};
#[cfg(feature = "peripheral-esp32")]
use super::nvs::{NvsDeleteTool, NvsGetTool, NvsSetTool};
#[cfg(feature = "peripheral-esp32")]
use super::serial::{SerialPeripheral, SerialTransport};
#[cfg(feature = "peripheral-esp32")]
use super::traits::Peripheral;
#[cfg(feature = "peripheral-esp32")]
use crate::error::Result;
#[cfg(feature = "peripheral-esp32")]
use crate::tools::Tool;
#[cfg(feature = "peripheral-esp32")]
use async_trait::async_trait;
#[cfg(feature = "peripheral-esp32")]
use std::sync::Arc;
#[cfg(feature = "peripheral-esp32")]
const ESP32_DEFAULT_BAUD: u32 = 115_200;
#[cfg(feature = "peripheral-esp32")]
pub struct Esp32Peripheral {
inner: SerialPeripheral,
transport: Arc<SerialTransport>,
}
#[cfg(feature = "peripheral-esp32")]
impl Esp32Peripheral {
pub fn new(path: &str) -> Result<Self> {
let inner = SerialPeripheral::connect_to(path, "esp32", ESP32_DEFAULT_BAUD)?;
let transport = inner.transport();
Ok(Self { inner, transport })
}
}
#[cfg(feature = "peripheral-esp32")]
#[async_trait]
impl Peripheral for Esp32Peripheral {
fn name(&self) -> &str {
self.inner.name()
}
fn board_type(&self) -> &str {
"esp32"
}
async fn connect(&mut self) -> Result<()> {
self.inner.connect().await
}
async fn disconnect(&mut self) -> Result<()> {
self.inner.disconnect().await
}
async fn health_check(&self) -> bool {
self.inner.health_check().await
}
fn tools(&self) -> Vec<Box<dyn Tool>> {
let mut tools: Vec<Box<dyn Tool>> = self.inner.tools();
if !ESP32_PROFILE.i2c_buses.is_empty() {
tools.push(Box::new(I2cScanTool {
transport: self.transport.clone(),
profile: &ESP32_PROFILE,
}));
tools.push(Box::new(I2cReadTool {
transport: self.transport.clone(),
profile: &ESP32_PROFILE,
}));
tools.push(Box::new(I2cWriteTool {
transport: self.transport.clone(),
profile: &ESP32_PROFILE,
}));
}
if ESP32_PROFILE.has_nvs {
tools.push(Box::new(NvsGetTool {
transport: self.transport.clone(),
}));
tools.push(Box::new(NvsSetTool {
transport: self.transport.clone(),
}));
tools.push(Box::new(NvsDeleteTool {
transport: self.transport.clone(),
}));
}
tools
}
}
#[cfg(all(test, feature = "peripheral-esp32"))]
mod tests {
use super::*;
use crate::peripherals::board_profile::ESP32_PROFILE;
#[test]
fn test_esp32_default_baud() {
assert_eq!(ESP32_DEFAULT_BAUD, 115_200);
}
#[test]
fn test_esp32_profile_has_i2c() {
assert!(
!ESP32_PROFILE.i2c_buses.is_empty(),
"ESP32 profile should have I2C buses"
);
let bus = ESP32_PROFILE.i2c_bus(0).expect("bus 0 should exist");
assert_eq!(bus.sda_pin, 21);
assert_eq!(bus.scl_pin, 22);
}
#[test]
fn test_esp32_profile_has_nvs() {
assert!(
ESP32_PROFILE.has_nvs,
"ESP32 profile should have NVS support"
);
}
#[test]
fn test_esp32_new_rejects_invalid_path() {
match Esp32Peripheral::new("/etc/passwd") {
Ok(_) => panic!("should reject disallowed path"),
Err(e) => {
let msg = e.to_string();
assert!(
msg.contains("not allowed"),
"error should mention 'not allowed', got: {msg}"
);
}
}
}
}