canlink_hal/backend.rs
1//! Backend trait definitions and factory pattern.
2//!
3//! This module defines the core `CanBackend` trait that all hardware backends must implement,
4//! as well as the `BackendFactory` trait for creating backend instances.
5
6use crate::{BackendConfig, BackendVersion, CanError, CanMessage, CanResult, HardwareCapability};
7use std::time::Duration;
8
9/// CAN hardware backend interface.
10///
11/// This trait defines the unified interface that all hardware backends must implement.
12/// It provides methods for lifecycle management, message transmission/reception,
13/// channel management, and capability querying.
14///
15/// # Thread Safety
16///
17/// This trait's methods require external synchronization. If you need to access the same
18/// backend instance from multiple threads, the caller must provide synchronization using
19/// `Mutex` or `RwLock`.
20///
21/// **Rationale**: External synchronization allows high-performance single-threaded usage
22/// without lock overhead, while still supporting multi-threaded scenarios when needed.
23///
24/// ## Single-Threaded Usage (No Synchronization Needed)
25///
26/// ```rust,ignore
27/// use canlink_hal::{CanBackend, BackendConfig};
28///
29/// fn main() -> Result<(), Box<dyn std::error::Error>> {
30/// let mut backend = create_backend();
31/// backend.initialize(&config)?;
32/// backend.open_channel(0)?;
33///
34/// // Direct access - no locks needed
35/// backend.send_message(&message)?;
36/// if let Some(msg) = backend.receive_message()? {
37/// println!("Received: {:?}", msg);
38/// }
39///
40/// backend.close()?;
41/// Ok(())
42/// }
43/// ```
44///
45/// ## Multi-Threaded Usage with Mutex
46///
47/// Use `Arc<Mutex<>>` when multiple threads need mutable access:
48///
49/// ```rust,ignore
50/// use std::sync::{Arc, Mutex};
51/// use std::thread;
52/// use canlink_hal::{CanBackend, CanMessage};
53///
54/// fn main() -> Result<(), Box<dyn std::error::Error>> {
55/// let backend = Arc::new(Mutex::new(create_backend()));
56///
57/// // Initialize in main thread
58/// backend.lock().unwrap().initialize(&config)?;
59/// backend.lock().unwrap().open_channel(0)?;
60///
61/// // Sender thread
62/// let backend_tx = Arc::clone(&backend);
63/// let tx_handle = thread::spawn(move || {
64/// for i in 0..100 {
65/// let msg = CanMessage::new_standard(0x100 + i, &[i as u8]).unwrap();
66/// backend_tx.lock().unwrap().send_message(&msg).unwrap();
67/// }
68/// });
69///
70/// // Receiver thread
71/// let backend_rx = Arc::clone(&backend);
72/// let rx_handle = thread::spawn(move || {
73/// let mut count = 0;
74/// while count < 100 {
75/// if let Some(msg) = backend_rx.lock().unwrap().receive_message().unwrap() {
76/// println!("Received: {:?}", msg);
77/// count += 1;
78/// }
79/// }
80/// });
81///
82/// tx_handle.join().unwrap();
83/// rx_handle.join().unwrap();
84///
85/// backend.lock().unwrap().close()?;
86/// Ok(())
87/// }
88/// ```
89///
90/// ## Multi-Threaded Usage with `RwLock`
91///
92/// Use `Arc<RwLock<>>` when you have many readers and few writers:
93///
94/// ```rust,ignore
95/// use std::sync::{Arc, RwLock};
96/// use std::thread;
97/// use canlink_hal::CanBackend;
98///
99/// fn main() -> Result<(), Box<dyn std::error::Error>> {
100/// let backend = Arc::new(RwLock::new(create_backend()));
101///
102/// // Initialize
103/// backend.write().unwrap().initialize(&config)?;
104/// backend.write().unwrap().open_channel(0)?;
105///
106/// // Multiple reader threads querying capabilities
107/// let mut handles = vec![];
108/// for i in 0..10 {
109/// let backend_clone = Arc::clone(&backend);
110/// let handle = thread::spawn(move || {
111/// // Read lock allows concurrent access
112/// let capability = backend_clone.read().unwrap().get_capability().unwrap();
113/// println!("Thread {}: {} channels", i, capability.channel_count);
114/// });
115/// handles.push(handle);
116/// }
117///
118/// // Writer thread sending messages
119/// let backend_writer = Arc::clone(&backend);
120/// let writer_handle = thread::spawn(move || {
121/// for i in 0..10 {
122/// let msg = CanMessage::new_standard(0x200, &[i]).unwrap();
123/// // Write lock for exclusive access
124/// backend_writer.write().unwrap().send_message(&msg).unwrap();
125/// }
126/// });
127///
128/// for handle in handles {
129/// handle.join().unwrap();
130/// }
131/// writer_handle.join().unwrap();
132///
133/// backend.write().unwrap().close()?;
134/// Ok(())
135/// }
136/// ```
137///
138/// ## Channel-Based Message Passing Pattern
139///
140/// For better performance, consider using channels to decouple threads:
141///
142/// ```rust,ignore
143/// use std::sync::mpsc;
144/// use std::thread;
145/// use canlink_hal::{CanBackend, CanMessage};
146///
147/// fn main() -> Result<(), Box<dyn std::error::Error>> {
148/// let mut backend = create_backend();
149/// backend.initialize(&config)?;
150/// backend.open_channel(0)?;
151///
152/// let (tx, rx) = mpsc::channel();
153///
154/// // Worker threads send messages via channel
155/// for i in 0..4 {
156/// let tx_clone = tx.clone();
157/// thread::spawn(move || {
158/// for j in 0..25 {
159/// let msg = CanMessage::new_standard(
160/// 0x100 + (i * 25 + j),
161/// &[i as u8, j as u8]
162/// ).unwrap();
163/// tx_clone.send(msg).unwrap();
164/// }
165/// });
166/// }
167/// drop(tx); // Close sender
168///
169/// // Main thread owns backend and sends messages
170/// for msg in rx {
171/// backend.send_message(&msg)?;
172/// }
173///
174/// backend.close()?;
175/// Ok(())
176/// }
177/// ```
178///
179/// ## Performance Considerations
180///
181/// - **Single-threaded**: Zero synchronization overhead
182/// - **Mutex**: Simple but serializes all access
183/// - **`RwLock`**: Better for read-heavy workloads (e.g., capability queries)
184/// - **Channel-based**: Best performance, avoids lock contention
185///
186/// ## Thread Safety Guarantees
187///
188/// - `CanBackend` is `Send`, so it can be moved between threads
189/// - Methods require `&mut self`, enforcing exclusive access
190/// - Backends do not use internal locks (external synchronization model)
191/// - All backend state is protected by the caller's synchronization primitive
192///
193/// # Lifecycle
194///
195/// Backend instances follow this lifecycle:
196/// 1. **Create** (via `BackendFactory::create()`)
197/// 2. **Initialize** (`initialize()`)
198/// 3. **Run** (call `send_message()`, `receive_message()`, etc.)
199/// 4. **Close** (`close()`)
200///
201/// # Examples
202///
203/// ```rust,ignore
204/// use canlink_hal::{CanBackend, BackendConfig};
205///
206/// // Create and initialize backend
207/// let mut backend = create_backend();
208/// backend.initialize(&config)?;
209///
210/// // Use backend
211/// backend.open_channel(0)?;
212/// backend.send_message(&message)?;
213///
214/// // Clean up
215/// backend.close()?;
216/// ```
217pub trait CanBackend: Send {
218 // ========== Lifecycle Management ==========
219
220 /// Initialize the backend.
221 ///
222 /// # Arguments
223 ///
224 /// * `config` - Backend configuration parameters
225 ///
226 /// # Errors
227 ///
228 /// * `CanError::InitializationFailed` - Hardware initialization failed
229 /// * `CanError::ConfigError` - Configuration parameters are invalid
230 ///
231 /// # Preconditions
232 ///
233 /// * Backend is in `Uninitialized` state
234 ///
235 /// # Postconditions
236 ///
237 /// * Success: Backend is in `Ready` state
238 /// * Failure: Backend remains in `Uninitialized` state
239 ///
240 /// # Examples
241 ///
242 /// ```rust,ignore
243 /// let mut backend = create_backend();
244 /// backend.initialize(&config)?;
245 /// ```
246 fn initialize(&mut self, config: &BackendConfig) -> CanResult<()>;
247
248 /// Close the backend and release resources.
249 ///
250 /// This method releases all resources held by the backend, including hardware handles,
251 /// memory buffers, and network connections. It should be called when the backend is
252 /// no longer needed.
253 ///
254 /// # Errors
255 ///
256 /// Returns an error if closing fails, but resources will still be released on a
257 /// best-effort basis.
258 ///
259 /// # Preconditions
260 ///
261 /// * Backend is in `Ready` state
262 ///
263 /// # Postconditions
264 ///
265 /// * Backend is in `Closed` state
266 /// * All resources are released
267 ///
268 /// # Examples
269 ///
270 /// ```rust,ignore
271 /// backend.close()?;
272 /// ```
273 fn close(&mut self) -> CanResult<()>;
274
275 // ========== Hardware Capability Query ==========
276
277 /// Query hardware capabilities.
278 ///
279 /// Returns information about the hardware's capabilities, including supported
280 /// channel count, CAN-FD support, maximum bitrate, and timestamp precision.
281 ///
282 /// Applications should query capabilities at startup to adapt their behavior
283 /// to the available hardware features. This enables writing portable code that
284 /// works across different CAN hardware backends.
285 ///
286 /// # Performance Requirements
287 ///
288 /// * Response time < 1ms (SC-004)
289 /// * Should be cached by the backend for fast repeated queries
290 ///
291 /// # Use Cases
292 ///
293 /// * **Feature Detection**: Check if CAN-FD is supported before sending FD frames
294 /// * **Channel Validation**: Verify channel numbers before opening
295 /// * **Bitrate Selection**: Choose from supported bitrates
296 /// * **Filter Planning**: Determine available hardware filters
297 /// * **Timestamp Handling**: Adapt to available timestamp precision
298 ///
299 /// # Examples
300 ///
301 /// Basic capability query:
302 ///
303 /// ```rust,ignore
304 /// let capability = backend.get_capability()?;
305 /// println!("Hardware: {} channels, CAN-FD: {}",
306 /// capability.channel_count,
307 /// capability.supports_canfd);
308 /// ```
309 ///
310 /// Adaptive message sending:
311 ///
312 /// ```rust,ignore
313 /// let capability = backend.get_capability()?;
314 ///
315 /// // Use CAN-FD if available, otherwise fall back to CAN 2.0
316 /// let message = if capability.supports_canfd {
317 /// CanMessage::new_canfd(0x123, &data, false)?
318 /// } else {
319 /// CanMessage::new_standard(0x123, &data[..8])?
320 /// };
321 /// backend.send_message(&message)?;
322 /// ```
323 ///
324 /// Bitrate validation:
325 ///
326 /// ```rust,ignore
327 /// let capability = backend.get_capability()?;
328 /// let desired_bitrate = 500_000;
329 ///
330 /// if !capability.supports_bitrate(desired_bitrate) {
331 /// eprintln!("Bitrate {} not supported", desired_bitrate);
332 /// eprintln!("Supported bitrates: {:?}", capability.supported_bitrates);
333 /// return Err(CanError::UnsupportedFeature("bitrate".into()));
334 /// }
335 /// ```
336 ///
337 /// Channel validation:
338 ///
339 /// ```rust,ignore
340 /// let capability = backend.get_capability()?;
341 /// let channel = 2;
342 ///
343 /// if !capability.has_channel(channel) {
344 /// return Err(CanError::InvalidChannel(channel));
345 /// }
346 /// backend.open_channel(channel)?;
347 /// ```
348 ///
349 /// # Errors
350 ///
351 /// Returns an error if the capability query fails (rare, typically only on
352 /// uninitialized or closed backends).
353 fn get_capability(&self) -> CanResult<HardwareCapability>;
354
355 // ========== Message Transmission/Reception ==========
356
357 /// Send a CAN message.
358 ///
359 /// Transmits a CAN message on the bus. The message must be valid and the hardware
360 /// must support the message type (e.g., CAN-FD messages require CAN-FD support).
361 ///
362 /// # Arguments
363 ///
364 /// * `message` - The message to send
365 ///
366 /// # Errors
367 ///
368 /// * `CanError::SendFailed` - Send failed (e.g., bus Bus-Off)
369 /// * `CanError::UnsupportedFeature` - Hardware doesn't support this message type
370 /// * `CanError::InvalidDataLength` - Data length exceeds limits
371 /// * `CanError::InvalidState` - Backend not in Ready state
372 ///
373 /// # Preconditions
374 ///
375 /// * Backend is in `Ready` state
376 /// * Message format is valid
377 /// * At least one channel is open
378 ///
379 /// # Postconditions
380 ///
381 /// * Success: Message is sent to the bus
382 /// * Failure: Message is not sent, backend state unchanged
383 ///
384 /// # Performance Requirements
385 ///
386 /// * Support 1000 messages/second throughput
387 /// * Abstraction layer overhead < 5% (SC-005)
388 ///
389 /// # Examples
390 ///
391 /// ```rust,ignore
392 /// let msg = CanMessage::new_standard(0x123, &[0x01, 0x02, 0x03])?;
393 /// backend.send_message(&msg)?;
394 /// ```
395 fn send_message(&mut self, message: &CanMessage) -> CanResult<()>;
396
397 /// Receive a CAN message (non-blocking).
398 ///
399 /// Attempts to receive a message from the receive queue. Returns immediately
400 /// with `None` if no messages are available.
401 ///
402 /// # Returns
403 ///
404 /// * `Ok(Some(message))` - A message was received
405 /// * `Ok(None)` - No messages currently available
406 /// * `Err(CanError)` - Reception failed
407 ///
408 /// # Errors
409 ///
410 /// * `CanError::ReceiveFailed` - Reception failed
411 /// * `CanError::InvalidState` - Backend not in Ready state
412 ///
413 /// # Preconditions
414 ///
415 /// * Backend is in `Ready` state
416 ///
417 /// # Postconditions
418 ///
419 /// * Success: Returned message is removed from receive queue
420 /// * Failure: Receive queue state unchanged
421 ///
422 /// # Examples
423 ///
424 /// ```rust,ignore
425 /// if let Some(msg) = backend.receive_message()? {
426 /// println!("Received: {:?}", msg);
427 /// }
428 /// ```
429 fn receive_message(&mut self) -> CanResult<Option<CanMessage>>;
430
431 // ========== Channel Management ==========
432
433 /// Open a CAN channel.
434 ///
435 /// Opens the specified CAN channel for communication. The channel index must be
436 /// valid (less than the channel count reported by `get_capability()`).
437 ///
438 /// # Arguments
439 ///
440 /// * `channel` - Channel index (0-based)
441 ///
442 /// # Errors
443 ///
444 /// * `CanError::ChannelNotFound` - Channel doesn't exist
445 /// * `CanError::ChannelAlreadyOpen` - Channel is already open
446 ///
447 /// # Preconditions
448 ///
449 /// * Backend is in `Ready` state
450 /// * Channel index is valid (< `capability.channel_count`)
451 ///
452 /// # Examples
453 ///
454 /// ```rust,ignore
455 /// backend.open_channel(0)?;
456 /// ```
457 fn open_channel(&mut self, channel: u8) -> CanResult<()>;
458
459 /// Close a CAN channel.
460 ///
461 /// Closes the specified CAN channel and stops communication on that channel.
462 ///
463 /// # Arguments
464 ///
465 /// * `channel` - Channel index
466 ///
467 /// # Errors
468 ///
469 /// * `CanError::ChannelNotFound` - Channel doesn't exist
470 /// * `CanError::ChannelNotOpen` - Channel is not open
471 ///
472 /// # Examples
473 ///
474 /// ```rust,ignore
475 /// backend.close_channel(0)?;
476 /// ```
477 fn close_channel(&mut self, channel: u8) -> CanResult<()>;
478
479 // ========== Version Information ==========
480
481 /// Get the backend version.
482 ///
483 /// Returns the semantic version number of the backend implementation.
484 ///
485 /// # Examples
486 ///
487 /// ```rust,ignore
488 /// let version = backend.version();
489 /// println!("Backend version: {}", version);
490 /// ```
491 fn version(&self) -> BackendVersion;
492
493 /// Get the backend name.
494 ///
495 /// Returns the unique identifier name of the backend (e.g., "`TSMaster`", "mock").
496 ///
497 /// # Examples
498 ///
499 /// ```rust,ignore
500 /// let name = backend.name();
501 /// println!("Using backend: {}", name);
502 /// ```
503 fn name(&self) -> &str;
504}
505
506/// Backend factory trait.
507///
508/// This trait defines the factory pattern for creating backend instances.
509/// Each backend implementation should provide a factory that implements this trait.
510///
511/// # Examples
512///
513/// ```rust,ignore
514/// use canlink_hal::{BackendFactory, BackendConfig};
515///
516/// struct MockBackendFactory;
517///
518/// impl BackendFactory for MockBackendFactory {
519/// fn create(&self, config: &BackendConfig) -> CanResult<Box<dyn CanBackend>> {
520/// Ok(Box::new(MockBackend::new()))
521/// }
522///
523/// fn name(&self) -> &str {
524/// "mock"
525/// }
526///
527/// fn version(&self) -> BackendVersion {
528/// BackendVersion::new(0, 1, 0)
529/// }
530/// }
531/// ```
532pub trait BackendFactory: Send + Sync {
533 /// Create a new backend instance.
534 ///
535 /// # Arguments
536 ///
537 /// * `config` - Backend configuration
538 ///
539 /// # Returns
540 ///
541 /// A boxed backend instance ready for initialization.
542 ///
543 /// # Errors
544 ///
545 /// * `CanError::ConfigError` - Invalid configuration
546 /// * `CanError::Other` - Factory-specific errors
547 fn create(&self, config: &BackendConfig) -> CanResult<Box<dyn CanBackend>>;
548
549 /// Get the factory name.
550 ///
551 /// Returns the unique identifier for this backend type.
552 fn name(&self) -> &str;
553
554 /// Get the factory version.
555 ///
556 /// Returns the version of the backend implementation.
557 fn version(&self) -> BackendVersion;
558}
559
560/// Helper function to retry backend initialization.
561///
562/// This function implements the retry logic specified in FR-009. It attempts to
563/// initialize a backend multiple times with a fixed interval between attempts.
564///
565/// # Arguments
566///
567/// * `backend` - The backend to initialize
568/// * `config` - Backend configuration
569/// * `retry_count` - Number of retry attempts (default: 3)
570/// * `retry_interval` - Interval between retries in milliseconds (default: 1000)
571///
572/// # Returns
573///
574/// * `Ok(())` - Initialization succeeded
575/// * `Err(CanError::InitializationFailed)` - All retry attempts failed
576///
577/// # Errors
578///
579/// Returns `CanError::InitializationFailed` if all retry attempts fail.
580///
581/// # Examples
582///
583/// ```rust,ignore
584/// let mut backend = create_backend();
585/// retry_initialize(&mut backend, &config, 3, 1000)?;
586/// ```
587pub fn retry_initialize(
588 backend: &mut dyn CanBackend,
589 config: &BackendConfig,
590 retry_count: u32,
591 retry_interval_ms: u64,
592) -> CanResult<()> {
593 let mut errors = Vec::new();
594 let start_time = std::time::Instant::now();
595
596 for attempt in 0..=retry_count {
597 match backend.initialize(config) {
598 Ok(()) => return Ok(()),
599 Err(e) => {
600 errors.push(format!("Attempt {}: {}", attempt + 1, e));
601 if attempt < retry_count {
602 std::thread::sleep(Duration::from_millis(retry_interval_ms));
603 }
604 }
605 }
606 }
607
608 let total_time = start_time.elapsed();
609 Err(CanError::InitializationFailed {
610 reason: format!(
611 "Failed after {} attempts in {:?}. Errors: {}",
612 retry_count + 1,
613 total_time,
614 errors.join("; ")
615 ),
616 })
617}
618
619/// Switch from one backend to another (FR-015).
620///
621/// This function performs a clean switch between backends:
622/// 1. Closes the old backend (discarding any unprocessed messages)
623/// 2. Initializes the new backend
624///
625/// **Important**: Any messages in the old backend's queue are discarded.
626/// Users should process all pending messages before calling this function
627/// if message preservation is required.
628///
629/// # Arguments
630///
631/// * `old_backend` - The currently active backend to close
632/// * `new_backend` - The new backend to initialize
633/// * `config` - Configuration for the new backend
634///
635/// # Errors
636///
637/// Returns an error if:
638/// - The old backend fails to close (warning only, continues)
639/// - The new backend fails to initialize
640///
641/// # Examples
642///
643/// ```rust,ignore
644/// use canlink_hal::{switch_backend, BackendConfig};
645///
646/// // Process any remaining messages first
647/// while let Some(msg) = old_backend.receive_message()? {
648/// process_message(msg);
649/// }
650///
651/// // Then switch backends
652/// switch_backend(&mut old_backend, &mut new_backend, &new_config)?;
653/// ```
654pub fn switch_backend(
655 old_backend: &mut dyn CanBackend,
656 new_backend: &mut dyn CanBackend,
657 config: &BackendConfig,
658) -> CanResult<()> {
659 // Get names upfront to avoid borrow issues (used for logging)
660 #[allow(unused_variables)]
661 let old_name = old_backend.name().to_string();
662 #[allow(unused_variables)]
663 let new_name = new_backend.name().to_string();
664
665 // Log the switch (if tracing is enabled)
666 #[cfg(feature = "tracing")]
667 tracing::info!("Switching backend from '{}' to '{}'", old_name, new_name);
668
669 // Close the old backend - ignore errors but log them
670 #[allow(unused_variables)]
671 if let Err(e) = old_backend.close() {
672 #[cfg(feature = "tracing")]
673 tracing::warn!("Error closing old backend '{}': {}", old_name, e);
674 // Continue anyway - we want to switch even if close fails
675 }
676
677 // Initialize the new backend
678 #[cfg(feature = "tracing")]
679 {
680 new_backend.initialize(config).map_err(|e| {
681 tracing::error!("Failed to initialize new backend '{}': {}", new_name, e);
682 e
683 })?;
684 }
685 #[cfg(not(feature = "tracing"))]
686 {
687 new_backend.initialize(config)?;
688 }
689
690 #[cfg(feature = "tracing")]
691 tracing::info!("Successfully switched to backend '{}'", new_name);
692
693 Ok(())
694}
695
696// ============================================================================
697// Async Backend Trait (feature-gated)
698// ============================================================================
699
700/// Async CAN hardware backend interface.
701///
702/// This trait provides asynchronous versions of the core message operations.
703/// It is only available when the `async` feature is enabled.
704///
705/// # Feature Flags
706///
707/// - `async` - Enable async trait (requires runtime selection)
708/// - `async-tokio` - Use tokio runtime
709/// - `async-async-std` - Use async-std runtime
710///
711/// # Thread Safety
712///
713/// Like [`CanBackend`], this trait requires external synchronization.
714/// Use `Arc<Mutex<>>` or `Arc<RwLock<>>` for shared access across tasks.
715///
716/// # Examples
717///
718/// ```rust,ignore
719/// use canlink_hal::{CanBackendAsync, CanMessage};
720///
721/// async fn send_messages(backend: &mut impl CanBackendAsync) -> Result<(), Box<dyn std::error::Error>> {
722/// let msg = CanMessage::new_standard(0x123, &[1, 2, 3, 4])?;
723/// backend.send_message_async(&msg).await?;
724///
725/// if let Some(received) = backend.receive_message_async(Some(Duration::from_secs(1))).await? {
726/// println!("Received: {:?}", received);
727/// }
728/// Ok(())
729/// }
730/// ```
731#[cfg(feature = "async")]
732#[allow(async_fn_in_trait)]
733pub trait CanBackendAsync: CanBackend {
734 /// Send a CAN message asynchronously.
735 ///
736 /// This is the async version of [`CanBackend::send_message`].
737 ///
738 /// # Arguments
739 ///
740 /// * `message` - The CAN message to send
741 ///
742 /// # Returns
743 ///
744 /// * `Ok(())` - Message sent successfully
745 /// * `Err(CanError)` - Send failed
746 ///
747 /// # Examples
748 ///
749 /// ```rust,ignore
750 /// let msg = CanMessage::new_standard(0x123, &[0x01, 0x02])?;
751 /// backend.send_message_async(&msg).await?;
752 /// ```
753 async fn send_message_async(&mut self, message: &CanMessage) -> CanResult<()>;
754
755 /// Receive a CAN message asynchronously with optional timeout.
756 ///
757 /// This is the async version of [`CanBackend::receive_message`].
758 /// Unlike the sync version, this method can wait for a message with a timeout.
759 ///
760 /// # Arguments
761 ///
762 /// * `timeout` - Optional timeout duration. If `None`, returns immediately
763 /// like the sync version. If `Some(duration)`, waits up to that duration
764 /// for a message.
765 ///
766 /// # Returns
767 ///
768 /// * `Ok(Some(message))` - A message was received
769 /// * `Ok(None)` - No message available (timeout expired or no timeout and queue empty)
770 /// * `Err(CanError)` - Reception failed
771 ///
772 /// # Examples
773 ///
774 /// ```rust,ignore
775 /// // Non-blocking receive
776 /// if let Some(msg) = backend.receive_message_async(None).await? {
777 /// println!("Received: {:?}", msg);
778 /// }
779 ///
780 /// // Receive with 1 second timeout
781 /// match backend.receive_message_async(Some(Duration::from_secs(1))).await? {
782 /// Some(msg) => println!("Received: {:?}", msg),
783 /// None => println!("Timeout - no message received"),
784 /// }
785 /// ```
786 async fn receive_message_async(
787 &mut self,
788 timeout: Option<Duration>,
789 ) -> CanResult<Option<CanMessage>>;
790}
791
792#[cfg(test)]
793mod tests {
794 use super::*;
795
796 // Mock backend for testing
797 struct TestBackend {
798 initialized: bool,
799 fail_count: u32,
800 }
801
802 impl TestBackend {
803 fn new(fail_count: u32) -> Self {
804 Self {
805 initialized: false,
806 fail_count,
807 }
808 }
809 }
810
811 impl CanBackend for TestBackend {
812 fn initialize(&mut self, _config: &BackendConfig) -> CanResult<()> {
813 if self.fail_count > 0 {
814 self.fail_count -= 1;
815 Err(CanError::InitializationFailed {
816 reason: "Test failure".to_string(),
817 })
818 } else {
819 self.initialized = true;
820 Ok(())
821 }
822 }
823
824 fn close(&mut self) -> CanResult<()> {
825 Ok(())
826 }
827
828 fn get_capability(&self) -> CanResult<HardwareCapability> {
829 unimplemented!()
830 }
831
832 fn send_message(&mut self, _message: &CanMessage) -> CanResult<()> {
833 unimplemented!()
834 }
835
836 fn receive_message(&mut self) -> CanResult<Option<CanMessage>> {
837 unimplemented!()
838 }
839
840 fn open_channel(&mut self, _channel: u8) -> CanResult<()> {
841 unimplemented!()
842 }
843
844 fn close_channel(&mut self, _channel: u8) -> CanResult<()> {
845 unimplemented!()
846 }
847
848 fn version(&self) -> BackendVersion {
849 BackendVersion::new(0, 1, 0)
850 }
851
852 fn name(&self) -> &'static str {
853 "test"
854 }
855 }
856
857 #[test]
858 fn test_retry_initialize_success_first_attempt() {
859 let mut backend = TestBackend::new(0);
860 let config = BackendConfig::new("test");
861
862 let result = retry_initialize(&mut backend, &config, 3, 10);
863 assert!(result.is_ok());
864 assert!(backend.initialized);
865 }
866
867 #[test]
868 fn test_retry_initialize_success_after_retries() {
869 let mut backend = TestBackend::new(2); // Fail 2 times, succeed on 3rd
870 let config = BackendConfig::new("test");
871
872 let result = retry_initialize(&mut backend, &config, 3, 10);
873 assert!(result.is_ok());
874 assert!(backend.initialized);
875 }
876
877 #[test]
878 fn test_retry_initialize_failure_all_attempts() {
879 let mut backend = TestBackend::new(10); // Fail all attempts
880 let config = BackendConfig::new("test");
881
882 let result = retry_initialize(&mut backend, &config, 3, 10);
883 assert!(result.is_err());
884 assert!(!backend.initialized);
885
886 if let Err(CanError::InitializationFailed { reason }) = result {
887 assert!(reason.contains("Failed after 4 attempts"));
888 } else {
889 panic!("Expected InitializationFailed error");
890 }
891 }
892}
893
894// ============================================================================
895// High-Frequency Message Rate Monitor (FR-016)
896// ============================================================================
897
898/// Message rate monitor for detecting high-frequency message scenarios.
899///
900/// This utility helps backends detect when message rates exceed a threshold
901/// and log warnings as specified in FR-016. It does not perform any automatic
902/// throttling or backpressure - it only logs warnings for user awareness.
903///
904/// # Usage
905///
906/// Backends can use this to monitor receive rates:
907///
908/// ```rust,ignore
909/// use canlink_hal::backend::MessageRateMonitor;
910///
911/// let mut monitor = MessageRateMonitor::new(1000); // Warn above 1000 msg/s
912///
913/// // In receive loop:
914/// if let Some(msg) = backend.receive_message()? {
915/// monitor.record_message();
916/// process(msg);
917/// }
918/// ```
919///
920/// # Thread Safety
921///
922/// This struct is not thread-safe. Each thread should have its own monitor
923/// or use external synchronization.
924#[derive(Debug)]
925pub struct MessageRateMonitor {
926 /// Threshold in messages per second
927 threshold_per_second: u32,
928 /// Message count in current window
929 message_count: u32,
930 /// Start of current measurement window
931 window_start: std::time::Instant,
932 /// Whether we've already warned in this window
933 warned_this_window: bool,
934}
935
936impl MessageRateMonitor {
937 /// Create a new message rate monitor.
938 ///
939 /// # Arguments
940 ///
941 /// * `threshold_per_second` - Message rate threshold that triggers warnings
942 ///
943 /// # Examples
944 ///
945 /// ```
946 /// use canlink_hal::backend::MessageRateMonitor;
947 ///
948 /// // Warn when rate exceeds 1000 messages/second
949 /// let monitor = MessageRateMonitor::new(1000);
950 /// ```
951 #[must_use]
952 pub fn new(threshold_per_second: u32) -> Self {
953 Self {
954 threshold_per_second,
955 message_count: 0,
956 window_start: std::time::Instant::now(),
957 warned_this_window: false,
958 }
959 }
960
961 /// Record a message and check if rate exceeds threshold.
962 ///
963 /// Returns `true` if the rate exceeds the threshold (warning should be logged).
964 /// Only returns `true` once per measurement window to avoid log spam.
965 ///
966 /// # Examples
967 ///
968 /// ```
969 /// use canlink_hal::backend::MessageRateMonitor;
970 ///
971 /// let mut monitor = MessageRateMonitor::new(1000);
972 ///
973 /// // Record messages
974 /// if monitor.record_message() {
975 /// // Rate exceeded threshold - handle warning
976 /// eprintln!("Warning: High message rate detected");
977 /// }
978 /// ```
979 pub fn record_message(&mut self) -> bool {
980 self.message_count += 1;
981
982 let elapsed = self.window_start.elapsed();
983
984 // Check every second
985 if elapsed >= Duration::from_secs(1) {
986 let exceeded = self.message_count > self.threshold_per_second;
987
988 // Log warning if exceeded and haven't warned yet
989 if exceeded && !self.warned_this_window {
990 #[cfg(feature = "tracing")]
991 tracing::warn!(
992 "High message rate detected: {} messages/second (threshold: {})",
993 self.message_count,
994 self.threshold_per_second
995 );
996 self.warned_this_window = true;
997 }
998
999 // Reset for next window
1000 self.message_count = 0;
1001 self.window_start = std::time::Instant::now();
1002 self.warned_this_window = false;
1003
1004 exceeded
1005 } else {
1006 false
1007 }
1008 }
1009
1010 /// Get the current message count in this window.
1011 #[must_use]
1012 pub fn current_count(&self) -> u32 {
1013 self.message_count
1014 }
1015
1016 /// Get the configured threshold.
1017 #[must_use]
1018 pub fn threshold(&self) -> u32 {
1019 self.threshold_per_second
1020 }
1021
1022 /// Reset the monitor state.
1023 pub fn reset(&mut self) {
1024 self.message_count = 0;
1025 self.window_start = std::time::Instant::now();
1026 self.warned_this_window = false;
1027 }
1028}
1029
1030impl Default for MessageRateMonitor {
1031 /// Create a monitor with default threshold of 10000 messages/second.
1032 fn default() -> Self {
1033 Self::new(10000)
1034 }
1035}