GCC Code Coverage Report


Directory: lib/fprime-samd/fprime-samd/Drv/GpioDriver/
File: GpioDriverHardwareStub.cpp
Date: 2026-09-26 00:05:13
Exec Total Coverage
Lines: 61 67 91.0%
Functions: 10 13 76.9%
Branches: 4 4 100.0%

Line Branch Exec Source
1 // ======================================================================
2 // \title GpioDriverHardwareStub.cpp
3 // \author tumbar
4 // \brief Stub hardware implementation for GPIO peripheral (Linux/test builds)
5 //
6 // This file is compiled for Linux/test builds to enable unit testing.
7 // For SAMD21 target builds, GpioDriverHardware.cpp is used instead.
8 //
9 // The stub records every HAL interaction in an observable GpioState so that
10 // unit tests can verify the driver drives the HAL correctly, and lets tests
11 // inject the value returned by read().
12 // ======================================================================
13
14 #include "Fw/Types/LogicEnumAc.hpp"
15 #include "fprime-samd/Drv/GpioDriver/GpioDriverHardware.hpp"
16
17 namespace Samd21 {
18 namespace GpioHardware {
19
20 //! Number of EIC external interrupt lines (EXTINT[0..15]); a pin maps to line pinIdx % this.
21 static constexpr U8 EXTINT_LINE_COUNT = 16;
22
23 //! Global GPIO state instance for stub
24 static GpioState g_gpio_state = {
25 .configure_input_count = 0,
26 .configure_external_interrupt_count = 0,
27 .configure_output_count = 0,
28 .write_count = 0,
29 .read_count = 0,
30 .last_group = 0,
31 .last_pin = 0,
32 .last_input_pull_mode = GpioDriver::InputPullMode::NO_PULL,
33 .last_input_interrupt_mode = GpioDriver::ExternalInterruptMode::NONE,
34 .last_write_group = 0,
35 .last_write_pin = 0,
36 .last_write_state = Fw::Logic::LOW,
37 .last_read_group = 0,
38 .last_read_pin = 0,
39 .read_value = Fw::Logic::HIGH,
40 };
41
42 //! Components registered for ISR dispatch, indexed by EXTINT line.
43 static GpioDriver* g_interrupt_handlers[EXTINT_LINE_COUNT] = {};
44
45 80 GpioState& getGpioState() {
46 80 return g_gpio_state;
47 }
48
49 11 void GpioHal::configureInput(U8 groupIdx, U8 pinIdx, GpioDriver::InputPullMode input_pull_mode) {
50 11 g_gpio_state.configure_input_count++;
51 11 g_gpio_state.last_group = groupIdx;
52 11 g_gpio_state.last_pin = pinIdx;
53 11 g_gpio_state.last_input_pull_mode = input_pull_mode;
54 11 }
55
56 5 void GpioHal::configureExternalInterrupt(U8 groupIdx, U8 pinIdx, GpioDriver::ExternalInterruptMode interrupt_mode) {
57 5 g_gpio_state.configure_external_interrupt_count++;
58 5 g_gpio_state.last_group = groupIdx;
59 5 g_gpio_state.last_pin = pinIdx;
60 5 g_gpio_state.last_input_interrupt_mode = interrupt_mode;
61 5 }
62
63 ✗ U32 GpioHal::getInterruptFlags() {
64 ✗ return 0;
65 }
66
67 ✗ void GpioHal::clearInterruptFlags(U32 mask) {
68 (void)mask;
69 ✗ }
70
71 5 void registerInterruptHandler(U8 pinIdx, GpioDriver* handler) {
72 5 FW_ASSERT(handler != nullptr);
73 5 g_interrupt_handlers[pinIdx % EXTINT_LINE_COUNT] = handler;
74 5 }
75
76 ✗ GpioDriver* getInterruptHandler(U8 extintLine) {
77 ✗ return g_interrupt_handlers[extintLine % EXTINT_LINE_COUNT];
78 }
79
80 67 void GpioHal::configureOutput(U8 groupIdx, U8 pinIdx) {
81 67 g_gpio_state.configure_output_count++;
82 67 g_gpio_state.last_group = groupIdx;
83 67 g_gpio_state.last_pin = pinIdx;
84 67 }
85
86 2 Fw::Logic GpioHal::read(U8 groupIdx, U8 pinIdx) {
87 2 g_gpio_state.read_count++;
88 2 g_gpio_state.last_read_group = groupIdx;
89 2 g_gpio_state.last_read_pin = pinIdx;
90 2 return g_gpio_state.read_value;
91 }
92
93 2 void GpioHal::write(U8 groupIdx, U8 pinIdx, const Fw::Logic& state) {
94 2 g_gpio_state.write_count++;
95 2 g_gpio_state.last_write_group = groupIdx;
96 2 g_gpio_state.last_write_pin = pinIdx;
97 2 g_gpio_state.last_write_state = state;
98 2 }
99
100 //! Test helper: reset stub state for clean test runs
101 81 void resetGpioState() {
102 81 g_gpio_state.configure_input_count = 0;
103 81 g_gpio_state.configure_external_interrupt_count = 0;
104 81 g_gpio_state.configure_output_count = 0;
105 81 g_gpio_state.write_count = 0;
106 81 g_gpio_state.read_count = 0;
107 81 g_gpio_state.last_group = 0;
108 81 g_gpio_state.last_pin = 0;
109 81 g_gpio_state.last_input_pull_mode = GpioDriver::InputPullMode::NO_PULL;
110 81 g_gpio_state.last_input_interrupt_mode = GpioDriver::ExternalInterruptMode::NONE;
111 81 g_gpio_state.last_write_group = 0;
112 81 g_gpio_state.last_write_pin = 0;
113 81 g_gpio_state.last_write_state = Fw::Logic::LOW;
114 81 g_gpio_state.last_read_group = 0;
115 81 g_gpio_state.last_read_pin = 0;
116 81 g_gpio_state.read_value = Fw::Logic::HIGH;
117
118
2/2
✓ Branch 0 taken 1296 times.
✓ Branch 1 taken 81 times.
1377 for (U8 line = 0; line < EXTINT_LINE_COUNT; line++) {
119 1296 g_interrupt_handlers[line] = nullptr;
120 }
121 81 }
122
123 //! Test helper: set the value returned by the next read()
124 2 void setReadValue(const Fw::Logic& state) {
125 2 g_gpio_state.read_value = state;
126 2 }
127
128 //! Test helper: dispatch an edge to a pin's registered handler like EIC_Handler would.
129 3 void simulateInterrupt(U8 pinIdx) {
130 3 GpioDriver* handler = g_interrupt_handlers[pinIdx % EXTINT_LINE_COUNT];
131
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1 times.
3 if (handler != nullptr) {
132 2 handler->gpioInterruptIsr();
133 }
134 3 }
135
136 } // namespace GpioHardware
137 } // namespace Samd21
138