crazyflie_lib/subsystems/memory/
eeprom_config.rs1use crate::{subsystems::memory::{memory_types, MemoryBackend}, Error, Result};
2use std::{
3 convert::{TryFrom, TryInto},
4 fmt::{self, Display},
5};
6
7use memory_types::{FromMemoryBackend, MemoryType};
8
9#[derive(Debug)]
12pub struct EEPROMConfigMemory {
13 memory: MemoryBackend,
14 version: u8,
16 radio_channel: u8,
18 radio_speed: RadioSpeed,
20 pitch_trim: f32,
22 roll_trim: f32,
24 radio_address: [u8; 5],
26}
27
28
29#[derive(Debug, Clone)]
31pub enum RadioSpeed {
32 R250Kbps = 0,
34 R1Mbps = 1,
36 R2Mbps = 2,
38}
39
40impl TryFrom<u8> for RadioSpeed {
41 type Error = Error;
42
43 fn try_from(value: u8) -> Result<Self> {
44 match value {
45 0 => Ok(RadioSpeed::R250Kbps),
46 1 => Ok(RadioSpeed::R1Mbps),
47 2 => Ok(RadioSpeed::R2Mbps),
48 _ => Err(Error::MemoryError(format!("Invalid radio speed value: {}", value))),
49 }
50 }
51}
52
53impl Display for RadioSpeed {
54 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
55 match self {
56 RadioSpeed::R250Kbps => write!(f, "250 kbps"),
57 RadioSpeed::R1Mbps => write!(f, "1 Mbps"),
58 RadioSpeed::R2Mbps => write!(f, "2 Mbps"),
59 }
60 }
61}
62
63impl FromMemoryBackend for EEPROMConfigMemory {
64 async fn from_memory_backend(memory: MemoryBackend) -> Result<Self> {
65 if memory.memory_type == MemoryType::EEPROMConfig {
66 Ok(EEPROMConfigMemory::new(memory).await?)
67 } else {
68 Err(Error::MemoryError("Wrong type of memory!".to_owned()))
69 }
70 }
71
72 async fn initialize_memory_backend(memory: MemoryBackend) -> Result<Self> {
73 if memory.memory_type == MemoryType::EEPROMConfig {
74 Ok(EEPROMConfigMemory::initialize(memory).await?)
75 } else {
76 Err(Error::MemoryError("Wrong type of memory!".to_owned()))
77 }
78 }
79
80 fn close_memory(self) -> MemoryBackend {
81 self.memory
82 }
83}
84
85impl EEPROMConfigMemory {
86 pub(crate) async fn new(memory: MemoryBackend) -> Result<Self> {
87 let data = memory.read::<fn(usize, usize)>(0, 21, None).await?;
88 if data.len() >= 4 && &data[0..4] == b"0xBC" {
89 let version = data[4];
90 let radio_channel = data[5];
91 let radio_speed = RadioSpeed::try_from(data[6])?;
92 let pitch_trim = f32::from_le_bytes(data[7..11].try_into().unwrap());
93 let roll_trim = f32::from_le_bytes(data[11..15].try_into().unwrap());
94 let mut radio_address = [0; 5];
95 radio_address.copy_from_slice(&data[15..20]);
96
97 let calculated_checksum = data[..data.len()-1].iter().fold(0u8, |acc, &byte| acc.wrapping_add(byte));
98 let stored_checksum = data[data.len()-1];
99
100 if calculated_checksum != stored_checksum {
101 return Err(Error::MemoryError("Checksum mismatch in EEPROM config data".to_string()));
102 }
103
104 Ok(EEPROMConfigMemory {
105 memory,
106 version,
107 radio_channel,
108 radio_speed,
109 pitch_trim,
110 roll_trim,
111 radio_address,
112 })
113 } else {
114 Err(Error::MemoryError(
115 "Malformed EEPROM config data".to_string(),
116 ))
117 }
118 }
119
120 pub(crate) async fn initialize(memory: MemoryBackend) -> Result<Self> {
121 Ok(EEPROMConfigMemory {
122 memory,
123 version: 0,
124 radio_channel: 80,
125 radio_speed: RadioSpeed::R2Mbps,
126 pitch_trim: 0.0,
127 roll_trim: 0.0,
128 radio_address: [0xE7, 0xE7, 0xE7, 0xE7, 0xE7],
129 })
130 }
131
132 pub async fn commit(&self) -> Result<()> {
139 let mut data = Vec::new();
140 data.extend_from_slice(b"0xBC");
141 data.push(self.version);
142 data.push(self.radio_channel);
143 data.push(self.radio_speed.clone() as u8);
144 data.extend_from_slice(&self.pitch_trim.to_le_bytes());
145 data.extend_from_slice(&self.roll_trim.to_le_bytes());
146 data.extend_from_slice(&self.radio_address);
147
148 let checksum = data.iter().fold(0u8, |acc, &byte| acc.wrapping_add(byte));
149 data.push(checksum);
150
151 self.memory.write::<fn(usize, usize)>(0, &data, None).await
152 }
153
154
155 pub fn get_radio_channel(&self) -> u8 {
157 self.radio_channel
158 }
159
160 pub fn set_radio_channel(&mut self, channel: u8) -> Result<()> {
162 if channel > 125 {
163 return Err(Error::InvalidParameter("Radio channel must be between 0 and 125".into()));
164 }
165 self.radio_channel = channel;
166 Ok(())
167 }
168
169 pub fn get_radio_speed(&self) -> &RadioSpeed {
171 &self.radio_speed
172 }
173
174 pub fn set_radio_speed(&mut self, speed: RadioSpeed) {
176 self.radio_speed = speed;
177 }
178
179 pub fn get_pitch_trim(&self) -> f32 {
181 self.pitch_trim
182 }
183
184 pub fn set_pitch_trim(&mut self, trim: f32) {
186 self.pitch_trim = trim;
187 }
188
189 pub fn get_roll_trim(&self) -> f32 {
191 self.roll_trim
192 }
193
194 pub fn set_roll_trim(&mut self, trim: f32) {
196 self.roll_trim = trim;
197 }
198
199 pub fn get_radio_address(&self) -> &[u8; 5] {
201 &self.radio_address
202 }
203
204 pub fn set_radio_address(&mut self, address: [u8; 5]) {
206 self.radio_address = address;
207 }
208}