* 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>
143 lines
4.8 KiB
Rust
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(())
|
|
}
|