Skip to content

Commit 814fa5f

Browse files
committed
[test] Introduce a Mock implementation of the lower level I2C Hardware traits.
- Configurable success/failure behavior for testing error paths - Event injection system for simulating slave events - Data injection for testing slave receive scenarios - Buffer management with realistic size constraints - State tracking for all operations
1 parent cf83d42 commit 814fa5f

File tree

6 files changed

+1276
-22
lines changed

6 files changed

+1276
-22
lines changed

.github/workflows/ci.yml

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -125,7 +125,24 @@ jobs:
125125
-W clippy::panic \
126126
-W clippy::mem_forget \
127127
-W clippy::multiple_unsafe_ops_per_block \
128-
-W clippy::undocumented_unsafe_blocks
128+
-W clippy::undocumented_unsafe_blocks \
129+
-A clippy::assertions_on_constants \
130+
-A clippy::needless_return
131+
132+
- name: Run strict security lints on non-test code
133+
run: |
134+
cargo clippy --lib --bins -- \
135+
-D warnings \
136+
-D clippy::arithmetic_side_effects \
137+
-D clippy::float_arithmetic \
138+
-D clippy::indexing_slicing \
139+
-D clippy::unwrap_used \
140+
-D clippy::expect_used \
141+
-D clippy::panic \
142+
-D clippy::mem_forget \
143+
-D clippy::multiple_unsafe_ops_per_block \
144+
-D clippy::undocumented_unsafe_blocks \
145+
-D clippy::assertions_on_constants
129146
130147
- name: Run semgrep security scan
131148
uses: returntocorp/semgrep-action@v1

Cargo.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,6 @@ repository = "https://github.com/rusty1968/openprot"
2323
edition = "2021"
2424

2525
[workspace.dependencies]
26-
zerocopy = { version = "0.8.27", features = ["derive"] }
26+
zerocopy = { version = "0.8", features = ["derive"] }
2727
zeroize = { version = "1.7", default-features = false, features = ["derive"] }
28-
subtle = { version = "2.5", default-features = false }
28+
subtle = { version = "2", default-features = false }

hal/blocking/src/i2c_hardware.rs

Lines changed: 51 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@
3232
//!
3333
//! For non-blocking slave operations, see `openprot-hal-nb::i2c_hardware`.
3434
35-
use embedded_hal::i2c::{Operation, SevenBitAddress};
35+
use embedded_hal::i2c::{AddressMode, Operation, SevenBitAddress};
3636

3737
/// Core I2C hardware interface providing basic operations
3838
///
@@ -45,11 +45,38 @@ pub trait I2cHardwareCore {
4545
/// Hardware-specific configuration type for I2C initialization and setup
4646
type Config;
4747

48+
/// I2C speed configuration type
49+
type I2cSpeed;
50+
51+
/// Timing configuration type
52+
type TimingConfig;
53+
4854
/// Initialize the I2C hardware with the given configuration
4955
fn init(&mut self, config: &mut Self::Config);
5056

5157
/// Configure timing parameters (clock speed, setup/hold times)
52-
fn configure_timing(&mut self, config: &mut Self::Config);
58+
///
59+
/// Takes timing parameters as input and returns the calculated clock source frequency.
60+
/// This provides type safety by making clear what is read vs. what is computed/returned.
61+
///
62+
/// # Arguments
63+
///
64+
/// * `speed` - Target I2C bus speed (Standard, Fast, FastPlus, etc.)
65+
/// * `timing` - Timing configuration parameters for setup/hold times
66+
///
67+
/// # Returns
68+
///
69+
/// Returns the actual calculated clock source frequency in Hz.
70+
///
71+
/// # Errors
72+
///
73+
/// Returns an error if the requested timing cannot be achieved with the
74+
/// available hardware clock sources or if parameters are invalid.
75+
fn configure_timing(
76+
&mut self,
77+
speed: Self::I2cSpeed,
78+
timing: &Self::TimingConfig,
79+
) -> Result<u32, Self::Error>;
5380

5481
/// Enable hardware interrupts with the specified mask
5582
fn enable_interrupts(&mut self, mask: u32);
@@ -137,9 +164,9 @@ pub mod slave {
137164
/// This trait provides the fundamental slave operations that all slave
138165
/// implementations need: setting slave address and enabling/disabling slave mode.
139166
/// This is the minimal trait for any I2C slave implementation.
140-
pub trait I2cSlaveCore: super::I2cHardwareCore {
167+
pub trait I2cSlaveCore<A: AddressMode = SevenBitAddress>: super::I2cHardwareCore {
141168
/// Configure the slave address for this I2C controller
142-
fn configure_slave_address(&mut self, addr: SevenBitAddress) -> Result<(), Self::Error>;
169+
fn configure_slave_address(&mut self, addr: A) -> Result<(), Self::Error>;
143170

144171
/// Enable slave mode operation
145172
fn enable_slave_mode(&mut self) -> Result<(), Self::Error>;
@@ -160,7 +187,7 @@ pub mod slave {
160187
/// Separate from core to allow different buffer management strategies.
161188
/// Implementations can choose different buffering approaches (ring buffer,
162189
/// simple array, DMA, etc.) while maintaining the same interface.
163-
pub trait I2cSlaveBuffer: I2cSlaveCore {
190+
pub trait I2cSlaveBuffer<A: AddressMode = SevenBitAddress>: I2cSlaveCore<A> {
164191
/// Read received data from the slave buffer
165192
///
166193
/// Returns the number of bytes actually read. The buffer is filled
@@ -204,7 +231,7 @@ pub mod slave {
204231
///
205232
/// Common interrupt and status operations shared by both async and sync event patterns.
206233
/// This provides the foundation for event-driven slave operations.
207-
pub trait I2cSlaveInterrupts: I2cSlaveCore {
234+
pub trait I2cSlaveInterrupts<A: AddressMode = SevenBitAddress>: I2cSlaveCore<A> {
208235
/// Enable slave-specific hardware interrupts
209236
///
210237
/// Configures the hardware to generate interrupts for slave events.
@@ -219,26 +246,26 @@ pub mod slave {
219246
/// that the interrupt has been handled.
220247
fn clear_slave_interrupts(&mut self, mask: u32);
221248

222-
/// Get current slave hardware status
249+
/// Current slave hardware status
223250
///
224251
/// Returns comprehensive status information about the slave controller
225252
/// including enabled state, address, buffer counts, and error conditions.
226-
fn get_slave_status(&self) -> Result<SlaveStatus, Self::Error>;
253+
fn slave_status(&self) -> Result<SlaveStatus, Self::Error>;
227254

228-
/// Get the last slave event that occurred
255+
/// Last slave event that occurred
229256
///
230257
/// Returns the most recent slave event, useful for debugging
231258
/// and state tracking. May return None if no events have occurred
232259
/// since reset or if the hardware doesn't track this information.
233-
fn get_last_slave_event(&self) -> Option<I2cSEvent>;
260+
fn last_slave_event(&self) -> Option<I2cSEvent>;
234261
}
235262

236263
/// Blocking slave event handling (sync pattern)
237264
///
238265
/// This trait provides blocking operations suitable for synchronous code
239266
/// that can afford to wait for events. Operations may block the calling
240267
/// thread until the requested condition is met or timeout occurs.
241-
pub trait I2cSlaveEventSync: I2cSlaveInterrupts {
268+
pub trait I2cSlaveEventSync<A: AddressMode = SevenBitAddress>: I2cSlaveInterrupts<A> {
242269
/// Wait for a specific slave event with timeout
243270
///
244271
/// Blocks until the specified event occurs or the timeout expires.
@@ -272,20 +299,29 @@ pub mod slave {
272299
/// This trait represents a basic slave implementation that combines
273300
/// core setup and buffer operations. It's suitable for most simple
274301
/// slave use cases without requiring event handling.
275-
pub trait I2cSlaveBasic: I2cSlaveCore + I2cSlaveBuffer {}
302+
pub trait I2cSlaveBasic<A: AddressMode = SevenBitAddress>:
303+
I2cSlaveCore<A> + I2cSlaveBuffer<A>
304+
{
305+
}
276306

277307
/// Blanket implementation: any type implementing core + buffer gets basic slave
278-
impl<T> I2cSlaveBasic for T where T: I2cSlaveCore + I2cSlaveBuffer {}
308+
impl<T, A: AddressMode> I2cSlaveBasic<A> for T where T: I2cSlaveCore<A> + I2cSlaveBuffer<A> {}
279309

280310
/// Complete sync slave implementation
281311
///
282312
/// This trait represents a full sync slave implementation that supports
283313
/// all blocking slave operations. Perfect for traditional blocking
284314
/// implementations that can afford to wait.
285-
pub trait I2cSlaveSync: I2cSlaveCore + I2cSlaveBuffer + I2cSlaveEventSync {}
315+
pub trait I2cSlaveSync<A: AddressMode = SevenBitAddress>:
316+
I2cSlaveCore<A> + I2cSlaveBuffer<A> + I2cSlaveEventSync<A>
317+
{
318+
}
286319

287320
/// Blanket implementation: any type implementing core + buffer + sync events gets sync slave
288-
impl<T> I2cSlaveSync for T where T: I2cSlaveCore + I2cSlaveBuffer + I2cSlaveEventSync {}
321+
impl<T, A: AddressMode> I2cSlaveSync<A> for T where
322+
T: I2cSlaveCore<A> + I2cSlaveBuffer<A> + I2cSlaveEventSync<A>
323+
{
324+
}
289325

290326
/// Combined trait for controllers supporting both master and slave modes
291327
///

hal/nb/src/i2c_hardware.rs

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,16 +8,17 @@
88
//! These traits complement the blocking traits in `openprot-hal-blocking` by providing
99
//! non-blocking alternatives suitable for async code, main loops, and interrupt handlers.
1010
11+
use embedded_hal::i2c::{AddressMode, SevenBitAddress};
1112
use openprot_hal_blocking::i2c_hardware::slave::{
1213
I2cSEvent, I2cSlaveBuffer, I2cSlaveCore, I2cSlaveInterrupts,
1314
};
1415

15-
/// Non-blocking slave event handling (polling pattern)
16+
/// Non-blocking slave event handling (async/polling pattern)
1617
///
1718
/// This trait provides non-blocking event operations suitable for async code,
1819
/// main loops, or interrupt-driven architectures. All operations return
1920
/// immediately without blocking the caller.
20-
pub trait I2cSlaveEventPolling: I2cSlaveInterrupts {
21+
pub trait I2cSlaveEventPolling<A: AddressMode = SevenBitAddress>: I2cSlaveInterrupts<A> {
2122
/// Check for pending slave events without blocking
2223
///
2324
/// Returns the next available slave event if one is pending, or None
@@ -44,7 +45,13 @@ pub trait I2cSlaveEventPolling: I2cSlaveInterrupts {
4445
/// This trait represents a full non-blocking slave implementation that supports
4546
/// all non-blocking slave operations. Perfect for interrupt-driven or
4647
/// polling-based implementations that cannot afford to block.
47-
pub trait I2cSlaveNonBlocking: I2cSlaveCore + I2cSlaveBuffer + I2cSlaveEventPolling {}
48+
pub trait I2cSlaveNonBlocking<A: AddressMode = SevenBitAddress>:
49+
I2cSlaveCore<A> + I2cSlaveBuffer<A> + I2cSlaveEventPolling<A>
50+
{
51+
}
4852

4953
/// Blanket implementation: any type implementing core + buffer + polling events gets non-blocking slave
50-
impl<T> I2cSlaveNonBlocking for T where T: I2cSlaveCore + I2cSlaveBuffer + I2cSlaveEventPolling {}
54+
impl<T, A: AddressMode> I2cSlaveNonBlocking<A> for T where
55+
T: I2cSlaveCore<A> + I2cSlaveBuffer<A> + I2cSlaveEventPolling<A>
56+
{
57+
}

0 commit comments

Comments
 (0)