diff --git a/CHANGELOG.md b/CHANGELOG.md index 2019fdcd..2cd9e333 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -25,8 +25,6 @@ and this project adheres to [Semantic Versioning](http://semver.org/). PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572 - HAL Devicehandlers: Periodic printout is run-time configurable now - `oneShotAction` flag in the `TestTask` class is not static anymore -- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations - PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585 - Major update for version handling, using `git describe` to fetch version information with git. PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/601 - Place `Version` class outside of `fsfw` namespace. It is generic @@ -45,12 +43,39 @@ and this project adheres to [Semantic Versioning](http://semver.org/). creation call. It allows passing context information and an arbitrary user argument into the message queue. Also streamlined and simplified `MessageQueue` implementation for all OSALs PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/583 -- Clock: - - `timeval` to `TimeOfDay_t` - - Added Mutex for gmtime calls: (compare http://www.opengate.at/blog/2020/01/timeless/) - - Moved the statics used by Clock in ClockCommon.cpp to this file - - Better check for leap seconds - - Added Unittests for Clock (only getter) + +### HAL + +- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585 +- HAL Linux SPI: Set the Clock Default State when setting new SPI speed + and mode + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/573 +- GPIO HAL: `Direction`, `GpioOperation` and `Levels` are enum classes now, which prevents + name clashes with Windows defines. + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/572 +- HAL Linux Uart: Baudrate and bits per word are enums now, avoiding misconfigurations + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/585 + +### Time + +PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/584 and +https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593 + +- `timeval` to `TimeOfDay_t` +- Added Mutex for gmtime calls: (compare http://www.opengate.at/blog/2020/01/timeless/) +- Moved the statics used by Clock in ClockCommon.cpp to this file +- Better check for leap seconds +- Added Unittests for Clock (only getter) + +### Power + +- `PowerSwitchIF`: Remove `const` specifier from `sendSwitchCommand` and `sendFuseOnCommand` and + also specify a `ReturnValue_t` return type + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590 +- Extend `PowerSwitcher` module to optionally check current state when calling `turnOn` or + `turnOff`. Tis can be helpful to avoid commanding switches which do not need commanding + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590 ## Removed @@ -60,11 +85,29 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## Additions +- LTO support: Allow using LTO/IPO by setting `FSFW_ENABLE_LTO=1`. CMake is able to detect whether + the user compiler supports IPO/LPO. LTO is on by default now. Most modern compilers support it, + can make good use of it and it usually makes the code faster and/or smaller. + After some more research: + Enabling LTO will actually cause the compiler to only produce thin LTO by adding + `-flto -fno-fat-lto-objects` to the compiler options. I am not sure this is an ideal choice + because if an application linking against the FSFW does not use LTO, there can be compile + issues (e.g. observed when compiling the FSFW tests without LTO). This is a known issue as + can be seen in the multiple CMake issues for it: + - https://gitlab.kitware.com/cmake/cmake/-/issues/22913, + - https://gitlab.kitware.com/cmake/cmake/-/issues/16808, + - https://gitlab.kitware.com/cmake/cmake/-/issues/21696 + Easiest solution for now: Keep this option OFF by default. + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/616 - Dedicated Version class and constant `fsfw::FSFW_VERSION` containing version information inside `fsfw/version.h` PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559 - Added ETL dependency and improved library dependency management PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/592 +- Add a `DummyPowerSwitcher` module which can be useful for test setups when no PCDU is available + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590 +- New typedef for switcher type + PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590 - `Subsystem`: New API to add table and sequence entries ## HAL diff --git a/CMakeLists.txt b/CMakeLists.txt index 0874cf3c..1b155b81 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,11 +18,12 @@ list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake" ) list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/cmake/cmake-modules") set(MSG_PREFIX "fsfw |") +set(FSFW_ETL_LIB_NAME etl) set(FSFW_ETL_LIB_MAJOR_VERSION 20 CACHE STRING - "ETL library major version requirement" + "ETL library major version requirement" ) set(FSFW_ETL_LIB_VERSION ${FSFW_ETL_LIB_MAJOR_VERSION}.27.3 CACHE STRING - "ETL library exact version requirement" + "ETL library exact version requirement" ) set(FSFW_ETL_LINK_TARGET etl::etl) @@ -33,19 +34,28 @@ set(FSFW_CATCH2_LIB_VERSION v${FSFW_CATCH2_LIB_MAJOR_VERSION}.0.0-preview5 CACHE "Catch2 library exact version requirement" ) -set(FSFW_ETL_LIB_NAME etl) +# Keep this off by default for now. See PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/616 +# for information which keeping this on by default is problematic +option(FSFW_ENABLE_IPO "Enable interprocedural optimization or link-time optimization if available" OFF) +if(FSFW_ENABLE_IPO) + include(CheckIPOSupported) + check_ipo_supported(RESULT IPO_SUPPORTED OUTPUT IPO_ERROR) + if(NOT IPO_SUPPORTED) + message(STATUS "FSFW | IPO/LTO not supported: ${IPO_ERROR}") + endif() +endif() option(FSFW_GENERATE_SECTIONS - "Generate function and data sections. Required to remove unused code" ON + "Generate function and data sections. Required to remove unused code" ON ) if(FSFW_GENERATE_SECTIONS) - option(FSFW_REMOVE_UNUSED_CODE "Remove unused code" ON) + option(FSFW_REMOVE_UNUSED_CODE "Remove unused code" ON) endif() option(FSFW_BUILD_UNITTESTS "Build unittest binary in addition to static library" OFF) option(FSFW_BUILD_DOCS "Build documentation with Sphinx and Doxygen" OFF) if(FSFW_BUILD_UNITTESTS) - option(FSFW_TESTS_GEN_COV "Generate coverage data for unittests" ON) + option(FSFW_TESTS_GEN_COV "Generate coverage data for unittests" ON) endif() option(FSFW_WARNING_SHADOW_LOCAL_GCC "Enable -Wshadow=local warning in GCC" ON) @@ -72,6 +82,10 @@ set(FSFW_DUMMY_TGT fsfw-dummy) add_library(${LIB_FSFW_NAME}) +if(IPO_SUPPORTED AND FSFW_ENABLE_IPO) + set_property(TARGET ${LIB_FSFW_NAME} PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) +endif() + set(FSFW_GIT_VER_HANDLING_OK FALSE) # Version handling if(EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/.git) @@ -128,6 +142,9 @@ if(FSFW_BUILD_UNITTESTS) project(${FSFW_TEST_TGT} CXX C) add_executable(${FSFW_TEST_TGT}) + if(IPO_SUPPORTED AND FSFW_ENABLE_IPO) + set_property(TARGET ${FSFW_TEST_TGT} PROPERTY INTERPROCEDURAL_OPTIMIZATION TRUE) + endif() if(FSFW_TESTS_GEN_COV) message(STATUS "${MSG_PREFIX} Generating coverage data for the library") diff --git a/src/fsfw/health/HasHealthIF.h b/src/fsfw/health/HasHealthIF.h index bdd1ce96..9b5ea6d2 100644 --- a/src/fsfw/health/HasHealthIF.h +++ b/src/fsfw/health/HasHealthIF.h @@ -16,10 +16,15 @@ class HasHealthIF { }; static const uint8_t INTERFACE_ID = CLASS_ID::HAS_HEALTH_IF; - static const ReturnValue_t OBJECT_NOT_HEALTHY = MAKE_RETURN_CODE(1); - static const ReturnValue_t INVALID_HEALTH_STATE = MAKE_RETURN_CODE(2); + static constexpr ReturnValue_t OBJECT_NOT_HEALTHY = + HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 1); + static constexpr ReturnValue_t INVALID_HEALTH_STATE = + HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 2); + static constexpr ReturnValue_t IS_EXTERNALLY_CONTROLLED = + HasReturnvaluesIF::makeReturnCode(INTERFACE_ID, 3); static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER_1; + //! P1: New Health, P2: Old Health static const Event HEALTH_INFO = MAKE_EVENT(6, severity::INFO); static const Event CHILD_CHANGED_HEALTH = MAKE_EVENT(7, severity::INFO); static const Event CHILD_PROBLEMS = MAKE_EVENT(8, severity::LOW); diff --git a/src/fsfw/power/DummyPowerSwitcher.cpp b/src/fsfw/power/DummyPowerSwitcher.cpp index d0a87288..799d49aa 100644 --- a/src/fsfw/power/DummyPowerSwitcher.cpp +++ b/src/fsfw/power/DummyPowerSwitcher.cpp @@ -1,8 +1,9 @@ #include "DummyPowerSwitcher.h" DummyPowerSwitcher::DummyPowerSwitcher(object_id_t objectId, size_t numberOfSwitches, - size_t numberOfFuses, uint32_t switchDelayMs) - : SystemObject(objectId), + size_t numberOfFuses, bool registerGlobally, + uint32_t switchDelayMs) + : SystemObject(objectId, registerGlobally), switcherList(numberOfSwitches), fuseList(numberOfFuses), switchDelayMs(switchDelayMs) {} diff --git a/src/fsfw/power/DummyPowerSwitcher.h b/src/fsfw/power/DummyPowerSwitcher.h index 24e9d648..6ccd8dd7 100644 --- a/src/fsfw/power/DummyPowerSwitcher.h +++ b/src/fsfw/power/DummyPowerSwitcher.h @@ -8,10 +8,17 @@ #include "definitions.h" #include "fsfw/objectmanager/SystemObject.h" +/** + * @brief This component can be used to simulate a power switcher like a + * Power Control Distribution Unit (PCDU) + * @details + * The dummy switcher will simply cache the commanded fuse and switch states and return them + * in the according switch getter functions. In that sense, it simulates an ideal PCDU. + */ class DummyPowerSwitcher : public SystemObject, public PowerSwitchIF { public: DummyPowerSwitcher(object_id_t objectId, size_t numberOfSwitches, size_t numberOfFuses, - uint32_t switchDelayMs = 5000); + bool registerGlobally = true, uint32_t switchDelayMs = 5000); void setInitialSwitcherList(std::vector switcherList); void setInitialFusesList(std::vector switcherList); diff --git a/src/fsfw/power/PowerSwitcher.h b/src/fsfw/power/PowerSwitcher.h index 853bbb40..279ffacf 100644 --- a/src/fsfw/power/PowerSwitcher.h +++ b/src/fsfw/power/PowerSwitcher.h @@ -18,7 +18,8 @@ class PowerSwitcher : public HasReturnvaluesIF { static const uint8_t INTERFACE_ID = CLASS_ID::POWER_SWITCHER; static const ReturnValue_t IN_POWER_TRANSITION = MAKE_RETURN_CODE(1); static const ReturnValue_t SWITCH_STATE_MISMATCH = MAKE_RETURN_CODE(2); - PowerSwitcher(PowerSwitchIF* switcher, uint8_t setSwitch1, uint8_t setSwitch2 = power::NO_SWITCH, + PowerSwitcher(PowerSwitchIF* switcher, power::Switch_t setSwitch1, + power::Switch_t setSwitch2 = power::NO_SWITCH, State_t setStartState = SWITCH_IS_OFF); void turnOn(bool checkCurrentState = true); void turnOff(bool checkCurrentState = true); diff --git a/tests/src/fsfw_tests/unit/CMakeLists.txt b/tests/src/fsfw_tests/unit/CMakeLists.txt index a8d31d88..b5143c3b 100644 --- a/tests/src/fsfw_tests/unit/CMakeLists.txt +++ b/tests/src/fsfw_tests/unit/CMakeLists.txt @@ -11,7 +11,10 @@ target_sources(${FSFW_TEST_TGT} PRIVATE ) add_subdirectory(testcfg) +add_subdirectory(mocks) + add_subdirectory(action) +add_subdirectory(power) add_subdirectory(container) add_subdirectory(osal) add_subdirectory(serialize) diff --git a/tests/src/fsfw_tests/unit/mocks/CMakeLists.txt b/tests/src/fsfw_tests/unit/mocks/CMakeLists.txt new file mode 100644 index 00000000..1b86547c --- /dev/null +++ b/tests/src/fsfw_tests/unit/mocks/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${FSFW_TEST_TGT} PRIVATE + PowerSwitcherMock.cpp +) diff --git a/tests/src/fsfw_tests/unit/mocks/PowerSwitcherMock.cpp b/tests/src/fsfw_tests/unit/mocks/PowerSwitcherMock.cpp new file mode 100644 index 00000000..5c6935e4 --- /dev/null +++ b/tests/src/fsfw_tests/unit/mocks/PowerSwitcherMock.cpp @@ -0,0 +1,77 @@ +#include "PowerSwitcherMock.h" + +static uint32_t SWITCH_REQUEST_UPDATE_VALUE = 0; + +PowerSwitcherMock::PowerSwitcherMock() {} + +ReturnValue_t PowerSwitcherMock::sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) { + if (switchMap.count(switchNr) == 0) { + switchMap.emplace(switchNr, SwitchInfo(switchNr, onOff)); + } else { + SwitchInfo& info = switchMap.at(switchNr); + info.currentState = onOff; + if (onOff == PowerSwitchIF::SWITCH_ON) { + info.timesCalledOn++; + } else { + info.timesCalledOff++; + } + } + return RETURN_OK; +} + +ReturnValue_t PowerSwitcherMock::sendFuseOnCommand(uint8_t fuseNr) { + if (fuseMap.count(fuseNr) == 0) { + fuseMap.emplace(fuseNr, FuseInfo(fuseNr)); + } else { + FuseInfo& info = fuseMap.at(fuseNr); + info.timesCalled++; + } + return RETURN_OK; +} + +ReturnValue_t PowerSwitcherMock::getSwitchState(power::Switch_t switchNr) const { + if (switchMap.count(switchNr) == 1) { + auto& info = switchMap.at(switchNr); + SWITCH_REQUEST_UPDATE_VALUE++; + return info.currentState; + } + return RETURN_FAILED; +} + +ReturnValue_t PowerSwitcherMock::getFuseState(uint8_t fuseNr) const { + if (fuseMap.count(fuseNr) == 1) { + return FUSE_ON; + } else { + return FUSE_OFF; + } + return RETURN_FAILED; +} + +uint32_t PowerSwitcherMock::getSwitchDelayMs(void) const { return 5000; } + +SwitchInfo::SwitchInfo() : switcher(0) {} + +SwitchInfo::SwitchInfo(power::Switch_t switcher, ReturnValue_t initState) + : switcher(switcher), currentState(initState) {} + +FuseInfo::FuseInfo(uint8_t fuse) : fuse(fuse) {} + +void PowerSwitcherMock::getSwitchInfo(power::Switch_t switcher, SwitchInfo& info) { + if (switchMap.count(switcher) == 1) { + info = switchMap.at(switcher); + } +} + +void PowerSwitcherMock::getFuseInfo(uint8_t fuse, FuseInfo& info) { + if (fuseMap.count(fuse) == 1) { + info = fuseMap.at(fuse); + } +} + +uint32_t PowerSwitcherMock::getAmountSwitchStatWasRequested() { + return SWITCH_REQUEST_UPDATE_VALUE; +} + +void PowerSwitcherMock::initSwitch(power::Switch_t switchNr) { + switchMap.emplace(switchNr, SwitchInfo(switchNr, PowerSwitchIF::SWITCH_OFF)); +} diff --git a/tests/src/fsfw_tests/unit/mocks/PowerSwitcherMock.h b/tests/src/fsfw_tests/unit/mocks/PowerSwitcherMock.h new file mode 100644 index 00000000..3a740e66 --- /dev/null +++ b/tests/src/fsfw_tests/unit/mocks/PowerSwitcherMock.h @@ -0,0 +1,52 @@ +#ifndef FSFW_TESTS_SRC_FSFW_TESTS_UNIT_MOCKS_POWERSWITCHERMOCK_H_ +#define FSFW_TESTS_SRC_FSFW_TESTS_UNIT_MOCKS_POWERSWITCHERMOCK_H_ + +#include + +#include +#include + +struct SwitchInfo { + public: + SwitchInfo(); + SwitchInfo(power::Switch_t switcher, ReturnValue_t initState); + + power::Switch_t switcher; + ReturnValue_t currentState = PowerSwitchIF::SWITCH_OFF; + uint32_t timesCalledOn = 0; + uint32_t timesCalledOff = 0; + uint32_t timesStatusRequested = 0; +}; + +struct FuseInfo { + public: + FuseInfo(uint8_t fuse); + uint8_t fuse; + uint32_t timesCalled = 0; +}; + +class PowerSwitcherMock : public PowerSwitchIF { + public: + PowerSwitcherMock(); + + ReturnValue_t sendSwitchCommand(power::Switch_t switchNr, ReturnValue_t onOff) override; + ReturnValue_t sendFuseOnCommand(uint8_t fuseNr) override; + ReturnValue_t getSwitchState(power::Switch_t switchNr) const override; + ReturnValue_t getFuseState(uint8_t fuseNr) const override; + uint32_t getSwitchDelayMs(void) const override; + + void getSwitchInfo(power::Switch_t switcher, SwitchInfo& info); + void getFuseInfo(uint8_t fuse, FuseInfo& info); + + uint32_t getAmountSwitchStatWasRequested(); + + void initSwitch(power::Switch_t switchNr); + + private: + using SwitchOnOffPair = std::pair; + using FuseOnOffPair = std::pair; + std::map switchMap; + std::map fuseMap; +}; + +#endif /* FSFW_TESTS_SRC_FSFW_TESTS_UNIT_MOCKS_POWERSWITCHERMOCK_H_ */ diff --git a/tests/src/fsfw_tests/unit/power/CMakeLists.txt b/tests/src/fsfw_tests/unit/power/CMakeLists.txt new file mode 100644 index 00000000..667e6f51 --- /dev/null +++ b/tests/src/fsfw_tests/unit/power/CMakeLists.txt @@ -0,0 +1,3 @@ +target_sources(${FSFW_TEST_TGT} PRIVATE + testPowerSwitcher.cpp +) diff --git a/tests/src/fsfw_tests/unit/power/testPowerSwitcher.cpp b/tests/src/fsfw_tests/unit/power/testPowerSwitcher.cpp new file mode 100644 index 00000000..d8523558 --- /dev/null +++ b/tests/src/fsfw_tests/unit/power/testPowerSwitcher.cpp @@ -0,0 +1,73 @@ +#include +#include +#include + +#include + +#include "objects/systemObjectList.h" + +TEST_CASE("Power Switcher", "[power-switcher]") { + PowerSwitcherMock mock; + PowerSwitcher switcher(&mock, 1); + DummyPowerSwitcher dummySwitcher(objects::DUMMY_POWER_SWITCHER, 5, 5, false); + PowerSwitcher switcherUsingDummy(&dummySwitcher, 1); + SwitchInfo switchInfo; + mock.initSwitch(1); + + SECTION("Basic Tests") { + REQUIRE(switcher.getFirstSwitch() == 1); + REQUIRE(switcher.getSecondSwitch() == power::NO_SWITCH); + // Default start state + REQUIRE(switcher.getState() == PowerSwitcher::SWITCH_IS_OFF); + switcher.turnOn(true); + REQUIRE(mock.getAmountSwitchStatWasRequested() == 1); + REQUIRE(switcher.getState() == PowerSwitcher::WAIT_ON); + REQUIRE(switcher.checkSwitchState() == PowerSwitcher::IN_POWER_TRANSITION); + REQUIRE(switcher.active()); + switcher.doStateMachine(); + REQUIRE(switcher.getState() == PowerSwitcher::SWITCH_IS_ON); + mock.getSwitchInfo(1, switchInfo); + REQUIRE(switchInfo.timesCalledOn == 1); + REQUIRE(not switcher.active()); + REQUIRE(mock.getAmountSwitchStatWasRequested() == 2); + REQUIRE(switcher.checkSwitchState() == HasReturnvaluesIF::RETURN_OK); + REQUIRE(mock.getAmountSwitchStatWasRequested() == 3); + switcher.turnOff(false); + REQUIRE(mock.getAmountSwitchStatWasRequested() == 3); + REQUIRE(switcher.getState() == PowerSwitcher::WAIT_OFF); + REQUIRE(switcher.active()); + REQUIRE(switcher.getState() == PowerSwitcher::WAIT_OFF); + switcher.doStateMachine(); + mock.getSwitchInfo(1, switchInfo); + REQUIRE(switcher.getState() == PowerSwitcher::SWITCH_IS_OFF); + REQUIRE(switchInfo.timesCalledOn == 1); + REQUIRE(switchInfo.timesCalledOff == 1); + REQUIRE(not switcher.active()); + REQUIRE(mock.getAmountSwitchStatWasRequested() == 4); + } + + SECTION("Dummy Test") { + // Same tests, but we can't really check the dummy + REQUIRE(switcherUsingDummy.getFirstSwitch() == 1); + REQUIRE(switcherUsingDummy.getSecondSwitch() == power::NO_SWITCH); + REQUIRE(switcherUsingDummy.getState() == PowerSwitcher::SWITCH_IS_OFF); + switcherUsingDummy.turnOn(true); + REQUIRE(switcherUsingDummy.getState() == PowerSwitcher::WAIT_ON); + REQUIRE(switcherUsingDummy.active()); + switcherUsingDummy.doStateMachine(); + REQUIRE(switcherUsingDummy.getState() == PowerSwitcher::SWITCH_IS_ON); + REQUIRE(not switcherUsingDummy.active()); + + switcherUsingDummy.turnOff(false); + REQUIRE(switcherUsingDummy.getState() == PowerSwitcher::WAIT_OFF); + REQUIRE(switcherUsingDummy.active()); + REQUIRE(switcherUsingDummy.getState() == PowerSwitcher::WAIT_OFF); + switcherUsingDummy.doStateMachine(); + REQUIRE(switcherUsingDummy.getState() == PowerSwitcher::SWITCH_IS_OFF); + REQUIRE(not switcherUsingDummy.active()); + } + + SECTION("More Dummy Tests") { + + } +} diff --git a/tests/src/fsfw_tests/unit/testcfg/objects/systemObjectList.h b/tests/src/fsfw_tests/unit/testcfg/objects/systemObjectList.h index 3eba1484..3fcd8368 100644 --- a/tests/src/fsfw_tests/unit/testcfg/objects/systemObjectList.h +++ b/tests/src/fsfw_tests/unit/testcfg/objects/systemObjectList.h @@ -21,8 +21,9 @@ enum sourceObjects : uint32_t { HK_RECEIVER_MOCK = 22, TEST_LOCAL_POOL_OWNER_BASE = 25, - SHARED_SET_ID = 26 + SHARED_SET_ID = 26, + DUMMY_POWER_SWITCHER = 27 }; }