Skip to main content

crazyflie_lib/subsystems/memory/
mod.rs

1//! # Memory subsystem
2//!
3//! The Crazyflie exposes a memory subsystem that allows to easily read and
4//! write various memories in the Crazyflie.
5//!
6//! During connection the memory subsystem fetches information about all the
7//! memories present in the Crazyflie. For interacting with a specific memory
8//! it's possible to using a wrapper, there's one for each memory type, or to
9//! get raw read and write access to the memory.
10
11use crate::{crtp_utils::WaitForPacket, Error, Result};
12use crazyflie_link::Packet;
13use flume as channel;
14use std::{collections::HashMap, convert::{TryFrom, TryInto}};
15use std::sync::Arc;
16use tokio::sync::Mutex;
17
18mod memory_types;
19mod eeprom_config;
20mod deckmem;
21mod raw;
22mod ow;
23mod trajectory;
24mod lighthouse;
25mod loco2;
26mod led_driver;
27
28use crate::crazyflie::MEMORY_PORT;
29
30pub use memory_types::*;
31pub use eeprom_config::*;
32pub use deckmem::*;
33pub use raw::*;
34pub use ow::*;
35pub use trajectory::*;
36pub use lighthouse::*;
37pub use loco2::*;
38pub use led_driver::*;
39
40/// # Access to the Crazyflie Memory Subsystem
41///
42/// This struct provide methods to interact with the memory subsystem. See the
43/// [memory module documentation](crate::subsystems::memory) for more context and information.
44#[derive(Debug)]
45pub struct Memory {
46    memories: Vec<MemoryDevice>,
47    backends: Vec<Mutex<Option<MemoryBackend>>>,
48    memory_read_dispatcher: MemoryDispatcher,
49    memory_write_dispatcher: MemoryDispatcher,
50}
51
52const INFO_CHANNEL: u8 = 0;
53const READ_CHANNEL: u8 = 1;
54const WRITE_CHANNEL: u8 = 2;
55
56const _CMD_INFO_VER: u8 = 0;
57const CMD_INFO_NBR: u8 = 1;
58const CMD_INFO_DETAILS: u8 = 2;
59
60#[derive(Debug)]
61struct MemoryDispatcher {
62  senders: Arc<Mutex<HashMap<u8, channel::Sender<Packet>>>>,
63}
64
65impl MemoryDispatcher {
66  fn new(downlink: channel::Receiver<Packet>, channel: u8) -> Self {
67
68    let senders: Arc<Mutex<HashMap<u8, channel::Sender<Packet>>>> = Arc::new(Mutex::new(HashMap::new()));
69    let internal_senders = senders.clone();
70
71    tokio::spawn(async move {
72      while let Ok(pk) = downlink.recv_async().await {
73        if pk.get_channel() == channel {
74          let memory_id = pk.get_data()[0];
75          if let Some(sender) = internal_senders.lock().await.get(&memory_id) {
76            let _ = sender.send_async(pk).await;
77          } else {
78            println!("Error: Received memory read response for unknown memory ID {}", memory_id);
79            break;
80          }
81        } else {
82          println!("Error: Received packet on unexpected channel {}", pk.get_channel());
83          break;
84        }
85      }
86      internal_senders.lock().await.clear();
87    });
88
89    Self {
90      senders: senders,
91    }
92  }
93
94  async fn get_channel(&mut self, memory_id: u8) -> channel::Receiver<Packet> {
95    if !self.senders.lock().await.contains_key(&memory_id) {
96      let (tx, rx) = channel::unbounded();
97      self.senders.lock().await.insert(memory_id, tx);
98      rx
99    } else {
100      panic!("Channel for memory ID {} already exists", memory_id)
101    }
102  }
103}
104
105impl Memory {
106    pub(crate) async fn new(
107        downlink: channel::Receiver<Packet>,
108        uplink: channel::Sender<Packet>,
109    ) -> Result<Self> {
110        let (info_channel_downlink, read_channel_downlink, write_channel_downlink, _misc_downlink) =
111            crate::crtp_utils::crtp_channel_dispatcher(downlink);
112
113        let mut memory = Self {
114            memories: Vec::new(),
115            backends: Vec::new(),
116            memory_read_dispatcher: MemoryDispatcher::new(read_channel_downlink.clone(), READ_CHANNEL),
117            memory_write_dispatcher: MemoryDispatcher::new(write_channel_downlink.clone(), WRITE_CHANNEL),
118        };
119
120        memory.update_memories(uplink.clone(), info_channel_downlink).await?;
121
122        Ok(memory)
123    }
124
125    async fn update_memories(&mut self, uplink: channel::Sender<Packet>, downlink: channel::Receiver<Packet>) -> Result<()> {
126      let pk = Packet::new(MEMORY_PORT, INFO_CHANNEL, vec![CMD_INFO_NBR]);
127      uplink
128          .send_async(pk)
129          .await
130          .map_err(|_| Error::Disconnected)?;
131
132      let pk = downlink.wait_packet(MEMORY_PORT, INFO_CHANNEL, &[CMD_INFO_NBR]).await?;
133      let memory_count = pk.get_data()[1];
134
135      for i in 0..memory_count {
136        let pk = Packet::new(MEMORY_PORT, INFO_CHANNEL, vec![CMD_INFO_DETAILS, i]);
137        uplink
138            .send_async(pk)
139            .await
140            .map_err(|_| Error::Disconnected)?;
141
142        let pk = downlink.wait_packet(MEMORY_PORT, INFO_CHANNEL, &[CMD_INFO_DETAILS, i]).await?;
143        let data = pk.get_data();
144        let memory_id = data[1];
145        let memory_type = MemoryType::try_from(data[2])?;
146        let memory_size = u32::from_le_bytes(data[3..7].try_into()?);
147        let raw_memory_serial = Vec::from(&data[7..]);
148
149        let memory_serial = if raw_memory_serial.iter().all(|&b| b == 0) {
150          None
151        } else {
152          Some(raw_memory_serial)
153        };
154
155        self.memories.push(MemoryDevice {
156          memory_id: memory_id,
157          memory_type: memory_type,
158          size: memory_size,
159          serial: memory_serial,
160        });
161
162        self.backends.push(Mutex::new(Some(MemoryBackend {
163          memory_id: memory_id,
164          memory_type: memory_type,
165          uplink: uplink.clone(),
166          read_downlink: self.memory_read_dispatcher.get_channel(memory_id).await,
167          write_downlink: self.memory_write_dispatcher.get_channel(memory_id).await,
168        })));
169      }
170      Ok(())
171
172    }
173
174    /// Get the list of memories in the Crazyflie, optionally filtered by type.
175    /// 
176    /// If `memory_type` is None, all memories are returned
177    /// If `memory_type` is Some(type), only memories of that type are returned
178    /// # Example
179    /// ```no_run
180    /// use crazyflie_lib::subsystems::memory::MemoryType;
181    /// use crazyflie_lib::{Crazyflie, Value, Error};
182    /// use crazyflie_lib::crazyflie_link::LinkContext;
183    /// async fn example() -> Result<(), Error> {
184    ///   let context = LinkContext::new();
185    ///   let cf = Crazyflie::connect_from_uri(
186    ///       &context,
187    ///       "radio://0/60/2M/E7E7E7E7E7",
188    ///       crazyflie_lib::NoTocCache
189    ///   ).await?;
190    ///   let memories = cf.memory.get_memories(Some(MemoryType::OneWire));
191    ///   Ok(())
192    /// };
193    /// 
194    /// ```
195    /// # Example
196    /// ```no_run
197    /// use crazyflie_lib::subsystems::memory::MemoryType;
198    /// use crazyflie_lib::{Crazyflie, Value, Error};
199    /// use crazyflie_lib::crazyflie_link::LinkContext;
200    /// async fn example() -> Result<(), Error> {
201    ///   let context = LinkContext::new();
202    ///   let cf = Crazyflie::connect_from_uri(
203    ///       &context,
204    ///       "radio://0/60/2M/E7E7E7E7E7",
205    ///       crazyflie_lib::NoTocCache
206    ///   ).await?;
207    ///   let memories = cf.memory.get_memories(None);
208    ///   Ok(())
209    /// };
210    /// ```
211    /// # Returns
212    /// A vector of references to MemoryDevice structs
213    /// If no memories are found, an empty vector is returned
214    pub fn get_memories(&self, memory_type: Option<MemoryType>) -> Vec<&MemoryDevice> {
215      match memory_type {
216        Some(ty) => self.memories.iter().filter(|m| m.memory_type == ty).collect(),
217        None => self.memories.iter().collect(),
218      }
219    }
220
221    /// Get a specific memory by its ID
222    /// 
223    /// # Arguments
224    /// * `memory` - The MemoryDevice struct representing the memory to get
225    /// # Returns
226    /// An Option containing a reference to the MemoryDevice struct if found, or None if not found
227    pub async fn open_memory<T: FromMemoryBackend>(&self, memory: MemoryDevice) -> Option<Result<T>> {
228      let backend = self.backends.get(memory.memory_id as usize)?.lock().await.take()?;
229      Some(T::from_memory_backend(backend).await)
230    }
231
232    /// Close a memory
233    /// 
234    /// # Arguments
235    /// * `memory_device` - The MemoryDevice struct representing the memory to close
236    /// * `backend` - The MemoryBackend to return to the subsystem
237    pub async fn close_memory<T: FromMemoryBackend>(&self, device: T) -> Result<()> {
238      let backend = device.close_memory();
239      if let Some(mutex) = self.backends.get(backend.memory_id as usize) {
240        let mut guard = mutex.lock().await;
241        if guard.is_none() {
242          *guard = Some(backend);
243        } else {
244          println!("Warning: Attempted to close memory ID {} which is already closed", backend.memory_id);
245        }
246      } else {
247        println!("Warning: Attempted to close memory ID {} which does not exist", backend.memory_id);
248      }
249      Ok(())
250    }
251
252    /// Get a specific memory by its ID and initialize it according to the defaults. Note that the
253    /// values will not be written to the memory by default, the user needs to handle this.
254    /// 
255    /// # Arguments
256    /// * `memory` - The MemoryDevice struct representing the memory to get
257    /// # Returns
258    /// An Option containing a reference to the MemoryDevice struct if found, or None if not found
259    pub async fn initialize_memory<T: FromMemoryBackend>(&self, memory: MemoryDevice) -> Option<Result<T>> {
260        let backend = self.backends.get(memory.memory_id as usize)?.lock().await.take()?;
261        Some(T::initialize_memory_backend(backend).await)
262    }
263
264}