Expand description
§CANLink Hardware Abstraction Layer
This crate provides a unified hardware abstraction layer for CAN bus interfaces. It allows applications to work with different CAN hardware backends through a common trait-based interface.
§Features
- Unified Interface: Single trait (
CanBackend) for all hardware backends - Backend Registry: Runtime registration and discovery of hardware backends
- Hardware Capabilities: Query hardware features at runtime
- Zero-Cost Abstraction: Minimal performance overhead (< 5%)
- Type Safety: Compile-time guarantees through Rust’s type system
- Async Support: Optional async API through feature flags
§Quick Start
use canlink_hal::{BackendConfig, CanBackend, CanMessage, CanId};
use canlink_mock::MockBackend;
// Create and initialize backend
let mut backend = MockBackend::new();
let config = BackendConfig::new("mock");
backend.initialize(&config)?;
// Open a channel
backend.open_channel(0)?;
// Send a message
let msg = CanMessage::new_standard(0x123, &[1, 2, 3, 4])?;
backend.send_message(&msg)?;
// Receive a message
if let Some(msg) = backend.receive_message()? {
println!("Received: ID={:?}, Data={:?}", msg.id(), msg.data());
}
// Clean up
backend.close_channel(0)?;
backend.close()?;§Architecture
The abstraction layer consists of several key components:
§Core Traits
-
CanBackend: Core interface that all backends must implementinitialize()- Initialize the backendsend_message()- Send a CAN messagereceive_message()- Receive a CAN messageopen_channel()/close_channel()- Channel managementget_capability()- Query hardware capabilities
-
BackendFactory: Factory trait for creating backend instances
§Key Types
-
CanMessage: Unified CAN message representation- Supports standard (11-bit) and extended (29-bit) IDs
- Supports CAN 2.0 and CAN-FD frames
- Supports remote frames
-
CanId: CAN identifier (standard or extended) -
HardwareCapability: Hardware feature description- Channel count
- CAN-FD support
- Supported bitrates
- Hardware filter count
- Timestamp precision
-
BackendRegistry: Manages backend registration and instantiation -
CanError: Common error types across all backends
§Usage Examples
§Basic Message Sending
use canlink_hal::{CanBackend, CanMessage};
use canlink_mock::MockBackend;
let mut backend = MockBackend::new();
backend.initialize(&config)?;
backend.open_channel(0)?;
// Standard CAN message
let msg = CanMessage::new_standard(0x123, &[0xAA, 0xBB, 0xCC, 0xDD])?;
backend.send_message(&msg)?;
// Extended ID message
let msg = CanMessage::new_extended(0x12345678, &[1, 2, 3, 4, 5, 6, 7, 8])?;
backend.send_message(&msg)?;
// CAN-FD message (if supported)
let data = vec![0; 64]; // Up to 64 bytes
let msg = CanMessage::new_fd(CanId::Standard(0x200), &data)?;
backend.send_message(&msg)?;§Capability-Based Adaptation
use canlink_hal::{CanBackend, CanMessage, CanId};
let capability = backend.get_capability()?;
// Adapt message type based on hardware support
let data = vec![0; 12];
let msg = if capability.supports_canfd {
CanMessage::new_fd(CanId::Standard(0x123), &data)?
} else {
// Split into multiple CAN 2.0 messages
CanMessage::new_standard(0x123, &data[..8])?
};
// Check bitrate support
if capability.supports_bitrate(1_000_000) {
println!("1 Mbps is supported");
}
// Check channel availability
if capability.has_channel(2) {
backend.open_channel(2)?;
}§Error Handling
use canlink_hal::{CanError, CanBackend};
match backend.send_message(&msg) {
Ok(_) => println!("Message sent successfully"),
Err(CanError::SendFailed { reason }) => {
eprintln!("Send failed: {}", reason);
}
Err(CanError::BusError { kind }) => {
eprintln!("Bus error: {:?}", kind);
}
Err(e) => eprintln!("Other error: {}", e),
}§Backend Registry
use canlink_hal::{BackendRegistry, BackendConfig};
use canlink_mock::MockBackendFactory;
use std::sync::Arc;
// Get global registry
let registry = BackendRegistry::global();
// Register a backend
let factory = Arc::new(MockBackendFactory::new());
registry.register(factory)?;
// List available backends
for name in registry.list_backends() {
println!("Available backend: {}", name);
}
// Create backend instance
let config = BackendConfig::new("mock");
let mut backend = registry.create("mock", &config)?;§Testing
The crate includes a mock backend for testing without hardware:
use canlink_hal::{CanBackend, CanMessage, CanId};
use canlink_mock::MockBackend;
#[test]
fn test_can_communication() {
let mut backend = MockBackend::new();
backend.initialize(&config).unwrap();
backend.open_channel(0).unwrap();
// Send message
let msg = CanMessage::new_standard(0x123, &[1, 2, 3]).unwrap();
backend.send_message(&msg).unwrap();
// Verify message was sent
assert!(backend.verify_message_sent(CanId::Standard(0x123)));
}§Feature Flags
async- Enable async API supportasync-tokio- Use tokio runtime for async operationsasync-async-std- Use async-std runtime for async operationstracing- Enable logging support via tracing frameworkhot-reload- Enable configuration hot-reload supportfull- Enable all features
§Performance
The abstraction layer is designed for minimal overhead:
- Trait method calls are typically inlined
- Zero-copy message passing where possible
- Abstraction overhead < 5% compared to direct hardware access
§Thread Safety
Backend implementations follow an external synchronization model:
- Backends are
Sendbut notSync - Each thread should have its own backend instance
- Use channels or locks for cross-thread communication
§Supported Backends
- Mock: Software simulation for testing (included)
SocketCAN: Linux CAN interface (planned)- PCAN: PEAK-System CAN adapters (planned)
- IXXAT: HMS IXXAT CAN interfaces (planned)
- Kvaser: Kvaser CAN devices (planned)
§See Also
canlink-mock- Mock backend for testingcanlink-cli- Command-line interface- Examples: see the workspace
examples/directory
Re-exports§
pub use backend::retry_initialize;pub use backend::switch_backend;pub use backend::BackendFactory;pub use backend::CanBackend;pub use backend::MessageRateMonitor;pub use capability::HardwareCapability;pub use capability::TimestampPrecision;pub use config::BackendConfig;pub use config::CanlinkConfig;pub use error::BusErrorKind;pub use error::CanError;pub use error::CanResult;pub use error::FilterError;pub use error::FilterResult;pub use error::MonitorError;pub use error::MonitorResult;pub use error::QueueError;pub use error::QueueResult;pub use message::CanId;pub use message::CanMessage;pub use message::MessageFlags;pub use message::Timestamp;pub use registry::BackendInfo;pub use registry::BackendRegistry;pub use state::BackendState;pub use version::BackendVersion;
Modules§
- backend
- Backend trait definitions and factory pattern.
- capability
- Hardware capability types.
- config
- Configuration management for backends.
- error
- Error types for the CAN hardware abstraction layer.
- filter
- Message filtering module (FR-005 to FR-009)
- message
- CAN message types and related structures.
- monitor
- Connection monitoring module (FR-010)
- queue
- Queue management module (FR-011, FR-017)
- registry
- Backend registry for managing and discovering hardware backends.
- resource
- Resource Management Guidelines and Best Practices (FR-012)
- state
- Backend state management.
- version
- Version management and compatibility checking.