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}