From 2d6b6b94aca5f6c1c21271fe8f2fd3e20c51020d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Schn=C3=B6rch?= Date: Fri, 26 Sep 2025 19:45:08 +0000 Subject: [PATCH 01/15] Enhance Makefile: add testing commands and improve output formatting --- Makefile | 87 +++++++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 67 insertions(+), 20 deletions(-) diff --git a/Makefile b/Makefile index b3929796..42e7c1a4 100644 --- a/Makefile +++ b/Makefile @@ -1,55 +1,102 @@ # AimDB Makefile # Simple automation for common development tasks -.PHONY: help build test clean fmt clippy doc all +.PHONY: help build test clean fmt clippy doc all check test-features test-embedded test-std test-no-std .DEFAULT_GOAL := help # Colors for output GREEN := \033[0;32m YELLOW := \033[0;33m +BLUE := \033[0;34m +RED := \033[0;31m NC := \033[0m # No Color ## Show available commands help: - @echo "$(GREEN)AimDB Development Commands$(NC)" - @echo "" - @echo " build Build the project" - @echo " test Run all tests" - @echo " fmt Format code" - @echo " clippy Run linter" - @echo " doc Generate docs" - @echo " clean Clean build artifacts" - @echo " check Quick development check (fmt + clippy + test)" - @echo " all Build everything" + @printf "$(GREEN)AimDB Development Commands$(NC)\n" + @printf "\n" + @printf " $(YELLOW)Core Commands:$(NC)\n" + @printf " build Build the project\n" + @printf " test Run all tests (std + all features)\n" + @printf " fmt Format code\n" + @printf " clippy Run linter\n" + @printf " doc Generate docs\n" + @printf " clean Clean build artifacts\n" + @printf "\n" + @printf " $(YELLOW)Testing Commands:$(NC)\n" + @printf " check Comprehensive development check (fmt + clippy + all tests)\n" + @printf " test-features Test different feature combinations\n" + @printf " test-embedded Test embedded/MCU compatibility\n" + @printf " test-std Test std-only features\n" + @printf " test-no-std Test no_std compatibility\n" + @printf "\n" + @printf " $(YELLOW)Convenience:$(NC)\n" + @printf " all Build everything\n" ## Core commands build: - @echo "$(GREEN)Building AimDB...$(NC)" + @printf "$(GREEN)Building AimDB...$(NC)\n" cargo build --all-features test: - @echo "$(GREEN)Running tests...$(NC)" + @printf "$(GREEN)Running standard tests...$(NC)\n" cargo test --all-features fmt: - @echo "$(GREEN)Formatting code...$(NC)" + @printf "$(GREEN)Formatting code...$(NC)\n" cargo fmt --all clippy: - @echo "$(GREEN)Running clippy...$(NC)" + @printf "$(GREEN)Running clippy...$(NC)\n" cargo clippy --all-targets --all-features -- -D warnings doc: - @echo "$(GREEN)Generating documentation...$(NC)" + @printf "$(GREEN)Generating documentation...$(NC)\n" cargo doc --all-features --no-deps --open clean: - @echo "$(GREEN)Cleaning...$(NC)" + @printf "$(GREEN)Cleaning...$(NC)\n" cargo clean +## Testing commands +test-features: + @printf "$(BLUE)Testing different feature combinations...$(NC)\n" + @printf "$(YELLOW) → Testing core no features (minimal)$(NC)\n" + cd aimdb-core && cargo test --no-default-features + @printf "$(YELLOW) → Testing core std features$(NC)\n" + cd aimdb-core && cargo test --features std + @printf "$(YELLOW) → Testing embassy adapter$(NC)\n" + cd aimdb-embassy-adapter && cargo test + @printf "$(YELLOW) → Testing all workspace crates$(NC)\n" + cargo test --all-features + +test-embedded: + @printf "$(BLUE)Testing embedded/MCU compatibility...$(NC)\n" + @printf "$(YELLOW) → Checking aimdb-core on thumbv7em-none-eabihf target$(NC)\n" + cd aimdb-core && cargo check --target thumbv7em-none-eabihf --no-default-features + @printf "$(YELLOW) → Checking aimdb-embassy-adapter on thumbv7em-none-eabihf target$(NC)\n" + cd aimdb-embassy-adapter && cargo check --target thumbv7em-none-eabihf + @printf "$(YELLOW) → Testing Embassy adapter in no_std$(NC)\n" + cd aimdb-embassy-adapter && cargo test + +test-std: + @printf "$(BLUE)Testing std-only features...$(NC)\n" + cd aimdb-core && cargo test --features std + +test-no-std: + @printf "$(BLUE)Testing no_std compatibility...$(NC)\n" + @printf "$(YELLOW) → Testing core minimal no_std$(NC)\n" + cd aimdb-core && cargo test --no-default-features + @printf "$(YELLOW) → Testing Embassy adapter no_std$(NC)\n" + cd aimdb-embassy-adapter && cargo test + ## Convenience commands -check: fmt clippy test - @echo "$(GREEN)Development checks completed!$(NC)" +check: fmt clippy test-features test-embedded + @printf "$(GREEN)Comprehensive development checks completed!$(NC)\n" + @printf "$(BLUE)✓ Code formatted$(NC)\n" + @printf "$(BLUE)✓ Linter passed$(NC)\n" + @printf "$(BLUE)✓ All feature combinations tested$(NC)\n" + @printf "$(BLUE)✓ Embedded target compatibility verified$(NC)\n" all: build test - @echo "$(GREEN)Build and test completed!$(NC)" + @printf "$(GREEN)Build and test completed!$(NC)\n" From 10c3d402b9d73c33579547ab2032b4fdd77e1bdb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Schn=C3=B6rch?= Date: Fri, 26 Sep 2025 19:46:00 +0000 Subject: [PATCH 02/15] Add aimdb-embassy-adapter and add necessary cargo dependencies --- Cargo.lock | 210 +++++++++++++++++++++++++++++++ Cargo.toml | 10 ++ aimdb-embassy-adapter/Cargo.toml | 27 ++++ 3 files changed, 247 insertions(+) create mode 100644 aimdb-embassy-adapter/Cargo.toml diff --git a/Cargo.lock b/Cargo.lock index 3a982bf8..93191612 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -24,6 +24,19 @@ dependencies = [ "thiserror", ] +[[package]] +name = "aimdb-embassy-adapter" +version = "0.1.0" +dependencies = [ + "aimdb-core", + "embassy-executor", + "embassy-time", + "embedded-hal 1.0.0", + "embedded-hal-async", + "embedded-hal-nb", + "heapless", +] + [[package]] name = "aimdb-examples" version = "0.1.0" @@ -40,6 +53,164 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +[[package]] +name = "cfg-if" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fd1289c04a9ea8cb22300a459a72a385d7c73d3259e2ed7dcb2af674838cfa9" + +[[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 = "document-features" +version = "0.2.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95249b50c6c185bee49034bcb378a49dc2b5dff0be90ff6616d31d64febab05d" +dependencies = [ + "litrs", +] + +[[package]] +name = "embassy-executor" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06070468370195e0e86f241c8e5004356d696590a678d47d6676795b2e439c6b" +dependencies = [ + "critical-section", + "document-features", + "embassy-executor-macros", + "embassy-executor-timer-queue", +] + +[[package]] +name = "embassy-executor-macros" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfdddc3a04226828316bf31393b6903ee162238576b1584ee2669af215d55472" +dependencies = [ + "darling", + "proc-macro2", + "quote", + "syn", +] + +[[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-time" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4fa65b9284d974dad7a23bb72835c4ec85c0b540d86af7fc4098c88cff51d65" +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.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0a244c7dc22c8d0289379c8d8830cae06bb93d8f990194d0de5efb3b5ae7ba6" +dependencies = [ + "document-features", +] + +[[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-hal-nb" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fba4268c14288c828995299e59b12babdbe170f6c6d73731af1b4648142e8605" +dependencies = [ + "embedded-hal 1.0.0", + "nb 1.1.0", +] + +[[package]] +name = "fnv" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" + +[[package]] +name = "futures-core" +version = "0.3.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05f29059c0c2090612e8d742178b0580d2dc940c837851ad723096f87af6663e" + [[package]] name = "hash32" version = "0.3.1" @@ -59,18 +230,45 @@ dependencies = [ "stable_deref_trait", ] +[[package]] +name = "ident_case" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9e0384b61958566e926dc50660321d12159025e767c18e043daf26b70104c39" + [[package]] name = "itoa" version = "1.0.15" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4a5f13b858c8d314ee3e8f639011f7ccefe71f97f96e50151fb991f267928e2c" +[[package]] +name = "litrs" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f5e54036fe321fd421e10d732f155734c4e4afd610dd556d9a82833ab3ee0bed" + [[package]] name = "memchr" version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" +[[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 = "proc-macro2" version = "1.0.101" @@ -143,6 +341,12 @@ version = "1.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" +[[package]] +name = "strsim" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7da8b5736845d9f2fcb837ea5d9e2628564b3b043a70948a3f0b778838c5fb4f" + [[package]] name = "syn" version = "2.0.106" @@ -179,3 +383,9 @@ name = "unicode-ident" version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f63a545481291138910575129486daeaf8ac54aee4387fe7906919f7830c7d9d" + +[[package]] +name = "void" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a02e4885ed3bc0f2de90ea6dd45ebcbb66dacffe03547fadbb0eeae2770887d" diff --git a/Cargo.toml b/Cargo.toml index aa989784..379ac1dc 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,6 +3,7 @@ members = [ "aimdb-core", "aimdb-connectors", "aimdb-adapters", + "aimdb-embassy-adapter", "tools/aimdb-cli", "examples", ] @@ -45,6 +46,15 @@ clap = { version = "4.0", features = ["derive"] } # Development dependencies tokio-test = "0.4" +# Embassy ecosystem for embedded async +embassy-executor = { version = "0.9.1" } +embassy-time = "0.5" + +# Embedded HAL for peripheral abstractions +embedded-hal = "1.0" +embedded-hal-async = "1.0" +embedded-hal-nb = "1.0" + [workspace.metadata.docs.rs] all-features = true rustdoc-args = ["--cfg", "docsrs"] diff --git a/aimdb-embassy-adapter/Cargo.toml b/aimdb-embassy-adapter/Cargo.toml new file mode 100644 index 00000000..6c20d8bf --- /dev/null +++ b/aimdb-embassy-adapter/Cargo.toml @@ -0,0 +1,27 @@ +[package] +name = "aimdb-embassy-adapter" +version.workspace = true +edition.workspace = true +license.workspace = true +description = "Embassy async runtime adapter for AimDB embedded targets" + +[features] +default = [] +std = ["aimdb-core/std"] + +[dependencies] +# Core AimDB types +aimdb-core = { path = "../aimdb-core", default-features = false } + +# Embassy ecosystem for embedded async +embassy-executor = { workspace = true } +embassy-time = { workspace = true } + +# Embedded HAL for peripheral abstractions +embedded-hal = { workspace = true } +embedded-hal-async = { workspace = true } +embedded-hal-nb = { workspace = true } + +[dev-dependencies] +# For testing on embedded targets +heapless = "0.9.1" From 6ca7f6a1b6db3af39f4c3f128d8d46ea10a71544 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Schn=C3=B6rch?= Date: Fri, 26 Sep 2025 19:50:02 +0000 Subject: [PATCH 03/15] Enhance error handling tests: add size monitoring and formatting checks for std environments --- aimdb-core/src/error.rs | 36 ++++++++++++++++++++++++++++++------ 1 file changed, 30 insertions(+), 6 deletions(-) diff --git a/aimdb-core/src/error.rs b/aimdb-core/src/error.rs index 7311c549..fd621fc6 100644 --- a/aimdb-core/src/error.rs +++ b/aimdb-core/src/error.rs @@ -954,9 +954,21 @@ mod tests { "DbError size ({} bytes) exceeds 64-byte limit for embedded targets", size ); + } - // Print size for monitoring + #[test] + #[cfg(feature = "std")] + fn test_error_size_monitoring() { + // Monitor error size for performance tracking in std environments + let size = core::mem::size_of::(); println!("DbError size: {} bytes", size); + + // Also test that std version is within reasonable bounds (higher than no_std) + assert!( + size >= 24, + "DbError std size ({} bytes) unexpectedly small - check feature compilation", + size + ); } #[test] @@ -979,15 +991,26 @@ mod tests { _resource_type: (), }; - // Test that errors can be formatted - let timeout_msg = format!("{:?}", timeout_error); - let capacity_msg = format!("{:?}", capacity_error); + // Test that errors can be formatted (std only) + #[cfg(feature = "std")] + { + let timeout_msg = format!("{:?}", timeout_error); + let capacity_msg = format!("{:?}", capacity_error); + + assert!(timeout_msg.contains("NetworkTimeout")); + assert!(capacity_msg.contains("CapacityExceeded")); + } - assert!(timeout_msg.contains("NetworkTimeout")); - assert!(capacity_msg.contains("CapacityExceeded")); + // Prevent unused variable warnings in no_std + #[cfg(not(feature = "std"))] + { + let _ = timeout_error; + let _ = capacity_error; + } } #[test] + #[cfg(feature = "std")] fn test_dbresult_usage() { // Test DbResult type alias usage fn example_operation() -> DbResult { @@ -1231,6 +1254,7 @@ mod tests { } #[test] + #[cfg(feature = "std")] fn test_error_code_uniqueness() { // Ensure all error codes are unique use std::collections::HashSet; From c10a4294707c448415ff42240d677642bd76fe14 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Schn=C3=B6rch?= Date: Fri, 26 Sep 2025 19:50:32 +0000 Subject: [PATCH 04/15] Fix: ensure no_std compatibility for non-standard builds --- aimdb-core/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/aimdb-core/src/lib.rs b/aimdb-core/src/lib.rs index 83f75b5b..c7a807fe 100644 --- a/aimdb-core/src/lib.rs +++ b/aimdb-core/src/lib.rs @@ -4,6 +4,8 @@ //! in-memory storage with real-time synchronization across MCU → edge → cloud //! environments. +#![cfg_attr(not(feature = "std"), no_std)] + mod error; // Public API exports From a4b84f404cf3256bdfe1084a97f8499d8779bfab Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Schn=C3=B6rch?= Date: Sat, 27 Sep 2025 18:42:48 +0000 Subject: [PATCH 05/15] refactos makefile - to build no-std and std features --- Makefile | 68 ++++++++++++++++++++++++-------------------------------- 1 file changed, 29 insertions(+), 39 deletions(-) diff --git a/Makefile b/Makefile index 42e7c1a4..7af7f3c6 100644 --- a/Makefile +++ b/Makefile @@ -1,7 +1,7 @@ # AimDB Makefile # Simple automation for common development tasks -.PHONY: help build test clean fmt clippy doc all check test-features test-embedded test-std test-no-std +.PHONY: help build test clean fmt clippy doc all check test-embedded .DEFAULT_GOAL := help # Colors for output @@ -16,8 +16,8 @@ help: @printf "$(GREEN)AimDB Development Commands$(NC)\n" @printf "\n" @printf " $(YELLOW)Core Commands:$(NC)\n" - @printf " build Build the project\n" - @printf " test Run all tests (std + all features)\n" + @printf " build Build all components (std + embedded)\n" + @printf " test Run all tests (std + embedded)\n" @printf " fmt Format code\n" @printf " clippy Run linter\n" @printf " doc Generate docs\n" @@ -25,22 +25,29 @@ help: @printf "\n" @printf " $(YELLOW)Testing Commands:$(NC)\n" @printf " check Comprehensive development check (fmt + clippy + all tests)\n" - @printf " test-features Test different feature combinations\n" - @printf " test-embedded Test embedded/MCU compatibility\n" - @printf " test-std Test std-only features\n" - @printf " test-no-std Test no_std compatibility\n" + @printf " test-embedded Test embedded/MCU cross-compilation compatibility\n" @printf "\n" @printf " $(YELLOW)Convenience:$(NC)\n" @printf " all Build everything\n" ## Core commands build: - @printf "$(GREEN)Building AimDB...$(NC)\n" - cargo build --all-features + @printf "$(GREEN)Building AimDB (all combinations)...$(NC)\n" + @printf "$(YELLOW) → Building default (no_std)$(NC)\n" + cargo build + @printf "$(YELLOW) → Building std components with all features$(NC)\n" + cargo build --workspace --exclude aimdb-embassy-adapter --all-features + @printf "$(YELLOW) → Building embassy adapter (no_std only)$(NC)\n" + cd aimdb-embassy-adapter && cargo build test: - @printf "$(GREEN)Running standard tests...$(NC)\n" - cargo test --all-features + @printf "$(GREEN)Running all tests (all combinations)...$(NC)\n" + @printf "$(YELLOW) → Testing default (no_std)$(NC)\n" + cargo test + @printf "$(YELLOW) → Testing std components with all features$(NC)\n" + cargo test --workspace --exclude aimdb-embassy-adapter --all-features + @printf "$(YELLOW) → Testing embassy adapter (no_std only)$(NC)\n" + cd aimdb-embassy-adapter && cargo test fmt: @printf "$(GREEN)Formatting code...$(NC)\n" @@ -48,55 +55,38 @@ fmt: clippy: @printf "$(GREEN)Running clippy...$(NC)\n" - cargo clippy --all-targets --all-features -- -D warnings + @printf "$(YELLOW) → Clippy on default (no_std)$(NC)\n" + cargo clippy --all-targets -- -D warnings + @printf "$(YELLOW) → Clippy on std components with all features$(NC)\n" + cargo clippy --workspace --exclude aimdb-embassy-adapter --all-targets --all-features -- -D warnings + @printf "$(YELLOW) → Clippy on embassy adapter$(NC)\n" + cd aimdb-embassy-adapter && cargo clippy --all-targets -- -D warnings doc: @printf "$(GREEN)Generating documentation...$(NC)\n" - cargo doc --all-features --no-deps --open + cargo doc --workspace --exclude aimdb-embassy-adapter --all-features --no-deps --open clean: @printf "$(GREEN)Cleaning...$(NC)\n" cargo clean ## Testing commands -test-features: - @printf "$(BLUE)Testing different feature combinations...$(NC)\n" - @printf "$(YELLOW) → Testing core no features (minimal)$(NC)\n" - cd aimdb-core && cargo test --no-default-features - @printf "$(YELLOW) → Testing core std features$(NC)\n" - cd aimdb-core && cargo test --features std - @printf "$(YELLOW) → Testing embassy adapter$(NC)\n" - cd aimdb-embassy-adapter && cargo test - @printf "$(YELLOW) → Testing all workspace crates$(NC)\n" - cargo test --all-features - test-embedded: - @printf "$(BLUE)Testing embedded/MCU compatibility...$(NC)\n" + @printf "$(BLUE)Testing embedded/MCU cross-compilation compatibility...$(NC)\n" @printf "$(YELLOW) → Checking aimdb-core on thumbv7em-none-eabihf target$(NC)\n" cd aimdb-core && cargo check --target thumbv7em-none-eabihf --no-default-features @printf "$(YELLOW) → Checking aimdb-embassy-adapter on thumbv7em-none-eabihf target$(NC)\n" cd aimdb-embassy-adapter && cargo check --target thumbv7em-none-eabihf - @printf "$(YELLOW) → Testing Embassy adapter in no_std$(NC)\n" - cd aimdb-embassy-adapter && cargo test - -test-std: - @printf "$(BLUE)Testing std-only features...$(NC)\n" - cd aimdb-core && cargo test --features std - -test-no-std: - @printf "$(BLUE)Testing no_std compatibility...$(NC)\n" - @printf "$(YELLOW) → Testing core minimal no_std$(NC)\n" - cd aimdb-core && cargo test --no-default-features - @printf "$(YELLOW) → Testing Embassy adapter no_std$(NC)\n" - cd aimdb-embassy-adapter && cargo test ## Convenience commands -check: fmt clippy test-features test-embedded +check: fmt clippy test test-embedded @printf "$(GREEN)Comprehensive development checks completed!$(NC)\n" @printf "$(BLUE)✓ Code formatted$(NC)\n" @printf "$(BLUE)✓ Linter passed$(NC)\n" @printf "$(BLUE)✓ All feature combinations tested$(NC)\n" @printf "$(BLUE)✓ Embedded target compatibility verified$(NC)\n" + + all: build test @printf "$(GREEN)Build and test completed!$(NC)\n" From 5a702b654efd1fa8286f7780ba2ea93b98e14dea Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Schn=C3=B6rch?= Date: Sat, 27 Sep 2025 18:43:15 +0000 Subject: [PATCH 06/15] add embedded feature --- aimdb-core/Cargo.toml | 3 ++- aimdb-embassy-adapter/Cargo.toml | 11 ++++++++--- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/aimdb-core/Cargo.toml b/aimdb-core/Cargo.toml index c88eb1de..b4b4bdc0 100644 --- a/aimdb-core/Cargo.toml +++ b/aimdb-core/Cargo.toml @@ -6,8 +6,9 @@ license.workspace = true description = "Core database engine for AimDB - async in-memory storage with real-time synchronization" [features] -default = ["std"] +default = [] std = ["thiserror", "anyhow", "serde_json"] +embedded = [] [dependencies] # Error handling - only for std environments diff --git a/aimdb-embassy-adapter/Cargo.toml b/aimdb-embassy-adapter/Cargo.toml index 6c20d8bf..1778a0b8 100644 --- a/aimdb-embassy-adapter/Cargo.toml +++ b/aimdb-embassy-adapter/Cargo.toml @@ -4,14 +4,19 @@ version.workspace = true edition.workspace = true license.workspace = true description = "Embassy async runtime adapter for AimDB embedded targets" +build = "build.rs" [features] default = [] -std = ["aimdb-core/std"] +# Note: std feature is intentionally kept but will cause build.rs to fail if enabled +# This provides clear error messages when accidentally enabled +std = [] [dependencies] -# Core AimDB types -aimdb-core = { path = "../aimdb-core", default-features = false } +# Core AimDB types - always no_std for Embassy +aimdb-core = { path = "../aimdb-core", default-features = false, features = [ + "embedded", +] } # Embassy ecosystem for embedded async embassy-executor = { workspace = true } From f98846a66edde1516c9ad86df77bfe43a4494917 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Schn=C3=B6rch?= Date: Sat, 27 Sep 2025 18:43:35 +0000 Subject: [PATCH 07/15] add error implementation for embassy adapter --- aimdb-embassy-adapter/src/error.rs | 448 +++++++++++++++++++++++++++++ aimdb-embassy-adapter/src/lib.rs | 56 ++++ 2 files changed, 504 insertions(+) create mode 100644 aimdb-embassy-adapter/src/error.rs create mode 100644 aimdb-embassy-adapter/src/lib.rs diff --git a/aimdb-embassy-adapter/src/error.rs b/aimdb-embassy-adapter/src/error.rs new file mode 100644 index 00000000..224e9be7 --- /dev/null +++ b/aimdb-embassy-adapter/src/error.rs @@ -0,0 +1,448 @@ +//! Embassy-specific error handling support +//! +//! This module provides traits and implementations that add Embassy +//! and embedded-hal specific functionality to AimDB's core error types. +//! +//! Embassy is a no_std async runtime, so this adapter always works in no_std mode +//! and uses the no_std field names from DbError. +//! +//! This crate is excluded from the main workspace to prevent feature unification issues +//! that would enable std mode. Build it separately with: cargo build -p aimdb-embassy-adapter + +use aimdb_core::DbError; +use embedded_hal::i2c; +use embedded_hal::spi; +use embedded_hal_nb::nb; + +/// Trait that provides Embassy-specific error constructors for DbError +/// +/// This trait provides hardware-specific error creation methods without requiring +/// the core AimDB crate to depend on embassy or embedded-hal. +pub trait EmbassyErrorSupport { + /// Creates an SPI error for Embassy environments (error codes 0x6100-0x61FF) + fn from_spi_error(code: u8) -> Self; + + /// Creates a UART error for Embassy environments (error codes 0x6200-0x62FF) + fn from_uart_error(code: u8) -> Self; + + /// Creates an I2C error for Embassy environments (error codes 0x6300-0x63FF) + fn from_i2c_error(code: u8) -> Self; + + /// Creates an ADC error for Embassy environments (error codes 0x6400-0x64FF) + fn from_adc_error(code: u8) -> Self; + + /// Creates a GPIO error for Embassy environments (error codes 0x6500-0x65FF) + fn from_gpio_error(code: u8) -> Self; + + /// Creates a Timer error for Embassy environments (error codes 0x6600-0x66FF) + fn from_timer_error(code: u8) -> Self; + + /// Converts an SPI error to DbError + fn from_spi_hal_error(error: spi::ErrorKind) -> Self; + + /// Converts an I2C error to DbError + fn from_i2c_hal_error(error: i2c::ErrorKind) -> Self; + + /// Converts a non-blocking error to DbError + fn from_nb_error(error: nb::Error) -> Self + where + E: Into, + Self: Sized; +} + +impl EmbassyErrorSupport for DbError { + /// Creates an SPI error for Embassy environments (error codes 0x6100-0x61FF) + fn from_spi_error(code: u8) -> Self { + DbError::HardwareError { + component: 2, // SPI component ID + error_code: 0x6100 | (code as u16), + _description: (), + } + } + + /// Creates a UART error for Embassy environments (error codes 0x6200-0x62FF) + fn from_uart_error(code: u8) -> Self { + DbError::HardwareError { + component: 4, // UART component ID + error_code: 0x6200 | (code as u16), + _description: (), + } + } + + /// Creates an I2C error for Embassy environments (error codes 0x6300-0x63FF) + fn from_i2c_error(code: u8) -> Self { + DbError::HardwareError { + component: 3, // I2C component ID + error_code: 0x6300 | (code as u16), + _description: (), + } + } + + /// Creates an ADC error for Embassy environments (error codes 0x6400-0x64FF) + fn from_adc_error(code: u8) -> Self { + DbError::HardwareError { + component: 5, // ADC component ID + error_code: 0x6400 | (code as u16), + _description: (), + } + } + + /// Creates a GPIO error for Embassy environments (error codes 0x6500-0x65FF) + fn from_gpio_error(code: u8) -> Self { + DbError::HardwareError { + component: 1, // GPIO component ID + error_code: 0x6500 | (code as u16), + _description: (), + } + } + + /// Creates a Timer error for Embassy environments (error codes 0x6600-0x66FF) + fn from_timer_error(code: u8) -> Self { + DbError::HardwareError { + component: 0, // Timer component ID + error_code: 0x6600 | (code as u16), + _description: (), + } + } + + /// Converts an SPI error to DbError + fn from_spi_hal_error(error: spi::ErrorKind) -> Self { + let error_code = match error { + spi::ErrorKind::ChipSelectFault => 0x01, + spi::ErrorKind::ModeFault => 0x02, + spi::ErrorKind::Overrun => 0x04, + spi::ErrorKind::FrameFormat => 0x05, + _ => 0xFF, // Generic/unknown error + }; + Self::from_spi_error(error_code) + } + + /// Converts an I2C error to DbError + fn from_i2c_hal_error(error: i2c::ErrorKind) -> Self { + let error_code = match error { + i2c::ErrorKind::Bus => 0x01, + i2c::ErrorKind::ArbitrationLoss => 0x02, + i2c::ErrorKind::NoAcknowledge(i2c::NoAcknowledgeSource::Address) => 0x03, + i2c::ErrorKind::NoAcknowledge(i2c::NoAcknowledgeSource::Data) => 0x04, + i2c::ErrorKind::NoAcknowledge(i2c::NoAcknowledgeSource::Unknown) => 0x05, + i2c::ErrorKind::Overrun => 0x06, + _ => 0xFF, // Generic/unknown error + }; + Self::from_i2c_error(error_code) + } + + /// Converts a non-blocking error to DbError + fn from_nb_error(error: nb::Error) -> Self + where + E: Into, + { + match error { + nb::Error::Other(e) => e.into(), + nb::Error::WouldBlock => DbError::ResourceUnavailable { + resource_type: 255, // Special code for "would block" + _resource_name: (), + }, + } + } +} + +/// Converter functions for embedded-hal errors to DbError +pub struct EmbassyErrorConverter; + +impl EmbassyErrorConverter { + /// Converts an SPI ErrorKind to DbError + pub fn from_spi(error: spi::ErrorKind) -> DbError { + DbError::from_spi_hal_error(error) + } + + /// Converts an I2C ErrorKind to DbError + pub fn from_i2c(error: i2c::ErrorKind) -> DbError { + DbError::from_i2c_hal_error(error) + } + + /// Converts an nb::Error to DbError + pub fn from_nb(error: nb::Error) -> DbError + where + E: Into, + { + DbError::from_nb_error(error) + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_embassy_hardware_error_constructors() { + // Test Embassy-specific const constructors for hardware errors + + // Test SPI error constructor (0x6100-0x61FF range) + let spi_error = DbError::from_spi_error(0x42); + if let DbError::HardwareError { + component, + error_code, + .. + } = spi_error + { + assert_eq!(component, 2); // SPI component ID + assert_eq!(error_code, 0x6142); // 0x6100 | 0x42 + } else { + panic!("Expected HardwareError variant"); + } + + // Test UART error constructor (0x6200-0x62FF range) + let uart_error = DbError::from_uart_error(0x10); + if let DbError::HardwareError { + component, + error_code, + .. + } = uart_error + { + assert_eq!(component, 4); // UART component ID + assert_eq!(error_code, 0x6210); // 0x6200 | 0x10 + } else { + panic!("Expected HardwareError variant"); + } + + // Test I2C error constructor (0x6300-0x63FF range) + let i2c_error = DbError::from_i2c_error(0x05); + if let DbError::HardwareError { + component, + error_code, + .. + } = i2c_error + { + assert_eq!(component, 3); // I2C component ID + assert_eq!(error_code, 0x6305); // 0x6300 | 0x05 + } else { + panic!("Expected HardwareError variant"); + } + + // Test ADC error constructor (0x6400-0x64FF range) + let adc_error = DbError::from_adc_error(0x20); + if let DbError::HardwareError { + component, + error_code, + .. + } = adc_error + { + assert_eq!(component, 5); // ADC component ID + assert_eq!(error_code, 0x6420); // 0x6400 | 0x20 + } else { + panic!("Expected HardwareError variant"); + } + + // Test GPIO error constructor (0x6500-0x65FF range) + let gpio_error = DbError::from_gpio_error(0x08); + if let DbError::HardwareError { + component, + error_code, + .. + } = gpio_error + { + assert_eq!(component, 1); // GPIO component ID + assert_eq!(error_code, 0x6508); // 0x6500 | 0x08 + } else { + panic!("Expected HardwareError variant"); + } + + // Test Timer error constructor (0x6600-0x66FF range) + let timer_error = DbError::from_timer_error(0xFF); + if let DbError::HardwareError { + component, + error_code, + .. + } = timer_error + { + assert_eq!(component, 0); // Timer component ID + assert_eq!(error_code, 0x66FF); // 0x6600 | 0xFF + } else { + panic!("Expected HardwareError variant"); + } + } + + #[test] + fn test_embedded_hal_error_conversions() { + use crate::EmbassyErrorConverter; + + // Test SPI error conversions + let spi_overrun = EmbassyErrorConverter::from_spi(spi::ErrorKind::Overrun); + if let DbError::HardwareError { + component, + error_code, + .. + } = spi_overrun + { + assert_eq!(component, 2); // SPI component + assert_eq!(error_code, 0x6104); // 0x6100 | 0x04 + } else { + panic!("Expected HardwareError variant"); + } + + let spi_mode_fault = EmbassyErrorConverter::from_spi(spi::ErrorKind::ModeFault); + if let DbError::HardwareError { + component, + error_code, + .. + } = spi_mode_fault + { + assert_eq!(component, 2); // SPI component + assert_eq!(error_code, 0x6102); // 0x6100 | 0x02 + } else { + panic!("Expected HardwareError variant"); + } + + // Test I2C error conversions + let i2c_bus_error = EmbassyErrorConverter::from_i2c(i2c::ErrorKind::Bus); + if let DbError::HardwareError { + component, + error_code, + .. + } = i2c_bus_error + { + assert_eq!(component, 3); // I2C component + assert_eq!(error_code, 0x6301); // 0x6300 | 0x01 + } else { + panic!("Expected HardwareError variant"); + } + + let i2c_nack = EmbassyErrorConverter::from_i2c(i2c::ErrorKind::NoAcknowledge( + i2c::NoAcknowledgeSource::Address, + )); + if let DbError::HardwareError { + component, + error_code, + .. + } = i2c_nack + { + assert_eq!(component, 3); // I2C component + assert_eq!(error_code, 0x6303); // 0x6300 | 0x03 + } else { + panic!("Expected HardwareError variant"); + } + } + + #[test] + fn test_nb_error_conversion() { + // Test nb::Error::WouldBlock conversion (use DbError directly since it can convert to itself) + let would_block: nb::Error = nb::Error::WouldBlock; + let db_error = DbError::from_nb_error(would_block); + + if let DbError::ResourceUnavailable { resource_type, .. } = db_error { + assert_eq!(resource_type, 255); // Special code for would block + } else { + panic!("Expected ResourceUnavailable variant"); + } + + // Test nb::Error::Other conversion with a known error + let known_error = DbError::from_spi_error(0x42); + let nb_other_error: nb::Error = nb::Error::Other(known_error); + let converted_error = DbError::from_nb_error(nb_other_error); + + // The converted error should have the same code as the original (0x6001 for all hardware errors) + assert_eq!(converted_error.error_code(), 0x6001); + } + + #[test] + fn test_embassy_error_code_ranges() { + // Test that Embassy hardware errors are properly categorized + // Note: All HardwareError variants return 0x6001 from error_code(), + // but have different component-specific error_code fields + + let spi_error = DbError::from_spi_error(0x00); + assert_eq!(spi_error.error_category(), 0x6000); // Hardware category + assert_eq!(spi_error.error_code(), 0x6001); // All hardware errors use this unified code + + let uart_error = DbError::from_uart_error(0x00); + assert_eq!(uart_error.error_category(), 0x6000); // Hardware category + assert_eq!(uart_error.error_code(), 0x6001); + + let i2c_error = DbError::from_i2c_error(0x00); + assert_eq!(i2c_error.error_category(), 0x6000); // Hardware category + assert_eq!(i2c_error.error_code(), 0x6001); + + let adc_error = DbError::from_adc_error(0x00); + assert_eq!(adc_error.error_category(), 0x6000); // Hardware category + assert_eq!(adc_error.error_code(), 0x6001); + + let gpio_error = DbError::from_gpio_error(0x00); + assert_eq!(gpio_error.error_category(), 0x6000); // Hardware category + assert_eq!(gpio_error.error_code(), 0x6001); + + let timer_error = DbError::from_timer_error(0x00); + assert_eq!(timer_error.error_category(), 0x6000); // Hardware category + assert_eq!(timer_error.error_code(), 0x6001); + } + + #[test] + fn test_converter_functions() { + // Test EmbassyErrorConverter functions + let spi_error = EmbassyErrorConverter::from_spi(spi::ErrorKind::Overrun); + if let DbError::HardwareError { + component, + error_code, + .. + } = spi_error + { + assert_eq!(component, 2); // SPI component + assert_eq!(error_code, 0x6104); // 0x6100 | 0x04 (Overrun) - component-specific code + } else { + panic!("Expected HardwareError variant"); + } + // But the unified error code is always 0x6001 + assert_eq!(spi_error.error_code(), 0x6001); + + let i2c_error = EmbassyErrorConverter::from_i2c(i2c::ErrorKind::Bus); + if let DbError::HardwareError { + component, + error_code, + .. + } = i2c_error + { + assert_eq!(component, 3); // I2C component + assert_eq!(error_code, 0x6301); // 0x6300 | 0x01 (Bus) - component-specific code + } else { + panic!("Expected HardwareError variant"); + } + // But the unified error code is always 0x6001 + assert_eq!(i2c_error.error_code(), 0x6001); + + // Test nb error conversion + let would_block: nb::Error = nb::Error::WouldBlock; + let db_error = EmbassyErrorConverter::from_nb(would_block); + if let DbError::ResourceUnavailable { resource_type, .. } = db_error { + assert_eq!(resource_type, 255); + } else { + panic!("Expected ResourceUnavailable variant"); + } + } + + #[test] + fn test_error_construction() { + // Test that constructors work correctly at runtime + + let spi_error = DbError::from_spi_error(0x01); + let uart_error = DbError::from_uart_error(0x02); + let i2c_error = DbError::from_i2c_error(0x03); + let adc_error = DbError::from_adc_error(0x04); + let gpio_error = DbError::from_gpio_error(0x05); + let timer_error = DbError::from_timer_error(0x06); + + // Verify the construction worked correctly (all hardware errors use 0x6001) + assert_eq!(spi_error.error_code(), 0x6001); + assert_eq!(uart_error.error_code(), 0x6001); + assert_eq!(i2c_error.error_code(), 0x6001); + assert_eq!(adc_error.error_code(), 0x6001); + assert_eq!(gpio_error.error_code(), 0x6001); + assert_eq!(timer_error.error_code(), 0x6001); + + // Verify they're all hardware errors + assert!(spi_error.is_hardware_error()); + assert!(uart_error.is_hardware_error()); + assert!(i2c_error.is_hardware_error()); + assert!(adc_error.is_hardware_error()); + assert!(gpio_error.is_hardware_error()); + assert!(timer_error.is_hardware_error()); + } +} diff --git a/aimdb-embassy-adapter/src/lib.rs b/aimdb-embassy-adapter/src/lib.rs new file mode 100644 index 00000000..d9cd8822 --- /dev/null +++ b/aimdb-embassy-adapter/src/lib.rs @@ -0,0 +1,56 @@ +//! Embassy Adapter for AimDB +//! +//! This crate provides Embassy-specific extensions for AimDB, enabling the database +//! to run on embedded systems using the Embassy async runtime and embedded-hal +//! peripheral abstractions. +//! +//! # Features +//! +//! - **Embassy Integration**: Seamless integration with Embassy async executor +//! - **Hardware Abstraction**: Support for SPI, I2C, UART, ADC, GPIO, and Timer peripherals +//! - **Error Handling**: Embassy-specific error conversions and handling +//! - **No-std Compatible**: Designed for resource-constrained embedded systems +//! +//! # Architecture +//! +//! Embassy is a no_std async runtime, so this adapter is designed for embedded +//! environments and works with the no_std version of aimdb-core by default. +//! +//! The adapter extends AimDB's core functionality without requiring embassy +//! dependencies in the core crate. It provides: +//! +//! - Hardware error constructors for common MCU peripherals +//! - Automatic conversions from embedded-hal error types +//! - Embassy-specific const functions for zero-overhead error handling +//! +//! # Usage +//! +//! ```rust +//! use aimdb_core::DbError; +//! use aimdb_embassy_adapter::{EmbassyErrorSupport, EmbassyErrorConverter}; +//! +//! // Create hardware-specific errors +//! let spi_error = DbError::from_spi_error(0x42); +//! let i2c_error = DbError::from_i2c_error(0x10); +//! +//! // Convert from embedded-hal errors using the converter +//! let hal_error = embedded_hal::spi::ErrorKind::Overrun; +//! let db_error = EmbassyErrorConverter::from_spi(hal_error); +//! ``` +//! +//! # Error Code Ranges +//! +//! The adapter uses specific error code ranges for different peripherals: +//! +//! - **SPI**: 0x6100-0x61FF +//! - **UART**: 0x6200-0x62FF +//! - **I2C**: 0x6300-0x63FF +//! - **ADC**: 0x6400-0x64FF +//! - **GPIO**: 0x6500-0x65FF +//! - **Timer**: 0x6600-0x66FF + +#![no_std] + +mod error; + +pub use error::{EmbassyErrorConverter, EmbassyErrorSupport}; From bee89dda31adc6fd1eb919b303de7597a8ae59e6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Schn=C3=B6rch?= Date: Sat, 27 Sep 2025 18:50:38 +0000 Subject: [PATCH 08/15] add build.rs to skip std build for embassy --- aimdb-embassy-adapter/build.rs | 36 ++++++++++++++++++++++++++++++++ aimdb-embassy-adapter/src/lib.rs | 4 ++++ 2 files changed, 40 insertions(+) create mode 100644 aimdb-embassy-adapter/build.rs diff --git a/aimdb-embassy-adapter/build.rs b/aimdb-embassy-adapter/build.rs new file mode 100644 index 00000000..ede0b4f3 --- /dev/null +++ b/aimdb-embassy-adapter/build.rs @@ -0,0 +1,36 @@ +//! Build script for aimdb-embassy-adapter +//! +//! This build script enforces no_std compilation for the Embassy adapter. +//! Embassy is designed for embedded targets and should always be no_std. + +use std::env; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + + // Check if std feature is enabled via feature unification + let features = env::var("CARGO_FEATURE_STD").is_ok(); + + if features { + println!("cargo:warning=aimdb-embassy-adapter: Skipping implementation due to std feature"); + println!( + "cargo:warning=This crate is designed exclusively for no_std embedded environments" + ); + println!("cargo:warning=To build embassy adapter: cd aimdb-embassy-adapter && cargo build"); + } + + // Always enforce no_std compilation + println!("cargo:rustc-cfg=no_std_enforced"); + + // Set target-specific configurations for embedded targets + let target = env::var("TARGET").unwrap_or_default(); + + if target.contains("thumbv") || target.contains("riscv") || target.contains("arm") { + // For embedded targets, ensure optimizations that help with code size + println!("cargo:rustc-link-arg=-Wl,--gc-sections"); + println!("cargo:rustc-cfg=embedded_target"); + } + + // Always available in no_std environments + println!("cargo:rustc-cfg=core_available"); +} diff --git a/aimdb-embassy-adapter/src/lib.rs b/aimdb-embassy-adapter/src/lib.rs index d9cd8822..e32157e1 100644 --- a/aimdb-embassy-adapter/src/lib.rs +++ b/aimdb-embassy-adapter/src/lib.rs @@ -51,6 +51,10 @@ #![no_std] +// Only include the implementation when std feature is not enabled +// Embassy adapter is designed exclusively for no_std environments +#[cfg(not(feature = "std"))] mod error; +#[cfg(not(feature = "std"))] pub use error::{EmbassyErrorConverter, EmbassyErrorSupport}; From 24aff2b4729306c7e5c7d4c1e0e88ba27a3da640 Mon Sep 17 00:00:00 2001 From: "sounds.like.lx" <147444674+lxsaah@users.noreply.github.com> Date: Sat, 27 Sep 2025 21:00:09 +0200 Subject: [PATCH 09/15] Update aimdb-embassy-adapter/build.rs Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- aimdb-embassy-adapter/build.rs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/aimdb-embassy-adapter/build.rs b/aimdb-embassy-adapter/build.rs index ede0b4f3..8be39fd4 100644 --- a/aimdb-embassy-adapter/build.rs +++ b/aimdb-embassy-adapter/build.rs @@ -27,7 +27,14 @@ fn main() { if target.contains("thumbv") || target.contains("riscv") || target.contains("arm") { // For embedded targets, ensure optimizations that help with code size - println!("cargo:rustc-link-arg=-Wl,--gc-sections"); + // Only add --gc-sections if using GNU ld as the linker + let linker_env = format!("CARGO_TARGET_{}_LINKER", target.replace('-', "_").to_uppercase()); + let linker = env::var(&linker_env) + .or_else(|_| env::var("RUSTC_LINKER")) + .unwrap_or_default(); + if linker.contains("ld") { + println!("cargo:rustc-link-arg=-Wl,--gc-sections"); + } println!("cargo:rustc-cfg=embedded_target"); } From cf04c2b108b160eb030c5c2c83c783b9e634d390 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Schn=C3=B6rch?= Date: Sat, 27 Sep 2025 19:10:04 +0000 Subject: [PATCH 10/15] add constants to avoid magic numbers --- aimdb-core/src/error.rs | 14 ++++++++++++++ aimdb-embassy-adapter/src/error.rs | 6 +++--- 2 files changed, 17 insertions(+), 3 deletions(-) diff --git a/aimdb-core/src/error.rs b/aimdb-core/src/error.rs index fd621fc6..f0f0a174 100644 --- a/aimdb-core/src/error.rs +++ b/aimdb-core/src/error.rs @@ -505,6 +505,20 @@ impl core::fmt::Display for DbError { } impl DbError { + // Resource type constants for ResourceUnavailable and ResourceAllocationFailed errors + pub const RESOURCE_TYPE_MEMORY: u8 = 0; + pub const RESOURCE_TYPE_FILE_HANDLE: u8 = 1; + pub const RESOURCE_TYPE_SOCKET: u8 = 2; + pub const RESOURCE_TYPE_BUFFER: u8 = 3; + pub const RESOURCE_TYPE_THREAD: u8 = 4; + pub const RESOURCE_TYPE_MUTEX: u8 = 5; + pub const RESOURCE_TYPE_SEMAPHORE: u8 = 6; + pub const RESOURCE_TYPE_CHANNEL: u8 = 7; + // Reserved range for embedded-specific resources: 8-127 + // Reserved range for connector-specific resources: 128-254 + /// Special resource type code for non-blocking operations that would block + pub const RESOURCE_TYPE_WOULD_BLOCK: u8 = 255; + /// Creates a network timeout error with the specified timeout duration pub fn network_timeout(timeout_ms: u64) -> Self { DbError::NetworkTimeout { diff --git a/aimdb-embassy-adapter/src/error.rs b/aimdb-embassy-adapter/src/error.rs index 224e9be7..0052bf28 100644 --- a/aimdb-embassy-adapter/src/error.rs +++ b/aimdb-embassy-adapter/src/error.rs @@ -139,7 +139,7 @@ impl EmbassyErrorSupport for DbError { match error { nb::Error::Other(e) => e.into(), nb::Error::WouldBlock => DbError::ResourceUnavailable { - resource_type: 255, // Special code for "would block" + resource_type: DbError::RESOURCE_TYPE_WOULD_BLOCK, _resource_name: (), }, } @@ -330,7 +330,7 @@ mod tests { let db_error = DbError::from_nb_error(would_block); if let DbError::ResourceUnavailable { resource_type, .. } = db_error { - assert_eq!(resource_type, 255); // Special code for would block + assert_eq!(resource_type, DbError::RESOURCE_TYPE_WOULD_BLOCK); } else { panic!("Expected ResourceUnavailable variant"); } @@ -412,7 +412,7 @@ mod tests { let would_block: nb::Error = nb::Error::WouldBlock; let db_error = EmbassyErrorConverter::from_nb(would_block); if let DbError::ResourceUnavailable { resource_type, .. } = db_error { - assert_eq!(resource_type, 255); + assert_eq!(resource_type, DbError::RESOURCE_TYPE_WOULD_BLOCK); } else { panic!("Expected ResourceUnavailable variant"); } From 024e69ee9efbf2ba6d901abc294a7c15e6b18d3d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Schn=C3=B6rch?= Date: Sat, 27 Sep 2025 19:10:17 +0000 Subject: [PATCH 11/15] update usage example to clarify no_std environment requirements --- aimdb-embassy-adapter/src/lib.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/aimdb-embassy-adapter/src/lib.rs b/aimdb-embassy-adapter/src/lib.rs index e32157e1..63d00188 100644 --- a/aimdb-embassy-adapter/src/lib.rs +++ b/aimdb-embassy-adapter/src/lib.rs @@ -25,7 +25,11 @@ //! //! # Usage //! -//! ```rust +//! ```rust,no_run +//! // This example only works when std feature is not enabled +//! // Embassy adapter is designed exclusively for no_std environments +//! # #[cfg(not(feature = "std"))] +//! # { //! use aimdb_core::DbError; //! use aimdb_embassy_adapter::{EmbassyErrorSupport, EmbassyErrorConverter}; //! @@ -36,6 +40,7 @@ //! // Convert from embedded-hal errors using the converter //! let hal_error = embedded_hal::spi::ErrorKind::Overrun; //! let db_error = EmbassyErrorConverter::from_spi(hal_error); +//! # } //! ``` //! //! # Error Code Ranges From ea5547325ac753f3b5b79d0188f0f72b3cfd6f74 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Schn=C3=B6rch?= Date: Sat, 27 Sep 2025 19:11:33 +0000 Subject: [PATCH 12/15] format linker_env for better readability --- aimdb-embassy-adapter/build.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/aimdb-embassy-adapter/build.rs b/aimdb-embassy-adapter/build.rs index 8be39fd4..04229d6d 100644 --- a/aimdb-embassy-adapter/build.rs +++ b/aimdb-embassy-adapter/build.rs @@ -28,7 +28,10 @@ fn main() { if target.contains("thumbv") || target.contains("riscv") || target.contains("arm") { // For embedded targets, ensure optimizations that help with code size // Only add --gc-sections if using GNU ld as the linker - let linker_env = format!("CARGO_TARGET_{}_LINKER", target.replace('-', "_").to_uppercase()); + let linker_env = format!( + "CARGO_TARGET_{}_LINKER", + target.replace('-', "_").to_uppercase() + ); let linker = env::var(&linker_env) .or_else(|_| env::var("RUSTC_LINKER")) .unwrap_or_default(); From a52c28f90a1e90cc102d1b85824bad24c49b3968 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Schn=C3=B6rch?= Date: Sat, 27 Sep 2025 19:24:21 +0000 Subject: [PATCH 13/15] refactor error handling to use constants for component IDs and error codes --- aimdb-embassy-adapter/src/error.rs | 129 ++++++++++++++++++----------- 1 file changed, 81 insertions(+), 48 deletions(-) diff --git a/aimdb-embassy-adapter/src/error.rs b/aimdb-embassy-adapter/src/error.rs index 0052bf28..039846fc 100644 --- a/aimdb-embassy-adapter/src/error.rs +++ b/aimdb-embassy-adapter/src/error.rs @@ -14,6 +14,38 @@ use embedded_hal::i2c; use embedded_hal::spi; use embedded_hal_nb::nb; +// Embassy Error Code Base Values +const SPI_ERROR_BASE: u16 = 0x6100; +const UART_ERROR_BASE: u16 = 0x6200; +const I2C_ERROR_BASE: u16 = 0x6300; +const ADC_ERROR_BASE: u16 = 0x6400; +const GPIO_ERROR_BASE: u16 = 0x6500; +const TIMER_ERROR_BASE: u16 = 0x6600; + +// Component IDs for Embassy hardware +const TIMER_COMPONENT_ID: u8 = 0; +const GPIO_COMPONENT_ID: u8 = 1; +const SPI_COMPONENT_ID: u8 = 2; +const I2C_COMPONENT_ID: u8 = 3; +const UART_COMPONENT_ID: u8 = 4; +const ADC_COMPONENT_ID: u8 = 5; + +// SPI-specific error codes +const SPI_CHIP_SELECT_FAULT: u8 = 0x01; +const SPI_MODE_FAULT: u8 = 0x02; +const SPI_OVERRUN: u8 = 0x04; +const SPI_FRAME_FORMAT: u8 = 0x05; +const SPI_UNKNOWN_ERROR: u8 = 0xFF; + +// I2C-specific error codes +const I2C_BUS_ERROR: u8 = 0x01; +const I2C_ARBITRATION_LOSS: u8 = 0x02; +const I2C_NACK_ADDRESS: u8 = 0x03; +const I2C_NACK_DATA: u8 = 0x04; +const I2C_NACK_UNKNOWN: u8 = 0x05; +const I2C_OVERRUN: u8 = 0x06; +const I2C_UNKNOWN_ERROR: u8 = 0xFF; + /// Trait that provides Embassy-specific error constructors for DbError /// /// This trait provides hardware-specific error creation methods without requiring @@ -54,8 +86,8 @@ impl EmbassyErrorSupport for DbError { /// Creates an SPI error for Embassy environments (error codes 0x6100-0x61FF) fn from_spi_error(code: u8) -> Self { DbError::HardwareError { - component: 2, // SPI component ID - error_code: 0x6100 | (code as u16), + component: SPI_COMPONENT_ID, + error_code: SPI_ERROR_BASE | (code as u16), _description: (), } } @@ -63,8 +95,8 @@ impl EmbassyErrorSupport for DbError { /// Creates a UART error for Embassy environments (error codes 0x6200-0x62FF) fn from_uart_error(code: u8) -> Self { DbError::HardwareError { - component: 4, // UART component ID - error_code: 0x6200 | (code as u16), + component: UART_COMPONENT_ID, + error_code: UART_ERROR_BASE | (code as u16), _description: (), } } @@ -72,8 +104,8 @@ impl EmbassyErrorSupport for DbError { /// Creates an I2C error for Embassy environments (error codes 0x6300-0x63FF) fn from_i2c_error(code: u8) -> Self { DbError::HardwareError { - component: 3, // I2C component ID - error_code: 0x6300 | (code as u16), + component: I2C_COMPONENT_ID, + error_code: I2C_ERROR_BASE | (code as u16), _description: (), } } @@ -81,8 +113,8 @@ impl EmbassyErrorSupport for DbError { /// Creates an ADC error for Embassy environments (error codes 0x6400-0x64FF) fn from_adc_error(code: u8) -> Self { DbError::HardwareError { - component: 5, // ADC component ID - error_code: 0x6400 | (code as u16), + component: ADC_COMPONENT_ID, + error_code: ADC_ERROR_BASE | (code as u16), _description: (), } } @@ -90,8 +122,8 @@ impl EmbassyErrorSupport for DbError { /// Creates a GPIO error for Embassy environments (error codes 0x6500-0x65FF) fn from_gpio_error(code: u8) -> Self { DbError::HardwareError { - component: 1, // GPIO component ID - error_code: 0x6500 | (code as u16), + component: GPIO_COMPONENT_ID, + error_code: GPIO_ERROR_BASE | (code as u16), _description: (), } } @@ -99,8 +131,8 @@ impl EmbassyErrorSupport for DbError { /// Creates a Timer error for Embassy environments (error codes 0x6600-0x66FF) fn from_timer_error(code: u8) -> Self { DbError::HardwareError { - component: 0, // Timer component ID - error_code: 0x6600 | (code as u16), + component: TIMER_COMPONENT_ID, + error_code: TIMER_ERROR_BASE | (code as u16), _description: (), } } @@ -108,11 +140,11 @@ impl EmbassyErrorSupport for DbError { /// Converts an SPI error to DbError fn from_spi_hal_error(error: spi::ErrorKind) -> Self { let error_code = match error { - spi::ErrorKind::ChipSelectFault => 0x01, - spi::ErrorKind::ModeFault => 0x02, - spi::ErrorKind::Overrun => 0x04, - spi::ErrorKind::FrameFormat => 0x05, - _ => 0xFF, // Generic/unknown error + spi::ErrorKind::ChipSelectFault => SPI_CHIP_SELECT_FAULT, + spi::ErrorKind::ModeFault => SPI_MODE_FAULT, + spi::ErrorKind::Overrun => SPI_OVERRUN, + spi::ErrorKind::FrameFormat => SPI_FRAME_FORMAT, + _ => SPI_UNKNOWN_ERROR, // Generic/unknown error }; Self::from_spi_error(error_code) } @@ -120,13 +152,13 @@ impl EmbassyErrorSupport for DbError { /// Converts an I2C error to DbError fn from_i2c_hal_error(error: i2c::ErrorKind) -> Self { let error_code = match error { - i2c::ErrorKind::Bus => 0x01, - i2c::ErrorKind::ArbitrationLoss => 0x02, - i2c::ErrorKind::NoAcknowledge(i2c::NoAcknowledgeSource::Address) => 0x03, - i2c::ErrorKind::NoAcknowledge(i2c::NoAcknowledgeSource::Data) => 0x04, - i2c::ErrorKind::NoAcknowledge(i2c::NoAcknowledgeSource::Unknown) => 0x05, - i2c::ErrorKind::Overrun => 0x06, - _ => 0xFF, // Generic/unknown error + i2c::ErrorKind::Bus => I2C_BUS_ERROR, + i2c::ErrorKind::ArbitrationLoss => I2C_ARBITRATION_LOSS, + i2c::ErrorKind::NoAcknowledge(i2c::NoAcknowledgeSource::Address) => I2C_NACK_ADDRESS, + i2c::ErrorKind::NoAcknowledge(i2c::NoAcknowledgeSource::Data) => I2C_NACK_DATA, + i2c::ErrorKind::NoAcknowledge(i2c::NoAcknowledgeSource::Unknown) => I2C_NACK_UNKNOWN, + i2c::ErrorKind::Overrun => I2C_OVERRUN, + _ => I2C_UNKNOWN_ERROR, // Generic/unknown error }; Self::from_i2c_error(error_code) } @@ -135,6 +167,7 @@ impl EmbassyErrorSupport for DbError { fn from_nb_error(error: nb::Error) -> Self where E: Into, + Self: Sized, { match error { nb::Error::Other(e) => e.into(), @@ -185,8 +218,8 @@ mod tests { .. } = spi_error { - assert_eq!(component, 2); // SPI component ID - assert_eq!(error_code, 0x6142); // 0x6100 | 0x42 + assert_eq!(component, SPI_COMPONENT_ID); + assert_eq!(error_code, SPI_ERROR_BASE | 0x42); } else { panic!("Expected HardwareError variant"); } @@ -199,8 +232,8 @@ mod tests { .. } = uart_error { - assert_eq!(component, 4); // UART component ID - assert_eq!(error_code, 0x6210); // 0x6200 | 0x10 + assert_eq!(component, UART_COMPONENT_ID); + assert_eq!(error_code, UART_ERROR_BASE | 0x10); } else { panic!("Expected HardwareError variant"); } @@ -213,8 +246,8 @@ mod tests { .. } = i2c_error { - assert_eq!(component, 3); // I2C component ID - assert_eq!(error_code, 0x6305); // 0x6300 | 0x05 + assert_eq!(component, I2C_COMPONENT_ID); + assert_eq!(error_code, I2C_ERROR_BASE | 0x05); } else { panic!("Expected HardwareError variant"); } @@ -227,8 +260,8 @@ mod tests { .. } = adc_error { - assert_eq!(component, 5); // ADC component ID - assert_eq!(error_code, 0x6420); // 0x6400 | 0x20 + assert_eq!(component, ADC_COMPONENT_ID); + assert_eq!(error_code, ADC_ERROR_BASE | 0x20); } else { panic!("Expected HardwareError variant"); } @@ -241,8 +274,8 @@ mod tests { .. } = gpio_error { - assert_eq!(component, 1); // GPIO component ID - assert_eq!(error_code, 0x6508); // 0x6500 | 0x08 + assert_eq!(component, GPIO_COMPONENT_ID); + assert_eq!(error_code, GPIO_ERROR_BASE | 0x08); } else { panic!("Expected HardwareError variant"); } @@ -255,8 +288,8 @@ mod tests { .. } = timer_error { - assert_eq!(component, 0); // Timer component ID - assert_eq!(error_code, 0x66FF); // 0x6600 | 0xFF + assert_eq!(component, TIMER_COMPONENT_ID); + assert_eq!(error_code, TIMER_ERROR_BASE | 0xFF); } else { panic!("Expected HardwareError variant"); } @@ -274,8 +307,8 @@ mod tests { .. } = spi_overrun { - assert_eq!(component, 2); // SPI component - assert_eq!(error_code, 0x6104); // 0x6100 | 0x04 + assert_eq!(component, SPI_COMPONENT_ID); + assert_eq!(error_code, SPI_ERROR_BASE | SPI_OVERRUN as u16); } else { panic!("Expected HardwareError variant"); } @@ -287,8 +320,8 @@ mod tests { .. } = spi_mode_fault { - assert_eq!(component, 2); // SPI component - assert_eq!(error_code, 0x6102); // 0x6100 | 0x02 + assert_eq!(component, SPI_COMPONENT_ID); + assert_eq!(error_code, SPI_ERROR_BASE | SPI_MODE_FAULT as u16); } else { panic!("Expected HardwareError variant"); } @@ -301,8 +334,8 @@ mod tests { .. } = i2c_bus_error { - assert_eq!(component, 3); // I2C component - assert_eq!(error_code, 0x6301); // 0x6300 | 0x01 + assert_eq!(component, I2C_COMPONENT_ID); + assert_eq!(error_code, I2C_ERROR_BASE | I2C_BUS_ERROR as u16); } else { panic!("Expected HardwareError variant"); } @@ -316,8 +349,8 @@ mod tests { .. } = i2c_nack { - assert_eq!(component, 3); // I2C component - assert_eq!(error_code, 0x6303); // 0x6300 | 0x03 + assert_eq!(component, I2C_COMPONENT_ID); + assert_eq!(error_code, I2C_ERROR_BASE | I2C_NACK_ADDRESS as u16); } else { panic!("Expected HardwareError variant"); } @@ -385,8 +418,8 @@ mod tests { .. } = spi_error { - assert_eq!(component, 2); // SPI component - assert_eq!(error_code, 0x6104); // 0x6100 | 0x04 (Overrun) - component-specific code + assert_eq!(component, SPI_COMPONENT_ID); + assert_eq!(error_code, SPI_ERROR_BASE | SPI_OVERRUN as u16); // component-specific code } else { panic!("Expected HardwareError variant"); } @@ -400,8 +433,8 @@ mod tests { .. } = i2c_error { - assert_eq!(component, 3); // I2C component - assert_eq!(error_code, 0x6301); // 0x6300 | 0x01 (Bus) - component-specific code + assert_eq!(component, I2C_COMPONENT_ID); + assert_eq!(error_code, I2C_ERROR_BASE | I2C_BUS_ERROR as u16); // component-specific code } else { panic!("Expected HardwareError variant"); } From 9c7f7028eefa3ccdb4917d1b307f96eb50cdf2f2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Schn=C3=B6rch?= Date: Sat, 27 Sep 2025 19:32:15 +0000 Subject: [PATCH 14/15] refactor linker check to avoid false positives with linker names --- aimdb-embassy-adapter/build.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/aimdb-embassy-adapter/build.rs b/aimdb-embassy-adapter/build.rs index 04229d6d..d2cfe9b0 100644 --- a/aimdb-embassy-adapter/build.rs +++ b/aimdb-embassy-adapter/build.rs @@ -35,7 +35,17 @@ fn main() { let linker = env::var(&linker_env) .or_else(|_| env::var("RUSTC_LINKER")) .unwrap_or_default(); - if linker.contains("ld") { + + // Check for GNU ld specifically, avoiding false positives with lld or paths containing 'ld' + let linker_name = linker + .split('/') + .last() + .unwrap_or(&linker) + .split('\\') + .last() + .unwrap_or(&linker); + + if linker_name == "ld" || linker_name.starts_with("arm-") && linker_name.ends_with("-ld") { println!("cargo:rustc-link-arg=-Wl,--gc-sections"); } println!("cargo:rustc-cfg=embedded_target"); From 9343f4191f4eae4415b92c7751eae500bd50267f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20Schn=C3=B6rch?= Date: Sat, 27 Sep 2025 19:35:10 +0000 Subject: [PATCH 15/15] refactor linker name extraction to improve clarity and avoid false positives --- aimdb-embassy-adapter/build.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/aimdb-embassy-adapter/build.rs b/aimdb-embassy-adapter/build.rs index d2cfe9b0..1b010a7b 100644 --- a/aimdb-embassy-adapter/build.rs +++ b/aimdb-embassy-adapter/build.rs @@ -39,10 +39,10 @@ fn main() { // Check for GNU ld specifically, avoiding false positives with lld or paths containing 'ld' let linker_name = linker .split('/') - .last() + .next_back() .unwrap_or(&linker) .split('\\') - .last() + .next_back() .unwrap_or(&linker); if linker_name == "ld" || linker_name.starts_with("arm-") && linker_name.ends_with("-ld") {