| 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 | ✗ | GpioState& getGpioState() { | |
| 46 | ✗ | return g_gpio_state; | |
| 47 | } | ||
| 48 | |||
| 49 | ✗ | void GpioHal::configureInput(U8 groupIdx, U8 pinIdx, GpioDriver::InputPullMode input_pull_mode) { | |
| 50 | ✗ | g_gpio_state.configure_input_count++; | |
| 51 | ✗ | g_gpio_state.last_group = groupIdx; | |
| 52 | ✗ | g_gpio_state.last_pin = pinIdx; | |
| 53 | ✗ | g_gpio_state.last_input_pull_mode = input_pull_mode; | |
| 54 | ✗ | } | |
| 55 | |||
| 56 | ✗ | void GpioHal::configureExternalInterrupt(U8 groupIdx, U8 pinIdx, GpioDriver::ExternalInterruptMode interrupt_mode) { | |
| 57 | ✗ | g_gpio_state.configure_external_interrupt_count++; | |
| 58 | ✗ | g_gpio_state.last_group = groupIdx; | |
| 59 | ✗ | g_gpio_state.last_pin = pinIdx; | |
| 60 | ✗ | g_gpio_state.last_input_interrupt_mode = interrupt_mode; | |
| 61 | ✗ | } | |
| 62 | |||
| 63 | ✗ | U32 GpioHal::getInterruptFlags() { | |
| 64 | ✗ | return 0; | |
| 65 | } | ||
| 66 | |||
| 67 | ✗ | void GpioHal::clearInterruptFlags(U32 mask) { | |
| 68 | (void)mask; | ||
| 69 | ✗ | } | |
| 70 | |||
| 71 | ✗ | void registerInterruptHandler(U8 pinIdx, GpioDriver* handler) { | |
| 72 | ✗ | FW_ASSERT(handler != nullptr); | |
| 73 | ✗ | g_interrupt_handlers[pinIdx % EXTINT_LINE_COUNT] = handler; | |
| 74 | ✗ | } | |
| 75 | |||
| 76 | ✗ | GpioDriver* getInterruptHandler(U8 extintLine) { | |
| 77 | ✗ | return g_interrupt_handlers[extintLine % EXTINT_LINE_COUNT]; | |
| 78 | } | ||
| 79 | |||
| 80 | ✗ | void GpioHal::configureOutput(U8 groupIdx, U8 pinIdx) { | |
| 81 | ✗ | g_gpio_state.configure_output_count++; | |
| 82 | ✗ | g_gpio_state.last_group = groupIdx; | |
| 83 | ✗ | g_gpio_state.last_pin = pinIdx; | |
| 84 | ✗ | } | |
| 85 | |||
| 86 | ✗ | Fw::Logic GpioHal::read(U8 groupIdx, U8 pinIdx) { | |
| 87 | ✗ | g_gpio_state.read_count++; | |
| 88 | ✗ | g_gpio_state.last_read_group = groupIdx; | |
| 89 | ✗ | g_gpio_state.last_read_pin = pinIdx; | |
| 90 | ✗ | return g_gpio_state.read_value; | |
| 91 | } | ||
| 92 | |||
| 93 | ✗ | void GpioHal::write(U8 groupIdx, U8 pinIdx, const Fw::Logic& state) { | |
| 94 | ✗ | g_gpio_state.write_count++; | |
| 95 | ✗ | g_gpio_state.last_write_group = groupIdx; | |
| 96 | ✗ | g_gpio_state.last_write_pin = pinIdx; | |
| 97 | ✗ | g_gpio_state.last_write_state = state; | |
| 98 | ✗ | } | |
| 99 | |||
| 100 | //! Test helper: reset stub state for clean test runs | ||
| 101 | ✗ | void resetGpioState() { | |
| 102 | ✗ | g_gpio_state.configure_input_count = 0; | |
| 103 | ✗ | g_gpio_state.configure_external_interrupt_count = 0; | |
| 104 | ✗ | g_gpio_state.configure_output_count = 0; | |
| 105 | ✗ | g_gpio_state.write_count = 0; | |
| 106 | ✗ | g_gpio_state.read_count = 0; | |
| 107 | ✗ | g_gpio_state.last_group = 0; | |
| 108 | ✗ | g_gpio_state.last_pin = 0; | |
| 109 | ✗ | g_gpio_state.last_input_pull_mode = GpioDriver::InputPullMode::NO_PULL; | |
| 110 | ✗ | g_gpio_state.last_input_interrupt_mode = GpioDriver::ExternalInterruptMode::NONE; | |
| 111 | ✗ | g_gpio_state.last_write_group = 0; | |
| 112 | ✗ | g_gpio_state.last_write_pin = 0; | |
| 113 | ✗ | g_gpio_state.last_write_state = Fw::Logic::LOW; | |
| 114 | ✗ | g_gpio_state.last_read_group = 0; | |
| 115 | ✗ | g_gpio_state.last_read_pin = 0; | |
| 116 | ✗ | g_gpio_state.read_value = Fw::Logic::HIGH; | |
| 117 | |||
| 118 | ✗ | for (U8 line = 0; line < EXTINT_LINE_COUNT; line++) { | |
| 119 | ✗ | g_interrupt_handlers[line] = nullptr; | |
| 120 | } | ||
| 121 | ✗ | } | |
| 122 | |||
| 123 | //! Test helper: set the value returned by the next read() | ||
| 124 | ✗ | void setReadValue(const Fw::Logic& state) { | |
| 125 | ✗ | g_gpio_state.read_value = state; | |
| 126 | ✗ | } | |
| 127 | |||
| 128 | //! Test helper: dispatch an edge to a pin's registered handler like EIC_Handler would. | ||
| 129 | ✗ | void simulateInterrupt(U8 pinIdx) { | |
| 130 | ✗ | GpioDriver* handler = g_interrupt_handlers[pinIdx % EXTINT_LINE_COUNT]; | |
| 131 | ✗ | if (handler != nullptr) { | |
| 132 | ✗ | handler->gpioInterruptIsr(); | |
| 133 | } | ||
| 134 | ✗ | } | |
| 135 | |||
| 136 | } // namespace GpioHardware | ||
| 137 | } // namespace Samd21 | ||
| 138 |