amebazii/types/sysctrl.rs
1use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt};
2use serde::{Deserialize, Serialize};
3use std::io;
4
5use crate::{
6 error::Error, is_valid_data, read_padding, read_valid_data, util::write_fill, write_data,
7 write_padding,
8};
9
10use super::{
11 enums::{FlashSize, SpiIOMode, SpiSpeed},
12 DataRefType, DataType, FromStream, ToStream,
13};
14
15/// Represents the configuration for forcing the use of an old image.
16///
17/// This struct is used to store and manipulate the settings for whether an old image
18/// (e.g., firmware or partition) should be used, and how it should be configured.
19/// The configuration consists of three components:
20/// - `pin`: A pin number (0-31) used in the configuration.
21/// - `port`: A port number (0 or 1), which determines whether the configuration uses a specific port.
22/// - `active`: A boolean flag indicating whether the old image configuration is active or not.
23///
24#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
25pub struct ForceOldImage {
26 /// The pin number (0-31) used in the configuration.
27 pin: u8,
28
29 /// The port number (0 or 1), which determines the port configuration.
30 port: u8,
31
32 /// A flag that determines if the old image configuration is active.
33 active: bool,
34}
35
36impl ForceOldImage {
37 /// Creates a new instance of `ForceOldImage` with the specified pin, port, and active status.
38 ///
39 /// # Returns:
40 /// - A new `ForceOldImage` struct.
41 pub fn new(pin: u8, port: u8, active: bool) -> Self {
42 Self { pin, port, active }
43 }
44
45 /// Retrieves the pin number of the configuration.
46 ///
47 /// # Returns:
48 /// - The pin number (0-31) used in the configuration.
49 pub fn pin(&self) -> u8 {
50 self.pin
51 }
52
53 /// Retrieves the port number of the configuration.
54 ///
55 /// # Returns:
56 /// - The port number (0 or 1) used in the configuration.
57 pub fn port(&self) -> u8 {
58 self.port
59 }
60
61 /// Checks whether the old image configuration is active.
62 ///
63 /// # Returns:
64 /// - `true` if the configuration is active, `false` otherwise.
65 pub fn is_active(&self) -> bool {
66 self.active
67 }
68}
69
70impl From<u32> for ForceOldImage {
71 /// Converts a 32-bit unsigned integer into a `ForceOldImage` instance.
72 ///
73 /// # Parameters:
74 /// - `value`: A `u32` integer representing the configuration.
75 ///
76 /// # Returns:
77 /// - A `ForceOldImage` struct with the appropriate values extracted from the `u32`.
78 fn from(value: u32) -> Self {
79 Self {
80 pin: (value & 0b11111) as u8,
81 port: ((value >> 5) & 0b1) as u8,
82 active: ((value >> 7) & 0b1) == 1,
83 }
84 }
85}
86
87impl Default for ForceOldImage {
88 /// Returns a default `ForceOldImage` configuration with all fields set to their default values.
89 ///
90 /// The default values are:
91 /// - `pin`: 0
92 /// - `port`: 0
93 /// - `active`: false
94 ///
95 /// # Returns:
96 /// - A `ForceOldImage` instance with default values.
97 fn default() -> Self {
98 Self {
99 pin: 0,
100 port: 0,
101 active: false,
102 }
103 }
104}
105
106impl Into<u32> for ForceOldImage {
107 /// Converts a `ForceOldImage` instance into a 32-bit unsigned integer.
108 ///
109 /// # Returns:b
110 /// - A `u32` integer representing the `ForceOldImage` configuration.
111 fn into(self) -> u32 {
112 (self.pin as u32) | ((self.port as u32) << 5) | ((self.active as u32) << 7)
113 }
114}
115
116/// Represents the SPI (Serial Peripheral Interface) configuration.
117///
118/// Example:
119/// ```rust
120/// // Create a new SPI configuration instance.
121/// let spi_config = SpiConfig {
122/// io_mode: SpiIOMode::Quad_IO,
123/// io_speed: SpiSpeed::_50MHz,
124/// };
125///
126/// // Convert the SPI config into a 32-bit integer.
127/// let packed_value: u32 = spi_config.into();
128///
129/// // Convert the 32-bit integer back into an SPI config.
130/// let unpacked_value = SpiConfig::from(packed_value);
131///
132/// // Print the values from the unpacked config.
133/// println!("SPI IO Mode: {:?}", unpacked_value.io_mode);
134/// println!("SPI IO Speed: {:?}", unpacked_value.io_speed);
135/// ```
136#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
137pub struct SpiConfig {
138 /// The SPI I/O mode (defines the number of I/O lines and mode of operation).
139 io_mode: SpiIOMode,
140
141 /// The SPI communication speed (defines the frequency at which data is transferred).
142 io_speed: SpiSpeed,
143}
144
145impl Default for SpiConfig {
146 /// Returns the default `SpiConfig` with default I/O mode and I/O speed.
147 ///
148 /// # Returns:
149 /// - A `SpiConfig` instance with default values for `io_mode` and `io_speed`.
150 fn default() -> Self {
151 Self {
152 io_mode: SpiIOMode::default(),
153 io_speed: SpiSpeed::default(),
154 }
155 }
156}
157
158impl Into<u32> for SpiConfig {
159 /// Converts a `SpiConfig` instance into a 32-bit unsigned integer.
160 ///
161 /// # Parameters:
162 /// - `self`: The `SpiConfig` instance to convert.
163 ///
164 /// # Returns:
165 /// - A `u32` integer that represents the `SpiConfig` instance in a packed format.
166 fn into(self) -> u32 {
167 (self.io_mode as u32) | ((self.io_speed as u32) << 16)
168 }
169}
170
171impl From<u32> for SpiConfig {
172 /// Converts a 32-bit unsigned integer into a `SpiConfig` instance.
173 ///
174 /// # Parameters:
175 /// - `value`: The `u32` integer to convert.
176 ///
177 /// # Returns:
178 /// - A `SpiConfig` instance with the `io_mode` and `io_speed` fields populated.
179 fn from(value: u32) -> Self {
180 Self {
181 io_mode: ((value & 0xFFFF) as u16).into(),
182 io_speed: (((value >> 16) & 0xFFFF) as u16).into(),
183 }
184 }
185}
186
187/// Represents information about the flash memory configuration.
188#[derive(Debug, Clone, Copy, Serialize, Deserialize)]
189pub struct FlashInfo {
190 /// The flash memory's unique identifier (e.g., a manufacturer ID or model number).
191 flash_id: u16,
192
193 /// The size of the flash memory, represented by the `FlashSize` enum.
194 flash_size: FlashSize,
195}
196
197impl Default for FlashInfo {
198 /// Returns the default `FlashInfo` instance.
199 ///
200 /// # Returns:
201 /// - A `FlashInfo` instance with a `flash_id` of 0 and the default `flash_size`.
202 fn default() -> Self {
203 Self {
204 flash_id: 0,
205 flash_size: FlashSize::default(),
206 }
207 }
208}
209
210impl Into<u32> for FlashInfo {
211 /// Converts a `FlashInfo` instance into a 32-bit unsigned integer.
212 ///
213 /// # Parameters:
214 /// - `self`: The `FlashInfo` instance to convert.
215 ///
216 /// # Returns:
217 /// - A `u32` integer that represents the `FlashInfo` instance in a packed format.
218 fn into(self) -> u32 {
219 (self.flash_id as u32) | ((self.flash_size as u32) << 16)
220 }
221}
222
223impl From<u32> for FlashInfo {
224 /// Converts a 32-bit unsigned integer into a `FlashInfo` instance.
225 ///
226 /// # Parameters:
227 /// - `value`: The `u32` integer to convert.
228 ///
229 /// # Returns:
230 /// - A `FlashInfo` instance with the `flash_id` and `flash_size` fields populated.
231 fn from(value: u32) -> Self {
232 Self {
233 flash_id: (value & 0xFFFF) as u16, // Extract the first 16 bits for flash_id
234 flash_size: (((value >> 16) & 0xFFFF) as u16).into(), // Extract the next 16 bits for flash_size
235 }
236 }
237}
238
239
240// Although hal_sys_ctrl.h only defines the first two fields as reserved, there are actually more:
241//
242// 1. OTA_Change(int current) in ota_8710c_ram_lib_soc.o implements the behaviour by
243// changing the current OTA address
244//
245// Layout:
246// +-------+------+-------+-------+--------+------+----------+---------+------+------+-------+------+----+----+----+----+
247// | 0 | 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 |
248// +========+=======+======+=======+=======+========+======+==========+=========+======+======+=======+======+====+====+====+====+
249// | 0x00 | ota2_address: u32 | ota2_size: u32 | force_old_ota: ForceOldOTA | |
250// +--------+------------------------------+------------------------------------+----------------------------+-------------------+
251// | 0x10 | |
252// +--------+--------------+---------------+---------------+--------------------+------------------------------------------------+
253// | 0x20 | io_mode: u16 | io_speed: u16 | flash_id: u16 | flash_size_mb: u16 | |
254// +--------+--------------+---------------+---------------+--------------------+------------------------------------------------+
255// | 0x30 | ulog_baud: u32 | |
256// +--------+------------------------------+-------------------------------------------------------------------------------------+
257// | 0x40 | spic_calibration_setting: bytes[0x30] |
258// +--------+--------------------------------------------------------------------------------------------------------------------+
259// | 0x70 | |
260// +--------+--------------------------------------------------------------------------------------------------------------------+
261// | 0xFE0 | bt_parameter_data: bytes[0x20] |
262// +--------+--------------------------------------------------------------------------------------------------------------------+
263
264/// Represents system data related to the device, including configuration for OTA, SPI, and other hardware settings.
265///
266/// The `SystemData` struct holds various fields representing the system's configuration and settings:
267/// - **OTA**: Configurations for over-the-air (OTA) updates, including address and size of OTA2.
268/// - **Force Old Image**: Settings related to forcing the usage of an older firmware image.
269/// - **SPI Configuration**: Configuration for the Serial Peripheral Interface (SPI) bus.
270/// - **Flash Information**: Information about the flash memory, including ID and size.
271/// - **Logging Baud Rate**: Baud rate for UART logging.
272/// - **Calibration Data**: SPI calibration data and Bluetooth parameters.
273///
274/// This struct is designed to be serialized and deserialized from a stream, allowing for easy reading and writing
275/// of system settings, especially in embedded systems or firmware configuration.
276#[derive(Debug)]
277pub struct SystemData {
278 /// Address of the OTA2 image, or `None` if OTA1 is active.
279 pub ota2_addr: Option<u32>,
280
281 /// Size of the OTA2 image, or `None` if OTA1 is active.
282 pub ota2_size: Option<u32>,
283
284 /// Configuration for forcing the usage of an older image, including the pin, port, and active status.
285 pub old_img_trap: ForceOldImage,
286
287 /// Configuration for the SPI bus, including IO mode and speed.
288 pub spi_cfg: SpiConfig,
289
290 /// Information about the flash memory, including ID and size.
291 pub flash_info: FlashInfo,
292
293 /// Baud rate for the UART logging interface.
294 pub ulog_baud: u32,
295
296 /// SPI calibration configuration, stored as raw data.
297 spic_calibcfg: DataType<0x30>,
298
299 /// Bluetooth parameter data, stored as raw data.
300 bt_parameter_data: DataType<0x20>,
301}
302
303impl Default for SystemData {
304 /// Returns the default `SystemData` instance with preset values.
305 ///
306 /// Default values:
307 /// - `ota2_addr`: `None` (indicating OTA1 is active).
308 /// - `ota2_size`: `None`.
309 /// - `old_img_trap`: Default `ForceOldImage` values.
310 /// - `spi_cfg`: Default `SpiConfig` values.
311 /// - `flash_info`: Default `FlashInfo` values.
312 /// - `ulog_baud`: `0xFFFF_FFFF`.
313 /// - `spic_calibcfg`: `None`.
314 /// - `bt_parameter_data`: `None`.
315 fn default() -> Self {
316 Self {
317 ota2_addr: None,
318 ota2_size: None,
319 old_img_trap: ForceOldImage::default(),
320 spi_cfg: SpiConfig::default(),
321 flash_info: FlashInfo::default(),
322 ulog_baud: 0xFFFF_FFFF,
323 spic_calibcfg: None,
324 bt_parameter_data: None,
325 }
326 }
327}
328
329impl FromStream for SystemData {
330 /// Reads `SystemData` from a stream (e.g., file, memory, or network).
331 ///
332 /// # Parameters:
333 /// - `_reader`: The reader from which data will be read (must implement `Read` and `Seek`).
334 ///
335 /// # Returns:
336 /// - A result indicating success or failure of the reading operation.
337 fn read_from<R>(&mut self, _reader: &mut R) -> Result<(), Error>
338 where
339 R: io::Read + io::Seek,
340 {
341 self.ota2_size = match _reader.read_u32::<LittleEndian>()? {
342 0xFFFF_FFFF => None,
343 value => Some(value),
344 };
345 self.ota2_addr = match _reader.read_u32::<LittleEndian>()? {
346 0xFFFF_FFFF => None,
347 value => Some(value),
348 };
349 self.old_img_trap = _reader.read_u32::<LittleEndian>()?.into();
350 read_padding!(_reader, 20);
351
352 self.spi_cfg = _reader.read_u32::<LittleEndian>()?.into();
353 self.flash_info = _reader.read_u32::<LittleEndian>()?.into();
354 read_padding!(_reader, 8);
355
356 self.ulog_baud = _reader.read_u32::<LittleEndian>()?;
357 read_padding!(_reader, 12);
358
359 read_valid_data!(self.spic_calibcfg, 0x30, _reader);
360 read_padding!(_reader, 0xf70);
361 read_valid_data!(self.bt_parameter_data, 0x20, _reader);
362 Ok(())
363 }
364}
365
366impl ToStream for SystemData {
367 /// Writes `SystemData` to a stream (e.g., file, memory, or network).
368 ///
369 /// # Parameters:
370 /// - `_writer`: The writer to which data will be written (must implement `Write` and `Seek`).
371 ///
372 /// # Returns:
373 /// - A result indicating success or failure of the writing operation.
374 fn write_to<W>(&self, _writer: &mut W) -> Result<(), Error>
375 where
376 W: io::Write + io::Seek,
377 {
378 _writer.write_u32::<LittleEndian>(self.ota2_size.unwrap_or(0xFFFF_FFFF))?;
379 _writer.write_u32::<LittleEndian>(self.ota2_addr.unwrap_or(0xFFFF_FFFF))?;
380 _writer.write_u32::<LittleEndian>(self.old_img_trap.into())?;
381 write_padding!(_writer, 20);
382
383 _writer.write_u32::<LittleEndian>(self.spi_cfg.into())?;
384 _writer.write_u32::<LittleEndian>(self.flash_info.into())?;
385 write_padding!(_writer, 8);
386
387 _writer.write_u32::<LittleEndian>(self.ulog_baud)?;
388 write_padding!(_writer, 12);
389
390 write_data!(_writer, self.spic_calibcfg, 0x30);
391 write_padding!(_writer, 0xf70);
392 write_data!(_writer, self.bt_parameter_data, 0x20);
393 Ok(())
394 }
395}
396
397impl SystemData {
398 /// Retrieves the Bluetooth parameter data as a reference.
399 ///
400 /// # Returns:
401 /// - A reference to the Bluetooth parameter data (if available).
402 pub fn get_bt_paramdata(&self) -> DataRefType<'_, 32> {
403 self.bt_parameter_data.as_ref()
404 }
405
406 /// Retrieves the SPI calibration configuration as a reference.
407 ///
408 /// # Returns:
409 /// - A reference to the SPI calibration data (if available).
410 pub fn get_spic_calibcfg(&self) -> DataRefType<'_, 48> {
411 self.spic_calibcfg.as_ref()
412 }
413
414 /// Sets the Bluetooth parameter data.
415 ///
416 /// # Parameters:
417 /// - `data`: The new Bluetooth parameter data to set.
418 pub fn set_pt_paramdata(&mut self, data: DataType<32>) {
419 self.bt_parameter_data = data;
420 }
421
422 /// Sets the SPI calibration configuration.
423 ///
424 /// # Parameters:
425 /// - `data`: The new SPI calibration data to set.
426 pub fn set_spic_calibcfg(&mut self, data: DataType<48>) {
427 self.spic_calibcfg = data;
428 }
429}