Skip to main content

crazyflie_lib/subsystems/memory/
led_driver.rs

1//! LED driver memory for the Crazyflie LED ring
2//!
3//! This module provides types and functionality for controlling the LEDs in
4//! the Crazyflie LED ring deck by writing RGB values to the LED driver memory.
5
6use crate::{Error, Result, subsystems::memory::{MemoryBackend, memory_types}};
7use memory_types::{FromMemoryBackend, MemoryType};
8
9const NUM_LEDS: usize = 12;
10const LED_DATA_SIZE: usize = NUM_LEDS * 2; // RGB565, 2 bytes per LED
11
12/// Represents a single LED with RGB color and intensity
13#[derive(Debug, Clone, Copy)]
14pub struct Led {
15    /// Red component (0-255)
16    pub r: u8,
17    /// Green component (0-255)
18    pub g: u8,
19    /// Blue component (0-255)
20    pub b: u8,
21    /// Intensity percentage (0-100). Values above 100 are clamped to 100 at write time.
22    pub intensity: u8,
23}
24
25impl Default for Led {
26    fn default() -> Self {
27        Self {
28            r: 0,
29            g: 0,
30            b: 0,
31            intensity: 100,
32        }
33    }
34}
35
36impl Led {
37    /// Set the R/G/B and optionally intensity in one call
38    pub fn set(&mut self, r: u8, g: u8, b: u8, intensity: Option<u8>) {
39        self.r = r;
40        self.g = g;
41        self.b = b;
42        if let Some(i) = intensity {
43            self.intensity = i;
44        }
45    }
46
47    fn to_rgb565(&self) -> u16 {
48        let intensity = self.intensity.min(100) as u32;
49        let r5 = ((((self.r as u32) * 249 + 1014) >> 11) & 0x1F) * intensity / 100;
50        let g6 = ((((self.g as u32) * 253 + 505) >> 10) & 0x3F) * intensity / 100;
51        let b5 = ((((self.b as u32) * 249 + 1014) >> 11) & 0x1F) * intensity / 100;
52        ((r5 << 11) | (g6 << 5) | b5) as u16
53    }
54}
55
56/// Memory interface for the Crazyflie LED ring
57///
58/// Provides methods to control the 12 LEDs in the Crazyflie LED ring by writing
59/// RGB values to the LED driver memory. Colors are compressed to RGB565 format
60/// with intensity applied before writing.
61#[derive(Debug)]
62pub struct LedDriverMemory {
63    /// The 12 LEDs in the ring
64    pub leds: [Led; NUM_LEDS],
65    memory: MemoryBackend,
66}
67
68impl LedDriverMemory {
69    fn from_backend(memory: MemoryBackend) -> Result<Self> {
70        if memory.memory_type == MemoryType::DriverLed {
71            Ok(Self {
72                leds: [Led::default(); NUM_LEDS],
73                memory,
74            })
75        } else {
76            Err(Error::MemoryError(format!(
77                "Expected DriverLed memory type, got {:?}",
78                memory.memory_type
79            )))
80        }
81    }
82
83    /// Write the current LED values to the Crazyflie LED ring
84    ///
85    /// Converts each LED's RGB values to RGB565 format with intensity applied,
86    /// and writes the 24-byte result to address 0x00 of the LED driver memory.
87    pub async fn write_leds(&self) -> Result<()> {
88        let mut data = Vec::with_capacity(LED_DATA_SIZE);
89        for led in &self.leds {
90            let rgb565 = led.to_rgb565();
91            data.push((rgb565 >> 8) as u8);
92            data.push((rgb565 & 0xFF) as u8);
93        }
94        self.memory.write::<fn(usize, usize)>(0x00, &data, None).await
95    }
96}
97
98impl FromMemoryBackend for LedDriverMemory {
99    async fn from_memory_backend(memory: MemoryBackend) -> Result<Self> {
100        Self::from_backend(memory)
101    }
102
103    async fn initialize_memory_backend(memory: MemoryBackend) -> Result<Self> {
104        Self::from_backend(memory)
105    }
106
107    fn close_memory(self) -> MemoryBackend {
108        self.memory
109    }
110}