Skip to main content

zeroclaw/peripherals/
mod.rs

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