crazyflie_lib/subsystems/memory/
ow.rs

1use std::collections::HashMap;
2
3use crate::{subsystems::memory::{memory_types, MemoryBackend}, Error, Result};
4use memory_types::{FromMemoryBackend, MemoryType};
5
6/// Describes the content of a Crazyflie decks 1-wire memory
7#[derive(Debug)]
8pub struct OwMemory {
9    memory: MemoryBackend,
10    /// Bitmap of used GPIO pins used for output
11    used_pins: u32,
12    /// Vendor ID
13    vid: u8,
14    /// Product ID
15    pid: u8,
16    /// Key-value pairs of elements stored in the memory
17    elements: HashMap<String, String>
18  }
19
20  impl OwMemory {
21    /// Gets the bitmap of used GPIO pins
22    pub fn used_pins(&self) -> u32 {
23      self.used_pins
24    }
25
26    /// Sets the bitmap of used GPIO pins
27    pub fn set_used_pins(&mut self, used_pins: u32) {
28      self.used_pins = used_pins;
29    }
30
31    /// Gets the vendor ID
32    pub fn vid(&self) -> u8 {
33      self.vid
34    }
35
36    /// Sets the vendor ID
37    pub fn set_vid(&mut self, vid: u8) {
38      self.vid = vid;
39    }
40
41    /// Gets the product ID
42    pub fn pid(&self) -> u8 {
43      self.pid
44    }
45
46    /// Sets the product ID
47    pub fn set_pid(&mut self, pid: u8) {
48      self.pid = pid;
49    }
50
51    /// Gets a reference to the elements map
52    pub fn elements(&self) -> &HashMap<String, String> {
53      &self.elements
54    }
55
56    /// Gets a mutable reference to the elements map
57    pub fn elements_mut(&mut self) -> &mut HashMap<String, String> {
58      &mut self.elements
59    }
60
61    /// Sets the elements map
62    pub fn set_elements(&mut self, elements: HashMap<String, String>) {
63      self.elements = elements;
64    }
65}
66
67impl FromMemoryBackend for OwMemory {
68    async fn from_memory_backend(memory: MemoryBackend) -> Result<Self> {
69        if memory.memory_type == MemoryType::OneWire {
70            Ok(OwMemory::new(memory).await?)
71        } else {
72            Err(Error::MemoryError("Wrong type of memory!".to_owned()))
73        }
74    }
75
76    async fn initialize_memory_backend(memory: MemoryBackend) -> Result<Self> {
77        if memory.memory_type == MemoryType::OneWire {
78            Ok(OwMemory::initialize(memory).await?)
79        } else {
80            Err(Error::MemoryError("Wrong type of memory!".to_owned()))
81        }
82    }
83
84    fn close_memory(self) -> MemoryBackend {
85      self.memory
86    }
87}
88
89impl OwMemory {
90    pub(crate) async fn new(memory: MemoryBackend) -> Result<Self> {
91        let header = memory.read::<fn(usize, usize)>(0, 8, None).await?;
92
93        // Validate header byte
94        if header[0] != 0xEB {
95          return Err(Error::MemoryError("Invalid OneWire header".to_owned()));
96        }
97
98        // Extract fields from header
99        let used_pins = u32::from_le_bytes([header[1], header[2], header[3], header[4]]);
100        let vid = header[5];
101        let pid = header[6];
102        let crc_byte = header[7];
103
104        // Calculate CRC32 of bytes 0-6 and check against LSB
105        let crc_data = &header[0..7];
106        let calculated_crc = crc32fast::hash(crc_data);
107        let expected_crc_lsb = (calculated_crc & 0xFF) as u8;
108
109        if crc_byte != expected_crc_lsb {
110          return Err(Error::MemoryError("OneWire CRC validation failed".to_owned()));
111        }
112
113        let element_header = memory.read::<fn(usize, usize)>(8, 2, None).await?;
114        let version = element_header[0];
115        let element_length = element_header[1];
116
117        if version != 0 {
118          return Err(Error::MemoryError("Unsupported OneWire version".to_owned()));   
119        }
120
121        let elements = memory.read::<fn(usize, usize)>(10, element_length as usize, None).await?;
122        let elements_crc = memory.read::<fn(usize, usize)>(10 + element_length as usize, 1, None).await?[0];
123
124        let mut data = element_header;
125        data.extend_from_slice(&elements);
126
127        let calculated_crc = crc32fast::hash(&data);
128        let expected_crc_lsb = (calculated_crc & 0xFF) as u8;
129
130        if elements_crc != expected_crc_lsb {
131          return Err(Error::MemoryError("OneWire data CRC validation failed".to_owned()));
132        }
133
134        let elements_map = Self::parse_elements(&elements);
135
136        Ok(OwMemory {
137          memory,
138          used_pins,
139          vid,
140          pid,
141          elements: elements_map
142        })
143    }
144
145    pub(crate) async fn initialize(memory: MemoryBackend) -> Result<Self> {
146      Ok(OwMemory {
147        memory,
148        used_pins: 0,
149        vid: 0,
150        pid: 0,
151        elements: HashMap::new()
152      })
153    }
154
155    fn parse_elements(data: &[u8]) -> HashMap<String, String> {
156        let mut elements = HashMap::new();
157        let mut offset = 0;
158
159        while offset < data.len() {
160            if offset + 1 >= data.len() {
161                break;
162            }
163
164            let element_id = data[offset];
165            let element_length = data[offset + 1];
166            offset += 2;
167
168            if offset + element_length as usize > data.len() {
169                break;
170            }
171
172            let element_data = &data[offset..offset + element_length as usize];
173            offset += element_length as usize;
174
175            match element_id {
176                1 => { // boardName
177                    if let Ok(board_name) = String::from_utf8(element_data.to_vec()) {
178                        elements.insert("boardName".to_string(), board_name);
179                    }
180                },
181                2 => { // revision
182                    if let Ok(revision) = String::from_utf8(element_data.to_vec()) {
183                        elements.insert("revision".to_string(), revision);
184                    }
185                },
186                3 => { // customData
187                    let custom_data = hex::encode(element_data);
188                    elements.insert("customData".to_string(), custom_data);
189                },
190                _ => {
191                    // Unknown elements are ignored
192                }
193            }
194        }
195
196        elements
197    }
198
199}