Feature: Allowed Submodes Mask for Mode List Entry #130
@ -21,6 +21,7 @@ SubsystemBase::~SubsystemBase() { QueueFactory::instance()->deleteMessageQueue(c
|
|||||||
|
|
||||||
ReturnValue_t SubsystemBase::checkStateAgainstTable(HybridIterator<ModeListEntry> tableIter,
|
ReturnValue_t SubsystemBase::checkStateAgainstTable(HybridIterator<ModeListEntry> tableIter,
|
||||||
Submode_t targetSubmode) {
|
Submode_t targetSubmode) {
|
||||||
|
using namespace mode;
|
||||||
std::map<object_id_t, ChildInfo>::iterator childIter;
|
std::map<object_id_t, ChildInfo>::iterator childIter;
|
||||||
|
|
||||||
for (; tableIter.value != NULL; ++tableIter) {
|
for (; tableIter.value != NULL; ++tableIter) {
|
||||||
gaisser marked this conversation as resolved
Outdated
|
|||||||
@ -34,13 +35,21 @@ ReturnValue_t SubsystemBase::checkStateAgainstTable(HybridIterator<ModeListEntry
|
|||||||
return returnvalue::FAILED;
|
return returnvalue::FAILED;
|
||||||
}
|
}
|
||||||
|
|
||||||
Submode_t submodeToCheckAgainst = tableIter.value->getSubmode();
|
// Check submodes here.
|
||||||
|
uint8_t mask;
|
||||||
gaisser marked this conversation as resolved
Outdated
gaisser
commented
This can be the else case of the above. Or maybe switch cases (not XX might be harder to read):
This can be the else case of the above. Or maybe switch cases (not XX might be harder to read):
``` c++
if (submodesAllowedMask) {
if ((childIter->second.submode | mask) != mask) {
return returnvalue::FAILED;
}
}else{
if (childIter->second.submode != submodeToCheckAgainst) {
return returnvalue::FAILED;
}
}
return returnvalue::OK;
```
|
|||||||
|
bool submodesAllowedMask = tableIter.value->submodesAllowed(&mask);
|
||||||
|
uint8_t submodeToCheckAgainst = tableIter.value->getSubmode();
|
||||||
if (tableIter.value->inheritSubmode()) {
|
if (tableIter.value->inheritSubmode()) {
|
||||||
submodeToCheckAgainst = targetSubmode;
|
submodeToCheckAgainst = targetSubmode;
|
||||||
}
|
}
|
||||||
|
if (submodesAllowedMask) {
|
||||||
if (childIter->second.submode != submodeToCheckAgainst) {
|
if ((childIter->second.submode | mask) != mask) {
|
||||||
return returnvalue::FAILED;
|
return returnvalue::FAILED;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (childIter->second.submode != submodeToCheckAgainst) {
|
||||||
|
return returnvalue::FAILED;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
|
@ -1,111 +1,126 @@
|
|||||||
#ifndef FSFW_SUBSYSTEM_MODES_MODEDEFINITIONS_H_
|
#ifndef FSFW_SUBSYSTEM_MODES_MODEDEFINITIONS_H_
|
||||||
#define FSFW_SUBSYSTEM_MODES_MODEDEFINITIONS_H_
|
#define FSFW_SUBSYSTEM_MODES_MODEDEFINITIONS_H_
|
||||||
|
|
||||||
#include "../../modes/HasModesIF.h"
|
#include "fsfw/modes/HasModesIF.h"
|
||||||
#include "../../objectmanager/SystemObjectIF.h"
|
#include "fsfw/objectmanager/SystemObjectIF.h"
|
||||||
#include "../../serialize/SerialLinkedListAdapter.h"
|
#include "fsfw/serialize/SerialLinkedListAdapter.h"
|
||||||
#include "../../serialize/SerializeIF.h"
|
#include "fsfw/serialize/SerializeIF.h"
|
||||||
|
|
||||||
class ModeListEntry : public SerializeIF, public LinkedElement<ModeListEntry> {
|
namespace mode {
|
||||||
|
enum SpecialSubmodeFlags : uint8_t { INHERIT = 1 << 0, ALLOWED_MASK = 1 << 1 };
|
||||||
|
}
|
||||||
|
|
||||||
|
class ModeListEntry : public SerialLinkedListAdapter<SerializeIF>,
|
||||||
|
public LinkedElement<ModeListEntry> {
|
||||||
public:
|
public:
|
||||||
ModeListEntry() : LinkedElement<ModeListEntry>(this) {}
|
static constexpr uint8_t ALL_SUBMODES_ALLOWED_MASK = 0xff;
|
||||||
|
|
||||||
uint32_t value1 = 0;
|
ModeListEntry() : SerialLinkedListAdapter(), LinkedElement<ModeListEntry>(this) { setLinks(); }
|
||||||
uint32_t value2 = 0;
|
|
||||||
uint8_t value3 = 0;
|
|
||||||
uint8_t value4 = 0;
|
|
||||||
|
|
||||||
virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
SerializeElement<uint32_t> value1 = 0;
|
||||||
Endianness streamEndianness) const {
|
SerializeElement<uint32_t> value2 = 0;
|
||||||
ReturnValue_t result;
|
SerializeElement<uint8_t> value3 = 0;
|
||||||
|
SerializeElement<uint8_t> value4 = 0;
|
||||||
|
SerializeElement<uint8_t> value5 = 0;
|
||||||
|
|
||||||
result = SerializeAdapter::serialize(&value1, buffer, size, maxSize, streamEndianness);
|
ModeListEntry(const ModeListEntry& other)
|
||||||
|
: SerialLinkedListAdapter(), LinkedElement<ModeListEntry>(this) {
|
||||||
if (result != returnvalue::OK) {
|
value1.entry = other.value1.entry;
|
||||||
return result;
|
value2.entry = other.value2.entry;
|
||||||
}
|
value3.entry = other.value3.entry;
|
||||||
result = SerializeAdapter::serialize(&value2, buffer, size, maxSize, streamEndianness);
|
value4.entry = other.value4.entry;
|
||||||
|
value5.entry = other.value5.entry;
|
||||||
if (result != returnvalue::OK) {
|
setLinks();
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result = SerializeAdapter::serialize(&value3, buffer, size, maxSize, streamEndianness);
|
|
||||||
|
|
||||||
if (result != returnvalue::OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = SerializeAdapter::serialize(&value4, buffer, size, maxSize, streamEndianness);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual size_t getSerializedSize() const {
|
ModeListEntry& operator=(const ModeListEntry& other) {
|
||||||
return sizeof(value1) + sizeof(value2) + sizeof(value3) + sizeof(value4);
|
this->value1.entry = other.value1.entry;
|
||||||
|
this->value2.entry = other.value2.entry;
|
||||||
|
this->value3.entry = other.value3.entry;
|
||||||
|
this->value4.entry = other.value4.entry;
|
||||||
|
this->value5.entry = other.value5.entry;
|
||||||
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
void setLinks() {
|
||||||
Endianness streamEndianness) {
|
setStart(&value1);
|
||||||
ReturnValue_t result;
|
value1.setNext(&value2);
|
||||||
|
value2.setNext(&value3);
|
||||||
result = SerializeAdapter::deSerialize(&value1, buffer, size, streamEndianness);
|
value3.setNext(&value4);
|
||||||
|
value4.setNext(&value5);
|
||||||
if (result != returnvalue::OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result = SerializeAdapter::deSerialize(&value2, buffer, size, streamEndianness);
|
|
||||||
|
|
||||||
if (result != returnvalue::OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result = SerializeAdapter::deSerialize(&value3, buffer, size, streamEndianness);
|
|
||||||
|
|
||||||
if (result != returnvalue::OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result = SerializeAdapter::deSerialize(&value4, buffer, size, streamEndianness);
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// for Sequences
|
// for Sequences
|
||||||
Mode_t getTableId() const { return value1; }
|
Mode_t getTableId() const { return value1.entry; }
|
||||||
|
|
||||||
void setTableId(Mode_t tableId) { this->value1 = tableId; }
|
void setTableId(Mode_t tableId) { this->value1.entry = tableId; }
|
||||||
|
|
||||||
uint8_t getWaitSeconds() const { return value2; }
|
uint8_t getWaitSeconds() const { return value2.entry; }
|
||||||
|
|
||||||
void setWaitSeconds(uint8_t waitSeconds) { this->value2 = waitSeconds; }
|
void setWaitSeconds(uint8_t waitSeconds) { this->value2.entry = waitSeconds; }
|
||||||
|
|
||||||
bool checkSuccess() const { return value3 == 1; }
|
bool checkSuccess() const { return value3.entry == 1; }
|
||||||
|
|
||||||
void setCheckSuccess(bool checkSuccess) { this->value3 = checkSuccess; }
|
void setCheckSuccess(bool checkSuccess) { this->value3.entry = checkSuccess; }
|
||||||
|
|
||||||
// for Tables
|
// for Tables
|
||||||
object_id_t getObject() const { return value1; }
|
object_id_t getObject() const { return value1.entry; }
|
||||||
|
|
||||||
void setObject(object_id_t object) { this->value1 = object; }
|
void setObject(object_id_t object) { this->value1.entry = object; }
|
||||||
|
|
||||||
Mode_t getMode() const { return value2; }
|
Mode_t getMode() const { return value2.entry; }
|
||||||
|
|
||||||
void setMode(Mode_t mode) { this->value2 = mode; }
|
void setMode(Mode_t mode) { this->value2.entry = mode; }
|
||||||
|
|
||||||
Submode_t getSubmode() const { return value3; }
|
Submode_t getSubmode() const { return value3.entry; }
|
||||||
|
|
||||||
void setSubmode(Submode_t submode) { this->value3 = submode; }
|
void setSubmode(Submode_t submode) { this->value3.entry = submode; }
|
||||||
|
|
||||||
bool inheritSubmode() const { return value4 == 1; }
|
bool inheritSubmode() const {
|
||||||
|
return (value4.entry & mode::SpecialSubmodeFlags::INHERIT) ==
|
||||||
void setInheritSubmode(bool inherit) {
|
mode::SpecialSubmodeFlags::INHERIT;
|
||||||
if (inherit) {
|
}
|
||||||
value4 = 1;
|
bool submodesAllowed(uint8_t* mask) const {
|
||||||
} else {
|
bool submodesAllowed = (value4.entry & mode::SpecialSubmodeFlags::ALLOWED_MASK) ==
|
||||||
value4 = 0;
|
mode::SpecialSubmodeFlags::ALLOWED_MASK;
|
||||||
|
if (submodesAllowed and mask != nullptr) {
|
||||||
|
*mask = value5.entry;
|
||||||
}
|
}
|
||||||
|
return submodesAllowed;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool operator==(ModeListEntry other) {
|
/**
|
||||||
return ((value1 == other.value1) && (value2 == other.value2) && (value3 == other.value3));
|
* Enable the inheritance of submodes. This is relevant for both the execution
|
||||||
|
* of mode tables and for mode checking.
|
||||||
|
*/
|
||||||
|
void enableInheritSubmode() { value4.entry |= mode::SpecialSubmodeFlags::INHERIT; }
|
||||||
|
/**
|
||||||
|
* Disable the inheritance of submodes. This is relevant for both the execution
|
||||||
|
* of mode tables and for mode checking.
|
||||||
|
*/
|
||||||
|
void disableInheritSubmode() { value4.entry &= ~mode::SpecialSubmodeFlags::INHERIT; }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Specialization of @enableSubmodeAllowed which allows all submodes.
|
||||||
gaisser marked this conversation as resolved
gaisser
commented
0xFF should be defined somewhere visible as a restricted mask. 0xFF should be defined somewhere visible as a restricted mask.
|
|||||||
|
*/
|
||||||
|
void allowAllSubmodes() { enableSubmodeAllowed(ALL_SUBMODES_ALLOWED_MASK); }
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Enable an allowed submode mask for mode checks. Any submode which contains bits
|
||||||
|
* outside of the mask will be declined.
|
||||||
|
*
|
||||||
|
* For example, for a mask of 0b11, only the modes 0b00, 0b01 and 0b11 will be accepted.
|
||||||
|
*/
|
||||||
|
void enableSubmodeAllowed(uint8_t mask) {
|
||||||
|
value4.entry |= mode::SpecialSubmodeFlags::ALLOWED_MASK;
|
||||||
|
value5.entry = mask;
|
||||||
|
}
|
||||||
|
/**
|
||||||
|
* Enforce the equality of submodes for mode checks. This is the default.
|
||||||
|
*/
|
||||||
|
void disableSubmodeAllowed() {
|
||||||
|
value4.entry &= ~mode::SpecialSubmodeFlags::ALLOWED_MASK;
|
||||||
|
value5.entry = 0;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -13,6 +13,7 @@ add_subdirectory(util)
|
|||||||
add_subdirectory(container)
|
add_subdirectory(container)
|
||||||
add_subdirectory(osal)
|
add_subdirectory(osal)
|
||||||
add_subdirectory(pus)
|
add_subdirectory(pus)
|
||||||
|
add_subdirectory(subsystem)
|
||||||
add_subdirectory(serialize)
|
add_subdirectory(serialize)
|
||||||
add_subdirectory(datapoollocal)
|
add_subdirectory(datapoollocal)
|
||||||
add_subdirectory(storagemanager)
|
add_subdirectory(storagemanager)
|
||||||
|
1
unittests/subsystem/CMakeLists.txt
Normal file
1
unittests/subsystem/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
target_sources(${FSFW_TEST_TGT} PRIVATE testModeDef.cpp)
|
49
unittests/subsystem/testModeDef.cpp
Normal file
49
unittests/subsystem/testModeDef.cpp
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
|
#include "fsfw/subsystem/modes/ModeDefinitions.h"
|
||||||
|
|
||||||
|
TEST_CASE("Mode Definitions", "[mode]") {
|
||||||
|
ModeListEntry entry;
|
||||||
|
|
||||||
|
SECTION("Basic") {
|
||||||
|
entry.setMode(HasModesIF::MODE_OFF);
|
||||||
|
entry.setSubmode(2);
|
||||||
|
CHECK(entry.getMode() == HasModesIF::MODE_OFF);
|
||||||
|
CHECK(entry.getSubmode() == 2);
|
||||||
|
uint8_t mask;
|
||||||
|
CHECK(entry.submodesAllowed(&mask) == false);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Allowed submode mask") {
|
||||||
|
entry.allowAllSubmodes();
|
||||||
|
uint8_t mask;
|
||||||
|
CHECK(entry.submodesAllowed(&mask) == true);
|
||||||
|
CHECK(mask == 0xff);
|
||||||
|
}
|
||||||
|
|
||||||
|
SECTION("Serialization") {
|
||||||
|
std::array<uint8_t, 32> buf{};
|
||||||
|
entry.setObject(0x1f2f3f4f);
|
||||||
|
entry.setMode(HasModesIF::MODE_ON);
|
||||||
|
entry.setSubmode(2);
|
||||||
|
entry.enableInheritSubmode();
|
||||||
|
entry.enableSubmodeAllowed(0x1f);
|
||||||
|
uint8_t* serPtr = buf.data();
|
||||||
|
size_t serLen = 0;
|
||||||
|
REQUIRE(entry.serialize(&serPtr, &serLen, buf.size(), SerializeIF::Endianness::NETWORK) ==
|
||||||
|
returnvalue::OK);
|
||||||
|
CHECK(buf[0] == 0x1f);
|
||||||
|
CHECK(buf[1] == 0x2f);
|
||||||
|
CHECK(buf[2] == 0x3f);
|
||||||
|
CHECK(buf[3] == 0x4f);
|
||||||
|
CHECK(buf[4] == 0);
|
||||||
|
CHECK(buf[5] == 0);
|
||||||
|
CHECK(buf[6] == 0);
|
||||||
|
CHECK(buf[7] == HasModesIF::MODE_ON);
|
||||||
|
CHECK(buf[8] == 2);
|
||||||
|
CHECK(buf[9] == (mode::SpecialSubmodeFlags::ALLOWED_MASK | mode::SpecialSubmodeFlags::INHERIT));
|
||||||
|
CHECK(buf[10] == 0x1f);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user
If you have to use a lambda, which I find a nightmare to read, maybe capture &childIter explicitly.