crazyflie_lib/subsystems/memory/
loco2.rs1use crate::{Error, Result, subsystems::memory::{MemoryBackend, memory_types}};
8use memory_types::{FromMemoryBackend, MemoryType};
9use std::collections::HashMap;
10
11const SIZE_FLOAT: usize = std::mem::size_of::<f32>();
12
13const MAX_NR_OF_ANCHORS: usize = 16;
14const ID_LIST_LEN: usize = 1 + MAX_NR_OF_ANCHORS;
15
16const ADR_ID_LIST: usize = 0x0000;
17const ADR_ACTIVE_ID_LIST: usize = 0x1000;
18const ADR_ANCHOR_BASE: usize = 0x2000;
19
20const ANCHOR_PAGE_SIZE: usize = 0x0100;
21const ANCHOR_DATA_LEN: usize = 3 * SIZE_FLOAT + 1;
22
23#[derive(Debug, Clone, Copy, Default, PartialEq)]
25pub struct LocoAnchorData {
26 pub position: [f32; 3],
28 pub is_valid: bool,
30}
31
32impl LocoAnchorData {
33 fn from_bytes(data: &[u8]) -> Result<Self> {
34 if data.len() < ANCHOR_DATA_LEN {
35 return Err(Error::MemoryError(format!(
36 "Insufficient data for anchor: expected {} bytes, got {}",
37 ANCHOR_DATA_LEN, data.len()
38 )));
39 }
40
41 let x = f32::from_le_bytes(data[0..4].try_into().unwrap());
42 let y = f32::from_le_bytes(data[4..8].try_into().unwrap());
43 let z = f32::from_le_bytes(data[8..12].try_into().unwrap());
44 let is_valid = data[12] != 0;
45
46 Ok(Self {
47 position: [x, y, z],
48 is_valid,
49 })
50 }
51}
52
53#[derive(Debug)]
58pub struct LocoMemory2 {
59 memory: MemoryBackend,
60}
61
62impl LocoMemory2 {
63 fn from_backend(memory: MemoryBackend) -> Result<Self> {
64 if memory.memory_type == MemoryType::Loco2 {
65 Ok(Self { memory })
66 } else {
67 Err(Error::MemoryError(format!(
68 "Expected Loco2 memory type, got {:?}",
69 memory.memory_type
70 )))
71 }
72 }
73
74 pub async fn read_id_list(&self) -> Result<Vec<u8>> {
78 let data = self.memory.read::<fn(usize, usize)>(ADR_ID_LIST, ID_LIST_LEN, None).await?;
79 let count = data[0] as usize;
80 if count > MAX_NR_OF_ANCHORS {
81 return Err(Error::MemoryError(format!(
82 "Anchor count {} exceeds maximum {}", count, MAX_NR_OF_ANCHORS
83 )));
84 }
85 Ok(data[1..1 + count].to_vec())
86 }
87
88 pub async fn read_active_id_list(&self) -> Result<Vec<u8>> {
92 let data = self.memory.read::<fn(usize, usize)>(ADR_ACTIVE_ID_LIST, ID_LIST_LEN, None).await?;
93 let count = data[0] as usize;
94 if count > MAX_NR_OF_ANCHORS {
95 return Err(Error::MemoryError(format!(
96 "Active anchor count {} exceeds maximum {}", count, MAX_NR_OF_ANCHORS
97 )));
98 }
99 Ok(data[1..1 + count].to_vec())
100 }
101
102 pub async fn read_anchor_data(&self, anchor_id: u8) -> Result<LocoAnchorData> {
107 if anchor_id as usize >= MAX_NR_OF_ANCHORS {
108 return Err(Error::MemoryError(format!(
109 "Anchor ID {} out of range (0-{})",
110 anchor_id,
111 MAX_NR_OF_ANCHORS - 1
112 )));
113 }
114 let addr = ADR_ANCHOR_BASE + ANCHOR_PAGE_SIZE * anchor_id as usize;
115 let data = self.memory.read::<fn(usize, usize)>(addr, ANCHOR_DATA_LEN, None).await?;
116 LocoAnchorData::from_bytes(&data)
117 }
118
119 pub async fn read_all(&self) -> Result<LocoSystemData> {
124 let anchor_ids = self.read_id_list().await?;
125 let active_ids = self.read_active_id_list().await?;
126
127 let mut anchors = HashMap::new();
128 for &id in &anchor_ids {
129 let data = self.read_anchor_data(id).await?;
130 anchors.insert(id, data);
131 }
132
133 Ok(LocoSystemData {
134 anchor_ids,
135 active_anchor_ids: active_ids,
136 anchors,
137 })
138 }
139}
140
141#[derive(Debug, Clone)]
143pub struct LocoSystemData {
144 pub anchor_ids: Vec<u8>,
146 pub active_anchor_ids: Vec<u8>,
148 pub anchors: HashMap<u8, LocoAnchorData>,
150}
151
152impl FromMemoryBackend for LocoMemory2 {
153 async fn from_memory_backend(memory: MemoryBackend) -> Result<Self> {
154 Self::from_backend(memory)
155 }
156
157 async fn initialize_memory_backend(memory: MemoryBackend) -> Result<Self> {
158 Self::from_backend(memory)
159 }
160
161 fn close_memory(self) -> MemoryBackend {
162 self.memory
163 }
164}