Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .vscode/mcp.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
"--manifest-path",
"${workspaceFolder}/tools/aimdb-mcp/Cargo.toml",
"--",
"--socket",
"/tmp/aimdb-demo.sock"
"--connect",
"unix:///tmp/aimdb-demo.sock"
]
}
}
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,12 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- **Embassy buffer + join-queue tests now run in CI (Issue #85).** The join-queue tests previously sat behind `embassy-runtime`, which pulls `embassy-executor`'s cortex-m assembly and can't compile under `cargo test` on x86_64 — so ordering / backpressure / clone-routing regressions were never caught. The `join_queue` module is now gated on `embassy-sync`, and `make test` runs the embassy adapter's unit tests + doctests on the host (no executor). Also adds `EmbassyBuffer::peek()` and fixes a stale `EmbassyBuffer` doc example. ([aimdb-embassy-adapter](aimdb-embassy-adapter/CHANGELOG.md))
- **`no_std` AimX server — a board can serve a host, not just dial one (Issue #120, follow-up to #39).** Cross-cutting de-std of `aimdb-core`'s central record API behind a new **`remote-access`** feature (`= ["json-serialize", "thiserror"]`, transitively enabled by `std`): the type-erased `AnyRecord` JSON + metadata methods, the `AimDb` JSON read/write/subscribe API, the `remote` module (config / protocol / security / error), and the AimX server dispatch (`AimxDispatch`/`AimxSession`) now all compile on `no_std + alloc` — swapping `std::collections` → `hashbrown`, `std::sync::Arc` → `alloc::sync::Arc`, and `thiserror` to `default-features = false`. Adds a runtime-neutral wall clock, `TimeOps::unix_time()`, implemented from the OS clock on Tokio and from an `EmbassyAdapter::set_unix_time(...)` anchor on Embassy. Verified by a new `thumbv7em-none-eabihf` dispatch cross-check in the Makefile. ([aimdb-core](aimdb-core/CHANGELOG.md), [aimdb-executor](aimdb-executor/CHANGELOG.md), [aimdb-tokio-adapter](aimdb-tokio-adapter/CHANGELOG.md), [aimdb-embassy-adapter](aimdb-embassy-adapter/CHANGELOG.md), [aimdb-uds-connector](aimdb-uds-connector/CHANGELOG.md), [tools/aimdb-mcp](tools/aimdb-mcp/CHANGELOG.md))
- **`aimdb-serial-connector` — COBS-framed serial/UART transport, the headline embedded scenario (Issue #122, follow-up to #39 / #120).** New crate: a sensor MCU dials a gateway over UART (and, on the `no_std` `AimxDispatch` from #120, an MCU *serves* a host over UART). Contributes only the `Dialer`/`Listener`/`Connection` triple + `SerialClient`/`SerialServer` sugar over the `serial://` scheme; reuses the AimX codec/dispatch and the session engines from core. Same compact AimX JSON, framed with **COBS** + a `0x00` sentinel (self-synchronizing on a lossy serial line). Dual halves: a std `tokio-runtime` (`tokio-serial`) riding the generic `Session*Connector`, and a `no_std + alloc` `embassy-runtime` generic over `embedded-io-async` UART halves that hand-rolls `ConnectorBuilder` and force-`Send`s the single-core futures via `SendFutureWrapper`. Cross-compiles to `thumbv7em-none-eabihf` (new Makefile `test-embedded` checks). Ships a real end-to-end demo: a host `serial_demo` example and an `embassy-serial-connector-demo` STM32H563ZI firmware (serves a record over USART3 ↔ the ST-LINK Virtual COM Port, queried from the host). The workspace `embedded-io-async` dep is bumped 0.6 → 0.7 to match the Embassy STM32 HAL. ([aimdb-serial-connector](aimdb-serial-connector/CHANGELOG.md))
- **Transport-agnostic host client — pick the transport at runtime with `--connect <scheme://url>` (Issue #123, follow-up to #39 / #122).** `aimdb-client` gains an `endpoint` resolver (`unix://` / `uds://` / bare path / `serial://DEVICE?baud=N`) over a new `impl Dialer for Box<dyn Dialer>` in `aimdb-core`; `AimxConnection::connect` takes an endpoint string, and transports are opt-in features (`transport-uds` default, `transport-serial` off-by-default). The `aimdb` CLI replaces the per-command `--socket` flags with a global `--connect` (+ `AIMDB_CONNECT`), and `aimdb-mcp` tools take an `endpoint` param with `--connect`/`AIMDB_CONNECT` (was `socket_path`/`--socket`/`AIMDB_SOCKET`). See **breaking** below. ([aimdb-client](aimdb-client/CHANGELOG.md), [tools/aimdb-cli](tools/aimdb-cli/CHANGELOG.md), [tools/aimdb-mcp](tools/aimdb-mcp/CHANGELOG.md), [aimdb-core](aimdb-core/CHANGELOG.md))

### Changed (breaking)

- **CLI/MCP endpoint surface reworked to `--connect <url>` (Issue #123).** `aimdb`'s per-command `--socket <path>` is replaced by a global `--connect <endpoint>` (`AIMDB_CONNECT` env; bare paths still work). `aimdb-mcp` renames the tools' `socket_path` param to `endpoint`, the startup `--socket` to `--connect`, and `AIMDB_SOCKET` to `AIMDB_CONNECT`; the pool is keyed by endpoint URL. `aimdb-client`'s `AimxConnection::connect` takes a `&str` endpoint (was a path) and `ClientError::ConnectionFailed.socket` is renamed `endpoint`. Serial endpoints (`serial://…`) require building the CLI/MCP with `--features transport-serial`. ([aimdb-client](aimdb-client/CHANGELOG.md), [tools/aimdb-cli](tools/aimdb-cli/CHANGELOG.md), [tools/aimdb-mcp](tools/aimdb-mcp/CHANGELOG.md))

- **`AimDbBuilder::with_remote_access(config)` removed — remote-access servers are now registered like any other connector (Issue #39).** Replace `.with_remote_access(config)` with `.with_connector(aimdb_uds_connector::UdsServer::from_config(config))`. The AimX wire was reshaped to **v2** (NDJSON tagged frames mapping onto the engine's role-neutral message set) and is **not** backward-compatible with the legacy AimX v1 framing; the bundled `aimdb-client` / CLI / MCP speak v2. The UDS transport types moved out of `aimdb-core` into `aimdb-uds-connector`. ([aimdb-core](aimdb-core/CHANGELOG.md), [aimdb-uds-connector](aimdb-uds-connector/CHANGELOG.md), [aimdb-client](aimdb-client/CHANGELOG.md))
- **M15 — `latest_snapshot` removed; point-in-time reads go through the new buffer-native `DynBuffer::peek()` ([Design 031](docs/design/031-M15-remove-latest-snapshot.md)).** `TypedRecord::latest()` and AimX `record.get` read the buffer directly instead of a per-record snapshot mutex (one lock + clone off the `produce()` hot path). Consequences: a `.with_remote_access()` record with **no buffer** now fails `build()` (was a silent runtime no-op); `record.get` / `latest()` on an `SpmcRing` record returns `not_found` / `None` (rings have no canonical latest — use `record.drain` / `record.subscribe`); `SingleLatest` and `Mailbox` are unaffected. `TypedRecord::produce` is removed — all writes go through `WriteHandle::push`. Adapters implement `peek()` per buffer type. ([aimdb-core](aimdb-core/CHANGELOG.md), [aimdb-tokio-adapter](aimdb-tokio-adapter/CHANGELOG.md), [aimdb-embassy-adapter](aimdb-embassy-adapter/CHANGELOG.md), [aimdb-wasm-adapter](aimdb-wasm-adapter/CHANGELOG.md))
- **M16 — `with_remote_access()` now requires the `json-serialize` feature (transitively enabled by `std`); `with_read_only_serialization()` removed ([Design 032](docs/design/032-M16-aimx-json-codec.md)).** The stored serializer/deserializer closures are replaced by a type-erased `Arc<dyn JsonCodec<T>>`. A `Serialize`-only record can no longer be exposed read-only over remote access. ([aimdb-core](aimdb-core/CHANGELOG.md))
Expand Down
6 changes: 5 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

8 changes: 8 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,8 @@ test:
cargo test --package aimdb-core --features "std,connector-session" --test session_engine
@printf "$(YELLOW) → Testing aimdb-client (engine-based AimX client + UDS round-trip)$(NC)\n"
cargo test --package aimdb-client
@printf "$(YELLOW) → Testing aimdb-client (endpoint resolver, serial transport arm)$(NC)\n"
cargo test --package aimdb-client --no-default-features --features "transport-serial"
@printf "$(YELLOW) → Testing tokio adapter$(NC)\n"
cargo test --package aimdb-tokio-adapter --features "tokio-runtime,tracing"
@printf "$(YELLOW) → Testing tokio adapter (with metrics)$(NC)\n"
Expand Down Expand Up @@ -222,12 +224,18 @@ clippy:
cargo clippy --package aimdb-sync --all-targets -- -D warnings
@printf "$(YELLOW) → Clippy on client library$(NC)\n"
cargo clippy --package aimdb-client --all-targets -- -D warnings
@printf "$(YELLOW) → Clippy on client library (serial transport arm)$(NC)\n"
cargo clippy --package aimdb-client --no-default-features --features "transport-serial" --all-targets -- -D warnings
@printf "$(YELLOW) → Clippy on codegen library$(NC)\n"
cargo clippy --package aimdb-codegen --all-targets -- -D warnings
@printf "$(YELLOW) → Clippy on CLI tools$(NC)\n"
cargo clippy --package aimdb-cli --all-targets -- -D warnings
@printf "$(YELLOW) → Clippy on CLI tools (serial transport)$(NC)\n"
cargo clippy --package aimdb-cli --features "transport-serial" --all-targets -- -D warnings
@printf "$(YELLOW) → Clippy on MCP server$(NC)\n"
cargo clippy --package aimdb-mcp --all-targets -- -D warnings
@printf "$(YELLOW) → Clippy on MCP server (serial transport)$(NC)\n"
cargo clippy --package aimdb-mcp --features "transport-serial" --all-targets -- -D warnings
@printf "$(YELLOW) → Clippy on persistence backend$(NC)\n"
cargo clippy --package aimdb-persistence --all-targets -- -D warnings
@printf "$(YELLOW) → Clippy on persistence SQLite backend$(NC)\n"
Expand Down
2 changes: 1 addition & 1 deletion _external/embassy
Submodule embassy updated 44 files
+1 −1 .github/ci/build-nightly.sh
+1 −1 .github/ci/build-xtensa.sh
+1 −1 .github/ci/build.sh
+1 −1 .github/ci/doc.sh
+1 −1 .github/ci/janitor.sh
+4 −1 ci.sh
+55 −5 embassy-mcxa/src/i2c/target.rs
+117 −32 embassy-mcxa/src/lpuart/bbq.rs
+22 −28 embassy-stm32-wpan/src/wba/platform.rs
+82 −2 embassy-stm32/Cargo.toml
+1 −6 embassy-stm32/build.rs
+1 −15 embassy-stm32/src/adc/ringbuffered.rs
+69 −2 embassy-stm32/src/comp.rs
+158 −110 embassy-stm32/src/dac/mod.rs
+6 −7 embassy-stm32/src/dac/ringbuffered.rs
+8 −10 embassy-stm32/src/dma/dma_bdma.rs
+10 −10 embassy-stm32/src/dma/gpdma/linked_list.rs
+6 −6 embassy-stm32/src/dma/gpdma/ringbuffered.rs
+3 −3 embassy-stm32/src/dma/ringbuffer/mod.rs
+68 −2 embassy-stm32/src/dma/ringbuffer/tests/mod.rs
+0 −1 embassy-stm32/src/hrtim/mod.rs
+2 −1 embassy-stm32/src/hrtim/stm32_hrtim.rs
+5 −4 embassy-stm32/src/i2s.rs
+18 −5 embassy-stm32/src/lib.rs
+5 −5 embassy-stm32/src/low_power.rs
+2 −2 embassy-stm32/src/sai/mod.rs
+7 −7 embassy-stm32/src/timer/input_capture.rs
+20 −0 embassy-stm32/src/usart/mod.rs
+3 −0 embassy-usb/src/class/dfu/dfu_mode.rs
+1 −2 examples/stm32f1/src/bin/input_capture.rs
+2 −2 examples/stm32f4/src/bin/dac.rs
+1 −1 examples/stm32f4/src/bin/input_capture.rs
+1 −10 examples/stm32f4/src/bin/input_capture_split.rs
+1 −1 examples/stm32g0/src/bin/input_capture.rs
+4 −4 examples/stm32g4/src/bin/dac_dma_circular.rs
+59 −6 examples/stm32g4/src/bin/input_capture.rs
+2 −2 examples/stm32h7/src/bin/dac.rs
+3 −3 examples/stm32h7/src/bin/dac_dma.rs
+2 −2 examples/stm32l4/src/bin/dac.rs
+3 −3 examples/stm32l4/src/bin/dac_dma.rs
+2 −2 examples/stm32u0/src/bin/dac.rs
+1 −1 tests/stm32/src/bin/afio.rs
+3 −3 tests/stm32/src/bin/dac.rs
+3 −3 tests/stm32/src/bin/dac_l1.rs
5 changes: 5 additions & 0 deletions aimdb-client/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

### Added

- **Transport-agnostic endpoint resolver — pick the transport at runtime via a `scheme://` URL (Issue #123, follow-up to #39 / #122).** New `endpoint` module: `parse_endpoint` (pure, feature-independent grammar) and `dial(url) -> Box<dyn Dialer>` map an endpoint string to a transport `Dialer`, the way records already pick one for links. Schemes: `unix://PATH` / `uds://PATH`, a bare path (the `unix://` shorthand), and `serial://DEVICE?baud=N`. An unknown scheme — or one whose transport isn't compiled in — is rejected with a clear error. New `AimxConnection::connect_over(dialer)` / `connect_over_with_timeout` dial over an explicit `Dialer`, bypassing resolution. (Rides a new `impl Dialer for Box<dyn Dialer>` in `aimdb-core`.)

### Changed (breaking)

- **`AimxConnection::connect` now takes a `&str` endpoint, and transports are feature-gated (Issue #123).** `connect`/`connect_with_timeout` accept an endpoint string (was `impl AsRef<Path>`) — a `scheme://` URL or a bare path — resolved through the new `endpoint` module. The transports are now opt-in Cargo features: `transport-uds` (default; makes `aimdb-uds-connector` optional and gates the `discovery` module — a Unix-socket scan) and `transport-serial` (off by default; pulls `aimdb-serial-connector`, i.e. `tokio-serial` → libudev). `ClientError::ConnectionFailed`'s `socket` field is renamed `endpoint`, and a new `ClientError::UnsupportedEndpoint` covers malformed / not-built-in endpoints. The discovery `InstanceInfo.socket_path` field is likewise renamed `endpoint` — it now also carries a caller-supplied endpoint, not just a discovered socket path.
- **`AimxClient` → `AimxConnection`, rebuilt on the shared session engine (Issue #39, [design doc](../docs/design/remote-access-via-connectors.md)).** The synchronous `connection::AimxClient` is retired; the new `engine::AimxConnection` drives `aimdb-core`'s `run_client` engine over `aimdb-uds-connector`'s `UdsDialer` and speaks the reshaped **AimX-v2** protocol. Both the type and the module are re-exported from the crate root (`aimdb_client::AimxConnection`); the `connection` module is replaced by `engine`. `connect()` performs the `hello` handshake, and the full tool surface (list/get/set/subscribe/drain/graph/query) is available.
- `subscribe(record_name)` now returns a `Stream` of updates directly — the engine routes events back by request id, so there is **no** server-allocated subscription id to track (the old `(subscription_id, queue_size)` handshake is gone).
- New `connect_with_timeout(path, timeout)` bounds the whole dial + handshake (used by discovery probing).
Expand Down
16 changes: 13 additions & 3 deletions aimdb-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,9 +10,16 @@ keywords = ["client", "protocol", "database", "remote", "rpc"]
categories = ["database", "network-programming"]

[features]
default = ["transport-uds"]
metrics = ["aimdb-core/metrics"]
profiling = ["aimdb-core/profiling"]

# Transports the endpoint resolver (`crate::endpoint`) can dial. Each gates its
# connector dep + the matching `dial`/`parse` arm; an endpoint whose scheme isn't
# compiled in is rejected at resolve time.
transport-uds = ["dep:aimdb-uds-connector"]
transport-serial = ["dep:aimdb-serial-connector"]

[dependencies]
# Core dependencies - protocol types from aimdb-core. `connector-session`
# exposes the shared session engine (`run_client`/`ClientHandle`) plus the AimX
Expand All @@ -22,9 +29,12 @@ aimdb-core = { version = "1.1.0", path = "../aimdb-core", features = [
"connector-session",
] }

# The UDS transport (`UdsDialer`) relocated out of core in Phase 6; the
# engine-based client dials over it.
aimdb-uds-connector = { version = "0.1.0", path = "../aimdb-uds-connector" }
# Transports the resolver dials over (relocated out of core in Phase 6), each
# behind its `transport-*` feature so a binary links only what it needs.
aimdb-uds-connector = { version = "0.1.0", path = "../aimdb-uds-connector", optional = true }
aimdb-serial-connector = { version = "0.1.0", path = "../aimdb-serial-connector", default-features = false, features = [
"tokio-runtime",
], optional = true }

# Serialization
serde = { version = "1", features = ["derive"] }
Expand Down
16 changes: 9 additions & 7 deletions aimdb-client/src/discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
use crate::engine::AimxConnection;
use crate::error::{ClientError, ClientResult};
use crate::protocol::WelcomeMessage;
use std::path::PathBuf;
use std::path::{Path, PathBuf};
use std::time::Duration;

/// Known directories where AimDB sockets might be located
Expand All @@ -14,7 +14,7 @@ const SOCKET_SEARCH_DIRS: &[&str] = &["/tmp", "/var/run/aimdb"];
/// Information about a discovered AimDB instance
#[derive(Debug, Clone)]
pub struct InstanceInfo {
pub socket_path: PathBuf,
pub endpoint: PathBuf,
pub server_version: String,
pub protocol_version: String,
pub permissions: Vec<String>,
Expand All @@ -24,9 +24,9 @@ pub struct InstanceInfo {
}

impl From<(PathBuf, WelcomeMessage)> for InstanceInfo {
fn from((socket_path, welcome): (PathBuf, WelcomeMessage)) -> Self {
fn from((endpoint, welcome): (PathBuf, WelcomeMessage)) -> Self {
Self {
socket_path,
endpoint,
server_version: welcome.server,
protocol_version: welcome.version,
permissions: welcome.permissions,
Expand Down Expand Up @@ -74,16 +74,18 @@ async fn scan_directory(mut entries: tokio::fs::ReadDir) -> Vec<InstanceInfo> {
}

/// Try to connect to a socket and get instance information
async fn probe_instance(socket_path: &PathBuf) -> ClientResult<InstanceInfo> {
async fn probe_instance(socket_path: &Path) -> ClientResult<InstanceInfo> {
// `connect_with_timeout` bounds the whole handshake (dial + hello), so a stale
// socket whose peer accepts but never replies fails fast instead of hanging —
// no need to wrap a second timeout around `connect`.
let connect_timeout = Duration::from_millis(500);
let client = AimxConnection::connect_with_timeout(socket_path, connect_timeout).await?;
// A discovered socket path is dialed as the bare-path (`unix://`) shorthand.
let endpoint = socket_path.to_string_lossy();
let client = AimxConnection::connect_with_timeout(&endpoint, connect_timeout).await?;

let welcome = client.server_info().clone();

Ok(InstanceInfo::from((socket_path.clone(), welcome)))
Ok(InstanceInfo::from((socket_path.to_path_buf(), welcome)))
}

/// Find a specific instance by socket path or name
Expand Down
Loading