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,66 @@ 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) ]
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); values above 100 are clamped to 100
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+ #[ setter]
76+ fn set_intensity ( & mut self , value : u8 ) {
77+ self . intensity = value. min ( 100 ) ;
78+ }
79+
80+ /// Set R/G/B and optionally intensity in one call.
81+ ///
82+ /// # Arguments
83+ /// * `r` - Red component (0-255)
84+ /// * `g` - Green component (0-255)
85+ /// * `b` - Blue component (0-255)
86+ /// * `intensity` - Intensity percentage (0-100); if None, keeps current value; clamped to 100 if higher
87+ #[ pyo3( signature = ( r, g, b, intensity=None ) ) ]
88+ fn set ( & mut self , r : u8 , g : u8 , b : u8 , intensity : Option < u8 > ) {
89+ self . r = r;
90+ self . g = g;
91+ self . b = b;
92+ if let Some ( i) = intensity {
93+ self . intensity = i. min ( 100 ) ;
94+ }
95+ }
96+ }
97+
3798/// A polynomial with up to 8 coefficients.
3899///
39100/// Coefficients beyond the provided values are zero-filled.
@@ -352,6 +413,58 @@ impl Memory {
352413 } )
353414 }
354415
416+ /// Write LED colors to the Crazyflie LED ring.
417+ ///
418+ /// Opens the LED driver memory, sets all 12 LED values, writes them to
419+ /// the ring, and closes the memory.
420+ ///
421+ /// # Arguments
422+ /// * `leds` - List of exactly 12 LedRingColor instances
423+ #[ gen_stub( override_return_type( type_repr = "collections.abc.Coroutine[typing.Any, typing.Any, None]" ) ) ]
424+ fn write_led_ring < ' py > (
425+ & self ,
426+ py : Python < ' py > ,
427+ leds : Vec < LedRingColor > ,
428+ ) -> PyResult < Bound < ' py , PyAny > > {
429+ let cf = self . cf . clone ( ) ;
430+ pyo3_async_runtimes:: tokio:: future_into_py ( py, async move {
431+ if leds. len ( ) != 12 {
432+ return Err ( PyValueError :: new_err (
433+ format ! ( "Expected 12 LEDs, got {}" , leds. len( ) )
434+ ) ) ;
435+ }
436+
437+ let memories = cf. memory . get_memories ( Some ( MemoryType :: DriverLed ) ) ;
438+ let mem_device = ( * memories. first ( )
439+ . ok_or_else ( || to_pyerr ( crazyflie_lib:: Error :: MemoryError (
440+ "No LED driver memory found on Crazyflie" . to_owned ( )
441+ ) ) ) ?)
442+ . clone ( ) ;
443+
444+ let mut led_mem: crazyflie_lib:: subsystems:: memory:: LedDriverMemory =
445+ cf. memory . initialize_memory ( mem_device) . await
446+ . ok_or_else ( || to_pyerr ( crazyflie_lib:: Error :: MemoryError (
447+ "Failed to open LED driver memory" . to_owned ( )
448+ ) ) ) ?
449+ . map_err ( to_pyerr) ?;
450+
451+ for ( i, led) in leds. iter ( ) . enumerate ( ) {
452+ led_mem. leds [ i] . r = led. r ;
453+ led_mem. leds [ i] . g = led. g ;
454+ led_mem. leds [ i] . b = led. b ;
455+ led_mem. leds [ i] . intensity = led. intensity ;
456+ }
457+
458+ let write_result = led_mem. write_leds ( ) . await . map_err ( to_pyerr) ;
459+ let close_result = cf. memory . close_memory ( led_mem) . await . map_err ( to_pyerr) ;
460+
461+ write_result?;
462+ close_result?;
463+
464+ Ok ( ( ) )
465+ } )
466+ }
467+
355468 /// List all memories available on the Crazyflie.
356469 ///
357470 /// Returns a list of tuples `(id, type, size)`:
0 commit comments