GCC Code Coverage Report


Directory: lib/fprime-samd/fprime-samd/Drv/I2cDriver/
File: I2cDriverHardwareStub.cpp
Date: 2026-09-26 00:05:14
Exec Total Coverage
Lines: 75 75 100.0%
Functions: 16 16 100.0%
Branches: 6 9 66.7%

Line Branch Exec Source
1 // ======================================================================
2 // \title I2cDriverHardwareStub.cpp
3 // \author tumbar
4 // \brief Stub hardware implementation for the I2C peripheral (Linux/test builds)
5 //
6 // This file is compiled for Linux/test builds to enable unit testing.
7 // For SAMD21 target builds, I2cDriverHardware.cpp is used instead.
8 //
9 // The stub records the arguments of each hardware call and exposes injectable
10 // interrupt/bus status so unit tests can drive the component's state machine,
11 // ISR error dispatch and telemetry mapping without any real MCU.
12 // ======================================================================
13
14 #include "fprime-samd/Drv/I2cDriver/I2cDriverHardware.hpp"
15
16 namespace Samd21 {
17 namespace I2cHardware {
18
19 static StubState s_state = {};
20
21 175 StubState& getStubState() {
22 175 return s_state;
23 }
24
25 39 void resetStubState() {
26 // Assign a fresh value-initialized instance rather than memset: several
27 // members (e.g. SercomKind) are autocoded classes with vtables that
28 // memset would corrupt.
29
3/5
✓ Branch 2 taken 39 times.
✓ Branch 5 taken 39 times.
✓ Branch 9 taken 39 times.
✗ Branch 14 not taken.
✗ Branch 15 not taken.
39 s_state = StubState{};
30 39 }
31
32 14 void fireIsr() {
33
1/2
✓ Branch 0 taken 14 times.
✗ Branch 1 not taken.
14 if (s_state.isr_callback != nullptr) {
34
2/2
✓ Branch 2 taken 14 times.
✓ Branch 5 taken 14 times.
14 s_state.isr_callback(s_state.isr_data, s_state.isr_sercom);
35 }
36 14 }
37
38 39 void I2cHal::registerIsr(SercomKind sercom,
39 void (*callback)(Fw::PassiveComponentBase*, SercomKind),
40 Fw::PassiveComponentBase* data) {
41 39 s_state.isr_callback = callback;
42 39 s_state.isr_data = data;
43 39 s_state.isr_sercom = sercom;
44 39 }
45
46 39 void I2cHal::configure(SercomKind sercom,
47 I2cDriver::SclLowTimeout scl_low_timeout,
48 I2cDriver::InactiveTimeout inactive_timeout,
49 I2cDriver::ClockStretchMode clock_stretch_mode,
50 I2cDriver::Frequency frequency,
51 I2cDriver::ClientSclLowTimeout client_scl_low_timeout,
52 I2cDriver::HostSclLowTimeout host_scl_low_timeout,
53 I2cDriver::SdaHold sda_hold,
54 I2cDriver::PinUsage pin_usage,
55 I2cDriver::RunInStandby run_in_standby) {
56 39 s_state.configured = true;
57 39 s_state.configure_count++;
58 39 s_state.sercom = sercom;
59 39 s_state.scl_low_timeout = scl_low_timeout;
60 39 s_state.inactive_timeout = inactive_timeout;
61 39 s_state.clock_stretch_mode = clock_stretch_mode;
62 39 s_state.frequency = frequency;
63 39 s_state.client_scl_low_timeout = client_scl_low_timeout;
64 39 s_state.host_scl_low_timeout = host_scl_low_timeout;
65 39 s_state.sda_hold = sda_hold;
66 39 s_state.pin_usage = pin_usage;
67 39 s_state.run_in_standby = run_in_standby;
68 39 }
69
70 49 U32 I2cHal::getDataRegisterAddress(SercomKind sercom) {
71 49 return s_state.data_register_address;
72 }
73
74 28 I2cInterruptStatus I2cHal::readInterruptStatus(SercomKind sercom) {
75 28 return s_state.interrupt_status;
76 }
77
78 35 I2cBusStatus I2cHal::readBusStatus(SercomKind sercom) {
79 35 return s_state.bus_status;
80 }
81
82 4 I2cRawRegisters I2cHal::readRawRegisters(SercomKind sercom) {
83 4 return s_state.raw_registers;
84 }
85
86 4 void I2cHal::recoverBusToIdle(SercomKind sercom) {
87 4 s_state.recover_bus_count++;
88
89 // Model the write-1-clear recovery: after recovery no interrupt/error flags
90 // remain pending and the bus is IDLE, so the driver can start fresh.
91 4 s_state.interrupt_status = I2cInterruptStatus{};
92 4 s_state.bus_status.busState = 0x1; // IDLE
93 4 s_state.bus_status.clockHold = false;
94 4 s_state.bus_status.masterOnBus = false;
95 4 s_state.bus_status.slaveOnBus = false;
96 4 }
97
98 8 void I2cHal::acknowledgeErrors(SercomKind sercom) {
99 8 s_state.acknowledge_errors_count++;
100 // Model the write-1-clear: once acked, the pending error/flags go away so a
101 // subsequent readInterruptStatus() does not re-report the same error.
102 8 s_state.interrupt_status.error = false;
103 8 s_state.interrupt_status.busError = false;
104 8 s_state.interrupt_status.arbLost = false;
105 8 s_state.interrupt_status.lowTimeout = false;
106 8 s_state.interrupt_status.masterExtTimeout = false;
107 8 s_state.interrupt_status.slaveExtTimeout = false;
108 8 s_state.interrupt_status.lengthError = false;
109 8 }
110
111 7 void I2cHal::acknowledgeMasterOnBus(SercomKind sercom) {
112 7 s_state.acknowledge_mb_count++;
113 7 s_state.interrupt_status.masterOnBus = false;
114 7 }
115
116 8 void I2cHal::enableMasterOnBusInterrupt(SercomKind sercom) {
117 8 s_state.enable_mb_count++;
118 8 }
119
120 8 void I2cHal::disableMasterOnBusInterrupt(SercomKind sercom) {
121 8 s_state.disable_mb_count++;
122 8 }
123
124 18 void I2cHal::beginRead(SercomKind sercom, U32 addr, U8 byteCount) {
125 18 s_state.begin_read_count++;
126 18 s_state.begin_read_addr = addr;
127 18 s_state.begin_read_len = byteCount;
128 18 }
129
130 22 void I2cHal::beginWrite(SercomKind sercom, U32 addr, U8 byteCount, bool generateStopCondition) {
131 22 s_state.begin_write_count++;
132 22 s_state.begin_write_addr = addr;
133 22 s_state.begin_write_len = byteCount;
134 22 s_state.begin_write_stop = generateStopCondition;
135 22 }
136
137 } // namespace I2cHardware
138 } // namespace Samd21
139