diff --git a/cmake/boardcore.cmake b/cmake/boardcore.cmake index 49c7e5016601ccf8571c727c9ad078a644ae2e14..3c6806988b9fcf80a1a9bce82c4536b4ae40033f 100644 --- a/cmake/boardcore.cmake +++ b/cmake/boardcore.cmake @@ -97,6 +97,7 @@ foreach(OPT_BOARD ${BOARDS}) # Utils ${SBS_BASE}/src/shared/utils/AeroUtils/AeroUtils.cpp ${SBS_BASE}/src/shared/utils/ButtonHandler/ButtonHandler.cpp + ${SBS_BASE}/src/shared/utils/PinObserver/PinObserver.cpp ${SBS_BASE}/src/shared/utils/SkyQuaternion/SkyQuaternion.cpp ${SBS_BASE}/src/shared/utils/Stats/Stats.cpp ${SBS_BASE}/src/shared/utils/TestUtils/TestHelper.cpp diff --git a/src/shared/utils/ButtonHandler/ButtonHandler.cpp b/src/shared/utils/ButtonHandler/ButtonHandler.cpp index 56a0e5df40a5f5e5b2d12d4c3c80e2f0bfb00774..89c20e726514ba2acc90a9f5ea5d1d2266c3365f 100644 --- a/src/shared/utils/ButtonHandler/ButtonHandler.cpp +++ b/src/shared/utils/ButtonHandler/ButtonHandler.cpp @@ -44,6 +44,11 @@ bool ButtonHandler::registerButtonCallback(miosix::GpioPin pin, return false; } +bool ButtonHandler::unregisterButtonCallback(miosix::GpioPin pin) +{ + return callbacks.erase(pin) != 0; +} + bool ButtonHandler::start() { return scheduler.start(); } void ButtonHandler::stop() { scheduler.stop(); } @@ -63,12 +68,12 @@ void ButtonHandler::periodicButtonValueCheck(miosix::GpioPin pin) // Retrieve the pin information const ButtonCallback &callback = std::get<0>(callbacks[pin]); bool &wasPressed = std::get<1>(callbacks[pin]); - int &pressedTicks = std::get<2>(callbacks[pin]); + unsigned int &pressedTicks = std::get<2>(callbacks[pin]); // Read the current button status // Note: The button is assumed to be pressed if the pin value is low // (pulldown) - bool isNowPressed = !pin.value(); + const bool isNowPressed = !pin.value(); if (isNowPressed) { diff --git a/src/shared/utils/ButtonHandler/ButtonHandler.h b/src/shared/utils/ButtonHandler/ButtonHandler.h index 2ff97a9beb9e4acb7e6e98c45ee88550fa3deddf..8ae5b7d583f10ed726f93e12709bb88279d8e0c3 100644 --- a/src/shared/utils/ButtonHandler/ButtonHandler.h +++ b/src/shared/utils/ButtonHandler/ButtonHandler.h @@ -23,8 +23,8 @@ #pragma once #include <Singleton.h> -#include <miosix.h> #include <scheduler/TaskScheduler.h> +#include <utils/GpioPinCompare.h> #include <map> @@ -33,24 +33,10 @@ namespace Boardcore enum class ButtonEvent { - PRESSED, // Called as soon as the button is pressed - SHORT_PRESS, // Called as soon as the button is released - LONG_PRESS, // Called as soon as the button is released - VERY_LONG_PRESS // Called as soon as the button is released -}; - -/** - * @brief Comparison operator between GpioPins used for std::map. - */ -struct GpioPinCompare -{ - bool operator()(const miosix::GpioPin& lhs, - const miosix::GpioPin& rhs) const - { - if (lhs.getPort() == rhs.getPort()) - return lhs.getNumber() < rhs.getNumber(); - return lhs.getPort() < rhs.getPort(); - } + PRESSED, ///< The button is pressed. + SHORT_PRESS, ///< The button is released before LONG_PRESS_TICKS. + LONG_PRESS, ///< The button is released before VERY_LONG_PRESS_TICKS. + VERY_LONG_PRESS ///< The button is released after VERY_LONG_PRESS_TICKS. }; /** @@ -122,17 +108,12 @@ private: /** * @brief Map of all the callbacks registered in the ButtonHandler. * - * The key is the GpioPin for which the callback is registered. To used - * GpioPin as a map key, the GpioPinCompare operator was defined as - * explained here: - * https://stackoverflow.com/questions/1102392/how-can-i-use-stdmaps-with-user-defined-types-as-key - * * The type stored is a tuple containing: * - The button callback function; * - Whether or not the button was pressed in the last check iteration; * - The relative tick of the last pin value change. */ - std::map<miosix::GpioPin, std::tuple<ButtonCallback, bool, int>, + std::map<miosix::GpioPin, std::tuple<ButtonCallback, bool, unsigned int>, GpioPinCompare> callbacks; }; diff --git a/src/shared/utils/GpioPinCompare.h b/src/shared/utils/GpioPinCompare.h new file mode 100644 index 0000000000000000000000000000000000000000..428c32c0b97ce46eba3ddb52ee4887efd4ab10e9 --- /dev/null +++ b/src/shared/utils/GpioPinCompare.h @@ -0,0 +1,47 @@ +/* Copyright (c) 2022 Skyward Experimental Rocketry + * Authors: Alberto Nidasio + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include <miosix.h> + +namespace Boardcore +{ + +/** + * @brief Comparison operator between GpioPins used for std::map. + * + * This function was implemented to use GpioPin as a map key. Check here for + * more explanation: + * https://stackoverflow.com/questions/1102392/how-can-i-use-stdmaps-with-user-defined-types-as-key + */ +struct GpioPinCompare +{ + bool operator()(const miosix::GpioPin& lhs, + const miosix::GpioPin& rhs) const + { + if (lhs.getPort() == rhs.getPort()) + return lhs.getNumber() < rhs.getNumber(); + return lhs.getPort() < rhs.getPort(); + } +}; +} // namespace Boardcore diff --git a/src/shared/utils/PinObserver.h b/src/shared/utils/PinObserver.h deleted file mode 100644 index a09573f5453f043219bde522004011a3f2a671b7..0000000000000000000000000000000000000000 --- a/src/shared/utils/PinObserver.h +++ /dev/null @@ -1,228 +0,0 @@ -/* Copyright (c) 2018 Skyward Experimental Rocketry - * Author: Luca Erbetta - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - * - * The above copyright notice and this permission notice shall be included in - * all copies or substantial portions of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - * THE SOFTWARE. - */ - -#pragma once - -#include <diagnostic/StackLogger.h> -#include <miosix.h> - -#include <functional> -#include <map> -#include <utility> - -#include "ActiveObject.h" - -using miosix::FastMutex; -using miosix::GpioPin; -using miosix::Lock; -using miosix::Thread; -using miosix::Unlock; - -using std::function; -using std::map; -using std::pair; - -namespace Boardcore -{ - -/** - * Class used to call a callback after a pin performs a specific transition - * (RISING or FALLING edge) and stays in the new state for a specific amount of - * time. Useful if you want to monitor pin transitions but you want to avoid - * spurious state changes. - * - * A callback to monitor each state change no matter the thresold or the - * transition is also available, in order to be able to observe the current - * state of the pin - */ -class PinObserver : public ActiveObject -{ -public: - /** - * @brief Pin transition - * Actual enumaration value represents the stat of the pin after the - * corresponding transition has occured. - */ - enum class Transition : int - { - FALLING_EDGE = 0, - RISING_EDGE = 1 - }; - - using OnStateChangeCallback = - function<void(unsigned int, unsigned char, int)>; - - using OnTransitionCallback = function<void(unsigned int, unsigned char)>; - - /** - * @brief Construct a new Pin Observer object - * - * @param pollIntervalMs Pin transition polling interval - */ - PinObserver(unsigned int pollIntervalMs = 20) : pollInterval(pollIntervalMs) - { - } - - /** - * Observe a pin for a specific transition, and optionally for every - * single state change. - * - * The @param transitionCb function is called only if the two following - * conditions are verified: - * 1. The transition specified in the @param transition is detected - * 2. The pin stays in the new state for at least detection_threshols - * samples. - * - * The @param onstatechangeCb function [optional] is called at each state - * change, both rising and falling edge, regardless of the @param - * detectionThreshold - * - * @param p GPIOA_BASE, GPIOB_BASE ... - * @param n Which pin (0 to 15) - * @param transition What transition to detect (RISING or FALLING edge) - * @param transitionCb Function to call when the transition is detected and - * the pin stays in the new configuration for at least @param - * detectionThreshold samples - * @param detectionThreshold How many times the pin should be observed in - * the post-transition state to trigger the actual transition callback. - * @param onstatechangeCb Function to be called at each pin state change, - * no matter the threshold or the transition - */ - void observePin(unsigned int p, unsigned char n, Transition transition, - OnTransitionCallback transitionCb, - unsigned int detectionThreshold = 1, - OnStateChangeCallback onstatechangeCb = nullptr) - { - Lock<FastMutex> lock(mtxMap); - observedPins.insert( - std::make_pair(pair<unsigned int, unsigned char>({p, n}), - ObserverData{GpioPin{p, n}, transition, transitionCb, - onstatechangeCb, detectionThreshold})); - } - - /** - * @brief Stop monitoring the specified pin - * - * @param p GPIOA_BASE, GPIOB_BASE ... - * @param n Which pin (0 to 15) - */ - void removeObservedPin(unsigned int p, unsigned char n) - { - Lock<FastMutex> lock(mtxMap); - observedPins.erase({p, n}); - } - -protected: - void run() - { - while (true) - { - { - Lock<FastMutex> lock(mtxMap); - - for (auto it = observedPins.begin(); it != observedPins.end(); - it++) - { - pair<int, int> key = it->first; - ObserverData& pinData = it->second; - - int oldState = pinData.state; - int newState = pinData.pin.value(); - - // Save current state in the struct - pinData.state = newState; - - // Are we in a post-transition state? - if (pinData.state == static_cast<int>(pinData.transition)) - { - ++pinData.detectedCount; - } - else - { - pinData.detectedCount = 0; - } - - // Pre-calcualate conditions in order to unlock the mutex - // only one time - - bool stateChange = pinData.onstatechangeCallback && - oldState != pinData.state; - bool pinTriggered = - pinData.detectedCount == pinData.detectionThreshold; - - { - Unlock<FastMutex> unlock(lock); - - if (stateChange) - { - pinData.onstatechangeCallback(key.first, key.second, - newState); - } - - if (pinTriggered) - { - pinData.transitionCallback(key.first, key.second); - } - } - } - } - - StackLogger::getInstance().updateStack(THID_PIN_OBS); - - Thread::sleep(pollInterval); - } - } - -private: - struct ObserverData - { - GpioPin pin; - Transition transition; - OnTransitionCallback transitionCallback; - OnStateChangeCallback onstatechangeCallback; - unsigned int detectionThreshold; - unsigned int detectedCount; - int state; // 1 if HIGH, 0 if LOW - - ObserverData(GpioPin pin, Transition transition, - OnTransitionCallback transitionCallback, - OnStateChangeCallback onstatechangeCallback, - unsigned int detectionThreshold) - : pin(pin), transition(transition), - transitionCallback(transitionCallback), - onstatechangeCallback(onstatechangeCallback), - detectionThreshold(detectionThreshold), - // Set to this value to avoid detection if the pin is already in - // the ending state of the "trigger" transition - detectedCount(detectionThreshold + 1), state(0) - { - } - }; - - map<pair<unsigned int, unsigned char>, ObserverData> observedPins; - FastMutex mtxMap; - - unsigned int pollInterval; - bool stopped = true; -}; - -} // namespace Boardcore diff --git a/src/shared/utils/PinObserver/PinObserver.cpp b/src/shared/utils/PinObserver/PinObserver.cpp new file mode 100644 index 0000000000000000000000000000000000000000..14430cda3df132bbfdcbf58565715f3b88067834 --- /dev/null +++ b/src/shared/utils/PinObserver/PinObserver.cpp @@ -0,0 +1,97 @@ +/* Copyright (c) 2018-2022 Skyward Experimental Rocketry + * Author: Luca Erbetta, Alberto Nidasio + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#include "PinObserver.h" + +#include <functional> + +namespace Boardcore +{ + +bool PinObserver::registerPinCallback(miosix::GpioPin pin, PinCallback callback, + unsigned int detectionThreshold) +{ + // Try to insert the callback + auto result = + callbacks.insert({pin, {callback, detectionThreshold, pin.value(), 0}}); + + // Check if the insertion took place + if (result.second) + { + return scheduler.addTask( + std::bind(&PinObserver::periodicPinValueCheck, this, pin), + SAMPLE_PERIOD, TaskScheduler::Policy::SKIP); + } + + return false; +} + +bool PinObserver::unregisterPinCallback(miosix::GpioPin pin) +{ + return callbacks.erase(pin) != 0; +} + +bool PinObserver::start() { return scheduler.start(); } + +void PinObserver::stop() { scheduler.stop(); } + +PinObserver::PinObserver() { scheduler.start(); } + +void PinObserver::periodicPinValueCheck(miosix::GpioPin pin) +{ + // Make sure the pin informations are still present + if (callbacks.find(pin) == callbacks.end()) + return; + + // Retrieve the pin information + const PinCallback &callback = std::get<0>(callbacks[pin]); + const unsigned int detectionThreshold = std::get<1>(callbacks[pin]); + bool &previousState = std::get<2>(callbacks[pin]); + unsigned int &detectedCount = std::get<3>(callbacks[pin]); + + // Read the current pin status + const bool newState = pin.value(); + + // Are we in a transition? + if (previousState != newState) + { + detectedCount = 0; // Yes, reset the counter + } + else + { + detectedCount++; // No, continue to increment + + // If the count reaches the threshold, then trigger the event + if (detectedCount > detectionThreshold) + { + if (newState) + callback(PinTransition::RISING_EDGE); + else + callback(PinTransition::FALLING_EDGE); + } + } + + // Save the current pin status + previousState = newState; +} + +} // namespace Boardcore diff --git a/src/shared/utils/PinObserver/PinObserver.h b/src/shared/utils/PinObserver/PinObserver.h new file mode 100644 index 0000000000000000000000000000000000000000..07090622a702af94f2dcbc04fdd1e3fe05065f62 --- /dev/null +++ b/src/shared/utils/PinObserver/PinObserver.h @@ -0,0 +1,133 @@ +/* Copyright (c) 2018-2022 Skyward Experimental Rocketry + * Author: Luca Erbetta, Alberto Nidasio + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + */ + +#pragma once + +#include <Singleton.h> +#include <scheduler/TaskScheduler.h> +#include <utils/GpioPinCompare.h> + +#include <map> + +namespace Boardcore +{ + +/** + * @brief Pin transition. + */ +enum class PinTransition +{ + FALLING_EDGE, ///< The pin goes from high to low. + RISING_EDGE ///< The pin goes from low to high. +}; + +/** + * Class used to call a callback after a pin performs a specific transition + * (RISING or FALLING edge) and stays in the new state for a specific amount of + * time. Useful if you want to monitor pin transitions but you want to avoid + * spurious state changes. + * + * A callback to monitor each state change no matter the threshold or the + * transition is also available, in order to be able to observe the current + * state of the pin. + */ +class PinObserver : public Singleton<PinObserver> +{ + friend Singleton<PinObserver>; + + static constexpr uint32_t SAMPLE_PERIOD = 100; // 10Hz + +public: + using PinCallback = std::function<void(PinTransition)>; + + /** + * Observe a pin for a specific transition, and optionally for every + * single state change. + * + * @param pin Pin to listen to. + * @param callback Function to call on button events. + * @param detectionThreshold How many times the pin should be observed in + * the post-transition state to trigger the actual transition callback, + * defaults to 1. + * @return False if another callback was already registered for the pin. + */ + bool registerPinCallback(miosix::GpioPin pin, PinCallback callback, + unsigned int detectionThreshold = 1); + + /** + * @brief Unregisters the callback associated with the specified pin, if + * any. + * + * @param pin Pin whose callback function is to be removed. + * @return True if a callback was present and removed for the given pin. + */ + bool unregisterPinCallback(miosix::GpioPin pin); + + /** + * @brief Starts the PinObserver's task scheduler. + * + * Note that the scheduler is started as soon as the PinObserver is first + * used. + * + * @return Whether the task scheduler was started or not. + */ + bool start(); + + /** + * @brief Stops the PinObserver's task scheduler. + */ + void stop(); + +private: + /** + * @brief Construct a new PinObserver object. + * + * @param pollInterval Pin transition polling interval, defaults to 20 [ms]. + */ + PinObserver(); + + /** + * @brief This function is added to the scheduler for every pin registered + * in the PinObserver. + * + * @param pin Pin whose value need to be checked. + */ + void periodicPinValueCheck(miosix::GpioPin pin); + + TaskScheduler scheduler; + + /** + * @brief Map of all the callbacks registered in the PinObserver. + + * The type stored is a tuple containing: + * - The button callback function; + * - Detection threshold: number of periods to trigger an event + * - The last pin status; + * - Number of periods the pin values stayed the same; + */ + std::map<miosix::GpioPin, + std::tuple<PinCallback, unsigned int, bool, unsigned int>, + GpioPinCompare> + callbacks; +}; + +} // namespace Boardcore diff --git a/src/tests/test-pinobserver.cpp b/src/tests/test-pinobserver.cpp index 1fe87708a4f27d22bf72f4d84455860331c34b0e..9856200ef36e72da7b604ae2d496a830ee3dc912 100644 --- a/src/tests/test-pinobserver.cpp +++ b/src/tests/test-pinobserver.cpp @@ -21,10 +21,14 @@ */ #include <miosix.h> -#include <utils/PinObserver.h> +#include <utils/PinObserver/PinObserver.h> + +#include <functional> using namespace Boardcore; using namespace miosix; +using namespace std; +using namespace std::placeholders; static constexpr unsigned int POLL_INTERVAL = 20; @@ -35,60 +39,38 @@ static constexpr unsigned char PIN1_PIN = 5; static constexpr unsigned int PIN2_PORT = GPIOE_BASE; static constexpr unsigned char PIN2_PIN = 6; -void onStateChange(unsigned int p, unsigned char n, int state) +void onTransition(GpioPin pin, PinTransition transition) { - if (p == BTN_PORT && n == BTN_PIN) - { - printf("BTN state change: %d\n", state); - } - if (p == PIN1_PORT && n == PIN1_PIN) - { - printf("PIN1 state change: %d\n", state); - } - if (p == PIN2_PORT && n == PIN2_PIN) - { - printf("PIN2 state change: %d\n", state); - } -} + if (pin.getPort() == BTN_PORT && pin.getNumber() == BTN_PIN) + printf("BTN transition: "); + if (pin.getPort() == PIN1_PORT && pin.getNumber() == PIN1_PIN) + printf("PIN1 transition: "); + if (pin.getPort() == PIN2_PORT && pin.getNumber() == PIN2_PIN) + printf("PIN2 transition: "); -void onTransition(unsigned int p, unsigned char n) -{ - if (p == BTN_PORT && n == BTN_PIN) - { - printf("BTN transition.\n"); - } - if (p == PIN1_PORT && n == PIN1_PIN) - { - printf("PIN1 transition.\n"); - } - if (p == PIN2_PORT && n == PIN2_PIN) - { - printf("PIN2 transition.\n"); - } + if (transition == PinTransition::FALLING_EDGE) + printf("FALLING_EDGE\n"); + else + printf("RISING_EDGE\n"); } int main() { - GpioPin(BTN_PORT, BTN_PIN).mode(Mode::INPUT); - GpioPin(PIN1_PORT, PIN1_PIN).mode(Mode::INPUT_PULL_DOWN); - GpioPin(PIN2_PORT, PIN2_PIN).mode(Mode::INPUT_PULL_UP); - - PinObserver observer; - - observer.observePin(BTN_PORT, BTN_PIN, PinObserver::Transition::RISING_EDGE, - &onTransition, 1, onStateChange); + auto btn = GpioPin(BTN_PORT, BTN_PIN); + auto pin1 = GpioPin(PIN1_PORT, PIN1_PIN); + auto pin2 = GpioPin(PIN2_PORT, PIN2_PIN); - observer.observePin(PIN1_PORT, PIN1_PIN, - PinObserver::Transition::FALLING_EDGE, &onTransition, - 1000 / POLL_INTERVAL, onStateChange); + btn.mode(Mode::INPUT); + pin1.mode(Mode::INPUT_PULL_DOWN); + pin2.mode(Mode::INPUT_PULL_UP); - observer.observePin(PIN2_PORT, PIN2_PIN, - PinObserver::Transition::RISING_EDGE, &onTransition, - 1000 / POLL_INTERVAL, onStateChange); + PinObserver::getInstance().registerPinCallback( + btn, std::bind(onTransition, btn, _1), 10); + PinObserver::getInstance().registerPinCallback( + pin1, std::bind(onTransition, pin1, _1), 10); + PinObserver::getInstance().registerPinCallback( + pin2, std::bind(onTransition, pin2, _1), 10); - observer.start(); - for (;;) - { + while (true) Thread::sleep(10000); - } }