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}