use anyhow::Result;
use espforge_model::Meta;
use toml_edit::{DocumentMut, Item, Table, value};
use super::chip::Chip;
pub const SERIAL_MONITOR: &str = "$serialMonitor";
pub fn board(chip: &str) -> &'static str {
match chip {
"esp32c3" => "board-esp32-c3-devkitm-1",
"esp32c6" => "board-esp32-c6-devkitc-1",
"esp32h2" => "board-esp32-h2-devkitm-1",
"esp32s2" => "board-esp32-s2-devkitm-1",
"esp32s3" => "board-esp32-s3-devkitc-1",
_ => "board-esp32-devkit-c-v4",
}
}
pub fn build(meta: &Meta, chip: &Chip) -> Result<String> {
let firmware = format!("target/{}/debug/{}", chip.rust_target, meta.crate_name());
let mut wokwi = Table::new();
wokwi["version"] = value(1);
wokwi["gdbServerPort"] = value(3333);
wokwi["elf"] = value(firmware.as_str());
wokwi["firmware"] = value(firmware.as_str());
let mut doc = DocumentMut::new();
doc["wokwi"] = Item::Table(wokwi);
Ok(doc.to_string())
}
pub fn chip_section(chip_json: Option<&str>) -> String {
let name = chip_json
.and_then(|text| serde_json::from_str::<serde_json::Value>(text).ok())
.and_then(|v| v.get("name").and_then(|n| n.as_str()).map(str::to_string))
.unwrap_or_else(|| "chip".to_string());
format!("\n[[chip]]\nname = '{name}'\nbinary = 'chip.wasm'\n")
}
#[cfg(test)]
mod tests {
use super::*;
use crate::codegen::test_support::{case, chip};
use espforge_model::Runtime;
fn build_wokwi(meta: &Meta, chip_name: &str) -> String {
build(meta, &chip(chip_name)).unwrap()
}
#[test]
fn the_firmware_paths_name_the_target_and_the_crate() {
let case = case("esp32c3", Runtime::Blocking, true, &[], &[]);
let doc: DocumentMut = build_wokwi(&case.meta, "esp32c3").parse().unwrap();
assert_eq!(doc["wokwi"]["version"].as_integer(), Some(1));
assert_eq!(doc["wokwi"]["gdbServerPort"].as_integer(), Some(3333));
assert_eq!(
doc["wokwi"]["elf"].as_str(),
Some("target/riscv32imc-unknown-none-elf/debug/hello_world")
);
assert_eq!(
doc["wokwi"]["firmware"].as_str(),
doc["wokwi"]["elf"].as_str()
);
}
#[test]
fn the_board_table_matches_the_old_diagram_chain() {
assert_eq!(board("esp32c3"), "board-esp32-c3-devkitm-1");
assert_eq!(board("esp32"), "board-esp32-devkit-c-v4");
assert_eq!(board("esp32s3"), "board-esp32-s3-devkitc-1");
assert_eq!(board("esp32c61"), "board-esp32-devkit-c-v4");
}
#[test]
fn an_xtensa_project_uses_the_xtensa_target() {
let case = case("esp32s3", Runtime::Blocking, true, &[], &[]);
assert!(
build_wokwi(&case.meta, "esp32s3")
.contains("target/xtensa-esp32s3-none-elf/debug/hello_world")
);
}
#[test]
fn the_section_takes_its_name_from_chip_json() {
let json = r#"{"name": "chip", "pins": ["SDA", "SCL"]}"#;
assert_eq!(
chip_section(Some(json)),
"\n[[chip]]\nname = 'chip'\nbinary = 'chip.wasm'\n"
);
assert!(chip_section(Some(r#"{"name": "mcp23017"}"#)).contains("name = 'mcp23017'"));
}
#[test]
fn a_missing_or_broken_chip_json_falls_back_to_chip() {
assert_eq!(
chip_section(None),
"\n[[chip]]\nname = 'chip'\nbinary = 'chip.wasm'\n"
);
assert_eq!(chip_section(Some("not json")), chip_section(None));
}
}