2121
2222//! # Memory subsystem bindings
2323//!
24- //! Provides Python bindings for trajectory memory operations.
24+ //! Provides Python bindings for memory operations.
2525//! Trajectory data is built in Python using [`Poly`], [`Poly4D`],
2626//! [`CompressedStart`], and [`CompressedSegment`], then uploaded
27- //! via the [`Memory`] subsystem.
27+ //! via the [`Memory`] subsystem. LED ring colors are set using
28+ //! [`LedRingColor`] and written via [`Memory::write_led_ring`].
2829
2930use pyo3:: prelude:: * ;
3031use pyo3:: exceptions:: PyValueError ;
@@ -34,6 +35,61 @@ use std::sync::Arc;
3435use crate :: error:: to_pyerr;
3536use crazyflie_lib:: subsystems:: memory:: MemoryType ;
3637
38+ /// A single LED color and intensity for the Crazyflie LED ring.
39+ ///
40+ /// Used to build the list of 12 LED values passed to `Memory.write_led_ring()`.
41+ #[ gen_stub_pyclass]
42+ #[ pyclass]
43+ #[ derive( Clone , Debug ) ]
44+ pub struct LedRingColor {
45+ /// Red component (0-255)
46+ #[ pyo3( get, set) ]
47+ r : u8 ,
48+ /// Green component (0-255)
49+ #[ pyo3( get, set) ]
50+ g : u8 ,
51+ /// Blue component (0-255)
52+ #[ pyo3( get, set) ]
53+ b : u8 ,
54+ /// Intensity percentage (0-100); values above 100 are clamped to 100
55+ #[ pyo3( get, set) ]
56+ intensity : u8 ,
57+ }
58+
59+ #[ gen_stub_pymethods]
60+ #[ pymethods]
61+ impl LedRingColor {
62+ /// Create a new LedRingColor.
63+ ///
64+ /// # Arguments
65+ /// * `r` - Red component (0-255, default 0)
66+ /// * `g` - Green component (0-255, default 0)
67+ /// * `b` - Blue component (0-255, default 0)
68+ /// * `intensity` - Intensity percentage (0-100, default 100); clamped to 100 if higher
69+ #[ new]
70+ #[ pyo3( signature = ( r=0 , g=0 , b=0 , intensity=100 ) ) ]
71+ fn new ( r : u8 , g : u8 , b : u8 , intensity : u8 ) -> Self {
72+ Self { r, g, b, intensity : intensity. min ( 100 ) }
73+ }
74+
75+ /// Set R/G/B and optionally intensity in one call.
76+ ///
77+ /// # Arguments
78+ /// * `r` - Red component (0-255)
79+ /// * `g` - Green component (0-255)
80+ /// * `b` - Blue component (0-255)
81+ /// * `intensity` - Intensity percentage (0-100); if None, keeps current value; clamped to 100 if higher
82+ #[ pyo3( signature = ( r, g, b, intensity=None ) ) ]
83+ fn set ( & mut self , r : u8 , g : u8 , b : u8 , intensity : Option < u8 > ) {
84+ self . r = r;
85+ self . g = g;
86+ self . b = b;
87+ if let Some ( i) = intensity {
88+ self . intensity = i. min ( 100 ) ;
89+ }
90+ }
91+ }
92+
3793/// A polynomial with up to 8 coefficients.
3894///
3995/// Coefficients beyond the provided values are zero-filled.
@@ -352,6 +408,55 @@ impl Memory {
352408 } )
353409 }
354410
411+ /// Write LED colors to the Crazyflie LED ring.
412+ ///
413+ /// Opens the LED driver memory, sets all 12 LED values, writes them to
414+ /// the ring, and closes the memory.
415+ ///
416+ /// # Arguments
417+ /// * `leds` - List of exactly 12 LedRingColor instances
418+ #[ gen_stub( override_return_type( type_repr = "collections.abc.Coroutine[typing.Any, typing.Any, None]" ) ) ]
419+ fn write_led_ring < ' py > (
420+ & self ,
421+ py : Python < ' py > ,
422+ leds : Vec < LedRingColor > ,
423+ ) -> PyResult < Bound < ' py , PyAny > > {
424+ let cf = self . cf . clone ( ) ;
425+ pyo3_async_runtimes:: tokio:: future_into_py ( py, async move {
426+ if leds. len ( ) != 12 {
427+ return Err ( PyValueError :: new_err (
428+ format ! ( "Expected 12 LEDs, got {}" , leds. len( ) )
429+ ) ) ;
430+ }
431+
432+ let memories = cf. memory . get_memories ( Some ( MemoryType :: DriverLed ) ) ;
433+ let mem_device = ( * memories. first ( )
434+ . ok_or_else ( || to_pyerr ( crazyflie_lib:: Error :: MemoryError (
435+ "No LED driver memory found on Crazyflie" . to_owned ( )
436+ ) ) ) ?)
437+ . clone ( ) ;
438+
439+ let mut led_mem: crazyflie_lib:: subsystems:: memory:: LedDriverMemory =
440+ cf. memory . initialize_memory ( mem_device) . await
441+ . ok_or_else ( || to_pyerr ( crazyflie_lib:: Error :: MemoryError (
442+ "Failed to open LED driver memory" . to_owned ( )
443+ ) ) ) ?
444+ . map_err ( to_pyerr) ?;
445+
446+ for ( i, led) in leds. iter ( ) . enumerate ( ) {
447+ led_mem. leds [ i] . r = led. r ;
448+ led_mem. leds [ i] . g = led. g ;
449+ led_mem. leds [ i] . b = led. b ;
450+ led_mem. leds [ i] . intensity = led. intensity ;
451+ }
452+
453+ led_mem. write_leds ( ) . await . map_err ( to_pyerr) ?;
454+ cf. memory . close_memory ( led_mem) . await . map_err ( to_pyerr) ?;
455+
456+ Ok ( ( ) )
457+ } )
458+ }
459+
355460 /// List all memories available on the Crazyflie.
356461 ///
357462 /// Returns a list of tuples `(id, type, size)`:
0 commit comments