ace-server 0.2.2

UDS ECU server state machine. Handles all session management security access, timing, periodic DID scheduling, and NRC construction.
Documentation
# `ace-server`

UDS ECU server state machine (ISO 14229-1 ECU side).

Handles all session management, security access state, P2/S3 timing, periodic DID scheduling, and NRC construction internally. The application provides data and actions via two traits:

**`ServerHandler`** — required hooks for service handling:

```rust
pub trait ServerHandler {
    type Error: NrcError;

    // Required
    fn read_did(&self, did: u16, buf: &mut [u8]) -> Result<usize, Self::Error>;
    fn write_did(&mut self, did: u16, data: &[u8]) -> Result<(), Self::Error>;
    fn ecu_reset(&mut self, reset_type: u8) -> Result<(), Self::Error>;

    // Optional — default returns NRC 0x11 serviceNotSupported
    fn routine_control(&mut self, ...) -> Result<usize, Self::Error> { Err(...) }
    fn communication_control(&mut self, ...) -> Result<(), Self::Error> { Err(...) }
    fn io_control(&mut self, ...) -> Result<usize, Self::Error> { Err(...) }
    fn request_download(&mut self, ...) -> Result<usize, Self::Error> { Err(...) }
    fn transfer_data(&mut self, ...) -> Result<usize, Self::Error> { Err(...) }
    fn request_transfer_exit(&mut self, ...) -> Result<usize, Self::Error> { Err(...) }
    fn request_file_transfer(&mut self, ...) -> Result<usize, Self::Error> { Err(...) }
}
```

**`SecurityProvider`** — seed generation and key validation:

```rust
pub trait SecurityProvider {
    fn generate_seed(&mut self, level: u8, buf: &mut [u8]) -> Result<usize, SecurityError>;
    fn validate_key(&self, level: u8, seed: &[u8], key: &[u8]) -> Result<(), SecurityError>;
}
```

**`ServerConfig`** — ODX-style ECU description built with a fluent builder:

```rust
let config = ServerConfig::new(physical_address: 0x0001, functional_address: 0x7DF)
    .with_session(SessionConfig::default_session())
    .with_session(SessionConfig::extended_session())
    .with_service(ServiceConfig::new(0x22, &[0x01, 0x02, 0x03]))
    .with_service(ServiceConfig::secured(0x2E, &[0x03], security_level: 1))
    .with_did(DidConfig::read_only(0xF190, &[0x01, 0x02, 0x03]))
    .with_did(DidConfig::read_write(0xF120, &[0x03], &[0x03]).secured(1))
    .with_security_level(SecurityLevelConfig {
        level: 0x01,
        max_attempts: 3,
        lockout_duration: Duration::from_millis(10_000),
        seed_length: 4,
        key_length: 4,
    });
```

The server is driven by three methods — identical in simulation and production:

```rust
server.handle(&src_addr, &raw_uds_bytes, now)?;  // process inbound frame
server.tick(now)?;                                 // drive timers
server.drain_outbox(&mut out);                     // collect responses
```