zeroclaw/src/peripherals/uno_q_setup.rs
ehu shubham shaw de3ec87d16
Ehu shubham shaw contribution --> Hardware support (#306)
* feat: add ZeroClaw firmware for ESP32 and Nucleo

* Introduced new firmware for ZeroClaw on ESP32 and Nucleo-F401RE, enabling JSON-over-serial communication for GPIO control.
* Added `zeroclaw-esp32` with support for commands like `gpio_read` and `gpio_write`, along with capabilities reporting.
* Implemented `zeroclaw-nucleo` firmware with similar functionality for STM32, ensuring compatibility with existing ZeroClaw protocols.
* Updated `.gitignore` to include new firmware targets and added necessary dependencies in `Cargo.toml` for both platforms.
* Created README files for both firmware projects detailing setup, build, and usage instructions.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* feat: enhance hardware peripheral support and documentation

- Added `Peripheral` trait implementation in `src/peripherals/` to manage hardware boards (STM32, RPi GPIO).
- Updated `AGENTS.md` to include new extension points for peripherals and their configuration.
- Introduced comprehensive documentation for adding boards and tools, including a quick start guide and supported boards.
- Enhanced `Cargo.toml` to include optional dependencies for PDF extraction and peripheral support.
- Created new datasheets for Arduino Uno, ESP32, and Nucleo-F401RE, detailing pin aliases and GPIO usage.
- Implemented new tools for hardware memory reading and board information retrieval in the agent loop.

This update significantly improves the integration and usability of hardware peripherals within the ZeroClaw framework.

* feat: add ZeroClaw firmware for ESP32 and Nucleo

* Introduced new firmware for ZeroClaw on ESP32 and Nucleo-F401RE, enabling JSON-over-serial communication for GPIO control.
* Added `zeroclaw-esp32` with support for commands like `gpio_read` and `gpio_write`, along with capabilities reporting.
* Implemented `zeroclaw-nucleo` firmware with similar functionality for STM32, ensuring compatibility with existing ZeroClaw protocols.
* Updated `.gitignore` to include new firmware targets and added necessary dependencies in `Cargo.toml` for both platforms.
* Created README files for both firmware projects detailing setup, build, and usage instructions.

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>

* feat: enhance hardware peripheral support and documentation

- Added `Peripheral` trait implementation in `src/peripherals/` to manage hardware boards (STM32, RPi GPIO).
- Updated `AGENTS.md` to include new extension points for peripherals and their configuration.
- Introduced comprehensive documentation for adding boards and tools, including a quick start guide and supported boards.
- Enhanced `Cargo.toml` to include optional dependencies for PDF extraction and peripheral support.
- Created new datasheets for Arduino Uno, ESP32, and Nucleo-F401RE, detailing pin aliases and GPIO usage.
- Implemented new tools for hardware memory reading and board information retrieval in the agent loop.

This update significantly improves the integration and usability of hardware peripherals within the ZeroClaw framework.

* feat: Introduce hardware auto-discovery and expanded configuration options for agents, hardware, and security.

* chore: update dependencies and improve probe-rs integration

- Updated `Cargo.lock` to remove specific version constraints for several dependencies, including `zerocopy`, `syn`, and `strsim`, allowing for more flexibility in version resolution.
- Upgraded `bincode` and `bitfield` to their latest versions, enhancing serialization and memory management capabilities.
- Updated `Cargo.toml` to reflect the new version of `probe-rs` from `0.24` to `0.30`, improving hardware probing functionality.
- Refactored code in `src/hardware` and `src/tools` to utilize the new `SessionConfig` for session management in `probe-rs`, ensuring better compatibility and performance.
- Cleaned up documentation in `docs/datasheets/nucleo-f401re.md` by removing unnecessary lines.

* fix: apply cargo fmt

* docs: add hardware architecture diagram.

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 11:40:10 -05:00

143 lines
4.8 KiB
Rust

//! Deploy ZeroClaw Bridge app to Arduino Uno Q.
use anyhow::{Context, Result};
use std::process::Command;
const BRIDGE_APP_NAME: &str = "zeroclaw-uno-q-bridge";
/// Deploy the Bridge app. If host is Some, scp from repo and ssh to start.
/// If host is None, assume we're ON the Uno Q — use embedded files and start.
pub fn setup_uno_q_bridge(host: Option<&str>) -> Result<()> {
let bridge_dir = std::path::Path::new(env!("CARGO_MANIFEST_DIR"))
.join("firmware")
.join("zeroclaw-uno-q-bridge");
if let Some(h) = host {
if bridge_dir.exists() {
deploy_remote(h, &bridge_dir)?;
} else {
anyhow::bail!(
"Bridge app not found at {}. Run from zeroclaw repo root.",
bridge_dir.display()
);
}
} else {
deploy_local(if bridge_dir.exists() {
Some(&bridge_dir)
} else {
None
})?;
}
Ok(())
}
fn deploy_remote(host: &str, bridge_dir: &std::path::Path) -> Result<()> {
let ssh_target = if host.contains('@') {
host.to_string()
} else {
format!("arduino@{}", host)
};
println!("Copying Bridge app to {}...", host);
let status = Command::new("ssh")
.args([&ssh_target, "mkdir", "-p", "~/ArduinoApps"])
.status()
.context("ssh mkdir failed")?;
if !status.success() {
anyhow::bail!("Failed to create ArduinoApps dir on Uno Q");
}
let status = Command::new("scp")
.args([
"-r",
bridge_dir.to_str().unwrap(),
&format!("{}:~/ArduinoApps/", ssh_target),
])
.status()
.context("scp failed")?;
if !status.success() {
anyhow::bail!("Failed to copy Bridge app");
}
println!("Starting Bridge app on Uno Q...");
let status = Command::new("ssh")
.args([
&ssh_target,
"arduino-app-cli",
"app",
"start",
&format!("~/ArduinoApps/zeroclaw-uno-q-bridge"),
])
.status()
.context("arduino-app-cli start failed")?;
if !status.success() {
anyhow::bail!("Failed to start Bridge app. Ensure arduino-app-cli is installed on Uno Q.");
}
println!("ZeroClaw Bridge app started. Add to config.toml:");
println!(" [[peripherals.boards]]");
println!(" board = \"arduino-uno-q\"");
println!(" transport = \"bridge\"");
Ok(())
}
fn deploy_local(bridge_dir: Option<&std::path::Path>) -> Result<()> {
let home = std::env::var("HOME").unwrap_or_else(|_| "/home/arduino".into());
let apps_dir = std::path::Path::new(&home).join("ArduinoApps");
let dest_dir = apps_dir.join(BRIDGE_APP_NAME);
std::fs::create_dir_all(&dest_dir).context("create dest dir")?;
if let Some(src) = bridge_dir {
println!("Copying Bridge app from repo...");
copy_dir(src, &dest_dir)?;
} else {
println!("Writing embedded Bridge app...");
write_embedded_bridge(&dest_dir)?;
}
println!("Starting Bridge app...");
let status = Command::new("arduino-app-cli")
.args(["app", "start", dest_dir.to_str().unwrap()])
.status()
.context("arduino-app-cli start failed")?;
if !status.success() {
anyhow::bail!("Failed to start Bridge app. Ensure arduino-app-cli is installed on Uno Q.");
}
println!("ZeroClaw Bridge app started.");
Ok(())
}
fn write_embedded_bridge(dest: &std::path::Path) -> Result<()> {
let app_yaml = include_str!("../../firmware/zeroclaw-uno-q-bridge/app.yaml");
let sketch_ino = include_str!("../../firmware/zeroclaw-uno-q-bridge/sketch/sketch.ino");
let sketch_yaml = include_str!("../../firmware/zeroclaw-uno-q-bridge/sketch/sketch.yaml");
let main_py = include_str!("../../firmware/zeroclaw-uno-q-bridge/python/main.py");
let requirements = include_str!("../../firmware/zeroclaw-uno-q-bridge/python/requirements.txt");
std::fs::write(dest.join("app.yaml"), app_yaml)?;
std::fs::create_dir_all(dest.join("sketch"))?;
std::fs::write(dest.join("sketch").join("sketch.ino"), sketch_ino)?;
std::fs::write(dest.join("sketch").join("sketch.yaml"), sketch_yaml)?;
std::fs::create_dir_all(dest.join("python"))?;
std::fs::write(dest.join("python").join("main.py"), main_py)?;
std::fs::write(dest.join("python").join("requirements.txt"), requirements)?;
Ok(())
}
fn copy_dir(src: &std::path::Path, dst: &std::path::Path) -> Result<()> {
for entry in std::fs::read_dir(src)? {
let e = entry?;
let name = e.file_name();
let src_path = src.join(&name);
let dst_path = dst.join(&name);
if e.file_type()?.is_dir() {
std::fs::create_dir_all(&dst_path)?;
copy_dir(&src_path, &dst_path)?;
} else {
std::fs::copy(&src_path, &dst_path)?;
}
}
Ok(())
}