diff --git a/Src/boards/rl/mini_v3/board/board.cmake b/Src/boards/rl/mini_v3/board/board.cmake index 2511d4da..8b168543 100644 --- a/Src/boards/rl/mini_v3/board/board.cmake +++ b/Src/boards/rl/mini_v3/board/board.cmake @@ -18,6 +18,7 @@ set(BOARD_FLASH_ORIGIN_HEX 0x08000000) set(BOARD_FLASH_SIZE_KB 512) set(BOOTLOADER_RESERVED_KB 64) list(APPEND APPLICATION_SOURCES + ${CMAKE_CURRENT_LIST_DIR}/gpio.cpp ${CMAKE_CURRENT_LIST_DIR}/pwm.cpp ${CMAKE_CURRENT_LIST_DIR}/rcpwm_channels.cpp ) diff --git a/Src/boards/rl/mini_v3/board/gpio.cpp b/Src/boards/rl/mini_v3/board/gpio.cpp new file mode 100644 index 00000000..19bb2c5d --- /dev/null +++ b/Src/boards/rl/mini_v3/board/gpio.cpp @@ -0,0 +1,25 @@ +/** + * This program is free software under the GNU General Public License v3. + * See for details. + */ + +#include +#include +#include "gpio_mapping.hpp" +#include "peripheral/gpio/gpio_stm32.hpp" + +namespace HAL { +namespace { +const std::array kGpios = {{ + {.port = CAN1_TERMINATOR_GPIO_Port, .pin = CAN1_TERMINATOR_Pin}, + {.port = CAN2_TERMINATOR_GPIO_Port, .pin = CAN2_TERMINATOR_Pin}, + } +}; +static_assert(BoardGpio::CAN1_TERMINATOR == 0); +static_assert(BoardGpio::CAN2_TERMINATOR == 1); +static_assert(BoardGpio::CAN2_TERMINATOR + 1 == kGpios.size()); +} + +const std::span gpios{kGpios}; + +} // namespace HAL diff --git a/Src/boards/rl/mini_v3/board/gpio_mapping.hpp b/Src/boards/rl/mini_v3/board/gpio_mapping.hpp new file mode 100644 index 00000000..e1a41892 --- /dev/null +++ b/Src/boards/rl/mini_v3/board/gpio_mapping.hpp @@ -0,0 +1,13 @@ +/** + * This program is free software under the GNU General Public License v3. + * See for details. + */ + +#pragma once +#include "peripheral/gpio/gpio.hpp" + +namespace BoardGpio { +static constexpr HAL::GpioPin INVALID = HAL::GPIO_INVALID_PIN; +static constexpr HAL::GpioPin CAN1_TERMINATOR = 0; +static constexpr HAL::GpioPin CAN2_TERMINATOR = 1; +} // namespace BoardGpio diff --git a/Src/boards/rl/node_v4/board/gpio_mapping.hpp b/Src/boards/rl/node_v4/board/gpio_mapping.hpp deleted file mode 100644 index 1da62104..00000000 --- a/Src/boards/rl/node_v4/board/gpio_mapping.hpp +++ /dev/null @@ -1,28 +0,0 @@ -/** - * This program is free software under the GNU General Public License v3. - * See for details. - */ - -#ifndef SRC_BOARDS_RL_NODE_V4_GPIO_MAPPING_HPP_ -#define SRC_BOARDS_RL_NODE_V4_GPIO_MAPPING_HPP_ - -#include "peripheral/gpio/gpio.hpp" - -namespace BoardGpio { - -static constexpr HAL::GPIO::Pin INVALID = HAL::GPIO::Pin::GPIO_AMOUNT; - -static constexpr HAL::GPIO::Pin INTERNAL_LED_RED = HAL::GPIO::Pin::INTERNAL_LED_RED; -static constexpr HAL::GPIO::Pin INTERNAL_LED_GREEN = HAL::GPIO::Pin::INTERNAL_LED_GREEN; -static constexpr HAL::GPIO::Pin INTERNAL_LED_BLUE = HAL::GPIO::Pin::INTERNAL_LED_BLUE; - -static constexpr HAL::GPIO::Pin EXT_RGB_LED_RED = INVALID; -static constexpr HAL::GPIO::Pin EXT_RGB_LED_GREEN = INVALID; -static constexpr HAL::GPIO::Pin EXT_RGB_LED_BLUE = INVALID; - -static constexpr HAL::GPIO::Pin CAN1_TERMINATOR = INVALID; -static constexpr HAL::GPIO::Pin CAN2_TERMINATOR = INVALID; - -} // namespace BoardGpio - -#endif // SRC_BOARDS_RL_NODE_V4_GPIO_MAPPING_HPP_ diff --git a/Src/modules/application/application.cpp b/Src/modules/application/application.cpp index 6edf69af..6b6d43ea 100644 --- a/Src/modules/application/application.cpp +++ b/Src/modules/application/application.cpp @@ -19,6 +19,10 @@ #include "module.hpp" #include "main.h" +#if defined(CAN1_TERMINATOR_Pin) && defined(CAN2_TERMINATOR_Pin) +#include "gpio_mapping.hpp" +#endif + #ifndef LIBPARAMS_HAS_REDUNDANT_STORAGE #define LIBPARAMS_HAS_REDUNDANT_STORAGE 1 #endif @@ -85,8 +89,8 @@ static int8_t init_board_periphery() { auto teminator_param = paramsGetIntegerValue(IntParamsIndexes::PARAM_SYSTEM_CAN_TEMINATOR); std::bitset<2> terminator_mask(teminator_param); - HAL::GPIO::set(HAL::GPIO::Pin::CAN1_TERMINATOR, terminator_mask[0]); - HAL::GPIO::set(HAL::GPIO::Pin::CAN2_TERMINATOR, terminator_mask[1]); + HAL::GPIO::set(BoardGpio::CAN1_TERMINATOR, terminator_mask[0]); + HAL::GPIO::set(BoardGpio::CAN2_TERMINATOR, terminator_mask[1]); #endif return 0; } diff --git a/Src/peripheral/gpio/CMakeLists.txt b/Src/peripheral/gpio/CMakeLists.txt index fe474f40..abbeb49a 100644 --- a/Src/peripheral/gpio/CMakeLists.txt +++ b/Src/peripheral/gpio/CMakeLists.txt @@ -11,11 +11,10 @@ if(NOT APP_PLATFORM) message(SEND_ERROR "APP_PLATFORM is not specified or unsupported! Options: stm32f103, stm32g0b1, stm32h753xx, ubuntu.") endif() -if(APP_PLATFORM STREQUAL "stm32f103") -elseif(APP_PLATFORM STREQUAL "stm32g0b1") - list(APPEND PERIPHERAL_SOURCES ${CMAKE_CURRENT_LIST_DIR}/gpio_stm32g0.cpp) -elseif(APP_PLATFORM STREQUAL "stm32h753xx") - list(APPEND PERIPHERAL_SOURCES ${CMAKE_CURRENT_LIST_DIR}/gpio_stm32h7.cpp) +if(APP_PLATFORM STREQUAL "stm32f103" OR + APP_PLATFORM STREQUAL "stm32g0b1" OR + APP_PLATFORM STREQUAL "stm32h753xx") + list(APPEND PERIPHERAL_SOURCES ${CMAKE_CURRENT_LIST_DIR}/gpio_stm32.cpp) elseif(APP_PLATFORM STREQUAL "ubuntu") list(APPEND PERIPHERAL_SOURCES ${CMAKE_CURRENT_LIST_DIR}/gpio_ubuntu.cpp) else() diff --git a/Src/peripheral/gpio/gpio.hpp b/Src/peripheral/gpio/gpio.hpp index c37d29eb..9f1375f1 100644 --- a/Src/peripheral/gpio/gpio.hpp +++ b/Src/peripheral/gpio/gpio.hpp @@ -12,42 +12,17 @@ namespace HAL { +using GpioPin = uint8_t; +inline constexpr GpioPin GPIO_INVALID_PIN = UINT8_MAX; + class GPIO { public: - enum class Pin { - /** - * @brief Any node must have an internal RGB LED - */ - INTERNAL_LED_RED, - INTERNAL_LED_GREEN, - INTERNAL_LED_BLUE, - - /** - * @brief A node may have an auxilliary external RGB LED - */ - EXT_RGB_LED_RED, - EXT_RGB_LED_GREEN, - EXT_RGB_LED_BLUE, - - /** - * @brief CAN terminator 120 ohm resistor - * v2: doesn't exist yet - * v3: PA15 - */ - CAN1_TERMINATOR, - - /** - * @brief CAN terminator 120 ohm resistor - * v2: doesn't exist yet - * v3: PB15 - */ - CAN2_TERMINATOR, - - GPIO_AMOUNT, - }; - - static void set(const Pin gpio_pin, bool state); - static bool get(const Pin gpio_pin); + static uint8_t pin_count(); + static void set(GpioPin gpio_pin, bool state); + static bool get(GpioPin gpio_pin); + +private: + static bool is_valid_pin(GpioPin gpio_pin); }; } // namespace HAL diff --git a/Src/peripheral/gpio/gpio_stm32.cpp b/Src/peripheral/gpio/gpio_stm32.cpp new file mode 100644 index 00000000..68f9daa6 --- /dev/null +++ b/Src/peripheral/gpio/gpio_stm32.cpp @@ -0,0 +1,42 @@ +/** + * This program is free software under the GNU General Public License v3. + * See for details. + */ + +#include "peripheral/gpio/gpio_stm32.hpp" +#include + +namespace HAL { + +namespace { +const std::array kNoGpios{}; +} + +extern const std::span gpios __attribute__((weak)) = kNoGpios; + +bool GPIO::is_valid_pin(GpioPin gpio_pin) { + return gpio_pin < pin_count(); +} + +uint8_t GPIO::pin_count() { + return static_cast(gpios.size()); +} + +void GPIO::set(GpioPin gpio_pin, bool state) { + if (!is_valid_pin(gpio_pin)) { + return; + } + + const auto pin_state = state ? GPIO_PIN_SET : GPIO_PIN_RESET; + HAL_GPIO_WritePin(gpios[gpio_pin].port, gpios[gpio_pin].pin, pin_state); +} + +bool GPIO::get(GpioPin gpio_pin) { + if (!is_valid_pin(gpio_pin)) { + return false; + } + + return HAL_GPIO_ReadPin(gpios[gpio_pin].port, gpios[gpio_pin].pin) == GPIO_PIN_SET; +} + +} // namespace HAL diff --git a/Src/peripheral/gpio/gpio_stm32.hpp b/Src/peripheral/gpio/gpio_stm32.hpp new file mode 100644 index 00000000..cfc7551b --- /dev/null +++ b/Src/peripheral/gpio/gpio_stm32.hpp @@ -0,0 +1,24 @@ +/** + * This program is free software under the GNU General Public License v3. + * See for details. + */ + +#ifndef SRC_PERIPHERAL_GPIO_STM32_HPP_ +#define SRC_PERIPHERAL_GPIO_STM32_HPP_ + +#include +#include "main.h" +#include "peripheral/gpio/gpio.hpp" + +namespace HAL { + +struct GpioPinInfo { + GPIO_TypeDef* port; + uint16_t pin; +}; + +extern const std::span gpios; + +} // namespace HAL + +#endif // SRC_PERIPHERAL_GPIO_STM32_HPP_ diff --git a/Src/peripheral/gpio/gpio_stm32g0.cpp b/Src/peripheral/gpio/gpio_stm32g0.cpp deleted file mode 100644 index f0a69dcc..00000000 --- a/Src/peripheral/gpio/gpio_stm32g0.cpp +++ /dev/null @@ -1,51 +0,0 @@ -/** - * This program is free software under the GNU General Public License v3. - * See for details. - * Author: Anastasiia Stepanova - * Author: Dmitry Ponomarev - */ - -#include "peripheral/gpio/gpio.hpp" -#include "main.h" - -namespace HAL { - -void GPIO::set(Pin gpio_pin, bool state) { -#ifdef CAN1_TERMINATOR_GPIO_Port - auto pin_state = state ? GPIO_PIN_SET : GPIO_PIN_RESET; - switch (gpio_pin) { - case Pin::CAN1_TERMINATOR: - HAL_GPIO_WritePin(CAN1_TERMINATOR_GPIO_Port, CAN1_TERMINATOR_Pin, pin_state); - break; - - case Pin::CAN2_TERMINATOR: - HAL_GPIO_WritePin(CAN2_TERMINATOR_GPIO_Port, CAN2_TERMINATOR_Pin, pin_state); - break; - default: - break; - } -#else - (void)gpio_pin; - (void)state; -#endif -} - -bool GPIO::get(Pin gpio_pin) { -#ifdef CAN1_TERMINATOR_GPIO_Port - switch (gpio_pin) { - case Pin::CAN1_TERMINATOR: - return HAL_GPIO_ReadPin(CAN1_TERMINATOR_GPIO_Port, CAN1_TERMINATOR_Pin); - - case Pin::CAN2_TERMINATOR: - return HAL_GPIO_ReadPin(CAN2_TERMINATOR_GPIO_Port, CAN2_TERMINATOR_Pin); - - default: - return GPIO_PIN_SET; - } -#else - (void)gpio_pin; - return GPIO_PIN_RESET; -#endif -} - -} // namespace HAL diff --git a/Src/peripheral/gpio/gpio_stm32h7.cpp b/Src/peripheral/gpio/gpio_stm32h7.cpp deleted file mode 100644 index da54103b..00000000 --- a/Src/peripheral/gpio/gpio_stm32h7.cpp +++ /dev/null @@ -1,58 +0,0 @@ -/** - * This program is free software under the GNU General Public License v3. - * See for details. - */ - -#include "peripheral/gpio/gpio.hpp" -#include "main.h" - -namespace HAL { - -void GPIO::set(Pin gpio_pin, bool state) { -#if defined(CAN1_TERMINATOR_GPIO_Port) || defined(CAN2_TERMINATOR_GPIO_Port) - const auto pin_state = state ? GPIO_PIN_SET : GPIO_PIN_RESET; - switch (gpio_pin) { - #ifdef CAN1_TERMINATOR_GPIO_Port - case Pin::CAN1_TERMINATOR: - HAL_GPIO_WritePin(CAN1_TERMINATOR_GPIO_Port, CAN1_TERMINATOR_Pin, pin_state); - break; - #endif - - #ifdef CAN2_TERMINATOR_GPIO_Port - case Pin::CAN2_TERMINATOR: - HAL_GPIO_WritePin(CAN2_TERMINATOR_GPIO_Port, CAN2_TERMINATOR_Pin, pin_state); - break; - #endif - - default: - break; - } -#else - (void)gpio_pin; - (void)state; -#endif -} - -bool GPIO::get(Pin gpio_pin) { -#if defined(CAN1_TERMINATOR_GPIO_Port) || defined(CAN2_TERMINATOR_GPIO_Port) - switch (gpio_pin) { - #ifdef CAN1_TERMINATOR_GPIO_Port - case Pin::CAN1_TERMINATOR: - return HAL_GPIO_ReadPin(CAN1_TERMINATOR_GPIO_Port, CAN1_TERMINATOR_Pin); - #endif - - #ifdef CAN2_TERMINATOR_GPIO_Port - case Pin::CAN2_TERMINATOR: - return HAL_GPIO_ReadPin(CAN2_TERMINATOR_GPIO_Port, CAN2_TERMINATOR_Pin); - #endif - - default: - return GPIO_PIN_RESET; - } -#else - (void)gpio_pin; - return GPIO_PIN_RESET; -#endif -} - -} // namespace HAL diff --git a/Src/peripheral/gpio/gpio_ubuntu.cpp b/Src/peripheral/gpio/gpio_ubuntu.cpp index da6f940e..71df34e5 100644 --- a/Src/peripheral/gpio/gpio_ubuntu.cpp +++ b/Src/peripheral/gpio/gpio_ubuntu.cpp @@ -5,20 +5,35 @@ * Author: Dmitry Ponomarev */ -#include "peripheral/gpio/gpio.hpp" -#include -#include "main.h" +#include "peripheral/gpio/gpio_ubuntu.hpp" +#include namespace HAL { -static std::vector gpio((int)GPIO::Pin::GPIO_AMOUNT, false); +namespace { +std::array kNoGpios{}; +} + +[[gnu::weak]] std::span gpios{kNoGpios}; + +bool GPIO::is_valid_pin(GpioPin gpio_pin) { + return gpio_pin < pin_count(); +} + +uint8_t GPIO::pin_count() { + return static_cast(gpios.size()); +} + +void GPIO::set(GpioPin gpio_pin, bool state) { + if (!is_valid_pin(gpio_pin)) { + return; + } -void GPIO::set(Pin gpio_pin, bool state) { - gpio[(int)gpio_pin] = state; + gpios[gpio_pin] = state; } -bool GPIO::get(Pin gpio_pin) { - return gpio[(int)gpio_pin]; +bool GPIO::get(GpioPin gpio_pin) { + return is_valid_pin(gpio_pin) ? gpios[gpio_pin] : false; } } // namespace HAL diff --git a/Src/peripheral/gpio/gpio_ubuntu.hpp b/Src/peripheral/gpio/gpio_ubuntu.hpp new file mode 100644 index 00000000..e7facba3 --- /dev/null +++ b/Src/peripheral/gpio/gpio_ubuntu.hpp @@ -0,0 +1,18 @@ +/** + * This program is free software under the GNU General Public License v3. + * See for details. + */ + +#ifndef SRC_PERIPHERAL_GPIO_UBUNTU_HPP_ +#define SRC_PERIPHERAL_GPIO_UBUNTU_HPP_ + +#include +#include "peripheral/gpio/gpio.hpp" + +namespace HAL { + +extern std::span gpios; + +} // namespace HAL + +#endif // SRC_PERIPHERAL_GPIO_UBUNTU_HPP_ diff --git a/Tests/CMakeLists.txt b/Tests/CMakeLists.txt index a45550eb..e461fcd8 100644 --- a/Tests/CMakeLists.txt +++ b/Tests/CMakeLists.txt @@ -40,3 +40,11 @@ endfunction() gen_test(fft ${UNIT_TESTS_DIR}/common/test_fft.cpp) gen_test(algorithms ${UNIT_TESTS_DIR}/common/test_algorithms.cpp) + +add_executable(gpio + ${UNIT_TESTS_DIR}/peripheral/test_gpio.cpp + ${ROOT_DIR}/Src/peripheral/gpio/gpio_ubuntu.cpp +) +target_include_directories(gpio PUBLIC ${ROOT_DIR}/Src) +target_link_libraries(gpio GTest::gtest GTest::gtest_main) +add_test(NAME gpio COMMAND gpio) diff --git a/Tests/peripheral/test_gpio.cpp b/Tests/peripheral/test_gpio.cpp new file mode 100644 index 00000000..00435831 --- /dev/null +++ b/Tests/peripheral/test_gpio.cpp @@ -0,0 +1,51 @@ +/** + * This program is free software under the GNU General Public License v3. + * See for details. + */ + +#include +#include +#include +#include "peripheral/gpio/gpio_ubuntu.hpp" + +namespace HAL { +namespace { +std::array kGpios{}; +} +std::span gpios{kGpios}; +} // namespace HAL + +class GpioTest : public testing::Test { +protected: + void SetUp() override { + HAL::GPIO::set(0, false); + HAL::GPIO::set(1, false); + } +}; + +TEST_F(GpioTest, StoresIndependentPinStates) { + HAL::GPIO::set(0, true); + + EXPECT_TRUE(HAL::GPIO::get(0)); + EXPECT_FALSE(HAL::GPIO::get(1)); + + HAL::GPIO::set(1, true); + + EXPECT_TRUE(HAL::GPIO::get(0)); + EXPECT_TRUE(HAL::GPIO::get(1)); +} + +TEST_F(GpioTest, InvalidReadReturnsFalse) { + EXPECT_FALSE(HAL::GPIO::get(HAL::GPIO_INVALID_PIN)); + EXPECT_FALSE(HAL::GPIO::get(HAL::GPIO::pin_count())); +} + +TEST_F(GpioTest, InvalidWriteDoesNotChangeValidPins) { + HAL::GPIO::set(0, true); + + HAL::GPIO::set(HAL::GPIO_INVALID_PIN, false); + HAL::GPIO::set(HAL::GPIO::pin_count(), false); + + EXPECT_TRUE(HAL::GPIO::get(0)); + EXPECT_FALSE(HAL::GPIO::get(1)); +}