From cb57951b573fa8eea9154ee7fc4ec4fe328440c2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Niccol=C3=B2=20Betto?= <niccolo.betto@skywarder.eu> Date: Wed, 19 Mar 2025 00:42:35 +0100 Subject: [PATCH] [ConRIG][ConRIGv2] Update button handling code to avoid spurious disarming --- src/ConRIG/Buttons/Buttons.cpp | 155 +++++--------------- src/ConRIG/Buttons/Buttons.h | 9 +- src/ConRIG/Radio/Radio.cpp | 28 ++-- src/ConRIG/Radio/Radio.h | 10 +- src/ConRIGv2/Buttons/Buttons.cpp | 233 ++++++------------------------- src/ConRIGv2/Buttons/Buttons.h | 9 +- src/ConRIGv2/Radio/Radio.cpp | 30 ++-- src/ConRIGv2/Radio/Radio.h | 8 +- 8 files changed, 127 insertions(+), 355 deletions(-) diff --git a/src/ConRIG/Buttons/Buttons.cpp b/src/ConRIG/Buttons/Buttons.cpp index 8390a9494..c4b5a98d1 100644 --- a/src/ConRIG/Buttons/Buttons.cpp +++ b/src/ConRIG/Buttons/Buttons.cpp @@ -32,11 +32,10 @@ using namespace miosix; using namespace Boardcore; using namespace ConRIG; -Buttons::Buttons() : state() {} - bool Buttons::start() { - TaskScheduler& scheduler = getModule<BoardScheduler>()->getRadioScheduler(); + TaskScheduler& scheduler = + getModule<BoardScheduler>()->getButtonsScheduler(); return scheduler.addTask([this]() { periodicStatusCheck(); }, Config::Buttons::BUTTON_SAMPLE_PERIOD) != 0; @@ -44,131 +43,43 @@ bool Buttons::start() mavlink_conrig_state_tc_t Buttons::getState() { return state; } -void Buttons::resetState() -{ - // Preserve the arm switch state - auto armSwitch = state.arm_switch; - state = {}; - state.arm_switch = armSwitch; -} - void Buttons::periodicStatusCheck() { +#define CHECK_BUTTON(cond, btn) \ + if (cond) \ + { \ + if (guard.btn > Config::Buttons::GUARD_THRESHOLD) \ + { \ + guard.btn = 0; \ + state.btn = true; \ + LOG_DEBUG(logger, #btn " button pressed"); \ + } \ + else \ + { \ + guard.btn++; \ + } \ + } \ + else \ + { \ + guard.btn = 0; \ + state.btn = false; \ + } + state.arm_switch = btns::arm::value(); - if (!btns::ignition::value() && state.arm_switch) - { - if (guard > Config::Buttons::GUARD_THRESHOLD) - { - guard = 0; - state.ignition_btn = true; - LOG_DEBUG(logger, "Ignition button pressed"); - } - else - { - guard++; - } - } - else if (btns::n2o_filling::value()) - { - if (guard > Config::Buttons::GUARD_THRESHOLD) - { - guard = 0; - state.ox_filling_btn = true; - LOG_DEBUG(logger, "ox filling button pressed"); - } - else - { - guard++; - } - } - else if (btns::n2o_release::value()) - { - if (guard > Config::Buttons::GUARD_THRESHOLD) - { - guard = 0; - state.ox_release_btn = true; - LOG_DEBUG(logger, "ox release button pressed"); - } - else - { - guard++; - } - } - else if (btns::n2_release::value()) - { - if (guard > Config::Buttons::GUARD_THRESHOLD) - { - guard = 0; - state.n2_release_btn = true; - LOG_DEBUG(logger, "n2 release button pressed"); - } - else - { - guard++; - } - } - else if (btns::n2o_venting::value()) - { - if (guard > Config::Buttons::GUARD_THRESHOLD) - { - guard = 0; - state.ox_venting_btn = true; - LOG_DEBUG(logger, "ox venting button pressed"); - } - else - { - guard++; - } - } - else if (btns::n2_detach::value()) - { - if (guard > Config::Buttons::GUARD_THRESHOLD) - { - guard = 0; - state.n2_detach_btn = true; - LOG_DEBUG(logger, "n2 detach button pressed"); - } - else - { - guard++; - } - } - else if (btns::n2_filling::value()) - { - if (guard > Config::Buttons::GUARD_THRESHOLD) - { - guard = 0; - state.n2_filling_btn = true; - LOG_DEBUG(logger, "n2 filling button pressed"); - } - else - { - guard++; - } - } - else if (btns::nitrogen::value()) - { - if (guard > Config::Buttons::GUARD_THRESHOLD) - { - guard = 0; - state.nitrogen_btn = true; - LOG_DEBUG(logger, "nitrogen button pressed"); - } - else - { - guard++; - } - } - else - { - // Reset all the states and guard - guard = 0; - resetState(); - } + CHECK_BUTTON(!btns::ignition::value() && state.arm_switch, ignition_btn); + CHECK_BUTTON(btns::n2o_filling::value(), ox_filling_btn); + CHECK_BUTTON(btns::n2o_release::value(), ox_release_btn); + CHECK_BUTTON(btns::n2_release::value(), n2_release_btn); + CHECK_BUTTON(btns::n2o_venting::value(), ox_venting_btn); + CHECK_BUTTON(btns::n2_detach::value(), n2_detach_btn); + CHECK_BUTTON(btns::n2_filling::value(), n2_filling_btn); + CHECK_BUTTON(btns::nitrogen::value(), nitrogen_btn); + +#undef CHECK_BUTTON // Set the internal button state in Radio module - getModule<Radio>()->setButtonsState(state); + getModule<Radio>()->updateButtonState(state); } void Buttons::enableIgnition() { ui::armedLed::high(); } diff --git a/src/ConRIG/Buttons/Buttons.h b/src/ConRIG/Buttons/Buttons.h index ecd160f2f..2d6fff4ae 100644 --- a/src/ConRIG/Buttons/Buttons.h +++ b/src/ConRIG/Buttons/Buttons.h @@ -36,8 +36,6 @@ class Radio; class Buttons : public Boardcore::InjectableWithDeps<BoardScheduler, Radio> { public: - Buttons(); - [[nodiscard]] bool start(); mavlink_conrig_state_tc_t getState(); @@ -46,14 +44,11 @@ public: void disableIgnition(); private: - void resetState(); - void periodicStatusCheck(); - mavlink_conrig_state_tc_t state; - + mavlink_conrig_state_tc_t state{}; // Counter guard to avoid spurious triggers - uint8_t guard = 0; + mavlink_conrig_state_tc_t guard{}; Boardcore::PrintLogger logger = Boardcore::Logging::getLogger("buttons"); }; diff --git a/src/ConRIG/Radio/Radio.cpp b/src/ConRIG/Radio/Radio.cpp index f6b4807cb..cb88b002b 100644 --- a/src/ConRIG/Radio/Radio.cpp +++ b/src/ConRIG/Radio/Radio.cpp @@ -80,9 +80,8 @@ void Radio::handleMessage(const mavlink_message_t& msg) // we assume this ack is about the last sent message if (id == MAVLINK_MSG_ID_CONRIG_STATE_TC) { - Lock<FastMutex> lock{buttonsMutex}; // Reset the internal button state - buttonState = {}; + resetButtonState(); } break; @@ -156,11 +155,11 @@ void Radio::loopBuzzer() } } -void Radio::setButtonsState(mavlink_conrig_state_tc_t state) +void Radio::updateButtonState(const mavlink_conrig_state_tc_t& state) { Lock<FastMutex> lock{buttonsMutex}; - // The OR operator is introduced to make sure that the receiver - // understood the command + // Merge the new state with the old one, an extra-dumb way to ensure + // that we don't lose any button pressess buttonState.ox_filling_btn |= state.ox_filling_btn; buttonState.ox_release_btn |= state.ox_release_btn; buttonState.n2_filling_btn |= state.n2_filling_btn; @@ -170,11 +169,24 @@ void Radio::setButtonsState(mavlink_conrig_state_tc_t state) buttonState.nitrogen_btn |= state.nitrogen_btn; buttonState.ox_detach_btn |= state.ox_detach_btn; buttonState.n2_quenching_btn |= state.n2_quenching_btn; - buttonState.n2_3way_btn |= state.n2_3way_btn; buttonState.tars3_btn |= state.tars3_btn; buttonState.tars3m_btn |= state.tars3m_btn; buttonState.ignition_btn |= state.ignition_btn; - buttonState.arm_switch |= state.arm_switch; + + // Don't merge lever states + buttonState.n2_3way_btn = state.n2_3way_btn; + buttonState.arm_switch = state.arm_switch; +} + +void Radio::resetButtonState() +{ + Lock<FastMutex> lock{buttonsMutex}; + // Save and restore lever states + auto n2_3way_btn = buttonState.n2_3way_btn; + auto arm_switch = buttonState.arm_switch; + buttonState = {}; + buttonState.n2_3way_btn = n2_3way_btn; + buttonState.arm_switch = arm_switch; } bool Radio::start() @@ -229,5 +241,3 @@ bool Radio::start() } MavlinkStatus Radio::getMavlinkStatus() { return mavDriver->getStatus(); } - -Radio::Radio() : buttonState() {} diff --git a/src/ConRIG/Radio/Radio.h b/src/ConRIG/Radio/Radio.h index f9d5edb29..949df5f99 100644 --- a/src/ConRIG/Radio/Radio.h +++ b/src/ConRIG/Radio/Radio.h @@ -49,13 +49,11 @@ class Radio : public Boardcore::InjectableWithDeps<Buses, BoardScheduler, Buttons, Serial> { public: - Radio(); - [[nodiscard]] bool start(); Boardcore::MavlinkStatus getMavlinkStatus(); - void setButtonsState(mavlink_conrig_state_tc_t state); + void updateButtonState(const mavlink_conrig_state_tc_t& state); bool enqueueMessage(const mavlink_message_t& msg); @@ -64,6 +62,8 @@ private: void loopBuzzer(); void handleMessage(const mavlink_message_t& msg); + void resetButtonState(); + std::unique_ptr<Boardcore::SX1278Lora> radio; std::unique_ptr<MavDriver> mavDriver; @@ -72,10 +72,10 @@ private: messageQueue; miosix::FastMutex queueMutex; - miosix::FastMutex buttonsMutex; // Button internal state - mavlink_conrig_state_tc_t buttonState; + miosix::FastMutex buttonsMutex; + mavlink_conrig_state_tc_t buttonState{}; std::thread buzzerLooper; diff --git a/src/ConRIGv2/Buttons/Buttons.cpp b/src/ConRIGv2/Buttons/Buttons.cpp index e7056ab79..f30478643 100644 --- a/src/ConRIGv2/Buttons/Buttons.cpp +++ b/src/ConRIGv2/Buttons/Buttons.cpp @@ -1,5 +1,5 @@ /* Copyright (c) 2025 Skyward Experimental Rocketry - * Author: Ettore Pane + * Authors: Ettore Pane, Niccolò Betto * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -32,15 +32,10 @@ using namespace miosix; using namespace Boardcore; using namespace ConRIGv2; -Buttons::Buttons() -{ - resetState(); - state.arm_switch = false; -} - bool Buttons::start() { - TaskScheduler& scheduler = getModule<BoardScheduler>()->getRadioScheduler(); + TaskScheduler& scheduler = + getModule<BoardScheduler>()->getButtonsScheduler(); return scheduler.addTask([this]() { periodicStatusCheck(); }, Config::Buttons::BUTTON_SAMPLE_PERIOD) != 0; @@ -48,196 +43,48 @@ bool Buttons::start() mavlink_conrig_state_tc_t Buttons::getState() { return state; } -void Buttons::resetState() -{ - // Preserve the arm switch state - auto armSwitch = state.arm_switch; - state = {}; - state.arm_switch = armSwitch; -} - void Buttons::periodicStatusCheck() { - state.arm_switch = btns::arm::value(); - - if (!btns::ignition::value() && state.arm_switch) - { - if (guard > Config::Buttons::GUARD_THRESHOLD) - { - guard = 0; - state.ignition_btn = true; - LOG_DEBUG(logger, "Ignition button pressed"); - } - else - { - guard++; - } - } - else if (btns::ox_filling::value()) - { - if (guard > Config::Buttons::GUARD_THRESHOLD) - { - guard = 0; - state.ox_filling_btn = true; - LOG_DEBUG(logger, "Ox filling button pressed"); - } - else - { - guard++; - } - } - else if (btns::ox_release::value()) - { - if (guard > Config::Buttons::GUARD_THRESHOLD) - { - guard = 0; - state.ox_release_btn = true; - LOG_DEBUG(logger, "Ox release button pressed"); - } - else - { - guard++; - } - } - else if (btns::ox_detach::value()) - { - if (guard > Config::Buttons::GUARD_THRESHOLD) - { - guard = 0; - state.ox_detach_btn = true; - LOG_DEBUG(logger, "Ox detach button pressed"); - } - else - { - guard++; - } - } - else if (btns::n2_3way::value()) - { - if (guard > Config::Buttons::GUARD_THRESHOLD) - { - guard = 0; - state.ox_detach_btn = true; - LOG_DEBUG(logger, "n2 3way button pressed"); - } - else - { - guard++; - } - } - else if (btns::n2_filling::value()) - { - if (guard > Config::Buttons::GUARD_THRESHOLD) - { - guard = 0; - state.n2_filling_btn = true; - LOG_DEBUG(logger, "N2 filling button pressed"); - } - else - { - guard++; - } - } - else if (btns::n2_release::value()) - { - if (guard > Config::Buttons::GUARD_THRESHOLD) - { - guard = 0; - state.n2_release_btn = true; - LOG_DEBUG(logger, "N2 release button pressed"); - } - else - { - guard++; - } - } - else if (btns::n2_detach::value()) - { - if (guard > Config::Buttons::GUARD_THRESHOLD) - { - guard = 0; - state.n2_detach_btn = true; - LOG_DEBUG(logger, "N2 detach button pressed"); - } - else - { - guard++; - } - } - else if (btns::nitrogen::value()) - { - if (guard > Config::Buttons::GUARD_THRESHOLD) - { - guard = 0; - state.nitrogen_btn = true; - LOG_DEBUG(logger, "Nitrogen button pressed"); - } - else - { - guard++; - } - } - else if (btns::ox_venting::value()) - { - if (guard > Config::Buttons::GUARD_THRESHOLD) - { - guard = 0; - state.ox_venting_btn = true; - LOG_DEBUG(logger, "Ox venting button pressed"); - } - else - { - guard++; - } - } - else if (btns::n2_quenching::value()) - { - if (guard > Config::Buttons::GUARD_THRESHOLD) - { - guard = 0; - state.n2_quenching_btn = true; - LOG_DEBUG(logger, "N2 quenching button pressed"); - } - else - { - guard++; - } - } - else if (btns::tars3::value()) - { - if (guard > Config::Buttons::GUARD_THRESHOLD) - { - guard = 0; - state.tars3_btn = true; - LOG_DEBUG(logger, "Tars3 button pressed"); - } - else - { - guard++; - } - } - else if (btns::tars3m::value()) - { - if (guard > Config::Buttons::GUARD_THRESHOLD) - { - guard = 0; - state.tars3m_btn = true; - LOG_DEBUG(logger, "Tars3m button pressed"); - } - else - { - guard++; - } - } - else - { - // Reset all the states and guard - guard = 0; - resetState(); +#define CHECK_BUTTON(cond, btn) \ + if (cond) \ + { \ + if (guard.btn > Config::Buttons::GUARD_THRESHOLD) \ + { \ + guard.btn = 0; \ + state.btn = true; \ + LOG_DEBUG(logger, #btn " button pressed"); \ + } \ + else \ + { \ + guard.btn++; \ + } \ + } \ + else \ + { \ + guard.btn = 0; \ + state.btn = false; \ } + state.arm_switch = btns::arm::value(); + state.n2_3way_btn = btns::n2_3way::value(); + + CHECK_BUTTON(!btns::ignition::value() && state.arm_switch, ignition_btn); + CHECK_BUTTON(btns::ox_filling::value(), ox_filling_btn); + CHECK_BUTTON(btns::ox_release::value(), ox_release_btn); + CHECK_BUTTON(btns::ox_detach::value(), ox_detach_btn); + CHECK_BUTTON(btns::ox_venting::value(), ox_venting_btn); + CHECK_BUTTON(btns::n2_filling::value(), n2_filling_btn); + CHECK_BUTTON(btns::n2_release::value(), n2_release_btn); + CHECK_BUTTON(btns::n2_detach::value(), n2_detach_btn); + CHECK_BUTTON(btns::n2_quenching::value(), n2_quenching_btn); + CHECK_BUTTON(btns::nitrogen::value(), nitrogen_btn); + CHECK_BUTTON(btns::tars3::value(), tars3_btn); + CHECK_BUTTON(btns::tars3m::value(), tars3m_btn); + +#undef CHECK_BUTTON + // Set the internal button state in Radio module - getModule<Radio>()->setButtonsState(state); + getModule<Radio>()->updateButtonState(state); } void Buttons::enableIgnition() { ui::armedLed::high(); } diff --git a/src/ConRIGv2/Buttons/Buttons.h b/src/ConRIGv2/Buttons/Buttons.h index 5d2c26d0e..2c4d54408 100644 --- a/src/ConRIGv2/Buttons/Buttons.h +++ b/src/ConRIGv2/Buttons/Buttons.h @@ -36,8 +36,6 @@ class Radio; class Buttons : public Boardcore::InjectableWithDeps<BoardScheduler, Radio> { public: - Buttons(); - [[nodiscard]] bool start(); mavlink_conrig_state_tc_t getState(); @@ -46,14 +44,11 @@ public: void disableIgnition(); private: - void resetState(); - void periodicStatusCheck(); - mavlink_conrig_state_tc_t state; - + mavlink_conrig_state_tc_t state{}; // Counter guard to avoid spurious triggers - uint8_t guard = 0; + mavlink_conrig_state_tc_t guard{}; Boardcore::PrintLogger logger = Boardcore::Logging::getLogger("buttons"); }; diff --git a/src/ConRIGv2/Radio/Radio.cpp b/src/ConRIGv2/Radio/Radio.cpp index 8e7ebb843..328df566a 100644 --- a/src/ConRIGv2/Radio/Radio.cpp +++ b/src/ConRIGv2/Radio/Radio.cpp @@ -1,5 +1,5 @@ /* Copyright (c) 2025 Skyward Experimental Rocketry - * Author: Ettore Pane + * Authors: Ettore Pane, Niccolò Betto * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal @@ -80,9 +80,8 @@ void Radio::handleMessage(const mavlink_message_t& msg) // we assume this ack is about the last sent message if (id == MAVLINK_MSG_ID_CONRIG_STATE_TC) { - Lock<FastMutex> lock{buttonsMutex}; // Reset the internal button state - buttonState = {}; + resetButtonState(); } break; @@ -164,11 +163,11 @@ void Radio::buzzerTask() } } -void Radio::setButtonsState(const mavlink_conrig_state_tc_t& state) +void Radio::updateButtonState(const mavlink_conrig_state_tc_t& state) { Lock<FastMutex> lock{buttonsMutex}; - // The OR operator is introduced to make sure that the receiver - // understood the command + // Merge the new state with the old one, an extra-dumb way to ensure + // that we don't lose any button pressess buttonState.ox_filling_btn |= state.ox_filling_btn; buttonState.ox_release_btn |= state.ox_release_btn; buttonState.n2_filling_btn |= state.n2_filling_btn; @@ -178,11 +177,24 @@ void Radio::setButtonsState(const mavlink_conrig_state_tc_t& state) buttonState.nitrogen_btn |= state.nitrogen_btn; buttonState.ox_detach_btn |= state.ox_detach_btn; buttonState.n2_quenching_btn |= state.n2_quenching_btn; - buttonState.n2_3way_btn |= state.n2_3way_btn; buttonState.tars3_btn |= state.tars3_btn; buttonState.tars3m_btn |= state.tars3m_btn; buttonState.ignition_btn |= state.ignition_btn; - buttonState.arm_switch |= state.arm_switch; + + // Don't merge lever states + buttonState.n2_3way_btn = state.n2_3way_btn; + buttonState.arm_switch = state.arm_switch; +} + +void Radio::resetButtonState() +{ + Lock<FastMutex> lock{buttonsMutex}; + // Save and restore lever states + auto n2_3way_btn = buttonState.n2_3way_btn; + auto arm_switch = buttonState.arm_switch; + buttonState = {}; + buttonState.n2_3way_btn = n2_3way_btn; + buttonState.arm_switch = arm_switch; } bool Radio::start() @@ -239,7 +251,7 @@ bool Radio::start() MavlinkStatus Radio::getMavlinkStatus() { return mavDriver->getStatus(); } -Radio::Radio() : buzzer(MIOSIX_BUZZER_TIM, 523), buttonState() +Radio::Radio() : buzzer(MIOSIX_BUZZER_TIM, 523) { buzzer.setDutyCycle(TimerUtils::Channel::MIOSIX_BUZZER_CHANNEL, 0.5); } diff --git a/src/ConRIGv2/Radio/Radio.h b/src/ConRIGv2/Radio/Radio.h index 399eb42fb..9d8c8bb47 100644 --- a/src/ConRIGv2/Radio/Radio.h +++ b/src/ConRIGv2/Radio/Radio.h @@ -56,7 +56,7 @@ public: Boardcore::MavlinkStatus getMavlinkStatus(); - void setButtonsState(const mavlink_conrig_state_tc_t& state); + void updateButtonState(const mavlink_conrig_state_tc_t& state); bool enqueueMessage(const mavlink_message_t& msg); @@ -65,6 +65,8 @@ private: void buzzerTask(); void handleMessage(const mavlink_message_t& msg); + void resetButtonState(); + std::unique_ptr<Boardcore::SX1278Lora> radio; std::unique_ptr<MavDriver> mavDriver; @@ -81,10 +83,10 @@ private: messageQueue; miosix::FastMutex queueMutex; - miosix::FastMutex buttonsMutex; // Button internal state - mavlink_conrig_state_tc_t buttonState; + miosix::FastMutex buttonsMutex; + mavlink_conrig_state_tc_t buttonState{}; std::atomic<uint8_t> messagesReceived{0}; std::atomic<bool> isArmed{false}; -- GitLab