Skip to content

Commit 3f896ac

Browse files
committed
chore: update tomls
1 parent 4fb842e commit 3f896ac

21 files changed

Lines changed: 377 additions & 0 deletions

File tree

crates/ace-can/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22
name = "ace-can"
33
version = "0.1.0"
44
edition = "2024"
5+
authors = ["Samuel Preston <samp.reston@outlook.com>"]
6+
description = "ISO-TP implementation. Provides the reassembler and segmenter used by an IsoTpNode to bridge DoIP UDS payloads to CAN frames."
7+
readme = "README.md"
8+
repository = "https://github.com/samp-reston/ace"
9+
license = "MIT or Apache-2.0"
10+
keywords = ["diagnostics", "vehicle", "standards"]
11+
categories = ["development-tools", "network-programming", "automotive"]
512

613
[features]
714
default = []

crates/ace-can/README.md

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
# `ace-can`
2+
3+
ISO-TP implementation (ISO 15765-2). Provides the reassembler and segmenter used by `ace-gateway`'s `IsoTpNode` to bridge DoIP UDS payloads to CAN frames.
4+
5+
**Design:** addressing mode (Normal / Extended / Mixed) is a caller concern. The reassembler and segmenter operate on pure PCI bytes — callers strip/prepend the address byte at the transport boundary.
6+
7+
```rust
8+
// Segmenter — owns its payload buffer, no lifetime, no unsafe
9+
let mut seg = Segmenter::<4096>::new(SegmenterConfig::classic(Normal));
10+
seg.start(&uds_payload)?;
11+
12+
let mut out = [0u8; 8];
13+
loop {
14+
match seg.next_frame(&mut out)? {
15+
SegmentResult::Frame { len } => { /* put out[..len] on CAN bus */ }
16+
SegmentResult::Complete => break,
17+
SegmentResult::WaitForFlowControl => {
18+
// wait for FC from receiver then call seg.handle_flow_control(fc)
19+
}
20+
}
21+
}
22+
```
23+
24+
```rust
25+
// Reassembler
26+
let mut rsm = Reassembler::<4096>::new(ReassemblerConfig::new(Normal));
27+
match rsm.feed(&can_frame_bytes)? {
28+
ReassembleResult::Complete { len } => { /* rsm.message(len) */ }
29+
ReassembleResult::FlowControl { .. } => { /* send FC back */ }
30+
ReassembleResult::InProgress => {}
31+
ReassembleResult::SessionAborted { .. } => {}
32+
}
33+
```

crates/ace-client/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22
name = "ace-client"
33
version = "0.1.0"
44
edition = "2024"
5+
authors = ["Samuel Preston <samp.reston@outlook.com>"]
6+
description = "UDS tester client state machine."
7+
readme = "README.md"
8+
repository = "https://github.com/samp-reston/ace"
9+
license = "MIT or Apache-2.0"
10+
keywords = ["diagnostics", "vehicle", "standards"]
11+
categories = ["development-tools", "network-programming", "automotive"]
512

613
[features]
714
default = []

crates/ace-client/README.md

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# `ace-client`
2+
3+
UDS tester client state machine (ISO 14229-1 tester side).
4+
5+
A dumb request/response pipe. Sends raw UDS frames, emits `ClientEvent`s as responses arrive. Tracks P2/P2* timeouts per pending request. Session state, security state, and retry logic are the caller's responsibility.
6+
7+
```rust
8+
let mut client = UdsClient::<1>::new(config, address);
9+
10+
// Send a request
11+
client.request(&[0x10, 0x03], now)?;
12+
13+
// After ticking, drain events
14+
for event in client.drain_events() {
15+
match event {
16+
ClientEvent::PositiveResponse { sid, data } => { /* ... */ }
17+
ClientEvent::NegativeResponse { sid, nrc } => { /* ... */ }
18+
ClientEvent::ResponsePending { sid } => { /* extended timeout active */ }
19+
ClientEvent::Timeout { sid } => { /* no response in time */ }
20+
ClientEvent::PeriodicData { did, data } => { /* periodic DID data */ }
21+
ClientEvent::Unsolicited { data } => { /* unmatched frame */ }
22+
}
23+
}
24+
```
25+
26+
Periodic DID subscriptions control classification of `0xF2xx` response frames:
27+
28+
```rust
29+
client.subscribe_periodic(0x90); // DID 0xF290 low byte
30+
client.unsubscribe_periodic(0x90);
31+
```

crates/ace-core/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22
name = "ace-core"
33
version = "0.1.0"
44
edition = "2024"
5+
authors = ["Samuel Preston <samp.reston@outlook.com>"]
6+
description = "Foundation layer, providing three codec traits that the rest of ACE builds on: FrameRead, FrameWrite, Writer"
7+
readme = "README.md"
8+
repository = "https://github.com/samp-reston/ace"
9+
license = "MIT or Apache-2.0"
10+
keywords = ["diagnostics", "vehicle", "standards"]
11+
categories = ["development-tools", "network-programming", "automotive"]
512

613
[features]
714
default = []

crates/ace-core/README.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# `ace-core`
2+
3+
Foundation layer. Defines the three codec traits that everything else builds on:
4+
5+
- `FrameRead<'a>` — zero-copy decode from a `&mut &'a [u8]` cursor
6+
- `FrameWrite` — encode into a `Writer` (either `&mut [u8]` or `BytesMut`)
7+
- `Writer` — sealed trait abstracting alloc and no-alloc write targets
8+
9+
Also provides `DiagError`, `AddressMode`, `DiagnosticAddress`, and the `FrameIter<'a, T>` lazy iterator for variable-length repeated fields.
10+
11+
```toml
12+
[dependencies]
13+
ace-core = { path = "../ace-core", default-features = false }
14+
```

crates/ace-doip/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22
name = "ace-doip"
33
version = "0.1.0"
44
edition = "2024"
5+
authors = ["Samuel Preston <samp.reston@outlook.com>"]
6+
description = "DoIP typed message and session layer implementing ISO 13400-2."
7+
readme = "README.md"
8+
repository = "https://github.com/samp-reston/ace"
9+
license = "MIT or Apache-2.0"
10+
keywords = ["diagnostics", "vehicle", "standards"]
11+
categories = ["development-tools", "network-programming", "automotive"]
512

613
[features]
714
default = []

crates/ace-doip/README.md

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
# `ace-doip`
2+
3+
DoIP typed message and session layer implementing ISO 13400-2.
4+
5+
**Message layer** — all payload types as structs deriving `FrameCodec`: `RoutingActivationRequest`, `RoutingActivationResponse`, `DiagnosticMessage`, `DiagnosticMessageAck`, `DiagnosticMessageNack`, `VehicleAnnouncementMessage`, `EntityStatusResponse`, `AliveCheckRequest`, `AliveCheckResponse`, and more.
6+
7+
**Session layer**`ActivationStateMachine` and `ConnectionState` model the per-TCP-connection routing activation lifecycle:
8+
9+
```
10+
Idle → ActivationPending → Active → Deactivated
11+
```
12+
13+
`ActivationAuthProvider` is a hook trait for OEM-specific authentication on `CentralSecurity` (0xFF) activation:
14+
15+
```rust
16+
pub trait ActivationAuthProvider {
17+
fn authenticate(
18+
&mut self,
19+
source_address: u16,
20+
oem_data: &[u8],
21+
) -> Result<(), ActivationDenialReason>;
22+
}
23+
```
24+
25+
`DoipFrameExt` provides semantic accessors on `DoipFrame`:
26+
27+
```rust
28+
frame.validate_header()?; // checks version, inverse, type, length
29+
frame.payload_type(); // Option<Result<PayloadType, _>>
30+
frame.payload_bytes(); // Option<&[u8]> — bytes after 8-byte header
31+
frame.payload_length_declared(); // length from header bytes 4-7
32+
```

crates/ace-gateway/Cargo.toml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,13 @@
22
name = "ace-gateway"
33
version = "0.1.0"
44
edition = "2024"
5+
authors = ["Samuel Preston <samp.reston@outlook.com>"]
6+
description = "DoIP Gateway, ISO-TP bridge node, and DoIP Tester"
7+
readme = "README.md"
8+
repository = "https://github.com/samp-reston/ace"
9+
license = "MIT or Apache-2.0"
10+
keywords = ["diagnostics", "vehicle", "standards"]
11+
categories = ["development-tools", "network-programming", "automotive"]
512

613
[dependencies]
714
ace-sim = { path = "../ace-sim", default-features = false }

crates/ace-gateway/README.md

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
# `ace-gateway`
2+
3+
DoIP gateway, ISO-TP bridge node, and DoIP tester.
4+
5+
**`DoipGateway<A, MAX_TESTERS, BUF>`** — gateway state machine. Translates DoIP frames from TCP into UDS bytes on CAN, and CAN responses back into DoIP frames. Has two faces — `handle_tcp` and `handle_can` — because it spans two buses. Routing table maps DoIP logical addresses to CAN IDs.
6+
7+
**`IsoTpNode<N>`** — bridges raw UDS bytes to ISO-TP CAN frames. Two independent segmenters (request and response directions) to handle concurrent multi-frame exchanges. Key methods: `handle_from_gateway(uds_data)`, `handle_uds_response(uds_data)`, `handle_from_ecu(can_frame)`.
8+
9+
**`DoipTester<MAX_CONNECTIONS, MAX_TARGETS>`** — models a physical DoIP tester device. Owns multiple `DoipConnection`s (one per TCP connection). Each connection addresses multiple ECUs simultaneously via `target_address`. P2/P2* timeouts are learned dynamically from `DiagnosticSessionControlResponse`. Events are tagged `(ConnectionId, TargetId, DoipTesterEvent)`.
10+
11+
```rust
12+
let mut tester = DoipTester::<4, 8>::new(0x0E00, NodeAddress(0x0E00));
13+
14+
// Open a connection to a gateway
15+
let conn = tester.open_connection(DoipConnectionConfig::new(0x0E80))?;
16+
17+
// After TCP connects (TcpSimBus::connect or real TcpStream):
18+
// tester.on_tcp_event(&TcpEvent::ConnectionEstablished { .. }, now);
19+
// → automatically sends RoutingActivationRequest
20+
21+
// Send UDS to ECU 0x0001 on that connection
22+
tester.request(conn, 0x0001, &[0x10, 0x03], now)?;
23+
24+
// Drain events
25+
for (conn_id, target_id, event) in tester.drain_events() {
26+
// ...
27+
}
28+
```
29+
30+
Node profiles accumulate from UDP announcements:
31+
32+
```rust
33+
if let Some(profile) = tester.profile(0x0E80) {
34+
println!("VIN: {:?}", profile.vin);
35+
}
36+
```
37+
38+
**`GatewayConfig`** builder:
39+
40+
```rust
41+
let config = GatewayConfig::new(0x0E80)
42+
.with_tester(0x0E00)
43+
.with_node(CanNodeEntry {
44+
logical_address: 0x0001,
45+
request_can_id: 0x7E0,
46+
response_can_id: 0x7E8,
47+
functional_can_id: 0x7DF,
48+
});
49+
```

0 commit comments

Comments
 (0)