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:
pub trait ServerHandler {
type Error: NrcError;
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>;
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:
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:
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:
server.handle(&src_addr, &raw_uds_bytes, now)?; server.tick(now)?; server.drain_outbox(&mut out);