From 16ebfffca7fefa41137a73b415a6c49677774e08 Mon Sep 17 00:00:00 2001 From: Aurelien Labrosse Date: Thu, 23 Nov 2023 12:54:02 +0000 Subject: [PATCH] Added test for calibration mode --- lib/Cross/Gun/SSD1306Ui.hpp | 12 ++++- lib/Domain/Contactor.cpp | 2 +- lib/Domain/Gun/Gun.cpp | 69 ++++++++++++------------- lib/Domain/Gun/Gun.hpp | 6 ++- lib/Domain/Gun/IGunUi.hpp | 1 + platformio.ini | 2 +- test/native/test_gun/gun.cpp | 99 +++++++++++++++++++++--------------- 7 files changed, 106 insertions(+), 85 deletions(-) diff --git a/lib/Cross/Gun/SSD1306Ui.hpp b/lib/Cross/Gun/SSD1306Ui.hpp index 5783195..e0d1b1d 100644 --- a/lib/Cross/Gun/SSD1306Ui.hpp +++ b/lib/Cross/Gun/SSD1306Ui.hpp @@ -38,13 +38,13 @@ class SSD1306Ui : public IGunUi { public: SSD1306Ui() {} - void setup() override{ + void setup() override { if (!display.begin(SSD1306_SWITCHCAPVCC, SCREEN_ADDRESS)) { for (;;) ; // Don't proceed, loop forever } } - + void displaySplash(uint16_t timeoutMs) override { display.clearDisplay(); display.setTextColor(WHITE); @@ -93,4 +93,12 @@ class SSD1306Ui : public IGunUi { display.print(count); display.display(); } + + void displayCalibration() override { + display.fillRect(11, 0, 68, 30, 0); // clear + display.setCursor(15, 25); + display.setFont(&FreeMonoOblique9pt7b); + display.print("Calibration"); + display.display(); + } }; \ No newline at end of file diff --git a/lib/Domain/Contactor.cpp b/lib/Domain/Contactor.cpp index f2908df..3f6706b 100644 --- a/lib/Domain/Contactor.cpp +++ b/lib/Domain/Contactor.cpp @@ -18,7 +18,7 @@ #include void Contactor::checkForLongPress(long now) { - if ((downStartTime > 0) && ((now - downStartTime) > LONG_PRESS)) { + if ((downStartTime > 0) && ((now - downStartTime) >= LONG_PRESS)) { downStartTime = 0; onLongPress(); } diff --git a/lib/Domain/Gun/Gun.cpp b/lib/Domain/Gun/Gun.cpp index 6e9e3d3..e258046 100644 --- a/lib/Domain/Gun/Gun.cpp +++ b/lib/Domain/Gun/Gun.cpp @@ -18,22 +18,32 @@ #define TICKS_BETWEEN_BATTERY_UI_UPDATE 100 -// counter for ticks between battery display update -uint16_t updateBatteryDisplayCycleCount; - -long now = 0; - Gun::Gun(IGunHal *hal, IGunUi *ui) { this->hal = hal; this->ui = ui; calibrationMode = false; shootCount = 0; + + // display at first loop shootCycleCountdown = 0; + batteryDisplayCycleCountdown = 0; button.setGun(this); trigger.setGun(this); } +void Gun::toggleCalibrationMode() { + calibrationMode = !calibrationMode; + if (calibrationMode) { + hal->laserOn(); + hal->vibrationOff(); + ui->displayCalibration(); + } else { + hal->laserOff(); + ui->displayShootCount(shootCount); + } +} + void Gun::activateShoot() { if (shootCycleCountdown == 0) { shootCount += 1; @@ -48,50 +58,35 @@ void Gun::activateShoot() { void Gun::loop(void) { // 10ms per loop thanks to timer2 - now += 10; + millisSinceStart += 10; - trigger.processPendingEvent(now); - button.processPendingEvent(now); - - button.checkForLongPress(now); - - if (calibrationMode) { - hal->laserOn(); - hal->vibrationOff(); + trigger.processPendingEvent(millisSinceStart); + button.processPendingEvent(millisSinceStart); - } else { + button.checkForLongPress(millisSinceStart); - if (shootCycleCountdown > 0) { + if (shootCycleCountdown > 0) { + shootCycleCountdown--; + if (shootCycleCountdown == 1) { + hal->laserOff(); + hal->vibrationOff(); + ui->displayShootCount(shootCount); shootCycleCountdown--; - if (shootCycleCountdown == 1) { - hal->laserOff(); - hal->vibrationOff(); - ui->displayShootCount(shootCount); - shootCycleCountdown--; - } - } - - if (updateBatteryDisplayCycleCount > 0) { - updateBatteryDisplayCycleCount--; - } - if (updateBatteryDisplayCycleCount == 0) { - ui->displayBatteryStatus(hal->getBatteryVoltageMv(), - hal->getBatteryVoltagePercent()); - updateBatteryDisplayCycleCount = TICKS_BETWEEN_BATTERY_UI_UPDATE; } } + if (batteryDisplayCycleCountdown > 0) { + batteryDisplayCycleCountdown--; + } else { + ui->displayBatteryStatus(hal->getBatteryVoltageMv(), + hal->getBatteryVoltagePercent()); + batteryDisplayCycleCountdown = TICKS_BETWEEN_BATTERY_UI_UPDATE; + } hal->sleep(); } void Gun::setup(void) { - - shootCount = 0; - updateBatteryDisplayCycleCount = TICKS_BETWEEN_BATTERY_UI_UPDATE; - ui->displaySplash(2000); - // mV is not used ui->displayBatteryStatus(0, hal->getBatteryVoltagePercent()); - ui->displayShootCount(0); } \ No newline at end of file diff --git a/lib/Domain/Gun/Gun.hpp b/lib/Domain/Gun/Gun.hpp index 53e61c2..b0ff0df 100644 --- a/lib/Domain/Gun/Gun.hpp +++ b/lib/Domain/Gun/Gun.hpp @@ -25,6 +25,9 @@ class Gun { uint8_t shootCycleCountdown; + uint16_t batteryDisplayCycleCountdown; + long millisSinceStart = 0; + bool calibrationMode; public: /* 50 ms */ @@ -34,14 +37,13 @@ class Gun { IGunUi *ui; Button button; Trigger trigger; - bool calibrationMode; uint16_t shootCount; Gun(IGunHal *hal, IGunUi *ui); void activateShoot(); - void toggleCalibrationMode() { calibrationMode = !calibrationMode; } + void toggleCalibrationMode(); /** * @brief Gun loop shall be called at least each 10ms, diff --git a/lib/Domain/Gun/IGunUi.hpp b/lib/Domain/Gun/IGunUi.hpp index 30e500d..c66510a 100644 --- a/lib/Domain/Gun/IGunUi.hpp +++ b/lib/Domain/Gun/IGunUi.hpp @@ -26,4 +26,5 @@ class IGunUi { virtual void displayBatteryStatus(uint16_t mv, uint8_t percent) = 0; virtual void displayChargingStatus(bool isCharging) = 0; virtual void displayShootCount(uint16_t shootCount) = 0; + virtual void displayCalibration() = 0; }; \ No newline at end of file diff --git a/platformio.ini b/platformio.ini index 3998c70..4a04cbc 100755 --- a/platformio.ini +++ b/platformio.ini @@ -51,7 +51,7 @@ upload_command = avrdude -vv -b57600 -pm328p -c avrisp -Pcom9 $UPLOAD_FLAGS -U f build_type = debug debug_build_flags = -Og -ggdb3 -g3 -DNATIVE test_ignore = cross/* - debug_test = noarch/test_contactor + debug_test = native/test_gun build_src_filter = ${env.src_filter} - - [env:cross] diff --git a/test/native/test_gun/gun.cpp b/test/native/test_gun/gun.cpp index 12cb2b0..6b98ea7 100644 --- a/test/native/test_gun/gun.cpp +++ b/test/native/test_gun/gun.cpp @@ -24,6 +24,21 @@ #include using namespace fakeit; +#define MOCK_ALL() \ + When(Method(mockHal, triggerIsUp)).AlwaysReturn(true); \ + When(Method(mockHal, buttonIsUp)).AlwaysReturn(true); \ + When(Method(mockHal, laserOn)).AlwaysReturn(); \ + When(Method(mockHal, vibrationOn)).AlwaysReturn(); \ + When(Method(mockHal, vibrationOff)).AlwaysReturn(); \ + When(Method(mockHal, laserOff)).AlwaysReturn(); \ + When(Method(mockHal, getBatteryVoltageMv)).AlwaysReturn(5000U); \ + When(Method(mockHal, getBatteryVoltagePercent)).AlwaysReturn(100U); \ + When(Method(mockHal, sleep)).AlwaysReturn(); \ + When(Method(mockUi, displayBatteryStatus)).AlwaysReturn(); \ + When(Method(mockUi, displayShootCount)).AlwaysReturn(); \ + When(Method(mockUi, displayCalibration)).AlwaysReturn(); \ + When(Method(mockUi, displaySplash)).AlwaysReturn(); + void tearDown() {} void setUp() { ArduinoFakeReset(); } @@ -32,17 +47,7 @@ void expect_gun_to_loop() { Mock mockUi; Mock mockHal; - When(Method(mockHal, triggerIsUp)).AlwaysReturn(true); - When(Method(mockHal, buttonIsUp)).AlwaysReturn(true); - When(Method(mockHal, laserOn)).AlwaysReturn(); - When(Method(mockHal, vibrationOn)).AlwaysReturn(); - When(Method(mockHal, vibrationOff)).AlwaysReturn(); - When(Method(mockHal, laserOff)).AlwaysReturn(); - When(Method(mockHal, getBatteryVoltageMv)).AlwaysReturn(5000); - When(Method(mockHal, getBatteryVoltagePercent)).AlwaysReturn(100); - When(Method(mockHal, sleep)).AlwaysReturn(); - When(Method(mockUi, displayBatteryStatus)).AlwaysReturn(); - When(Method(mockUi, displayShootCount)).AlwaysReturn(); + MOCK_ALL(); IGunUi &ui = mockUi.get(); IGunHal &hal = mockHal.get(); @@ -51,23 +56,12 @@ void expect_gun_to_loop() { gun.loop(); } - void expect_gun_to_shoot_50ms_on_trigger_down() { Mock mockUi; Mock mockHal; - When(Method(mockHal, triggerIsUp)).AlwaysReturn(true); - When(Method(mockHal, buttonIsUp)).AlwaysReturn(true); - When(Method(mockHal, laserOn)).AlwaysReturn(); - When(Method(mockHal, vibrationOn)).AlwaysReturn(); - When(Method(mockHal, vibrationOff)).AlwaysReturn(); - When(Method(mockHal, laserOff)).AlwaysReturn(); - When(Method(mockHal, getBatteryVoltageMv)).AlwaysReturn(5000); - When(Method(mockHal, getBatteryVoltagePercent)).AlwaysReturn(100); - When(Method(mockHal, sleep)).AlwaysReturn(); - When(Method(mockUi, displayBatteryStatus)).AlwaysReturn(); - When(Method(mockUi, displayShootCount)).AlwaysReturn(); + MOCK_ALL(); IGunUi &ui = mockUi.get(); IGunHal &hal = mockHal.get(); @@ -93,45 +87,66 @@ void expect_gun_to_shoot_50ms_on_trigger_down() { Verify(Method(mockHal, laserOff)).Once(); Verify(Method(mockHal, sleep)).Exactly(7); } - -void expect_ui_to_display_battery_state_each_1s() { +void expect_ui_to_display_battery_state_at_boot_and_each_1s() { Mock mockUi; Mock mockHal; - When(Method(mockHal, triggerIsUp)).AlwaysReturn(true); - When(Method(mockHal, buttonIsUp)).AlwaysReturn(true); - When(Method(mockHal, laserOn)).AlwaysReturn(); - When(Method(mockHal, vibrationOn)).AlwaysReturn(); - When(Method(mockHal, vibrationOff)).AlwaysReturn(); - When(Method(mockHal, laserOff)).AlwaysReturn(); - When(Method(mockHal, getBatteryVoltageMv)).AlwaysReturn(5000U); - When(Method(mockHal, getBatteryVoltagePercent)).AlwaysReturn(100U); - When(Method(mockHal, sleep)).AlwaysReturn(); - When(Method(mockUi, displayBatteryStatus)).AlwaysReturn(); - When(Method(mockUi, displayShootCount)).AlwaysReturn(); - When(Method(mockUi, displaySplash)).AlwaysReturn(); + MOCK_ALL(); IGunUi &ui = mockUi.get(); IGunHal &hal = mockHal.get(); Gun gun(&hal, &ui); - // displayBatteryStatus first call - gun.setup(); - - for (uint8_t tickCounter = 0; tickCounter < 100; tickCounter++) { + for (uint8_t tickCounter = 0; tickCounter <= 101; tickCounter++) { // displayBatteryStatus call after 100 ticks gun.loop(); } + // display at first loop, then each second (or 100 ticks) Verify(Method(mockUi, displayBatteryStatus)).Exactly(2); } +void expect_switch_to_maintenance_after_2s_button_continuous_press() { + Mock mockUi; + Mock mockHal; + + MOCK_ALL(); + + IGunUi &ui = mockUi.get(); + IGunHal &hal = mockHal.get(); + + Gun gun(&hal, &ui); + + gun.button.pendingEvent = Contactor::Event::Pressed; + for (uint8_t tickCounter = 0; tickCounter <= 200; tickCounter++) { + // long press shall be accounted after 2s, 200 ticks + gun.loop(); + } + gun.button.pendingEvent = Contactor::Event::Released; + gun.loop(); + gun.button.pendingEvent = Contactor::Event::Pressed; + for (uint8_t tickCounter = 0; tickCounter <= 200; tickCounter++) { + // long press shall be accounted after 2s, 200 ticks + gun.loop(); + } + + // switch to calibration + Verify(Method(mockHal, laserOn)).Exactly(1); + Verify(Method(mockUi, displayCalibration)).Exactly(1); + + // back to normal + Verify(Method(mockHal, laserOff)).Exactly(1); + Verify(Method(mockUi, displayShootCount)).Exactly(1); +} + int main(int, char **) { UNITY_BEGIN(); RUN_TEST(expect_gun_to_loop); RUN_TEST(expect_gun_to_shoot_50ms_on_trigger_down); - RUN_TEST(expect_ui_to_display_battery_state_each_1s); + RUN_TEST(expect_ui_to_display_battery_state_at_boot_and_each_1s); + RUN_TEST(expect_switch_to_maintenance_after_2s_button_continuous_press); + UNITY_END(); return 0; }