From d47765cad80dd79bc27cf90eabfd8be15ba116fc Mon Sep 17 00:00:00 2001 From: "D.R.racer" Date: Wed, 19 May 2021 08:49:04 +0200 Subject: [PATCH] Buttons module implementation A module representing a model of the 3 buttons Includes a unit test project (empty at this stage) --- CMakeLists.txt | 23 +++---- src/hal/adc.h | 1 + src/modules/buttons.cpp | 74 +++++++++++++++++++++ tests/unit/dummy_main.cpp | 1 - tests/unit/modules/CMakeLists.txt | 1 + tests/unit/modules/buttons/CMakeLists.txt | 10 +++ tests/unit/modules/buttons/stub_adc.cpp | 20 ++++++ tests/unit/modules/buttons/stub_adc.h | 14 ++++ tests/unit/modules/buttons/test_buttons.cpp | 15 +++++ 9 files changed, 143 insertions(+), 16 deletions(-) create mode 100644 src/modules/buttons.cpp delete mode 100644 tests/unit/dummy_main.cpp create mode 100644 tests/unit/modules/buttons/CMakeLists.txt create mode 100644 tests/unit/modules/buttons/stub_adc.cpp create mode 100644 tests/unit/modules/buttons/stub_adc.h create mode 100644 tests/unit/modules/buttons/test_buttons.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index abe11df..326a896 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -175,21 +175,6 @@ if(CMAKE_CROSSCOMPILING) # generate linker map file target_link_options(firmware PUBLIC -Wl,-Map=firmware.map) - - target_sources( - firmware PRIVATE src/main.cpp src/hal/avr/cpu.cpp src/modules/protocol.cpp - src/hal/avr/usart.cpp - ) - -else() - enable_testing() - add_subdirectory(tests) - # TODO - still need to decide about the dummy_main.cpp - for unit tests it should not be necessary - # to make a separate main.cpp file - target_sources( - firmware PRIVATE tests/unit/dummy_main.cpp src/hal/avr/cpu.cpp src/modules/protocol.cpp - ) - endif() # add_link_dependency(firmware "${LINKER_SCRIPT}") @@ -197,6 +182,10 @@ endif() target_include_directories(firmware PRIVATE include src) target_compile_options(firmware PRIVATE -Wdouble-promotion) +target_sources( + firmware PRIVATE src/main.cpp src/hal/avr/cpu.cpp src/hal/avr/usart.cpp src/modules/protocol.cpp + src/modules/buttons.cpp + ) set_property( SOURCE src/version.c @@ -208,3 +197,7 @@ set_property( FW_VERSION_SUFFIX=${PROJECT_VERSION_SUFFIX} FW_VERSION_SUFFIX_SHORT=${PROJECT_VERSION_SUFFIX_SHORT} ) +if(NOT CMAKE_CROSSCOMPILING) + enable_testing() + add_subdirectory(tests) +endif() diff --git a/src/hal/adc.h b/src/hal/adc.h index 6d3d5ff..61a0f26 100644 --- a/src/hal/adc.h +++ b/src/hal/adc.h @@ -1,4 +1,5 @@ #pragma once +#include /// Hardware Abstraction Layer for the ADC's diff --git a/src/modules/buttons.cpp b/src/modules/buttons.cpp new file mode 100644 index 0000000..f3fb27d --- /dev/null +++ b/src/modules/buttons.cpp @@ -0,0 +1,74 @@ +#include "buttons.h" +#include "../hal/adc.h" + +namespace modules { + +uint16_t Buttons::tmpTiming = 0; + +// original idea from: https://www.eeweb.com/debouncing-push-buttons-using-a-state-machine-approach +void Button::Step(uint16_t time, bool press) { + switch (state) { + case State::Waiting: + if (press) { + state = State::Detected; + timeLastChange = time; + tmp = press; + } + break; + case State::Detected: + if (tmp == press) { + if (time - timeLastChange > debounce) { + state = State::WaitForRelease; + } + } else { + state = State::Waiting; + } + break; + case State::WaitForRelease: + if (!press) { + state = State::Update; + } + break; + case State::Update: + pressed = tmp; + state = State::Waiting; + timeLastChange = time; + tmp = false; + break; + default: + state = State::Waiting; + timeLastChange = time; + tmp = false; + pressed = false; + } +} + +int8_t Buttons::Sample() { + // decode 3 buttons' levels from one ADC + uint16_t raw = hal::ADC::ReadADC(0); + + // Button 1 - 0 + // Button 2 - 344 + // Button 3 - 516 + // Doesn't handle multiple pressed buttons at once + + if (raw < 10) + return 0; + else if (raw > 320 && raw < 360) + return 1; + else if (raw > 500 && raw < 530) + return 2; + return -1; +} + +void Buttons::Step() { + // @@TODO temporary timing + ++tmpTiming; + int8_t currentState = Sample(); + for (uint_fast8_t b = 0; b < N; ++b) { + // this button was pressed if b == currentState, released otherwise + buttons[b].Step(tmpTiming, b == currentState); + } +} + +} // namespace modules diff --git a/tests/unit/dummy_main.cpp b/tests/unit/dummy_main.cpp deleted file mode 100644 index 237c8ce..0000000 --- a/tests/unit/dummy_main.cpp +++ /dev/null @@ -1 +0,0 @@ -int main() {} diff --git a/tests/unit/modules/CMakeLists.txt b/tests/unit/modules/CMakeLists.txt index be359f4..4203bf3 100644 --- a/tests/unit/modules/CMakeLists.txt +++ b/tests/unit/modules/CMakeLists.txt @@ -1 +1,2 @@ +add_subdirectory(buttons) add_subdirectory(protocol) diff --git a/tests/unit/modules/buttons/CMakeLists.txt b/tests/unit/modules/buttons/CMakeLists.txt new file mode 100644 index 0000000..1d2e9cc --- /dev/null +++ b/tests/unit/modules/buttons/CMakeLists.txt @@ -0,0 +1,10 @@ +# define the test executable +add_executable(buttons_tests ../../../../src/modules/buttons.cpp stub_adc.cpp test_buttons.cpp) + +# define required search paths +target_include_directories( + buttons_tests PUBLIC ${CMAKE_SOURCE_DIR}/src/modules ${CMAKE_SOURCE_DIR}/src/hal + ) + +# tell build system about the test case +add_catch_test(buttons_tests) diff --git a/tests/unit/modules/buttons/stub_adc.cpp b/tests/unit/modules/buttons/stub_adc.cpp new file mode 100644 index 0000000..e801824 --- /dev/null +++ b/tests/unit/modules/buttons/stub_adc.cpp @@ -0,0 +1,20 @@ +#include "adc.h" +#include "stub_adc.h" +#include + +namespace hal { +namespace ADC { + + static TADCData values2Return; + static TADCData::const_iterator rdptr = values2Return.cbegin(); + + void ReinitADC(TADCData d) { + values2Return = d; + rdptr = values2Return.cbegin(); + } + + /// ADC access routines + uint16_t ReadADC(uint8_t /*adc*/) { return rdptr != values2Return.end() ? *rdptr++ : 0; } + +} // namespace ADC +} // namespace hal diff --git a/tests/unit/modules/buttons/stub_adc.h b/tests/unit/modules/buttons/stub_adc.h new file mode 100644 index 0000000..ebda1c0 --- /dev/null +++ b/tests/unit/modules/buttons/stub_adc.h @@ -0,0 +1,14 @@ +#pragma once + +#include +#include + +namespace hal { +namespace ADC { + + using TADCData = std::vector; + + void ReinitADC(TADCData d); + +} // namespace ADC +} // namespace hal diff --git a/tests/unit/modules/buttons/test_buttons.cpp b/tests/unit/modules/buttons/test_buttons.cpp new file mode 100644 index 0000000..21cfbf2 --- /dev/null +++ b/tests/unit/modules/buttons/test_buttons.cpp @@ -0,0 +1,15 @@ +#include "catch2/catch.hpp" +#include "buttons.h" +#include "stub_adc.h" + +using Catch::Matchers::Equals; + +TEST_CASE("buttons::Step", "[buttons]") { + using namespace modules; + + hal::ADC::TADCData d = { 1, 2, 3, 4, 5 }; + hal::ADC::ReinitADC(d); + + Buttons b; + b.Step(); +}