Skip to content

Commit 53c7fc4

Browse files
authored
provide current button state via Keypad::isKeyPressed() (#121)
- **implements `Keypad::isKeyPressed()`** - adds unit test - outsource some test infrastructure to `test/hmi/test_dummies.cpp` such that it can be used by multiple tests - new unit test is in `test/hmi/test_keyState/test_keyState.cpp` Resolves #120
2 parents aa00a98 + 334b9cb commit 53c7fc4

7 files changed

Lines changed: 151 additions & 50 deletions

File tree

lib/3rd_party_adapters/FreeRTOS/debouncedIsr.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,7 +93,7 @@ class Debouncer
9393
*
9494
* Has been determined by measuring the stack high water mark and by experimenting.
9595
*/
96-
static constexpr configSTACK_DEPTH_TYPE stackSize = configMINIMAL_STACK_SIZE + 708;
96+
static constexpr configSTACK_DEPTH_TYPE stackSize = configMINIMAL_STACK_SIZE + 708 + 1'000;
9797

9898
/**
9999
* Triggers the startup delay.

lib/board_adapters/input_device_interface/Keypad.cpp

Lines changed: 36 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
#include "Keypad.hpp"
22
#include "debouncedIsr.hpp"
33
#include <Arduino-wrapper.h>
4+
#include <algorithm>
5+
#include <array>
46
#include <board_pins.hpp>
7+
#include <cassert>
58
#include <chrono>
69
#include <cstddef>
710
#include <functional>
11+
#include <iterator>
12+
#include <optional>
813
#include <utility>
914

1015
#if __has_include(<FunctionalInterrupt.h>) // specific to Arduino-ESP32
@@ -24,6 +29,34 @@ static HmiHandler callBack;
2429
*/
2530
static constexpr auto debouncePeriod = 20ms;
2631

32+
/**
33+
* Maps HMI buttons to events.
34+
*/
35+
static constexpr std::pair<board::PinType, KeyId> selectionForPins[] = {
36+
{board::button::pin::task1, KeyId::TASK1},
37+
{board::button::pin::task2, KeyId::TASK2},
38+
{board::button::pin::task3, KeyId::TASK3},
39+
{board::button::pin::task4, KeyId::TASK4},
40+
{board::button::pin::up, KeyId::LEFT},
41+
{board::button::pin::down, KeyId::RIGHT},
42+
{board::button::pin::enter, KeyId::ENTER},
43+
{board::button::pin::back, KeyId::BACK},
44+
};
45+
46+
static std::array<bool, std::size(selectionForPins)> keyPressedState;
47+
48+
static std::optional<std::size_t> getStateIndex(const KeyId keyId)
49+
{
50+
for (std::size_t index = 0; index < std::size(selectionForPins); ++index)
51+
{
52+
if (selectionForPins[index].second == keyId)
53+
{
54+
return index;
55+
}
56+
}
57+
return std::nullopt;
58+
}
59+
2760
/**
2861
* Reacts on a debounced (stabilized) pin change.
2962
*
@@ -40,22 +73,9 @@ static void reactOnPinChange(const board::PinType pin, KeyId keyId)
4073
{
4174
callBack(keyId);
4275
}
76+
keyPressedState.at(getStateIndex(keyId).value()) = isPressed;
4377
}
4478

45-
/**
46-
* Maps HMI buttons to events.
47-
*/
48-
static constexpr std::pair<board::PinType, KeyId> selectionForPins[] = {
49-
{board::button::pin::task1, KeyId::TASK1},
50-
{board::button::pin::task2, KeyId::TASK2},
51-
{board::button::pin::task3, KeyId::TASK3},
52-
{board::button::pin::task4, KeyId::TASK4},
53-
{board::button::pin::up, KeyId::LEFT},
54-
{board::button::pin::down, KeyId::RIGHT},
55-
{board::button::pin::enter, KeyId::ENTER},
56-
{board::button::pin::back, KeyId::BACK},
57-
};
58-
5979
Keypad::Keypad()
6080
{
6181
// input pins
@@ -73,6 +93,7 @@ Keypad::Keypad()
7393
CHANGE);
7494
index++;
7595
}
96+
std::fill(std::begin(keyPressedState), std::end(keyPressedState), false);
7697
}
7798

7899
void Keypad::setCallback(std::function<void(KeyId)> callbackFunction)
@@ -82,5 +103,5 @@ void Keypad::setCallback(std::function<void(KeyId)> callbackFunction)
82103

83104
bool Keypad::isKeyPressed(const KeyId keyInquiry)
84105
{
85-
return false; //TODO
106+
return keyPressedState.at(getStateIndex(keyInquiry).value());
86107
}

platformio.ini

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,9 @@ debug_test = test_string_helpers
9797

9898
[env:test_native_hmi]
9999
extends = test_native
100-
test_filter = test_hmi
100+
test_filter = hmi/*
101101
lib_deps =
102102
${test_native.lib_deps}
103103
application_business_rules
104104
board_adapters
105+
utilities

test/hmi/test_dummies.cpp

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
#include "test_dummies.hpp"
2+
#include <Arduino-wrapper.h>
3+
#include <board_pins.hpp>
4+
#include <cassert>
5+
#include <input_device_interface/debouncedIsr.hpp>
6+
#include <iomanip>
7+
#include <iostream>
8+
#include <iterator>
9+
10+
using namespace fakeit;
11+
12+
std::map<board::PinType, std::function<void(void)>> isr_collection;
13+
14+
// test dummy for Arduino-ESP32 specific function
15+
void attachInterrupt(const uint8_t interruptNum, const std::function<void(void)> userFunc, const int mode)
16+
{
17+
isr_collection.emplace(interruptNum, userFunc);
18+
std::cout << "Added ISR for interrupt number " << static_cast<unsigned int>(interruptNum)
19+
<< " function pointer " << std::showbase << std::hex << reinterpret_cast<std::intptr_t>(userFunc.target<void (*)(void)>()) << std::resetiosflags(std::ios::showbase | std::ios::basefield) << std::endl;
20+
}
21+
22+
// test dummy for a FreeRTOS adapter function
23+
int debouncer::defaultPriorityToInt()
24+
{
25+
return 0xC0FFE;
26+
}
27+
28+
// test dummy for a FreeRTOS adapter function
29+
std::function<void(void)> createDebouncer(const std::function<void(void)> handler, std::chrono::milliseconds, int)
30+
{
31+
return handler;
32+
}
33+
34+
void changeButtonState(const board::PinType pin)
35+
{
36+
const auto isr = isr_collection.find(pin); // ISR we expect for that pin
37+
assert(isr != std::end(isr_collection)); // assert we found an ISR
38+
std::cout << "trigger ISR for pin " << static_cast<int>(pin) << std::endl;
39+
isr->second(); // trigger interrupt for button
40+
}

test/hmi/test_dummies.hpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#pragma once
2+
#include <board_types.hpp>
3+
#include <functional>
4+
#include <map>
5+
6+
extern std::map<board::PinType, std::function<void(void)>> isr_collection;
7+
8+
/**
9+
* Triggers a interrupt and sets the internal state.
10+
*/
11+
void changeButtonState(board::PinType pin);
Lines changed: 4 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,12 @@
1+
#include "../test_dummies.hpp"
12
#include <Arduino-wrapper.h>
23
#include <algorithm>
34
#include <board_pins.hpp>
4-
#include <board_types.hpp>
55
#include <chrono>
66
#include <cstdint>
77
#include <input_device_interface/debouncedIsr.hpp>
8-
#include <iomanip>
98
#include <ios>
10-
#include <iostream>
119
#include <iterator>
12-
#include <map>
1310
#include <serial_interface/serial_port.hpp>
1411
#include <tasks/Task.hpp>
1512
#include <thread>
@@ -41,8 +38,6 @@ namespace serial_port
4138
std::basic_ostream<CharType> &cout = std::cout;
4239
}
4340

44-
static std::map<board::PinType, std::function<void(void)>> isr_collection;
45-
4641
void setUp()
4742
{
4843
isr_collection.clear();
@@ -52,26 +47,6 @@ void tearDown()
5247
{
5348
}
5449

55-
// test dummy for Arduino-ESP32 specific function
56-
void attachInterrupt(const uint8_t interruptNum, const std::function<void(void)> userFunc, const int mode)
57-
{
58-
isr_collection.emplace(interruptNum, userFunc);
59-
std::cout << "Added ISR for interrupt number " << static_cast<unsigned int>(interruptNum)
60-
<< " function pointer " << std::showbase << std::hex << reinterpret_cast<std::intptr_t>(userFunc.target<void (*)(void)>()) << std::resetiosflags(std::ios::showbase | std::ios::basefield) << std::endl;
61-
}
62-
63-
// test dummy for a FreeRTOS adapter function
64-
std::function<void(void)> createDebouncer(const std::function<void(void)> handler, std::chrono::milliseconds, int)
65-
{
66-
return handler;
67-
}
68-
69-
// test dummy for a FreeRTOS adapter function
70-
int debouncer::defaultPriorityToInt()
71-
{
72-
return 0xC0FFE;
73-
}
74-
7550
void test_Controller()
7651
{
7752
// irrelevant test doubles
@@ -83,13 +58,10 @@ void test_Controller()
8358
Menu singleMenu(board::getDisplay());
8459
Presenter presenter(singleMenu, board::getStatusIndicators());
8560
ProcessHmiInputs processor(presenter, board::getKeypad());
86-
auto &task1 = std::begin(device::tasks)->second; // we are going to test for task 1
87-
const auto isrTask1 = isr_collection.find(board::button::pin::task1); // ISR we expect for task 1
88-
TEST_ASSERT_NOT_EQUAL(std::end(isr_collection), isrTask1); // assert we found an ISR for task 1 in the list
61+
auto &task1 = std::begin(device::tasks)->second; // we are going to test for task 1
8962

90-
std::cout << "trigger ISR for task 1: 'start task'" << std::endl;
9163
When(Method(ArduinoFake(), digitalRead).Using(board::button::pin::task1)).Return(LOW); // set task 1 button to low
92-
isrTask1->second(); // trigger interrupt for task 1 button
64+
changeButtonState(board::button::pin::task1);
9365

9466
// wait for the task to be running
9567
while (!task1.isRunning())
@@ -100,9 +72,8 @@ void test_Controller()
10072
constexpr int millisecondsToWait = 1000;
10173
std::this_thread::sleep_for(std::chrono::milliseconds(millisecondsToWait)); // wait a defined time
10274

103-
std::cout << "trigger ISR for task 1: 'stop task'" << std::endl;
10475
When(Method(ArduinoFake(), digitalRead).Using(board::button::pin::task1)).Return(LOW); // set task 1 button to low
105-
isrTask1->second(); // stop task
76+
changeButtonState(board::button::pin::task1); // stop task
10677

10778
// wait for the task to be stopped
10879
while (task1.isRunning())
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
#include "../test_dummies.hpp"
2+
#include <Arduino-wrapper.h>
3+
#include <board_pins.hpp>
4+
#include <input_device_interface/Keypad.hpp>
5+
#include <iostream>
6+
#include <unity.h>
7+
8+
using namespace fakeit;
9+
10+
static void dummyCallback(const KeyId id)
11+
{
12+
std::cout << "dummy callback has been called with key " << id << std::endl;
13+
}
14+
15+
void setUp(void)
16+
{
17+
isr_collection.clear();
18+
}
19+
20+
void tearDown(void)
21+
{
22+
}
23+
24+
void test_default_inactive()
25+
{
26+
Keypad keypad;
27+
TEST_ASSERT_FALSE(keypad.isKeyPressed(KeyId::TASK1));
28+
}
29+
30+
void test_switch_on_off()
31+
{
32+
Keypad keypad;
33+
keypad.setCallback(dummyCallback);
34+
35+
// set & test "active"
36+
When(Method(ArduinoFake(), digitalRead).Using(board::button::pin::task1)).Return(LOW); // set task 1 button to low
37+
changeButtonState(board::button::pin::task1); // stop task
38+
TEST_ASSERT_TRUE(keypad.isKeyPressed(KeyId::TASK1));
39+
40+
// set & test "inactive"
41+
When(Method(ArduinoFake(), digitalRead).Using(board::button::pin::task1)).Return(HIGH); // set task 1 button to high
42+
changeButtonState(board::button::pin::task1); // stop task
43+
TEST_ASSERT_FALSE(keypad.isKeyPressed(KeyId::TASK1));
44+
}
45+
46+
int main()
47+
{
48+
// irrelevant test doubles
49+
Fake(Method(ArduinoFake(), pinMode));
50+
51+
UNITY_BEGIN();
52+
53+
RUN_TEST(test_default_inactive);
54+
RUN_TEST(test_switch_on_off);
55+
56+
return UNITY_END();
57+
}

0 commit comments

Comments
 (0)