crazyflie_lib/subsystems/memory/
deckmem.rs1use std::{sync::Arc, time::Duration};
2
3use crate::{
4 Error, Result,
5 subsystems::memory::{MemoryBackend, memory_types},
6};
7use memory_types::{FromMemoryBackend, MemoryType};
8use tokio::{sync::Mutex, time::sleep};
9
10const DECKMEM_VERSION_REQUIREMENT: u8 = 3;
11
12const IS_VALID_MASK: u8 = 0x01;
14const IS_STARTED_MASK: u8 = 0x02;
15const SUPPORTS_READ_MASK: u8 = 0x04;
16const SUPPORTS_WRITE_MASK: u8 = 0x08;
17const SUPPORTS_UPGRADE_MASK: u8 = 0x10;
18const UPGRADE_REQUIRED_MASK: u8 = 0x20;
19const BOOTLOADER_ACTIVE_MASK: u8 = 0x40;
20
21const CAN_RESET_TO_FIRMWARE_MASK: u8 = 0x01;
23const CAN_RESET_TO_BOOTLOADER_MASK: u8 = 0x02;
24
25const DECKMEM_MAX_SECTIONS: usize = 8;
26const DECKMEM_INFO_OFFSET: usize = 1;
27const DECKMEM_INFO_SIZE: usize = 0x20;
28const DECKMEM_CMD_OFFSET: usize = 0x1000;
29const DECKMEM_CMD_SIZE: usize = 0x20;
30const DECKMEM_CMD_NEW_FW_SIZE_OFFSET: usize = 0x0;
31const DECKMEM_CMD_BITS_OFFSET: usize = 0x4;
32
33const DECKMEM_CMD_RST_TO_FIRMWARE: u8 = 0x01;
34const DECKMEM_CMD_RST_TO_BOOTLOADER: u8 = 0x02;
35
36#[derive(Debug)]
38pub struct DeckMemory {
39 memory: Arc<Mutex<MemoryBackend>>,
41 sections: Vec<DeckMemorySection>,
44}
45
46impl FromMemoryBackend for DeckMemory {
47 async fn from_memory_backend(memory: MemoryBackend) -> Result<Self> {
48 if memory.memory_type == MemoryType::DeckMemory {
49 Ok(DeckMemory::new(memory).await?)
50 } else {
51 Err(Error::MemoryError("Wrong type of memory!".to_owned()))
52 }
53 }
54
55 async fn initialize_memory_backend(_memory: MemoryBackend) -> Result<Self> {
56 Err(Error::MemoryError(
57 "Memory does not support initializing".to_owned(),
58 ))
59 }
60
61 fn close_memory(mut self) -> MemoryBackend {
62 self.sections.clear();
64
65 Arc::try_unwrap(self.memory)
67 .map_err(|_arc| {
68 Error::MemoryError(format!("Multiple references to memory"))
69 })
70 .map(|mutex| mutex.into_inner())
71 .expect("Multiple reference to sections still held")
72 }
73}
74
75#[derive(Debug)]
76pub struct DeckMemorySection {
82 supports_read: bool,
84 supports_write: bool,
86 supports_upgrade: bool,
88 can_reset_to_firmware: bool,
90 can_reset_to_bootloader: bool,
92 required_hash: Option<u32>,
94 required_length: Option<u32>,
96 base_address: usize,
98 command_address: usize,
100 info_address: usize,
102 name: String,
104 memory: Arc<Mutex<MemoryBackend>>,
106}
107
108impl DeckMemorySection {
109 async fn from_bytes(
110 memory: Arc<Mutex<MemoryBackend>>,
111 info_offset: usize,
112 command_address: usize,
113 ) -> Result<Option<Self>> {
114 let data = memory
115 .lock()
116 .await
117 .read::<fn(usize, usize)>(info_offset, DECKMEM_INFO_SIZE, None)
118 .await?;
119
120 if data.len() < DECKMEM_INFO_SIZE {
122 return Ok(None);
123 }
124
125 let bit_field_1 = data[0];
128 let is_valid = (bit_field_1 & IS_VALID_MASK) != 0;
129 let supports_read = (bit_field_1 & SUPPORTS_READ_MASK) != 0;
130 let supports_write = (bit_field_1 & SUPPORTS_WRITE_MASK) != 0;
131 let supports_upgrade = (bit_field_1 & SUPPORTS_UPGRADE_MASK) != 0;
132
133 let bit_field_2 = data[1];
134 let can_reset_to_firmware = (bit_field_2 & CAN_RESET_TO_FIRMWARE_MASK) != 0;
135 let can_reset_to_bootloader = (bit_field_2 & CAN_RESET_TO_BOOTLOADER_MASK) != 0;
136
137 let required_hash = u32::from_le_bytes([data[2], data[3], data[4], data[5]]);
138 let required_length = u32::from_le_bytes([data[6], data[7], data[8], data[9]]);
139 let base_address = u32::from_le_bytes([data[10], data[11], data[12], data[13]]);
140
141 let name_bytes = &data[14..32];
143 let name = name_bytes
144 .iter()
145 .take_while(|&&b| b != 0)
146 .copied()
147 .collect::<Vec<u8>>();
148 let name = String::from_utf8_lossy(&name).to_string();
149
150 if is_valid {
151 Ok(Some(DeckMemorySection {
152 supports_read,
153 supports_write,
154 supports_upgrade,
155 can_reset_to_firmware,
156 can_reset_to_bootloader,
157 required_hash: match required_hash {
158 0 => None,
159 v => Some(v),
160 },
161 required_length: match required_length {
162 0 => None,
163 v => Some(v),
164 },
165 base_address: base_address as usize,
166 command_address: command_address,
167 info_address: info_offset,
168 name,
169 memory,
170 }))
171 } else {
172 Ok(None)
173 }
174 }
175
176 async fn read_info_byte(&self) -> Result<u8> {
177 let data = self.memory
178 .lock()
179 .await
180 .read::<fn(usize, usize)>(self.info_address, 1, None)
181 .await?;
182 Ok(data[0])
183 }
184
185 pub async fn is_started(&self) -> Result<bool> {
187 let data = self.read_info_byte().await?;
188 Ok((data & IS_STARTED_MASK) != 0)
189 }
190
191 pub fn supports_read(&self) -> bool {
193 self.supports_read
194 }
195
196 pub fn supports_write(&self) -> bool {
198 self.supports_write
199 }
200
201 pub fn supports_upgrade(&self) -> bool {
203 self.supports_upgrade
204 }
205
206 pub async fn upgrade_required(&self) -> Result<bool> {
208 let data = self.read_info_byte().await?;
209 Ok((data & UPGRADE_REQUIRED_MASK) != 0)
210 }
211
212 pub async fn bootloader_active(&self) -> Result<bool> {
214 let data = self.read_info_byte().await?;
215 Ok((data & BOOTLOADER_ACTIVE_MASK) != 0)
216 }
217
218 pub fn can_reset_to_firmware(&self) -> bool {
220 self.can_reset_to_firmware
221 }
222
223 pub fn can_reset_to_bootloader(&self) -> bool {
225 self.can_reset_to_bootloader
226 }
227
228 pub fn required_hash(&self) -> Option<u32> {
230 self.required_hash
231 }
232
233 pub fn required_length(&self) -> Option<u32> {
235 self.required_length
236 }
237
238 pub fn name(&self) -> &str {
240 &self.name
241 }
242
243 pub async fn flash_firmware(&self, data: &[u8]) -> Result<()> {
255 if !self.supports_upgrade {
256 return Err(Error::MemoryError(
257 "Section does not support firmware upgrade".to_owned(),
258 ));
259 }
260
261 let size = u32::try_from(data.len()).map_err(|_| {
262 Error::MemoryError(format!(
263 "Firmware too large: {} bytes exceeds u32::MAX",
264 data.len()
265 ))
266 })?;
267 self.write_new_firmware_size(size).await?;
268 self.write(0, data).await
269 }
270
271 pub async fn flash_firmware_with_progress<F>(
282 &self,
283 data: &[u8],
284 progress_callback: F,
285 ) -> Result<()>
286 where
287 F: FnMut(usize, usize),
288 {
289 if !self.supports_upgrade {
290 return Err(Error::MemoryError(
291 "Section does not support firmware upgrade".to_owned(),
292 ));
293 }
294
295 let size = u32::try_from(data.len()).map_err(|_| {
296 Error::MemoryError(format!(
297 "Firmware too large: {} bytes exceeds u32::MAX",
298 data.len()
299 ))
300 })?;
301 self.write_new_firmware_size(size).await?;
302 self.write_with_progress(0, data, progress_callback).await
303 }
304
305 async fn write_new_firmware_size(&self, size: u32) -> Result<()> {
306 self.memory
307 .lock()
308 .await
309 .write::<fn(usize, usize)>(
310 self.command_address + DECKMEM_CMD_NEW_FW_SIZE_OFFSET,
311 &size.to_le_bytes(),
312 None,
313 )
314 .await
315 }
316
317 pub async fn reset_to_bootloader(&self) -> Result<()> {
325 if !self.can_reset_to_bootloader {
326 return Err(Error::MemoryError(
327 "Section cannot reset to bootloader".to_owned(),
328 ));
329 }
330
331 self.memory
333 .lock()
334 .await
335 .write::<fn(usize, usize)>(self.command_address + DECKMEM_CMD_BITS_OFFSET, &[DECKMEM_CMD_RST_TO_BOOTLOADER], None)
336 .await?;
337
338 sleep(Duration::from_millis(10)).await;
340
341 Ok(())
342 }
343
344 pub async fn reset_to_firmware(&self) -> Result<()> {
352 if !self.can_reset_to_firmware {
353 return Err(Error::MemoryError(
354 "Section cannot reset to firmware".to_owned(),
355 ));
356 }
357
358 self.memory
360 .lock()
361 .await
362 .write::<fn(usize, usize)>(self.command_address + DECKMEM_CMD_BITS_OFFSET, &[DECKMEM_CMD_RST_TO_FIRMWARE], None)
363 .await?;
364
365 sleep(Duration::from_millis(10)).await;
367
368 Ok(())
369 }
370
371 async fn write(&self, address: usize, data: &[u8]) -> Result<()> {
382 if !self.supports_write {
383 return Err(Error::MemoryError(
384 "Section does not support write".to_owned(),
385 ));
386 }
387
388 self.memory
389 .lock()
390 .await
391 .write::<fn(usize, usize)>(self.base_address + address, data, None)
392 .await
393 }
394
395 async fn write_with_progress<F>(
408 &self,
409 address: usize,
410 data: &[u8],
411 progress_callback: F,
412 ) -> Result<()>
413 where
414 F: FnMut(usize, usize),
415 {
416 if !self.supports_write {
417 return Err(Error::MemoryError(
418 "Section does not support write".to_owned(),
419 ));
420 }
421
422 self.memory
423 .lock()
424 .await
425 .write(self.base_address + address, data, Some(progress_callback))
426 .await
427 }
428
429 pub async fn read(&self, address: usize, length: usize) -> Result<Vec<u8>> {
437 if !self.supports_read {
438 return Err(Error::MemoryError(
439 "Section does not support read".to_owned(),
440 ));
441 }
442
443 self
444 .memory
445 .lock()
446 .await
447 .read::<fn(usize, usize)>(self.base_address + address, length, None)
448 .await
449 }
450
451 pub async fn read_with_progress<F>(
461 &self,
462 address: usize,
463 length: usize,
464 progress_callback: F,
465 ) -> Result<Vec<u8>>
466 where
467 F: FnMut(usize, usize),
468 {
469 if !self.supports_read {
470 return Err(Error::MemoryError(
471 "Section does not support read".to_owned(),
472 ));
473 }
474
475 self.memory
476 .lock()
477 .await
478 .read(self.base_address + address, length, Some(progress_callback))
479 .await
480 }
481}
482
483impl DeckMemory {
484 pub(crate) async fn new(memory: MemoryBackend) -> Result<Self> {
485 let sharable_memory = Arc::new(Mutex::new(memory));
486
487 let info = sharable_memory
488 .lock()
489 .await
490 .read::<fn(usize, usize)>(0, 1, None)
491 .await?;
492
493 let version = info[0];
495 if version != DECKMEM_VERSION_REQUIREMENT {
496 return Err(Error::MemoryError(format!(
497 "Unsupported deck memory version: {}",
498 version
499 )));
500 }
501
502 let mut sections: Vec<DeckMemorySection> = Vec::new();
503 for i in 0..DECKMEM_MAX_SECTIONS {
504 let info_base = DECKMEM_INFO_OFFSET + i * DECKMEM_INFO_SIZE;
505 let cmd_base = DECKMEM_CMD_OFFSET + i * DECKMEM_CMD_SIZE;
506 if let Some(section) =
507 DeckMemorySection::from_bytes(sharable_memory.clone(), info_base, cmd_base).await?
508 {
509 sections.push(section);
510 }
511 }
512
513 Ok(DeckMemory {
514 memory: sharable_memory,
515 sections,
516 })
517 }
518
519 pub fn sections(&self) -> &[DeckMemorySection] {
523 &self.sections
524 }
525
526 pub fn section(&self, name: &str) -> Option<&DeckMemorySection> {
532 self.sections.iter().find(|s| s.name == name)
533 }
534}