pokeys-lib 1.0.4

Pure Rust core library for PoKeys device control - USB/Network connectivity, I/O, PWM, encoders, SPI/I2C protocols
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
//! uSPIBridge protocol implementation
//!
//! This module provides uSPIBridge-specific functionality for PoKeys devices,
//! including custom segment mapping and display configuration for MAX7219 devices.

use crate::device::PoKeysDevice;
use crate::error::Result;
use crate::types::I2cStatus;

/// uSPIBridge-specific I2C commands for display control and virtual devices
///
/// All commands are now available via I2C interface after firmware implementation.
#[derive(Debug, Clone, Copy, PartialEq)]
#[repr(u8)]
pub enum USPIBridgeCommand {
    // Device Commands (0x10-0x2F) - All implemented in I2C
    SetBrightness = 0x11, // Set device brightness ✅
    DisplayText = 0x20,   // Display text on device ✅
    DisplayNumber = 0x21, // Display number on device ✅
    SetCharacter = 0x22,  // Set character at position ✅
    SetPattern = 0x23,    // Set raw segment pattern ✅
    SetDecimal = 0x24,    // Set decimal point ✅
    ClearDevice = 0x25,   // Clear device ✅

    // Segment Mapping Commands (0x26-0x2F) - Now implemented in I2C
    SetSegmentMapping = 0x26,     // Set custom segment mapping array ✅
    SetSegmentMappingType = 0x27, // Set predefined segment mapping type ✅
    GetSegmentMapping = 0x28,     // Get current segment mapping ✅
    TestSegmentMapping = 0x29,    // Test segment mapping with pattern ✅

    // Virtual Display Commands (0x40-0x4F) - All implemented in I2C
    CreateVirtualDevice = 0x40, // Create virtual device ✅
    DeleteVirtualDevice = 0x41, // Delete virtual device ✅
    ListVirtualDevices = 0x42,  // List virtual devices ✅
    VirtualText = 0x43,         // Virtual display text ✅
    VirtualBrightness = 0x44,   // Virtual device brightness ✅
    VirtualClear = 0x45,        // Clear virtual display ✅
    VirtualScrollLeft = 0x46,   // Virtual scroll left ✅
    VirtualScrollRight = 0x47,  // Virtual scroll right ✅
    VirtualFlash = 0x48,        // Virtual flash ✅
    VirtualStop = 0x49,         // Stop virtual effect ✅

    // System Commands (0x50-0x5F) - Implemented in I2C
    SystemReset = 0x50,  // Reset system/devices ✅
    SystemStatus = 0x51, // Get system status ✅
    SystemConfig = 0x52, // System configuration (Serial only)
}

/// Predefined segment mapping types for different display manufacturers
///
/// Values match the uSPIBridge firmware SegmentMappingType enum:
/// - C++ enum class values are implicitly 0, 1, 2, 3, 4, 5
/// - I2C interface currently only accepts 0-4 for setSegmentMappingType
/// - Value 5 (Custom) is used internally when custom arrays are provided
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(u8)]
pub enum SegmentMappingType {
    /// Standard MAX7219 mapping (A=6, B=5, C=4, D=3, E=2, F=1, G=0, DP=7)
    Standard = 0,
    /// Completely reversed bit order mapping
    Reversed = 1,
    /// Common cathode display variant mapping
    CommonCathode = 2,
    /// SparkFun Serial 7-Segment Display mapping
    SparkfunSerial = 3,
    /// Adafruit LED Backpack mapping
    AdafruitBackpack = 4,
    /// User-defined custom mapping (used internally)
    Custom = 5,
}

impl Default for SegmentMappingType {
    fn default() -> Self {
        Self::Standard
    }
}

/// Segment mapping configuration for custom 7-segment display wiring
#[derive(Debug, Clone, PartialEq)]
pub struct SegmentMapping {
    /// The type of segment mapping being used
    pub mapping_type: SegmentMappingType,
    /// Custom bit mapping array (only used when mapping_type is Custom)
    pub custom_mapping: Option<[u8; 8]>,
}

impl Default for SegmentMapping {
    fn default() -> Self {
        Self {
            mapping_type: SegmentMappingType::Standard,
            custom_mapping: None,
        }
    }
}

impl SegmentMapping {
    /// Create a new segment mapping with a predefined type
    pub fn new(mapping_type: SegmentMappingType) -> Self {
        Self {
            mapping_type,
            custom_mapping: None,
        }
    }

    /// Create a new segment mapping with a custom mapping array
    pub fn custom(mapping: [u8; 8]) -> Self {
        Self {
            mapping_type: SegmentMappingType::Custom,
            custom_mapping: Some(mapping),
        }
    }

    /// Check if this mapping uses a custom array
    pub fn is_custom(&self) -> bool {
        self.mapping_type == SegmentMappingType::Custom
    }

    /// Get the mapping array if it's custom
    pub fn get_custom_mapping(&self) -> Option<&[u8; 8]> {
        self.custom_mapping.as_ref()
    }
}

/// uSPIBridge configuration for multiple MAX7219 devices
#[derive(Debug, Clone)]
pub struct USPIBridgeConfig {
    /// Number of MAX7219 devices in the daisy chain
    pub device_count: u8,
    /// Segment mappings for each device
    pub segment_mappings: Vec<SegmentMapping>,
    /// Default brightness level (0-15)
    pub default_brightness: u8,
    /// Maximum number of virtual devices supported
    pub max_virtual_devices: u8,
}

impl Default for USPIBridgeConfig {
    fn default() -> Self {
        Self::new()
    }
}

impl USPIBridgeConfig {
    /// Create a new uSPIBridge configuration with default settings
    pub fn new() -> Self {
        Self {
            device_count: 8,
            segment_mappings: vec![SegmentMapping::default(); 8],
            default_brightness: 8,
            max_virtual_devices: 16,
        }
    }

    /// Set the number of devices in the daisy chain
    pub fn with_device_count(mut self, count: u8) -> Self {
        self.device_count = count;
        // Ensure we have enough segment mappings
        self.segment_mappings
            .resize(count as usize, SegmentMapping::default());
        self
    }

    /// Set the segment mapping for a specific device
    pub fn with_segment_mapping(mut self, device_id: usize, mapping: SegmentMapping) -> Self {
        if device_id < self.segment_mappings.len() {
            self.segment_mappings[device_id] = mapping;
        }
        self
    }

    /// Set the same segment mapping for all devices
    pub fn with_all_devices_segment_mapping(mut self, mapping: SegmentMapping) -> Self {
        for device_mapping in &mut self.segment_mappings {
            *device_mapping = mapping.clone();
        }
        self
    }

    /// Set the default brightness level
    pub fn with_default_brightness(mut self, brightness: u8) -> Self {
        self.default_brightness = brightness.min(15);
        self
    }

    /// Set the maximum number of virtual devices
    pub fn with_max_virtual_devices(mut self, max_devices: u8) -> Self {
        self.max_virtual_devices = max_devices;
        self
    }
}

/// uSPIBridge protocol implementation
impl PoKeysDevice {
    /// Write I2C command with proper uSPIBridge packet structure
    ///
    /// # Arguments
    /// * `slave_address` - I2C slave address of the uSPIBridge device
    /// * `command` - uSPIBridge command type
    /// * `device_id` - Target device ID (for device-specific commands)
    /// * `data` - Command payload data
    ///
    /// # Returns
    /// I2C operation status
    pub fn uspibridge_write_command(
        &mut self,
        slave_address: u8,
        command: USPIBridgeCommand,
        device_id: u8,
        data: &[u8],
    ) -> Result<I2cStatus> {
        let mut packet = Vec::new();
        packet.push(command as u8); // Command type
        packet.push(device_id); // Device ID
        packet.push(data.len() as u8); // Data length
        packet.extend_from_slice(data); // Data payload

        // Calculate XOR checksum
        let mut checksum = 0u8;
        for &byte in &packet {
            checksum ^= byte;
        }
        packet.push(checksum);

        self.i2c_write(slave_address, &packet)
    }

    /// Set custom segment mapping for a specific device
    ///
    /// # Arguments
    /// * `slave_address` - I2C slave address of the uSPIBridge device
    /// * `device_id` - Target MAX7219 device ID (0-based)
    /// * `mapping` - Array of 8 values mapping standard bits to custom bits
    ///
    /// # Returns
    /// I2C operation status
    pub fn uspibridge_set_segment_mapping(
        &mut self,
        slave_address: u8,
        device_id: u8,
        mapping: &[u8; 8],
    ) -> Result<I2cStatus> {
        self.uspibridge_write_command(
            slave_address,
            USPIBridgeCommand::SetSegmentMapping,
            device_id,
            mapping,
        )
    }

    /// Set predefined segment mapping type for a specific device
    ///
    /// # Arguments
    /// * `slave_address` - I2C slave address of the uSPIBridge device
    /// * `device_id` - Target MAX7219 device ID (0-based)
    /// * `mapping_type` - Predefined mapping type to use (0-4 supported)
    ///
    /// # Returns
    /// I2C operation status
    pub fn uspibridge_set_segment_mapping_type(
        &mut self,
        slave_address: u8,
        device_id: u8,
        mapping_type: SegmentMappingType,
    ) -> Result<I2cStatus> {
        let data = vec![mapping_type as u8];
        self.uspibridge_write_command(
            slave_address,
            USPIBridgeCommand::SetSegmentMappingType,
            device_id,
            &data,
        )
    }

    /// Get current segment mapping for a specific device
    ///
    /// # Arguments
    /// * `slave_address` - I2C slave address of the uSPIBridge device
    /// * `device_id` - Target MAX7219 device ID (0-based)
    ///
    /// # Returns
    /// Tuple of (I2C status, optional segment mapping array)
    pub fn uspibridge_get_segment_mapping(
        &mut self,
        slave_address: u8,
        device_id: u8,
    ) -> Result<(I2cStatus, Option<[u8; 8]>)> {
        // Send get mapping command
        let status = self.uspibridge_write_command(
            slave_address,
            USPIBridgeCommand::GetSegmentMapping,
            device_id,
            &[],
        )?;

        if status != I2cStatus::Ok {
            return Ok((status, None));
        }

        // Wait for response processing
        std::thread::sleep(std::time::Duration::from_millis(10));

        // Read response (expecting 8 bytes of mapping data)
        let (read_status, response_data) = self.i2c_read(slave_address, 10)?;

        if read_status == I2cStatus::Ok && response_data.len() >= 8 {
            let mut mapping = [0u8; 8];
            mapping.copy_from_slice(&response_data[0..8]);
            Ok((read_status, Some(mapping)))
        } else {
            Ok((read_status, None))
        }
    }

    /// Test segment mapping with a specific pattern
    ///
    /// This command displays a test pattern on the specified device to verify
    /// that the segment mapping is working correctly.
    ///
    /// # Arguments
    /// * `slave_address` - I2C slave address of the uSPIBridge device
    /// * `device_id` - Target MAX7219 device ID (0-based)
    /// * `test_pattern` - 8-bit pattern to display for testing
    ///
    /// # Returns
    /// I2C operation status
    pub fn uspibridge_test_segment_mapping(
        &mut self,
        slave_address: u8,
        device_id: u8,
        test_pattern: u8,
    ) -> Result<I2cStatus> {
        let data = vec![test_pattern];
        self.uspibridge_write_command(
            slave_address,
            USPIBridgeCommand::TestSegmentMapping,
            device_id,
            &data,
        )
    }

    /// Display text on a specific MAX7219 device
    ///
    /// # Arguments
    /// * `slave_address` - I2C slave address of the uSPIBridge device
    /// * `device_id` - Target MAX7219 device ID (0-based)
    /// * `text` - Text to display on the device
    ///
    /// # Returns
    /// I2C operation status
    pub fn uspibridge_display_text(
        &mut self,
        slave_address: u8,
        device_id: u8,
        text: &str,
    ) -> Result<I2cStatus> {
        self.uspibridge_write_command(
            slave_address,
            USPIBridgeCommand::DisplayText,
            device_id,
            text.as_bytes(),
        )
    }

    /// Display a number on a specific MAX7219 device
    ///
    /// # Arguments
    /// * `slave_address` - I2C slave address of the uSPIBridge device
    /// * `device_id` - Target MAX7219 device ID (0-based)
    /// * `number` - 32-bit number to display
    ///
    /// # Returns
    /// I2C operation status
    pub fn uspibridge_display_number(
        &mut self,
        slave_address: u8,
        device_id: u8,
        number: u32,
    ) -> Result<I2cStatus> {
        let data = number.to_le_bytes();
        self.uspibridge_write_command(
            slave_address,
            USPIBridgeCommand::DisplayNumber,
            device_id,
            &data,
        )
    }

    /// Set a character at a specific position on a MAX7219 device
    ///
    /// # Arguments
    /// * `slave_address` - I2C slave address of the uSPIBridge device
    /// * `device_id` - Target MAX7219 device ID (0-based)
    /// * `position` - Position on the display (0-7)
    /// * `character` - Character to display
    ///
    /// # Returns
    /// I2C operation status
    pub fn uspibridge_set_character(
        &mut self,
        slave_address: u8,
        device_id: u8,
        position: u8,
        character: u8,
    ) -> Result<I2cStatus> {
        let data = vec![position, character];
        self.uspibridge_write_command(
            slave_address,
            USPIBridgeCommand::SetCharacter,
            device_id,
            &data,
        )
    }

    /// Set a raw segment pattern at a specific position on a MAX7219 device
    ///
    /// # Arguments
    /// * `slave_address` - I2C slave address of the uSPIBridge device
    /// * `device_id` - Target MAX7219 device ID (0-based)
    /// * `position` - Position on the display (0-7)
    /// * `pattern` - 8-bit segment pattern
    ///
    /// # Returns
    /// I2C operation status
    pub fn uspibridge_set_pattern(
        &mut self,
        slave_address: u8,
        device_id: u8,
        position: u8,
        pattern: u8,
    ) -> Result<I2cStatus> {
        let data = vec![position, pattern];
        self.uspibridge_write_command(
            slave_address,
            USPIBridgeCommand::SetPattern,
            device_id,
            &data,
        )
    }

    /// Set decimal point at a specific position on a MAX7219 device
    ///
    /// # Arguments
    /// * `slave_address` - I2C slave address of the uSPIBridge device
    /// * `device_id` - Target MAX7219 device ID (0-based)
    /// * `position` - Position on the display (0-7)
    /// * `state` - Decimal point state (0=off, 1=on)
    ///
    /// # Returns
    /// I2C operation status
    pub fn uspibridge_set_decimal(
        &mut self,
        slave_address: u8,
        device_id: u8,
        position: u8,
        state: bool,
    ) -> Result<I2cStatus> {
        let data = vec![position, if state { 1 } else { 0 }];
        self.uspibridge_write_command(
            slave_address,
            USPIBridgeCommand::SetDecimal,
            device_id,
            &data,
        )
    }

    /// Set brightness for a specific MAX7219 device
    ///
    /// # Arguments
    /// * `slave_address` - I2C slave address of the uSPIBridge device
    /// * `device_id` - Target MAX7219 device ID (0-based)
    /// * `brightness` - Brightness level (0-15)
    ///
    /// # Returns
    /// I2C operation status
    pub fn uspibridge_set_brightness(
        &mut self,
        slave_address: u8,
        device_id: u8,
        brightness: u8,
    ) -> Result<I2cStatus> {
        let data = vec![brightness.min(15)];
        self.uspibridge_write_command(
            slave_address,
            USPIBridgeCommand::SetBrightness,
            device_id,
            &data,
        )
    }

    /// Clear a specific MAX7219 device
    ///
    /// # Arguments
    /// * `slave_address` - I2C slave address of the uSPIBridge device
    /// * `device_id` - Target MAX7219 device ID (0-based)
    ///
    /// # Returns
    /// I2C operation status
    pub fn uspibridge_clear_device(
        &mut self,
        slave_address: u8,
        device_id: u8,
    ) -> Result<I2cStatus> {
        self.uspibridge_write_command(
            slave_address,
            USPIBridgeCommand::ClearDevice,
            device_id,
            &[],
        )
    }

    /// Set text on a virtual display
    ///
    /// # Arguments
    /// * `slave_address` - I2C slave address of the uSPIBridge device
    /// * `virtual_id` - Virtual display ID (0-based)
    /// * `text` - Text to display
    ///
    /// # Returns
    /// I2C operation status
    pub fn uspibridge_virtual_text(
        &mut self,
        slave_address: u8,
        virtual_id: u8,
        text: &str,
    ) -> Result<I2cStatus> {
        self.uspibridge_write_command(
            slave_address,
            USPIBridgeCommand::VirtualText,
            virtual_id,
            text.as_bytes(),
        )
    }

    /// Create a new virtual device
    ///
    /// # Arguments
    /// * `slave_address` - I2C slave address of the uSPIBridge device
    /// * `virtual_id` - Virtual device ID to create (0-based)
    /// * `physical_devices` - Array of physical device IDs to map to this virtual device
    ///
    /// # Returns
    /// I2C operation status
    pub fn uspibridge_create_virtual_device(
        &mut self,
        slave_address: u8,
        virtual_id: u8,
        physical_devices: &[u8],
    ) -> Result<I2cStatus> {
        self.uspibridge_write_command(
            slave_address,
            USPIBridgeCommand::CreateVirtualDevice,
            virtual_id,
            physical_devices,
        )
    }

    /// Delete a virtual device
    ///
    /// # Arguments
    /// * `slave_address` - I2C slave address of the uSPIBridge device
    /// * `virtual_id` - Virtual device ID to delete (0-based)
    ///
    /// # Returns
    /// I2C operation status
    pub fn uspibridge_delete_virtual_device(
        &mut self,
        slave_address: u8,
        virtual_id: u8,
    ) -> Result<I2cStatus> {
        self.uspibridge_write_command(
            slave_address,
            USPIBridgeCommand::DeleteVirtualDevice,
            virtual_id,
            &[],
        )
    }

    /// List all virtual devices
    ///
    /// # Arguments
    /// * `slave_address` - I2C slave address of the uSPIBridge device
    ///
    /// # Returns
    /// Tuple of (I2C status, optional virtual device list data)
    pub fn uspibridge_list_virtual_devices(
        &mut self,
        slave_address: u8,
    ) -> Result<(I2cStatus, Option<Vec<u8>>)> {
        let status = self.uspibridge_write_command(
            slave_address,
            USPIBridgeCommand::ListVirtualDevices,
            0, // Device ID not used for this command
            &[],
        )?;

        if status != I2cStatus::Ok {
            return Ok((status, None));
        }

        // Wait for response processing
        std::thread::sleep(std::time::Duration::from_millis(10));

        // Read response
        let (read_status, response_data) = self.i2c_read(slave_address, 32)?;
        Ok((read_status, Some(response_data)))
    }

    /// Set brightness for a virtual device
    ///
    /// # Arguments
    /// * `slave_address` - I2C slave address of the uSPIBridge device
    /// * `virtual_id` - Virtual device ID (0-based)
    /// * `brightness` - Brightness level (0-15)
    ///
    /// # Returns
    /// I2C operation status
    pub fn uspibridge_virtual_brightness(
        &mut self,
        slave_address: u8,
        virtual_id: u8,
        brightness: u8,
    ) -> Result<I2cStatus> {
        let data = vec![brightness.min(15)];
        self.uspibridge_write_command(
            slave_address,
            USPIBridgeCommand::VirtualBrightness,
            virtual_id,
            &data,
        )
    }

    /// Start scrolling effect on a virtual display
    ///
    /// # Arguments
    /// * `slave_address` - I2C slave address of the uSPIBridge device
    /// * `virtual_id` - Virtual display ID (0-based)
    /// * `text` - Text to scroll
    /// * `speed_ms` - Scroll speed in milliseconds
    /// * `direction_left` - True for left scroll, false for right scroll
    ///
    /// # Returns
    /// I2C operation status
    pub fn uspibridge_virtual_scroll(
        &mut self,
        slave_address: u8,
        virtual_id: u8,
        text: &str,
        speed_ms: u16,
        direction_left: bool,
    ) -> Result<I2cStatus> {
        let mut data = text.as_bytes().to_vec();
        data.extend_from_slice(&speed_ms.to_le_bytes());

        let command = if direction_left {
            USPIBridgeCommand::VirtualScrollLeft
        } else {
            USPIBridgeCommand::VirtualScrollRight
        };

        self.uspibridge_write_command(slave_address, command, virtual_id, &data)
    }

    /// Start flashing effect on a virtual display
    ///
    /// # Arguments
    /// * `slave_address` - I2C slave address of the uSPIBridge device
    /// * `virtual_id` - Virtual display ID (0-based)
    /// * `text` - Text to flash
    /// * `interval_ms` - Flash interval in milliseconds
    ///
    /// # Returns
    /// I2C operation status
    pub fn uspibridge_virtual_flash(
        &mut self,
        slave_address: u8,
        virtual_id: u8,
        text: &str,
        interval_ms: u16,
    ) -> Result<I2cStatus> {
        let mut data = text.as_bytes().to_vec();
        data.extend_from_slice(&interval_ms.to_le_bytes());

        self.uspibridge_write_command(
            slave_address,
            USPIBridgeCommand::VirtualFlash,
            virtual_id,
            &data,
        )
    }

    /// Stop effects on a virtual display
    ///
    /// # Arguments
    /// * `slave_address` - I2C slave address of the uSPIBridge device
    /// * `virtual_id` - Virtual display ID (0-based)
    ///
    /// # Returns
    /// I2C operation status
    pub fn uspibridge_virtual_stop(
        &mut self,
        slave_address: u8,
        virtual_id: u8,
    ) -> Result<I2cStatus> {
        self.uspibridge_write_command(
            slave_address,
            USPIBridgeCommand::VirtualStop,
            virtual_id,
            &[],
        )
    }

    /// Clear a virtual display
    ///
    /// # Arguments
    /// * `slave_address` - I2C slave address of the uSPIBridge device
    /// * `virtual_id` - Virtual display ID (0-based)
    ///
    /// # Returns
    /// I2C operation status
    pub fn uspibridge_virtual_clear(
        &mut self,
        slave_address: u8,
        virtual_id: u8,
    ) -> Result<I2cStatus> {
        self.uspibridge_write_command(
            slave_address,
            USPIBridgeCommand::VirtualClear,
            virtual_id,
            &[],
        )
    }

    /// Reset the uSPIBridge system
    ///
    /// # Arguments
    /// * `slave_address` - I2C slave address of the uSPIBridge device
    ///
    /// # Returns
    /// I2C operation status
    pub fn uspibridge_system_reset(&mut self, slave_address: u8) -> Result<I2cStatus> {
        self.uspibridge_write_command(slave_address, USPIBridgeCommand::SystemReset, 0, &[])
    }

    /// Get uSPIBridge system status
    ///
    /// # Arguments
    /// * `slave_address` - I2C slave address of the uSPIBridge device
    ///
    /// # Returns
    /// Tuple of (I2C status, optional status data)
    pub fn uspibridge_system_status(
        &mut self,
        slave_address: u8,
    ) -> Result<(I2cStatus, Option<Vec<u8>>)> {
        let status =
            self.uspibridge_write_command(slave_address, USPIBridgeCommand::SystemStatus, 0, &[])?;

        if status != I2cStatus::Ok {
            return Ok((status, None));
        }

        // Wait for response processing
        std::thread::sleep(std::time::Duration::from_millis(10));

        // Read response
        let (read_status, response_data) = self.i2c_read(slave_address, 16)?;
        Ok((read_status, Some(response_data)))
    }
}