Skip to main content

Crate canlink_hal

Crate canlink_hal 

Source
Expand description

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 implement

    • initialize() - Initialize the backend
    • send_message() - Send a CAN message
    • receive_message() - Receive a CAN message
    • open_channel() / close_channel() - Channel management
    • get_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 support
  • async-tokio - Use tokio runtime for async operations
  • async-async-std - Use async-std runtime for async operations
  • tracing - Enable logging support via tracing framework
  • hot-reload - Enable configuration hot-reload support
  • full - 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 Send but not Sync
  • 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 testing
  • canlink-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.