airfrog_rpc/
io.rs

1//! Async I/O traits for accessing RAM, flash, files, etc.
2//!
3//! This module contains traits for reading/writing flash or RAM data on a target.
4//! They can be used remotely, accessing the target over SWD or other protocols,
5//! or can be used on the target itself (although they may be overkill in that
6//! application).
7//!
8//! # Possible implementations
9//!
10//! - For PC-based applications: Read/write in-memory buffers or memory-mapped
11//!   files, such as firmware images read from a file
12//! - For accessing embedded devices: Read/write from flash via SWD, JTAG, or
13//!   other debug interfaces
14//! - For implementing on embedded devices: Read directly from flash memory
15//!   (although this trait may be overkill)
16//!
17//! # Address Space
18//!
19//! The methods uses absolute addresses as they appear in the target's
20//! memory map. For STM32F4 devices, flash typically starts at `0x08000000` and
21//! RAM at `0x20000000`.
22//!
23//! The implementation is responsible for translating these addresses to
24//! whatever internal representation it uses (file offsets, SWD commands, etc.).
25
26// Copyright (C) 2025 Piers Finlayson <piers@piers.rocks>
27//
28// MIT License
29
30/// Reader trait.
31pub trait Reader {
32    /// The error type returned by read operations.
33    ///
34    /// This allows implementations to use their own error types
35    /// (e.g., `std::io::Error` for file I/O, custom errors for SWD).
36    type Error: core::fmt::Debug;
37
38    /// Read bytes from the firmware at the specified absolute address.
39    ///
40    /// # Arguments
41    ///
42    /// * `addr` - The absolute address to read from (e.g., `0x08000200`)
43    /// * `buf` - Buffer to fill with the read data
44    ///
45    /// # Errors
46    ///
47    /// Returns an error if:
48    /// - The address is out of bounds for the firmware
49    /// - The underlying read operation fails (I/O error, communication error, etc.)
50    /// - The requested read size would exceed firmware boundaries
51    ///
52    /// # Performance Notes
53    ///
54    /// Implementations should optimize for small reads (1-256 bytes) as the parser
55    /// typically reads headers and metadata in small chunks. For embedded implementations
56    /// reading via debug interfaces, consider implementing bulk reads and internal
57    /// buffering to reduce round-trip overhead.
58    fn read(
59        &mut self,
60        addr: u32,
61        buf: &mut [u8],
62    ) -> impl core::future::Future<Output = Result<(), Self::Error>> + Send;
63
64    /// Updates the reader's base address if it is later detected that it needs
65    /// to change.
66    fn update_base_address(&mut self, new_base: u32);
67}
68
69/// Writer trait.
70pub trait Writer {
71    /// The error type returned by write operations.
72    type Error: core::fmt::Debug;
73
74    /// Write bytes to the firmware at the specified absolute address.
75    ///
76    /// # Arguments
77    ///
78    /// * `addr` - The absolute address to write to (e.g., `0x20000200`)
79    /// * `data` - Data to write
80    ///
81    /// # Errors
82    ///
83    /// Returns an error if:
84    /// - The address is out of bounds for the target
85    /// - The underlying write operation fails (I/O error, communication error, etc.)
86    /// - The target memory is read-only or protected
87    fn write(
88        &mut self,
89        addr: u32,
90        data: &[u8],
91    ) -> impl core::future::Future<Output = Result<(), Self::Error>> + Send;
92
93    /// Updates the writer's base address if it is later detected that it needs
94    /// to change.
95    fn update_base_address(&mut self, new_base: u32);
96}