zeroclaw/peripherals/
mod.rs1#[allow(unused_imports)]
2#[cfg(feature = "hardware")]
3pub use zeroclaw_hardware::peripherals::*;
4
5use crate::config::{Config, PeripheralBoardConfig};
6use anyhow::Result;
7
8pub async fn handle_command(cmd: crate::PeripheralCommands, config: &Config) -> Result<()> {
9 match cmd {
10 crate::PeripheralCommands::List => {
11 let boards: Vec<&PeripheralBoardConfig> = if config.peripherals.enabled {
12 config.peripherals.boards.iter().collect()
13 } else {
14 Vec::new()
15 };
16 if boards.is_empty() {
17 println!("No peripherals configured.");
18 println!();
19 println!("Add one with: zeroclaw peripheral add <board> <path>");
20 println!(" Example: zeroclaw peripheral add nucleo-f401re /dev/ttyACM0");
21 println!();
22 println!("Or add to config.toml:");
23 println!(" [peripherals]");
24 println!(" enabled = true");
25 println!();
26 println!(" [[peripherals.boards]]");
27 println!(" board = \"nucleo-f401re\"");
28 println!(" transport = \"serial\"");
29 println!(" path = \"/dev/ttyACM0\"");
30 } else {
31 println!("Configured peripherals:");
32 for b in boards {
33 let path = b.path.as_deref().unwrap_or("(native)");
34 println!(" {} {} {}", b.board, b.transport, path);
35 }
36 }
37 }
38 crate::PeripheralCommands::Add { board, path } => {
39 let transport = if path == "native" { "native" } else { "serial" };
40 let path_opt = if path == "native" {
41 None
42 } else {
43 Some(path.clone())
44 };
45
46 let mut cfg = Box::pin(crate::config::Config::load_or_init()).await?;
47 cfg.peripherals.enabled = true;
48
49 if cfg
50 .peripherals
51 .boards
52 .iter()
53 .any(|b| b.board == board && b.path.as_deref() == path_opt.as_deref())
54 {
55 println!("Board {} at {:?} already configured.", board, path_opt);
56 return Ok(());
57 }
58
59 cfg.peripherals.boards.push(PeripheralBoardConfig {
60 board: board.clone(),
61 transport: transport.to_string(),
62 path: path_opt,
63 baud: 115_200,
64 });
65 Box::pin(cfg.save()).await?;
66 println!("Added {} at {}. Restart daemon to apply.", board, path);
67 }
68 #[cfg(feature = "hardware")]
69 crate::PeripheralCommands::Flash { port } => {
70 let port_str = arduino_flash::resolve_port(config, port.as_deref())
71 .or_else(|| port.clone())
72 .ok_or_else(|| {
73 ::zeroclaw_log::record!(
74 WARN,
75 ::zeroclaw_log::Event::new(module_path!(), ::zeroclaw_log::Action::Reject)
76 .with_outcome(::zeroclaw_log::EventOutcome::Failure),
77 "peripheral flash refused: no port resolved (no --port flag and no arduino-uno in config)"
78 );
79 anyhow::Error::msg(
80 "No port specified. Use --port /dev/cu.usbmodem* or add arduino-uno to config.toml"
81 )
82 })?;
83 arduino_flash::flash_arduino_firmware(&port_str)?;
84 }
85 #[cfg(not(feature = "hardware"))]
86 crate::PeripheralCommands::Flash { .. } => {
87 println!("Arduino flash requires the 'hardware' feature.");
88 println!("Build with: cargo build --features hardware");
89 }
90 #[cfg(feature = "hardware")]
91 crate::PeripheralCommands::SetupUnoQ { host } => {
92 uno_q_setup::setup_uno_q_bridge(host.as_deref())?;
93 }
94 #[cfg(not(feature = "hardware"))]
95 crate::PeripheralCommands::SetupUnoQ { .. } => {
96 println!("Uno Q setup requires the 'hardware' feature.");
97 println!("Build with: cargo build --features hardware");
98 }
99 #[cfg(feature = "hardware")]
100 crate::PeripheralCommands::FlashNucleo => {
101 nucleo_flash::flash_nucleo_firmware()?;
102 }
103 #[cfg(not(feature = "hardware"))]
104 crate::PeripheralCommands::FlashNucleo => {
105 println!("Nucleo flash requires the 'hardware' feature.");
106 println!("Build with: cargo build --features hardware");
107 }
108 }
109 Ok(())
110}