diff --git a/lib/Cross/Gun/Atmega328pHal.cpp b/lib/Cross/Gun/Atmega328pHal.cpp index 5e59b10..16121bd 100644 --- a/lib/Cross/Gun/Atmega328pHal.cpp +++ b/lib/Cross/Gun/Atmega328pHal.cpp @@ -26,20 +26,21 @@ #define VIBRATOR_PIN 6 #define BATTERY_VOLTAGE_PIN A3 #define CHARGING_STATE_PIN A2 -#define BUTTON2_PIN 3 +#define BUTTON_PIN 3 #define TRIGGER_PIN 2 #define MIN_BAT_VOLTAGE 3000 #define MAX_BAT_VOLTAGE 4120 Atmega328pHal::Atmega328pHal() { - pinMode(VIBRATOR_PIN, OUTPUT); pinMode(LASER_PIN, OUTPUT); + pinMode(TRIGGER_PIN, INPUT_PULLUP); + pinMode(BUTTON_PIN, INPUT_PULLUP); } bool Atmega328pHal::triggerIsUp() { return bit_is_set(PIND, PD2); } -bool Atmega328pHal::buttonIsUp() { return bit_is_set(PIND, PD3); } +bool Atmega328pHal::buttonIsUp() { return bit_is_clear(PIND, PD3); } /* * the 'loop' method shall be called each 10ms @@ -89,17 +90,14 @@ void Atmega328pHal::sleep() { USART0_OFF, TWI_OFF); } -void Atmega328pHal::setGun(Gun *gun) { gun = gun; } +void Atmega328pHal::setGun(Gun *gun) { this->gun = gun; } extern void buttonInterruptHandler(); -void Atmega328pHal::configureInputCallbacks() { +extern void triggerInterruptHandler(); - pinMode(BUTTON2_PIN, INPUT_PULLUP); - attachInterrupt(digitalPinToInterrupt(BUTTON2_PIN), buttonInterruptHandler, +void Atmega328pHal::configureInputCallbacks() { + attachInterrupt(digitalPinToInterrupt(BUTTON_PIN), buttonInterruptHandler, CHANGE); - - extern void triggerInterruptHandler(); - pinMode(TRIGGER_PIN, INPUT_PULLUP); attachInterrupt(digitalPinToInterrupt(TRIGGER_PIN), triggerInterruptHandler, CHANGE); } \ No newline at end of file diff --git a/lib/Cross/Gun/SSD1306Ui.hpp b/lib/Cross/Gun/SSD1306Ui.hpp index 7920620..6fd6b28 100644 --- a/lib/Cross/Gun/SSD1306Ui.hpp +++ b/lib/Cross/Gun/SSD1306Ui.hpp @@ -95,13 +95,13 @@ class SSD1306Ui : public IGunUi { } void clearCalibration() override { - display.fillRect(2, 10, 126, 14, 0); // clear + display.fillRect(2, 10, 126, 22, 0); // clear } void displayCalibration() override { display.clearDisplay(); - display.setCursor(2, 25); display.setFont(&FreeMonoOblique9pt7b); + display.setCursor(2, 25); display.print("Calibration"); display.display(); } diff --git a/src/GunApp.cpp b/src/GunApp.cpp index fa32e66..5e195ec 100644 --- a/src/GunApp.cpp +++ b/src/GunApp.cpp @@ -23,27 +23,31 @@ SSD1306Ui ui; Atmega328pHal hal; Gun gun(&hal, &ui); -volatile bool tick = false; -ISR(TIMER2_COMPA_vect) { tick = true; } +volatile bool applicativeEvent = false; +ISR(TIMER2_COMPA_vect) { applicativeEvent = true; } volatile Contactor::Event pendingTriggerEvent; void triggerInterruptHandler() { - if (hal.triggerIsUp()) { - pendingTriggerEvent = Contactor::Event::Released; - } else { - pendingTriggerEvent = Contactor::Event::Pressed; + if (Contactor::Event::NoEvent == pendingTriggerEvent) { + if (hal.triggerIsUp()) { + pendingTriggerEvent = Contactor::Event::Released; + } else { + pendingTriggerEvent = Contactor::Event::Pressed; + } + applicativeEvent = true; } - tick = true; } volatile Contactor::Event pendingButtonEvent; void buttonInterruptHandler() { - if (hal.buttonIsUp()) { - pendingButtonEvent = Contactor::Event::Released; - } else { - pendingButtonEvent = Contactor::Event::Pressed; + if (Contactor::Event::NoEvent == pendingButtonEvent) { + if (hal.buttonIsUp()) { + pendingButtonEvent = Contactor::Event::Released; + } else { + pendingButtonEvent = Contactor::Event::Pressed; + } + applicativeEvent = true; } - tick = true; } void loop(void) { @@ -53,16 +57,19 @@ void loop(void) { // and counter1, used internally by the Arduino // framework. Avoid processing these wakeups as // applicative events using 'tick' control variable. - - if (tick) { + + if (applicativeEvent) { + applicativeEvent = false; + // wire interrupt-based events with main code gun.trigger.pendingEvent = pendingTriggerEvent; gun.button.pendingEvent = pendingButtonEvent; + + gun.loop(); + pendingTriggerEvent = Contactor::Event::NoEvent; pendingButtonEvent = Contactor::Event::NoEvent; - gun.loop(); - tick = false; hal.sleep(); } } diff --git a/test/native/test_gun/gun.cpp b/test/native/test_gun/gun.cpp index 63fa00d..4ecc02b 100644 --- a/test/native/test_gun/gun.cpp +++ b/test/native/test_gun/gun.cpp @@ -191,12 +191,43 @@ void expect_trigger_to_have_no_effect_in_calibration_mode() { Verify(Method(mockHal, laserOff)).Exactly(0); } +void expect_long_press_to_trigger_only_if_button_is_down() { + Mock mockUi; + Mock mockHal; + + MOCK_ALL(); + + IGunUi &ui = mockUi.get(); + IGunHal &hal = mockHal.get(); + + Gun gun(&hal, &ui); + + gun.button.pendingEvent = Contactor::Event::Pressed; + gun.loop(); + + gun.button.pendingEvent = Contactor::Event::Released; + gun.loop(); + + for (uint8_t tickCounter = 0; tickCounter <= 200; tickCounter++) { + // long press shall be accounted after 2s, 200 ticks + gun.loop(); + } + + // No long press, no switch to calibration + Verify(Method(mockHal, laserOn)).Exactly(0); + Verify(Method(mockUi, displayCalibration)).Exactly(0); + Verify(Method(mockHal, laserOff)).Exactly(0); + Verify(Method(mockUi, clearCalibration)).Exactly(0); + 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_at_boot_and_each_1s); RUN_TEST(expect_switch_to_maintenance_after_2s_button_continuous_press); + RUN_TEST(expect_long_press_to_trigger_only_if_button_is_down); RUN_TEST(expect_button_press_to_reset_shoot_count_and_redisplay); RUN_TEST(expect_trigger_to_have_no_effect_in_calibration_mode);