app
Adom Symbol
Public Made by Adomby adom
KiCad symbol creator with interactive viewer and delivery to KiCad/Fusion 360
master
John Lauer
1.2.0: chip thumbnail baked into every IC symbol by default (real outline or generic chip), chipOutline/chipSize prefs, AI check-and-revise hints, STEP ladder in hints
9a15e91
1mo ago
//! adom-symbol in the browser: the SAME `sym_gen` the CLI uses, compiled to
//! wasm32 with a plain C ABI (no wasm-bindgen CLI needed). One export:
//! `generate(json) -> kicad_sym` with the CLI's `create` JSON body.
#[path = "../../src/sym_gen.rs"]
#[allow(dead_code)]
mod sym_gen;
use std::alloc::{alloc, dealloc, Layout};
#[derive(serde::Deserialize)]
struct JsonPin { name: String, number: String, #[serde(rename = "type")] ptype: String, #[serde(default)] group: Option<String>, #[serde(default)] side: Option<String> }
#[derive(serde::Deserialize, Default)]
struct Preferences { #[serde(default, rename = "pinLayout")] pin_layout: Option<String>, #[serde(default, rename = "chipNameCentered")] chip_name_centered: bool, #[serde(default, rename = "refPos")] ref_pos: Option<String>, #[serde(default, rename = "valuePos")] value_pos: Option<String>, #[serde(default, rename = "chipOutline")] chip_outline: Option<bool>, #[serde(default, rename = "chipSize")] chip_size: Option<String> }
#[derive(serde::Deserialize)]
struct Input { #[serde(rename = "symbolName")] symbol_name: String, #[serde(default)] manufacturer: String, #[serde(default)] package: String, #[serde(default)] description: String, #[serde(default, rename = "datasheetUrl")] datasheet_url: String, #[serde(default, rename = "referencePrefix")] reference_prefix: Option<String>, #[serde(default)] pins: Vec<JsonPin>, #[serde(default)] preferences: Preferences }
fn run(json: &str) -> String {
let i: Input = match serde_json::from_str(json) { Ok(v) => v, Err(e) => return format!("ERROR: {e}") };
let input = sym_gen::IcInput {
symbol_name: i.symbol_name, manufacturer: i.manufacturer, package: i.package, description: i.description,
datasheet_url: i.datasheet_url, reference_prefix: i.reference_prefix.unwrap_or_else(|| "U".into()),
pins: i.pins.into_iter().map(|p| sym_gen::Pin { name: p.name, number: p.number, ptype: p.ptype, group: p.group, side: p.side }).collect(),
pin_layout: i.preferences.pin_layout.unwrap_or_else(|| "left-right".into()),
chip_name_centered: i.preferences.chip_name_centered,
ref_pos: i.preferences.ref_pos.unwrap_or_default(), value_pos: i.preferences.value_pos.unwrap_or_default(),
distributor_pn: vec![],
// Browser build: no assets to discover, so the generic chip (default ON,
// like the CLI) or nothing.
chip_outline: if i.preferences.chip_outline.unwrap_or(true) { Some(sym_gen::generic_outline(i.preferences.chip_size.as_deref().unwrap_or("large"))) } else { None },
};
sym_gen::generate_ic_sym(&input)
}
/// Allocate `len` bytes the host can write into.
#[no_mangle]
pub extern "C" fn ab_alloc(len: usize) -> *mut u8 { unsafe { alloc(Layout::from_size_align(len.max(1), 1).unwrap()) } }
#[no_mangle]
pub extern "C" fn ab_free(ptr: *mut u8, len: usize) { unsafe { dealloc(ptr, Layout::from_size_align(len.max(1), 1).unwrap()) } }
/// Returns a pointer to [u32 len][bytes...]; free with ab_free(ptr, len+4).
#[no_mangle]
pub extern "C" fn ab_generate(ptr: *const u8, len: usize) -> *mut u8 {
let json = unsafe { std::str::from_utf8_unchecked(std::slice::from_raw_parts(ptr, len)) };
let out = run(json);
let bytes = out.as_bytes();
let total = bytes.len() + 4;
let p = ab_alloc(total);
unsafe {
std::ptr::copy_nonoverlapping((bytes.len() as u32).to_le_bytes().as_ptr(), p, 4);
std::ptr::copy_nonoverlapping(bytes.as_ptr(), p.add(4), bytes.len());
}
p
}