Skip to content
Snippets Groups Projects
Commit c55dc86d authored by athatheo's avatar athatheo
Browse files

Merge branch 'issue-141-notifying-parameters' into 'master'

Add notifying parameter callbacks

Closes #141

See merge request acubesat/obc/ecss-services!118
parents 21283376 2b51a94e
No related branches found
No related tags found
No related merge requests found
#ifndef ECSS_SERVICES_NOTIFYPARAMETER_HPP
#define ECSS_SERVICES_NOTIFYPARAMETER_HPP
#include <etl/optional.h>
#include <functional>
#include "Parameter.hpp"
/**
* A Notifying parameter will call a function whenever its value is written to.
*
* This is useful for updating the state of things when a parameter is changed,
* for example to disable/enable peripherals, to make configuration changes etc.
*
* @warning Calling NotifyParameter::setValue will *not* call the notifier
* function. You should use setValueLoudly for this purpose instead.
*
* @tparam DataType The data type of the parameter's value
*/
template <typename DataType>
class NotifyParameter : public Parameter<DataType> {
public:
using Notifier = std::function<void(const DataType&)>;
using Parent = Parameter<DataType>;
/**
* Constructor without a notifier function. Nothing will then happen when the parameter is updated.
*/
explicit NotifyParameter(DataType initialValue) : Parent(initialValue) {}
/**
* Constructor with a default notifier function.
*/
NotifyParameter(DataType initialValue, const Notifier& notifier) : Parent(initialValue), notifier(notifier) {}
/**
* Same as Parameter::setValue(), but also calls the NotifyParameter::notifier function, if it
* exists.
*/
inline void setValueLoudly(DataType value) {
Parent::setValue(value);
if (notifier) {
(*notifier)(Parent::currentValue);
}
}
/**
* Call the notifier if it exists, without updating the value
*/
inline void notify() {
if (notifier) {
(*notifier)(Parent::currentValue);
}
}
inline void setValueFromMessage(Message& message) override {
Parent::setValueFromMessage(message);
if (notifier) {
(*notifier)(Parent::currentValue);
}
}
/**
* Set the notifier function, to be called whenever the value of this parameter is updated.
*
* @note This function will be called even when a _parameter update_ command is received, but the
* new value is the same as the previous one. This is done so that there is an option to repair
* systems with a weird or unknown state.
* @param call Whether to also call the notifier function immediately, to ensure that a change is
* made.
*/
void setNotifier(const Notifier& _notifier, bool call=true) {
notifier = _notifier;
if (call) {
_notifier(Parent::currentValue);
}
}
/**
* Unset the notifier function, so that nothing is called when the value of this function is updated.
*/
void unsetNotifier() {
notifier.reset();
}
private:
etl::optional<Notifier> notifier;
};
#endif //ECSS_SERVICES_NOTIFYPARAMETER_HPP
...@@ -58,7 +58,7 @@ public: ...@@ -58,7 +58,7 @@ public:
*/ */
template <typename DataType> template <typename DataType>
class Parameter : public ParameterBase { class Parameter : public ParameterBase {
private: protected:
DataType currentValue; DataType currentValue;
public: public:
......
#include "Helpers/NotifyParameter.hpp"
#include "Message.hpp"
#include "catch2/catch_all.hpp"
TEST_CASE("Notify Parameter: Notifier") {
int counter = 0;
NotifyParameter<uint32_t> parameter(0);
SECTION("Notifier not set") {
parameter.setValueLoudly(1);
CHECK(counter == 0);
}
parameter.setNotifier([&counter](auto) -> auto{
counter++;
});
CHECK(counter == 1);
parameter.setValueLoudly(2);
CHECK(counter == 2);
parameter.setValueLoudly(2);
CHECK(counter == 3);
parameter.unsetNotifier();
parameter.setValueLoudly(3);
CHECK(counter == 3);
}
TEST_CASE("Notify Parameter: Messages") {
int16_t storage;
NotifyParameter<uint32_t> parameter(
0, [&storage](auto v) -> auto{
storage = v;
});
Message message(0, 0, Message::TC);
message.appendUint32(184);
parameter.setValueFromMessage(message);
CHECK(storage == 184);
}
TEST_CASE("Notify Parameter: Extra functionality") {
int counter = 0;
NotifyParameter<uint32_t> parameter(0);
auto notifier = [&counter](auto) -> auto{
counter++;
};
parameter.setNotifier(notifier);
CHECK(counter == 1);
parameter.setNotifier(notifier, false);
CHECK(counter == 1);
parameter.notify();
CHECK(counter == 2);
}
\ No newline at end of file
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment