renik/
bluetooth.rs

1//! # Bluetooth Device Management
2//!
3//! This module provides comprehensive Bluetooth device management capabilities
4//! for embedded systems, including device information storage, connection state
5//! tracking, and finite state machine (FSM) management.
6//!
7//! ## Features
8//!
9//! - **Device Information**: Store and manage individual Bluetooth device configurations
10//! - **Device Lists**: Manage multiple paired devices (up to 10)
11//! - **Connection State**: Track real-time connection status with FSM support
12//! - **Type-Safe Handles**: Validated connection handle wrapper
13//! - **Security Management**: Store pairing keys and security information
14//! - **Memory Efficient**: Fixed-size structures optimized for embedded use
15//!
16//! ## Core Structures
17//!
18//! - [`BluetoothDeviceInfo`]: Complete device information including pairing data
19//! - [`BluetoothDeviceList`]: Container for multiple device configurations (max 10)
20//! - [`BluetoothConnectionState`]: Real-time connection tracking with FSM
21//! - [`ConnHandle`]: Type-safe connection handle wrapper
22//! - [`BluetoothConnectionPhase`]: FSM phases for connection lifecycle
23//!
24//! ## Finite State Machine
25//!
26//! The Bluetooth connection FSM supports 13 distinct phases:
27//!
28//! ```text
29//! 0  Idle                → 1  Discovery
30//! 1  Discovery           → 2  Connecting
31//! 2  Connecting          → 3  Connected | 11 Failed
32//! 3  Connected           → 4  Authenticating | 7 ServiceDiscovery | 12 Disconnecting
33//! 4  Authenticating      → 5  SettingUpEncryption | 11 Failed | 12 Disconnecting
34//! 5  SettingUpEncryption → 6  FullyConnected | 11 Failed | 12 Disconnecting
35//! 6  FullyConnected      → 7  ServiceDiscovery | 8 Ready | 12 Disconnecting
36//! 7  ServiceDiscovery    → 8  Ready | 11 Failed | 12 Disconnecting
37//! 8  Ready               → 9  Maintaining | 12 Disconnecting
38//! 9  Maintaining         → 10 Reconnecting | 12 Disconnecting
39//! 10 Reconnecting        → 2  Connecting | 11 Failed
40//! 11 Failed              → 10 Reconnecting
41//! 12 Disconnecting       → 0  Idle (only allowed transition)
42//! ```
43//!
44//! See `BluetoothConnectionPhase` and `BluetoothConnectionState::is_valid_transition` for details.
45//!
46//! ## Memory Layout
47//!
48//! All structures use `#[repr(C)]` layout for reliable serialization:
49//! - Predictable field ordering
50//! - No hidden padding (except explicit padding fields)
51//! - Cross-platform compatibility
52//! - Suitable for persistent storage
53//!
54//! ## Examples
55//!
56//! ### Basic Device Management
57//! ```
58//! use renik::{BluetoothDeviceInfo, BluetoothDeviceList};
59//!
60//! // Create a device
61//! let mac_addr = [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC];
62//! let mut device = BluetoothDeviceInfo::new(&mac_addr, b"My Speaker")?;
63//! device.set_pairing_key(b"audio_key_123")?;
64//! device.add_flag(BluetoothDeviceInfo::FLAG_AUDIO);
65//!
66//! // Add to device list
67//! let mut device_list = BluetoothDeviceList::default();
68//! device_list.add_device(device)?;
69//! # Ok::<(), renik::Error>(())
70//! ```
71//!
72//! ### Connection State Tracking
73//! ```
74//! use renik::{BluetoothConnectionState, BluetoothConnectionPhase, ConnHandle};
75//!
76//! let mut connection = BluetoothConnectionState::default();
77//!
78//! // FSM transitions
79//! assert!(connection.advance_to_phase(BluetoothConnectionPhase::Discovery));
80//! assert!(connection.advance_to_phase(BluetoothConnectionPhase::Connecting));
81//! assert!(connection.advance_to_phase(BluetoothConnectionPhase::Connected));
82//!
83//! // Set connection details
84//! connection.set_connection_handle(Some(ConnHandle::new(0x0042)));
85//! connection.set_link_quality(85);
86//! # Ok::<(), renik::Error>(())
87//! ```
88
89use crate::Error;
90use bytemuck::{Pod, Zeroable};
91
92/// Magic number used to validate Bluetooth device configuration structures
93/// Value: 0x42544C45 (ASCII "BTLE")
94const BLUETOOTH_CONFIG_MAGIC: u32 = 0x4254_4C45;
95
96/// Magic number for Bluetooth device list
97/// Value: 0x42544C53 (ASCII "BTLS")
98const BLUETOOTH_DEVICE_LIST_MAGIC: u32 = 0x4254_4C53;
99
100/// Magic number for Bluetooth connection state
101/// Value: 0x42544353 (ASCII "BTCS")
102const BLUETOOTH_CONNECTION_STATE_MAGIC: u32 = 0x4254_4353;
103
104/// Bluetooth device list structure
105///
106/// This structure represents a list of up to 10 Bluetooth devices, including their
107/// configuration and connection status. It's used for managing multiple
108/// Bluetooth devices in embedded systems.
109///
110/// # Memory Layout
111/// The structure uses `#[repr(C)]` to ensure predictable memory layout,
112/// making it suitable for serialization and inter-process communication.
113///
114/// # Security Note
115/// This structure may store sensitive pairing data. Ensure proper
116/// memory protection and secure storage mechanisms when persisting this data.
117///
118/// # Fields
119/// - `magic`: Structure validation (0x42544C53)
120/// - `devices`: Array of up to 10 device configurations
121/// - `device_count`: Number of valid devices in the list
122/// - `_padding`: Ensures 4-byte alignment
123///
124/// # Errors
125/// - `Error::DeviceListFull` if adding more than 10 devices
126/// - `Error::IndexOutOfBounds` for invalid indices
127///
128/// # Examples
129/// ```
130/// use renik::{BluetoothDeviceInfo, BluetoothDeviceList};
131///
132/// let mac_addr1 = [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC];
133/// let mac_addr2 = [0x98, 0x76, 0x54, 0x32, 0x10, 0xFE];
134/// let device1 = BluetoothDeviceInfo::new(&mac_addr1, b"Device 1").unwrap();
135/// let device2 = BluetoothDeviceInfo::new(&mac_addr2, b"Device 2").unwrap();
136/// let mut device_list = BluetoothDeviceList::default();
137/// device_list.add_device(device1).unwrap();
138/// device_list.add_device(device2).unwrap();
139/// assert_eq!(device_list.len(), 2);
140/// ```
141#[derive(Debug, Clone, Copy, Pod, Zeroable)]
142#[repr(C, packed)]
143pub struct BluetoothDeviceList {
144    /// Magic number for structure validation (0x42544C53)
145    magic: u32, // 4-byte aligned
146    /// Array of Bluetooth device configurations
147    devices: [BluetoothDeviceInfo; 10], // 4-byte aligned
148    /// Number of devices currently in the list
149    device_count: u8, // 1-byte aligned
150    /// Padding to ensure proper alignment
151    _padding: [u8; 3], // Ensures 4-byte alignment
152}
153
154impl Default for BluetoothDeviceList {
155    /// Creates a new Bluetooth device list with default values
156    ///
157    /// The structure is initialized with the correct magic number
158    /// and an empty device list.
159    fn default() -> Self {
160        Self {
161            magic: BLUETOOTH_DEVICE_LIST_MAGIC,
162            devices: Default::default(),
163            device_count: 0,
164            _padding: [0; 3],
165        }
166    }
167}
168
169impl BluetoothDeviceList {
170    /// Adds a Bluetooth device configuration to the list
171    ///
172    /// # Parameters
173    /// - `device_config`: Bluetooth device configuration
174    ///
175    /// # Returns
176    /// - `Ok(())` if the device was added successfully
177    /// - `Err(Error)` if the device list is full
178    ///
179    /// # Errors
180    /// Returns `Error::DeviceListFull` if the device list is already at maximum capacity.
181    pub fn add_device(&mut self, device_config: BluetoothDeviceInfo) -> Result<(), Error> {
182        if self.device_count as usize >= self.devices.len() {
183            return Err(Error::DeviceListFull);
184        }
185
186        self.devices[self.device_count as usize] = device_config;
187        self.device_count += 1;
188
189        Ok(())
190    }
191
192    /// Removes a Bluetooth device configuration from the list
193    ///
194    /// # Parameters
195    /// - `index`: Index of the device to remove (0-based)
196    ///
197    /// # Returns
198    /// - `Ok(())` if the device was removed successfully
199    /// - `Err(Error)` if the index is out of bounds
200    ///
201    /// # Errors
202    /// Returns `Error::IndexOutOfBounds` if the specified index is not valid.
203    pub fn remove_device(&mut self, index: usize) -> Result<(), Error> {
204        if index >= self.device_count as usize {
205            return Err(Error::IndexOutOfBounds);
206        }
207
208        // Shift devices down to fill the gap
209        for i in index..(self.device_count as usize - 1) {
210            self.devices[i] = self.devices[i + 1];
211        }
212
213        self.device_count -= 1;
214
215        Ok(())
216    }
217
218    /// Returns a reference to a Bluetooth device configuration
219    ///
220    /// # Parameters
221    /// - `index`: Index of the device to retrieve (0-based)
222    ///
223    /// # Returns
224    /// - `Ok(&BluetoothDeviceInfo)` if the index is valid
225    /// - `Err(Error)` if the index is out of bounds
226    ///
227    /// # Errors
228    /// Returns `Error::IndexOutOfBounds` if the specified index is not valid.
229    pub fn device(&self, index: usize) -> Result<&BluetoothDeviceInfo, Error> {
230        if index >= self.device_count as usize {
231            return Err(Error::IndexOutOfBounds);
232        }
233
234        Ok(&self.devices[index])
235    }
236
237    /// Returns the number of devices in the list
238    ///
239    /// # Returns
240    /// The current device count
241    #[must_use]
242    pub fn len(&self) -> usize {
243        self.device_count as usize
244    }
245
246    /// Checks if the device list is empty
247    ///
248    /// # Returns
249    /// - `true` if there are no devices in the list
250    /// - `false` otherwise
251    #[must_use]
252    pub fn is_empty(&self) -> bool {
253        self.device_count == 0
254    }
255}
256
257/// Bluetooth connection state structure
258///
259/// This structure represents the connection state of a Bluetooth device,
260/// including information about the remote device, connection status,
261/// and link quality. It's used for managing Bluetooth connections
262/// in embedded systems.
263///
264/// # Memory Layout
265/// The structure uses `#[repr(C)]` to ensure predictable memory layout,
266/// making it suitable for serialization and inter-process communication.
267///
268/// # Security Note
269/// This structure may store sensitive connection data. Ensure proper
270/// memory protection and secure storage mechanisms when persisting this data.
271///
272/// # Fields
273/// - `magic`: Structure validation (0x42544353)
274/// - `device_config`: Bluetooth device configuration
275/// - `connection_flags`: Bitfield for connection/authentication
276/// - `link_quality`: RSSI/LQI/etc.
277/// - `connection_phase`: Current FSM phase (see `BluetoothConnectionPhase`)
278/// - `_padding`: Ensures 4-byte alignment
279///
280/// # Examples
281/// ```
282/// use renik::{BluetoothDeviceInfo, BluetoothConnectionState};
283///
284/// let mac_addr = [0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC];
285/// let device = BluetoothDeviceInfo::new(&mac_addr, b"My Device").unwrap();
286/// let mut connection_state = BluetoothConnectionState::default();
287/// connection_state.set_remote_device(device);
288/// connection_state.set_connected(true);
289/// assert!(connection_state.is_connected());
290/// ```
291#[derive(Debug, Clone, Copy, Pod, Zeroable)]
292#[repr(C, packed)]
293pub struct BluetoothConnectionState {
294    /// Magic number for structure validation (0x42544353)
295    magic: u32, // 4-byte aligned
296    /// Bluetooth device configuration
297    device_config: BluetoothDeviceInfo, // 4-byte aligned
298    /// Connection status flags
299    connection_flags: u8, // 1-byte aligned
300    /// Link quality (RSSI, LQI, etc.)
301    link_quality: u8, // 1-byte aligned
302    /// Current connection phase
303    connection_phase: u8, // 1-byte aligned (maps to BluetoothConnectionPhase)
304    /// Padding to ensure proper alignment
305    _padding: [u8; 1], // Ensures 4-byte alignment
306}
307
308impl Default for BluetoothConnectionState {
309    /// Creates a new Bluetooth connection state with default values
310    ///
311    /// The structure is initialized with the correct magic number
312    /// and a disconnected state.
313    fn default() -> Self {
314        Self {
315            magic: BLUETOOTH_CONNECTION_STATE_MAGIC,
316            device_config: BluetoothDeviceInfo::default(),
317            connection_flags: 0,
318            link_quality: 0,
319            connection_phase: BluetoothConnectionPhase::Idle as u8,
320            _padding: [0; 1],
321        }
322    }
323}
324
325impl BluetoothConnectionState {
326    /// Sets the remote Bluetooth device configuration
327    ///
328    /// # Parameters
329    /// - `device_config`: Bluetooth device configuration
330    pub fn set_remote_device(&mut self, device_config: BluetoothDeviceInfo) {
331        self.device_config = device_config;
332    }
333
334    /// Sets the connection status
335    ///
336    /// # Parameters
337    /// - `connected`: `true` if connected, `false` if disconnected
338    pub fn set_connected(&mut self, connected: bool) {
339        if connected {
340            self.connection_flags |= 0x01;
341        } else {
342            self.connection_flags &= !0x01;
343        }
344    }
345
346    /// Sets the link quality
347    ///
348    /// # Parameters
349    /// - `quality`: Link quality value (0-255)
350    pub fn set_link_quality(&mut self, quality: u8) {
351        self.link_quality = quality;
352    }
353
354    /// Returns the remote Bluetooth device configuration
355    ///
356    /// # Returns
357    /// A reference to the Bluetooth device configuration
358    #[must_use]
359    pub fn remote_device(&self) -> &BluetoothDeviceInfo {
360        &self.device_config
361    }
362
363    /// Returns the connection status
364    ///
365    /// # Returns
366    /// - `true` if connected
367    /// - `false` if disconnected
368    #[must_use]
369    pub fn is_connected(&self) -> bool {
370        (self.connection_flags & 0x01) != 0
371    }
372
373    /// Returns the link quality
374    ///
375    /// # Returns
376    /// The link quality value (0-255)
377    #[must_use]
378    pub fn link_quality(&self) -> u8 {
379        self.link_quality
380    }
381
382    /// Sets the authentication status
383    ///
384    /// # Parameters
385    /// - `authenticated`: `true` if authenticated, `false` if not
386    pub fn set_authenticated(&mut self, authenticated: bool) {
387        if authenticated {
388            self.connection_flags |= 0x02;
389        } else {
390            self.connection_flags &= !0x02;
391        }
392    }
393
394    /// Returns the authentication status
395    ///
396    /// # Returns
397    /// - `true` if authenticated
398    /// - `false` if not authenticated
399    #[must_use]
400    pub fn is_authenticated(&self) -> bool {
401        (self.connection_flags & 0x02) != 0
402    }
403
404    /// Sets the remote device address
405    ///
406    /// # Parameters
407    /// - `address`: 6-byte Bluetooth address
408    pub fn set_remote_device_address(&mut self, address: [u8; 6]) {
409        self.device_config.mac_address = address;
410    }
411
412    /// Gets the remote device address
413    ///
414    /// # Returns
415    /// Optional 6-byte Bluetooth address
416    #[must_use]
417    pub fn remote_device_address(&self) -> Option<[u8; 6]> {
418        Some(self.device_config.mac_address)
419    }
420
421    /// Sets the connection handle
422    ///
423    /// # Parameters
424    /// - `handle`: Connection handle (`ConnHandle`)
425    pub fn set_connection_handle(&mut self, handle: Option<ConnHandle>) {
426        self.device_config.connection_params.connection_handle = handle.unwrap_or_default();
427    }
428
429    /// Gets the connection handle
430    ///
431    /// # Returns
432    /// Optional connection handle
433    #[must_use]
434    pub fn connection_handle(&self) -> Option<ConnHandle> {
435        if self.device_config.connection_params.connection_handle.raw() == 0 {
436            None
437        } else {
438            Some(self.device_config.connection_params.connection_handle)
439        }
440    }
441
442    /// Sets the link type
443    ///
444    /// # Parameters
445    /// - `link_type`: Link type (0x01 = ACL, 0x02 = SCO)
446    pub fn set_link_type(&mut self, link_type: u8) {
447        self.device_config.connection_params.link_type = link_type;
448    }
449
450    /// Gets the link type
451    ///
452    /// # Returns
453    /// Link type value
454    #[must_use]
455    pub fn link_type(&self) -> u8 {
456        self.device_config.connection_params.link_type
457    }
458
459    /// Sets the connection phase
460    ///
461    /// # Parameters
462    /// - `phase`: Connection phase
463    pub fn set_connection_phase(&mut self, phase: BluetoothConnectionPhase) {
464        self.connection_phase = phase as u8;
465    }
466
467    /// Gets the connection phase
468    ///
469    /// # Returns
470    /// The current connection phase
471    #[must_use]
472    pub fn connection_phase(&self) -> BluetoothConnectionPhase {
473        // Convert u8 back to enum, default to Idle if invalid
474        match self.connection_phase {
475            1 => BluetoothConnectionPhase::Discovery,
476            2 => BluetoothConnectionPhase::Connecting,
477            3 => BluetoothConnectionPhase::Connected,
478            4 => BluetoothConnectionPhase::Authenticating,
479            5 => BluetoothConnectionPhase::SettingUpEncryption,
480            6 => BluetoothConnectionPhase::FullyConnected,
481            7 => BluetoothConnectionPhase::ServiceDiscovery,
482            8 => BluetoothConnectionPhase::Ready,
483            9 => BluetoothConnectionPhase::Maintaining,
484            10 => BluetoothConnectionPhase::Reconnecting,
485            11 => BluetoothConnectionPhase::Failed,
486            12 => BluetoothConnectionPhase::Disconnecting,
487            _ => BluetoothConnectionPhase::Idle, // Default for 0 and invalid values
488        }
489    }
490
491    /// Advances to the next connection phase
492    ///
493    /// # Parameters
494    /// - `next_phase`: The next phase to transition to
495    ///
496    /// # Returns
497    /// - `true` if the transition is valid
498    /// - `false` if the transition is not allowed
499    pub fn advance_to_phase(&mut self, next_phase: BluetoothConnectionPhase) -> bool {
500        let current = self.connection_phase();
501
502        // Simple rule-based validation instead of exhaustive matching
503        let valid_transition = next_phase == BluetoothConnectionPhase::Idle
504            || Self::is_valid_transition(current, next_phase);
505
506        if valid_transition {
507            self.set_connection_phase(next_phase);
508        }
509
510        valid_transition
511    }
512
513    /// Helper function to check if a state transition is valid
514    fn is_valid_transition(
515        current: BluetoothConnectionPhase,
516        next: BluetoothConnectionPhase,
517    ) -> bool {
518        use BluetoothConnectionPhase::{
519            Authenticating, Connected, Connecting, Disconnecting, Discovery, Failed,
520            FullyConnected, Idle, Maintaining, Ready, Reconnecting, ServiceDiscovery,
521            SettingUpEncryption,
522        };
523
524        match current {
525            Idle => matches!(next, Discovery | Connecting),
526            Discovery => next == Connecting,
527            Connecting => matches!(next, Connected | Failed),
528            Connected => matches!(next, Authenticating | ServiceDiscovery | Disconnecting),
529            Authenticating => matches!(next, SettingUpEncryption | Failed | Disconnecting),
530            SettingUpEncryption => matches!(next, FullyConnected | Failed | Disconnecting),
531            FullyConnected => matches!(next, ServiceDiscovery | Ready | Disconnecting),
532            ServiceDiscovery => matches!(next, Ready | Failed | Disconnecting),
533            Ready => matches!(next, Maintaining | Disconnecting),
534            Maintaining => matches!(next, Reconnecting | Disconnecting),
535            Reconnecting => matches!(next, Connecting | Failed),
536            Failed => next == Reconnecting,
537            Disconnecting => false, // Only to Idle, handled above
538        }
539    }
540}
541
542/// Connection parameters for Bluetooth devices
543#[derive(Debug, Clone, Copy, Pod, Zeroable)]
544#[repr(C, packed)]
545pub struct BluetoothConnectionParams {
546    connection_handle: ConnHandle,
547    connection_interval: u16,
548    connection_latency: u16,
549    supervision_timeout: u16,
550    master_clock_accuracy: u8,
551    link_type: u8,
552    encryption_enabled: u8,
553    rssi: i8,
554    connected_at: u32,
555    last_activity: u32,
556    _padding: [u8; 4],
557}
558
559impl Default for BluetoothConnectionParams {
560    fn default() -> Self {
561        Self {
562            connection_handle: ConnHandle::default(),
563            connection_interval: 0,
564            connection_latency: 0,
565            supervision_timeout: 0,
566            master_clock_accuracy: 0,
567            link_type: 0,
568            encryption_enabled: 0,
569            rssi: -127,
570            connected_at: 0,
571            last_activity: 0,
572            _padding: [0; 4],
573        }
574    }
575}
576
577impl BluetoothConnectionParams {
578    /// Returns the connection handle assigned by the controller
579    #[must_use]
580    pub fn connection_handle(&self) -> ConnHandle {
581        self.connection_handle
582    }
583
584    /// Returns the connection interval in 1.25ms units
585    #[must_use]
586    pub fn connection_interval(&self) -> u16 {
587        self.connection_interval
588    }
589
590    /// Returns the connection latency
591    #[must_use]
592    pub fn connection_latency(&self) -> u16 {
593        self.connection_latency
594    }
595
596    /// Returns the supervision timeout in 10ms units
597    #[must_use]
598    pub fn supervision_timeout(&self) -> u16 {
599        self.supervision_timeout
600    }
601
602    /// Returns the master clock accuracy
603    #[must_use]
604    pub fn master_clock_accuracy(&self) -> u8 {
605        self.master_clock_accuracy
606    }
607
608    /// Returns the link type (0x01 = ACL, 0x02 = SCO)
609    #[must_use]
610    pub fn link_type(&self) -> u8 {
611        self.link_type
612    }
613
614    /// Returns whether encryption is enabled (0x00 = disabled, 0x01 = enabled)
615    #[must_use]
616    pub fn encryption_enabled(&self) -> u8 {
617        self.encryption_enabled
618    }
619
620    /// Returns the RSSI value (-127 to 127 dBm)
621    #[must_use]
622    pub fn rssi(&self) -> i8 {
623        self.rssi
624    }
625
626    /// Returns the connection timestamp (seconds since epoch)
627    #[must_use]
628    pub fn connected_at(&self) -> u32 {
629        self.connected_at
630    }
631
632    /// Returns the last activity timestamp (seconds since epoch)
633    #[must_use]
634    pub fn last_activity(&self) -> u32 {
635        self.last_activity
636    }
637
638    /// Sets the connection handle assigned by the controller
639    pub fn set_connection_handle(&mut self, handle: ConnHandle) {
640        self.connection_handle = handle;
641    }
642
643    /// Sets the connection interval in 1.25ms units
644    pub fn set_connection_interval(&mut self, interval: u16) {
645        self.connection_interval = interval;
646    }
647
648    /// Sets the connection latency
649    pub fn set_connection_latency(&mut self, latency: u16) {
650        self.connection_latency = latency;
651    }
652
653    /// Sets the supervision timeout in 10ms units
654    pub fn set_supervision_timeout(&mut self, timeout: u16) {
655        self.supervision_timeout = timeout;
656    }
657
658    /// Sets the master clock accuracy
659    pub fn set_master_clock_accuracy(&mut self, accuracy: u8) {
660        self.master_clock_accuracy = accuracy;
661    }
662
663    /// Sets the link type (0x01 = ACL, 0x02 = SCO)
664    pub fn set_link_type(&mut self, link_type: u8) {
665        self.link_type = link_type;
666    }
667
668    /// Sets whether encryption is enabled (0x00 = disabled, 0x01 = enabled)
669    pub fn set_encryption_enabled(&mut self, enabled: u8) {
670        self.encryption_enabled = enabled;
671    }
672
673    /// Sets the RSSI value (-127 to 127 dBm)
674    pub fn set_rssi(&mut self, rssi: i8) {
675        self.rssi = rssi;
676    }
677
678    /// Sets the connection timestamp (seconds since epoch)
679    pub fn set_connected_at(&mut self, timestamp: u32) {
680        self.connected_at = timestamp;
681    }
682
683    /// Sets the last activity timestamp (seconds since epoch)
684    pub fn set_last_activity(&mut self, timestamp: u32) {
685        self.last_activity = timestamp;
686    }
687}
688
689/// Security information for Bluetooth connections
690#[derive(Debug, Clone, Copy, Pod, Zeroable)]
691#[repr(C, packed)]
692pub struct BluetoothSecurityInfo {
693    link_key: [u8; 16],
694    link_key_type: u8,
695    auth_requirements: u8,
696    io_capabilities: u8,
697    security_level: u8,
698    pin_length: u8,
699    link_key_valid: u8,
700    authenticated: u8,
701    encrypted: u8,
702    ssp_supported: u8,
703    mitm_required: u8,
704    _padding: [u8; 6],
705}
706
707impl Default for BluetoothSecurityInfo {
708    fn default() -> Self {
709        Self {
710            link_key: [0; 16],
711            link_key_type: 0,
712            auth_requirements: 0,
713            io_capabilities: 0,
714            security_level: 1,
715            pin_length: 0,
716            link_key_valid: 0,
717            authenticated: 0,
718            encrypted: 0,
719            ssp_supported: 0,
720            mitm_required: 0,
721            _padding: [0; 6],
722        }
723    }
724}
725
726impl BluetoothSecurityInfo {
727    /// Returns the link key for authentication (16 bytes)
728    #[must_use]
729    pub fn link_key(&self) -> &[u8; 16] {
730        &self.link_key
731    }
732    /// Sets the link key for authentication (16 bytes)
733    pub fn set_link_key(&mut self, key: [u8; 16]) {
734        self.link_key = key;
735    }
736    #[must_use]
737    pub fn link_key_type(&self) -> u8 {
738        self.link_key_type
739    }
740    pub fn set_link_key_type(&mut self, t: u8) {
741        self.link_key_type = t;
742    }
743    #[must_use]
744    pub fn auth_requirements(&self) -> u8 {
745        self.auth_requirements
746    }
747    pub fn set_auth_requirements(&mut self, r: u8) {
748        self.auth_requirements = r;
749    }
750    #[must_use]
751    pub fn io_capabilities(&self) -> u8 {
752        self.io_capabilities
753    }
754    pub fn set_io_capabilities(&mut self, c: u8) {
755        self.io_capabilities = c;
756    }
757    #[must_use]
758    pub fn security_level(&self) -> u8 {
759        self.security_level
760    }
761    pub fn set_security_level(&mut self, l: u8) {
762        self.security_level = l;
763    }
764    #[must_use]
765    pub fn pin_length(&self) -> u8 {
766        self.pin_length
767    }
768    pub fn set_pin_length(&mut self, l: u8) {
769        self.pin_length = l;
770    }
771    #[must_use]
772    pub fn link_key_valid(&self) -> u8 {
773        self.link_key_valid
774    }
775    pub fn set_link_key_valid(&mut self, v: u8) {
776        self.link_key_valid = v;
777    }
778    #[must_use]
779    pub fn authenticated(&self) -> u8 {
780        self.authenticated
781    }
782    pub fn set_authenticated(&mut self, v: u8) {
783        self.authenticated = v;
784    }
785    #[must_use]
786    pub fn encrypted(&self) -> u8 {
787        self.encrypted
788    }
789    pub fn set_encrypted(&mut self, v: u8) {
790        self.encrypted = v;
791    }
792    #[must_use]
793    pub fn ssp_supported(&self) -> u8 {
794        self.ssp_supported
795    }
796    pub fn set_ssp_supported(&mut self, v: u8) {
797        self.ssp_supported = v;
798    }
799    #[must_use]
800    pub fn mitm_required(&self) -> u8 {
801        self.mitm_required
802    }
803    pub fn set_mitm_required(&mut self, v: u8) {
804        self.mitm_required = v;
805    }
806}
807
808/// Complete Bluetooth device information for storage
809#[derive(Debug, Clone, Copy, Pod, Zeroable)]
810#[repr(C, packed)]
811pub struct BluetoothDeviceInfo {
812    magic: u32,                                   // 4
813    connection_count: u32,                        // 4
814    last_seen: u32,                               // 4
815    last_connected: u32,                          // 4
816    connection_params: BluetoothConnectionParams, // 40
817    security_info: BluetoothSecurityInfo,         // 32
818    vendor_id: u16,                               // 2
819    product_id: u16,                              // 2
820    version: u16,                                 // 2
821    mac_address: [u8; 6],                         // 6
822    class_of_device: [u8; 3],                     // 3
823    device_type: u8,                              // 1
824    flags: u8,                                    // 1
825    device_name_len: u8,                          // 1
826    pairing_key_len: u8,                          // 1
827    device_name: [u8; 32],                        // 32
828    pairing_key: [u8; 64],                        // 64
829    _padding: [u8; 6],                            // 6 (to align struct to 4 bytes)
830}
831
832impl Default for BluetoothDeviceInfo {
833    fn default() -> Self {
834        Self {
835            magic: BLUETOOTH_CONFIG_MAGIC,
836            connection_count: 0,
837            last_seen: 0,
838            last_connected: 0,
839            connection_params: BluetoothConnectionParams::default(),
840            security_info: BluetoothSecurityInfo::default(),
841            vendor_id: 0,
842            product_id: 0,
843            version: 0,
844            mac_address: [0; 6],
845            class_of_device: [0; 3],
846            device_type: 0,
847            flags: 0,
848            device_name_len: 0,
849            pairing_key_len: 0,
850            device_name: [0; 32],
851            pairing_key: [0; 64],
852            _padding: [0; 6],
853        }
854    }
855}
856
857/// Device type constants based on Class of Device major class
858impl BluetoothDeviceInfo {
859    pub const DEVICE_TYPE_UNKNOWN: u8 = 0;
860    pub const DEVICE_TYPE_COMPUTER: u8 = 1;
861    pub const DEVICE_TYPE_PHONE: u8 = 2;
862    pub const DEVICE_TYPE_NETWORK: u8 = 3;
863    pub const DEVICE_TYPE_AUDIO: u8 = 4;
864    pub const DEVICE_TYPE_PERIPHERAL: u8 = 5;
865    pub const DEVICE_TYPE_IMAGING: u8 = 6;
866    pub const DEVICE_TYPE_WEARABLE: u8 = 7;
867    pub const DEVICE_TYPE_TOY: u8 = 8;
868}
869
870/// Device flags for `BluetoothDeviceInfo`
871impl BluetoothDeviceInfo {
872    /// Device is paired
873    pub const FLAG_PAIRED: u8 = 0x01;
874    /// Device is trusted
875    pub const FLAG_TRUSTED: u8 = 0x02;
876    /// Device supports audio
877    pub const FLAG_AUDIO: u8 = 0x04;
878    /// Device supports input (keyboard/mouse)
879    pub const FLAG_INPUT: u8 = 0x08;
880    /// Device supports file transfer
881    pub const FLAG_FILE_TRANSFER: u8 = 0x10;
882    /// Device is currently connected
883    pub const FLAG_CONNECTED: u8 = 0x20;
884    /// Device supports automatic reconnection
885    pub const FLAG_AUTO_RECONNECT: u8 = 0x40;
886    /// Device was discovered recently
887    pub const FLAG_RECENTLY_DISCOVERED: u8 = 0x80;
888}
889
890impl BluetoothDeviceInfo {
891    /// Creates a new Bluetooth device info with basic information
892    ///
893    /// # Parameters
894    /// - `mac_address`: Bluetooth MAC address as 6-byte array
895    /// - `device_name`: Device name as byte slice (max 32 bytes)
896    ///
897    /// # Returns
898    /// - `Ok(BluetoothDeviceInfo)` if the device info was created successfully
899    /// - `Err(Error)` if the device name length exceeded the maximum allowed
900    ///
901    /// # Errors
902    /// Returns `Error::InvalidBluetoothDeviceInfo` if the device name exceeds 32 bytes.
903    pub fn new(mac_address: &[u8; 6], device_name: &[u8]) -> Result<Self, Error> {
904        if device_name.len() > 32 {
905            return Err(Error::InvalidBluetoothDeviceInfo);
906        }
907
908        let mut device = Self::default();
909        device.set_mac_address(mac_address);
910        device.set_device_name(device_name)?;
911        Ok(device)
912    }
913
914    /// Validates the device info structure
915    #[must_use]
916    pub fn is_valid(&self) -> bool {
917        self.magic == BLUETOOTH_CONFIG_MAGIC && !self.mac_address.iter().all(|&b| b == 0)
918    }
919
920    /// Sets the MAC address
921    pub fn set_mac_address(&mut self, mac_address: &[u8; 6]) {
922        self.mac_address.copy_from_slice(mac_address);
923    }
924
925    /// Sets the device name
926    ///
927    /// # Parameters
928    /// - `device_name`: Device name as byte slice (max 32 bytes)
929    ///
930    /// # Returns
931    /// - `Ok(())` if the device name was set successfully
932    /// - `Err(Error)` if the device name length exceeded the maximum allowed
933    ///
934    /// # Errors
935    /// Returns `Error::InvalidBluetoothDeviceInfo` if the device name exceeds 32 bytes.
936    #[allow(clippy::cast_possible_truncation)]
937    pub fn set_device_name(&mut self, device_name: &[u8]) -> Result<(), Error> {
938        if device_name.len() > 32 {
939            return Err(Error::InvalidBluetoothDeviceInfo);
940        }
941
942        self.device_name_len = device_name.len() as u8;
943        self.device_name.fill(0);
944        self.device_name[..device_name.len()].copy_from_slice(device_name);
945        Ok(())
946    }
947
948    /// Sets the pairing key/PIN for the device
949    ///
950    /// # Parameters
951    /// - `pairing_key`: Pairing key/PIN as byte slice (max 64 bytes)
952    ///
953    /// # Returns
954    /// - `Ok(())` if the pairing key was set successfully
955    /// - `Err(Error)` if the pairing key length exceeded the maximum allowed
956    ///
957    /// # Errors
958    /// Returns `Error::InvalidBluetoothDeviceInfo` if the pairing key exceeds 64 bytes.
959    #[allow(clippy::cast_possible_truncation)]
960    pub fn set_pairing_key(&mut self, pairing_key: &[u8]) -> Result<(), Error> {
961        if pairing_key.len() > 64 {
962            return Err(Error::InvalidBluetoothDeviceInfo);
963        }
964
965        self.pairing_key_len = pairing_key.len() as u8;
966        self.pairing_key.fill(0);
967        self.pairing_key[..pairing_key.len()].copy_from_slice(pairing_key);
968        Ok(())
969    }
970
971    /// Returns the stored pairing key as a byte slice
972    ///
973    /// # Returns
974    /// A slice containing only the valid pairing key bytes (length determined by `pairing_key_len`)
975    #[must_use]
976    pub fn pairing_key(&self) -> &[u8] {
977        &self.pairing_key[..self.pairing_key_len as usize]
978    }
979
980    /// Sets both device name and pairing key at once
981    ///
982    /// # Parameters
983    /// - `device_name`: Device name as byte slice (max 32 bytes)
984    /// - `pairing_key`: Pairing key/PIN as byte slice (max 64 bytes)
985    ///
986    /// # Returns
987    /// - `Ok(())` if both were set successfully
988    /// - `Err(Error)` if either length exceeded the maximum allowed
989    ///
990    /// # Errors
991    /// Returns `Error::InvalidBluetoothDeviceInfo` if either the device name exceeds 32 bytes
992    /// or the pairing key exceeds 64 bytes.
993    pub fn set_device_info(&mut self, device_name: &[u8], pairing_key: &[u8]) -> Result<(), Error> {
994        self.set_device_name(device_name)?;
995        self.set_pairing_key(pairing_key)?;
996        Ok(())
997    }
998
999    /// Sets the class of device
1000    pub fn set_class_of_device(&mut self, class_of_device: &[u8; 3]) {
1001        self.class_of_device.copy_from_slice(class_of_device);
1002
1003        // Update device type based on major class
1004        // Major class is bits 8-12 (bits 0-4 of the second byte)
1005        let major_class = (class_of_device[1] >> 2) & 0x1F;
1006        self.device_type = match major_class {
1007            1 => Self::DEVICE_TYPE_COMPUTER,
1008            2 => Self::DEVICE_TYPE_PHONE,
1009            3 => Self::DEVICE_TYPE_NETWORK,
1010            4 => Self::DEVICE_TYPE_AUDIO,
1011            5 => Self::DEVICE_TYPE_PERIPHERAL,
1012            6 => Self::DEVICE_TYPE_IMAGING,
1013            7 => Self::DEVICE_TYPE_WEARABLE,
1014            8 => Self::DEVICE_TYPE_TOY,
1015            _ => Self::DEVICE_TYPE_UNKNOWN,
1016        };
1017    }
1018
1019    /// Updates connection parameters
1020    pub fn update_connection_params(&mut self, params: &BluetoothConnectionParams) {
1021        self.connection_params = *params;
1022        self.connection_count += 1;
1023        self.add_flag(Self::FLAG_CONNECTED);
1024    }
1025
1026    /// Updates security information
1027    pub fn update_security_info(&mut self, security: &BluetoothSecurityInfo) {
1028        self.security_info = *security;
1029        if security.authenticated != 0 {
1030            self.add_flag(Self::FLAG_PAIRED);
1031        }
1032    }
1033
1034    /// Sets connection flags
1035    pub fn set_flags(&mut self, flags: u8) {
1036        self.flags = flags;
1037    }
1038
1039    /// Adds a connection flag
1040    pub fn add_flag(&mut self, flag: u8) {
1041        self.flags |= flag;
1042    }
1043
1044    /// Removes a connection flag
1045    pub fn remove_flag(&mut self, flag: u8) {
1046        self.flags &= !flag;
1047    }
1048
1049    /// Checks if a specific flag is set
1050    #[must_use]
1051    pub fn has_flag(&self, flag: u8) -> bool {
1052        (self.flags & flag) != 0
1053    }
1054
1055    /// Updates last seen timestamp
1056    pub fn update_last_seen(&mut self, timestamp: u32) {
1057        self.last_seen = timestamp;
1058    }
1059
1060    /// Updates last connected timestamp
1061    pub fn update_last_connected(&mut self, timestamp: u32) {
1062        self.last_connected = timestamp;
1063    }
1064
1065    /// Sets the connection count
1066    pub fn set_connection_count(&mut self, count: u32) {
1067        self.connection_count = count;
1068    }
1069
1070    /// Increments the connection count
1071    pub fn increment_connection_count(&mut self) {
1072        self.connection_count = self.connection_count.saturating_add(1);
1073    }
1074
1075    /// Sets the last connected timestamp
1076    pub fn set_last_connected(&mut self, timestamp: u32) {
1077        self.last_connected = timestamp;
1078    }
1079
1080    /// Sets the last seen timestamp
1081    pub fn set_last_seen(&mut self, timestamp: u32) {
1082        self.last_seen = timestamp;
1083    }
1084
1085    /// Getters
1086    #[must_use]
1087    pub fn mac_address(&self) -> &[u8; 6] {
1088        &self.mac_address
1089    }
1090
1091    #[must_use]
1092    pub fn device_name(&self) -> &[u8] {
1093        &self.device_name[..self.device_name_len as usize]
1094    }
1095
1096    #[must_use]
1097    pub fn class_of_device(&self) -> &[u8; 3] {
1098        &self.class_of_device
1099    }
1100
1101    #[must_use]
1102    pub fn device_type(&self) -> u8 {
1103        self.device_type
1104    }
1105
1106    #[must_use]
1107    pub fn flags(&self) -> u8 {
1108        self.flags
1109    }
1110
1111    #[must_use]
1112    pub fn connection_params(&self) -> &BluetoothConnectionParams {
1113        &self.connection_params
1114    }
1115
1116    #[must_use]
1117    pub fn security_info(&self) -> &BluetoothSecurityInfo {
1118        &self.security_info
1119    }
1120
1121    #[must_use]
1122    pub fn is_paired(&self) -> bool {
1123        self.has_flag(Self::FLAG_PAIRED)
1124    }
1125
1126    #[must_use]
1127    pub fn is_connected(&self) -> bool {
1128        self.has_flag(Self::FLAG_CONNECTED)
1129    }
1130
1131    #[must_use]
1132    pub fn is_trusted(&self) -> bool {
1133        self.has_flag(Self::FLAG_TRUSTED)
1134    }
1135
1136    #[must_use]
1137    pub fn supports_auto_reconnect(&self) -> bool {
1138        self.has_flag(Self::FLAG_AUTO_RECONNECT)
1139    }
1140
1141    #[must_use]
1142    pub fn vendor_id(&self) -> u16 {
1143        self.vendor_id
1144    }
1145    #[must_use]
1146    pub fn product_id(&self) -> u16 {
1147        self.product_id
1148    }
1149    #[must_use]
1150    pub fn version(&self) -> u16 {
1151        self.version
1152    }
1153    #[must_use]
1154    pub fn connection_count(&self) -> u32 {
1155        self.connection_count
1156    }
1157    #[must_use]
1158    pub fn last_seen(&self) -> u32 {
1159        self.last_seen
1160    }
1161    #[must_use]
1162    pub fn last_connected(&self) -> u32 {
1163        self.last_connected
1164    }
1165    #[must_use]
1166    pub fn device_name_len(&self) -> u8 {
1167        self.device_name_len
1168    }
1169    #[must_use]
1170    pub fn pairing_key_len(&self) -> u8 {
1171        self.pairing_key_len
1172    }
1173}
1174
1175/// Bluetooth connection handle wrapper
1176///
1177/// Provides a type-safe wrapper around the raw connection handle value
1178/// with validation to ensure the handle is within the valid range (0x0000-0x0EFF).
1179///
1180/// According to the Bluetooth specification, connection handles are assigned by
1181/// the Bluetooth controller and must be unique for each active connection.
1182/// The valid range is 0x0000-0x0EFF (0-3839 decimal), with 0x0F00-0x0FFF
1183/// reserved for future use.
1184///
1185/// # Use Cases
1186/// - Tracking active Bluetooth connections in embedded systems
1187/// - Providing type safety for connection handle operations
1188/// - Ensuring compliance with Bluetooth specification limits
1189///
1190/// # Performance
1191/// This is a zero-cost abstraction - the wrapper has the same memory
1192/// layout and performance characteristics as a raw `u16`.
1193///
1194/// # Examples
1195/// ```
1196/// use renik::ConnHandle;
1197///
1198/// // Create a valid connection handle
1199/// let handle = ConnHandle::new(0x0001);
1200/// assert_eq!(handle.raw(), 0x0001);
1201///
1202/// // Handles can be converted to/from u16
1203/// let raw_value: u16 = handle.into();
1204/// let back_to_handle = ConnHandle::from(raw_value);
1205/// assert_eq!(handle, back_to_handle);
1206///
1207/// // Maximum valid handle
1208/// let max_handle = ConnHandle::new(0x0EFF);
1209/// assert_eq!(max_handle.raw(), 0x0EFF);
1210/// ```
1211///
1212/// # Panics
1213/// The `new` method panics if the provided value exceeds 0x0EFF:
1214/// ```should_panic
1215/// use renik::ConnHandle;
1216/// let invalid = ConnHandle::new(0x0F00); // Panics!
1217/// ```
1218#[derive(Debug, Clone, Copy, PartialEq, Eq, Pod, Zeroable)]
1219#[repr(transparent)]
1220#[derive(Default)]
1221pub struct ConnHandle(u16);
1222
1223impl ConnHandle {
1224    /// Create a new connection handle instance.
1225    ///
1226    /// # Parameters
1227    /// - `val`: Raw connection handle value (must be <= 0x0EFF)
1228    ///
1229    /// # Panics
1230    /// Panics if the value exceeds 0x0EFF (the maximum valid connection handle).
1231    #[must_use]
1232    pub fn new(val: u16) -> Self {
1233        assert!(val <= 0x0EFF, "Connection handle must be <= 0x0EFF");
1234        Self(val)
1235    }
1236
1237    /// Get the underlying representation.
1238    ///
1239    /// # Returns
1240    /// The raw u16 connection handle value.
1241    #[must_use]
1242    pub fn raw(self) -> u16 {
1243        self.0
1244    }
1245}
1246
1247impl From<u16> for ConnHandle {
1248    fn from(val: u16) -> Self {
1249        Self::new(val)
1250    }
1251}
1252
1253impl From<ConnHandle> for u16 {
1254    fn from(handle: ConnHandle) -> Self {
1255        handle.raw()
1256    }
1257}
1258
1259/// Connection phases for multi-phase Bluetooth connection flow
1260///
1261/// Provides 13 distinct phases for the Bluetooth connection lifecycle:
1262/// - `Idle` (0): No connection attempt
1263/// - `Discovery` (1): Discovering devices
1264/// - `Connecting` (2): Connecting to a device
1265/// - `Connected` (3): Connected, not authenticated
1266/// - `Authenticating` (4): Authentication in progress
1267/// - `SettingUpEncryption` (5): Setting up encryption
1268/// - `FullyConnected` (6): Connected, authenticated, encrypted
1269/// - `ServiceDiscovery` (7): Service discovery in progress
1270/// - `Ready` (8): Connection established with services
1271/// - `Maintaining` (9): Maintenance mode
1272/// - `Reconnecting` (10): Attempting reconnection
1273/// - `Failed` (11): Connection failed
1274/// - `Disconnecting` (12): Disconnecting
1275///
1276/// See `BluetoothConnectionState::is_valid_transition` for allowed transitions.
1277#[derive(Debug, Clone, Copy, PartialEq, Eq)]
1278#[repr(u8)]
1279pub enum BluetoothConnectionPhase {
1280    /// Initial state - no connection attempt
1281    Idle = 0,
1282    /// Discovering devices
1283    Discovery = 1,
1284    /// Connecting to a specific device
1285    Connecting = 2,
1286    /// Connected but not authenticated
1287    Connected = 3,
1288    /// Authentication in progress
1289    Authenticating = 4,
1290    /// Authenticated, setting up encryption
1291    SettingUpEncryption = 5,
1292    /// Connected, authenticated, and encrypted
1293    FullyConnected = 6,
1294    /// Service discovery in progress
1295    ServiceDiscovery = 7,
1296    /// Connection established with services
1297    Ready = 8,
1298    /// Connection maintenance mode
1299    Maintaining = 9,
1300    /// Connection lost, attempting reconnection
1301    Reconnecting = 10,
1302    /// Connection failed
1303    Failed = 11,
1304    /// Disconnecting
1305    Disconnecting = 12,
1306}
1307
1308impl Default for BluetoothConnectionPhase {
1309    fn default() -> Self {
1310        Self::Idle
1311    }
1312}
1313
1314impl BluetoothConnectionPhase {
1315    /// Returns true if the phase indicates an active connection
1316    #[must_use]
1317    pub fn is_connected(&self) -> bool {
1318        matches!(
1319            self,
1320            Self::Connected
1321                | Self::Authenticating
1322                | Self::SettingUpEncryption
1323                | Self::FullyConnected
1324                | Self::ServiceDiscovery
1325                | Self::Ready
1326                | Self::Maintaining
1327        )
1328    }
1329
1330    /// Returns true if the phase indicates the connection is secure
1331    #[must_use]
1332    pub fn is_secure(&self) -> bool {
1333        matches!(
1334            self,
1335            Self::FullyConnected | Self::ServiceDiscovery | Self::Ready | Self::Maintaining
1336        )
1337    }
1338
1339    /// Returns true if the phase indicates the connection is ready for use
1340    #[must_use]
1341    pub fn is_ready(&self) -> bool {
1342        matches!(self, Self::Ready | Self::Maintaining)
1343    }
1344}