diff --git a/Cargo.toml b/Cargo.toml index 18bfc9e..9f6cf0d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,16 @@ resolver = "2" members = ["crates/*"] # ziggurat-phy-esp and ziggurat-esp only build for an ESP32-C6 (riscv32imac) with esp-hal; # excluded so host `cargo build` over the workspace doesn't try (and fail) to compile them. -exclude = ["fuzz", "crates/ziggurat-phy-esp", "crates/ziggurat-esp"] +# The EFR32MG24 crates likewise only build for thumbv8m.main-none-eabihf (Cortex-M33F). +exclude = [ + "fuzz", + "crates/ziggurat-phy-esp", + "crates/ziggurat-esp", + "crates/ziggurat-efr32-pac", + "crates/ziggurat-rail-sys", + "crates/ziggurat-efr32", + "crates/ziggurat-phy-efr32", +] [workspace.package] version = "0.1.0" diff --git a/crates/ziggurat-driver/src/zigbee_stack.rs b/crates/ziggurat-driver/src/zigbee_stack.rs index c7dfe63..8204f57 100644 --- a/crates/ziggurat-driver/src/zigbee_stack.rs +++ b/crates/ziggurat-driver/src/zigbee_stack.rs @@ -994,7 +994,7 @@ impl ZigbeeStack { loop { let (packet, ieee802154_frame) = self.recv_frame().await; - if !matches!( + if matches!( ieee802154_frame, ziggurat_ieee_802154::Ieee802154Frame::Beacon(_) ) { @@ -1437,9 +1437,15 @@ impl ZigbeeStack { let result: Result<(), RadioError> = async { let radio = self.radio.lock().await; + radio.set_promiscuous(true).await?; + + let mut sweep: Result<(), RadioError> = Ok(()); for &channel in channels { - radio.set_channel(channel).await?; - radio + if let Err(e) = radio.set_channel(channel).await { + sweep = Err(e); + break; + } + let tx = radio .transmit(TxFrame { psdu: beacon_request.clone(), channel: None, @@ -1448,11 +1454,17 @@ impl ZigbeeStack { max_csma_backoffs: self.tunables.mac_max_csma_backoffs, security_processed: true, }) - .await?; + .await; + if let Err(e) = tx { + sweep = Err(e); + break; + } R::sleep(duration_per_channel).await; } - // Leave the radio on the home channel before releasing it. - radio.set_channel(home_channel).await + + radio.set_promiscuous(false).await?; + radio.set_channel(home_channel).await?; + sweep } .await; diff --git a/crates/ziggurat-driver/src/zigbee_stack/mac.rs b/crates/ziggurat-driver/src/zigbee_stack/mac.rs index b250824..5465af6 100644 --- a/crates/ziggurat-driver/src/zigbee_stack/mac.rs +++ b/crates/ziggurat-driver/src/zigbee_stack/mac.rs @@ -205,7 +205,7 @@ impl ZigbeeStack { fcs: 0x0000, }); - frame.to_bytes() + frame.to_bytes_without_fcs() } #[allow(clippy::cognitive_complexity)] @@ -396,7 +396,7 @@ impl ZigbeeStack { tracing::trace!("Sending 802.15.4 frame: {final_frame:?}"); tracing::trace!( "Sending 802.15.4 frame bytes: {:02X?}", - final_frame.to_bytes() + final_frame.to_bytes_without_fcs() ); if self.state.hack_disable_tx { @@ -408,7 +408,7 @@ impl ZigbeeStack { let result = self .radio .transmit(TxFrame { - psdu: final_frame.to_bytes(), + psdu: final_frame.to_bytes_without_fcs(), channel: Some(channel), csma_ca: true, max_frame_retries: self.tunables.mac_max_frame_retries, diff --git a/crates/ziggurat-efr32-pac/.gitignore b/crates/ziggurat-efr32-pac/.gitignore new file mode 100644 index 0000000..96ef6c0 --- /dev/null +++ b/crates/ziggurat-efr32-pac/.gitignore @@ -0,0 +1,2 @@ +/target +Cargo.lock diff --git a/crates/ziggurat-efr32-pac/Cargo.lock b/crates/ziggurat-efr32-pac/Cargo.lock new file mode 100644 index 0000000..412c573 --- /dev/null +++ b/crates/ziggurat-efr32-pac/Cargo.lock @@ -0,0 +1,1150 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f02882884d3e1bc524fb12c79f107f6ad0e1cfd498c536ffb494301740995dfe" + +[[package]] +name = "bare-metal" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "blake2b_simd" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79834656f71332577234b50bfc009996f7449e0c056884e6a02492ded0ca2f3" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "clap" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + +[[package]] +name = "cortex-m" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" +dependencies = [ + "bare-metal", + "bitfield", + "embedded-hal", + "volatile-register", +] + +[[package]] +name = "cortex-m-rt" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6" +dependencies = [ + "cortex-m-rt-macros", +] + +[[package]] +name = "cortex-m-rt-macros" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn", +] + +[[package]] +name = "defmt" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6e524506490a1953d237cb87b1cfc1e46f88c18f10a22dfe0f507dc6bfc7f7f" +dependencies = [ + "bitflags", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0a27770e9c8f719a79d8b638281f4d828f77d8fd61e0bd94451b9b85e576a0b" +dependencies = [ + "defmt-parser", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror 2.0.18", +] + +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn", +] + +[[package]] +name = "displaydoc" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "env_filter" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900d271a03799a1ee8d1ca9b19893b48ca674a9284fefcfb85f05e74ed314217" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de671bd27a75a797dc9ae289ba1e77276e75e2026408aab65185384e2d5cd3f6" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "inflections" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a257582fdcde896fd96463bf2d40eefea0580021c0712a0e2b028b60b47a837a" + +[[package]] +name = "irx-config" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6266a086f9c5635dffbfd7bd49262b2a40e0a580ab34e85d88dc59ed8133976a" +dependencies = [ + "blake2b_simd", + "cfg-if", + "clap", + "derive_builder", + "serde", + "serde_json", + "serde_yaml", + "thiserror 1.0.69", + "toml", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jiff" +version = "0.2.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccfe6121cbe750cf81efa362d85c0bde7ea298ec43092d3a193baca59cdbd634" +dependencies = [ + "defmt", + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", +] + +[[package]] +name = "jiff-static" +version = "0.2.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e165e897f662d428f3cd3828a919dbe067c2d42bb1031eede74ef9d27ecdedd2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "memchr" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "portable-atomic-util" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "roxmltree" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "smallvec" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "svd-parser" +version = "0.14.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41fe17e46dee363a7d3b20e878bbf6d6b4e839ae010ff07ef0e05d41d201811" +dependencies = [ + "anyhow", + "roxmltree", + "svd-rs", + "thiserror 1.0.69", +] + +[[package]] +name = "svd-rs" +version = "0.14.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9b88ee2e82f09623ff76965587dc15a2e7150a3126854899c86e94dab777458" +dependencies = [ + "once_cell", + "regex", + "serde", + "thiserror 1.0.69", +] + +[[package]] +name = "svd2rust" +version = "0.37.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1eaf6a040bfbc04e7b946a6a373b24aab09e1feb875bb0e20c929946c4b7bfc4" +dependencies = [ + "anyhow", + "clap", + "env_logger", + "inflections", + "irx-config", + "log", + "proc-macro2", + "quote", + "regex", + "serde", + "serde_json", + "serde_yaml", + "svd-parser", + "svd-rs", + "syn", + "thiserror 2.0.18", + "url", +] + +[[package]] +name = "syn" +version = "2.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", + "serde_derive", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "vcell" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "volatile-register" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" +dependencies = [ + "vcell", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "ziggurat-efr32-pac" +version = "0.1.0" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "critical-section", + "svd2rust", + "vcell", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/crates/ziggurat-efr32-pac/Cargo.toml b/crates/ziggurat-efr32-pac/Cargo.toml new file mode 100644 index 0000000..07285ca --- /dev/null +++ b/crates/ziggurat-efr32-pac/Cargo.toml @@ -0,0 +1,29 @@ +[package] +name = "ziggurat-efr32-pac" +version = "0.1.0" +edition = "2021" +description = "Peripheral access crate for the EFR32MG24 (svd2rust-generated)" +license = "MIT OR Apache-2.0" +repository = "https://github.com/zigpy/ziggurat" + +# svd2rust-generated; see REGENERATE.md. Excluded from the host workspace +# (builds only for thumbv8m.main-none-eabihf). +[dependencies] +cortex-m = "0.7.7" +vcell = "0.1.3" +critical-section = { version = "1.1", optional = true } +cortex-m-rt = { version = "0.7.5", optional = true } + +[build-dependencies] +# Generates the PAC from the SVD at build time (lib API — no CLI on PATH needed). +svd2rust = "0.37" + +[features] +rt = ["cortex-m-rt"] +# Thread-safe `Peripherals::take()` via critical-section. The binary crate must +# also provide a critical-section implementation (e.g. cortex-m's +# `critical-section-single-core`). +critical-section = ["dep:critical-section"] + +[package.metadata.docs.rs] +features = ["rt", "critical-section"] diff --git a/crates/ziggurat-efr32-pac/build.rs b/crates/ziggurat-efr32-pac/build.rs new file mode 100644 index 0000000..448e5ae --- /dev/null +++ b/crates/ziggurat-efr32-pac/build.rs @@ -0,0 +1,173 @@ +use std::env; +use std::fs; +use std::path::PathBuf; +use std::process::Command; + +// The EFR32MG24 SVD lives inside the Silicon Labs CMSIS DFP pack (a zip). We fetch the +// pack once, extract the single SVD entry, and generate the PAC with svd2rust at build +// time — nothing derived is committed. Bump URL + REV together on an SVD update. +const PACK_URL: &str = "https://www.silabs.com/documents/public/cmsis-packs/SiliconLabs.GeckoPlatform_EFR32MG24_DFP.2025.12.1.pack"; +const PACK_REV: &str = "2025.12.1"; +const SVD_ENTRY: &str = "SVD/EFR32MG24/EFR32MG24A420F1536IM40.svd"; + +fn svd_xml() -> String { + if let Ok(p) = env::var("ZIGGURAT_EFR32_SVD") { + return fs::read_to_string(p).unwrap(); + } + let cache = env::var("ZIGGURAT_EFR32_PAC_CACHE") + .map(PathBuf::from) + .unwrap_or_else(|_| { + PathBuf::from(env::var("HOME").unwrap()).join(".cache/ziggurat-efr32-pac") + }); + let svd = cache.join(format!("{PACK_REV}.svd")); + if !svd.exists() { + fs::create_dir_all(&cache).unwrap(); + let pack = cache.join(format!("{PACK_REV}.pack")); + if !pack.exists() { + let ok = Command::new("curl") + .args(["-fSL", "--retry", "3", "-o"]) + .arg(&pack) + .arg(PACK_URL) + .status() + .unwrap() + .success(); + assert!(ok, "failed to download DFP pack from {PACK_URL}"); + } + // `unzip -p` streams the single SVD entry to stdout — no full extraction. + let out = Command::new("unzip") + .args(["-p"]) + .arg(&pack) + .arg(SVD_ENTRY) + .output() + .unwrap(); + assert!( + out.status.success() && !out.stdout.is_empty(), + "failed to extract {SVD_ENTRY} from the DFP pack" + ); + fs::write(&svd, &out.stdout).unwrap(); + } + fs::read_to_string(&svd).unwrap() +} + +// The public Gecko DFP SVD deliberately omits the radio peripheral interrupts (AGC, FRC, +// MODEM, PROTIMER, RAC_*, SYNTH, RFECA*, ...). Their NVIC vector slots (IRQ 30-39, 70-71) +// therefore come out `Reserved` in the generated vector table, so the RAIL blob's radio +// ISRs can never be wired in — a radio IRQ would vector to address 0 and hard fault. +// Inject the missing interrupts (real IRQ numbers from the EFR32MG24 CMSIS header) so +// svd2rust emits real vector slots + `PROVIDE( = DefaultHandler)` weak aliases that +// a binary can override with the blob's `*_IRQHandler`. +fn inject_radio_interrupts(svd: String) -> String { + // (name, IRQ number). HOSTMAILBOX (38) and SYSRTC_SEQ (68) are already in the SVD. + const RADIO_IRQS: &[(&str, u32)] = &[ + ("AGC", 30), + ("BUFC", 31), + ("FRC_PRI", 32), + ("FRC", 33), + ("MODEM", 34), + ("PROTIMER", 35), + ("RAC_RSM", 36), + ("RAC_SEQ", 37), + ("SYNTH", 39), + ("RFECA0", 70), + ("RFECA1", 71), + ]; + let mut xml = String::new(); + for (name, value) in RADIO_IRQS { + xml.push_str(&format!( + "{name}Radio {name} (injected){value}" + )); + } + // svd2rust aggregates elements across all peripherals into one vector + // table indexed by value, so attaching them to the first peripheral is sufficient. + let anchor = ""; + let pos = svd.find(anchor).expect("no in SVD"); + let mut out = String::with_capacity(svd.len() + xml.len()); + out.push_str(&svd[..pos]); + out.push_str(&xml); + out.push_str(&svd[pos..]); + out +} + +// svd2rust emits crate-level inner attributes (#![no_std], #![allow(...)], …) at the +// top. Those can't survive being `include!`d at the crate root, so strip the leading +// inner-attr run (string-literal-aware: the `doc` attr contains `]`); lib.rs re-declares +// the crate attributes itself. +fn strip_leading_inner_attrs(s: &str) -> &str { + let b = s.as_bytes(); + let mut i = 0; + loop { + let mut j = i; + while j < b.len() && b[j].is_ascii_whitespace() { + j += 1; + } + if b.get(j) != Some(&b'#') { + break; + } + j += 1; + while j < b.len() && b[j].is_ascii_whitespace() { + j += 1; + } + if b.get(j) != Some(&b'!') { + break; // an outer attribute or a real item — done stripping + } + j += 1; + while j < b.len() && b[j].is_ascii_whitespace() { + j += 1; + } + if b.get(j) != Some(&b'[') { + break; + } + let mut depth = 0; + let mut in_str = false; + while j < b.len() { + let c = b[j]; + if in_str { + match c { + b'\\' => j += 1, + b'"' => in_str = false, + _ => {} + } + } else { + match c { + b'"' => in_str = true, + b'[' => depth += 1, + b']' => { + depth -= 1; + if depth == 0 { + j += 1; + break; + } + } + _ => {} + } + } + j += 1; + } + i = j; + } + &s[i..] +} + +fn main() { + let out = PathBuf::from(env::var("OUT_DIR").unwrap()); + + let mut config = svd2rust::Config::default(); + config.target = svd2rust::Target::CortexM; + let svd = inject_radio_interrupts(svd_xml()); + let generated = svd2rust::generate(&svd, &config).expect("svd2rust generation failed"); + + fs::write(out.join("pac.rs"), strip_leading_inner_attrs(&generated.lib_rs)).unwrap(); + + // device.x carries the interrupt vector table; only needed (and only INCLUDEd by + // cortex-m-rt's link.x) under the `rt` feature. + if env::var_os("CARGO_FEATURE_RT").is_some() { + if let Some(ds) = generated.device_specific { + fs::write(out.join("device.x"), ds.device_x).unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + } + } + + println!("cargo:rerun-if-env-changed=ZIGGURAT_EFR32_SVD"); + println!("cargo:rerun-if-env-changed=ZIGGURAT_EFR32_PAC_CACHE"); + println!("cargo:rerun-if-changed=build.rs"); +} diff --git a/crates/ziggurat-efr32-pac/src/lib.rs b/crates/ziggurat-efr32-pac/src/lib.rs new file mode 100644 index 0000000..5f08129 --- /dev/null +++ b/crates/ziggurat-efr32-pac/src/lib.rs @@ -0,0 +1,7 @@ +// svd2rust-generated PAC, produced at build time from the EFR32MG24 SVD (see build.rs). +// build.rs strips the generated crate-level inner attributes; they're re-declared here so +// the code can be `include!`d at the crate root. +#![no_std] +#![allow(non_camel_case_types, non_snake_case, non_upper_case_globals, dead_code)] + +include!(concat!(env!("OUT_DIR"), "/pac.rs")); diff --git a/crates/ziggurat-efr32/.cargo/config.toml b/crates/ziggurat-efr32/.cargo/config.toml new file mode 100644 index 0000000..e558c65 --- /dev/null +++ b/crates/ziggurat-efr32/.cargo/config.toml @@ -0,0 +1,5 @@ +[target.thumbv8m.main-none-eabihf] +rustflags = ["-C", "link-arg=-Tlink.x"] + +[build] +target = "thumbv8m.main-none-eabihf" diff --git a/crates/ziggurat-efr32/Cargo.lock b/crates/ziggurat-efr32/Cargo.lock new file mode 100644 index 0000000..7f94cbb --- /dev/null +++ b/crates/ziggurat-efr32/Cargo.lock @@ -0,0 +1,2123 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "abstract-bits" +version = "0.2.0" +source = "git+https://github.com/yara-blue/abstract-bits.git#f82569eb658505e2b96c9baa498b376169adfe51" +dependencies = [ + "abstract-bits-derive", + "arbitrary-int 1.3.0", + "bitvec", + "thiserror 2.0.18", +] + +[[package]] +name = "abstract-bits-derive" +version = "0.2.0" +source = "git+https://github.com/yara-blue/abstract-bits.git#f82569eb658505e2b96c9baa498b376169adfe51" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "aead" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1973cfbc1a2daf9cf550e74e1f088c28e7f7d8c1e1418fb6c9dc5184b7e84c99" +dependencies = [ + "crypto-common", + "inout", +] + +[[package]] +name = "aes" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1fc76eaeac4c9164506c466d4ffdd8ec9d0c5bf57ee97177c4d8eceb3a0e138" +dependencies = [ + "cipher", + "cpubits", + "cpufeatures", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "anstream" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "824a212faf96e9acacdbd09febd34438f8f711fb84e09a8916013cd7815ca28d" +dependencies = [ + "anstyle", + "anstyle-parse", + "anstyle-query", + "anstyle-wincon", + "colorchoice", + "is_terminal_polyfill", + "utf8parse", +] + +[[package]] +name = "anstyle" +version = "1.0.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "940b3a0ca603d1eade50a4846a2afffd5ef57a9feac2c0e2ec2e14f9ead76000" + +[[package]] +name = "anstyle-parse" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ce7f38b242319f7cabaa6813055467063ecdc9d355bbb4ce0c68908cd8130e" +dependencies = [ + "utf8parse", +] + +[[package]] +name = "anstyle-query" +version = "1.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "anstyle-wincon" +version = "3.0.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" +dependencies = [ + "anstyle", + "once_cell_polyfill", + "windows-sys", +] + +[[package]] +name = "anyhow" +version = "1.0.103" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a4385e2e34eb35d6b3efe798b9eb88096925d87726c0798709bf56d9ed84af3" + +[[package]] +name = "arbitrary-int" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "825297538d77367557b912770ca3083f778a196054b3ee63b22673c4a3cae0a5" + +[[package]] +name = "arbitrary-int" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "993a810118f8f37e9c4411c86f1c4c940a09a7ab34b7bf2d88d06f50c553fab7" + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f02882884d3e1bc524fb12c79f107f6ad0e1cfd498c536ffb494301740995dfe" + +[[package]] +name = "bare-metal" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5deb64efa5bd81e31fcd1938615a6d98c82eafcbcd787162b6f63b91d6bac5b3" +dependencies = [ + "rustc_version", +] + +[[package]] +name = "base64" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e1b586273c5702936fe7b7d6896644d8be71e6314cfe09d3167c95f712589e8" + +[[package]] +name = "bindgen" +version = "0.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags 2.13.0", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex 1.3.0", + "syn 2.0.118", +] + +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" + +[[package]] +name = "bitvec" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddcec3d12c579d40898fe0a9a358a803c23e9c52ca3c425707f81c9436211837" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "blake2b_simd" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b79834656f71332577234b50bfc009996f7449e0c056884e6a02492ded0ca2f3" +dependencies = [ + "arrayref", + "arrayvec", + "constant_time_eq", +] + +[[package]] +name = "block-buffer" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2f6c7dbe95a6ed67ad9f18e57daf93a2f034c524b99fd2b76d18fdfeb6660aa" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cc" +version = "1.2.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96" +dependencies = [ + "find-msvc-tools", + "shlex 2.0.1", +] + +[[package]] +name = "ccm" +version = "0.6.0-rc.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4edea5ea70a1285565ac264767613d6c88351a9a0557e7af793a0942590baaed" +dependencies = [ + "aead", + "cipher", + "ctr", + "subtle", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cipher" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c" +dependencies = [ + "block-buffer", + "crypto-common", + "inout", +] + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "clap" +version = "4.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ddb117e43bbf7dacf0a4190fef4d345b9bad68dfc649cb349e7d17d28428e51" +dependencies = [ + "clap_builder", +] + +[[package]] +name = "clap_builder" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714a53001bf66416adb0e2ef5ac857140e7dc3a0c48fb28b2f10762fc4b5069f" +dependencies = [ + "anstream", + "anstyle", + "clap_lex", + "strsim", +] + +[[package]] +name = "clap_lex" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8d4a3bb8b1e0c1050499d1815f5ab16d04f0959b233085fb31653fbfc9d98f9" + +[[package]] +name = "colorchoice" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" + +[[package]] +name = "const-default" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b396d1f76d455557e1218ec8066ae14bba60b4b36ecd55577ba979f5db7ecaa" + +[[package]] +name = "constant_time_eq" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" + +[[package]] +name = "cordyceps" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "688d7fbb8092b8de775ef2536f36c8c31f2bc4006ece2e8d8ad2d17d00ce0a2a" +dependencies = [ + "loom", + "tracing", +] + +[[package]] +name = "cortex-m" +version = "0.7.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ec610d8f49840a5b376c69663b6369e71f4b34484b9b2eb29fb918d92516cb9" +dependencies = [ + "bare-metal", + "bitfield", + "critical-section", + "embedded-hal 0.2.7", + "volatile-register", +] + +[[package]] +name = "cortex-m-rt" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d4dec46b34c299ccf6b036717ae0fce602faa4f4fe816d9013b9a7c9f5ba6" +dependencies = [ + "cortex-m-rt-macros", +] + +[[package]] +name = "cortex-m-rt-macros" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e37549a379a9e0e6e576fd208ee60394ccb8be963889eebba3ffe0980364f472" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "cpubits" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b85f9c39137c3a891689859392b1bd49812121d0d61c9caf00d46ed5ce06ae" + +[[package]] +name = "cpufeatures" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" +dependencies = [ + "libc", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "crypto-common" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "ctr" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baaca1c4b237092596f64d571e9db6ce4109c4ef9742e27590f1709594461f21" +dependencies = [ + "cipher", +] + +[[package]] +name = "darling" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7f46116c46ff9ab3eb1597a45688b6715c6e628b5c133e288e709a29bcb4ee" +dependencies = [ + "darling_core", + "darling_macro", +] + +[[package]] +name = "darling_core" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d00b9596d185e565c2207a0b01f8bd1a135483d02d9b7b0a54b11da8d53412e" +dependencies = [ + "fnv", + "ident_case", + "proc-macro2", + "quote", + "strsim", + "syn 2.0.118", +] + +[[package]] +name = "darling_macro" +version = "0.20.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc34b93ccb385b40dc71c6fceac4b2ad23662c7eeb248cf10d529b7e055b6ead" +dependencies = [ + "darling_core", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "defmt" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6e524506490a1953d237cb87b1cfc1e46f88c18f10a22dfe0f507dc6bfc7f7f" +dependencies = [ + "bitflags 1.3.2", + "defmt-macros", +] + +[[package]] +name = "defmt-macros" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0a27770e9c8f719a79d8b638281f4d828f77d8fd61e0bd94451b9b85e576a0b" +dependencies = [ + "defmt-parser", + "proc-macro-error2", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "defmt-parser" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10d60334b3b2e7c9d91ef8150abfb6fa4c1c39ebbcf4a81c2e346aad939fee3e" +dependencies = [ + "thiserror 2.0.18", +] + +[[package]] +name = "derive_builder" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "507dfb09ea8b7fa618fcf76e953f4f5e192547945816d5358edffe39f6f94947" +dependencies = [ + "derive_builder_macro", +] + +[[package]] +name = "derive_builder_core" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d5bcf7b024d6835cfb3d473887cd966994907effbe9227e8c8219824d06c4e8" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "derive_builder_macro" +version = "0.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab63b0e2bf4d5928aff72e83a7dace85d7bba5fe12dcc3c5a572d78caffd3f3c" +dependencies = [ + "derive_builder_core", + "syn 2.0.118", +] + +[[package]] +name = "displaydoc" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ac70aa55017e108007fbaf5aa0f54b021c98f92ff8af59d42eda9da96e3dd4f" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "either" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + +[[package]] +name = "embassy-executor" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0d3b15c9d7dc4fec1d8cb77112472fb008b3b28c51ad23838d83587a6d2f1e" +dependencies = [ + "cordyceps", + "cortex-m", + "critical-section", + "document-features", + "embassy-executor-macros", + "embassy-executor-timer-queue", +] + +[[package]] +name = "embassy-executor-macros" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d11a246f53de5f97a387f40ac24726817cd0b6f833e7603baac784f29d6ff276" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "embassy-executor-timer-queue" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc328bf943af66b80b98755db9106bf7e7471b0cf47dc8559cd9a6be504cc9c" + +[[package]] +name = "embassy-futures" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc2d050bdc5c21e0862a89256ed8029ae6c290a93aecefc73084b3002cdebb01" + +[[package]] +name = "embassy-sync" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bbd85cf5a5ae56bdf26f618364af642d1d0a4e245cdd75cd9aabda382f65a81" +dependencies = [ + "cfg-if", + "critical-section", + "embedded-io-async", + "futures-core", + "futures-sink", + "heapless", +] + +[[package]] +name = "embassy-time" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "592b0c143ec626e821d4d90da51a2bd91d559d6c442b7c74a47d368c9e23d97a" +dependencies = [ + "cfg-if", + "critical-section", + "document-features", + "embassy-time-driver", + "embedded-hal 0.2.7", + "embedded-hal 1.0.0", + "embedded-hal-async", + "futures-core", +] + +[[package]] +name = "embassy-time-driver" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ee71af1b3a0deaa53eaf2d39252f83504c853646e472400b763060389b9fcc9" +dependencies = [ + "document-features", +] + +[[package]] +name = "embassy-time-queue-utils" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "168297bf80aaf114b3c9ad589bf38b01b3009b9af7f97cd18086c5bbf96f5693" +dependencies = [ + "embassy-executor-timer-queue", + "heapless", +] + +[[package]] +name = "embedded-alloc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f2de9133f68db0d4627ad69db767726c99ff8585272716708227008d3f1bddd" +dependencies = [ + "const-default", + "critical-section", + "linked_list_allocator", + "rlsf", +] + +[[package]] +name = "embedded-hal" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35949884794ad573cf46071e41c9b60efb0cb311e3ca01f7af807af1debc66ff" +dependencies = [ + "nb 0.1.3", + "void", +] + +[[package]] +name = "embedded-hal" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "361a90feb7004eca4019fb28352a9465666b24f840f5c3cddf0ff13920590b89" + +[[package]] +name = "embedded-hal-async" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c4c685bbef7fe13c3c6dd4da26841ed3980ef33e841cddfa15ce8a8fb3f1884" +dependencies = [ + "embedded-hal 1.0.0", +] + +[[package]] +name = "embedded-io" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eb1aa714776b75c7e67e1da744b81a129b3ff919c8712b5e1b32252c1f07cc7" + +[[package]] +name = "embedded-io-async" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2564b9f813c544241430e147d8bc454815ef9ac998878d30cc3055449f7fd4c0" +dependencies = [ + "embedded-io", +] + +[[package]] +name = "enum-ordinalize" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07f808d588c10e464ea6f7d3eaed500049eff30aaac103460f61828c2d65b3eb" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e528e2d34ba8a67a1a650b86beae8ef69fc5fdb638016f386b973226590432" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "env_filter" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "900d271a03799a1ee8d1ca9b19893b48ca674a9284fefcfb85f05e74ed314217" +dependencies = [ + "log", + "regex", +] + +[[package]] +name = "env_logger" +version = "0.11.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de671bd27a75a797dc9ae289ba1e77276e75e2026408aab65185384e2d5cd3f6" +dependencies = [ + "anstream", + "anstyle", + "env_filter", + "jiff", + "log", +] + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b147ee9d1f6d097cef9ce628cd2ee62288d963e16fb287bd9286455b241382d" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07bbe89c50d7a535e539b8c17bc0b49bdb77747034daa8087407d655f3f7cc1d" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-sink", + "futures-task", + "pin-project-lite", +] + +[[package]] +name = "generator" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b3b854b0e584ead1a33f18b2fcad7cf7be18b3875c78816b753639aa501513ae" +dependencies = [ + "cc", + "cfg-if", + "libc", + "log", + "rustversion", + "windows-link", + "windows-result", +] + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "hashbrown" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a" + +[[package]] +name = "heapless" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ba4bd83f9415b58b4ed8dc5714c76e626a105be4646c02630ad730ad3b5aa4" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hybrid-array" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" +dependencies = [ + "typenum", +] + +[[package]] +name = "icu_collections" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2984d1cd16c883d7935b9e07e44071dca8d917fd52ecc02c04d5fa0b5a3f191c" +dependencies = [ + "displaydoc", + "potential_utf", + "utf8_iter", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92219b62b3e2b4d88ac5119f8904c10f8f61bf7e95b640d25ba3075e6cac2c29" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c56e5ee99d6e3d33bd91c5d85458b6005a22140021cc324cea84dd0e72cff3b4" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da3be0ae77ea334f4da67c12f149704f19f81d1adf7c51cf482943e84a2bad38" + +[[package]] +name = "icu_properties" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bee3b67d0ea5c2cca5003417989af8996f8604e34fb9ddf96208a033901e70de" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e2bbb201e0c04f7b4b3e14382af113e17ba4f63e2c9d2ee626b720cbce54a14" + +[[package]] +name = "icu_provider" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139c4cf31c8b5f33d7e199446eff9c1e02decfc2f0eec2c8d71f65befa45b421" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb68373c0d6620ef8105e855e7745e18b0d00d3bdb07fb532e434244cdb9a714" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown", +] + +[[package]] +name = "inflections" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a257582fdcde896fd96463bf2d40eefea0580021c0712a0e2b028b60b47a837a" + +[[package]] +name = "inout" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" +dependencies = [ + "hybrid-array", +] + +[[package]] +name = "irx-config" +version = "3.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6266a086f9c5635dffbfd7bd49262b2a40e0a580ab34e85d88dc59ed8133976a" +dependencies = [ + "blake2b_simd", + "cfg-if", + "clap", + "derive_builder", + "serde", + "serde_json", + "serde_yaml", + "thiserror 1.0.69", + "toml", +] + +[[package]] +name = "is_terminal_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "itoa" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682" + +[[package]] +name = "jiff" +version = "0.2.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccfe6121cbe750cf81efa362d85c0bde7ea298ec43092d3a193baca59cdbd634" +dependencies = [ + "defmt", + "jiff-static", + "log", + "portable-atomic", + "portable-atomic-util", + "serde_core", +] + +[[package]] +name = "jiff-static" +version = "0.2.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e165e897f662d428f3cd3828a919dbe067c2d42bb1031eede74ef9d27ecdedd2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "lazy_static" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "linked_list_allocator" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b23ac50abb8261cb38c6e2a7192d3302e0836dac1628f6a93b82b4fad185897" + +[[package]] +name = "litemap" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92daf443525c4cce67b150400bc2316076100ce0b3686209eb8cf3c31612e6f0" + +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "loom" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca" +dependencies = [ + "cfg-if", + "generator", + "scoped-tls", + "tracing", + "tracing-subscriber", +] + +[[package]] +name = "matchers" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d1525a2a28c7f4fa0fc98bb91ae755d1e2d1505079e05539e35bc876b5d65ae9" +dependencies = [ + "regex-automata", +] + +[[package]] +name = "memchr" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nb" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "801d31da0513b6ec5214e9bf433a77966320625a37860f910be265be6e18d06f" +dependencies = [ + "nb 1.1.0", +] + +[[package]] +name = "nb" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8d5439c4ad607c3c23abf66de8c8bf57ba8adcd1f129e699851a6e43935d339d" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "nu-ansi-term" +version = "0.50.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5" +dependencies = [ + "windows-sys", +] + +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "once_cell" +version = "1.21.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" + +[[package]] +name = "once_cell_polyfill" +version = "1.70.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" + +[[package]] +name = "panic-halt" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a513e167849a384b7f9b746e517604398518590a9142f4846a32e3c2a4de7b11" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project-lite" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a89322df9ebe1c1578d689c92318e070967d1042b512afbe49518723f4e6d5cd" + +[[package]] +name = "portable-atomic" +version = "1.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49" + +[[package]] +name = "portable-atomic-util" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618" +dependencies = [ + "portable-atomic", +] + +[[package]] +name = "potential_utf" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0103b1cef7ec0cf76490e969665504990193874ea05c85ff9bab8b911d0a0564" +dependencies = [ + "zerovec", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn 2.0.118", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "regex" +version = "1.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "rlsf" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1646a59a9734b8b7a0ac51689388a60fe1625d4b956348e9de07591a1478457a" +dependencies = [ + "cfg-if", + "const-default", + "libc", + "rustversion", + "svgbobdoc", +] + +[[package]] +name = "roxmltree" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c20b6793b5c2fa6553b250154b78d6d0db37e72700ae35fad9387a46f487c97" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +dependencies = [ + "semver", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "ryu" +version = "1.0.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9774ba4a74de5f7b1c1451ed6cd5285a32eddb5cccb8cc655a4e50009e06477f" + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +dependencies = [ + "semver-parser", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "serde_json" +version = "1.0.150" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_spanned" +version = "0.6.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bf41e0cfaf7226dca15e8197172c295a782857fcb97fad1808a166870dee75a3" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_yaml" +version = "0.9.34+deprecated" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a8b1a1a2ebf674015cc02edccce75287f1a0130d394307b36743c2f5d504b47" +dependencies = [ + "indexmap", + "itoa", + "ryu", + "serde", + "unsafe-libyaml", +] + +[[package]] +name = "sharded-slab" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f40ca3c46823713e0d4209592e8d6e826aa57e928f09752619fc696c499637f6" +dependencies = [ + "lazy_static", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "smallvec" +version = "1.15.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8ed6a63f02c8539c91a8685a86f4099661ba3da017932f6ebbea6de3f0fa7c90" + +[[package]] +name = "spin" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + +[[package]] +name = "subtle" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" + +[[package]] +name = "svd-parser" +version = "0.14.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a41fe17e46dee363a7d3b20e878bbf6d6b4e839ae010ff07ef0e05d41d201811" +dependencies = [ + "anyhow", + "roxmltree", + "svd-rs", + "thiserror 1.0.69", +] + +[[package]] +name = "svd-rs" +version = "0.14.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9b88ee2e82f09623ff76965587dc15a2e7150a3126854899c86e94dab777458" +dependencies = [ + "once_cell", + "regex", + "serde", + "thiserror 1.0.69", +] + +[[package]] +name = "svd2rust" +version = "0.37.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1eaf6a040bfbc04e7b946a6a373b24aab09e1feb875bb0e20c929946c4b7bfc4" +dependencies = [ + "anyhow", + "clap", + "env_logger", + "inflections", + "irx-config", + "log", + "proc-macro2", + "quote", + "regex", + "serde", + "serde_json", + "serde_yaml", + "svd-parser", + "svd-rs", + "syn 2.0.118", + "thiserror 2.0.18", + "url", +] + +[[package]] +name = "svgbobdoc" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2c04b93fc15d79b39c63218f15e3fdffaa4c227830686e3b7c5f41244eb3e50" +dependencies = [ + "base64", + "proc-macro2", + "quote", + "syn 1.0.109", + "unicode-width", +] + +[[package]] +name = "syn" +version = "1.0.109" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "syn" +version = "2.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "thread_local" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f60246a4944f24f6e018aa17cdeffb7818b76356965d03b07d6a9886e8962185" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "tinystr" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8323304221c2a851516f22236c5722a72eaa19749016521d6dff0824447d96d" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "toml" +version = "0.8.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc1beb996b9d83529a9e75c17a1686767d148d70663143c7854d8b4a09ced362" +dependencies = [ + "serde", + "serde_spanned", + "toml_datetime", + "toml_edit", +] + +[[package]] +name = "toml_datetime" +version = "0.6.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "22cddaf88f4fbc13c51aebbf5f8eceb5c7c5a9da2ac40a13519eb5b0a0e8f11c" +dependencies = [ + "serde", +] + +[[package]] +name = "toml_edit" +version = "0.22.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fe8c660ae4257887cf66394862d21dbca4a6ddd26f04a3560410406a2f819a" +dependencies = [ + "indexmap", + "serde", + "serde_spanned", + "toml_datetime", + "toml_write", + "winnow", +] + +[[package]] +name = "toml_write" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d99f8c9a7727884afe522e9bd5edbfc91a3312b36a77b5fb8926e4c31a41801" + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", + "valuable", +] + +[[package]] +name = "tracing-log" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee855f1f400bd0e5c02d150ae5de3840039a3f54b025156404e34c23c03f47c3" +dependencies = [ + "log", + "once_cell", + "tracing-core", +] + +[[package]] +name = "tracing-subscriber" +version = "0.3.23" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb7f578e5945fb242538965c2d0b04418d38ec25c79d160cd279bf0731c8d319" +dependencies = [ + "matchers", + "nu-ansi-term", + "once_cell", + "regex-automata", + "sharded-slab", + "smallvec", + "thread_local", + "tracing", + "tracing-core", + "tracing-log", +] + +[[package]] +name = "typenum" +version = "1.20.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unsafe-libyaml" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "673aac59facbab8a9007c7f6108d11f63b603f7cabff99fabf650fea5c32b861" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", + "serde_derive", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "utf8parse" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" + +[[package]] +name = "valuable" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba73ea9cf16a25df0c8caa16c51acb937d5712a8429db78a3ee29d5dcacd3a65" + +[[package]] +name = "vcell" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77439c1b53d2303b20d9459b1ade71a83c716e3f9c34f3228c00e6f185d6c002" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" + +[[package]] +name = "volatile-register" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de437e2a6208b014ab52972a27e59b33fa2920d3e00fe05026167a1c509d19cc" +dependencies = [ + "vcell", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "winnow" +version = "0.7.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df79d97927682d2fd8adb29682d1140b343be4ac0f08fd68b7765d9c059d3945" +dependencies = [ + "memchr", +] + +[[package]] +name = "writeable" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1ffae5123b2d3fc086436f8834ae3ab053a283cfac8fe0a0b8eaae044768a4c4" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "yoke" +version = "0.8.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709fe23a0424b6a435d82152b1bd3fdfb0833487d5fa90d05d42762a9891fef5" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de844c262c8848816172cef550288e7dc6c7b7814b4ee56b3e1553f275f1858e" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", + "synstructure", +] + +[[package]] +name = "zerofrom" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ec05a11813ea801ff6d75110ad09cd0824ddba17dfe17128ea0d5f68e6c5272" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11532158c46691caf0f2593ea8358fed6bbf68a0315e80aae9bd41fbade684a1" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f9152d31db0792fa83f70fb2f83148effb5c1f5b8c7686c3459e361d9bc20bf" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90f911cbc359ab6af17377d242225f4d75119aec87ea711a880987b18cd7b239" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625dc425cab0dca6dc3c3319506e6593dcb08a9f387ea3b284dbd52a92c40555" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.118", +] + +[[package]] +name = "ziggurat-driver" +version = "0.1.0" +dependencies = [ + "abstract-bits", + "arbitrary-int 2.1.1", + "embassy-executor", + "embassy-sync", + "embassy-time", + "futures", + "spin", + "thiserror 2.0.18", + "tracing", + "ziggurat-ieee-802154", + "ziggurat-phy", + "ziggurat-zigbee", +] + +[[package]] +name = "ziggurat-efr32" +version = "0.1.0" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "critical-section", + "embassy-executor", + "embassy-futures", + "embassy-sync", + "embassy-time", + "embassy-time-driver", + "embassy-time-queue-utils", + "embedded-alloc", + "heapless", + "hex", + "panic-halt", + "serde", + "serde_json", + "ziggurat-driver", + "ziggurat-efr32-pac", + "ziggurat-ieee-802154", + "ziggurat-phy", + "ziggurat-phy-efr32", + "ziggurat-rail-sys", + "ziggurat-zigbee", +] + +[[package]] +name = "ziggurat-efr32-pac" +version = "0.1.0" +dependencies = [ + "cortex-m", + "cortex-m-rt", + "critical-section", + "svd2rust", + "vcell", +] + +[[package]] +name = "ziggurat-ieee-802154" +version = "0.1.0" +dependencies = [ + "abstract-bits", + "educe", + "heapless", + "hex", + "num_enum", + "serde", + "thiserror 2.0.18", +] + +[[package]] +name = "ziggurat-phy" +version = "0.1.0" +dependencies = [ + "thiserror 2.0.18", + "ziggurat-ieee-802154", +] + +[[package]] +name = "ziggurat-phy-efr32" +version = "0.1.0" +dependencies = [ + "embassy-futures", + "embassy-sync", + "ziggurat-ieee-802154", + "ziggurat-phy", + "ziggurat-rail-sys", +] + +[[package]] +name = "ziggurat-rail-sys" +version = "0.1.0" +dependencies = [ + "bindgen", + "cc", +] + +[[package]] +name = "ziggurat-zigbee" +version = "0.1.0" +dependencies = [ + "abstract-bits", + "aes", + "arbitrary-int 2.1.1", + "ccm", + "educe", + "hex", + "num_enum", + "once_cell", + "serde", + "subtle", + "thiserror 2.0.18", + "tracing", + "ziggurat-ieee-802154", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" diff --git a/crates/ziggurat-efr32/Cargo.toml b/crates/ziggurat-efr32/Cargo.toml new file mode 100644 index 0000000..5c207f0 --- /dev/null +++ b/crates/ziggurat-efr32/Cargo.toml @@ -0,0 +1,44 @@ +[package] +name = "ziggurat-efr32" +version = "0.1.0" +edition = "2021" +description = "Ziggurat firmware for the EFR32MG24 (Cortex-M33F), RAIL radio backend" +license = "Apache-2.0" + +[[bin]] +name = "ziggurat-efr32" +path = "src/main.rs" + +[dependencies] +ziggurat-rail-sys = { path = "../ziggurat-rail-sys" } +ziggurat-efr32-pac = { path = "../ziggurat-efr32-pac", features = ["rt", "critical-section"] } +ziggurat-phy = { path = "../ziggurat-phy" } +ziggurat-phy-efr32 = { path = "../ziggurat-phy-efr32" } +ziggurat-ieee-802154 = { path = "../ziggurat-ieee-802154" } +ziggurat-driver = { path = "../ziggurat-driver", default-features = false, features = ["embassy"] } +ziggurat-zigbee = { path = "../ziggurat-zigbee" } +serde = { version = "1", default-features = false, features = ["alloc", "derive"] } +serde_json = { version = "1", default-features = false, features = ["alloc"] } +hex = { version = "0.4", default-features = false, features = ["alloc"] } +heapless = { version = "0.9", default-features = false } +cortex-m = { version = "0.7.7", features = ["critical-section-single-core"] } +cortex-m-rt = { version = "0.7.5", features = ["device"] } +embassy-executor = { version = "0.10", features = ["platform-cortex-m", "executor-thread"] } +embassy-sync = "0.8" +embassy-futures = "0.1" +embassy-time = "0.5" +embassy-time-driver = "0.2" +embassy-time-queue-utils = { version = "0.3", features = ["generic-queue-16"] } +critical-section = "1" +embedded-alloc = "0.6" +panic-halt = "1" + +[profile.release] +opt-level = "s" +debug = true +lto = "fat" +codegen-units = 1 + +# Standalone workspace: only builds for thumbv8m.main-none-eabihf; excluded from the host +# workspace. +[workspace] diff --git a/crates/ziggurat-efr32/build.rs b/crates/ziggurat-efr32/build.rs new file mode 100644 index 0000000..f2b23a8 --- /dev/null +++ b/crates/ziggurat-efr32/build.rs @@ -0,0 +1,11 @@ +use std::env; +use std::fs; +use std::path::PathBuf; + +fn main() { + // Make memory.x available to cortex-m-rt's link.x. + let out = PathBuf::from(env::var("OUT_DIR").unwrap()); + fs::write(out.join("memory.x"), include_bytes!("memory.x")).unwrap(); + println!("cargo:rustc-link-search={}", out.display()); + println!("cargo:rerun-if-changed=memory.x"); +} diff --git a/crates/ziggurat-efr32/memory.x b/crates/ziggurat-efr32/memory.x new file mode 100644 index 0000000..ad1dd91 --- /dev/null +++ b/crates/ziggurat-efr32/memory.x @@ -0,0 +1,8 @@ +/* EFR32MG24A420F1536IM40 on the ZBT-2 — regions from the ZBT-2 build's linkerfile.ld. + * The app lives above the Gecko bootloader (0x08000000..0x08006000); RAM's first 4 bytes + * are the bootloader reset region. */ +MEMORY +{ + FLASH (rx) : ORIGIN = 0x08006000, LENGTH = 0x178000 + RAM (rwx) : ORIGIN = 0x20000004, LENGTH = 0x3fffc +} diff --git a/crates/ziggurat-efr32/src/api.rs b/crates/ziggurat-efr32/src/api.rs new file mode 100644 index 0000000..e1c54ce --- /dev/null +++ b/crates/ziggurat-efr32/src/api.rs @@ -0,0 +1,837 @@ +//! The line-delimited JSON-RPC surface, mirroring the host server's wire protocol. One +//! request per line; each is answered with an `accepted` event then a `response`. +//! Unsolicited `notification` lines carry network events. + +use alloc::boxed::Box; +use alloc::format; +use alloc::string::{String, ToString}; +use alloc::sync::Arc; +use alloc::vec::Vec; +use core::time::Duration; + +use embassy_futures::select::{Either, select}; +use serde::Deserialize; +use serde_json::{Value, json}; + +use crate::CaptureStop; + +use ziggurat_driver::runtime::Spawn; +use ziggurat_driver::zigbee_stack::aps_security::TclkFlavor; +use ziggurat_driver::zigbee_stack::{ + ApsAck, ApsAckResult, NetworkBeacon, NetworkConfig, NwkDeviceType, RequestId, SendResult, + TclkSeed, Tunables, TxPriority, WELL_KNOWN_LINK_KEY, ZigbeeNotification, ZigbeeStack, +}; +use ziggurat_driver::ziggurat_ieee_802154::types::{Eui64, Key, Nwk, PanId}; +use ziggurat_phy::{RadioConfig, RadioPhy, Receiver}; +use ziggurat_zigbee::aps::frame::ApsDeliveryMode; + +use crate::{App, OUTBOUND}; + +const PROTOCOL_VERSION: u32 = 1; +const DEFAULT_TX_POWER: i8 = 8; + +// The EFR32 factory unique ID (from em_system.c in the RAIL glue), used as the coordinator +// EUI-64 by `get_hw_address`. +extern "C" { + fn SYSTEM_GetUnique() -> u64; +} + +/// Queue one JSON object for the serial writer task. +pub async fn emit(value: Value) { + if let Ok(line) = serde_json::to_string(&value) { + push_outbound(line); + } +} + +fn push_outbound(mut line: String) { + loop { + match OUTBOUND.try_send(line) { + Ok(()) => break, + Err(embassy_sync::channel::TrySendError::Full(returned)) => { + line = returned; + let _ = OUTBOUND.try_receive(); + } + } + } +} + +pub fn hello_message(configured: bool) -> Value { + let state = if configured { + "running" + } else { + "awaiting_configuration" + }; + json!({"type": "hello", "version": PROTOCOL_VERSION, "state": state}) +} + +fn event(id: u64, name: &str) -> Value { + json!({"type": "event", "id": id, "event": name}) +} + +fn event_data(id: u64, name: &str, data: Value) -> Value { + json!({"type": "event", "id": id, "event": name, "data": data}) +} + +fn response(id: u64, result: Value) -> Value { + json!({"type": "response", "id": id, "result": result}) +} + +fn error_response(id: u64, code: &str, message: impl ToString) -> Value { + json!({ + "type": "response", "id": id, + "error": {"code": code, "message": message.to_string()}, + }) +} + +fn notification(name: &str, data: Value) -> Value { + json!({"type": "notification", "event": name, "data": data}) +} + +/// Big-endian colon-separated hex, matching the host server / zigpy format. +fn eui64_to_string(eui64: Eui64) -> String { + let mut bytes = eui64.to_bytes(); + bytes.reverse(); + join_hex(&bytes) +} + +fn key_to_string(key: &Key) -> String { + join_hex(&key.to_bytes()) +} + +fn join_hex(bytes: &[u8]) -> String { + let mut out = String::new(); + for (i, byte) in bytes.iter().enumerate() { + if i != 0 { + out.push(':'); + } + out.push_str(&format!("{byte:02x}")); + } + out +} + +#[derive(Deserialize)] +struct Request { + id: u64, + method: String, + #[serde(default)] + params: Value, +} + +#[derive(Deserialize, Default, Clone, Copy)] +#[serde(rename_all = "lowercase")] +enum NodeRole { + #[default] + Coordinator, + Router, +} + +impl From for NwkDeviceType { + fn from(role: NodeRole) -> Self { + match role { + NodeRole::Coordinator => Self::Coordinator, + NodeRole::Router => Self::Router, + } + } +} + +#[derive(Deserialize)] +struct ConfigureRequest { + #[serde(default)] + role: NodeRole, + channel: u8, + nwk_update_id: u8, + pan_id: PanId, + extended_pan_id: Eui64, + nwk_address: Nwk, + ieee_address: Eui64, + network_key: Key, + network_key_seq: u8, + network_key_tx_counter: u32, + tc_link_key: Option, + tclk_seed: Option, + tclk_flavor: Option, + #[serde(default)] + key_table: Vec, + #[serde(default)] + source_routing: bool, + tx_power: Option, +} + +#[derive(Deserialize)] +struct KeyTableEntry { + partner_ieee: Eui64, + key: Key, +} + +#[derive(Deserialize)] +struct SendApsRequest { + delivery_mode: ApsDeliveryMode, + destination_eui64: Option, + destination: Option, + profile_id: u16, + cluster_id: u16, + src_ep: u8, + dst_ep: u8, + aps_ack: bool, + aps_seq: u8, + radius: u8, + /// Hex-encoded ASDU + data: String, + #[serde(default)] + aps_encryption: bool, + #[serde(default)] + priority: i8, +} + +#[derive(Deserialize)] +struct PermitJoinsRequest { + #[serde(default)] + duration: u64, + #[serde(default = "default_accept_direct_joins")] + accept_direct_joins: bool, +} + +const fn default_accept_direct_joins() -> bool { + true +} + +#[derive(Deserialize)] +struct EnergyScanRequest { + channels: Vec, + duration_per_channel_ms: u16, +} + +#[derive(Deserialize)] +struct NetworkScanRequest { + channels: Vec, + duration_per_channel_ms: u16, +} + +#[derive(Deserialize)] +struct SetChannelRequest { + channel: u8, +} + +#[derive(Deserialize)] +struct SetNwkUpdateIdRequest { + nwk_update_id: u8, +} + +#[derive(Deserialize)] +struct SetProvisionalKeyRequest { + ieee: Eui64, + key: Key, +} + +#[derive(Deserialize)] +#[serde(rename_all = "lowercase")] +enum ResetType { + /// Stop transient radio activity (packet capture) and return to idle. The configured + /// network, if any, keeps running. Sent by the client on connect as a session reset. + Soft, + /// Reboot the MCU. The serial link drops and the client reconnects. + Hard, +} + +#[derive(Deserialize)] +struct ResetRequest { + reset_type: ResetType, +} + +/// Parse and dispatch one inbound line, emitting the `accepted` event and the response. +pub async fn handle_line(app: &mut App, line: &[u8]) { + let request: Request = match serde_json::from_slice(line) { + Ok(request) => request, + Err(e) => { + emit(error_response(0, "invalid_request", e)).await; + return; + } + }; + + emit(event(request.id, "accepted")).await; + + let Request { id, method, params } = request; + let message = match method.as_str() { + "ping" => response(id, json!({"status": "pong"})), + "reset" => handle_reset(app, id, params), + "configure" => handle_configure(app, id, params).await, + "get_hw_address" => handle_get_hw_address(id), + "get_network_info" => handle_get_network_info(app, id), + "send_aps" => { + // Fire-and-forget: the stack accepts or rejects now, and the terminal outcome + // arrives later as a `send_confirm` notification keyed by the request id. + dispatch_send_aps(app, id, params).await; + return; + } + "energy_scan" => handle_energy_scan(app, id, params).await, + "network_scan" => handle_network_scan(app, id, params).await, + "permit_joins" => handle_permit_joins(app, id, params), + "set_channel" => handle_set_channel(app, id, params).await, + "packet_capture" => { + // Streaming with no terminal response: the spawned capture task emits + // `captured_packet` events until the client disconnects. + handle_packet_capture(app, id, params).await; + return; + } + "packet_capture_change_channel" => { + handle_packet_capture_change_channel(app, id, params).await + } + "set_nwk_update_id" => handle_set_nwk_update_id(app, id, params), + "set_provisional_key" => handle_set_provisional_key(app, id, params), + other => error_response(id, "unknown_method", other), + }; + + emit(message).await; +} + +/// Soft or hard reset. Both stop any in-progress packet capture (freeing the radio); a hard +/// reset additionally reboots the MCU. The configured network is left running on a soft +/// reset — it must survive client reconnects. +fn handle_reset(app: &mut App, id: u64, params: Value) -> Value { + let request: ResetRequest = match serde_json::from_value(params) { + Ok(request) => request, + Err(e) => return error_response(id, "invalid_request", e), + }; + + if let Some(stop) = app.capture_stop.take() { + stop.signal(()); + } + + if matches!(request.reset_type, ResetType::Hard) { + cortex_m::peripheral::SCB::sys_reset(); // diverges; the link drops and the client reconnects + } + + response(id, json!({"status": "success"})) +} + +async fn handle_configure(app: &mut App, id: u64, params: Value) -> Value { + let request: ConfigureRequest = match serde_json::from_value(params) { + Ok(request) => request, + Err(e) => return error_response(id, "invalid_request", e), + }; + + if let Some(old_stack) = app.stack.take() { + old_stack.shutdown().await; + } + + let tclk_seed = match (request.tclk_seed, request.tclk_flavor) { + (Some(seed), Some(flavor)) => Some(TclkSeed { seed, flavor }), + (None, None) => None, + _ => { + return error_response( + id, + "invalid_request", + "tclk_seed and tclk_flavor must be provided together", + ); + } + }; + + let stack = ZigbeeStack::new( + app.phy.clone(), + NetworkConfig { + role: request.role.into(), + channel: request.channel, + update_id: request.nwk_update_id, + pan_id: request.pan_id, + extended_pan_id: request.extended_pan_id, + network_address: request.nwk_address, + ieee_address: request.ieee_address, + network_key: request.network_key, + network_key_seq_number: request.network_key_seq, + network_key_tx_counter: request.network_key_tx_counter, + tc_link_key: request.tc_link_key.unwrap_or(WELL_KNOWN_LINK_KEY), + tclk_seed, + tx_power: request.tx_power.unwrap_or(DEFAULT_TX_POWER), + source_routing: request.source_routing, + }, + Tunables::new(), + app.spawner, + ); + + if !request.key_table.is_empty() { + let mut core = stack.state.core.lock(); + for entry in request.key_table { + core.aib + .aps_security + .restore_device_key(entry.partner_ieee, entry.key); + } + } + + if let Err(e) = stack.start_network().await { + return error_response(id, "network_start_failed", e); + } + + let run_stack = stack.clone(); + stack.spawn_tracked(async move { + run_stack.run().await; + }); + + // Drain network events to the serial writer. + let notify_stack = stack.clone(); + stack.spawn_tracked(async move { + loop { + for notification_event in notify_stack.next_notifications().await { + emit(notification_to_json(notification_event)).await; + } + } + }); + + app.stack = Some(stack); + response(id, json!({"status": "success"})) +} + +/// The factory IEEE address, derived from the SoC's eFuse base MAC (EUI-48 → EUI-64). +fn handle_get_hw_address(id: u64) -> Value { + // The EFR32's factory-programmed 64-bit DEVINFO unique ID is the coordinator EUI-64. + // `Eui64` stores bytes little-endian (see the reversal in the host/ESP paths). + let ieee = Eui64(unsafe { SYSTEM_GetUnique() }.to_le_bytes()); + response(id, json!({"ieee_address": eui64_to_string(ieee)})) +} + +fn handle_get_network_info(app: &App, id: u64) -> Value { + let Some(stack) = app.stack.as_ref() else { + return error_response(id, "not_configured", "no stack is running"); + }; + + let state = &stack.state; + let core = state.core.lock(); + let nwk_security = &core.nib.nwk_security; + let aps_security = &core.aib.aps_security; + let tclk_seed = &stack.config.tclk_seed; + + response( + id, + json!({ + "channel": core.mac.channel, + "nwk_update_id": core.nib.update_id, + "pan_id": format!("{:04x}", core.mac.pan_id.0), + "extended_pan_id": eui64_to_string(state.extended_pan_id), + "nwk_address": format!("{:04x}", state.network_address.as_u16()), + "ieee_address": eui64_to_string(state.ieee_address), + "network_key": key_to_string(&nwk_security.network_key()), + "network_key_seq": nwk_security.key_seq_number(), + "network_key_tx_counter": nwk_security.outgoing_frame_counter(), + "tc_link_key": key_to_string(&stack.config.tc_link_key), + "tclk_seed": tclk_seed.as_ref().map(|tclk| hex::encode(tclk.seed.to_bytes())), + "tclk_flavor": tclk_seed.as_ref().map(|tclk| match tclk.flavor { + TclkFlavor::ZStack => "zstack", + TclkFlavor::Ezsp => "ezsp", + }), + "key_table": aps_security + .device_keys() + .map(|(partner_ieee, entry)| json!({ + "partner_ieee": eui64_to_string(partner_ieee), + "key": key_to_string(&entry.key), + })) + .collect::>(), + "tx_power": stack.config.tx_power, + }), + ) +} + +/// Fire-and-forget APS send: build and enqueue the frame, then return. No task, no +/// blocking — delivery is driven by the stack's tables. The stack accepts or rejects the +/// frame now (the `accepted`/error response); its terminal outcome arrives later as a +/// `send_confirm` notification keyed by the request id. +async fn dispatch_send_aps(app: &App, id: u64, params: Value) { + let Some(stack) = app.stack.as_ref() else { + emit(error_response(id, "not_configured", "no stack is running")).await; + return; + }; + + let request: SendApsRequest = match serde_json::from_value(params) { + Ok(request) => request, + Err(e) => return emit(error_response(id, "invalid_request", e)).await, + }; + + let destination = match (request.destination_eui64, request.destination) { + (_, Some(nwk)) => nwk, + (Some(eui64), None) => match stack.state.core.lock().nib.address_map.nwk_for(eui64) { + Some(nwk) => nwk, + None => { + return emit(error_response( + id, + "unknown_destination_eui64", + format!("{eui64:?}"), + )) + .await; + } + }, + (None, None) => { + return emit(error_response( + id, + "missing_destination", + "no destination given", + )) + .await; + } + }; + + let asdu = match hex::decode(&request.data) { + Ok(asdu) => asdu, + Err(e) => return emit(error_response(id, "invalid_data", e)).await, + }; + + let aps_security = if request.aps_encryption { + match (request.destination_eui64, request.delivery_mode) { + (Some(eui64), ApsDeliveryMode::Unicast) => Some(eui64), + _ => { + return emit(error_response( + id, + "invalid_request", + "aps_encryption requires a unicast destination_eui64", + )) + .await; + } + } + } else { + None + }; + + let aps_ack = if request.aps_ack { + ApsAck::Request + } else { + ApsAck::None + }; + + let outcome = stack.send_aps( + request.delivery_mode, + destination, + request.profile_id, + request.cluster_id, + request.src_ep, + request.dst_ep, + aps_ack, + request.radius, + request.aps_seq, + asdu, + aps_security, + TxPriority(request.priority), + id as RequestId, + ); + + // The stack accepts the frame for transmission or rejects it now. The terminal + // delivery outcome arrives later as a `send_confirm` notification keyed by this + // request id (the send token). + let message = match outcome { + Ok(()) => response(id, json!({"status": "accepted"})), + Err(e) => error_response(id, "transmit_failed", e), + }; + emit(message).await; +} + +/// Energy scan: per-channel hardware energy detection, streamed as `energy_result` +/// events. The radio's ED is driven directly through its registers (see ziggurat-phy-esp). +async fn handle_energy_scan(app: &App, id: u64, params: Value) -> Value { + let request: EnergyScanRequest = match serde_json::from_value(params) { + Ok(request) => request, + Err(e) => return error_response(id, "invalid_request", e), + }; + + // Energy detect is a radio operation, not a network one. + let duration = Duration::from_millis(u64::from(request.duration_per_channel_ms)); + for channel in request.channels { + match app.phy.energy_detect(channel, duration).await { + Ok(rssi) => { + emit(event_data( + id, + "energy_result", + json!({"channel": channel, "rssi": rssi}), + )) + .await; + } + Err(e) => return error_response(id, "energy_scan_failed", e), + } + } + + response(id, json!({"status": "complete"})) +} + +fn network_beacon_json(beacon: &NetworkBeacon) -> Value { + json!({ + "channel": beacon.channel, + "source": beacon.source.map(|nwk| format!("{:04x}", nwk.0)), + "pan_id": format!("{:04x}", beacon.pan_id.0), + "extended_pan_id": eui64_to_string(beacon.extended_pan_id), + "permit_joining": beacon.permit_joining, + "stack_profile": beacon.stack_profile, + "protocol_version": beacon.protocol_version, + "router_capacity": beacon.router_capacity, + "end_device_capacity": beacon.end_device_capacity, + "device_depth": beacon.device_depth, + "update_id": beacon.update_id, + "lqi": beacon.lqi, + "rssi": beacon.rssi, + }) +} + +/// Active scan: beacon-request each channel and stream the beacons heard. Runs inline — +/// the receive loop collects beacons concurrently during the per-channel dwell, so they +/// are all queued by the time the scan returns and we drain them. +async fn handle_network_scan(app: &App, id: u64, params: Value) -> Value { + let request: NetworkScanRequest = match serde_json::from_value(params) { + Ok(request) => request, + Err(e) => return error_response(id, "invalid_request", e), + }; + + let Some(stack) = app.stack.as_ref() else { + return error_response(id, "not_configured", "no stack is running"); + }; + + stack.begin_network_scan(); + let duration = Duration::from_millis(u64::from(request.duration_per_channel_ms)); + let result = stack.run_network_scan(&request.channels, duration).await; + + loop { + let batch = stack.next_scan_beacons().await; + if batch.is_empty() { + break; + } + for beacon in batch { + emit(event_data( + id, + "network_found", + network_beacon_json(&beacon), + )) + .await; + } + } + + match result { + Ok(()) => response(id, json!({"status": "complete"})), + Err(e) => error_response(id, "network_scan_failed", e), + } +} + +fn handle_permit_joins(app: &App, id: u64, params: Value) -> Value { + let request: PermitJoinsRequest = match serde_json::from_value(params) { + Ok(request) => request, + Err(e) => return error_response(id, "invalid_request", e), + }; + + let Some(stack) = app.stack.as_ref() else { + return error_response(id, "not_configured", "no stack is running"); + }; + + stack.permit_joins(request.duration, request.accept_direct_joins); + response(id, json!({"status": "success"})) +} + +async fn handle_set_channel(app: &App, id: u64, params: Value) -> Value { + let request: SetChannelRequest = match serde_json::from_value(params) { + Ok(request) => request, + Err(e) => return error_response(id, "invalid_request", e), + }; + + let Some(stack) = app.stack.as_ref() else { + return error_response(id, "not_configured", "no stack is running"); + }; + + match stack.set_channel(request.channel).await { + Ok(()) => response(id, json!({"status": "success"})), + Err(e) => error_response(id, "set_channel_failed", e), + } +} + +/// Radio programming for promiscuous capture: receive every frame on `channel`, no PAN/ +/// address filtering, no network required. Dummy addresses since nothing is addressed to us. +const fn capture_config(channel: u8) -> RadioConfig { + RadioConfig { + channel, + tx_power: DEFAULT_TX_POWER, + short_address: Nwk(0xFFFF), + extended_address: Eui64([0; 8]), + pan_id: PanId(0xFFFF), + promiscuous: true, + rx_on_when_idle: true, + frame_pending_short: Vec::new(), + frame_pending_extended: Vec::new(), + } +} + +/// Put the radio in promiscuous mode and stream every received frame as a `captured_packet` +/// event. No configured stack needed (only `connect()`). Singleton: a second call just +/// retunes. Stopped by `reset` (the client sends a soft reset on connect, clearing any stale +/// capture). There is no terminal response. +async fn handle_packet_capture(app: &mut App, id: u64, params: Value) { + let request: SetChannelRequest = match serde_json::from_value(params) { + Ok(request) => request, + Err(e) => { + emit(error_response(id, "invalid_request", e)).await; + return; + } + }; + + if let Err(e) = app.phy.reconfigure(&capture_config(request.channel)).await { + emit(error_response(id, "packet_capture_failed", e)).await; + return; + } + + // Already capturing: the reconfigure above retuned it; don't spawn a second task. + if app.capture_stop.is_some() { + return; + } + + let stop = Arc::new(CaptureStop::new()); + app.capture_stop = Some(stop.clone()); + + let phy = app.phy.clone(); + app.spawner.spawn(Box::pin(async move { + let mut rx = phy.subscribe_rx(); + loop { + match select(rx.recv(), stop.wait()).await { + Either::First(Some(frame)) => { + if let Ok(line) = serde_json::to_string(&event_data( + id, + "captured_packet", + json!({ + "channel": frame.channel, + "rssi": frame.rssi, + "lqi": frame.lqi, + "data": hex::encode(&frame.psdu), + }), + )) { + // Drop on a full queue: a sniffer must not block (or back up stale + // frames for a reconnecting client). + let _ = OUTBOUND.try_send(line); + } + } + // RX stream closed or `reset` signalled the stop. + _ => break, + } + } + })); +} + +async fn handle_packet_capture_change_channel(app: &App, id: u64, params: Value) -> Value { + let request: SetChannelRequest = match serde_json::from_value(params) { + Ok(request) => request, + Err(e) => return error_response(id, "invalid_request", e), + }; + + match app.phy.reconfigure(&capture_config(request.channel)).await { + Ok(()) => response(id, json!({"status": "success"})), + Err(e) => error_response(id, "set_channel_failed", e), + } +} + +fn handle_set_nwk_update_id(app: &App, id: u64, params: Value) -> Value { + let request: SetNwkUpdateIdRequest = match serde_json::from_value(params) { + Ok(request) => request, + Err(e) => return error_response(id, "invalid_request", e), + }; + + let Some(stack) = app.stack.as_ref() else { + return error_response(id, "not_configured", "no stack is running"); + }; + + stack.set_nwk_update_id(request.nwk_update_id); + response(id, json!({"status": "success"})) +} + +fn handle_set_provisional_key(app: &App, id: u64, params: Value) -> Value { + let request: SetProvisionalKeyRequest = match serde_json::from_value(params) { + Ok(request) => request, + Err(e) => return error_response(id, "invalid_request", e), + }; + + let Some(stack) = app.stack.as_ref() else { + return error_response(id, "not_configured", "no stack is running"); + }; + + stack.set_provisional_key(request.ieee, request.key); + response(id, json!({"status": "success"})) +} + +fn notification_to_json(notification_event: ZigbeeNotification) -> Value { + match notification_event { + ZigbeeNotification::ReceivedApsCommand { + source, + destination, + group, + profile_id, + cluster_id, + src_ep, + dst_ep, + lqi, + rssi, + data, + } => notification( + "received_aps_command", + json!({ + "source": hex::encode(source.to_bytes()), + "destination": hex::encode(destination.to_bytes()), + "group": group, + "profile_id": profile_id, + "cluster_id": cluster_id, "src_ep": src_ep, "dst_ep": dst_ep, + "lqi": lqi, "rssi": rssi, "data": hex::encode(data), + }), + ), + ZigbeeNotification::FrameCounterUpdate { frame_counter } => notification( + "frame_counter_update", + json!({"frame_counter": frame_counter}), + ), + ZigbeeNotification::LinkKeyUpdate { ieee, key } => notification( + "link_key_update", + json!({"ieee": eui64_to_string(ieee), "key": key_to_string(&key)}), + ), + ZigbeeNotification::DeviceJoined { nwk, ieee, parent } => notification( + "device_joined", + json!({ + "nwk": hex::encode(nwk.to_bytes()), + "ieee": eui64_to_string(ieee), + "parent": hex::encode(parent.to_bytes()), + }), + ), + ZigbeeNotification::DeviceLeft { nwk, ieee, .. } => notification( + "device_left", + json!({ + "nwk": hex::encode(nwk.to_bytes()), + "ieee": ieee.map(eui64_to_string), + }), + ), + ZigbeeNotification::ApsDecryptionFailure { + source, + source_ieee, + frame_counter, + key_id, + } => notification( + "aps_decryption_failure", + json!({ + "source": hex::encode(source.to_bytes()), + "source_ieee": eui64_to_string(source_ieee), + "frame_counter": frame_counter, + "key_id": key_id, + }), + ), + ZigbeeNotification::SendConfirm { request_id, result } => notification( + "send_confirm", + match result { + SendResult::Confirmed { next_hop } => json!({ + "id": request_id, + "status": "confirmed", + "next_hop": next_hop.map(|nwk| format!("{:04x}", nwk.0)), + }), + SendResult::Failed { reason } => json!({ + "id": request_id, + "status": "failed", + "reason": reason, + }), + }, + ), + ZigbeeNotification::ApsAckConfirm { request_id, result } => notification( + "aps_ack_confirm", + match result { + ApsAckResult::Acked => json!({ + "id": request_id, + "status": "confirmed", + }), + ApsAckResult::Failed { reason } => json!({ + "id": request_id, + "status": "failed", + "reason": reason, + }), + }, + ), + } +} diff --git a/crates/ziggurat-efr32/src/bin/rail_rx.rs b/crates/ziggurat-efr32/src/bin/rail_rx.rs new file mode 100644 index 0000000..f21374c --- /dev/null +++ b/crates/ziggurat-efr32/src/bin/rail_rx.rs @@ -0,0 +1,48 @@ +#![no_std] +#![no_main] + +#[path = "../uart.rs"] +mod uart; +#[path = "../rail.rs"] +mod rail; + +use core::fmt::Write; + +use cortex_m_rt::entry; +use panic_halt as _; + +use uart::Vcom; + +const CHANNEL: u16 = 25; + +#[entry] +fn main() -> ! { + let p = ziggurat_efr32_pac::Peripherals::take().unwrap(); + + // Bring up the clock tree (HFXO for the radio) FIRST: the clock manager repoints the + // EM01GRPCCLK branch, so the UART must be initialized afterwards — Vcom re-pins that + // branch to the always-on FSRCO with a matching divider, giving a stable 115200 baud. + let (init, runtime) = rail::init_clocks(); + + let mut vcom = Vcom::new(&p.cmu_s, &p.gpio_s, p.eusart0_s); + writeln!(vcom, "\r\n=== EFR32MG24 RAIL RX demo ===").ok(); + writeln!(vcom, "clock_manager: init={init:#x} runtime={runtime:#x}").ok(); + + let radio = rail::Radio::new(); + writeln!(vcom, "RAIL initialized").ok(); + + let status = radio.start_rx(CHANNEL); + writeln!(vcom, "start_rx(ch {CHANNEL}) status={status:#x}; listening...").ok(); + + let mut buf = [0u8; 256]; + loop { + if let Some(len) = rail::take_packet(&mut buf) { + let shown = core::cmp::min(len, buf.len()); + write!(vcom, "RX len={len}:").ok(); + for byte in &buf[..shown] { + write!(vcom, " {byte:02x}").ok(); + } + writeln!(vcom).ok(); + } + } +} diff --git a/crates/ziggurat-efr32/src/board.rs b/crates/ziggurat-efr32/src/board.rs new file mode 100644 index 0000000..b95d148 --- /dev/null +++ b/crates/ziggurat-efr32/src/board.rs @@ -0,0 +1,105 @@ +//! Board-support glue shared by RAIL-based binaries: the heap, clock bring-up, and the +//! radio interrupt trampolines. This is the runtime environment `ziggurat_phy_efr32::Efr32Phy` +//! expects to already be in place (it owns only the RAIL logic, not the board init). + +use embedded_alloc::LlffHeap as Heap; +use ziggurat_rail_sys as rail; + +#[global_allocator] +static HEAP: Heap = Heap::empty(); + +/// Silabs `ApplicationProperties_t` (bootloader/application_properties.h). Commander scans the +/// image for its magic to build the GBL, and the Gecko bootloader reads it for OTA version +/// checks. Unsigned (`signature_type = 0`), Zigbee application type. +#[repr(C)] +struct ApplicationData { + type_: u32, + version: u32, + capabilities: u32, + product_id: [u8; 16], +} +#[repr(C)] +struct ApplicationProperties { + magic: [u8; 16], + struct_version: u32, + signature_type: u32, + signature_location: u32, + app: ApplicationData, + long_token_section_address: usize, + decrypt_key: [u8; 16], +} +unsafe impl Sync for ApplicationProperties {} + +#[used] +#[no_mangle] +static sl_app_properties: ApplicationProperties = ApplicationProperties { + magic: [ + 0x13, 0xb7, 0x79, 0xfa, 0xc9, 0x25, 0xdd, 0xb7, 0xad, 0xf3, 0xcf, 0xe0, 0xf1, 0xb6, 0x14, + 0xb8, + ], + struct_version: 0x0201, // APPLICATION_PROPERTIES_VERSION (major 1, minor 2) + signature_type: 0, // APPLICATION_SIGNATURE_NONE + signature_location: 0, + app: ApplicationData { + type_: 1, // APPLICATION_TYPE_ZIGBEE + version: 0, + capabilities: 0, + product_id: [0; 16], + }, + long_token_section_address: 0, + decrypt_key: [0; 16], +}; + +/// Heap for the `alloc` types the PHY and stack use (Vec/String in frames, config). Sized +/// generously for a first bring-up; a real network needs re-measuring. +const HEAP_BYTES: usize = 64 * 1024; + +/// Point VTOR at our vector table. The Gecko bootloader jumps to the app (linked at +/// 0x08006000, see memory.x) without updating VTOR, so interrupts would otherwise vector +/// through the bootloader's table at 0x08000000. Must run before any interrupt is enabled. +pub fn init_vtor() { + const APP_FLASH_ORIGIN: u32 = 0x0800_6000; + unsafe { (*cortex_m::peripheral::SCB::PTR).vtor.write(APP_FLASH_ORIGIN) }; +} + +/// Initialize the global allocator. Must run before any allocation. +pub fn init_heap() { + use core::mem::MaybeUninit; + static mut ARENA: [MaybeUninit; HEAP_BYTES] = [MaybeUninit::uninit(); HEAP_BYTES]; + unsafe { HEAP.init(core::ptr::addr_of_mut!(ARENA) as usize, HEAP_BYTES) } +} + +/// Bring up the clock tree (HFXO for the radio) via the SDK clock manager — the safe +/// enable-wait-switch path. Must run before the UART (it repoints EM01GRPCCLK) and RAIL. +pub fn init_clocks() { + unsafe { + rail::sl_clock_manager_init(); + rail::sl_clock_manager_runtime_init(); + } +} + +// Route the PAC's radio interrupt vector slots to the RAIL blob's `_IRQHandler`. +// Without these, radio IRQs vector to DefaultHandler and RAIL's state machine never advances. +macro_rules! radio_irq { + ($($vector:ident => $handler:ident,)*) => { + extern "C" { $(fn $handler();)* } + $( + #[no_mangle] + extern "C" fn $vector() { unsafe { $handler() } } + )* + }; +} + +radio_irq! { + AGC => AGC_IRQHandler, + BUFC => BUFC_IRQHandler, + FRC => FRC_IRQHandler, + FRC_PRI => FRC_PRI_IRQHandler, + MODEM => MODEM_IRQHandler, + PROTIMER => PROTIMER_IRQHandler, + RAC_RSM => RAC_RSM_IRQHandler, + RAC_SEQ => RAC_SEQ_IRQHandler, + SYNTH => SYNTH_IRQHandler, + RFECA0 => RFECA0_IRQHandler, + RFECA1 => RFECA1_IRQHandler, +} diff --git a/crates/ziggurat-efr32/src/hw_crypto.rs b/crates/ziggurat-efr32/src/hw_crypto.rs new file mode 100644 index 0000000..4ecd7be --- /dev/null +++ b/crates/ziggurat-efr32/src/hw_crypto.rs @@ -0,0 +1,95 @@ +//! Zigbee crypto backed by the EFR32 RADIOAES hardware engine (`sli_ccm_zigbee` for CCM*, +//! `sli_aes_crypt_ecb_radio` for the AES-128 block). Installed into `ziggurat_zigbee::crypto` +//! so the whole stack's NWK/APS encryption runs on hardware (~91x faster than software). +//! +//! Each operation is synchronous: the RADIOAES DMA is kicked and the call busy-waits for +//! completion (~29 us) — see `sli_radioaes_run_operation`. The management stub's `acquire` +//! waits for the engine to be idle first, so this is safe alongside the radio's own use. + +use ziggurat_ieee_802154::FrameBytes; +use ziggurat_ieee_802154::types::Key; +use ziggurat_rail_sys as rail; +use ziggurat_zigbee::crypto::{self, CryptoBackend, DecryptionError, MIC_LENGTH}; + +/// Max 802.15.4 PHY payload; bounds the scratch buffer. +const MAX_FRAME: usize = 128; + +struct RadioAesBackend; + +impl CryptoBackend for RadioAesBackend { + fn aes128_encrypt_block(&self, key: &[u8; 16], block: &mut [u8; 16]) { + let mut out = [0u8; 16]; + unsafe { + rail::sli_aes_crypt_ecb_radio(true, key.as_ptr(), 128, block.as_ptr(), out.as_mut_ptr()); + } + *block = out; + } + + fn encrypt_ccm(&self, key: &Key, nonce: &[u8; 13], auth_data: &[u8], mut buffer: FrameBytes) -> FrameBytes { + let len = buffer.len(); + let mut out = [0u8; MAX_FRAME]; + let mut tag = [0u8; MIC_LENGTH]; + unsafe { + rail::sli_ccm_zigbee( + true, + buffer.as_ptr(), + out.as_mut_ptr(), + len, + key.0.as_ptr(), + nonce.as_ptr(), + auth_data.as_ptr(), + auth_data.len(), + tag.as_mut_ptr(), + MIC_LENGTH, + ); + } + buffer[..len].copy_from_slice(&out[..len]); + buffer.extend_from_slice(&tag).expect("a frame always has room for its MIC"); + buffer + } + + fn decrypt_ccm( + &self, + key: &Key, + nonce: &[u8; 13], + auth_data: &[u8], + mut tagged_ciphertext: FrameBytes, + ) -> Result { + let ct_len = tagged_ciphertext + .len() + .checked_sub(MIC_LENGTH) + .ok_or(DecryptionError::CiphertextTooShort)?; + let mut tag = [0u8; MIC_LENGTH]; + tag.copy_from_slice(&tagged_ciphertext[ct_len..]); + let mut out = [0u8; MAX_FRAME]; + let status = unsafe { + rail::sli_ccm_zigbee( + false, + tagged_ciphertext.as_ptr(), + out.as_mut_ptr(), + ct_len, + key.0.as_ptr(), + nonce.as_ptr(), + auth_data.as_ptr(), + auth_data.len(), + tag.as_mut_ptr(), + MIC_LENGTH, + ) + }; + if status != 0 { + return Err(DecryptionError::InvalidMacTag); + } + tagged_ciphertext.truncate(ct_len); + tagged_ciphertext[..ct_len].copy_from_slice(&out[..ct_len]); + Ok(tagged_ciphertext) + } +} + +static BACKEND: RadioAesBackend = RadioAesBackend; + +/// Route all Zigbee crypto through the RADIOAES hardware. Call once at startup, before the +/// stack processes any frame. +pub fn init() { + unsafe { rail::sli_protocol_crypto_init() }; + crypto::install(&BACKEND); +} diff --git a/crates/ziggurat-efr32/src/main.rs b/crates/ziggurat-efr32/src/main.rs new file mode 100644 index 0000000..4e68b8a --- /dev/null +++ b/crates/ziggurat-efr32/src/main.rs @@ -0,0 +1,28 @@ +#![no_std] +#![no_main] + +mod uart; + +use core::fmt::Write; + +use cortex_m::asm; +use cortex_m_rt::entry; +use panic_halt as _; + +use uart::Vcom; + +// SYSCLK runs from FSRCO (20 MHz) out of reset, so this is roughly one second. +const CYCLES_PER_SECOND: u32 = 20_000_000; + +#[entry] +fn main() -> ! { + let p = ziggurat_efr32_pac::Peripherals::take().unwrap(); + let mut vcom = Vcom::new(&p.cmu_s, &p.gpio_s, p.eusart0_s); + + let mut counter: u32 = 0; + loop { + let _ = writeln!(vcom, "Hello from EFR32MG24! #{counter}"); + counter = counter.wrapping_add(1); + asm::delay(CYCLES_PER_SECOND); + } +} diff --git a/crates/ziggurat-efr32/src/rail.rs b/crates/ziggurat-efr32/src/rail.rs new file mode 100644 index 0000000..9ebfada --- /dev/null +++ b/crates/ziggurat-efr32/src/rail.rs @@ -0,0 +1,151 @@ +//! Minimal receive-only 802.15.4 bring-up on the EFR32MG24, driving the RAIL blob +//! directly through the modern `sl_rail_*` API (see `ot-efr32/src/src/radio.c` for the +//! full reference). This is a sniffer: promiscuous, no auto-ack, accept all frame types. +//! +//! RAIL is interrupt-driven — the radio ISRs (FRC/MODEM/RAC/PROTIMER/SYNTH/AGC/BUFC/RFECA) +//! advance the state machine and fill the packet queue, then invoke [`rail_events_callback`] +//! from IRQ context. The callback copies the frame into a static slot; the main loop polls +//! [`take_packet`]. + +use core::sync::atomic::{AtomicBool, AtomicU16, Ordering}; + +use ziggurat_rail_sys as rail; + +// --------------------------------------------------------------------------- +// Radio interrupt trampolines. +// +// The RAIL blob defines the radio ISRs as `_IRQHandler`, but the PAC vector table +// names those slots `` (we injected the SVD-redacted radio IRQs in the PAC build). +// Each `#[no_mangle]` fn below is a strong symbol overriding the weak `PROVIDE( = +// DefaultHandler)` from device.x, forwarding to the blob's handler. +// --------------------------------------------------------------------------- +macro_rules! radio_irq { + ($($vector:ident => $handler:ident,)*) => { + extern "C" { $(fn $handler();)* } + $( + #[no_mangle] + extern "C" fn $vector() { unsafe { $handler() } } + )* + }; +} + +radio_irq! { + AGC => AGC_IRQHandler, + BUFC => BUFC_IRQHandler, + FRC => FRC_IRQHandler, + FRC_PRI => FRC_PRI_IRQHandler, + MODEM => MODEM_IRQHandler, + PROTIMER => PROTIMER_IRQHandler, + RAC_RSM => RAC_RSM_IRQHandler, + RAC_SEQ => RAC_SEQ_IRQHandler, + SYNTH => SYNTH_IRQHandler, + RFECA0 => RFECA0_IRQHandler, + RFECA1 => RFECA1_IRQHandler, +} + +// --------------------------------------------------------------------------- +// Constants that bindgen skips (cast / shift macros). +// --------------------------------------------------------------------------- +const EFR32_HANDLE: rail::sl_rail_handle_t = 0xFFFF_FFFF as rail::sl_rail_handle_t; +const RX_PACKET_HANDLE_NEWEST: rail::sl_rail_rx_packet_handle_t = 3 as rail::sl_rail_rx_packet_handle_t; +const EVENT_RX_PACKET_RECEIVED: u64 = + 1 << (rail::sl_rail_events_t_enum::SL_RAIL_EVENT_RX_PACKET_RECEIVED_SHIFT as u64); + +const RX_SLOT_BYTES: usize = 256; + +// --------------------------------------------------------------------------- +// IRQ <-> main-loop handoff: one-packet slot guarded by a ready flag. +// --------------------------------------------------------------------------- +static RX_READY: AtomicBool = AtomicBool::new(false); +static RX_LEN: AtomicU16 = AtomicU16::new(0); +static mut RX_SLOT: [u8; RX_SLOT_BYTES] = [0; RX_SLOT_BYTES]; + +/// RAIL event callback, invoked from radio IRQ context. On a completed RX packet, copy it +/// into the slot (dropping it if the previous one hasn't been consumed yet). +unsafe extern "C" fn rail_events_callback(rail_handle: rail::sl_rail_handle_t, events: rail::sl_rail_events_t) { + if (events as u64) & EVENT_RX_PACKET_RECEIVED == 0 { + return; + } + if RX_READY.load(Ordering::Acquire) { + return; // previous packet still pending; drop this one + } + + let mut info: rail::sl_rail_rx_packet_info_t = core::mem::zeroed(); + rail::sl_rail_get_rx_packet_info(rail_handle, RX_PACKET_HANDLE_NEWEST, &mut info); + if info.packet_bytes == 0 { + return; + } + + let len = core::cmp::min(info.packet_bytes as usize, RX_SLOT_BYTES); + // The packet is auto-released when this callback returns, so copy it out now. + rail::sl_rail_copy_rx_packet(rail_handle, core::ptr::addr_of_mut!(RX_SLOT) as *mut u8, &info); + RX_LEN.store(len as u16, Ordering::Relaxed); + RX_READY.store(true, Ordering::Release); +} + +/// If a received frame is pending, copy it into `dest` and return its length. +pub fn take_packet(dest: &mut [u8]) -> Option { + if !RX_READY.load(Ordering::Acquire) { + return None; + } + let len = RX_LEN.load(Ordering::Relaxed) as usize; + let n = core::cmp::min(len, dest.len()); + // Safe: RX_READY is set, so the IRQ will not touch RX_SLOT until we clear it. + unsafe { + dest[..n].copy_from_slice(&core::ptr::addr_of!(RX_SLOT).as_ref().unwrap()[..n]); + } + RX_READY.store(false, Ordering::Release); + Some(len) +} + +/// Bring up the clock tree (HFXO the safe way) via the SDK's clock manager. Returns the +/// two `sl_status_t` values for diagnostics. +pub fn init_clocks() -> (u32, u32) { + unsafe { + let init = rail::sl_clock_manager_init(); + let runtime = rail::sl_clock_manager_runtime_init(); + (init as u32, runtime as u32) + } +} + +pub struct Radio { + handle: rail::sl_rail_handle_t, +} + +impl Radio { + /// Initialize RAIL and configure the 2.4 GHz 802.15.4 PHY for promiscuous RX. + pub fn new() -> Self { + unsafe { + let mut config: rail::sl_rail_config_t = core::mem::zeroed(); + config.events_callback = Some(rail_events_callback); + config.rx_packet_queue_entries = rail::sl_rail_builtin_rx_packet_queue_entries; + config.p_rx_packet_queue = rail::sl_rail_builtin_rx_packet_queue_ptr; + config.rx_fifo_bytes = rail::sl_rail_builtin_rx_fifo_bytes; + config.p_rx_fifo_buffer = rail::sl_rail_builtin_rx_fifo_ptr; + + let mut handle: rail::sl_rail_handle_t = EFR32_HANDLE; + rail::sl_rail_init(&mut handle, &config, None); + rail::sl_rail_config_cal(handle, rail::SL_RAIL_CAL_ALL as _); + + let mut ieee: rail::sl_rail_ieee802154_config_t = core::mem::zeroed(); + ieee.frames_mask = (rail::SL_RAIL_IEEE802154_ACCEPT_STANDARD_FRAMES + | rail::SL_RAIL_IEEE802154_ACCEPT_ACK_FRAMES) as u8; + ieee.promiscuous_mode = true; + ieee.timings.idle_to_rx = 100; + ieee.timings.tx_to_rx = 182; + ieee.timings.idle_to_tx = 100; + ieee.timings.rx_to_tx = 192; + rail::sl_rail_ieee802154_init(handle, &ieee); + rail::sl_rail_ieee802154_config_2p4_ghz_radio(handle); + + rail::sl_rail_config_events(handle, u64::MAX as _, EVENT_RX_PACKET_RECEIVED as _); + + Radio { handle } + } + } + + /// Start continuous receive on the given 802.15.4 channel (11-26). + pub fn start_rx(&self, channel: u16) -> u32 { + unsafe { rail::sl_rail_start_rx(self.handle, channel, core::ptr::null()) as u32 } + } +} diff --git a/crates/ziggurat-efr32/src/serial.rs b/crates/ziggurat-efr32/src/serial.rs new file mode 100644 index 0000000..1762cf3 --- /dev/null +++ b/crates/ziggurat-efr32/src/serial.rs @@ -0,0 +1,121 @@ +//! Bidirectional EUSART0 for the JSON API on the ZBT-2 VCOM: TX PA08, RX PA07, with +//! CTS PA05 / RTS PA00 hardware flow control (matching the ZBT-2 board), 460800 8N1. +//! +//! RX is interrupt-driven: the EUSART0_RX ISR drains the hardware FIFO into a ring buffer +//! and signals the async reader. This is essential under load — the earlier poll-based RX +//! dropped inbound bytes (corrupting commands) whenever the executor was busy, and its +//! `yield_now` busy-loop kept the core from ever sleeping, starving the radio/capture tasks. +//! TX stays blocking (poll TXFL, gated by hardware CTS), which is fine for the writer task. + +use core::cell::RefCell; + +use critical_section::Mutex; +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::signal::Signal; +use heapless::Deque; +use ziggurat_efr32_pac::{CmuS, Eusart0S, GpioS, Interrupt}; + +const REF_HZ: u32 = 20_000_000; // FSRCO clocking EM01GRPCCLK -> EUSART0 +const BAUD: u32 = 460_800; +const OVS: u32 = 16; +const CLKDIV: u32 = ((32 * REF_HZ) + (BAUD * OVS) / 2) / (BAUD * OVS) - 32; + +/// GPIO port A pin-mode value for a push-pull output (EFR32 `GPIO_P_MODE` encoding). +const MODE_PUSHPULL: u32 = 4; + +const RX_RING_BYTES: usize = 512; + +static RX_RING: Mutex>> = Mutex::new(RefCell::new(Deque::new())); +static RX_SIGNAL: Signal = Signal::new(); + +fn eusart() -> &'static ziggurat_efr32_pac::eusart0_s::RegisterBlock { + unsafe { &*Eusart0S::ptr() } +} + +/// Configure EUSART0 for bidirectional VCOM with CTS/RTS flow control, enable the RX +/// interrupt, and return the split handles. +pub fn init(cmu: &CmuS, gpio: &GpioS, _eusart: Eusart0S) -> (SerialTx, SerialRx) { + cmu.clken0().modify(|_, w| w.gpio().set_bit()); + cmu.clken1().modify(|_, w| w.eusart0().set_bit()); + cmu.em01grpcclkctrl().write(|w| w.clksel().fsrco()); + cmu.eusart0clkctrl().write(|w| w.clksel().em01grpcclk()); + + // RTS PA00 (output, peripheral-driven), CTS PA05 (input), RX PA07 (input) live in MODEL. + gpio.porta_model() + .modify(|_, w| w.mode0().pushpull().mode5().input().mode7().input()); + // TX PA08 lives in MODEH, whose per-pin mode fields aren't generated in the PAC; write + // pin 8's nibble (bits 3:0) to PUSHPULL directly. Pins 9-15 are unused (left disabled). + unsafe { core::ptr::write_volatile(gpio.porta_modeh().as_ptr(), MODE_PUSHPULL) }; + + gpio.eusart0_txroute() + .write(|w| unsafe { w.port().bits(0).pin().bits(8) }); + gpio.eusart0_rxroute() + .write(|w| unsafe { w.port().bits(0).pin().bits(7) }); + gpio.eusart0_ctsroute() + .write(|w| unsafe { w.port().bits(0).pin().bits(5) }); + gpio.eusart0_rtsroute() + .write(|w| unsafe { w.port().bits(0).pin().bits(0) }); + // CTS is an input (no route-enable); enable the TX/RX/RTS output pins. + gpio.eusart0_routeen() + .write(|w| w.txpen().set_bit().rxpen().set_bit().rtspen().set_bit()); + + let e = eusart(); + // Enable CTS flow control (gates TX); RTS is auto-driven from the RX FIFO once routed. + // CFG1 must be written while the EUSART is disabled. + e.cfg1().modify(|_, w| w.ctsen().set_bit()); + e.framecfg() + .write(|w| w.databits().eight().stopbits().one().parity().none()); + e.clkdiv().write(|w| unsafe { w.div().bits(CLKDIV) }); + e.en().write(|w| w.en().set_bit()); + e.cmd().write(|w| w.txen().set_bit().rxen().set_bit()); + + // Interrupt when the RX FIFO has data; the ISR drains it into RX_RING. + e.ien().write(|w| w.rxfl().set_bit()); + unsafe { cortex_m::peripheral::NVIC::unmask(Interrupt::EUSART0_RX) }; + + (SerialTx, SerialRx) +} + +/// EUSART0 RX FIFO interrupt: drain every available byte into the ring, then wake the reader. +#[no_mangle] +extern "C" fn EUSART0_RX() { + let e = eusart(); + critical_section::with(|cs| { + let mut ring = RX_RING.borrow_ref_mut(cs); + while e.status().read().rxfl().bit_is_set() { + let byte = e.rxdata().read().rxdata().bits() as u8; + let _ = ring.push_back(byte); // drop on overflow rather than wedge + } + }); + // IF.RXFL is latched; clear it via the Silabs CLR alias (reg + PER_REG_BLOCK_CLR_OFFSET + // = 0x2000), or the interrupt re-fires forever and wedges the core. + let if_clr = (e.if_().as_ptr() as usize + 0x2000) as *mut u32; + unsafe { core::ptr::write_volatile(if_clr, 0xFFFF_FFFF) }; + RX_SIGNAL.signal(()); +} + +pub struct SerialTx; + +impl SerialTx { + pub fn write_all(&mut self, bytes: &[u8]) { + let e = eusart(); + for &byte in bytes { + while e.status().read().txfl().bit_is_clear() {} + e.txdata().write(|w| unsafe { w.txdata().bits(u16::from(byte)) }); + } + } +} + +pub struct SerialRx; + +impl SerialRx { + /// Await the next received byte from the interrupt-fed ring buffer. + pub async fn read_byte(&mut self) -> u8 { + loop { + if let Some(byte) = critical_section::with(|cs| RX_RING.borrow_ref_mut(cs).pop_front()) { + return byte; + } + RX_SIGNAL.wait().await; + } + } +} diff --git a/crates/ziggurat-efr32/src/time.rs b/crates/ziggurat-efr32/src/time.rs new file mode 100644 index 0000000..098b2ba --- /dev/null +++ b/crates/ziggurat-efr32/src/time.rs @@ -0,0 +1,137 @@ +//! `embassy-time` driver backed by RAIL's microsecond timer. +//! +//! `now()` reads RAIL's free-running microsecond clock (`sl_rail_get_time`, 32-bit, wraps +//! ~every 71 min) and extends it to 64 bits by counting wraps. Alarms use a single RAIL +//! multi-timer whose completion callback (radio IRQ context) services the embassy timer +//! queue. Tick rate is embassy-time's default 1 MHz, so ticks are microseconds directly. +//! +//! Requires the PHY to have initialized RAIL (`ziggurat_phy_efr32::rail_handle()` non-null) +//! and enabled the multi-timer; before that, `now()` reports 0 as the `Driver` contract +//! allows. + +use core::cell::RefCell; +use core::mem::MaybeUninit; +use core::sync::atomic::{AtomicU32, Ordering}; +use core::task::Waker; + +use critical_section::Mutex; +use embassy_time_driver::Driver; +use embassy_time_queue_utils::Queue; +use ziggurat_phy_efr32::rail_handle; +use ziggurat_rail_sys as rail; + +const TIME_ABSOLUTE: rail::sl_rail_time_mode_t = + rail::sl_rail_time_mode_t_enum::SL_RAIL_TIME_ABSOLUTE as rail::sl_rail_time_mode_t; + +/// The one RAIL multi-timer node backing all embassy alarms. RAIL keeps a pointer to it, so +/// it must live forever; zeroed is the valid "unset" state. +static mut ALARM_TIMER: MaybeUninit = MaybeUninit::zeroed(); + +struct RailTimeDriver { + queue: Mutex>, + /// Number of 2^32-microsecond wraps observed by [`now`]. + period: AtomicU32, + /// Last raw microsecond reading, for wrap detection. + last: AtomicU32, +} + +embassy_time_driver::time_driver_impl!( + static DRIVER: RailTimeDriver = RailTimeDriver { + queue: Mutex::new(RefCell::new(Queue::new())), + period: AtomicU32::new(0), + last: AtomicU32::new(0), + } +); + +fn raw_now() -> u32 { + let h = rail_handle(); + if h.is_null() { + return 0; + } + unsafe { rail::sl_rail_get_time(h) } +} + +impl RailTimeDriver { + /// 64-bit monotonic microseconds. Serialized under a critical section so wrap detection + /// is atomic even when called from an interrupt. + fn now64(&self) -> u64 { + critical_section::with(|_| { + let t = raw_now(); + let last = self.last.load(Ordering::Relaxed); + let mut hi = self.period.load(Ordering::Relaxed); + if t < last { + hi = hi.wrapping_add(1); + self.period.store(hi, Ordering::Relaxed); + } + self.last.store(t, Ordering::Relaxed); + (u64::from(hi) << 32) | u64::from(t) + }) + } + + /// Try to program (or cancel) the hardware alarm for deadline `at`. Returns `false` if + /// `at` is already in the past (so RAIL would reject it and never fire) — the caller must + /// then re-service the queue. `u64::MAX` disables the alarm and returns `true`. + fn set_alarm(&self, at: u64) -> bool { + let h = rail_handle(); + if h.is_null() { + return true; + } + let timer = core::ptr::addr_of_mut!(ALARM_TIMER) as *mut rail::sl_rail_multi_timer_t; + critical_section::with(|_| unsafe { + if at == u64::MAX { + rail::sl_rail_cancel_multi_timer(h, timer); + return true; + } + // Bail if the deadline has already passed (checked with interrupts masked so it + // can't slip past between the check and arming the timer). + if at <= self.now64() { + return false; + } + // RAIL's timer is 32-bit microseconds; the low word is the absolute deadline. + rail::sl_rail_set_multi_timer( + h, + timer, + at as u32, + TIME_ABSOLUTE, + Some(on_alarm), + core::ptr::null_mut(), + ) == 0 + }) + } + + /// Re-arm to the queue's next deadline, waking any already-expired timers. Loops so a + /// deadline that lapses while arming is serviced rather than lost. + fn rearm(&self) { + critical_section::with(|cs| { + let mut queue = self.queue.borrow_ref_mut(cs); + loop { + let next = queue.next_expiration(self.now64()); + if self.set_alarm(next) { + break; + } + } + }); + } +} + +impl Driver for RailTimeDriver { + fn now(&self) -> u64 { + self.now64() + } + + fn schedule_wake(&self, at: u64, waker: &Waker) { + let changed = critical_section::with(|cs| self.queue.borrow_ref_mut(cs).schedule_wake(at, waker)); + if changed { + self.rearm(); + } + } +} + +/// RAIL multi-timer completion, in radio IRQ context: wake expired timers and re-arm. +unsafe extern "C" fn on_alarm( + _tmr: *mut rail::sl_rail_multi_timer_t, + _expected: rail::sl_rail_time_t, + _arg: *mut core::ffi::c_void, +) { + DRIVER.rearm(); +} diff --git a/crates/ziggurat-efr32/src/uart.rs b/crates/ziggurat-efr32/src/uart.rs new file mode 100644 index 0000000..311f968 --- /dev/null +++ b/crates/ziggurat-efr32/src/uart.rs @@ -0,0 +1,73 @@ +//! Minimal blocking driver for EUSART0 in UART mode, wired to the xG24 Dev Kit +//! (BRD2601B) virtual COM port: EUSART0 TX on PA05, 115200 8N1. +//! +//! EM01GRPCCLK (and thus EUSART0) is sourced from the always-on 20 MHz FSRCO, so no +//! crystal or DPLL bring-up is needed. + +use core::fmt; + +use ziggurat_efr32_pac::{CmuS, Eusart0S, GpioS}; + +/// FSRCO frequency clocking EM01GRPCCLK → EUSART0. +const REF_HZ: u32 = 20_000_000; +const BAUD: u32 = 115_200; + +/// 16x oversampling (CFG0.OVS reset value). +const OVS: u32 = 16; + +/// CLKDIV.DIV fractional divider field value; mirrors the SDK's +/// `sl_hal_eusart_uart_calculate_clock_div` for the async 16x case. +const CLKDIV: u32 = (32 * REF_HZ) / (BAUD * OVS) - 32; + +pub struct Vcom { + eusart: Eusart0S, +} + +impl Vcom { + /// Bring up clocks, route EUSART0 TX to PA05, and enable the transmitter. + pub fn new(cmu: &CmuS, gpio: &GpioS, eusart: Eusart0S) -> Self { + // Peripheral clocks: GPIO and EUSART0. + cmu.clken0().modify(|_, w| w.gpio().set_bit()); + cmu.clken1().modify(|_, w| w.eusart0().set_bit()); + + // Clock EUSART0 from EM01GRPCCLK, itself sourced from FSRCO (20 MHz). + cmu.em01grpcclkctrl().write(|w| w.clksel().fsrco()); + cmu.eusart0clkctrl().write(|w| w.clksel().em01grpcclk()); + + // PA05 as push-pull output, driven by the EUSART0 TX signal. + gpio.porta_model().modify(|_, w| w.mode5().pushpull()); + gpio.eusart0_txroute() + .write(|w| unsafe { w.port().bits(0).pin().bits(5) }); + gpio.eusart0_routeen().write(|w| w.txpen().set_bit()); + + // Frame format: 8 data bits, 1 stop bit, no parity. Must be set while the + // module is disabled (it is, out of reset). + eusart + .framecfg() + .write(|w| w.databits().eight().stopbits().one().parity().none()); + eusart.clkdiv().write(|w| unsafe { w.div().bits(CLKDIV) }); + + // Enable the module, then the transmitter. + eusart.en().write(|w| w.en().set_bit()); + eusart.cmd().write(|w| w.txen().set_bit()); + + Self { eusart } + } + + pub fn write_byte(&self, byte: u8) { + // Wait until there is room in the TX FIFO. + while self.eusart.status().read().txfl().bit_is_clear() {} + self.eusart + .txdata() + .write(|w| unsafe { w.txdata().bits(byte as u16) }); + } +} + +impl fmt::Write for Vcom { + fn write_str(&mut self, s: &str) -> fmt::Result { + for byte in s.bytes() { + self.write_byte(byte); + } + Ok(()) + } +} diff --git a/crates/ziggurat-phy-efr32/Cargo.lock b/crates/ziggurat-phy-efr32/Cargo.lock new file mode 100644 index 0000000..a39dde4 --- /dev/null +++ b/crates/ziggurat-phy-efr32/Cargo.lock @@ -0,0 +1,570 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "abstract-bits" +version = "0.2.0" +source = "git+https://github.com/yara-blue/abstract-bits.git#f82569eb658505e2b96c9baa498b376169adfe51" +dependencies = [ + "abstract-bits-derive", + "arbitrary-int", + "bitvec", + "thiserror", +] + +[[package]] +name = "abstract-bits-derive" +version = "0.2.0" +source = "git+https://github.com/yara-blue/abstract-bits.git#f82569eb658505e2b96c9baa498b376169adfe51" +dependencies = [ + "proc-macro-error2", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "arbitrary-int" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "825297538d77367557b912770ca3083f778a196054b3ee63b22673c4a3cae0a5" + +[[package]] +name = "bindgen" +version = "0.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex 1.3.0", + "syn", +] + +[[package]] +name = "bitflags" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" + +[[package]] +name = "bitvec" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddcec3d12c579d40898fe0a9a358a803c23e9c52ca3c425707f81c9436211837" +dependencies = [ + "funty", + "radium", + "tap", + "wyz", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cc" +version = "1.2.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96" +dependencies = [ + "find-msvc-tools", + "shlex 2.0.1", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "critical-section" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790eea4361631c5e7d22598ecd5723ff611904e3344ce8720784c93e3d83d40b" + +[[package]] +name = "educe" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d7bc049e1bd8cdeb31b68bbd586a9464ecf9f3944af3958a7a9d0f8b9799417" +dependencies = [ + "enum-ordinalize", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "either" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + +[[package]] +name = "embassy-futures" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc2d050bdc5c21e0862a89256ed8029ae6c290a93aecefc73084b3002cdebb01" + +[[package]] +name = "embassy-sync" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bbd85cf5a5ae56bdf26f618364af642d1d0a4e245cdd75cd9aabda382f65a81" +dependencies = [ + "cfg-if", + "critical-section", + "embedded-io-async", + "futures-core", + "futures-sink", + "heapless", +] + +[[package]] +name = "embedded-io" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9eb1aa714776b75c7e67e1da744b81a129b3ff919c8712b5e1b32252c1f07cc7" + +[[package]] +name = "embedded-io-async" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2564b9f813c544241430e147d8bc454815ef9ac998878d30cc3055449f7fd4c0" +dependencies = [ + "embedded-io", +] + +[[package]] +name = "enum-ordinalize" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "07f808d588c10e464ea6f7d3eaed500049eff30aaac103460f61828c2d65b3eb" +dependencies = [ + "enum-ordinalize-derive", +] + +[[package]] +name = "enum-ordinalize-derive" +version = "4.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42e528e2d34ba8a67a1a650b86beae8ef69fc5fdb638016f386b973226590432" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "funty" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c" + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "hash32" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47d60b12902ba28e2730cd37e95b8c9223af2808df9e902d4df49588d1470606" +dependencies = [ + "byteorder", +] + +[[package]] +name = "heapless" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25ba4bd83f9415b58b4ed8dc5714c76e626a105be4646c02630ad730ad3b5aa4" +dependencies = [ + "hash32", + "stable_deref_trait", +] + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "memchr" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "num_enum" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0bca838442ec211fa11de3a8b0e0e8f3a4522575b5c4c06ed722e005036f26" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "680998035259dcfcafe653688bf2aa6d3e2dc05e98be6ab46afb089dc84f1df8" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro-error-attr2" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96de42df36bb9bba5542fe9f1a054b8cc87e172759a1868aa05c1f3acc89dfc5" +dependencies = [ + "proc-macro2", + "quote", +] + +[[package]] +name = "proc-macro-error2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11ec05c52be0a07b08061f7dd003e7d7092e0472bc731b4af7bb1ef876109802" +dependencies = [ + "proc-macro-error-attr2", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "radium" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09" + +[[package]] +name = "regex" +version = "1.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "syn" +version = "2.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "tap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55937e1799185b12863d447f42597ed69d9928686b8d88a1df17376a097d8369" + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "wyz" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f360fc0b24296329c78fda852a1e9ae82de9cf7b27dae4b7f62f118f77b9ed" +dependencies = [ + "tap", +] + +[[package]] +name = "ziggurat-ieee-802154" +version = "0.1.0" +dependencies = [ + "abstract-bits", + "educe", + "heapless", + "hex", + "num_enum", + "serde", + "thiserror", +] + +[[package]] +name = "ziggurat-phy" +version = "0.1.0" +dependencies = [ + "thiserror", + "ziggurat-ieee-802154", +] + +[[package]] +name = "ziggurat-phy-efr32" +version = "0.1.0" +dependencies = [ + "embassy-futures", + "embassy-sync", + "ziggurat-ieee-802154", + "ziggurat-phy", + "ziggurat-rail-sys", +] + +[[package]] +name = "ziggurat-rail-sys" +version = "0.1.0" +dependencies = [ + "bindgen", + "cc", +] diff --git a/crates/ziggurat-phy-efr32/Cargo.toml b/crates/ziggurat-phy-efr32/Cargo.toml new file mode 100644 index 0000000..9a1382f --- /dev/null +++ b/crates/ziggurat-phy-efr32/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "ziggurat-phy-efr32" +version = "0.1.0" +edition = "2024" +rust-version = "1.96" +description = "Silicon Labs RAIL (EFR32MG24) backend implementing the ziggurat-phy RadioPhy trait" +license = "Apache-2.0" + +[dependencies] +ziggurat-phy = { path = "../ziggurat-phy" } +ziggurat-ieee-802154 = { path = "../ziggurat-ieee-802154" } +ziggurat-rail-sys = { path = "../ziggurat-rail-sys" } + +embassy-sync = "0.8" +embassy-futures = "0.1" + +# Standalone: only builds for thumbv8m.main-none-eabihf (via ziggurat-rail-sys); excluded +# from the host workspace. +[workspace] diff --git a/crates/ziggurat-phy-efr32/src/lib.rs b/crates/ziggurat-phy-efr32/src/lib.rs new file mode 100644 index 0000000..3d4ecab --- /dev/null +++ b/crates/ziggurat-phy-efr32/src/lib.rs @@ -0,0 +1,443 @@ +//! [`RadioPhy`] implemented over Silicon Labs RAIL on the EFR32MG24. +//! +//! RAIL is callback-driven from radio IRQ context: the one `events_callback` registered at +//! [`sl_rail_init`] fires for RX completion and TX/ACK completion. This wraps that in an +//! embassy async layer — the callback copies received frames into a [`Channel`] and posts +//! TX results to a [`Signal`] an async future awaits. Unlike the ESP backend, RAIL performs +//! CSMA-CA and ACK timing in hardware, so no software backoff / `embassy-time` is needed. +//! +//! Prerequisites the board binary must provide before [`Efr32Phy::new`] (mirrors how the ESP +//! backend takes an already-initialized peripheral): the clock tree up (HFXO via the SDK +//! clock manager), the radio IRQ vectors wired to the RAIL blob's `*_IRQHandler`, a global +//! allocator, and an async executor to poll the returned futures. +//! +//! Scaffold status: RX, reconfigure, and transmit are real. Gaps marked TODO: per-frame +//! RSSI/LQI/timestamp extraction, the frame-pending (source-match) table, and energy detect. + +#![no_std] + +extern crate alloc; + +use alloc::string::String; +use core::sync::atomic::{AtomicU8, AtomicUsize, Ordering}; +use core::time::Duration; + +use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex; +use embassy_sync::channel::{Channel, Receiver as ChannelReceiver}; +use embassy_sync::mutex::{Mutex, MutexGuard}; +use embassy_sync::signal::Signal; +use ziggurat_ieee_802154::types::{Eui64, Nwk}; +use ziggurat_phy::{ + ExclusiveRadio, RadioConfig, RadioError, RadioPhy, Receiver, ResetEvent, RxFrame, TxFrame, + TxResult, +}; +use ziggurat_rail_sys as rail; + +const RX_DEPTH: usize = 16; +const TX_FIFO_WORDS: usize = 32; // 128 bytes, RAIL's minimum/typical 802.15.4 TX FIFO + +// RAIL event bits (bindgen only emits the `_SHIFT` values; the bitmask macros are skipped). +mod events { + use ziggurat_rail_sys::sl_rail_events_t_enum as e; + pub const RX_PACKET_RECEIVED: u64 = 1 << e::SL_RAIL_EVENT_RX_PACKET_RECEIVED_SHIFT as u64; + pub const TX_PACKET_SENT: u64 = 1 << e::SL_RAIL_EVENT_TX_PACKET_SENT_SHIFT as u64; + pub const TX_CHANNEL_BUSY: u64 = 1 << e::SL_RAIL_EVENT_TX_CHANNEL_BUSY_SHIFT as u64; + pub const TX_ABORTED: u64 = 1 << e::SL_RAIL_EVENT_TX_ABORTED_SHIFT as u64; + pub const TX_BLOCKED: u64 = 1 << e::SL_RAIL_EVENT_TX_BLOCKED_SHIFT as u64; + pub const TX_UNDERFLOW: u64 = 1 << e::SL_RAIL_EVENT_TX_UNDERFLOW_SHIFT as u64; + pub const RX_ACK_TIMEOUT: u64 = 1 << e::SL_RAIL_EVENT_RX_ACK_TIMEOUT_SHIFT as u64; + pub const RX_FIFO_OVERFLOW: u64 = 1 << e::SL_RAIL_EVENT_RX_FIFO_OVERFLOW_SHIFT as u64; + pub const CAL_NEEDED: u64 = 1 << e::SL_RAIL_EVENT_CAL_NEEDED_SHIFT as u64; + + /// Everything the backend acts on. + pub const SUBSCRIBED: u64 = RX_PACKET_RECEIVED + | RX_FIFO_OVERFLOW + | TX_PACKET_SENT + | TX_CHANNEL_BUSY + | TX_ABORTED + | TX_BLOCKED + | TX_UNDERFLOW + | RX_ACK_TIMEOUT + | CAL_NEEDED; +} + +const TX_OPTION_WAIT_FOR_ACK: u64 = + 1 << rail::sl_rail_tx_options_t_enum::SL_RAIL_TX_OPTION_WAIT_FOR_ACK_SHIFT as u64; + +const RX_PACKET_HANDLE_OLDEST_COMPLETE: rail::sl_rail_rx_packet_handle_t = + 2 as rail::sl_rail_rx_packet_handle_t; +// sl_rail_rx_packet_status_t values. +const RX_PACKET_NONE: u32 = 0; +const RX_PACKET_READY_SUCCESS: u32 = 7; +// SL_RAIL_RF_STATE_RX: keep the radio receiving after each operation. +const RF_STATE_RX: rail::sl_rail_radio_state_t = 2 as rail::sl_rail_radio_state_t; + +/// 802.15.4-2003 2.4 GHz OQPSK CSMA-CA parameters (from the SDK's +/// `SL_RAIL_CSMA_CONFIG_802_15_4_2003_2P4_GHZ_OQPSK_CSMA` initializer). +fn csma_802154() -> rail::sl_rail_csma_config_t { + rail::sl_rail_csma_config_t { + csma_min_bo_exp: 3, + csma_max_bo_exp: 5, + csma_tries: 5, + cca_threshold_dbm: -75, + cca_backoff_us: 320, + cca_duration_us: 128, + csma_timeout_us: 0, + } +} + +// One radio, so a single set of statics backs it; the RAIL callback (plain `extern "C"`, +// no captures) reaches the async side only through them. +static RX_CHANNEL: Channel = Channel::new(); +static RESET_CHANNEL: Channel = Channel::new(); +static TX_COMPLETE: Signal = Signal::new(); + +/// The real RAIL handle from [`sl_rail_init`], stored as a `usize` so the callback and the +/// async methods can recover it. 0 until initialized. +static RAIL_HANDLE: AtomicUsize = AtomicUsize::new(0); +/// The channel the receiver is currently tuned to, for stamping [`RxFrame::channel`]. +static CURRENT_CHANNEL: AtomicU8 = AtomicU8::new(0); + +/// Static TX FIFO. RAIL requires a persistent, word-aligned backing buffer. +static mut TX_FIFO: [u32; TX_FIFO_WORDS] = [0; TX_FIFO_WORDS]; + +fn handle() -> rail::sl_rail_handle_t { + RAIL_HANDLE.load(Ordering::Relaxed) as rail::sl_rail_handle_t +} + +/// The initialized RAIL handle, or null before [`Efr32Phy::new`]. Exposed so a board's +/// embassy-time driver can drive RAIL's microsecond timer / multi-timer. +pub fn rail_handle() -> rail::sl_rail_handle_t { + handle() +} + +/// RAIL event callback, invoked from radio IRQ context. +unsafe extern "C" fn on_rail_event(rail_handle: rail::sl_rail_handle_t, events: rail::sl_rail_events_t) { + let events = events as u64; + + // Drain the ENTIRE RX queue on a receive or FIFO-overflow event. On a busy network the + // radio queues several packets per interrupt (and the byte FIFO overflows and stalls RX + // if not drained promptly), so reading a single packet per event drops almost everything. + if events & (self::events::RX_PACKET_RECEIVED | self::events::RX_FIFO_OVERFLOW) != 0 { + loop { + let mut info: rail::sl_rail_rx_packet_info_t = unsafe { core::mem::zeroed() }; + let handle = unsafe { + rail::sl_rail_get_rx_packet_info(rail_handle, RX_PACKET_HANDLE_OLDEST_COMPLETE, &mut info) + }; + if info.packet_status as u32 == RX_PACKET_NONE { + break; // queue drained + } + if info.packet_status as u32 == RX_PACKET_READY_SUCCESS && info.packet_bytes >= 1 { + let mut details: rail::sl_rail_rx_packet_details_t = unsafe { core::mem::zeroed() }; + unsafe { rail::sl_rail_get_rx_packet_details(rail_handle, handle, &mut details) }; + // RAIL hands us [PHR length byte][MAC frame without FCS]. + let mut buf = [0u8; 128]; + let n = core::cmp::min(info.packet_bytes as usize, buf.len()); + unsafe { rail::sl_rail_copy_rx_packet(rail_handle, buf.as_mut_ptr(), &info) }; + let frame = RxFrame { + psdu: buf[1..n].to_vec(), // drop the PHR length byte + channel: CURRENT_CHANNEL.load(Ordering::Relaxed), + rssi: details.rssi_dbm, + lqi: details.lqi, + timestamp_us: u64::from(details.time_received.packet_time), + }; + let _ = RX_CHANNEL.try_send(frame); + } + // Release to advance the queue and free FIFO space. + unsafe { rail::sl_rail_release_rx_packet(rail_handle, handle) }; + } + } + + // TX/ACK completion. RAIL with WAIT_FOR_ACK reports TX_PACKET_SENT only once the ACK is + // received (success) and RX_ACK_TIMEOUT when none arrives. + let tx_result = if events & self::events::TX_PACKET_SENT != 0 { + Some(TxResult::Acked) + } else if events & self::events::RX_ACK_TIMEOUT != 0 { + Some(TxResult::NoAck) + } else if events & self::events::TX_CHANNEL_BUSY != 0 { + Some(TxResult::ChannelAccessFailure) + } else if events & (self::events::TX_ABORTED | self::events::TX_BLOCKED) != 0 { + Some(TxResult::Aborted) + } else if events & self::events::TX_UNDERFLOW != 0 { + Some(TxResult::Failed) + } else { + None + }; + if let Some(result) = tx_result { + TX_COMPLETE.signal(result); + } + + if events & self::events::CAL_NEEDED != 0 { + unsafe { + rail::sl_rail_calibrate( + rail_handle, + core::ptr::null_mut(), + rail::SL_RAIL_CAL_ALL_PENDING as rail::sl_rail_cal_mask_t, + ) + }; + } +} + +/// Serializes access to the shared radio and tracks the last applied configuration. +struct RadioState { + config: Option, +} + +pub struct Efr32Phy { + state: Mutex, + exclusive: Mutex, +} + +impl Efr32Phy { + /// Initialize RAIL for 2.4 GHz 802.15.4 and register the event callback. The board must + /// have brought up clocks and wired the radio IRQ vectors first (see module docs). + pub fn new() -> Self { + unsafe { + let mut config: rail::sl_rail_config_t = core::mem::zeroed(); + config.events_callback = Some(on_rail_event); + config.rx_packet_queue_entries = rail::sl_rail_builtin_rx_packet_queue_entries; + config.p_rx_packet_queue = rail::sl_rail_builtin_rx_packet_queue_ptr; + config.rx_fifo_bytes = rail::sl_rail_builtin_rx_fifo_bytes; + config.p_rx_fifo_buffer = rail::sl_rail_builtin_rx_fifo_ptr; + + let mut h: rail::sl_rail_handle_t = 0xFFFF_FFFF as rail::sl_rail_handle_t; + rail::sl_rail_init(&mut h, &config, None); + rail::sl_rail_config_cal(h, rail::SL_RAIL_CAL_ALL as _); + + let mut ieee: rail::sl_rail_ieee802154_config_t = core::mem::zeroed(); + ieee.frames_mask = (rail::SL_RAIL_IEEE802154_ACCEPT_STANDARD_FRAMES + | rail::SL_RAIL_IEEE802154_ACCEPT_ACK_FRAMES) as u8; + ieee.timings.idle_to_rx = 100; + ieee.timings.tx_to_rx = 182; + ieee.timings.idle_to_tx = 100; + ieee.timings.rx_to_tx = 192; + ieee.ack_config.enable = true; + ieee.ack_config.ack_timeout_us = 672; + // Stay in RX after every RX/TX/ACK. Left at 0 (INACTIVE) the radio drops to + // idle after the first received+acked frame and stops receiving, catching + // almost nothing on a busy network. + let stay_rx = rail::sl_rail_state_transitions_t { + success: RF_STATE_RX, + error: RF_STATE_RX, + }; + ieee.ack_config.rx_transitions = stay_rx; + ieee.ack_config.tx_transitions = stay_rx; + rail::sl_rail_ieee802154_init(h, &ieee); + rail::sl_rail_ieee802154_config_2p4_ghz_radio(h); + rail::sl_rail_set_rx_transitions(h, &stay_rx); + + rail::sl_rail_util_pa_init(); + let tx_power_config = rail::sl_rail_tx_power_config_t { + mode: rail::sl_rail_tx_power_mode_t_enum::SL_RAIL_TX_POWER_MODE_2P4_GHZ_HIGHEST + as rail::sl_rail_tx_power_mode_t, + voltage_mv: rail::ziggurat_pa_voltage_mv(), + ramp_time_us: rail::ziggurat_pa_ramp_time_us(), + }; + rail::sl_rail_config_tx_power(h, &tx_power_config); + + rail::sl_rail_set_tx_fifo( + h, + core::ptr::addr_of_mut!(TX_FIFO) as *mut rail::sl_rail_fifo_buffer_align_t, + (TX_FIFO_WORDS * 4) as u16, + 0, + 0, + ); + + rail::sl_rail_config_events(h, u64::MAX as _, self::events::SUBSCRIBED as _); + + // Enable the RAIL multi-timer so a board can build an embassy-time driver on it. + rail::sl_rail_config_multi_timer(h, true); + + RAIL_HANDLE.store(h as usize, Ordering::Relaxed); + } + + Self { + state: Mutex::new(RadioState { config: None }), + exclusive: Mutex::new(()), + } + } + + /// Drains received frames — kept for API symmetry with the ESP backend; RAIL already + /// enqueues from the callback, so this is currently a no-op sink. + pub async fn run_rx(&self) -> ! { + core::future::pending().await + } + + async fn transmit_inner(&self, frame: &TxFrame) -> Result { + let ack_requested = frame.psdu.first().is_some_and(|fcf| fcf & 0x20 != 0); + let channel = u16::from(frame.channel.unwrap_or_else(|| CURRENT_CHANNEL.load(Ordering::Relaxed))); + let mut tx_options: rail::sl_rail_tx_options_t = 0; + if ack_requested { + tx_options |= TX_OPTION_WAIT_FOR_ACK as rail::sl_rail_tx_options_t; + } + + let mut attempt = 0u8; + loop { + let result = { + let _state = self.state.lock().await; + let h = handle(); + // RAIL computes and appends the 2-byte FCS in hardware, so the PHR + // length counts those extra 2 bytes. + let phr: u8 = (frame.psdu.len() + 2) as u8; + let csma = csma_802154(); + TX_COMPLETE.reset(); + unsafe { + rail::sl_rail_write_tx_fifo(h, &phr, 1, true); + rail::sl_rail_write_tx_fifo(h, frame.psdu.as_ptr(), frame.psdu.len() as u16, false); + let status = rail::sl_rail_start_cca_csma_tx( + h, + channel, + tx_options, + &csma, + core::ptr::null(), + ); + if status != 0 { + return Err(RadioError::Other(String::from("start_cca_csma_tx failed"))); + } + } + // Hold the radio lock across the completion wait. + TX_COMPLETE.wait().await + }; + + match result { + TxResult::NoAck if attempt < frame.max_frame_retries => attempt += 1, + other => return Ok(other), + } + } + } +} + +impl Default for Efr32Phy { + fn default() -> Self { + Self::new() + } +} + +pub struct Efr32Rx(ChannelReceiver<'static, CriticalSectionRawMutex, RxFrame, RX_DEPTH>); + +impl Receiver for Efr32Rx { + async fn recv(&mut self) -> Option { + Some(self.0.receive().await) + } +} + +pub struct Efr32ResetStream(ChannelReceiver<'static, CriticalSectionRawMutex, ResetEvent, 1>); + +impl Receiver for Efr32ResetStream { + async fn recv(&mut self) -> Option { + Some(self.0.receive().await) + } +} + +pub struct Efr32Exclusive<'a> { + phy: &'a Efr32Phy, + _guard: MutexGuard<'a, CriticalSectionRawMutex, ()>, +} + +impl ExclusiveRadio for Efr32Exclusive<'_> { + async fn set_channel(&self, channel: u8) -> Result<(), RadioError> { + let state = self.phy.state.lock().await; + CURRENT_CHANNEL.store(channel, Ordering::Relaxed); + let h = handle(); + unsafe { + if let Some(config) = state.config.as_ref() { + rail::sl_rail_set_tx_power_dbm(h, rail::sl_rail_tx_power_t::from(config.tx_power) * 10); + } + let status = rail::sl_rail_start_rx(h, u16::from(channel), core::ptr::null()); + if status != 0 { + return Err(RadioError::Other(String::from("start_rx failed"))); + } + } + Ok(()) + } + + async fn transmit(&self, frame: TxFrame) -> Result { + self.phy.transmit_inner(&frame).await + } + + async fn set_promiscuous(&self, promiscuous: bool) -> Result<(), RadioError> { + let _state = self.phy.state.lock().await; + unsafe { rail::sl_rail_ieee802154_set_promiscuous_mode(handle(), promiscuous) }; + Ok(()) + } +} + +impl RadioPhy for Efr32Phy { + type Exclusive<'a> = Efr32Exclusive<'a>; + type RxStream = Efr32Rx; + type ResetStream = Efr32ResetStream; + + async fn reset(&self) -> Result<(), RadioError> { + // No external RCP to reset; reconfigure re-applies all state. Synthesize the reset + // notification the driver waits for. + let _ = RESET_CHANNEL.try_send(ResetEvent { + reason: String::from("rail ready"), + }); + Ok(()) + } + + async fn reconfigure(&self, config: &RadioConfig) -> Result<(), RadioError> { + let mut state = self.state.lock().await; + let h = handle(); + CURRENT_CHANNEL.store(config.channel, Ordering::Relaxed); + unsafe { + rail::sl_rail_ieee802154_set_pan_id(h, config.pan_id.0, 0); + rail::sl_rail_ieee802154_set_short_address(h, config.short_address.as_u16(), 0); + let ext = config.extended_address.to_bytes(); + rail::sl_rail_ieee802154_set_long_address(h, ext.as_ptr(), 0); + rail::sl_rail_ieee802154_set_promiscuous_mode(h, config.promiscuous); + rail::sl_rail_set_tx_power_dbm(h, rail::sl_rail_tx_power_t::from(config.tx_power) * 10); + let status = rail::sl_rail_start_rx(h, u16::from(config.channel), core::ptr::null()); + if status != 0 { + return Err(RadioError::Other(String::from("start_rx failed"))); + } + } + state.config = Some(config.clone()); + Ok(()) + } + + async fn set_frame_pending_table( + &self, + _short: &[Nwk], + _extended: &[Eui64], + ) -> Result<(), RadioError> { + // TODO: RAIL software source-match table (ot-efr32's soft_source_match_table.c) driving + // sl_rail_ieee802154_{set_data_req_frame_pending, enable_data_frame_pending}. + Ok(()) + } + + async fn transmit(&self, frame: TxFrame) -> Result { + // Wait behind any exclusive holder (e.g. a scan) so this can't retune mid-operation. + let _exclusive = self.exclusive.lock().await; + self.transmit_inner(&frame).await + } + + async fn energy_detect(&self, _channel: u8, _duration: Duration) -> Result { + // TODO: real measurement via sl_rail_start_average_rssi over the dwell. For now return + // 0 dBm; the driver's channel selection treats 0 as "no energy" and falls back to a + // default channel, which is fine for bring-up (no TX / real scan needed yet). + Ok(0) + } + + async fn lock(&self) -> Efr32Exclusive<'_> { + Efr32Exclusive { + phy: self, + _guard: self.exclusive.lock().await, + } + } + + fn subscribe_rx(&self) -> Efr32Rx { + Efr32Rx(RX_CHANNEL.receiver()) + } + + fn subscribe_reset(&self) -> Efr32ResetStream { + Efr32ResetStream(RESET_CHANNEL.receiver()) + } +} + +// Compile-time proof that Efr32Phy satisfies the full RadioPhy contract, including the +// `Send + Sync + 'static` supertrait and the `+ Send` bound on every returned future. +const _: () = { + fn assert_radiophy() {} + let _ = assert_radiophy::; +}; diff --git a/crates/ziggurat-phy-esp/src/lib.rs b/crates/ziggurat-phy-esp/src/lib.rs index 6824d09..ac03710 100644 --- a/crates/ziggurat-phy-esp/src/lib.rs +++ b/crates/ziggurat-phy-esp/src/lib.rs @@ -28,6 +28,7 @@ use esp_hal::peripherals::{IEEE802154, Interrupt}; use esp_hal::system::Cpu; use esp_radio::ieee802154::{Config, Ieee802154}; use ziggurat_ieee_802154::types::{Eui64, Nwk}; +use ziggurat_ieee_802154::{FrameBytes, Ieee802154Frame}; use ziggurat_phy::{ ExclusiveRadio, RadioConfig, RadioError, RadioPhy, Receiver, ResetEvent, RxFrame, TxFrame, TxResult, @@ -160,6 +161,11 @@ impl EspPhy { let mut csma_attempt = 0; let ack_requested = frame.psdu.first().is_some_and(|fcf| fcf & 0x20 != 0); + // esp-radio's frame length must include the FCS + let mut raw = frame.psdu.clone(); + let fcs = Ieee802154Frame::::compute_fcs(&raw).to_le_bytes(); + raw.extend_from_slice(&fcs); + loop { let result = { let mut state = self.state.lock().await; @@ -172,7 +178,7 @@ impl EspPhy { TX_FAILED.reset(); state .radio - .transmit_raw(&frame.psdu, frame.csma_ca) + .transmit_raw(&raw, frame.csma_ca) .map_err(|e| RadioError::Other(String::from(esp_err(e))))?; // Hold the radio lock across the completion wait. diff --git a/crates/ziggurat-phy-spinel/src/lib.rs b/crates/ziggurat-phy-spinel/src/lib.rs index 481cbd8..1b3f0bb 100644 --- a/crates/ziggurat-phy-spinel/src/lib.rs +++ b/crates/ziggurat-phy-spinel/src/lib.rs @@ -8,6 +8,7 @@ use tokio::sync::Mutex as AsyncMutex; use tokio::sync::mpsc; use tokio::time::timeout; use ziggurat_ieee_802154::types::{Eui64, Nwk}; +use ziggurat_ieee_802154::{FrameBytes, Ieee802154Frame}; use ziggurat_phy::{ ExclusiveRadio, RadioConfig, RadioError, RadioPhy, Receiver, ResetEvent, RxFrame, TxFrame, TxResult, @@ -251,8 +252,13 @@ async fn apply_config(client: &SpinelClient, config: &RadioConfig) -> Result<(), } fn tx_frame_to_spinel(frame: TxFrame, channel: u8) -> SpinelTxFrame { + // The RCP's frame length must include the FCS. + let mut psdu = frame.psdu; + let fcs = Ieee802154Frame::::compute_fcs(&psdu).to_le_bytes(); + psdu.extend_from_slice(&fcs); + SpinelTxFrame { - psdu: frame.psdu, + psdu, channel: Some(frame.channel.unwrap_or(channel)), max_csma_backoffs: Some(frame.max_csma_backoffs), max_frame_retries: Some(frame.max_frame_retries), diff --git a/crates/ziggurat-phy/src/lib.rs b/crates/ziggurat-phy/src/lib.rs index 6a6139f..c95a84e 100644 --- a/crates/ziggurat-phy/src/lib.rs +++ b/crates/ziggurat-phy/src/lib.rs @@ -17,8 +17,8 @@ pub trait Receiver: Send { fn recv(&mut self) -> impl Future> + Send; } -/// A frame to transmit. `psdu` is the serialized 802.15.4 frame; the backend supplies -/// or recomputes the FCS. `channel` overrides the current channel for this frame only. +/// A frame to transmit. `psdu` is the 802.15.4 frame without the FCS; `channel` +/// overrides the current channel for this frame only. #[derive(Debug, Clone)] pub struct TxFrame { pub psdu: Vec, @@ -138,4 +138,14 @@ pub trait ExclusiveRadio: Send { fn transmit(&self, frame: TxFrame) -> impl Future> + Send; + + fn set_promiscuous( + &self, + promiscuous: bool, + ) -> impl Future> + Send { + async move { + let _ = promiscuous; + Ok(()) + } + } } diff --git a/crates/ziggurat-rail-sys/.gitignore b/crates/ziggurat-rail-sys/.gitignore new file mode 100644 index 0000000..779b29d --- /dev/null +++ b/crates/ziggurat-rail-sys/.gitignore @@ -0,0 +1,6 @@ +/target +Cargo.lock +recipe/build/ +recipe/*.o +recipe/*.elf +recipe/*.map diff --git a/crates/ziggurat-rail-sys/Cargo.lock b/crates/ziggurat-rail-sys/Cargo.lock new file mode 100644 index 0000000..b5fbdb7 --- /dev/null +++ b/crates/ziggurat-rail-sys/Cargo.lock @@ -0,0 +1,251 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "bindgen" +version = "0.70.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f49d8fed880d473ea71efb9bf597651e77201bdd4893efe54c9e5d65ae04ce6f" +dependencies = [ + "bitflags", + "cexpr", + "clang-sys", + "itertools", + "log", + "prettyplease", + "proc-macro2", + "quote", + "regex", + "rustc-hash", + "shlex 1.3.0", + "syn", +] + +[[package]] +name = "bitflags" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" + +[[package]] +name = "cc" +version = "1.2.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e228eec9be7c17ccb640b59b36a5cd805ea2a564a4c5e162c2f659fea30d3b96" +dependencies = [ + "find-msvc-tools", + "shlex 2.0.1", +] + +[[package]] +name = "cexpr" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" +dependencies = [ + "nom", +] + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "clang-sys" +version = "1.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" +dependencies = [ + "glob", + "libc", + "libloading", +] + +[[package]] +name = "either" +version = "1.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e" + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "glob" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "itertools" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" +dependencies = [ + "either", +] + +[[package]] +name = "libc" +version = "0.2.186" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "log" +version = "0.4.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ceec5bc11778974d1bcb055b18002eba7f4b3518b6a0081b3af5f21666da9ad" + +[[package]] +name = "memchr" +version = "2.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4" + +[[package]] +name = "minimal-lexical" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" + +[[package]] +name = "nom" +version = "7.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d273983c5a657a70a3e8f2a01329822f3b8c8172b73826411a55751e404a0a4a" +dependencies = [ + "memchr", + "minimal-lexical", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.46" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfbc457d0c7a0759a614551b11a6409e5951f6c7537be1f1b7682b9ae9230368" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "regex" +version = "1.12.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "shlex" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba" + +[[package]] +name = "syn" +version = "2.0.118" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "ziggurat-rail-sys" +version = "0.1.0" +dependencies = [ + "bindgen", + "cc", +] diff --git a/crates/ziggurat-rail-sys/Cargo.toml b/crates/ziggurat-rail-sys/Cargo.toml new file mode 100644 index 0000000..a275626 --- /dev/null +++ b/crates/ziggurat-rail-sys/Cargo.toml @@ -0,0 +1,19 @@ +[package] +name = "ziggurat-rail-sys" +version = "0.1.0" +edition = "2021" +description = "FFI bindings to Silicon Labs RAIL for EFR32MG24, with the C glue compiled from vendored SDK source and linked against the precompiled RAIL library" +license = "Apache-2.0" +repository = "https://github.com/zigpy/ziggurat" +links = "rail" + +# Excluded from the host workspace; builds only for thumbv8m.main-none-eabihf. +# The one prebuilt binary is vendor/lib/librail_efr32xg24_gcc_release.a; everything +# else is C glue compiled from source (see build.rs + recipe/). The SDK source root +# is configured via the ZIGGURAT_SDK_TREE env var (defaults to the vendored OpenThread +# RCP build tree during bring-up). +[dependencies] + +[build-dependencies] +cc = "1.2" +bindgen = "0.70" diff --git a/crates/ziggurat-rail-sys/build.rs b/crates/ziggurat-rail-sys/build.rs new file mode 100644 index 0000000..92d69c4 --- /dev/null +++ b/crates/ziggurat-rail-sys/build.rs @@ -0,0 +1,204 @@ +use std::env; +use std::fs; +use std::path::{Path, PathBuf}; +use std::process::Command; + +// The Simplicity SDK 2026.6.0 conan package: source of the C glue, headers, and the +// precompiled RAIL library. Fetched once and cached. Bump both together on an SDK update; +// SDK_REV doubles as the cache key so a bump re-downloads. +const SDK_URL: &str = "https://conan.silabs.net/v2/conans/simplicity-sdk/2026.6.0/silabs/_/revisions/d82063f9e47c75ac02812efeee2ac4e2/packages/aba2da4388b60e756ce70b12d6c63f3c69e22ef9/revisions/48dca41e2c905fbd226c80e428b5da12/files/conan_package.tgz"; +const SDK_REV: &str = "48dca41e2c905fbd226c80e428b5da12"; + +// Resolve the SDK root: an explicit pre-extracted tree (fast local dev — point at the +// extracted package or a ~/.silabs install), else the download cache. +fn sdk_root() -> PathBuf { + if let Ok(tree) = env::var("ZIGGURAT_SDK_TREE") { + return PathBuf::from(tree); + } + let cache = env::var("ZIGGURAT_SDK_CACHE") + .map(PathBuf::from) + .unwrap_or_else(|_| PathBuf::from(env::var("HOME").unwrap()).join(".cache/ziggurat-rail-sdk")); + let sdk_dir = cache.join(SDK_REV); + let marker = sdk_dir.join(".extracted"); + if !marker.exists() { + fs::create_dir_all(&sdk_dir).unwrap(); + let tgz = cache.join(format!("{SDK_REV}.tgz")); + if !tgz.exists() { + let ok = Command::new("curl") + .args(["-fSL", "--retry", "3", "-o"]) + .arg(&tgz) + .arg(SDK_URL) + .status() + .unwrap() + .success(); + assert!(ok, "failed to download Simplicity SDK from {SDK_URL}"); + } + let ok = Command::new("tar") + .arg("-xzf") + .arg(&tgz) + .arg("-C") + .arg(&sdk_dir) + .status() + .unwrap() + .success(); + assert!(ok, "failed to extract Simplicity SDK package"); + fs::write(&marker, SDK_URL).unwrap(); + } + sdk_dir +} + +// clang (with --target) doesn't know the arm-none-eabi newlib/gcc header locations the +// way gcc does, so ask gcc for its system include search paths and feed them to bindgen. +fn gcc_system_includes() -> Vec { + let out = Command::new("arm-none-eabi-gcc") + .args(["-E", "-Wp,-v", "-xc", "/dev/null"]) + .output() + .unwrap(); + let stderr = String::from_utf8_lossy(&out.stderr); + let mut args = Vec::new(); + let mut in_section = false; + for line in stderr.lines() { + if line.contains("#include <...> search starts here") { + in_section = true; + } else if line.contains("End of search list") { + break; + } else if in_section { + // Canonicalize first: the newlib dir is reported with `..` segments that pass + // literally through `lib/gcc`. After resolving, keep newlib's headers + // (string.h, …) but skip GCC's own include dirs — their arm_acle.h/arm_mve.h + // use GCC __builtin_arm_* intrinsics clang rejects; clang ships its own. + let dir = fs::canonicalize(line.trim()).unwrap_or_else(|_| PathBuf::from(line.trim())); + // The GCC-internal dirs canonicalize to `.../lib/gcc/...`; newlib's headers + // (string.h, …) live at `.../arm-none-eabi/include` with no `lib/gcc` segment. + if !dir.to_string_lossy().contains("/lib/gcc/") { + args.push(format!("-isystem{}", dir.display())); + } + } + } + args +} + +fn read_lines(path: &Path) -> Vec { + fs::read_to_string(path) + .unwrap_or_else(|e| panic!("reading {}: {e}", path.display())) + .lines() + .map(str::trim) + .filter(|l| !l.is_empty()) + .map(str::to_owned) + .collect() +} + +fn main() { + let crate_dir = PathBuf::from(env::var("CARGO_MANIFEST_DIR").unwrap()); + let recipe = crate_dir.join("recipe"); + let vendor = crate_dir.join("vendor"); + let sdk = sdk_root(); + + // Include dirs (SDK-relative + the vendored SLC config/autogen) and defines, shared + // between the cc glue compile and bindgen. The `defines.txt` entry whose value was + // quote-mangled in the manifest is dropped there and re-added correctly here. + let mut include_dirs: Vec = read_lines(&recipe.join("sdk_includes.txt")) + .iter() + .map(|i| sdk.join(i)) + .collect(); + include_dirs.push(vendor.join("config")); + include_dirs.push(vendor.join("autogen")); + + let mut defines: Vec<(String, Option)> = read_lines(&recipe.join("defines.txt")) + .into_iter() + .filter(|d| !d.ends_with('\\')) + .map(|d| match d.split_once('=') { + Some((k, v)) => (k.to_owned(), Some(v.to_owned())), + None => (d, None), + }) + .collect(); + defines.push(( + "CMSIS_NVIC_VIRTUAL_HEADER_FILE".into(), + Some("\"cmsis_nvic_virtual.h\"".into()), + )); + + let mut build = cc::Build::new(); + build.compiler("arm-none-eabi-gcc"); + build.warnings(false); + + // Exact compile flags from the generated project (LTO dropped — normal compile; + // dead code is pruned by --gc-sections at the final binary link). + for flag in [ + "-mcpu=cortex-m33", + "-mthumb", + "-mfpu=fpv5-sp-d16", + "-mfloat-abi=hard", + "-mcmse", + "-Os", + "-fdata-sections", + "-ffunction-sections", + "-fomit-frame-pointer", + "-fno-strict-aliasing", + "--specs=nano.specs", + "-std=gnu11", + ] { + build.flag(flag); + } + for inc in &include_dirs { + build.include(inc); + } + for (k, v) in &defines { + build.define(k, v.as_deref()); + } + // Glue translation units (platform_core + rail_library), relative to the SDK root. + for src in read_lines(&recipe.join("sdk_sources.txt")) { + build.file(sdk.join(src)); + } + // Minimal RADIOAES management (replaces the SDK's PSA-heavy sli_radioaes_management.c). + build.file(vendor.join("sli_radioaes_stub.c")); + // Accessors exposing the board's compile-time RF config macros to Rust. + build.file(vendor.join("ziggurat_board.c")); + build.compile("ziggurat_rail_glue"); + + // Generate Rust FFI for the public RAIL API. `-fshort-enums` matches the ARM EABI + // (and the precompiled blob's) enum sizing — a mismatch here is silent ABI corruption. + let mut clang_args: Vec = vec![ + "--target=thumbv8m.main-none-eabihf".into(), + "-fshort-enums".into(), + ]; + clang_args.extend(gcc_system_includes()); + clang_args.extend(include_dirs.iter().map(|i| format!("-I{}", i.display()))); + clang_args.extend(defines.iter().map(|(k, v)| match v { + Some(v) => format!("-D{k}={v}"), + None => format!("-D{k}"), + })); + + let bindings = bindgen::Builder::default() + .header(crate_dir.join("wrapper.h").to_str().unwrap()) + .clang_args(&clang_args) + .use_core() + .ctypes_prefix("core::ffi") + .allowlist_function("(sl_rail|RAIL)_.*") + .allowlist_function("sl_clock_manager_.*") + .allowlist_function("sli_(ccm|aes|protocol_crypto)_.*") + .allowlist_function("ziggurat_.*") + .allowlist_type("(sl_rail|RAIL|sli_rail)_.*") + .allowlist_var("(SL_RAIL|RAIL)_.*") + // The blob's built-in RX FIFO/packet-queue backing store (lowercase, so not + // covered by the SL_RAIL_ var pattern above). + .allowlist_var("sl_rail_builtin_.*") + .default_enum_style(bindgen::EnumVariation::ModuleConsts) + .generate() + .expect("bindgen failed to generate RAIL FFI"); + bindings + .write_to_file(PathBuf::from(env::var("OUT_DIR").unwrap()).join("bindings.rs")) + .unwrap(); + println!("cargo:rerun-if-changed=wrapper.h"); + + // The one prebuilt library: the RAIL blob, taken from the SDK package. + println!( + "cargo:rustc-link-search=native={}", + sdk.join("rail_library/autogen/librail_release").display() + ); + println!("cargo:rustc-link-lib=static=rail_efr32xg24_gcc_release"); + + println!("cargo:rerun-if-env-changed=ZIGGURAT_SDK_TREE"); + println!("cargo:rerun-if-env-changed=ZIGGURAT_SDK_CACHE"); + println!("cargo:rerun-if-changed=recipe"); + println!("cargo:rerun-if-changed=vendor"); +} diff --git a/crates/ziggurat-rail-sys/project/app.c b/crates/ziggurat-rail-sys/project/app.c new file mode 100644 index 0000000..a64a4db --- /dev/null +++ b/crates/ziggurat-rail-sys/project/app.c @@ -0,0 +1,16 @@ +// Bare-bones RAIL app. RAIL itself is brought up by the rail_util_init component via +// the generated init sequence, so the application hooks are intentionally empty. + +#include "app.h" + +void app_init(void) +{ +} + +void app_process_action(void) +{ +} + +void app_exit(void) +{ +} diff --git a/crates/ziggurat-rail-sys/project/app.h b/crates/ziggurat-rail-sys/project/app.h new file mode 100644 index 0000000..d324059 --- /dev/null +++ b/crates/ziggurat-rail-sys/project/app.h @@ -0,0 +1,12 @@ +#ifndef APP_H +#define APP_H + +#if defined(SL_COMPONENT_CATALOG_PRESENT) +#include "sl_component_catalog.h" +#endif + +void app_init(void); +void app_process_action(void); +void app_exit(void); + +#endif diff --git a/crates/ziggurat-rail-sys/project/rail_minimal.slcp b/crates/ziggurat-rail-sys/project/rail_minimal.slcp new file mode 100644 index 0000000..4f281f2 --- /dev/null +++ b/crates/ziggurat-rail-sys/project/rail_minimal.slcp @@ -0,0 +1,50 @@ +project_name: rail_minimal +label: RAIL - Minimal +package: platform +description: > + Bare-bones RAIL application: the RAIL library plus its init/PA/PHY/callback glue and + nothing else. Used to generate the minimal RAIL platform (autogen, config, source set) + for the Ziggurat EFR32MG24 port. +category: RAIL Examples +quality: experimental + +component: + - id: sl_main + - id: device_init + - id: clock_manager + - id: rail_lib + - id: rail_util_init + instance: + - inst0 + - id: rail_util_protocol + - id: rail_util_pa + - id: rail_util_callbacks + - id: rail_util_pti + # Match the other ZBT-2 firmwares' link-time optimization. + - id: toolchain_gcc_lto + condition: + - toolchain_gcc + +include: + - path: . + file_list: + - path: app.h + +source: + - path: app.c + +configuration: + - name: SL_MAIN_START_TASK_STACK_SIZE_BYTES + value: 2752 + condition: [sl_main] + - name: SL_STACK_SIZE + value: 0x800 + condition: [kernel] + +filter: + - name: "Wireless Technology" + value: ["Proprietary"] + - name: "Device Type" + value: ["SoC"] + - name: "Project Difficulty" + value: ["Advanced"] diff --git a/crates/ziggurat-rail-sys/project/zbt2_rail_minimal.yaml b/crates/ziggurat-rail-sys/project/zbt2_rail_minimal.yaml new file mode 100644 index 0000000..c716050 --- /dev/null +++ b/crates/ziggurat-rail-sys/project/zbt2_rail_minimal.yaml @@ -0,0 +1,16 @@ +name: Home Assistant Connect ZBT-2 RAIL Minimal +device: EFR32MG24A420F1536IM40 +base_project: src/rail_minimal +filename: "{manifest_name}_gsdk_{sdk_version}" +sdk: "simplicity_sdk:2026.6.0" +toolchain: "gcc:14.2.1.20241119" + +gbl: + fw_type: rail-minimal + baudrate: 460800 + +c_defines: + # ZBT-2 HFXO (39 MHz) — required for the radio to come up. + SL_CLOCK_MANAGER_HFXO_FREQ: 39000000 + SL_CLOCK_MANAGER_HFXO_PRECISION: 10 + SL_CLOCK_MANAGER_HFXO_CTUNE: 108 diff --git a/crates/ziggurat-rail-sys/recipe/defines.txt b/crates/ziggurat-rail-sys/recipe/defines.txt new file mode 100644 index 0000000..3741cfd --- /dev/null +++ b/crates/ziggurat-rail-sys/recipe/defines.txt @@ -0,0 +1,15 @@ +EFR32MG24A420F1536IM40=1 +SL_CODE_COMPONENT_SYSTEM=system +SL_CODE_COMPONENT_CLOCK_MANAGER=clock_manager +SL_COMPONENT_CATALOG_PRESENT=1 +SL_CODE_COMPONENT_GPIO=gpio +SL_CODE_COMPONENT_HAL_COMMON=hal_common +SL_CODE_COMPONENT_HAL_GPIO=hal_gpio +SL_CODE_COMPONENT_HAL_LDMA=hal_ldma +SL_CODE_COMPONENT_INTERRUPT_MANAGER=interrupt_manager +CMSIS_NVIC_VIRTUAL=1 +CMSIS_NVIC_VIRTUAL_HEADER_FILE=\ +SL_RAIL_LIB_MULTIPROTOCOL_SUPPORT=0 +SL_RAIL_UTIL_PA_CONFIG_HEADER= +SL_RAIL_UTIL_PA_PLUGIN_HEADER= +SL_CODE_COMPONENT_CORE=core diff --git a/crates/ziggurat-rail-sys/recipe/sdk_includes.txt b/crates/ziggurat-rail-sys/recipe/sdk_includes.txt new file mode 100644 index 0000000..339f25a --- /dev/null +++ b/crates/ziggurat-rail-sys/recipe/sdk_includes.txt @@ -0,0 +1,34 @@ +cmsis/Core/Include +cmsis/Core/Include/a-profile +cmsis/Core/Include/m-profile +platform_core/platform/common/inc +platform_core/platform/Device/SiliconLabs/EFR32MG24/Include +platform_core/platform/driver/gpio/inc +platform_core/platform/emlib/inc +platform_core/platform/peripheral/inc +platform_core/platform/security/sl_component/sl_protocol_crypto/src +platform_core/platform/service/clock_manager/inc +platform_core/platform/service/clock_manager/src +platform_core/platform/service/device_init/inc +platform_core/platform/service/device_manager/inc +platform_core/platform/service/interrupt_manager/inc +platform_core/platform/service/interrupt_manager/inc/arm +platform_core/platform/service/interrupt_manager/src +platform_core/platform/service/memory_manager/inc +platform_core/platform/service/sl_main/inc +platform_core/platform/service/sl_main/src +rail_library/chip/efr32/efr32xg2x +rail_library/common +rail_library/plugin/pa-conversions +rail_library/plugin/pa-conversions/efr32xg24 +rail_library/plugin/sl_rail_util_built_in_phys/efr32xg24 +rail_library/plugin/sl_rail_util_callbacks +rail_library/plugin/sl_rail_util_compatible_pa +rail_library/plugin/sl_rail_util_pa_conversions +rail_library/plugin/sl_rail_util_protocol +rail_library/plugin/sl_rail_util_pti +rail_library/protocol/ble +rail_library/protocol/ieee802154 +rail_library/protocol/sidewalk +rail_library/protocol/wmbus +rail_library/protocol/zwave diff --git a/crates/ziggurat-rail-sys/recipe/sdk_sources.txt b/crates/ziggurat-rail-sys/recipe/sdk_sources.txt new file mode 100644 index 0000000..9b7736b --- /dev/null +++ b/crates/ziggurat-rail-sys/recipe/sdk_sources.txt @@ -0,0 +1,29 @@ +platform_core/platform/common/src/sl_assert.c +platform_core/platform/common/src/sl_core_cortexm.c +platform_core/platform/common/src/sl_syscalls.c +platform_core/platform/Device/SiliconLabs/EFR32MG24/Source/system_efr32mg24.c +platform_core/platform/driver/gpio/src/sl_gpio.c +platform_core/platform/emlib/src/em_cmu.c +platform_core/platform/emlib/src/em_emu.c +platform_core/platform/emlib/src/em_gpio.c +platform_core/platform/emlib/src/em_system.c +platform_core/platform/service/clock_manager/src/sl_clock_manager_hal_s2.c +platform_core/platform/service/clock_manager/src/sl_clock_manager_init_hal_s2.c +platform_core/platform/service/clock_manager/src/sl_clock_manager_init.c +platform_core/platform/service/clock_manager/src/sl_clock_manager.c +platform_core/platform/service/device_manager/clocks/sl_device_clock_efr32xg24.c +platform_core/platform/service/device_manager/src/sl_device_clock.c +rail_library/plugin/pa-conversions/pa_conversions_efr32.c +rail_library/plugin/pa-conversions/pa_curves_efr32.c +rail_library/plugin/sl_rail_util_pa_conversions/sl_rail_util_pa_conversions.c +rail_library/plugin/sl_rail_util_built_in_phys/efr32xg24/sl_rail_ble_config_38M4Hz.c +rail_library/plugin/sl_rail_util_built_in_phys/efr32xg24/sl_rail_ble_config_39MHz.c +rail_library/plugin/sl_rail_util_built_in_phys/efr32xg24/sl_rail_ble_config_40MHz.c +rail_library/plugin/sl_rail_util_built_in_phys/efr32xg24/sl_rail_ieee802154_config_38M4Hz.c +rail_library/plugin/sl_rail_util_built_in_phys/efr32xg24/sl_rail_ieee802154_config_39MHz.c +rail_library/plugin/sl_rail_util_built_in_phys/efr32xg24/sl_rail_ieee802154_config_40MHz.c +rail_library/plugin/sl_rail_util_built_in_phys/efr32xg24/sl_rail_rfsense_ook_config_38M4Hz.c +rail_library/plugin/sl_rail_util_built_in_phys/efr32xg24/sl_rail_rfsense_ook_config_39MHz.c +rail_library/plugin/sl_rail_util_built_in_phys/efr32xg24/sl_rail_rfsense_ook_config_40MHz.c +rail_library/plugin/sl_rail_util_built_in_phys/sl_rail_util_built_in_phys.c +platform_core/platform/security/sl_component/sl_protocol_crypto/src/sli_protocol_crypto_radioaes.c diff --git a/crates/ziggurat-rail-sys/src/lib.rs b/crates/ziggurat-rail-sys/src/lib.rs new file mode 100644 index 0000000..6dcbad3 --- /dev/null +++ b/crates/ziggurat-rail-sys/src/lib.rs @@ -0,0 +1,14 @@ +//! FFI bindings to Silicon Labs RAIL for the EFR32MG24. +//! +//! The C glue is compiled from the Simplicity SDK by `build.rs` and linked against the +//! precompiled `librail_efr32xg24_gcc_release.a`; the `sl_rail` / `sl_rail_ieee802154` +//! API is bound with bindgen. Safe wrappers live in `ziggurat-phy-efr32`; this crate is +//! the raw `-sys` layer. + +#![no_std] +#![allow(non_upper_case_globals)] +#![allow(non_camel_case_types)] +#![allow(non_snake_case)] +#![allow(dead_code)] + +include!(concat!(env!("OUT_DIR"), "/bindings.rs")); diff --git a/crates/ziggurat-rail-sys/vendor/PROVENANCE.md b/crates/ziggurat-rail-sys/vendor/PROVENANCE.md new file mode 100644 index 0000000..9e3c9ee --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/PROVENANCE.md @@ -0,0 +1,43 @@ +# Vendored inputs + +Most of what this crate compiles comes from the **Simplicity SDK 2026.6.0 conan +package**, which `build.rs` downloads and caches (see `SDK_URL`/`SDK_REV` there): the C +glue sources, all SDK headers, and the precompiled RAIL library. That is *not* vendored. + +Vendored here are only the small, project-specific SLC outputs that are not part of the +SDK package: + +- `config/` — SLC-generated component config headers (`sl_rail_util_*_config.h`, + `sl_device_init_*`, clock-manager/core config, …). +- `autogen/` — SLC-generated glue: `linkerfile.ld`, the component catalog, device-init + instances, the RAIL util init instance, etc. + +These were generated from the **minimal RAIL SLC project** vendored under `../project/` +(`rail_minimal.slcp` + `app.{c,h}` + `zbt2_rail_minimal.yaml`) — a bare-bones project +that is just the RAIL library plus its init/PA/PHY/callback glue. That project's generated +build also defines the authoritative minimal source/include/define set captured in +`../recipe/`. + +## Regenerating config/autogen (after an SDK bump or project change) + +The project is built with NabuCasa's `silabs-firmware-builder` (Docker): + +1. Copy `project/rail_minimal.slcp` + `project/app.{c,h}` to `silabs-firmware-builder/src/rail_minimal/`. +2. Copy `project/zbt2_rail_minimal.yaml` to `silabs-firmware-builder/manifests/nabucasa/zbt2/`. +3. From the builder repo: + ```sh + docker run --rm -v "$(pwd):/repo" silabs-firmware-builder:sdk-bump-arm64 \ + --manifest manifests/nabucasa/zbt2/zbt2_rail_minimal.yaml \ + --output gbl --output-dir artifacts --no-clean-build-dir + ``` + (The `.gbl` postbuild fails — no `app_properties` component — which is fine; the + generated project tree under `build/_zbt2_rail_minimal/` is what we want.) +4. Copy that tree's `config/` and `autogen/` back here, and re-derive `../recipe/*` from + its `cmake_gcc/rail_minimal.cmake`. + +## SDK fetch + +`build.rs` fetches the conan package to `~/.cache/ziggurat-rail-sdk//` (override with +`ZIGGURAT_SDK_CACHE`) and extracts it; the extraction dir is the SDK root. Set +`ZIGGURAT_SDK_TREE` to a pre-extracted SDK (or a `~/.silabs` install) to skip the download +during local development. diff --git a/crates/ziggurat-rail-sys/vendor/autogen/RTE_Components.h b/crates/ziggurat-rail-sys/vendor/autogen/RTE_Components.h new file mode 100644 index 0000000..aa62dc4 --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/autogen/RTE_Components.h @@ -0,0 +1,22 @@ +// This file is autogenerated by Simplicity Configuration Tools. +// The contents of this file will be replaced in their entirety upon regeneration. +// +// Source template file: RTE_Components.h.jinja + + +#ifndef RTE_COMPONENTS_H +#define RTE_COMPONENTS_H + +/* standard device header from emlib */ +#define CMSIS_device_header "em_device.h" + +/* components are auto-generated here */ + + +#endif /* RTE_COMPONENTS_H */ + +/* This file is autogenerated by Simplicity Configuration Tools. */ +/* The contents of this file will be replaced in their entirety upon regeneration. */ +/* */ +/* Source template file: RTE_Components.h.jinja */ + diff --git a/crates/ziggurat-rail-sys/vendor/autogen/gen.properties b/crates/ziggurat-rail-sys/vendor/autogen/gen.properties new file mode 100644 index 0000000..a584e44 --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/autogen/gen.properties @@ -0,0 +1 @@ +sdk=silabs.simplicity_sdk:2026.6.0 diff --git a/crates/ziggurat-rail-sys/vendor/autogen/linkerfile.ld b/crates/ziggurat-rail-sys/vendor/autogen/linkerfile.ld new file mode 100644 index 0000000..95a6bb3 --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/autogen/linkerfile.ld @@ -0,0 +1,318 @@ +/***************************************************************************//** + * GCC Linker script for Silicon Labs devices + ******************************************************************************* + * # License + * Copyright 2020 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Zlib + * + * The licensor of this software is Silicon Laboratories Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + ******************************************************************************/ + + MEMORY + { + FLASH (rx) : ORIGIN = 0x8000000, LENGTH = 0x17e000 + RAM (rwx) : ORIGIN = 0x20000000, LENGTH = 0x40000 + /* Dummy region is used for the dummy segment, which in turn never gets data + * loaded, but is only used to calculate the size of objects placed in it. */ + DUMMY (!ax) : ORIGIN = 0xffe82000, LENGTH = 0x17e000 + } + +/******************************************************************************* + * Due to an issue in GNU LD, which results in wrongly applying the writeable + * flag to a text section (thereby triggering an error since the memory block is + * declared rx), we need to define our segments manually. + * + * Typical Silicon Labs program layout: + * + * ----- START OF APPLICATION FLASH ----- + * R - Vector table + * R X - RAM functions (copied to RAM at startup) + * R - Read-only data + * R X - Code + * R X - Secure Gateways (Trustzone S only) + * R X - extab + * R X - exidx + * R - startup copy table + * R - startup zeroization table + * RW - Initialised RAM data (copied to RAM at startup) + * - [unallocated space] + * - NVM (defined using linker symbols only, not an ELF section) + * ----- END OF APPLICATION FLASH ----- + * + * ----- START OF APPLICATION RAM ----- + * RW - Bootloader reset reason (if present) + * RW - stack + * RW - stack sealing + * RW - BSS (zero-init RAM) + * RW - uninitialised RAM + * R X - RAM functions + * RW - Initialised RAM + * RW - Heap (automatically expanded to end of RAM) + * ----- END OF APPLICATION RAM ----- + * + * ----- START OF DUMMY REGION ----- + * RW - NVM sections (not loadable, only such that linker can calculate the size + * of the symbols placed inside it, to subtract that size from the end of + * the available flash space) + * ----- END OF DUMMY REGION ----- + * + * For the purpose of defining segments, we need a new segment whenever the + * data loaded changes type. That means e.g. we need three segments for all RAM + * content: the initial RW segment, the RX segment, and the final RW segment. + ******************************************************************************/ + +PHDRS +{ + vectors PT_LOAD FLAGS(4); /* Flash content before RAM functions is R */ + readonly PT_LOAD FLAGS(4); /* Readonly content after RAM functions */ + text PT_LOAD FLAGS(5); /* Executable flash content after readonly */ + tables PT_LOAD FLAGS(4); /* Tables supporting startup copying are R */ + empty PT_LOAD FLAGS(4); /* Empty area is R */ + + ram_pre_code PT_LOAD FLAGS(6); /* All RAM content before RAMfuncs is RW */ + ram_code PT_LOAD FLAGS(5); /* RAMfuncs need to be RX */ + ram_data PT_LOAD FLAGS(6); /* Relocatable RAM data needs own segment */ + ram_post_data PT_LOAD FLAGS(6); /* All RAM content after data is RW */ + + dummy_seg PT_NULL FLAGS(4); /* Dummy segment for dummy sections */ +} + +ENTRY(Reset_Handler) + +SECTIONS +{ + .vectors : + { + linker_vectors_begin = .; + KEEP(*(.vectors)) + linker_vectors_end = .; + + __Vectors_End = .; + __Vectors_Size = __Vectors_End - __Vectors; + } > FLASH :vectors + + .stack (NOLOAD): + { + . = ALIGN(8); + __stack_limit = .; + __StackLimit = .; + KEEP(*(.stack*)) + . = ALIGN(4); + __stack = .; + __StackTop = .; + } > RAM :ram_pre_code + + .bss : + { + . = ALIGN(4); + __bss_start__ = .; + *(SORT_BY_ALIGNMENT(.bss*)) + *(COMMON) + . = ALIGN(4); + __bss_end__ = .; + } > RAM :ram_pre_code + + .noinit (NOLOAD) : ALIGN(4) + { + *(.noinit*); + } > RAM :ram_pre_code + + text_application_ram : ALIGN(4) + { + . = ALIGN(4); + __vma_ramfuncs_start__ = .; + + /* text_application_ram */ + *(text_application_ram) + + . = ALIGN(4); + __vma_ramfuncs_end__ = .; + } > RAM AT > FLASH :ram_code + + __lma_ramfuncs_start__ = LOADADDR(text_application_ram); + __lma_ramfuncs_end__ = LOADADDR(text_application_ram) + SIZEOF(text_application_ram); + + .rodata : + { + } > FLASH :readonly + + .text : + { + linker_code_begin = .; + *(SORT_BY_ALIGNMENT(.text*)) + *(SORT_BY_ALIGNMENT(text_*)) + . = ALIGN(32); + linker_code_end = .; + + KEEP(*(.init)) + KEEP(*(.fini)) + + /* .ctors */ + *crtbegin.o(.ctors) + *crtbegin?.o(.ctors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .ctors) + *(SORT(.ctors.*)) + *(.ctors) + + /* .dtors */ + *crtbegin.o(.dtors) + *crtbegin?.o(.dtors) + *(EXCLUDE_FILE(*crtend?.o *crtend.o) .dtors) + *(SORT(.dtors.*)) + *(.dtors) + + *(.rodata*) + *(.eh_frame*) + } > FLASH :text + + .ARM.extab : + { + *(.ARM.extab* .gnu.linkonce.armextab.*) + } > FLASH :text + + __exidx_start = .; + .ARM.exidx : + { + *(.ARM.exidx* .gnu.linkonce.armexidx.*) + } > FLASH :text + __exidx_end = .; + + .copy.table : + { + . = ALIGN(4); + __copy_table_start__ = .; + + LONG (__etext) + LONG (__data_start__) + LONG ((__data_end__ - __data_start__) / 4) + + /* Add each additional data section here */ + /* + LONG (__etext2) + LONG (__data2_start__) + LONG ((__data2_end__ - __data2_start__) / 4) + */ + + __copy_table_end__ = .; + } > FLASH :tables + + .zero.table : + { + . = ALIGN(4); + __zero_table_start__ = .; + /* Add each additional bss section here */ + /* + LONG (__bss2_start__) + LONG ((__bss2_end__ - __bss2_start__) / 4) + */ + + __zero_table_end__ = .; + } > FLASH :tables + + .data : + { + *(vtable) + *(SORT_BY_ALIGNMENT(.data*)) + . = ALIGN(4); + + . = ALIGN(4); + /* preinit data */ + PROVIDE_HIDDEN (__preinit_array_start = .); + KEEP(*(.preinit_array)) + PROVIDE_HIDDEN (__preinit_array_end = .); + + . = ALIGN(4); + /* init data */ + PROVIDE_HIDDEN (__init_array_start = .); + KEEP(*(SORT(.init_array.*))) + KEEP(*(.init_array)) + PROVIDE_HIDDEN (__init_array_end = .); + + . = ALIGN(4); + /* finit data */ + PROVIDE_HIDDEN (__fini_array_start = .); + KEEP(*(SORT(.fini_array.*))) + KEEP(*(.fini_array)) + PROVIDE_HIDDEN (__fini_array_end = .); + + . = ALIGN(4); + /* All data end */ + + } > RAM AT > FLASH :ram_data + + /* Values to support copying initialised values at startup */ + __etext = LOADADDR(.data); + __data_start__ = ADDR(.data); + __data_end__ = ADDR(.data) + SIZEOF(.data); + + ASSERT((__etext % 4) == 0, "Data section needs to be word-aligned in LMA") + ASSERT((__data_start__ % 4) == 0, "Data section needs to be word-aligned in VMA") + ASSERT((__data_end__ % 4) == 0, "Data section needs to be word-multiple sized") + /* Sets the difference between VMA and LMA to 0 for the next NOLOAD sections */ + .empty : + { + } > FLASH :empty + +/* Calculate heap size based on RAM limits. */ +heap_limit = ORIGIN(RAM) + LENGTH(RAM); /* End of RAM */ +heap_size = heap_limit - __HeapBase; + .heap (NOLOAD): + { + . = ALIGN(8); + __HeapBase = .; + . += heap_size; + __end__ = .; + _end = __end__; + KEEP(*(.heap*)) + __HeapLimit = ORIGIN(RAM) + LENGTH(RAM); + } > RAM :ram_post_data + + __ram_end__ = 0x20000000 + 0x40000; + __main_flash_end__ = 0x8000000 + 0x17e000; + + /* This is where we handle flash storage blocks. We use dummy sections for finding the configured + * block sizes and then "place" them at the end of flash when the size is known. */ + .internal_storage (NOLOAD) : { + KEEP(*(.internal_storage*)) + } > DUMMY :dummy_seg + + + .nvm (NOLOAD) : { + KEEP(*(.simee*)) + } > DUMMY :dummy_seg + + __ramfuncs_start__ = __vma_ramfuncs_start__; + __ramfuncs_end__ = __vma_ramfuncs_end__; + + linker_nvm_end = __main_flash_end__; + linker_nvm_begin = linker_nvm_end - SIZEOF(.nvm); + linker_storage_end = linker_nvm_begin; + __nvm3Base = linker_nvm_begin; + + linker_storage_begin = linker_storage_end - SIZEOF(.internal_storage); + ASSERT((linker_storage_begin >= (__etext + SIZEOF(.data))), "FLASH memory overflowed !") + + + HIDDEN(app_flash_end = 0x8000000 + 0x17e000); + ASSERT( (linker_nvm_begin + SIZEOF(.nvm)) <= app_flash_end, "NVM3 is excessing the flash size !") + +} diff --git a/crates/ziggurat-rail-sys/vendor/autogen/sl_component_catalog.h b/crates/ziggurat-rail-sys/vendor/autogen/sl_component_catalog.h new file mode 100644 index 0000000..3d7682e --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/autogen/sl_component_catalog.h @@ -0,0 +1,29 @@ +#ifndef SL_COMPONENT_CATALOG_H +#define SL_COMPONENT_CATALOG_H + +// APIs present in project +#define SL_CATALOG_CLOCK_MANAGER_PRESENT +#define SL_CATALOG_DEVICE_INIT_PRESENT +#define SL_CATALOG_DEVICE_INIT_DCDC_PRESENT +#define SL_CATALOG_DEVICE_INIT_EMU_PRESENT +#define SL_CATALOG_EMLIB_CORE_PRESENT +#define SL_CATALOG_EMLIB_GPIO_PRESENT +#define SL_CATALOG_GPIO_PRESENT +#define SL_CATALOG_HAL_SYSTEM_PRESENT +#define SL_CATALOG_INTERRUPT_MANAGER_PRESENT +#define SL_CATALOG_RAIL_LIB_PRESENT +#define SL_CATALOG_RAIL_UTIL_INIT_PRESENT +#define SL_CATALOG_SL_CORE_PRESENT +#define SL_CATALOG_SL_MAIN_PRESENT +#define SL_CATALOG_SL_RAIL_UTIL_BUILT_IN_PHYS_PRESENT +#define SL_CATALOG_RAIL_UTIL_BUILT_IN_PHYS_PRESENT +#define SL_CATALOG_RAIL_UTIL_CALLBACKS_PRESENT +#define SL_CATALOG_SL_RAIL_UTIL_PROTOCOL_PRESENT +#define SL_CATALOG_RAIL_UTIL_PROTOCOL_PRESENT +#define SL_CATALOG_SL_RAIL_UTIL_PTI_PRESENT +#define SL_CATALOG_RAIL_UTIL_PTI_PRESENT +#define SL_CATALOG_SL_RAIL_UTIL_SEQUENCER_PRESENT +#define SL_CATALOG_RAIL_UTIL_SEQUENCER_PRESENT +#define SL_CATALOG_TOOLCHAIN_GCC_LTO_PRESENT + +#endif // SL_COMPONENT_CATALOG_H diff --git a/crates/ziggurat-rail-sys/vendor/autogen/sl_event_handler.c b/crates/ziggurat-rail-sys/vendor/autogen/sl_event_handler.c new file mode 100644 index 0000000..750f78a --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/autogen/sl_event_handler.c @@ -0,0 +1,69 @@ +#include "sl_event_handler.h" + +#include "sl_clock_manager.h" +#include "sl_rail_util_compatible_pa.h" +#include "sl_rail_util_pti.h" +#include "sl_rail_util_init.h" +#include "sl_gpio.h" + +void sli_driver_permanent_allocation(void) +{ +} + +void sli_service_permanent_allocation(void) +{ +} + +void sli_stack_permanent_allocation(void) +{ +} + +void sli_internal_permanent_allocation(void) +{ +} + +void sl_platform_init(void) +{ + sl_clock_manager_runtime_init(); +} + +void sli_internal_init_early(void) +{ +} + +void sl_driver_init(void) +{ + sl_gpio_init(); +} + +void sl_service_init(void) +{ +} + +void sl_stack_init(void) +{ + sl_rail_util_pa_init(); + sl_rail_util_pti_init(); + sl_rail_util_init(); +} + +void sl_internal_app_init(void) +{ +} + +void sli_platform_process_action(void) +{ +} + +void sli_service_process_action(void) +{ +} + +void sli_stack_process_action(void) +{ +} + +void sli_internal_app_process_action(void) +{ +} + diff --git a/crates/ziggurat-rail-sys/vendor/autogen/sl_event_handler.h b/crates/ziggurat-rail-sys/vendor/autogen/sl_event_handler.h new file mode 100644 index 0000000..5d22097 --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/autogen/sl_event_handler.h @@ -0,0 +1,19 @@ +#ifndef SL_EVENT_HANDLER_H +#define SL_EVENT_HANDLER_H + +void sli_driver_permanent_allocation(void); +void sli_service_permanent_allocation(void); +void sli_stack_permanent_allocation(void); +void sli_internal_permanent_allocation(void); +void sl_platform_init(void); +void sli_internal_init_early(void); +void sl_driver_init(void); +void sl_service_init(void); +void sl_stack_init(void); +void sl_internal_app_init(void); +void sli_platform_process_action(void); +void sli_service_process_action(void); +void sli_stack_process_action(void); +void sli_internal_app_process_action(void); + +#endif // SL_EVENT_HANDLER_H diff --git a/crates/ziggurat-rail-sys/vendor/autogen/sl_rail_util_callbacks.c b/crates/ziggurat-rail-sys/vendor/autogen/sl_rail_util_callbacks.c new file mode 100644 index 0000000..55d3234 --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/autogen/sl_rail_util_callbacks.c @@ -0,0 +1,174 @@ + /***************************************************************************//** + * @file sl_rail_util_callbacks.c + * @brief RAIL Callbacks + * WARNING: Auto-Generated Radio Callbacks - DO NOT EDIT + * Any application code placed within this file will be discarged + * upon project regeneration. + ******************************************************************************* + * # License + * Copyright 2024 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Zlib + * + * The licensor of this software is Silicon Laboratories Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + ******************************************************************************/ + +#include +#ifdef SL_COMPONENT_CATALOG_PRESENT +#include "sl_component_catalog.h" +#endif +#ifdef SL_CATALOG_APP_ASSERT_PRESENT +#include "app_assert.h" +#define APP_ASSERT(expr, ...) app_assert(expr,__VA_ARGS__) +#else + #define APP_ASSERT(expr, ...) \ + do { \ + if (!(expr)) { \ + while (1) ; \ + } \ + } while (0) +#endif + +#include "sl_rail.h" +#include "rail.h" +#include "sl_rail_util_callbacks_config.h" +#include "pa_conversions_efr32.h" + +// Provide weak function called by callback RAILCb_AssertFailed. +__WEAK +#ifdef SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT +void sl_rail_util_on_assert_failed(sl_rail_handle_t rail_handle, + sl_rail_assert_error_codes_t error_code, + int line) +#else//!SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT +void sl_rail_util_on_assert_failed(RAIL_Handle_t rail_handle, + RAIL_AssertErrorCodes_t error_code) +#endif//SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT +{ + (void) rail_handle; + (void) error_code; +#ifdef SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT + (void) line; + APP_ASSERT(false, "rail_handle: 0x%lX, error_code: %" PRIu32 ", line: %d", + (unsigned long)rail_handle, error_code, line); +#else//!SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT + APP_ASSERT(false, "rail_handle: 0x%lX, error_code: %" PRIu32, + (unsigned long)rail_handle, error_code); +#endif//SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT +} + +#if SL_RAIL_UTIL_CALLBACKS_ASSERT_FAILED_OVERRIDE +// Note: RAILCb_AssertFailed is called directly by the RAIL library when +// needed, so maintain this exact function signature. +#ifdef SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT +void sl_railcb_assert_failed(sl_rail_handle_t rail_handle, + sl_rail_assert_error_codes_t error_code, + int line) +#else//!SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT +void RAILCb_AssertFailed(RAIL_Handle_t rail_handle, + RAIL_AssertErrorCodes_t error_code) +#endif//SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT +{ +#ifdef SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT + sl_rail_util_on_assert_failed(rail_handle, error_code, line); +#else//!SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT + sl_rail_util_on_assert_failed(rail_handle, error_code); +#endif//SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT +} +#endif + +// Provide weak function called by callback sli_rail_util_on_rf_ready. +__WEAK +#ifdef SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT +void sl_rail_util_on_rf_ready(sl_rail_handle_t rail_handle) +#else//!SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT +void sl_rail_util_on_rf_ready(RAIL_Handle_t rail_handle) +#endif//SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT +{ + (void) rail_handle; +} + +#ifdef SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT +// Internal-only callback set up through call to sl_rail_init(). +void sli_rail_util_on_rf_ready(sl_rail_handle_t rail_handle) +#else//!SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT +// Internal-only callback set up through call to RAIL_Init(). +void sli_rail_util_on_rf_ready(RAIL_Handle_t rail_handle) +#endif//SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT +{ + sl_rail_util_on_rf_ready(rail_handle); +} + +// Provide weak function called by callback +// sli_rail_util_on_channel_config_change. +__WEAK +#ifdef SL_CATALOG_SL_RAIL_UTIL_PA_PRESENT +void sl_rail_util_on_channel_config_change(sl_rail_handle_t rail_handle, + const sl_rail_channel_config_entry_t *p_entry) +#else//!SL_CATALOG_SL_RAIL_UTIL_PA_PRESENT +void sl_rail_util_on_channel_config_change(RAIL_Handle_t rail_handle, + const RAIL_ChannelConfigEntry_t *p_entry) +#endif//SL_CATALOG_SL_RAIL_UTIL_PA_PRESENT +{ + (void) rail_handle; + (void) p_entry; +} + +#ifdef SL_CATALOG_SL_RAIL_UTIL_PA_PRESENT +// Internal-only callback set up through call to sl_rail_config_channels(). +void sli_rail_util_on_channel_config_change(sl_rail_handle_t rail_handle, + const sl_rail_channel_config_entry_t *p_entry) +#else//!SL_CATALOG_SL_RAIL_UTIL_PA_PRESENT +// Internal-only callback set up through call to RAIL_ConfigChannels(). +void sli_rail_util_on_channel_config_change(RAIL_Handle_t rail_handle, + const RAIL_ChannelConfigEntry_t *p_entry) +#endif//SL_CATALOG_SL_RAIL_UTIL_PA_PRESENT +{ + sl_rail_util_pa_on_channel_config_change(rail_handle, p_entry); + sl_rail_util_on_channel_config_change(rail_handle, p_entry); +} + +// Provide weak function called by callback sli_rail_util_on_event. +__WEAK +#ifdef SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT +void sl_rail_util_on_event(sl_rail_handle_t rail_handle, + sl_rail_events_t events) +#else//!SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT +void sl_rail_util_on_event(RAIL_Handle_t rail_handle, + RAIL_Events_t events) +#endif//SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT +{ + (void) rail_handle; + (void) events; +} + +#ifdef SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT +// Internal-only callback set up through call to sl_rail_init(). +void sli_rail_util_on_event(sl_rail_handle_t rail_handle, + sl_rail_events_t events) +#else//!SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT +// Internal-only callback set up through call to RAIL_Init(). +void sli_rail_util_on_event(RAIL_Handle_t rail_handle, + RAIL_Events_t events) +#endif//SL_CATALOG_SL_RAIL_UTIL_CALLBACKS_PRESENT +{ + sl_rail_util_on_event(rail_handle, events); +} diff --git a/crates/ziggurat-rail-sys/vendor/autogen/sl_rail_util_init.c b/crates/ziggurat-rail-sys/vendor/autogen/sl_rail_util_init.c new file mode 100644 index 0000000..d3c58d6 --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/autogen/sl_rail_util_init.c @@ -0,0 +1,257 @@ +/***************************************************************************//** + * @file + * @brief + ******************************************************************************* + * # License + * Copyright 2020 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Zlib + * + * The licensor of this software is Silicon Laboratories Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + ******************************************************************************/ +#include +#include "rail.h" +#include "rail_ble.h" // for RAIL_BLE_State_t +#include "sli_rail_util_callbacks.h" // for internal-only callback signatures +#include "sl_rail_util_init.h" +#include "sl_rail_util_protocol.h" +#if defined(SL_COMPONENT_CATALOG_PRESENT) +#include "sl_component_catalog.h" +#endif + +#if defined(SL_CATALOG_TIMING_TEST_PRESENT) && !SL_RAIL_LIB_MULTIPROTOCOL_SUPPORT +// Needed for measuring RAIL_Init() time as a part of +// detailed timing characterization. +#include "em_device.h" +#if defined(_SILICON_LABS_32B_SERIES_2) +#include "em_timer.h" +#else +#include "sl_hal_timer.h" +#endif // defined(_SILICON_LABS_32B_SERIES_2) + +#if defined(SL_CATALOG_CLOCK_MANAGER_PRESENT) +#include "sl_clock_manager.h" +#else +#include "em_cmu.h" +#endif //defined(SL_CATALOG_CLOCK_MANAGER_PRESENT) +#endif //defined(SL_CATALOG_TIMING_TEST_PRESENT) && !SL_RAIL_LIB_MULTIPROTOCOL_SUPPORT + +#ifdef SL_CATALOG_APP_ASSERT_PRESENT +#include "app_assert.h" +#define APP_ASSERT(expr, ...) app_assert(expr,__VA_ARGS__) +#else +#define APP_ASSERT(expr, ...) \ + do { \ + if (!(expr)) { \ + while (1) ; \ + } \ + } while (0) +#endif + +#if 0U \ + || SL_RAIL_UTIL_INIT_RADIO_CONFIG_SUPPORT_INST0_ENABLE \ + || 0U + #include "rail_config.h" +#endif + +// Instance: inst0 +static RAIL_Handle_t sl_rail_handle_inst0 = RAIL_EFR32_HANDLE; + +#if defined(SL_CATALOG_TIMING_TEST_PRESENT) && !SL_RAIL_LIB_MULTIPROTOCOL_SUPPORT +uint32_t sli_timing_start_tick = 0U; +uint32_t sli_timing_end_tick = 0U; +static TIMER_TypeDef *timer = TIMER0; +static void setupTimingTestTimer(void) +{ +// Clock TIMER0 using the HF clock +#ifndef SL_CATALOG_CLOCK_MANAGER_PRESENT + CMU_CLOCK_SELECT_SET(TIMER0, HFXO); + CMU_ClockEnable(cmuClock_TIMER0, true); + // Use default configuration, prescaled by 8. + TIMER_Init_TypeDef timerCfg = TIMER_INIT_DEFAULT; + timerCfg.prescale = timerPrescale8; + // Enable TIMER0 to upcount + TIMER_Init(timer, &timerCfg); +#else + sl_clock_manager_enable_bus_clock(SL_BUS_CLOCK_TIMER0); + sl_hal_timer_config_t timerCfg = SL_HAL_TIMER_CONFIG_DEFAULT; + // Use default configuration, prescaled by 8. + timerCfg.prescaler = TIMER_CFG_PRESC_DIV8; + // Enable TIMER0 to upcount + sl_hal_timer_init(timer, &timerCfg); +#endif //SL_CATALOG_CLOCK_MANAGER_PRESENT +} +#endif + +static void sl_rail_util_init_inst0(void) +{ +#if SL_RAIL_UTIL_INIT_INST0_ENABLE + RAIL_Status_t status; + RAIL_Config_t sl_rail_config = { + .eventsCallback = &sli_rail_util_on_event, + // Other fields are ignored nowadays + }; + (void) status; // Suppress compiler warning if status ends up unused +#ifdef SL_CATALOG_TIMING_TEST_PRESENT + setupTimingTestTimer(); + sli_timing_start_tick = timer->CNT; +#endif // SL_CATALOG_TIMING_TEST_PRESENT + sl_rail_handle_inst0 = RAIL_Init(&sl_rail_config, +#if SL_RAIL_UTIL_INIT_INIT_COMPLETE_CALLBACK_INST0_ENABLE + &sli_rail_util_on_rf_ready +#else + NULL +#endif // SL_RAIL_UTIL_INIT_INIT_COMPLETE_CALLBACK_INST0_ENABLE + ); +#ifdef SL_CATALOG_TIMING_TEST_PRESENT + sli_timing_end_tick = timer->CNT; +#endif // SL_CATALOG_TIMING_TEST_PRESENT + APP_ASSERT((NULL != sl_rail_handle_inst0), + "RAIL_Init failed, return value: NULL"); + +#if SL_RAIL_UTIL_INIT_DATA_FORMATS_INST0_ENABLE + RAIL_DataConfig_t data_config = { + .txSource = SL_RAIL_UTIL_INIT_DATA_FORMAT_INST0_TX_SOURCE, + .rxSource = SL_RAIL_UTIL_INIT_DATA_FORMAT_INST0_RX_SOURCE, + .txMethod = SL_RAIL_UTIL_INIT_DATA_FORMAT_INST0_TX_MODE, + .rxMethod = SL_RAIL_UTIL_INIT_DATA_FORMAT_INST0_RX_MODE, + }; + status = RAIL_ConfigData(sl_rail_handle_inst0, &data_config); + APP_ASSERT((RAIL_STATUS_NO_ERROR == status), + "RAIL_ConfigData failed, return value: 0x%04" PRIX32, + status); +#endif // SL_RAIL_UTIL_INIT_DATA_FORMATS_INST0_ENABLE + +#if SL_RAIL_UTIL_INIT_PROTOCOLS_INST0_ENABLE + const RAIL_ChannelConfig_t *channel_config = NULL; + if (SL_RAIL_UTIL_INIT_PROTOCOL_INST0_DEFAULT + == SL_RAIL_UTIL_PROTOCOL_PROPRIETARY) { +#if SL_RAIL_UTIL_INIT_RADIO_CONFIG_SUPPORT_INST0_ENABLE + channel_config = channelConfigs[SL_RAIL_UTIL_INIT_PROTOCOL_PROPRIETARY_INST0_INDEX]; +#else // !SL_RAIL_UTIL_INIT_RADIO_CONFIG_SUPPORT_INST0_ENABLE + APP_ASSERT(false, + "SL_RAIL_UTIL_INIT_RADIO_CONFIG_SUPPORT_INST0_ENABLE must be true when (SL_RAIL_UTIL_INIT_PROTOCOL_INST0_DEFAULT == SL_RAIL_UTIL_PROTOCOL_PROPRIETARY)"); +#endif // SL_RAIL_UTIL_INIT_RADIO_CONFIG_SUPPORT_INST0_ENABLE + } + (void) RAIL_ConfigChannels(sl_rail_handle_inst0, + channel_config, + (RAIL_RadioConfigChangedCallback_t)(void *) + &sli_rail_util_on_channel_config_change); + status = sl_rail_util_protocol_config(sl_rail_handle_inst0, + SL_RAIL_UTIL_INIT_PROTOCOL_INST0_DEFAULT); + APP_ASSERT((RAIL_STATUS_NO_ERROR == status), + "sl_rail_util_protocol_config failed, return value: 0x%04" PRIX32, + status); +#endif // SL_RAIL_UTIL_INIT_PROTOCOLS_INST0_ENABLE + +#if SL_RAIL_UTIL_INIT_CALIBRATIONS_INST0_ENABLE + status = RAIL_ConfigCal(sl_rail_handle_inst0, + 0U + | (SL_RAIL_UTIL_INIT_CALIBRATION_TEMPERATURE_NOTIFY_INST0_ENABLE + ? RAIL_CAL_TEMP : 0U) + | (SL_RAIL_UTIL_INIT_CALIBRATION_ONETIME_NOTIFY_INST0_ENABLE + ? RAIL_CAL_ONETIME : 0U)); + APP_ASSERT((RAIL_STATUS_NO_ERROR == status), + "RAIL_ConfigCal failed, return value: 0x%04" PRIX32, + status); +#endif // SL_RAIL_UTIL_INIT_CALIBRATIONS_INST0_ENABLE + +#if SL_RAIL_UTIL_INIT_EVENTS_INST0_ENABLE + status = RAIL_ConfigEvents(sl_rail_handle_inst0, + RAIL_EVENTS_ALL, + SL_RAIL_UTIL_INIT_EVENT_INST0_MASK); + APP_ASSERT((RAIL_STATUS_NO_ERROR == status), + "RAIL_ConfigEvents failed, return value: 0x%04" PRIX32, + status); +#endif // SL_RAIL_UTIL_INIT_EVENTS_INST0_ENABLE + +#if SL_RAIL_UTIL_INIT_TRANSITIONS_INST0_ENABLE + RAIL_StateTransitions_t tx_transitions = { + .success = SL_RAIL_UTIL_INIT_TRANSITION_INST0_TX_SUCCESS, + .error = SL_RAIL_UTIL_INIT_TRANSITION_INST0_TX_ERROR + }; + RAIL_StateTransitions_t rx_transitions = { + .success = SL_RAIL_UTIL_INIT_TRANSITION_INST0_RX_SUCCESS, + .error = SL_RAIL_UTIL_INIT_TRANSITION_INST0_RX_ERROR + }; + status = RAIL_SetTxTransitions(sl_rail_handle_inst0, + &tx_transitions); + APP_ASSERT((RAIL_STATUS_NO_ERROR == status), + "RAIL_SetTxTransitions failed, return value: 0x%04" PRIX32, + status); + status = RAIL_SetRxTransitions(sl_rail_handle_inst0, + &rx_transitions); + APP_ASSERT((RAIL_STATUS_NO_ERROR == status), + "RAIL_SetRxTransitions failed, return value: 0x%04" PRIX32, + status); +#endif // SL_RAIL_UTIL_INIT_TRANSITIONS_INST0_ENABLE +#else // !SL_RAIL_UTIL_INIT_INST0_ENABLE + // Eliminate compiler warnings. + (void) sl_rail_handle_inst0; +#endif // SL_RAIL_UTIL_INIT_INST0_ENABLE +} + +RAIL_Handle_t sl_rail_util_get_handle(sl_rail_util_handle_type_t handle) +{ + RAIL_Handle_t *sl_rail_handle_array[] = { + &sl_rail_handle_inst0, + }; + return *sl_rail_handle_array[handle]; +} + +#define INIT_INSTANCES (0 + 1) + +#if (INIT_INSTANCES > 1) && !SL_RAIL_LIB_MULTIPROTOCOL_SUPPORT + #error "sl_rail_util_init.c: If you are going to use more than one rail_util_init instance, you must use the Multiprotocol RAIL library." +#elif (INIT_INSTANCES > 4) + static uint64_t extraStateBuffers[INIT_INSTANCES - 4][RAIL_STATE_BUFFER_BYTES / sizeof(uint64_t)]; + static RAIL_StateBufferEntry_t extraProtos[INIT_INSTANCES - 4]; +#else + // RAIL provides enough built-in state buffers for all the instances +#endif + +void sl_rail_util_init(void) +{ +#if (INIT_INSTANCES > 2) + RAIL_Status_t status; + status = RAIL_AddStateBuffer3(RAIL_EFR32_HANDLE); + APP_ASSERT((RAIL_STATUS_NO_ERROR == status), + "RAIL_AddStateBuffer3 failed, return value: 0x%04" PRIX32, + status); +#if (INIT_INSTANCES > 3) + status = RAIL_AddStateBuffer4(RAIL_EFR32_HANDLE); + APP_ASSERT((RAIL_STATUS_NO_ERROR == status), + "RAIL_AddStateBuffer4 failed, return value: 0x%04" PRIX32, + status); +#endif +#if (INIT_INSTANCES > 4) + for (int i = 0; i < (INIT_INSTANCES - 4); i++) { + extraProtos[i].bufferBytes = sizeof(extraStateBuffers[0]); + extraProtos[i].buffer = extraStateBuffers[i]; + status = RAIL_AddStateBuffer(RAIL_EFR32_HANDLE, &extraProtos[i]); + APP_ASSERT((RAIL_STATUS_NO_ERROR == status), + "RAIL_AddStateBuffer(%d) failed, return value: 0x%04" PRIX32, + (INIT_INSTANCES + i), status); + } +#endif +#endif + sl_rail_util_init_inst0(); +} diff --git a/crates/ziggurat-rail-sys/vendor/autogen/sl_rail_util_init.h b/crates/ziggurat-rail-sys/vendor/autogen/sl_rail_util_init.h new file mode 100644 index 0000000..b5980b7 --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/autogen/sl_rail_util_init.h @@ -0,0 +1,228 @@ +/***************************************************************************//** + * @file + * @brief + ******************************************************************************* + * # License + * Copyright 2020 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Zlib + * + * The licensor of this software is Silicon Laboratories Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + ******************************************************************************/ + +#ifndef SL_RAIL_UTIL_INIT_H +#define SL_RAIL_UTIL_INIT_H + +#include "rail.h" +#include "sl_rail_util_init_inst0_config.h" + +#ifdef __cplusplus +extern "C" { +#endif + +typedef enum sl_rail_util_handle_type{ + SL_RAIL_UTIL_HANDLE_INST0, +} sl_rail_util_handle_type_t; + +/** + * Initialize the RAIL Init Utility. + * + * @note: This function should be called during application initialization. + */ +void sl_rail_util_init(void); + +/** + * Get the RAIL handle created during initialization. + * @param[in] handle The enum name of the desired RAIL handle. + * + * @return A valid RAIL handle. If the RAIL handle hasn't been set up, the + * invalid value of \ref RAIL_EFR32_HANDLE will be returned. + */ +RAIL_Handle_t sl_rail_util_get_handle(sl_rail_util_handle_type_t handle); + +/** + * A callback available to the application, called on RAIL asserts. + * + * @param[in] rail_handle The RAIL handle associated with the assert. + * @param[in] error_code The assertion error code. + */ +void sl_rail_util_on_assert_failed(RAIL_Handle_t rail_handle, + RAIL_AssertErrorCodes_t error_code); + +/** + * A callback available to the application, called on RAIL init completion. + * + * @param[in] rail_handle The RAIL handle associated with the RAIL init + * completion notification. + */ +void sl_rail_util_on_rf_ready(RAIL_Handle_t rail_handle); + +/** + * A callback available to the application, called on a channel configuration + * change. + * + * @param[in] rail_handle The RAIL handle associated with the channel config + * change notification. + * @param[in] p_entry A pointer to the channel configuration being changed to. + */ +void sl_rail_util_on_channel_config_change(RAIL_Handle_t rail_handle, + const RAIL_ChannelConfigEntry_t *p_entry); + +/** + * A callback available to the application, called on registered RAIL events. + * + * @param[in] rail_handle The RAIL handle associated with the RAIL event + * notification. + * @param[in] events The RAIL events having occurred. + */ +void sl_rail_util_on_event(RAIL_Handle_t rail_handle, + RAIL_Events_t events); + +#ifndef SL_RAIL_UTIL_INIT_EVENT_TX_CCA_ACTIVATED_INST0_ENABLE +#define SL_RAIL_UTIL_INIT_EVENT_TX_CCA_ACTIVATED_INST0_ENABLE 0 +#endif + +/** + * An event mask, available to the application, specifying the radio events + * setup within the init code. + * + * @note: Because the value of this define is evaluated based on values in the + * \ref RAIL_Events_t enum, this define will only have a valid value during + * run-time. + */ +#define SL_RAIL_UTIL_INIT_EVENT_INST0_MASK (RAIL_EVENTS_NONE \ + | (SL_RAIL_UTIL_INIT_EVENT_RSSI_AVERAGE_DONE_INST0_ENABLE \ + ? RAIL_EVENT_RSSI_AVERAGE_DONE : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_RX_ACK_TIMEOUT_INST0_ENABLE \ + ? RAIL_EVENT_RX_ACK_TIMEOUT : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_RX_FIFO_ALMOST_FULL_INST0_ENABLE \ + ? RAIL_EVENT_RX_FIFO_ALMOST_FULL : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_RX_PACKET_RECEIVED_INST0_ENABLE \ + ? RAIL_EVENT_RX_PACKET_RECEIVED : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_RX_PREAMBLE_LOST_INST0_ENABLE \ + ? RAIL_EVENT_RX_PREAMBLE_LOST : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_RX_PREAMBLE_DETECT_INST0_ENABLE \ + ? RAIL_EVENT_RX_PREAMBLE_DETECT : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_RX_SYNC1_DETECT_INST0_ENABLE \ + ? RAIL_EVENT_RX_SYNC1_DETECT : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_RX_SYNC2_DETECT_INST0_ENABLE \ + ? RAIL_EVENT_RX_SYNC2_DETECT : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_RX_FRAME_ERROR_INST0_ENABLE \ + ? RAIL_EVENT_RX_FRAME_ERROR : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_RX_FIFO_FULL_INST0_ENABLE \ + ? RAIL_EVENT_RX_FIFO_FULL : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_RX_FIFO_OVERFLOW_INST0_ENABLE \ + ? RAIL_EVENT_RX_FIFO_OVERFLOW : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_RX_ADDRESS_FILTERED_INST0_ENABLE \ + ? RAIL_EVENT_RX_ADDRESS_FILTERED : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_RX_TIMEOUT_INST0_ENABLE \ + ? RAIL_EVENT_RX_TIMEOUT : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_RX_TX_SCHEDULED_RX_TX_STARTED_INST0_ENABLE \ + ? RAIL_EVENT_SCHEDULED_RX_STARTED : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_RX_SCHEDULED_RX_END_INST0_ENABLE \ + ? RAIL_EVENT_RX_SCHEDULED_RX_END : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_RX_SCHEDULED_RX_MISSED_INST0_ENABLE \ + ? RAIL_EVENT_RX_SCHEDULED_RX_MISSED : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_RX_PACKET_ABORTED_INST0_ENABLE \ + ? RAIL_EVENT_RX_PACKET_ABORTED : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_RX_FILTER_PASSED_INST0_ENABLE \ + ? RAIL_EVENT_RX_FILTER_PASSED : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_RX_TIMING_LOST_INST0_ENABLE \ + ? RAIL_EVENT_RX_TIMING_LOST : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_RX_TIMING_DETECT_INST0_ENABLE \ + ? RAIL_EVENT_RX_TIMING_DETECT : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_RX_CHANNEL_HOPPING_COMPLETE_INST0_ENABLE \ + ? RAIL_EVENT_RX_CHANNEL_HOPPING_COMPLETE : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_RX_DUTY_CYCLE_RX_END_INST0_ENABLE \ + ? RAIL_EVENT_RX_DUTY_CYCLE_RX_END : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_IEEE802154_DATA_REQUEST_COMMAND_INST0_ENABLE \ + ? RAIL_EVENT_IEEE802154_DATA_REQUEST_COMMAND : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_ZWAVE_BEAM_INST0_ENABLE \ + ? RAIL_EVENT_ZWAVE_BEAM : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_ZWAVE_LR_ACK_REQUEST_COMMAND_INST0_ENABLE \ + ? RAIL_EVENT_ZWAVE_LR_ACK_REQUEST_COMMAND : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_TX_FIFO_ALMOST_EMPTY_INST0_ENABLE \ + ? RAIL_EVENT_TX_FIFO_ALMOST_EMPTY : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_TX_PACKET_SENT_INST0_ENABLE \ + ? RAIL_EVENT_TX_PACKET_SENT : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_TXACK_PACKET_SENT_INST0_ENABLE \ + ? RAIL_EVENT_TXACK_PACKET_SENT : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_TX_ABORTED_INST0_ENABLE \ + ? RAIL_EVENT_TX_ABORTED : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_TXACK_ABORTED_INST0_ENABLE \ + ? RAIL_EVENT_TXACK_ABORTED : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_TX_BLOCKED_INST0_ENABLE \ + ? RAIL_EVENT_TX_BLOCKED : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_TXACK_BLOCKED_INST0_ENABLE \ + ? RAIL_EVENT_TXACK_BLOCKED : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_TX_UNDERFLOW_INST0_ENABLE \ + ? RAIL_EVENT_TX_UNDERFLOW : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_TXACK_UNDERFLOW_INST0_ENABLE \ + ? RAIL_EVENT_TXACK_UNDERFLOW : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_TX_CHANNEL_CLEAR_INST0_ENABLE \ + ? RAIL_EVENT_TX_CHANNEL_CLEAR : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_TX_CHANNEL_BUSY_INST0_ENABLE \ + ? RAIL_EVENT_TX_CHANNEL_BUSY : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_TX_CCA_RETRY_INST0_ENABLE \ + ? RAIL_EVENT_TX_CCA_RETRY : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_TX_START_CCA_INST0_ENABLE \ + ? RAIL_EVENT_TX_START_CCA : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_TX_CCA_ACTIVATED_INST0_ENABLE \ + ? RAIL_EVENT_TX_CCA_ACTIVATED : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_TX_STARTED_INST0_ENABLE \ + ? RAIL_EVENT_TX_STARTED : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_TX_SCHEDULED_TX_MISSED_INST0_ENABLE \ + ? RAIL_EVENT_TX_SCHEDULED_TX_MISSED : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_CONFIG_UNSCHEDULED_INST0_ENABLE \ + ? RAIL_EVENT_CONFIG_UNSCHEDULED : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_CONFIG_SCHEDULED_INST0_ENABLE \ + ? RAIL_EVENT_CONFIG_SCHEDULED : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_SCHEDULER_STATUS_INST0_ENABLE \ + ? RAIL_EVENT_SCHEDULER_STATUS : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_CAL_NEEDED_INST0_ENABLE \ + ? RAIL_EVENT_CAL_NEEDED : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_DETECT_RSSI_THRESHOLD_INST0_ENABLE \ + ? RAIL_EVENT_DETECT_RSSI_THRESHOLD : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_THERMISTOR_DONE_INST0_ENABLE \ + ? RAIL_EVENT_THERMISTOR_DONE : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_TX_BLOCKED_TOO_HOT_INST0_ENABLE \ + ? RAIL_EVENT_TX_BLOCKED_TOO_HOT : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_TEMPERATURE_TOO_HOT_INST0_ENABLE \ + ? RAIL_EVENT_TEMPERATURE_TOO_HOT : RAIL_EVENTS_NONE) \ + | (SL_RAIL_UTIL_INIT_EVENT_TEMPERATURE_COOL_DOWN_INST0_ENABLE \ + ? RAIL_EVENT_TEMPERATURE_COOL_DOWN : RAIL_EVENTS_NONE)) + +/** + * An inverted event mask, available to the application, specifying the radio + * events setup within the init code. + * + * @note: Because the value of this define is evaluated based on values in the + * \ref RAIL_Events_t enum, this define will only have a valid value during + * run-time. + */ +#define SL_RAIL_UTIL_INIT_EVENT_INST0_INVERSE_MASK \ + (~SL_RAIL_UTIL_INIT_EVENT_INST0_MASK) + +#ifdef __cplusplus +} +#endif + +#endif // SL_RAIL_UTIL_INIT_H diff --git a/crates/ziggurat-rail-sys/vendor/config/sl_clock_manager_oscillator_config.h b/crates/ziggurat-rail-sys/vendor/config/sl_clock_manager_oscillator_config.h new file mode 100644 index 0000000..985c622 --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/config/sl_clock_manager_oscillator_config.h @@ -0,0 +1,414 @@ +/***************************************************************************//** + * @file + * @brief Clock Manager - Oscillators configuration file. + ******************************************************************************* + * # License + * Copyright 2026 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Zlib + * + * The licensor of this software is Silicon Laboratories Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + ******************************************************************************/ + +#ifndef SL_CLOCK_MANAGER_OSCILLATOR_CONFIG_H +#define SL_CLOCK_MANAGER_OSCILLATOR_CONFIG_H + +#if defined(SL_COMPONENT_CATALOG_PRESENT) +#include "sl_component_catalog.h" + +#endif + +// Internal Defines: DO NOT MODIFY +#define SL_CLOCK_MANAGER_HFXO_EN_ENABLE 1 +#define SL_CLOCK_MANAGER_HFXO_EN_DISABLE 0 + +#if defined(SL_CATALOG_RAIL_LIB_PRESENT) +#define SL_CLOCK_MANAGER_HFXO_EN_AUTO SL_CLOCK_MANAGER_HFXO_EN_ENABLE +#else +#define SL_CLOCK_MANAGER_HFXO_EN_AUTO SL_CLOCK_MANAGER_HFXO_EN_DISABLE +#endif + +// <<< Use Configuration Wizard in Context Menu >>> + +// Oscillators Settings + +// HFXO Settings (if High Frequency crystal is used) + +// Enable +// Enable to configure HFXO +// AUTO enables HFXO if a radio is used +// AUTO +// ENABLE +// DISABLE +// SL_CLOCK_MANAGER_HFXO_EN_AUTO +#ifndef SL_CLOCK_MANAGER_HFXO_EN +#define SL_CLOCK_MANAGER_HFXO_EN SL_CLOCK_MANAGER_HFXO_EN_ENABLE +#endif + +// Mode +// +// XTAL +// EXTCLK +// EXTCLKPKDET +// HFXO_CFG_MODE_XTAL +#ifndef SL_CLOCK_MANAGER_HFXO_MODE +#define SL_CLOCK_MANAGER_HFXO_MODE HFXO_CFG_MODE_XTAL +#endif + +// Frequency in Hz <38000000-40000000> +// 39000000 +#ifndef SL_CLOCK_MANAGER_HFXO_FREQ +#define SL_CLOCK_MANAGER_HFXO_FREQ 39000000 +#endif + +// CTUNE <0-255> +// 140 +#ifndef SL_CLOCK_MANAGER_HFXO_CTUNE +#define SL_CLOCK_MANAGER_HFXO_CTUNE 108 +#endif + +// Enable DC Bias (AC-Coupled EXTCLK) +// Enable to add an internal DC bias +// when AC-coupled connected external oscillator +// 0 +#ifndef SL_CLOCK_MANAGER_HFXO_ENXIDCBIASANA +#define SL_CLOCK_MANAGER_HFXO_ENXIDCBIASANA 0 +#endif + +// Precision in PPM <0-65535> +// 50 +#ifndef SL_CLOCK_MANAGER_HFXO_PRECISION +#define SL_CLOCK_MANAGER_HFXO_PRECISION 10 +#endif + +// CTUNE HXFO manufacturing +// Enable to use CTUNE HFXO manufacturing value for calibration +// 1 +#ifndef SL_CLOCK_MANAGER_CTUNE_MFG_HFXO_EN +#define SL_CLOCK_MANAGER_CTUNE_MFG_HFXO_EN 1 +#endif + +// Enable Separate CTUNE XI/XO +// Enable to be able to configure the XI and XO CTUNE values separately +#ifndef SL_CLOCK_MANAGER_HFXO_SEPARATE_CTUNEXIANA_CTUNEXOANA_EN +#define SL_CLOCK_MANAGER_HFXO_SEPARATE_CTUNEXIANA_CTUNEXOANA_EN 0 +#endif + +// CTUNE XI <0-255> +// 140 +#ifndef SL_CLOCK_MANAGER_HFXO_CTUNEXIANA +#define SL_CLOCK_MANAGER_HFXO_CTUNEXIANA 140 +#endif + +// CTUNE XO <0-255> +// 140 +#ifndef SL_CLOCK_MANAGER_HFXO_CTUNEXOANA +#define SL_CLOCK_MANAGER_HFXO_CTUNEXOANA 140 +#endif + +// + +// HFXO crystal sharing feature +// Enable to configure HFXO crystal sharing leader or follower +#ifndef SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_EN +#define SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_EN 0 +#endif + +// Crystal sharing leader +// Enable to configure HFXO crystal sharing leader +#ifndef SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_LEADER_EN +#define SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_LEADER_EN 0 +#endif + +// Crystal sharing leader minimum startup delay +// If enabled, BUFOUT does not start until timeout set in +// SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_LEADER_TIMEOUT_STARTUP expires. +// This prevents waste of power if BUFOUT is ready too early. +// 1 +#ifndef SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_LEADER_MIN_STARTUP_DELAY_EN +#define SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_LEADER_MIN_STARTUP_DELAY_EN 1 +#endif + +// Wait duration of oscillator startup sequence +// +// T42US +// T83US +// T108US +// T133US +// T158US +// T183US +// T208US +// T233US +// T258US +// T283US +// T333US +// T375US +// T417US +// T458US +// T500US +// T667US +// HFXO_BUFOUTCTRL_TIMEOUTSTARTUP_T208US +#ifndef SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_LEADER_TIMEOUT_STARTUP +#define SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_LEADER_TIMEOUT_STARTUP HFXO_BUFOUTCTRL_TIMEOUTSTARTUP_T208US +#endif +// +// + +// Crystal sharing follower +// Enable to configure HFXO crystal sharing follower +#ifndef SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_FOLLOWER_EN +#define SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_FOLLOWER_EN 0 +#endif +// + +// GPIO Port +// Bufout request GPIO port. If SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_LEADER_EN +// is enabled, this port will be used to receive the BUFOUT request. If +// SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_FOLLOWER_EN is enabled this port +// will be used to request BUFOUT from the crystal sharing leader. +#ifndef SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_GPIO_PORT +#define SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_GPIO_PORT 0 +#endif + +// GPIO Pin +// Bufout request GPIO pin. If SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_LEADER_EN +// is enabled, this pin will be used to receive the BUFOUT request. If +// SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_FOLLOWER_EN is enabled this pin +// will be used to request BUFOUT from the crystal sharing leader. +#ifndef SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_GPIO_PIN +#define SL_CLOCK_MANAGER_HFXO_CRYSTAL_SHARING_GPIO_PIN 10 +#endif +// +// + +// LFXO Settings (if Low Frequency crystal is used) +// Enable to configure LFXO +#ifndef SL_CLOCK_MANAGER_LFXO_EN +#define SL_CLOCK_MANAGER_LFXO_EN 1 +#endif + +// Mode +// +// XTAL +// BUFEXTCLK +// DIGEXTCLK +// LFXO_CFG_MODE_XTAL +#ifndef SL_CLOCK_MANAGER_LFXO_MODE +#define SL_CLOCK_MANAGER_LFXO_MODE LFXO_CFG_MODE_XTAL +#endif + +// CTUNE <0-127> +// 63 +#ifndef SL_CLOCK_MANAGER_LFXO_CTUNE +#define SL_CLOCK_MANAGER_LFXO_CTUNE 63 +#endif + +// Gain <0-3> +// LFXO gain setting for load capacitance matching +// 1 +#ifndef SL_CLOCK_MANAGER_LFXO_GAIN +#define SL_CLOCK_MANAGER_LFXO_GAIN 1 +#endif + +// LFXO precision in PPM <0-65535> +// 50 +#ifndef SL_CLOCK_MANAGER_LFXO_PRECISION +#define SL_CLOCK_MANAGER_LFXO_PRECISION 50 +#endif + +// Startup Timeout Delay +// +// CYCLES2 +// CYCLES256 +// CYCLES1K +// CYCLES2K +// CYCLES4K +// CYCLES8K +// CYCLES16K +// CYCLES32K +// LFXO_CFG_TIMEOUT_CYCLES4K +#ifndef SL_CLOCK_MANAGER_LFXO_TIMEOUT +#define SL_CLOCK_MANAGER_LFXO_TIMEOUT LFXO_CFG_TIMEOUT_CYCLES4K +#endif + +// CTUNE LXFO manufacturing +// Enable to use CTUNE LFXO manufacturing value for calibration +// 1 +#ifndef SL_CLOCK_MANAGER_CTUNE_MFG_LFXO_EN +#define SL_CLOCK_MANAGER_CTUNE_MFG_LFXO_EN 1 +#endif +// + +// HFRCO and DPLL Settings +// Frequency Band +// RC Oscillator Frequency Band +// 1 MHz +// 2 MHz +// 4 MHz +// 7 MHz +// 13 MHz +// 16 MHz +// 19 MHz +// 26 MHz +// 32 MHz +// 38 MHz +// 48 MHz +// 56 MHz +// 64 MHz +// 80 MHz +// cmuHFRCODPLLFreq_80M0Hz +#ifndef SL_CLOCK_MANAGER_HFRCO_BAND +#define SL_CLOCK_MANAGER_HFRCO_BAND cmuHFRCODPLLFreq_80M0Hz +#endif + +// Use DPLL +// Enable to use the DPLL with HFRCO +#ifndef SL_CLOCK_MANAGER_HFRCO_DPLL_EN +#define SL_CLOCK_MANAGER_HFRCO_DPLL_EN 0 +#endif + +// Target Frequency in Hz <1000000-80000000> +// DPLL target frequency +// 78000000 +#ifndef SL_CLOCK_MANAGER_DPLL_FREQ +#define SL_CLOCK_MANAGER_DPLL_FREQ 78000000 +#endif + +// Numerator (N) <300-4095> +// Value of N for output frequency calculation fout = fref * (N+1) / (M+1) +// 3839 +#ifndef SL_CLOCK_MANAGER_DPLL_N +#define SL_CLOCK_MANAGER_DPLL_N 3839 +#endif + +// Denominator (M) <0-4095> +// Value of M for output frequency calculation fout = fref * (N+1) / (M+1) +// 1919 +#ifndef SL_CLOCK_MANAGER_DPLL_M +#define SL_CLOCK_MANAGER_DPLL_M 1919 +#endif + +// Reference Clock +// Reference clock source for DPLL +// DISABLED +// HFXO +// LFXO +// CLKIN0 +// CMU_DPLLREFCLKCTRL_CLKSEL_HFXO +#ifndef SL_CLOCK_MANAGER_DPLL_REFCLK +#define SL_CLOCK_MANAGER_DPLL_REFCLK CMU_DPLLREFCLKCTRL_CLKSEL_HFXO +#endif + +// Reference Clock Edge Detect +// Edge detection for reference clock +// Falling Edge +// Rising Edge +// cmuDPLLEdgeSel_Fall +#ifndef SL_CLOCK_MANAGER_DPLL_EDGE +#define SL_CLOCK_MANAGER_DPLL_EDGE cmuDPLLEdgeSel_Fall +#endif + +// DPLL Lock Mode +// Lock mode +// Frequency-Lock Loop +// Phase-Lock Loop +// cmuDPLLLockMode_Freq +#ifndef SL_CLOCK_MANAGER_DPLL_LOCKMODE +#define SL_CLOCK_MANAGER_DPLL_LOCKMODE cmuDPLLLockMode_Phase +#endif + +// Automatic Lock Recovery +// 1 +#ifndef SL_CLOCK_MANAGER_DPLL_AUTORECOVER +#define SL_CLOCK_MANAGER_DPLL_AUTORECOVER 1 +#endif + +// Enable Dither +// 0 +#ifndef SL_CLOCK_MANAGER_DPLL_DITHER +#define SL_CLOCK_MANAGER_DPLL_DITHER 0 +#endif +// +// + +// HFRCOEM23 Settings +// Frequency Band +// RC Oscillator Frequency Band +// 1 MHz +// 2 MHz +// 4 MHz +// 5 MHz +// 10 MHz +// 13 MHz +// 16 MHz +// 19 MHz +// 20 MHz +// 26 MHz +// 32 MHz +// 40 MHz +// cmuHFRCOEM23Freq_19M0Hz +#ifndef SL_CLOCK_MANAGER_HFRCOEM23_BAND +#define SL_CLOCK_MANAGER_HFRCOEM23_BAND cmuHFRCOEM23Freq_19M0Hz +#endif +// + +// LFRCO Settings +// Precision Mode +// Precision mode uses hardware to automatically re-calibrate the LFRCO +// against a crystal driven by the HFXO. Hardware detects temperature +// changes and initiates a re-calibration of the LFRCO as needed when +// operating in EM0, EM1, or EM2. If a re-calibration is necessary and the +// HFXO is not active, the precision mode hardware will automatically +// enable HFXO for a short time to perform the calibration. EM4 operation is +// not allowed while precision mode is enabled. +// If high precision is selected on devices that do not support it, default +// precision will be used. +// Default precision +// High precision +// cmuPrecisionDefault +#ifndef SL_CLOCK_MANAGER_LFRCO_PRECISION +#define SL_CLOCK_MANAGER_LFRCO_PRECISION cmuPrecisionDefault +#endif +// + +// CLKIN0 Settings +// Frequency in Hz <1000000-38000000> +// 38000000 +#ifndef SL_CLOCK_MANAGER_CLKIN0_FREQ +#define SL_CLOCK_MANAGER_CLKIN0_FREQ 38000000 +#endif +// + +// + +// <<< end of configuration section >>> + +// <<< sl:start pin_tool >>> + +// SL_CLOCK_MANAGER_CLKIN0 +// $[CMU_SL_CLOCK_MANAGER_CLKIN0] + + +// [CMU_SL_CLOCK_MANAGER_CLKIN0]$ + +// <<< sl:end pin_tool >>> + +#endif /* SL_CLOCK_MANAGER_OSCILLATOR_CONFIG_H */ diff --git a/crates/ziggurat-rail-sys/vendor/config/sl_clock_manager_tree_config.h b/crates/ziggurat-rail-sys/vendor/config/sl_clock_manager_tree_config.h new file mode 100644 index 0000000..4e44f82 --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/config/sl_clock_manager_tree_config.h @@ -0,0 +1,311 @@ +/***************************************************************************//** + * @file + * @brief Clock Manager - Clock Tree configuration file. + ******************************************************************************* + * # License + * Copyright 2026 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Zlib + * + * The licensor of this software is Silicon Laboratories Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + ******************************************************************************/ + +#ifndef SL_CLOCK_MANAGER_TREE_CONFIG_H +#define SL_CLOCK_MANAGER_TREE_CONFIG_H + +#if defined(SL_COMPONENT_CATALOG_PRESENT) +#include "sl_component_catalog.h" + +#endif + +// Internal Defines: DO NOT MODIFY +// Those defines are used internally to help converting the DEFAULT_HF_CLOCK_SOURCE and DEFAULT_LF_CLOCK_SOURCE +// selection of each clock branch to the right HW register value. +#define SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE_HFRCODPLL 0xFF +#define SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE_HFXO 0xFE +#define SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE_FSRCO 0xFD +#define SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE_LFRCO 0xFC +#define SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE_LFXO 0xFB +#define SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE_ULFRCO 0xFA +#define SL_CLOCK_MANAGER_DEFAULT_EUSART0_LF_CLOCK_SOURCE SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE + +#if defined(SL_CATALOG_RAIL_LIB_PRESENT) +#define SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE_AUTO SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE_HFXO +#else +#define SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE_AUTO SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE_HFRCODPLL +#endif + +// <<< Use Configuration Wizard in Context Menu >>> + +// Clock Tree Settings + +// Default Clock Source Selection for HF clock branches +// AUTO +// HFRCODPLL +// HFXO +// FSRCO +// Selection of the high frequency clock source. HF clock branches can select this value by chosing the DEFAULT_HF value. +// AUTO uses HFXO if a radio is used and HFRCODPLL otherwise +// SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE_AUTO +#ifndef SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE +#define SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE_HFXO +#endif + +// Default Clock Source Selection for LF clock branches +// LFRCO +// LFXO +// ULFRCO +// Selection of the low frequency clock source. LF clock branches can select this value by chosing the DEFAULT_HF value. +// SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE_LFRCO +#ifndef SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE +#define SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE_LFXO +#endif + +// System Clock Branch Settings + +// Clock Source Selection for SYSCLK branch +// DEFAULT_HF +// FSRCO +// HFRCODPLL +// HFXO +// CLKIN0 +// Selection of the Clock source for SYSCLK +// SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE +#ifndef SL_CLOCK_MANAGER_SYSCLK_SOURCE +#define SL_CLOCK_MANAGER_SYSCLK_SOURCE SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE +#endif + +// HCLK branch divider +// DIV1 +// DIV2 +// DIV4 +// DIV8 +// DIV16 +// HCLK branch is derived from SYSCLK. This clock drives the AHB bus interface. +// CMU_SYSCLKCTRL_HCLKPRESC_DIV1 +#ifndef SL_CLOCK_MANAGER_HCLK_DIVIDER +#define SL_CLOCK_MANAGER_HCLK_DIVIDER CMU_SYSCLKCTRL_HCLKPRESC_DIV1 +#endif + +// PCLK branch divider +// DIV1 +// DIV2 +// MIN +// PCLK branch is derived from HCLK. This clock drives the APB bus interface. +// SL_CLOCK_MANAGER_PCLK_DIV_MIN +#ifndef SL_CLOCK_MANAGER_PCLK_DIVIDER +#define SL_CLOCK_MANAGER_PCLK_DIVIDER SL_CLOCK_MANAGER_PCLK_DIV_MIN +#endif + +// + +// Trace Clock Branches Settings +// Clock Source Selection for TRACECLK branch +// DISABLE +// SYSCLK +// HFRCOEM23 +// HFRCODPLLRT +// Selection of the Clock source for TRACECLK +// CMU_TRACECLKCTRL_CLKSEL_SYSCLK +#ifndef SL_CLOCK_MANAGER_TRACECLK_SOURCE +#define SL_CLOCK_MANAGER_TRACECLK_SOURCE CMU_TRACECLKCTRL_CLKSEL_SYSCLK +#endif + +// TRACECLK branch Divider +// DIV1 +// DIV2 +// DIV3 +// DIV4 +// Selection of the divider value for TRACECLK branch +// CMU_TRACECLKCTRL_PRESC_DIV1 +#ifndef SL_CLOCK_MANAGER_TRACECLK_DIVIDER +#define SL_CLOCK_MANAGER_TRACECLK_DIVIDER CMU_TRACECLKCTRL_PRESC_DIV1 +#endif + +// + +// High Frequency Clock Branches Settings +// Each HF Clock Tree branch can be customized, else the same clock source as for SYSCLK will be used when possible +// EM01GRPACLK clock the Timer peripherals +// Clock Source Selection for EM01GRPACLK branch +// DEFAULT_HF +// HFRCODPLL +// HFXO +// FSRCO +// HFRCOEM23 +// HFRCODPLLRT +// HFXORT +// Selection of the Clock source for EM01GRPACLK +// SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE +#ifndef SL_CLOCK_MANAGER_EM01GRPACLK_SOURCE +#define SL_CLOCK_MANAGER_EM01GRPACLK_SOURCE SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE +#endif + +// Clock Source Selection for EM01GRPCCLK branch +// DEFAULT_HF +// HFRCODPLL +// HFXO +// FSRCO +// HFRCOEM23 +// HFRCODPLLRT +// HFXORT +// Selection of the Clock source for EM01GRPCCLK +// SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE +#ifndef SL_CLOCK_MANAGER_EM01GRPCCLK_SOURCE +#define SL_CLOCK_MANAGER_EM01GRPCCLK_SOURCE SL_CLOCK_MANAGER_DEFAULT_HF_CLOCK_SOURCE +#endif + +// Clock Source Selection for IADCCLK branch +// EM01GRPACLK +// FSRCO +// HFRCOEM23 +// Selection of the Clock source for IADCCLK +// CMU_IADCCLKCTRL_CLKSEL_EM01GRPACLK +#ifndef SL_CLOCK_MANAGER_IADCCLK_SOURCE +#define SL_CLOCK_MANAGER_IADCCLK_SOURCE CMU_IADCCLKCTRL_CLKSEL_EM01GRPACLK +#endif + +// + +// Low Frequency Clock Branches Settings + +// Clock Source Selection for EM23GRPACLK branch +// DEFAULT_LF +// LFRCO +// LFXO +// ULFRCO +// Selection of the Clock source for EM23GRPACLK +// SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE +#ifndef SL_CLOCK_MANAGER_EM23GRPACLK_SOURCE +#define SL_CLOCK_MANAGER_EM23GRPACLK_SOURCE SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE +#endif + +// Clock Source Selection for EM4GRPACLK branch +// DEFAULT_LF +// LFRCO +// LFXO +// ULFRCO +// Selection of the Clock source for EM4GRPACLK +// SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE +#ifndef SL_CLOCK_MANAGER_EM4GRPACLK_SOURCE +#define SL_CLOCK_MANAGER_EM4GRPACLK_SOURCE SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE +#endif + +// Clock Source Selection for SYSRTCCLK branch +// DEFAULT_LF +// LFRCO +// LFXO +// ULFRCO +// Selection of the Clock source for SYSRTCCLK +// SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE +#ifndef SL_CLOCK_MANAGER_SYSRTCCLK_SOURCE +#define SL_CLOCK_MANAGER_SYSRTCCLK_SOURCE SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE +#endif + +// Clock Source Selection for WDOG0CLK branch +// DEFAULT_LF +// LFRCO +// LFXO +// ULFRCO +// HCLKDIV1024 +// Selection of the Clock source for WDOG0CLK +// SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE +#ifndef SL_CLOCK_MANAGER_WDOG0CLK_SOURCE +#define SL_CLOCK_MANAGER_WDOG0CLK_SOURCE SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE +#endif + +// Clock Source Selection for WDOG1CLK branch +// DEFAULT_LF +// LFRCO +// LFXO +// ULFRCO +// HCLKDIV1024 +// Selection of the Clock source for WDOG1CLK +// SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE +#ifndef SL_CLOCK_MANAGER_WDOG1CLK_SOURCE +#define SL_CLOCK_MANAGER_WDOG1CLK_SOURCE SL_CLOCK_MANAGER_DEFAULT_LF_CLOCK_SOURCE +#endif + +// Clock Source Selection for PCNT0CLK branch +// DISABLED +// EM23GRPACLK +// PCNTS0 +// Selection of the Clock source for PCNT0CLK +// CMU_PCNT0CLKCTRL_CLKSEL_EM23GRPACLK +#ifndef SL_CLOCK_MANAGER_PCNT0CLK_SOURCE +#define SL_CLOCK_MANAGER_PCNT0CLK_SOURCE CMU_PCNT0CLKCTRL_CLKSEL_EM23GRPACLK +#endif + +// + +// Mixed Frequency Clock Branch Settings +// Clock Source Selection for EUSART0CLK branch +// LF_DEFAULT +// DISABLED +// EM01GRPCCLK +// HFRCOEM23 +// LFRCO +// LFXO +// Selection of the Clock source for EUSART0CLK +// CMU_EUSART0CLKCTRL_CLKSEL_EM01GRPCCLK +#ifndef SL_CLOCK_MANAGER_EUSART0CLK_SOURCE +#define SL_CLOCK_MANAGER_EUSART0CLK_SOURCE CMU_EUSART0CLKCTRL_CLKSEL_EM01GRPCCLK +#endif + +// Clock Source Selection for SYSTICKCLK branch +// <0=> HCLK +// <1=> EM23GRPACLK +// Selection of the Clock source for SYSTICKCLK +// 0 +#ifndef SL_CLOCK_MANAGER_SYSTICKCLK_SOURCE +#define SL_CLOCK_MANAGER_SYSTICKCLK_SOURCE 0 +#endif + +// Clock Source Selection for VDAC0CLK branch +// DISABLED +// EM01GRPACLK +// EM23GRPACLK +// FSRCO +// HFRCOEM23 +// Selection of the Clock source for VDAC0CLK +// CMU_VDAC0CLKCTRL_CLKSEL_EM01GRPACLK +#ifndef SL_CLOCK_MANAGER_VDAC0CLK_SOURCE +#define SL_CLOCK_MANAGER_VDAC0CLK_SOURCE CMU_VDAC0CLKCTRL_CLKSEL_EM01GRPACLK +#endif + +// Clock Source Selection for VDAC1CLK branch +// DISABLED +// EM01GRPACLK +// EM23GRPACLK +// FSRCO +// HFRCOEM23 +// Selection of the Clock source for VDAC1CLK +// CMU_VDAC1CLKCTRL_CLKSEL_EM01GRPACLK +#ifndef SL_CLOCK_MANAGER_VDAC1CLK_SOURCE +#define SL_CLOCK_MANAGER_VDAC1CLK_SOURCE CMU_VDAC1CLKCTRL_CLKSEL_EM01GRPACLK +#endif + +// +// + +#endif /* SL_CLOCK_MANAGER_TREE_CONFIG_H */ + +// <<< end of configuration section >>> diff --git a/crates/ziggurat-rail-sys/vendor/config/sl_core_config.h b/crates/ziggurat-rail-sys/vendor/config/sl_core_config.h new file mode 100644 index 0000000..16d372f --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/config/sl_core_config.h @@ -0,0 +1,45 @@ +/***************************************************************************//** + * @file + * @brief sl_core Configuration + ******************************************************************************* + * # License + * Copyright 2023 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Zlib + * + * The licensor of this software is Silicon Laboratories Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + ******************************************************************************/ + +#ifndef SL_CORE_CONFIG_H +#define SL_CORE_CONFIG_H + +// <<< Use Configuration Wizard in Context Menu >>> + +// Core Abstraction Configuration + +// Enables measurement of interrupt masking time for debugging purposes. +// Default: 0 +#define SL_CORE_DEBUG_INTERRUPTS_MASKED_TIMING 0 +// + +// <<< end of configuration section >>> +#endif // SL_CORE_CONFIG_H + diff --git a/crates/ziggurat-rail-sys/vendor/config/sl_device_init_dcdc_config.h b/crates/ziggurat-rail-sys/vendor/config/sl_device_init_dcdc_config.h new file mode 100644 index 0000000..9207f13 --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/config/sl_device_init_dcdc_config.h @@ -0,0 +1,59 @@ +/***************************************************************************//** + * @file + * @brief DEVICE_INIT_DCDC Config + ******************************************************************************* + * # License + * Copyright 2022 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Zlib + * + * The licensor of this software is Silicon Laboratories Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + ******************************************************************************/ + +#ifndef SL_DEVICE_INIT_DCDC_CONFIG_H +#define SL_DEVICE_INIT_DCDC_CONFIG_H + +// <<< Use Configuration Wizard in Context Menu >>> + +// Enable DC/DC Converter +// +// Default: 1 +#define SL_DEVICE_INIT_DCDC_ENABLE 1 + +// Set DC/DC Converter in Bypass Mode +// +// Default: 0 +#define SL_DEVICE_INIT_DCDC_BYPASS 0 + +// Override for DCDC PFMX Mode Peak Current Setting +// +// Default: 1 +#define SL_DEVICE_INIT_DCDC_PFMX_IPKVAL_OVERRIDE 1 + +// DCDC PFMX Mode Peak Current Setting <0-15> +// +// Default: DCDC_PFMXCTRL_IPKVAL_DEFAULT +#define SL_DEVICE_INIT_DCDC_PFMX_IPKVAL 9 + +// <<< end of configuration section >>> + +#endif // SL_DEVICE_INIT_DCDC_CONFIG_H + diff --git a/crates/ziggurat-rail-sys/vendor/config/sl_device_init_emu_config.h b/crates/ziggurat-rail-sys/vendor/config/sl_device_init_emu_config.h new file mode 100644 index 0000000..15bad31 --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/config/sl_device_init_emu_config.h @@ -0,0 +1,54 @@ +/***************************************************************************//** + * @file + * @brief DEVICE_INIT_EMU Config + ******************************************************************************* + * # License + * Copyright 2019 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Zlib + * + * The licensor of this software is Silicon Laboratories Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + ******************************************************************************/ + +#ifndef SL_DEVICE_INIT_EMU_CONFIG_H +#define SL_DEVICE_INIT_EMU_CONFIG_H + +#include "em_emu.h" + +// <<< Use Configuration Wizard in Context Menu >>> + +// Allow debugger to remain connected in EM2 +// Force PD0B to stay on on EM2 entry. This allows the debugger to remain connected in EM2 and EM3. +// Enabling debug connectivity results in an increased power consumption in EM2/EM3. +// Default: 1 +#define SL_DEVICE_INIT_EMU_EM2_DEBUG_ENABLE 1 + +// EM4 pin retention mode +// No Retention: Pads enter reset state when entering EM4. +// Retention through EM4: Pads enter reset state when exiting EM4. +// Retention through EM4 and wakeup. +// Default: emuPinRetentionDisable +#define SL_DEVICE_INIT_EMU_EM4_PIN_RETENTION_MODE emuPinRetentionDisable + +// <<< end of configuration section >>> + +#endif // SL_DEVICE_INIT_EMU_CONFIG_H + diff --git a/crates/ziggurat-rail-sys/vendor/config/sl_memory_manager_region_config.h b/crates/ziggurat-rail-sys/vendor/config/sl_memory_manager_region_config.h new file mode 100644 index 0000000..47c4699 --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/config/sl_memory_manager_region_config.h @@ -0,0 +1,52 @@ +/***************************************************************************//** + * @file + * @brief Memory Heap and stack size configuration file. + ******************************************************************************* + * # License + * Copyright 2024 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Zlib + * + * The licensor of this software is Silicon Laboratories Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + ******************************************************************************/ + +// <<< Use Configuration Wizard in Context Menu >>> + +#ifndef SL_MEMORY_MANAGER_REGION_CONFIG_H +#define SL_MEMORY_MANAGER_REGION_CONFIG_H + +#include "sl_component_catalog.h" + +// Memory configuration + +// Stack size for the application. +// Default: 4096 +// The stack size configured here will be used by the stack that the +// application uses when coming out of a reset. +#ifndef SL_STACK_SIZE +#define SL_STACK_SIZE 4096 +#endif +// + +// <<< end of configuration section >>> + +#endif /* SL_MEMORY_MANAGER_REGION_CONFIG_H */ + diff --git a/crates/ziggurat-rail-sys/vendor/config/sl_rail_util_callbacks_config.h b/crates/ziggurat-rail-sys/vendor/config/sl_rail_util_callbacks_config.h new file mode 100644 index 0000000..e1f0253 --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/config/sl_rail_util_callbacks_config.h @@ -0,0 +1,45 @@ +/***************************************************************************//** + * @file + * @brief RAIL callbacks configuration header file. + ******************************************************************************* + * # License + * Copyright 2021 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Zlib + * + * The licensor of this software is Silicon Laboratories Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + ******************************************************************************/ + +#ifndef SL_RAIL_UTIL_CALLBACKS_CONFIG_H +#define SL_RAIL_UTIL_CALLBACKS_CONFIG_H + +// <<< Use Configuration Wizard in Context Menu >>> + +// RAIL Callbacks Configuration + +// Override weak internal RAIL callback RAILCb_AssertFailed() +// Default: 1 +#define SL_RAIL_UTIL_CALLBACKS_ASSERT_FAILED_OVERRIDE 1 + +// +// <<< end of configuration section >>> +#endif // SL_RAIL_UTIL_CALLBACKS_CONFIG_H + diff --git a/crates/ziggurat-rail-sys/vendor/config/sl_rail_util_init_inst0_config.h b/crates/ziggurat-rail-sys/vendor/config/sl_rail_util_init_inst0_config.h new file mode 100644 index 0000000..9399379 --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/config/sl_rail_util_init_inst0_config.h @@ -0,0 +1,334 @@ +/***************************************************************************//** + * @file + * @brief + ******************************************************************************* + * # License + * Copyright 2020 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Zlib + * + * The licensor of this software is Silicon Laboratories Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + ******************************************************************************/ + +#ifndef SL_RAIL_UTIL_INIT_INST0_CONFIG_H +#define SL_RAIL_UTIL_INIT_INST0_CONFIG_H + +// <<< Use Configuration Wizard in Context Menu >>> + +// RAIL Init Configuration +// Initialize RAIL +// Default: 1 +#define SL_RAIL_UTIL_INIT_INST0_ENABLE 1 + +// Project Configuration +// Enable Radio Configurator Support (include rail_config.c/h generated by Radio Config) +// Default: 0 +#define SL_RAIL_UTIL_INIT_RADIO_CONFIG_SUPPORT_INST0_ENABLE 0 +// Enable RAIL Init Complete Callback +// Default: 0 +#define SL_RAIL_UTIL_INIT_INIT_COMPLETE_CALLBACK_INST0_ENABLE 0 +// + +// Protocol Configuration +// Default: 0 +#define SL_RAIL_UTIL_INIT_PROTOCOLS_INST0_ENABLE 0 +// Radio Configuration +// Default Radio Configuration +// Proprietary (use rail_config.c/h) +// Bluetooth LE 1Mbps +// Bluetooth LE 2Mbps +// Bluetooth LE Coded 125Kbps +// Bluetooth LE Coded 500Kbps +// Bluetooth Quuppa 1Mbps +// IEEE 802.15.4 2.4GHz +// IEEE 802.15.4 2.4GHz, antenna diversity +// IEEE 802.15.4 2.4GHz, coexistence +// IEEE 802.15.4 2.4GHz, antenna diversity, coexistence +// Default: SL_RAIL_UTIL_PROTOCOL_BLE_1MBPS +#define SL_RAIL_UTIL_INIT_PROTOCOL_INST0_DEFAULT SL_RAIL_UTIL_PROTOCOL_BLE_1MBPS +// Proprietary Radio Config Index (if Proprietary radio config selected, use index X of channelConfigs[X]) +// <0-255:1> +// Default: 0 +#define SL_RAIL_UTIL_INIT_PROTOCOL_PROPRIETARY_INST0_INDEX 0 +// +// + +// Calibration Configuration +// Default: 0 +#define SL_RAIL_UTIL_INIT_CALIBRATIONS_INST0_ENABLE 0 +// Calibration Notifications +// Enable Temperature Calibration Notifications (RAIL_EVENT_CAL_NEEDED radio event issued when temperature calibrations needed, for example VCO calibration) +// Default: 0 +#define SL_RAIL_UTIL_INIT_CALIBRATION_TEMPERATURE_NOTIFY_INST0_ENABLE 0 +// Enable One-time Calibration Notifications (RAIL_EVENT_CAL_NEEDED radio event issued when one-time calibrations needed, for example IR calibration) +// Default: 0 +#define SL_RAIL_UTIL_INIT_CALIBRATION_ONETIME_NOTIFY_INST0_ENABLE 0 +// +// + +// Auto Transition Configuration +// Default: 0 +#define SL_RAIL_UTIL_INIT_TRANSITIONS_INST0_ENABLE 0 +// TX Transitions +// Transition on TX Success +// RX +// Idle +// Default: RAIL_RF_STATE_IDLE +#define SL_RAIL_UTIL_INIT_TRANSITION_INST0_TX_SUCCESS RAIL_RF_STATE_IDLE +// Transition on TX Error +// RX +// Idle +// Default: RAIL_RF_STATE_IDLE +#define SL_RAIL_UTIL_INIT_TRANSITION_INST0_TX_ERROR RAIL_RF_STATE_IDLE +// +// RX Transitions +// Transition on RX Success +// RX +// TX +// Idle +// Default: RAIL_RF_STATE_IDLE +#define SL_RAIL_UTIL_INIT_TRANSITION_INST0_RX_SUCCESS RAIL_RF_STATE_IDLE +// Transition on RX Error +// RX +// Idle +// Default: RAIL_RF_STATE_IDLE +#define SL_RAIL_UTIL_INIT_TRANSITION_INST0_RX_ERROR RAIL_RF_STATE_IDLE +// +// + +// Data Format Configuration +// Default: 0 +#define SL_RAIL_UTIL_INIT_DATA_FORMATS_INST0_ENABLE 0 +// TX Data +// Source of TX Data +// Use frame hardware to packetize data +// Default: TX_PACKET_DATA +#define SL_RAIL_UTIL_INIT_DATA_FORMAT_INST0_TX_SOURCE TX_PACKET_DATA +// Method of Providing TX Data +// Packet Mode +// FIFO Mode +// Default: PACKET_MODE +#define SL_RAIL_UTIL_INIT_DATA_FORMAT_INST0_TX_MODE PACKET_MODE +// +// RX Data +// Source of RX Data +// Use frame hardware to packetize data +// Get 8-bit output from demodulator +// Get lowest 16 bits of I/Q data provided to demodulator +// Get highest 16 bits of I/Q data provided to demodulator +// Default: RX_PACKET_DATA +#define SL_RAIL_UTIL_INIT_DATA_FORMAT_INST0_RX_SOURCE RX_PACKET_DATA +// Method of Retrieving RX Data +// Packet Mode +// FIFO Mode +// Default: PACKET_MODE +#define SL_RAIL_UTIL_INIT_DATA_FORMAT_INST0_RX_MODE PACKET_MODE +// +// + +// Radio Event Configuration +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENTS_INST0_ENABLE 0 +// RX Radio Events +// RX Timing Detect +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_RX_TIMING_DETECT_INST0_ENABLE 0 +// RX Timing Lost +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_RX_TIMING_LOST_INST0_ENABLE 0 +// RX Preamble Detect +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_RX_PREAMBLE_DETECT_INST0_ENABLE 0 +// RX Preamble Lost +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_RX_PREAMBLE_LOST_INST0_ENABLE 0 +// RX Sync1 Detect +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_RX_SYNC1_DETECT_INST0_ENABLE 0 +// RX Sync2 Detect +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_RX_SYNC2_DETECT_INST0_ENABLE 0 +// RX Filter Passed +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_RX_FILTER_PASSED_INST0_ENABLE 0 +// RX Address Filtered +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_RX_ADDRESS_FILTERED_INST0_ENABLE 0 +// RX Packet Received +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_RX_PACKET_RECEIVED_INST0_ENABLE 0 +// RX Frame Error +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_RX_FRAME_ERROR_INST0_ENABLE 0 +// RX Packet Aborted +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_RX_PACKET_ABORTED_INST0_ENABLE 0 +// RX Timeout +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_RX_TIMEOUT_INST0_ENABLE 0 +// RX Channel Hopping Complete +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_RX_CHANNEL_HOPPING_COMPLETE_INST0_ENABLE 0 +// RX Duty Cycle RX End +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_RX_DUTY_CYCLE_RX_END_INST0_ENABLE 0 +// +// TX Radio Events +// TX Packet Sent +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_TX_PACKET_SENT_INST0_ENABLE 0 +// TX Aborted +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_TX_ABORTED_INST0_ENABLE 0 +// TX Blocked +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_TX_BLOCKED_INST0_ENABLE 0 +// TX Started +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_TX_STARTED_INST0_ENABLE 0 +// +// RSSI Radio Events +// RSSI Average Done +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_RSSI_AVERAGE_DONE_INST0_ENABLE 0 +// +// FIFO Radio Events +// RX FIFO, Almost Full +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_RX_FIFO_ALMOST_FULL_INST0_ENABLE 0 +// RX FIFO, Full +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_RX_FIFO_FULL_INST0_ENABLE 0 +// RX FIFO, Overflow +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_RX_FIFO_OVERFLOW_INST0_ENABLE 0 +// TX FIFO, Almost Empty +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_TX_FIFO_ALMOST_EMPTY_INST0_ENABLE 0 +// TX FIFO, Underflow +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_TX_UNDERFLOW_INST0_ENABLE 0 +// +// CCA Radio Events +// TX CCA, Channel Clear +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_TX_CHANNEL_CLEAR_INST0_ENABLE 0 +// TX CCA, Channel Busy +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_TX_CHANNEL_BUSY_INST0_ENABLE 0 +// TX CCA, Retry +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_TX_CCA_RETRY_INST0_ENABLE 0 +// TX CCA, Started +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_TX_START_CCA_INST0_ENABLE 0 +// TX CCA, Activated +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_TX_CCA_ACTIVATED_INST0_ENABLE 0 +// +// Scheduled Radio Events +// Scheduled RX/TX Started +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_RX_TX_SCHEDULED_RX_TX_STARTED_INST0_ENABLE 0 +// Scheduled RX End +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_RX_SCHEDULED_RX_END_INST0_ENABLE 0 +// Scheduled RX Missed +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_RX_SCHEDULED_RX_MISSED_INST0_ENABLE 0 +// Scheduled TX Missed +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_TX_SCHEDULED_TX_MISSED_INST0_ENABLE 0 +// +// ACK Radio Events +// RX ACK, Timeout +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_RX_ACK_TIMEOUT_INST0_ENABLE 0 +// TX ACK, Packet Sent +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_TXACK_PACKET_SENT_INST0_ENABLE 0 +// TX ACK, Aborted +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_TXACK_ABORTED_INST0_ENABLE 0 +// TX ACK, Blocked +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_TXACK_BLOCKED_INST0_ENABLE 0 +// TX ACK, FIFO Underflow +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_TXACK_UNDERFLOW_INST0_ENABLE 0 +// +// Protocol Radio Events +// IEEE 802.15.4 Data Request Command +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_IEEE802154_DATA_REQUEST_COMMAND_INST0_ENABLE 0 +// Z-Wave Beam +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_ZWAVE_BEAM_INST0_ENABLE 0 +// Z-Wave LR ACK Request Command +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_ZWAVE_LR_ACK_REQUEST_COMMAND_INST0_ENABLE 0 +// +// Dynamic Multiprotocol (DMP) Radio Events +// Config Unscheduled +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_CONFIG_UNSCHEDULED_INST0_ENABLE 0 +// Config Scheduled +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_CONFIG_SCHEDULED_INST0_ENABLE 0 +// Scheduler Status +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_SCHEDULER_STATUS_INST0_ENABLE 0 +// +// Calibration Radio Events +// Calibration Needed +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_CAL_NEEDED_INST0_ENABLE 0 +// +// RSSI Radio Events +// RSSI detect threshold +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_DETECT_RSSI_THRESHOLD_INST0_ENABLE 0 +// +// Thermistor Events +// End of thermistor measurement +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_THERMISTOR_DONE_INST0_ENABLE 0 +// +// Temperature Events +// Transmit blocked because of temperature limitation +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_TX_BLOCKED_TOO_HOT_INST0_ENABLE 0 +// Temperature is too hot for Tx operation +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_TEMPERATURE_TOO_HOT_INST0_ENABLE 0 +// Temperature has cooled enough for Tx operation +// Default: 0 +#define SL_RAIL_UTIL_INIT_EVENT_TEMPERATURE_COOL_DOWN_INST0_ENABLE 0 +// +// + +// +// + +// <<< end of configuration section >>> + +#endif // SL_RAIL_UTIL_INIT_INST0_CONFIG_H + diff --git a/crates/ziggurat-rail-sys/vendor/config/sl_rail_util_pa_config.h b/crates/ziggurat-rail-sys/vendor/config/sl_rail_util_pa_config.h new file mode 100644 index 0000000..63259c5 --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/config/sl_rail_util_pa_config.h @@ -0,0 +1,61 @@ +/***************************************************************************//** + * @file + * @brief Power Amplifier configuration file. + ******************************************************************************* + * # License + * Copyright 2025 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Zlib + * + * The licensor of this software is Silicon Laboratories Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + ******************************************************************************/ + +#ifndef SL_RAIL_UTIL_PA_CONFIG_H +#define SL_RAIL_UTIL_PA_CONFIG_H + +// <<< Use Configuration Wizard in Context Menu >>> + +// PA Configuration +// Initial PA Power (deci-dBm, 100 = 10.0 dBm) +// Default: 100 +#define SL_RAIL_UTIL_PA_POWER_DECI_DBM 100 + +// PA Ramp Time (microseconds) +// <0-65535:1> +// Default: 10 +#define SL_RAIL_UTIL_PA_RAMP_TIME_US 10 + +// Milli-volts on PA supply pin (PA_VDD) +// <0-65535:1> +// Default: 3300 +#define SL_RAIL_UTIL_PA_VOLTAGE_MV 3300 +// + +// PA Calibration Configuration +// Enable PA Calibration +// Default: 1 +#define SL_RAIL_UTIL_PA_CALIBRATION_ENABLE 1 +// + +// <<< end of configuration section >>> + +#endif // SL_RAIL_UTIL_PA_CONFIG_H + diff --git a/crates/ziggurat-rail-sys/vendor/config/sl_rail_util_protocol_config.h b/crates/ziggurat-rail-sys/vendor/config/sl_rail_util_protocol_config.h new file mode 100644 index 0000000..ebe423c --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/config/sl_rail_util_protocol_config.h @@ -0,0 +1,173 @@ +/***************************************************************************//** + * @file + * @brief + ******************************************************************************* + * # License + * Copyright 2020 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Zlib + * + * The licensor of this software is Silicon Laboratories Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + ******************************************************************************/ + +#ifndef SL_RAIL_UTIL_PROTOCOL_CONFIG_H +#define SL_RAIL_UTIL_PROTOCOL_CONFIG_H + +// <<< Use Configuration Wizard in Context Menu >>> + +// Bluetooth LE Settings +// BLE: Transition Times +// Enable/Disable BLE +// Default: 1 +#define SL_RAIL_UTIL_PROTOCOL_BLE_ENABLE 1 +// Transition time (microseconds) from idle to RX +// <0-65535:1> +// Default: 100 +#define SL_RAIL_UTIL_PROTOCOL_BLE_TIMING_IDLE_TO_RX_US 100 +// Transition time (microseconds) from TX to RX +// <0-65535:1> +// Default: 150 +#define SL_RAIL_UTIL_PROTOCOL_BLE_TIMING_TX_TO_RX_US 150 +// Transition time (microseconds) from idle to TX +// <0-65535:1> +// Default: 100 +#define SL_RAIL_UTIL_PROTOCOL_BLE_TIMING_IDLE_TO_TX_US 100 +// Transition time (microseconds) from RX to TX +// <0-65535:1> +// Default: 150 +#define SL_RAIL_UTIL_PROTOCOL_BLE_TIMING_RX_TO_TX_US 150 +// + +// BLE: RX Search Timeouts +// Enable RX Search timeout after Idle +// Default: 0 +#define SL_RAIL_UTIL_PROTOCOL_BLE_TIMING_RX_SEARCH_TIMEOUT_AFTER_IDLE_ENABLE 0 +// Max time (microseconds) radio will search for packet when coming from idle +// <1-65535:1> +// Default: 65535 +#define SL_RAIL_UTIL_PROTOCOL_BLE_TIMING_RX_SEARCH_TIMEOUT_AFTER_IDLE_US 65535 +// +// Enable RX Search timeout after TX +// Default: 0 +#define SL_RAIL_UTIL_PROTOCOL_BLE_TIMING_RX_SEARCH_TIMEOUT_AFTER_TX_ENABLE 0 +// Max time (microseconds) radio will search for packet when coming from TX +// <1-65535:1> +// Default: 65535 +#define SL_RAIL_UTIL_PROTOCOL_BLE_TIMING_RX_SEARCH_TIMEOUT_AFTER_TX_US 65535 +// +// +// + +// IEEE 802.15.4, 2.4 GHz Settings +// 2.4 GHz: Node Configuration +// Enable/Disable IEEE 802.15.4 2.4 GHz Protocol +// Default: 1 +#define SL_RAIL_UTIL_PROTOCOL_IEEE802154_2P4GHZ_ENABLE 1 +// PAN Coordinator +// Default: 0 +#define SL_RAIL_UTIL_PROTOCOL_IEEE802154_2P4GHZ_PAN_COORDINATOR_ENABLE 0 +// Promiscuous Mode +// Default: 1 +#define SL_RAIL_UTIL_PROTOCOL_IEEE802154_2P4GHZ_PROMISCUOUS_MODE_ENABLE 1 +// Default Frame Pending bit value for outgoing ACKs in response to Data Request Command +// Default: 0 +#define SL_RAIL_UTIL_PROTOCOL_IEEE802154_2P4GHZ_DEFAULT_FRAME_PENDING_STATE 0 +// + +// 2.4 GHz: Receivable Frame Types +// Beacon Frames +// Default: 1 +#define SL_RAIL_UTIL_PROTOCOL_IEEE802154_2P4GHZ_ACCEPT_BEACON_FRAME_ENABLE 1 +// Data Frames +// Default: 1 +#define SL_RAIL_UTIL_PROTOCOL_IEEE802154_2P4GHZ_ACCEPT_DATA_FRAME_ENABLE 1 +// ACK Frames +// Default: 0 +#define SL_RAIL_UTIL_PROTOCOL_IEEE802154_2P4GHZ_ACCEPT_ACK_FRAME_ENABLE 0 +// Command Frames +// Default: 1 +#define SL_RAIL_UTIL_PROTOCOL_IEEE802154_2P4GHZ_ACCEPT_COMMAND_FRAME_ENABLE 1 +// + +// 2.4 GHz: Transition Times +// Transition time (microseconds) from idle to RX +// <0-65535:1> +// Default: 100 +#define SL_RAIL_UTIL_PROTOCOL_IEEE802154_2P4GHZ_TIMING_IDLE_TO_RX_US 100 +// Transition time (microseconds) from TX to RX +// <0-65535:1> +// Default: 182 +#define SL_RAIL_UTIL_PROTOCOL_IEEE802154_2P4GHZ_TIMING_TX_TO_RX_US 182 +// Transition time (microseconds) from idle to TX +// <0-65535:1> +// Default: 100 +#define SL_RAIL_UTIL_PROTOCOL_IEEE802154_2P4GHZ_TIMING_IDLE_TO_TX_US 100 +// Transition time (microseconds) from RX to TX +// <0-65535:1> +// Default: 192 +#define SL_RAIL_UTIL_PROTOCOL_IEEE802154_2P4GHZ_TIMING_RX_TO_TX_US 192 +// + +// 2.4 GHz: RX Search Timeouts +// Enable RX Search timeout after Idle +// Default: 0 +#define SL_RAIL_UTIL_PROTOCOL_IEEE802154_2P4GHZ_TIMING_RX_SEARCH_TIMEOUT_AFTER_IDLE_ENABLE 0 +// Max time (microseconds) radio will search for packet when coming from idle +// <1-65535:1> +// Default: 65535 +#define SL_RAIL_UTIL_PROTOCOL_IEEE802154_2P4GHZ_TIMING_RX_SEARCH_TIMEOUT_AFTER_IDLE_US 65535 +// +// Enable RX Search timeout after TX +// Default: 0 +#define SL_RAIL_UTIL_PROTOCOL_IEEE802154_2P4GHZ_TIMING_RX_SEARCH_TIMEOUT_AFTER_TX_ENABLE 0 +// Max time (microseconds) radio will search for packet when coming from TX +// <1-65535:1> +// Default: 65535 +#define SL_RAIL_UTIL_PROTOCOL_IEEE802154_2P4GHZ_TIMING_RX_SEARCH_TIMEOUT_AFTER_TX_US 65535 +// +// + +// 2.4 GHz: Auto ACK Configuration +// Enable Auto ACKs +// Default: 1 +#define SL_RAIL_UTIL_PROTOCOL_IEEE802154_2P4GHZ_AUTO_ACK_ENABLE 1 +// RX ACK timeout duration (microseconds) +// <1-65535:1> +// Default: 672 +#define SL_RAIL_UTIL_PROTOCOL_IEEE802154_2P4GHZ_AUTO_ACK_TIMEOUT_US 672 +// Radio state transition after attempting to receive ACK +// Idle +// RX +// Default: SL_RAIL_RF_STATE_RX +#define SL_RAIL_UTIL_PROTOCOL_IEEE802154_2P4GHZ_AUTO_ACK_RX_TRANSITION_STATE SL_RAIL_RF_STATE_RX +// Radio state transition after transmitting ACK +// Idle +// RX +// Default: SL_RAIL_RF_STATE_RX +#define SL_RAIL_UTIL_PROTOCOL_IEEE802154_2P4GHZ_AUTO_ACK_TX_TRANSITION_STATE SL_RAIL_RF_STATE_RX +// +// +// + +// <<< end of configuration section >>> + +#endif // SL_RAIL_UTIL_PROTOCOL_CONFIG_H + diff --git a/crates/ziggurat-rail-sys/vendor/config/sl_rail_util_pti_config.h b/crates/ziggurat-rail-sys/vendor/config/sl_rail_util_pti_config.h new file mode 100644 index 0000000..097e67b --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/config/sl_rail_util_pti_config.h @@ -0,0 +1,78 @@ +/***************************************************************************//** + * @file + * @brief Packet Trace Information configuration file. + ******************************************************************************* + * # License + * Copyright 2020 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Zlib + * + * The licensor of this software is Silicon Laboratories Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + ******************************************************************************/ + +#ifndef SL_RAIL_UTIL_PTI_CONFIG_H +#define SL_RAIL_UTIL_PTI_CONFIG_H + +// <<< Use Configuration Wizard in Context Menu >>> +// PTI Configuration + +// PTI mode +// UART +// UART onewire +// SPI +// Disabled +// Default: SL_RAIL_PTI_MODE_UART +#define SL_RAIL_UTIL_PTI_MODE SL_RAIL_PTI_MODE_DISABLED + +// PTI Baud Rate (Hertz) +// <147800-20000000:1> +// Default: 1600000 +#define SL_RAIL_UTIL_PTI_BAUD_RATE_HZ 1600000 + +// +// <<< end of configuration section >>> + +// <<< sl:start pin_tool >>> +// SL_RAIL_UTIL_PTI +// $[PTI_SL_RAIL_UTIL_PTI] +// #warning "RAIL PTI peripheral not configured" +#define SL_RAIL_UTIL_PTI_PERIPHERAL PTI + +// SL_RAIL_UTIL_PTI_DOUT_* needed for UART_ONEWIRE and UART and SPI modes +// #define SL_RAIL_UTIL_PTI_DOUT_PORT gpioPortB +// #define SL_RAIL_UTIL_PTI_DOUT_PIN 12 +// #define SL_RAIL_UTIL_PTI_DOUT_LOC 6 + +// SL_RAIL_UTIL_PTI_DFRAME_* needed for UART and SPI modes only +// #define SL_RAIL_UTIL_PTI_DFRAME_PORT gpioPortB +// #define SL_RAIL_UTIL_PTI_DFRAME_PIN 13 +// #define SL_RAIL_UTIL_PTI_DFRAME_LOC 6 + +// SL_RAIL_UTIL_PTI_DCLK_* needed for SPI mode only +// #define SL_RAIL_UTIL_PTI_DCLK_PORT gpioPortA +// #define SL_RAIL_UTIL_PTI_DCLK_PIN 0 +// #define SL_RAIL_UTIL_PTI_DCLK_LOC 0 +// [PTI_SL_RAIL_UTIL_PTI]$ + +// <<< sl:end pin_tool >>> + +#endif // SL_RAIL_UTIL_PTI_CONFIG_H + diff --git a/crates/ziggurat-rail-sys/vendor/config/sl_rail_util_sequencer_config.h b/crates/ziggurat-rail-sys/vendor/config/sl_rail_util_sequencer_config.h new file mode 100644 index 0000000..706e91c --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/config/sl_rail_util_sequencer_config.h @@ -0,0 +1,47 @@ +/***************************************************************************//** + * @file + * @brief + ******************************************************************************* + * # License + * Copyright 2023 Silicon Laboratories Inc. www.silabs.com + ******************************************************************************* + * + * SPDX-License-Identifier: Zlib + * + * The licensor of this software is Silicon Laboratories Inc. + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you must not + * claim that you wrote the original software. If you use this software + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original software. + * 3. This notice may not be removed or altered from any source distribution. + * + ******************************************************************************/ + +#ifndef SL_RAIL_UTIL_SEQUENCER_H +#define SL_RAIL_UTIL_SEQUENCER_H + +#ifdef __cplusplus +extern "C" { +#endif + +#define SL_RAIL_UTIL_SEQUENCER_RUNTIME_IMAGE_SELECTION 0 + +#define SL_RAIL_UTIL_SEQUENCER_IMAGE RAIL_SEQ_IMAGE_PA_20_DBM + +#ifdef __cplusplus +} +#endif + +#endif // SL_RAIL_UTIL_SEQUENCER_H + diff --git a/crates/ziggurat-rail-sys/vendor/sli_radioaes_stub.c b/crates/ziggurat-rail-sys/vendor/sli_radioaes_stub.c new file mode 100644 index 0000000..e1a2bd6 --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/sli_radioaes_stub.c @@ -0,0 +1,50 @@ +// Minimal single-user replacement for sli_radioaes_management (the SDK's full version +// pulls in PSA/mbedTLS + an OS abstraction, all gated on SLI_PSEC_THREADING which we don't +// define). sli_protocol_crypto_radioaes.c needs only these four hooks; it self-contains +// sli_radioaes_run_operation, sli_ccm_zigbee, sli_aes_crypt_ecb_radio, etc. +// +// acquire enables the RADIOAES clock (mirroring the SDK acquire). save/restore are no-ops: +// valid when the RADIOAES is not contended by RAIL. RAIL coexistence (real save/restore) +// is a later step; for now callers must not use RADIOAES concurrently with an active radio +// operation that also uses it. + +#include "em_device.h" +#include "sli_radioaes_management.h" +#include "sli_protocol_crypto.h" + +// No-op without SLI_PSEC_THREADING (the SDK version only sets up an OS lock in that case). +sl_status_t sli_protocol_crypto_init(void) +{ + return SL_STATUS_OK; +} + +sl_status_t sli_radioaes_acquire(void) +{ +#if defined(_CMU_CLKEN0_MASK) + CMU->CLKEN0 |= CMU_CLKEN0_RADIOAES; +#endif + CMU->RADIOCLKCTRL |= CMU_RADIOCLKCTRL_EN; + + while (RADIOAES->STATUS + & (AES_STATUS_FETCHERBSY | AES_STATUS_PUSHERBSY | AES_STATUS_SOFTRSTBSY)) { + } + + return SL_STATUS_OK; +} + +sl_status_t sli_radioaes_release(void) +{ + return SL_STATUS_OK; +} + +sl_status_t sli_radioaes_save_state(sli_radioaes_state_t *ctx) +{ + (void)ctx; + return SL_STATUS_OK; +} + +sl_status_t sli_radioaes_restore_state(sli_radioaes_state_t *ctx) +{ + (void)ctx; + return SL_STATUS_OK; +} diff --git a/crates/ziggurat-rail-sys/vendor/ziggurat_board.c b/crates/ziggurat-rail-sys/vendor/ziggurat_board.c new file mode 100644 index 0000000..e92eee8 --- /dev/null +++ b/crates/ziggurat-rail-sys/vendor/ziggurat_board.c @@ -0,0 +1,14 @@ +// Accessors that surface the board's compile-time RF config macros to Rust, so the values +// live in the vendored SLC config headers (per board) rather than being duplicated in the +// Rust source. Retargeting a board is then just a config-header swap. +#include + +#include "sl_rail_util_pa_config.h" + +uint16_t ziggurat_pa_voltage_mv(void) { + return SL_RAIL_UTIL_PA_VOLTAGE_MV; +} + +uint16_t ziggurat_pa_ramp_time_us(void) { + return SL_RAIL_UTIL_PA_RAMP_TIME_US; +} diff --git a/crates/ziggurat-rail-sys/wrapper.h b/crates/ziggurat-rail-sys/wrapper.h new file mode 100644 index 0000000..d3fc9d5 --- /dev/null +++ b/crates/ziggurat-rail-sys/wrapper.h @@ -0,0 +1,15 @@ +// bindgen entry point: the public RAIL API plus the IEEE 802.15.4 protocol layer. +#include "sl_rail.h" +#include "sl_rail_ieee802154.h" +// Clock Manager: needed to bring up HFXO (the radio reference clock) the safe way +// (enable -> wait-ready -> switch) before RAIL init. +#include "sl_clock_manager.h" +#include "sl_clock_manager_init.h" +// Hardware AES-CCM* / AES-ECB on the RADIOAES peripheral (Zigbee crypto acceleration). +#include "sli_protocol_crypto.h" +// PA / TX power configuration (needed to transmit). +#include "sl_rail_util_pa_conversions.h" +// Accessors surfacing the board's compile-time RF config macros (see vendor/ziggurat_board.c). +#include +uint16_t ziggurat_pa_voltage_mv(void); +uint16_t ziggurat_pa_ramp_time_us(void);