Compare commits
36 Commits
e660cfad72
...
spahr/Shar
Author | SHA1 | Date | |
---|---|---|---|
![]() |
b30e88640b | ||
![]() |
5818265a7d | ||
f01e58a757 | |||
![]() |
cd94fad8e5 | ||
![]() |
0681b1895b | ||
![]() |
131456e19e | ||
![]() |
40be8ebef5 | ||
55b8d01b93 | |||
8cb1d84c58 | |||
8801dfa31d | |||
b8979d8f90 | |||
9557db7036 | |||
c9fcabccd6 | |||
ecd36f5e52 | |||
fc19c0838e | |||
![]() |
8c3f366d1a | ||
![]() |
6efb2641a7 | ||
![]() |
260bbad9a0 | ||
9edd6221f8 | |||
735e341aab | |||
921bfb1e99 | |||
5b1651e1a6 | |||
e916b9b096 | |||
b14e761bad | |||
33f3ae2434 | |||
f0087d5b0d | |||
![]() |
69c33587e8 | ||
![]() |
d1bf04cc29 | ||
![]() |
8e3bc1b8aa | ||
![]() |
64f97fc3ba | ||
![]() |
1427fbd2fe | ||
![]() |
81cd8bd290 | ||
5dfeee08b3 | |||
d77dbe44c6
|
|||
2165f8ead8 | |||
3def5d8d85
|
15
CHANGELOG.md
15
CHANGELOG.md
@@ -26,6 +26,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## Added
|
||||
|
||||
- FreeRTOS monotonic clock which is not subjected to time jumps of the system clock
|
||||
- add CFDP subsystem ID
|
||||
https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/742
|
||||
- `PusTmZcWriter` now exposes API to set message counter field.
|
||||
@@ -34,8 +35,20 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
|
||||
|
||||
## Changed
|
||||
|
||||
- Complete refactoring of HK subsystem. Replaced local data pool manager by periodic HK
|
||||
- Complete overhaul of HK subsystem. Replaced local data pool manager by periodic HK
|
||||
helper. The shared pool and the periodic HK generation are now distinct concepts.
|
||||
- The local HK manager was replaced by a periodic HK helper which has reduced responsibilities.
|
||||
It takes care of tracking the HK generation using a set specification provided by the user.n
|
||||
However, it leaves serialization of the HK data completely to the developer. This removes a major
|
||||
constraint on the format of the HK data, which was previously constrained to implementors of a
|
||||
certain base class.
|
||||
- The former set classes and pool objects are still available for HK set specification and
|
||||
generation. The API has changed, but the general usage and their architecture has not.
|
||||
- A new set of set classes and helper objects to specify HK sets and data which does not need to be
|
||||
shared was added as well. The majority of datasets do not need to be shared anyway.
|
||||
- The non-shared API retain the capability of appending of a validity blob for each piece of set
|
||||
data at the end of the HK data. For both non-shared and shared data, this capability can be
|
||||
specified in the constructor, and defaults to true.
|
||||
- Improved File System Abstraction to be more in line with normal filesystems.
|
||||
- CFDP implementation was improved, has now even less dependencies on other FSFW components
|
||||
and allows one inserted packet per state machine call.
|
||||
|
@@ -18,13 +18,13 @@ class MgmRM3100Handler : public DeviceHandlerBase {
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::MGM_RM3100;
|
||||
|
||||
//! [EXPORT] : [COMMENT] P1: TMRC value which was set, P2: 0
|
||||
static constexpr Event tmrcSet = event::makeEvent(SUBSYSTEM_ID::MGM_RM3100, 0x00, severity::INFO);
|
||||
static constexpr Event tmrcSet = event::makeEvent<SUBSYSTEM_ID::MGM_RM3100, 0x00, severity::INFO>();
|
||||
|
||||
//! [EXPORT] : [COMMENT] Cycle counter set. P1: First two bytes new Cycle Count X
|
||||
//! P1: Second two bytes new Cycle Count Y
|
||||
//! P2: New cycle count Z
|
||||
static constexpr Event cycleCountersSet =
|
||||
event::makeEvent(SUBSYSTEM_ID::MGM_RM3100, 0x01, severity::INFO);
|
||||
event::makeEvent<SUBSYSTEM_ID::MGM_RM3100, 0x01, severity::INFO>();
|
||||
|
||||
MgmRM3100Handler(object_id_t objectId, object_id_t deviceCommunication, CookieIF *comCookie,
|
||||
uint32_t transitionDelay);
|
||||
|
@@ -19,13 +19,13 @@ struct FsfwParams {
|
||||
};
|
||||
|
||||
namespace events {
|
||||
static constexpr Event PDU_SEND_ERROR = event::makeEvent(SSID, 1, severity::LOW);
|
||||
static constexpr Event SERIALIZATION_ERROR = event::makeEvent(SSID, 2, severity::LOW);
|
||||
static constexpr Event FILESTORE_ERROR = event::makeEvent(SSID, 3, severity::LOW);
|
||||
static constexpr Event PDU_SEND_ERROR = event::makeEvent<SSID, 1, severity::LOW>();
|
||||
static constexpr Event SERIALIZATION_ERROR = event::makeEvent<SSID, 2, severity::LOW>();
|
||||
static constexpr Event FILESTORE_ERROR = event::makeEvent<SSID, 3, severity::LOW>();
|
||||
//! [EXPORT] : [COMMENT] P1: Transaction step ID, P2: 0 for source file name, 1 for dest file name
|
||||
static constexpr Event FILENAME_TOO_LARGE_ERROR = event::makeEvent(SSID, 4, severity::LOW);
|
||||
static constexpr Event FILENAME_TOO_LARGE_ERROR = event::makeEvent<SSID, 4, severity::LOW>();
|
||||
//! [EXPORT] : [COMMENT] CFDP request handling failed. P2: Returncode.
|
||||
static constexpr Event HANDLING_CFDP_REQUEST_FAILED = event::makeEvent(SSID, 5, severity::LOW);
|
||||
static constexpr Event HANDLING_CFDP_REQUEST_FAILED = event::makeEvent<SSID, 5, severity::LOW>();
|
||||
} // namespace events
|
||||
|
||||
static constexpr ReturnValue_t SOURCE_TRANSACTION_PENDING = returnvalue::makeCode(CID, 0);
|
||||
|
@@ -34,11 +34,12 @@ class ExtendedControllerBase : public ControllerBase,
|
||||
ActionHelper actionHelper;
|
||||
|
||||
// Periodic HK methods, default method assumes that no shared pool is required.
|
||||
virtual datapool::SharedPool* getOptionalSharedPool() override;
|
||||
datapool::SharedPool* getOptionalSharedPool() override = 0;
|
||||
|
||||
// Periodic HK abstract methods.
|
||||
ReturnValue_t serializeHkDataset(dp::sid_t structureId, uint8_t* buf, size_t maxSize) = 0;
|
||||
ReturnValue_t specifyHkDatasets(std::vector<hk::SetSpecification>& setList) = 0;
|
||||
ReturnValue_t serializeHkDataset(dp::sid_t structureId, uint8_t* buf,
|
||||
size_t maxSize) override = 0;
|
||||
ReturnValue_t specifyHkDatasets(std::vector<hk::SetSpecification>& setList) override = 0;
|
||||
|
||||
/**
|
||||
* Implemented by child class. Handle all command messages which are
|
||||
|
@@ -48,6 +48,14 @@ PoolObjectBase::PoolObjectBase(object_id_t poolOwner, id_t poolId, DataSetIF* da
|
||||
return;
|
||||
}
|
||||
sharedPool = hkOwner->getOptionalSharedPool();
|
||||
if (sharedPool == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "PoolObjectBase: HK owner 0x" << std::hex << poolOwner << std::dec
|
||||
<< "does not have a shared pool " << std::endl;
|
||||
#else
|
||||
sif::printError("PoolObjectBase: HK owner 0x%08x does not have a shared pool\n", poolOwner);
|
||||
#endif
|
||||
}
|
||||
|
||||
if (dataSet != nullptr) {
|
||||
dataSet->registerVariable(this);
|
||||
@@ -64,6 +72,10 @@ void PoolObjectBase::setReadWriteMode(pool_rwm_t newReadWriteMode) {
|
||||
this->readWriteMode = newReadWriteMode;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool PoolObjectBase::isValid() const { return valid; }
|
||||
|
||||
void PoolObjectBase::setValid(bool valid) { this->valid = valid; }
|
||||
|
||||
void PoolObjectBase::reportReadCommitError(const char* variableType, ReturnValue_t error, bool read,
|
||||
object_id_t objectId, id_t lpId) {
|
||||
#if FSFW_DISABLE_PRINTOUT == 0
|
||||
|
@@ -27,6 +27,9 @@ class PoolObjectBase : public PoolVariableIF {
|
||||
[[nodiscard]] dp::id_t getDataPoolId() const override;
|
||||
void setDataPoolId(dp::id_t poolId);
|
||||
|
||||
[[nodiscard]] bool isValid() const;
|
||||
void setValid(bool valid);
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief To access the correct data pool entry on read and commit calls,
|
||||
@@ -40,6 +43,8 @@ class PoolObjectBase : public PoolVariableIF {
|
||||
*/
|
||||
ReadWriteMode_t readWriteMode = pool_rwm_t::VAR_READ_WRITE;
|
||||
|
||||
bool valid = false;
|
||||
|
||||
//! @brief Pointer to the class which manages the HK pool.
|
||||
dp::SharedPool* sharedPool = nullptr;
|
||||
|
||||
@@ -47,4 +52,4 @@ class PoolObjectBase : public PoolVariableIF {
|
||||
object_id_t objectId, dp::id_t lpId);
|
||||
};
|
||||
|
||||
} // namespace datapool
|
||||
} // namespace datapool
|
||||
|
@@ -216,6 +216,7 @@ class PoolVector : public PoolObjectBase {
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
this->valid = poolEntry->getValid();
|
||||
std::memcpy(this->value, poolEntry->getDataPtr(), poolEntry->getByteSize());
|
||||
return returnvalue::OK;
|
||||
}
|
||||
@@ -237,6 +238,7 @@ class PoolVector : public PoolObjectBase {
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
poolEntry->setValid(this->valid);
|
||||
std::memcpy(poolEntry->getDataPtr(), this->value, poolEntry->getByteSize());
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
@@ -1,15 +1,19 @@
|
||||
#include "fsfw/datapool/PoolDataSetBase.h"
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
|
||||
#include "fsfw/datapool/ReadCommitIFAttorney.h"
|
||||
#include "fsfw/globalfunctions/bitutility.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
|
||||
PoolDataSetBase::PoolDataSetBase(PoolVariableIF** registeredVariablesArray,
|
||||
const size_t maxFillCount)
|
||||
: registeredVariables(registeredVariablesArray), maxFillCount(maxFillCount) {}
|
||||
const size_t maxFillCount, bool serializeWithValidityBlob)
|
||||
: serializeWithValidityBlob(serializeWithValidityBlob),
|
||||
registeredVariables(registeredVariablesArray),
|
||||
maxFillCount(maxFillCount) {}
|
||||
|
||||
PoolDataSetBase::~PoolDataSetBase() {}
|
||||
PoolDataSetBase::~PoolDataSetBase() = default;
|
||||
|
||||
ReturnValue_t PoolDataSetBase::registerVariable(PoolVariableIF* variable) {
|
||||
if (registeredVariables == nullptr) {
|
||||
@@ -172,6 +176,9 @@ ReturnValue_t PoolDataSetBase::unlockDataPool() { return returnvalue::OK; }
|
||||
|
||||
ReturnValue_t PoolDataSetBase::serialize(uint8_t** buffer, size_t* size, const size_t maxSize,
|
||||
SerializeIF::Endianness streamEndianness) const {
|
||||
if (this->serializeWithValidityBlob) {
|
||||
return doSerializeWithValidityBlob(buffer, size, maxSize, streamEndianness);
|
||||
}
|
||||
ReturnValue_t result = returnvalue::FAILED;
|
||||
for (uint16_t count = 0; count < fillCount; count++) {
|
||||
result = registeredVariables[count]->serialize(buffer, size, maxSize, streamEndianness);
|
||||
@@ -182,6 +189,51 @@ ReturnValue_t PoolDataSetBase::serialize(uint8_t** buffer, size_t* size, const s
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t PoolDataSetBase::doSerializeWithValidityBlob(
|
||||
uint8_t** buffer, size_t* size, const size_t maxSize,
|
||||
SerializeIF::Endianness streamEndianness) const {
|
||||
ReturnValue_t result = returnvalue::FAILED;
|
||||
const uint8_t validityMaskSize = std::ceil(static_cast<float>(fillCount) / 8.0);
|
||||
uint8_t* validityPtr = nullptr;
|
||||
#if defined(_MSC_VER) || defined(__clang__)
|
||||
// Use a std::vector here because MSVC will (rightly) not create a fixed size array
|
||||
// with a non constant size specifier. The Apple compiler (LLVM) will not accept
|
||||
// the initialization of a variable sized array
|
||||
std::vector<uint8_t> validityMask(validityMaskSize, 0);
|
||||
validityPtr = validityMask.data();
|
||||
#else
|
||||
uint8_t validityMask[validityMaskSize] = {};
|
||||
validityPtr = validityMask;
|
||||
#endif
|
||||
uint8_t validBufferIndex = 0;
|
||||
uint8_t validBufferIndexBit = 0;
|
||||
for (uint16_t count = 0; count < fillCount; count++) {
|
||||
if (registeredVariables[count]->isValid()) {
|
||||
// Set bit at correct position
|
||||
bitutil::set(validityPtr + validBufferIndex, validBufferIndexBit);
|
||||
}
|
||||
if (validBufferIndexBit == 7) {
|
||||
validBufferIndex++;
|
||||
validBufferIndexBit = 0;
|
||||
} else {
|
||||
validBufferIndexBit++;
|
||||
}
|
||||
|
||||
result = registeredVariables[count]->serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (*size + validityMaskSize > maxSize) {
|
||||
return SerializeIF::BUFFER_TOO_SHORT;
|
||||
}
|
||||
// copy validity buffer to end
|
||||
std::memcpy(*buffer, validityPtr, validityMaskSize);
|
||||
*size += validityMaskSize;
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t PoolDataSetBase::deSerialize(const uint8_t** buffer, size_t* size,
|
||||
SerializeIF::Endianness streamEndianness) {
|
||||
ReturnValue_t result = returnvalue::FAILED;
|
||||
@@ -199,6 +251,9 @@ size_t PoolDataSetBase::getSerializedSize() const {
|
||||
for (uint16_t count = 0; count < fillCount; count++) {
|
||||
size += registeredVariables[count]->getSerializedSize();
|
||||
}
|
||||
if (serializeWithValidityBlob) {
|
||||
size += std::ceil(static_cast<float>(fillCount) / 8.0);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
@@ -215,3 +270,9 @@ void PoolDataSetBase::setReadCommitProtectionBehaviour(bool protectEveryReadComm
|
||||
this->timeoutTypeForSingleVars = timeoutType;
|
||||
this->mutexTimeoutForSingleVars = mutexTimeout;
|
||||
}
|
||||
|
||||
void PoolDataSetBase::setChildrenValidity(bool valid) {
|
||||
for (uint16_t count = 0; count < fillCount; count++) {
|
||||
registeredVariables[count]->setValid(valid);
|
||||
}
|
||||
}
|
||||
|
@@ -41,7 +41,8 @@ class PoolDataSetBase : public PoolDataSetIF, public SerializeIF {
|
||||
* supply a pointer to this dataset to PoolVariable
|
||||
* initializations to register pool variables.
|
||||
*/
|
||||
PoolDataSetBase(PoolVariableIF** registeredVariablesArray, size_t maxFillCount);
|
||||
PoolDataSetBase(PoolVariableIF** registeredVariablesArray, size_t maxFillCount,
|
||||
bool serializeWithValidityBlob = true);
|
||||
|
||||
/* Forbidden for now */
|
||||
PoolDataSetBase(const PoolDataSetBase& otherSet) = delete;
|
||||
@@ -115,13 +116,15 @@ class PoolDataSetBase : public PoolDataSetIF, public SerializeIF {
|
||||
|
||||
[[nodiscard]] uint16_t getFillCount() const override;
|
||||
|
||||
/* SerializeIF implementations */
|
||||
// SerializeIF implementations
|
||||
ReturnValue_t serialize(uint8_t** buffer, size_t* size, const size_t maxSize,
|
||||
SerializeIF::Endianness streamEndianness) const override;
|
||||
[[nodiscard]] size_t getSerializedSize() const override;
|
||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
SerializeIF::Endianness streamEndianness) override;
|
||||
|
||||
ReturnValue_t doSerializeWithValidityBlob(uint8_t** buffer, size_t* size, const size_t maxSize,
|
||||
SerializeIF::Endianness streamEndianness) const;
|
||||
/**
|
||||
* Can be used to individually protect every read and commit call.
|
||||
* @param protectEveryReadCommit
|
||||
@@ -131,6 +134,13 @@ class PoolDataSetBase : public PoolDataSetIF, public SerializeIF {
|
||||
bool protectEveryReadCommit, MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING,
|
||||
uint32_t mutexTimeout = 20);
|
||||
|
||||
/**
|
||||
* Set the validity of all children
|
||||
*/
|
||||
void setChildrenValidity(bool valid);
|
||||
|
||||
bool serializeWithValidityBlob = false;
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief The fill_count attribute ensures that the variables
|
||||
|
@@ -52,6 +52,16 @@ void* PoolEntry<T>::getRawData() {
|
||||
return this->address;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void PoolEntry<T>::setValid(bool isValid) {
|
||||
this->valid = isValid;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool PoolEntry<T>::getValid() {
|
||||
return valid;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void PoolEntry<T>::print() {
|
||||
const char* validString = nullptr;
|
||||
|
@@ -105,6 +105,17 @@ class PoolEntry : public PoolEntryIF {
|
||||
*/
|
||||
void* getRawData();
|
||||
|
||||
/**
|
||||
* @brief This method allows to set the valid information
|
||||
* of the pool entry.
|
||||
*/
|
||||
void setValid(bool isValid) override;
|
||||
/**
|
||||
* @brief This method allows to get the valid information
|
||||
* of the pool entry.
|
||||
*/
|
||||
bool getValid() override;
|
||||
|
||||
/**
|
||||
* @brief This is a debug method that prints all values and the valid
|
||||
* information to the screen. It prints all array entries in a row.
|
||||
|
@@ -51,6 +51,15 @@ class PoolEntryIF {
|
||||
* Returns the type of the entry.
|
||||
*/
|
||||
virtual Type getType() = 0;
|
||||
|
||||
/**
|
||||
* @brief This method allows to set the valid information of the pool entry.
|
||||
*/
|
||||
virtual void setValid(bool isValid) = 0;
|
||||
/**
|
||||
* @brief This method allows to set the valid information of the pool entry.
|
||||
*/
|
||||
virtual bool getValid() = 0;
|
||||
};
|
||||
|
||||
#endif /* FSFW_DATAPOOL_POOLENTRYIF_H_ */
|
||||
|
@@ -20,9 +20,9 @@ class PoolReadGuard {
|
||||
if (readResult != returnvalue::OK) {
|
||||
#if FSFW_VERBOSE_LEVEL == 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "PoolReadHelper: Read failed!" << std::endl;
|
||||
sif::error << "PoolReadGuard: Read failed!" << std::endl;
|
||||
#else
|
||||
sif::printError("PoolReadHelper: Read failed!\n");
|
||||
sif::printError("PoolReadGuard: Read failed!\n");
|
||||
#endif /* FSFW_PRINT_VERBOSITY_LEVEL == 1 */
|
||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
}
|
||||
|
@@ -210,6 +210,7 @@ inline ReturnValue_t PoolVariable<T>::readWithoutLock() {
|
||||
}
|
||||
|
||||
this->value = *(poolEntry->getDataPtr());
|
||||
this->valid = poolEntry->getValid();
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
@@ -241,6 +242,7 @@ ReturnValue_t PoolVariable<T>::commitWithoutLock() {
|
||||
}
|
||||
|
||||
*(poolEntry->getDataPtr()) = this->value;
|
||||
poolEntry->setValid(this->valid);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
|
@@ -47,6 +47,9 @@ class PoolVariableIF : public SerializeIF, public ReadCommitIF {
|
||||
* @brief This operation shall return the data pool id of the variable.
|
||||
*/
|
||||
virtual uint32_t getDataPoolId() const = 0;
|
||||
|
||||
virtual bool isValid() const = 0;
|
||||
virtual void setValid(bool valid) = 0;
|
||||
};
|
||||
|
||||
using pool_rwm_t = PoolVariableIF::ReadWriteMode_t;
|
||||
|
@@ -2,14 +2,17 @@
|
||||
|
||||
using namespace dp;
|
||||
|
||||
SharedSet::SharedSet(dp::SharedPool& sharedPool, uint32_t setId, const size_t maxNumberOfVariables)
|
||||
: SharedSetBase(sharedPool, setId, nullptr, maxNumberOfVariables),
|
||||
SharedSet::SharedSet(dp::SharedPool& sharedPool, uint32_t setId, const size_t maxNumberOfVariables,
|
||||
bool serializeWithValidityBlob)
|
||||
: SharedSetBase(sharedPool, setId, nullptr, maxNumberOfVariables, serializeWithValidityBlob),
|
||||
poolVarList(maxNumberOfVariables) {
|
||||
this->setContainer(poolVarList.data());
|
||||
}
|
||||
|
||||
SharedSet::SharedSet(dp::structure_id_t sid, const size_t maxNumberOfVariables)
|
||||
: SharedSetBase(sid, nullptr, maxNumberOfVariables), poolVarList(maxNumberOfVariables) {
|
||||
SharedSet::SharedSet(dp::structure_id_t sid, const size_t maxNumberOfVariables,
|
||||
bool serializeWithValidityBlob)
|
||||
: SharedSetBase(sid, nullptr, maxNumberOfVariables, serializeWithValidityBlob),
|
||||
poolVarList(maxNumberOfVariables) {
|
||||
this->setContainer(poolVarList.data());
|
||||
}
|
||||
|
||||
|
@@ -21,9 +21,10 @@ namespace datapool {
|
||||
*/
|
||||
class SharedSet : public SharedSetBase {
|
||||
public:
|
||||
SharedSet(SharedPool& sharedPool, uint32_t setId, size_t maxSize);
|
||||
SharedSet(SharedPool& sharedPool, uint32_t setId, size_t maxSize,
|
||||
bool serializeWithValidityBlob = true);
|
||||
|
||||
SharedSet(sid_t sid, size_t maxSize);
|
||||
SharedSet(sid_t sid, size_t maxSize, bool serializeWithValidityBlob = true);
|
||||
|
||||
~SharedSet() override;
|
||||
|
||||
|
@@ -14,8 +14,9 @@ using namespace datapool;
|
||||
|
||||
SharedSetBase::SharedSetBase(SharedPool &sharedPool, uint32_t setId,
|
||||
PoolVariableIF **registeredVariablesArray,
|
||||
const size_t maxNumberOfVariables)
|
||||
: base(registeredVariablesArray, maxNumberOfVariables), sharedPool(&sharedPool) {
|
||||
const size_t maxNumberOfVariables, bool serializeWithValidityBlob)
|
||||
: base(registeredVariablesArray, maxNumberOfVariables, serializeWithValidityBlob),
|
||||
sharedPool(&sharedPool) {
|
||||
mutexIfSingleDataCreator = sharedPool.getPoolMutex();
|
||||
|
||||
this->sid.objectId = sharedPool.getOwnerId();
|
||||
@@ -23,8 +24,8 @@ SharedSetBase::SharedSetBase(SharedPool &sharedPool, uint32_t setId,
|
||||
}
|
||||
|
||||
SharedSetBase::SharedSetBase(structure_id_t sid, PoolVariableIF **registeredVariablesArray,
|
||||
const size_t maxNumberOfVariables)
|
||||
: base(registeredVariablesArray, maxNumberOfVariables) {
|
||||
const size_t maxNumberOfVariables, bool serializeWithValidityBlob)
|
||||
: base(registeredVariablesArray, maxNumberOfVariables, serializeWithValidityBlob) {
|
||||
auto *hkOwner = ObjectManager::instance()->get<hk::GeneratesPeriodicHkIF>(sid.objectId);
|
||||
if (hkOwner != nullptr) {
|
||||
sharedPool = hkOwner->getOptionalSharedPool();
|
||||
@@ -37,8 +38,9 @@ SharedSetBase::SharedSetBase(structure_id_t sid, PoolVariableIF **registeredVari
|
||||
}
|
||||
|
||||
SharedSetBase::SharedSetBase(PoolVariableIF **registeredVariablesArray,
|
||||
const size_t maxNumberOfVariables, bool protectEveryReadCommitCall)
|
||||
: base(registeredVariablesArray, maxNumberOfVariables) {
|
||||
const size_t maxNumberOfVariables, bool protectEveryReadCommitCall,
|
||||
bool serializeWithValidityBlob)
|
||||
: base(registeredVariablesArray, maxNumberOfVariables, serializeWithValidityBlob) {
|
||||
base.setReadCommitProtectionBehaviour(protectEveryReadCommitCall);
|
||||
}
|
||||
|
||||
@@ -120,6 +122,8 @@ bool SharedSetBase::getReportingEnabled() const { return reportingEnabled; }
|
||||
|
||||
structure_id_t SharedSetBase::getStructureId() const { return sid; }
|
||||
|
||||
void SharedSetBase::setChildrenValidity(bool valid) { return base.setChildrenValidity(valid); }
|
||||
|
||||
object_id_t SharedSetBase::getCreatorObjectId() {
|
||||
if (sharedPool != nullptr) {
|
||||
return sharedPool->getOwnerId();
|
||||
@@ -136,10 +140,17 @@ void SharedSetBase::setAllVariablesReadOnly() {
|
||||
void SharedSetBase::printSet() { return; }
|
||||
|
||||
ReturnValue_t SharedSetBase::read(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
|
||||
return base.read(timeoutType, timeoutMs);
|
||||
lockDataPool(timeoutType, timeoutMs);
|
||||
ReturnValue_t result = base.read(timeoutType, timeoutMs);
|
||||
unlockDataPool();
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t SharedSetBase::commit(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs) {
|
||||
return base.commit(timeoutType, timeoutMs);
|
||||
lockDataPool(timeoutType, timeoutMs);
|
||||
ReturnValue_t result = base.commit(timeoutType, timeoutMs);
|
||||
unlockDataPool();
|
||||
return result;
|
||||
}
|
||||
uint16_t SharedSetBase::getFillCount() const { return base.getFillCount(); }
|
||||
|
||||
@@ -151,3 +162,8 @@ void SharedSetBase::setContainer(PoolVariableIF **variablesContainer) {
|
||||
return base.setContainer(variablesContainer);
|
||||
}
|
||||
PoolVariableIF **SharedSetBase::getContainer() const { return base.getContainer(); }
|
||||
|
||||
void SharedSetBase::updateValidityBlobSerialization(bool enable) {
|
||||
base.serializeWithValidityBlob = enable;
|
||||
}
|
||||
bool SharedSetBase::getValidityBlobSerialization() const { return base.serializeWithValidityBlob; }
|
||||
|
@@ -40,8 +40,6 @@ namespace datapool {
|
||||
* @ingroup data_pool
|
||||
*/
|
||||
class SharedSetBase : public SerializeIF, public PoolDataSetIF {
|
||||
// friend class PeriodicHousekeepingHelper;
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Constructor for the creator of local pool data.
|
||||
@@ -50,7 +48,7 @@ class SharedSetBase : public SerializeIF, public PoolDataSetIF {
|
||||
* periodic handling.
|
||||
*/
|
||||
SharedSetBase(SharedPool& sharedPool, uint32_t setId, PoolVariableIF** registeredVariablesArray,
|
||||
size_t maxNumberOfVariables);
|
||||
size_t maxNumberOfVariables, bool serializeWithValidityBlob = true);
|
||||
|
||||
/**
|
||||
* @brief Constructor for users of the local pool data, which need
|
||||
@@ -63,7 +61,8 @@ class SharedSetBase : public SerializeIF, public PoolDataSetIF {
|
||||
* @param registeredVariablesArray
|
||||
* @param maxNumberOfVariables
|
||||
*/
|
||||
SharedSetBase(sid_t sid, PoolVariableIF** registeredVariablesArray, size_t maxNumberOfVariables);
|
||||
SharedSetBase(sid_t sid, PoolVariableIF** registeredVariablesArray, size_t maxNumberOfVariables,
|
||||
bool serializeWithValidityBlob = true);
|
||||
|
||||
/**
|
||||
* @brief Simple constructor, if the dataset is not the owner by
|
||||
@@ -84,7 +83,7 @@ class SharedSetBase : public SerializeIF, public PoolDataSetIF {
|
||||
* commit calls separately.
|
||||
*/
|
||||
SharedSetBase(PoolVariableIF** registeredVariablesArray, size_t maxNumberOfVariables,
|
||||
bool protectEveryReadCommitCall = true);
|
||||
bool serializeWithValidityBlob, bool protectEveryReadCommitCall = true);
|
||||
|
||||
/**
|
||||
* @brief The destructor automatically manages writing the valid
|
||||
@@ -109,14 +108,14 @@ class SharedSetBase : public SerializeIF, public PoolDataSetIF {
|
||||
*/
|
||||
void setAllVariablesReadOnly();
|
||||
|
||||
[[nodiscard]] ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const override;
|
||||
[[nodiscard]] virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const override;
|
||||
|
||||
[[nodiscard]] ReturnValue_t serialize(uint8_t* buffer, size_t& serLen, size_t maxSize,
|
||||
SerializeIF::Endianness streamEndianness) const override;
|
||||
|
||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
Endianness streamEndianness) override;
|
||||
virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
Endianness streamEndianness) override;
|
||||
|
||||
[[nodiscard]] dp::sid_t getStructureId() const;
|
||||
|
||||
@@ -155,6 +154,14 @@ class SharedSetBase : public SerializeIF, public PoolDataSetIF {
|
||||
void setContainer(PoolVariableIF** variablesContainer);
|
||||
PoolVariableIF** getContainer() const;
|
||||
|
||||
/**
|
||||
* Set the validity of all children
|
||||
*/
|
||||
void setChildrenValidity(bool valid);
|
||||
|
||||
void updateValidityBlobSerialization(bool enable);
|
||||
bool getValidityBlobSerialization() const;
|
||||
|
||||
protected:
|
||||
PoolDataSetBase base;
|
||||
|
||||
@@ -169,12 +176,6 @@ class SharedSetBase : public SerializeIF, public PoolDataSetIF {
|
||||
|
||||
void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval);
|
||||
|
||||
/**
|
||||
* If the valid state of a dataset is always relevant to the whole
|
||||
* data set we can use this flag.
|
||||
*/
|
||||
bool valid = false;
|
||||
|
||||
/**
|
||||
* @brief This is a small helper function to facilitate locking
|
||||
* the global data pool.
|
||||
|
@@ -28,8 +28,9 @@ class StaticSharedSet : public datapool::SharedSetBase {
|
||||
* @param sharedPool Shared pool this dataset will read from or write to.
|
||||
* @param setId
|
||||
*/
|
||||
StaticSharedSet(SharedPool& sharedPool, const uint32_t setId)
|
||||
: SharedSetBase(sharedPool, setId, nullptr, NUM_VARIABLES) {
|
||||
StaticSharedSet(SharedPool& sharedPool, const uint32_t setId,
|
||||
bool serializeWithValidityBlob = true)
|
||||
: SharedSetBase(sharedPool, setId, nullptr, NUM_VARIABLES, serializeWithValidityBlob) {
|
||||
this->setContainer(poolVarList.data());
|
||||
}
|
||||
|
||||
@@ -37,7 +38,8 @@ class StaticSharedSet : public datapool::SharedSetBase {
|
||||
* Constructor used by data users like controllers.
|
||||
* @param sid
|
||||
*/
|
||||
explicit StaticSharedSet(const structure_id_t sid) : SharedSetBase(sid, nullptr, NUM_VARIABLES) {
|
||||
explicit StaticSharedSet(const structure_id_t sid, bool serializeWithValidityBlob = true)
|
||||
: SharedSetBase(sid, nullptr, NUM_VARIABLES, serializeWithValidityBlob) {
|
||||
this->setContainer(poolVarList.data());
|
||||
}
|
||||
|
||||
|
@@ -13,7 +13,7 @@ class DeviceHandlerThermalSet : public dp::StaticSharedSet<2> {
|
||||
: DeviceHandlerThermalSet(hkOwner->getObjectId(), cfg) {}
|
||||
|
||||
DeviceHandlerThermalSet(object_id_t deviceHandler, ThermalStateCfg cfg)
|
||||
: StaticSharedSet(dp::structure_id_t(deviceHandler, cfg.thermalSetId)),
|
||||
: StaticSharedSet(dp::structure_id_t(deviceHandler, cfg.thermalSetId), true),
|
||||
thermalStatePoolId(cfg.thermalStatePoolId),
|
||||
heaterRequestPoolId(cfg.thermalRequestPoolId) {}
|
||||
|
||||
|
@@ -190,4 +190,6 @@ ReturnValue_t FreshDeviceHandlerBase::getParameter(uint8_t domainId, uint8_t uni
|
||||
return INVALID_DOMAIN_ID;
|
||||
}
|
||||
|
||||
datapool::SharedPool* FreshDeviceHandlerBase::getOptionalSharedPool() { return nullptr; }
|
||||
datapool::SharedPool* FreshDeviceHandlerBase::getOptionalSharedPool() { return nullptr; }
|
||||
|
||||
ModeHelper& FreshDeviceHandlerBase::getModeHelper() { return this->modeHelper; }
|
@@ -26,6 +26,33 @@ struct DhbConfig {
|
||||
uint32_t msgQueueDepth = 10;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* This is a base class which can be used for handler classes which drive physical devices.
|
||||
*
|
||||
* @details
|
||||
* This class performs some boilerplate tasks to make it compatible to the FSFW ecosystem.
|
||||
* For example, it adds all required interfaces and helpers which are required for the majority
|
||||
* of physical devices:
|
||||
*
|
||||
* - SystemObject to become globally addressable
|
||||
* - HasModesIF and the ModeHelper: Expose modes. It is expected that most device handlers
|
||||
* use the default device handler modes OFF, ON and NORMAL at the very least.
|
||||
* - HasHealthIF, HealthHelper and a FDIR object: Physical devices can break down or require
|
||||
* power cycling as the most common FDIR reaction. The FDHB implements the necessary interface
|
||||
* and is also composed of a FDIR object which can set the health state to FAULTY or
|
||||
* NEEDS_RECOVERY to cause FDIR reactions.
|
||||
* - ModeTreeChildIF: Many device handlers are part of a mode tree.
|
||||
* - HasActionsIF and the ActionHelper: Most device handlers expose executable commands, for example
|
||||
* to re-configure the physical device or to poll data from the physical device.
|
||||
* - ReceivesParameterMessagesIF and the ParameterHelper: Most device handlers have tweakable
|
||||
* parameters.
|
||||
*
|
||||
* This class is used to extending it in a concrete device handler class and then implementing
|
||||
* all abstract methods. The abstract methods provide adaption points for users which were
|
||||
* deemed sufficient for most use-cases. The behaviour of the base-class can also be further
|
||||
* configured by implementing other virtual functions.
|
||||
*/
|
||||
class FreshDeviceHandlerBase : public SystemObject,
|
||||
public DeviceHandlerIF,
|
||||
public HasModesIF,
|
||||
@@ -41,7 +68,20 @@ class FreshDeviceHandlerBase : public SystemObject,
|
||||
~FreshDeviceHandlerBase() override;
|
||||
|
||||
/**
|
||||
* @brief
|
||||
* Periodic helper executed function, implemented by child class.
|
||||
*
|
||||
* @details
|
||||
* This will be called by the default performOperation call. This is the main adaption point
|
||||
* for the actual device handling logic. It is expected that the following common tasks are
|
||||
* performed in this method:
|
||||
*
|
||||
* 1. Performing periodic polling of the physical device in NORMAL mode. This is usually required
|
||||
* to poll housekeeping data from the device periodically.
|
||||
* 2. Handle on-going mode transitions if the mode transitions can only be handled asynchronously.
|
||||
* This might also involve communication with the physical device and power switch
|
||||
* handling/polling for transition to OFF or ON/NORMAL.
|
||||
* 3. Perform other periodic tasks which always need to be done irrespective of mode.
|
||||
*/
|
||||
virtual void performDeviceOperation(uint8_t opCode) = 0;
|
||||
|
||||
@@ -57,6 +97,11 @@ class FreshDeviceHandlerBase : public SystemObject,
|
||||
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF& parent) override;
|
||||
ModeTreeChildIF& getModeTreeChildIF() override;
|
||||
|
||||
/**
|
||||
* @brief Return an interface to the ModeHelper.
|
||||
*/
|
||||
ModeHelper& getModeHelper();
|
||||
|
||||
protected:
|
||||
ActionHelper actionHelper;
|
||||
ModeHelper modeHelper;
|
||||
@@ -89,13 +134,17 @@ class FreshDeviceHandlerBase : public SystemObject,
|
||||
|
||||
// Mode Helpers.
|
||||
virtual void modeChanged(Mode_t mode, Submode_t submode);
|
||||
|
||||
/**
|
||||
* This method is called when a mode message to set a new mode is received.
|
||||
*
|
||||
* The default implementation sets the new mode immediately. If this is not applicable for
|
||||
* certain modes, the user should provide a custom implementation, which performs roughly
|
||||
* the same functionality of this function, when all the steps have been taken to reach the
|
||||
* new mode.
|
||||
*/
|
||||
void startTransition(Mode_t mode, Submode_t submode) override;
|
||||
|
||||
virtual void setMode(Mode_t newMode, Submode_t newSubmode);
|
||||
virtual void setMode(Mode_t newMode);
|
||||
void getMode(Mode_t* mode, Submode_t* submode) override;
|
||||
@@ -104,12 +153,23 @@ class FreshDeviceHandlerBase : public SystemObject,
|
||||
// System Object overrides.
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
// Default implementation assumes that no optional shared pool is required.
|
||||
virtual datapool::SharedPool* getOptionalSharedPool();
|
||||
/**
|
||||
* This function is implemented to serialize a housekeeping packet when a HK message to
|
||||
* generate the packet is received, or periodic generation is necessary. The user should serialize
|
||||
* the HK set into the provided buffer, which will have the size specified in the set
|
||||
* specification.
|
||||
*/
|
||||
ReturnValue_t serializeHkDataset(dp::sid_t structureId, uint8_t* buf,
|
||||
size_t maxSize) override = 0;
|
||||
/**
|
||||
* This function is implemented by the user to specify the available housekeeping sets.
|
||||
*/
|
||||
ReturnValue_t specifyHkDatasets(std::vector<hk::SetSpecification>& setList) override = 0;
|
||||
|
||||
// Implemented by child, required for periodic HK.
|
||||
ReturnValue_t serializeHkDataset(dp::sid_t structureId, uint8_t* buf, size_t maxSize) = 0;
|
||||
ReturnValue_t specifyHkDatasets(std::vector<hk::SetSpecification>& setList) = 0;
|
||||
/*
|
||||
* If this device handler has an optional pool, return it. Otherwise, nullptr can be returned.
|
||||
*/
|
||||
datapool::SharedPool* getOptionalSharedPool() override = 0;
|
||||
|
||||
/**
|
||||
* Implemented by child class. Handle all command messages which are
|
||||
@@ -124,11 +184,33 @@ class FreshDeviceHandlerBase : public SystemObject,
|
||||
uint32_t* msToReachTheMode) override = 0;
|
||||
// Health Overrides.
|
||||
ReturnValue_t setHealth(HealthState health) override;
|
||||
// Action override. Forward to user.
|
||||
|
||||
/**
|
||||
* This is called when an ActionMessage is received to execute it.
|
||||
* @param actionId
|
||||
* @param commandedBy
|
||||
* @param data
|
||||
* @param size
|
||||
* @return
|
||||
*/
|
||||
ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
|
||||
const uint8_t* data, size_t size) override = 0;
|
||||
// Executable overrides.
|
||||
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
/**
|
||||
* This is the default periodic operation handler.
|
||||
*
|
||||
* Currently, it performs the following tasks:
|
||||
*
|
||||
* 1. Handle the message queue and all message types covered by the base class as specified
|
||||
* in the class documentation. It uses the composed helper classes for this.
|
||||
* 2. Poll the FDIR instance to check for failures. The FDIR works by checking all events
|
||||
* received by the FDHB. An FDIR reaction sets the health state of the FDHB, which might
|
||||
* in turn trigger FDIR reactions.
|
||||
* 3. Call the performDeviceOperation user hook.
|
||||
* 4. Handle periodic housekeeping data generation.
|
||||
* @param opCode
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
|
||||
/**
|
||||
* This calls the FDIR instance event trigger function.
|
||||
|
@@ -14,8 +14,6 @@ enum Severity : EventSeverity_t { INFO = 1, LOW = 2, MEDIUM = 3, HIGH = 4 };
|
||||
|
||||
} // namespace severity
|
||||
|
||||
#define MAKE_EVENT(id, severity) (((severity) << 16) + (SUBSYSTEM_ID * 100) + (id))
|
||||
|
||||
typedef uint32_t Event;
|
||||
|
||||
namespace event {
|
||||
@@ -24,11 +22,14 @@ constexpr EventId_t getEventId(Event event) { return (event & 0xFFFF); }
|
||||
|
||||
constexpr EventSeverity_t getSeverity(Event event) { return ((event >> 16) & 0xFF); }
|
||||
|
||||
constexpr Event makeEvent(uint8_t subsystemId, UniqueEventId_t uniqueEventId,
|
||||
EventSeverity_t eventSeverity) {
|
||||
template<uint8_t subsystemId, UniqueEventId_t uniqueEventId, EventSeverity_t eventSeverity>
|
||||
constexpr Event makeEvent() {
|
||||
static_assert(uniqueEventId < 100, "The unique event ID must be smaller than 100!");
|
||||
return (eventSeverity << 16) + (subsystemId * 100) + uniqueEventId;
|
||||
}
|
||||
|
||||
} // namespace event
|
||||
|
||||
#define MAKE_EVENT(id, severity) event::makeEvent<SUBSYSTEM_ID, id, severity>();
|
||||
|
||||
#endif /* EVENTOBJECT_EVENT_H_ */
|
||||
|
@@ -1,9 +1,4 @@
|
||||
#ifndef FSFW_INC_FSFW_HOUSEKEEPING_H_
|
||||
#define FSFW_INC_FSFW_HOUSEKEEPING_H_
|
||||
#pragma once
|
||||
|
||||
#include "src/core/housekeeping/HousekeepingMessage.h"
|
||||
#include "src/core/housekeeping/HousekeepingPacketDownlink.h"
|
||||
#include "src/core/housekeeping/HousekeepingSetPacket.h"
|
||||
#include "src/core/housekeeping/HousekeepingSnapshot.h"
|
||||
|
||||
#endif /* FSFW_INC_FSFW_HOUSEKEEPING_H_ */
|
||||
#include "fsfw/housekeeping/Dataset.h"
|
||||
#include "fsfw/housekeeping/DatasetElement.h"
|
128
src/fsfw/housekeeping/Dataset.h
Normal file
128
src/fsfw/housekeeping/Dataset.h
Normal file
@@ -0,0 +1,128 @@
|
||||
#pragma once
|
||||
|
||||
#include <cmath>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <vector>
|
||||
|
||||
#include "SerializableWithValidityIF.h"
|
||||
#include "definitions.h"
|
||||
#include "fsfw/globalfunctions/bitutility.h"
|
||||
|
||||
namespace hk {
|
||||
class Dataset : public SerializeIF {
|
||||
public:
|
||||
explicit Dataset(dp::structure_id_t sid, bool serializeWithValidityBlob = true)
|
||||
: serializeWithValidityBlob(serializeWithValidityBlob), sid(sid) {}
|
||||
|
||||
[[nodiscard]] dp::structure_id_t getStructureId() const { return sid; }
|
||||
|
||||
void addSerializable(const std::reference_wrapper<SerializableWithValidityIF> serializable) {
|
||||
serializables.push_back(serializable);
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t getNumberOfSerializables() const { return serializables.size(); }
|
||||
|
||||
[[nodiscard]] ReturnValue_t doSerializeWithValidityBlob(uint8_t **buffer, size_t *size,
|
||||
size_t maxSize,
|
||||
Endianness streamEndianness) const {
|
||||
ReturnValue_t result = returnvalue::FAILED;
|
||||
const uint8_t validityMaskSize = std::ceil(static_cast<float>(serializables.size()) / 8.0);
|
||||
uint8_t *validityPtr = nullptr;
|
||||
#if defined(_MSC_VER) || defined(__clang__)
|
||||
// Use a std::vector here because MSVC will (rightly) not create a fixed size array
|
||||
// with a non constant size specifier. The Apple compiler (LLVM) will not accept
|
||||
// the initialization of a variable sized array
|
||||
std::vector<uint8_t> validityMask(validityMaskSize, 0);
|
||||
validityPtr = validityMask.data();
|
||||
#else
|
||||
uint8_t validityMask[validityMaskSize] = {};
|
||||
validityPtr = validityMask;
|
||||
#endif
|
||||
uint8_t validBufferIndex = 0;
|
||||
uint8_t validBufferIndexBit = 0;
|
||||
for (auto &serializable : serializables) {
|
||||
if (serializable.get().isValid()) {
|
||||
// Set bit at correct position
|
||||
bitutil::set(validityPtr + validBufferIndex, validBufferIndexBit);
|
||||
}
|
||||
if (validBufferIndexBit == 7) {
|
||||
validBufferIndex++;
|
||||
validBufferIndexBit = 0;
|
||||
} else {
|
||||
validBufferIndexBit++;
|
||||
}
|
||||
|
||||
result = serializable.get().serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
if (*size + validityMaskSize > maxSize) {
|
||||
return SerializeIF::BUFFER_TOO_SHORT;
|
||||
}
|
||||
// copy validity buffer to end
|
||||
std::memcpy(*buffer, validityPtr, validityMaskSize);
|
||||
*size += validityMaskSize;
|
||||
*buffer += validityMaskSize;
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] ReturnValue_t serialize(uint8_t **buffer, size_t *size, size_t maxSize,
|
||||
Endianness streamEndianness) const override {
|
||||
if (serializeWithValidityBlob) {
|
||||
return doSerializeWithValidityBlob(buffer, size, maxSize, streamEndianness);
|
||||
}
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
for (auto &serializable : serializables) {
|
||||
result = serializable.get().serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] ReturnValue_t serialize(uint8_t *buffer, size_t &serSize, size_t maxSize,
|
||||
Endianness streamEndianness) const override {
|
||||
return SerializeIF::serialize(buffer, serSize, maxSize, streamEndianness);
|
||||
}
|
||||
|
||||
void setChildrenValidity(bool valid) {
|
||||
for (auto &serializable : serializables) {
|
||||
serializable.get().setValid(valid);
|
||||
}
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t getSerializedSize() const override {
|
||||
size_t size = 0;
|
||||
for (auto &serializable : serializables) {
|
||||
size += serializable.get().getSerializedSize();
|
||||
}
|
||||
if (serializeWithValidityBlob) {
|
||||
size += std::ceil(static_cast<float>(serializables.size()) / 8.0);
|
||||
}
|
||||
return size;
|
||||
}
|
||||
|
||||
ReturnValue_t deSerialize(const uint8_t **buffer, size_t *size,
|
||||
const Endianness streamEndianness) override {
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
for (auto &serializable : serializables) {
|
||||
result = serializable.get().deSerialize(buffer, size, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
bool serializeWithValidityBlob = false;
|
||||
|
||||
private:
|
||||
dp::structure_id_t sid;
|
||||
std::vector<std::reference_wrapper<SerializableWithValidityIF>> serializables;
|
||||
};
|
||||
|
||||
} // namespace hk
|
165
src/fsfw/housekeeping/DatasetElement.h
Normal file
165
src/fsfw/housekeeping/DatasetElement.h
Normal file
@@ -0,0 +1,165 @@
|
||||
#pragma once
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "Dataset.h"
|
||||
#include "SerializableWithValidityIF.h"
|
||||
#include "fsfw/serialize/SerializeAdapter.h"
|
||||
|
||||
namespace hk {
|
||||
|
||||
template <typename T>
|
||||
class ListVariable : public SerializableWithValidityIF {
|
||||
public:
|
||||
template <typename... Args>
|
||||
explicit ListVariable(Dataset& list, Args... args) : entry(std::forward<Args>(args)...) {
|
||||
list.addSerializable(*this);
|
||||
}
|
||||
explicit ListVariable(Dataset& list) : entry() { list.addSerializable(*this); }
|
||||
|
||||
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const override {
|
||||
return SerializeAdapter::serialize(&entry, buffer, size, maxSize, streamEndianness);
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t getSerializedSize() const override {
|
||||
return SerializeAdapter::getSerializedSize(&entry);
|
||||
}
|
||||
|
||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
Endianness streamEndianness) override {
|
||||
return SerializeAdapter::deSerialize(&entry, buffer, size, streamEndianness);
|
||||
}
|
||||
|
||||
explicit operator T() { return entry; }
|
||||
|
||||
ListVariable& operator=(T newValue) {
|
||||
entry = newValue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
[[nodiscard]] bool isValid() const override { return valid; };
|
||||
|
||||
void setValid(bool _valid) override { this->valid = _valid; }
|
||||
|
||||
T* operator->() { return &entry; }
|
||||
|
||||
T get() const { return entry; }
|
||||
|
||||
bool valid = false;
|
||||
T entry{};
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
using LVar = ListVariable<T>;
|
||||
|
||||
using lvar_u8 = LVar<uint8_t>;
|
||||
using lvar_u16 = LVar<uint16_t>;
|
||||
using lvar_u32 = LVar<uint32_t>;
|
||||
using lvar_u64 = LVar<uint64_t>;
|
||||
using lvar_i8 = LVar<int8_t>;
|
||||
using lvar_i16 = LVar<int16_t>;
|
||||
using lvar_i32 = LVar<int32_t>;
|
||||
using lvar_i64 = LVar<int64_t>;
|
||||
using lvar_f32 = LVar<float>;
|
||||
using lvar_f64 = LVar<double>;
|
||||
|
||||
template <typename T, size_t N>
|
||||
class ListVector : public SerializableWithValidityIF {
|
||||
public:
|
||||
template <typename... Args>
|
||||
explicit ListVector(Dataset& list, Args... args) : entry(std::forward<Args>(args)...) {
|
||||
list.addSerializable(*this);
|
||||
}
|
||||
explicit ListVector(Dataset& list) : entry() { list.addSerializable(*this); }
|
||||
|
||||
const T* get() const { return entry; }
|
||||
T* getMut() { return entry; }
|
||||
|
||||
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const override {
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
result = SerializeAdapter::serialize(entry + i, buffer, size, maxSize, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
[[nodiscard]] size_t getSerializedSize() const override {
|
||||
return SerializeAdapter::getSerializedSize(entry) * N;
|
||||
}
|
||||
|
||||
ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size,
|
||||
Endianness streamEndianness) override {
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
for (size_t i = 0; i < N; i++) {
|
||||
result = SerializeAdapter::deSerialize(entry + i, buffer, size, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
explicit operator T() { return entry; }
|
||||
|
||||
ListVector& operator=(T newValue[N]) {
|
||||
entry = newValue;
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Array subscript operator for access
|
||||
T& operator[](size_t index) {
|
||||
// No exceptions, so user takes care of index validation..
|
||||
return entry[index];
|
||||
}
|
||||
|
||||
const T& operator[](size_t index) const { return entry[index]; }
|
||||
|
||||
// Conversion operator
|
||||
explicit operator T*() { return entry; }
|
||||
explicit operator const T*() const { return entry; }
|
||||
|
||||
// Iterators for range-based for loops and STL compatibility
|
||||
T* begin() { return std::begin(entry); }
|
||||
T* end() { return std::end(entry); }
|
||||
const T* begin() const { return std::begin(entry); }
|
||||
const T* end() const { return std::end(entry); }
|
||||
const T* cbegin() const { return std::begin(entry); }
|
||||
const T* cend() const { return std::end(entry); }
|
||||
|
||||
[[nodiscard]] bool isValid() const override { return valid; };
|
||||
|
||||
void setValid(bool _valid) override { this->valid = _valid; }
|
||||
|
||||
// Additional utility methods
|
||||
[[nodiscard]] constexpr size_t size() const { return N; }
|
||||
|
||||
bool valid = false;
|
||||
T entry[N];
|
||||
};
|
||||
|
||||
template <typename T, size_t N>
|
||||
using LVec = ListVector<T, N>;
|
||||
|
||||
template <size_t N>
|
||||
using lvec_u8 = LVec<uint8_t, N>;
|
||||
template <size_t N>
|
||||
using lvec_u16 = LVec<uint16_t, N>;
|
||||
template <size_t N>
|
||||
using lvec_u32 = LVec<uint32_t, N>;
|
||||
template <size_t N>
|
||||
using lvec_i8 = LVec<int8_t, N>;
|
||||
template <size_t N>
|
||||
using lvec_i16 = LVec<int16_t, N>;
|
||||
template <size_t N>
|
||||
using lvec_i32 = LVec<int32_t, N>;
|
||||
template <size_t N>
|
||||
using lvec_f32 = LVec<float, N>;
|
||||
template <size_t N>
|
||||
using lvec_f64 = LVec<double, N>;
|
||||
|
||||
} // namespace hk
|
@@ -17,7 +17,7 @@ PeriodicHelper::PeriodicHelper(GeneratesPeriodicHkIF* owner, MessageQueueIF* que
|
||||
MessageQueueId_t hkDestQueue)
|
||||
: hkDestinationId(hkDestQueue) {
|
||||
if (owner == nullptr) {
|
||||
printWarningOrError(sif::OutputTypes::OUT_WARNING, "LocalDataPoolManager", returnvalue::FAILED,
|
||||
printWarningOrError(sif::OutputTypes::OUT_WARNING, "PeriodicHkHelper", returnvalue::FAILED,
|
||||
"Invalid supplied owner");
|
||||
return;
|
||||
}
|
||||
@@ -200,11 +200,10 @@ void PeriodicHelper::performPeriodicHkGeneration(SetSpecification& setSpec, time
|
||||
if (result != returnvalue::OK) {
|
||||
// Configuration error
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "LocalDataPoolManager::performPeriodicHkOperation: HK generation failed."
|
||||
sif::warning << "hk::PeriodicHelper::performPeriodicHkOperation: HK generation failed."
|
||||
<< std::endl;
|
||||
#else
|
||||
sif::printWarning(
|
||||
"LocalDataPoolManager::performPeriodicHkOperation: HK generation failed.\n");
|
||||
sif::printWarning("hk::PeriodicHelper::performPeriodicHkOperation: HK generation failed.\n");
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
10
src/fsfw/housekeeping/SerializableWithValidityIF.h
Normal file
10
src/fsfw/housekeeping/SerializableWithValidityIF.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "fsfw/serialize/SerializeIF.h"
|
||||
|
||||
class SerializableWithValidityIF : public SerializeIF {
|
||||
public:
|
||||
[[nodiscard]] virtual bool isValid() const = 0;
|
||||
|
||||
virtual void setValid(bool valid) = 0;
|
||||
};
|
@@ -10,15 +10,16 @@ class InternalErrorDataset : public dp::StaticSharedSet<4> {
|
||||
public:
|
||||
static constexpr uint8_t ERROR_SET_ID = 0;
|
||||
|
||||
InternalErrorDataset(dp::SharedPool& sharedPool) : StaticSharedSet(sharedPool, ERROR_SET_ID) {}
|
||||
InternalErrorDataset(dp::SharedPool& sharedPool)
|
||||
: StaticSharedSet(sharedPool, ERROR_SET_ID, false) {}
|
||||
|
||||
InternalErrorDataset(object_id_t objectId)
|
||||
: StaticSharedSet(dp::structure_id_t(objectId, ERROR_SET_ID)) {}
|
||||
: StaticSharedSet(dp::structure_id_t(objectId, ERROR_SET_ID), false) {}
|
||||
|
||||
dp::var_t<uint8_t> valid = dp::var_t<uint8_t>(sid.objectId, VALID, this);
|
||||
dp::var_t<uint32_t> tmHits = dp::var_t<uint32_t>(sid.objectId, TM_HITS, this);
|
||||
dp::var_t<uint32_t> queueHits = dp::var_t<uint32_t>(sid.objectId, QUEUE_HITS, this);
|
||||
dp::var_t<uint32_t> storeHits = dp::var_t<uint32_t>(sid.objectId, STORE_HITS, this);
|
||||
dp::var_t<uint8_t> valid = dp::var_t<uint8_t>(sid.objectId, VALID, this);
|
||||
};
|
||||
|
||||
#endif /* FSFW_INTERNALERROR_INTERNALERRORDATASET_H_ */
|
||||
|
@@ -35,8 +35,12 @@ ReturnValue_t ModeHelper::handleModeCommand(CommandMessage* command) {
|
||||
commandedMode = mode;
|
||||
commandedSubmode = submode;
|
||||
|
||||
if ((parentQueueId != MessageQueueIF::NO_QUEUE) &&
|
||||
(theOneWhoCommandedAMode != parentQueueId)) {
|
||||
// if (((parentQueueId != MessageQueueIF::NO_QUEUE) &&
|
||||
// (theOneWhoCommandedAMode != parentQueueId))) {
|
||||
// owner->setToExternalControl();
|
||||
// }
|
||||
|
||||
if(theOneWhoCommandedAMode != parentQueueId and theOneWhoCommandedAMode != powerswitchQueueId) {
|
||||
owner->setToExternalControl();
|
||||
}
|
||||
|
||||
@@ -106,3 +110,7 @@ bool ModeHelper::isTimedOut() { return countdown.hasTimedOut(); }
|
||||
bool ModeHelper::isForced() { return forced; }
|
||||
|
||||
void ModeHelper::setForced(bool forced) { this->forced = forced; }
|
||||
|
||||
void ModeHelper::setPowerSwitchQueueId(MessageQueueId_t queueId) {
|
||||
powerswitchQueueId = queueId;
|
||||
}
|
||||
|
@@ -21,10 +21,15 @@ class ModeHelper {
|
||||
|
||||
/**
|
||||
* @param parentQueue the Queue id of the parent object.
|
||||
* Set to 0 if no parent present
|
||||
* Set to MessageQueueIF::NO_QUEUE if no parent present
|
||||
*/
|
||||
void setParentQueue(MessageQueueId_t parentQueueId);
|
||||
|
||||
/**
|
||||
* Set to MessageQueue::NO_QUEUE if no powerswitch is commanding the obejct.
|
||||
*/
|
||||
void setPowerSwitchQueueId(MessageQueueId_t queueId);
|
||||
|
||||
ReturnValue_t initialize(MessageQueueId_t parentQueueId);
|
||||
|
||||
ReturnValue_t initialize(void);
|
||||
@@ -42,6 +47,7 @@ class ModeHelper {
|
||||
protected:
|
||||
HasModesIF *owner;
|
||||
MessageQueueId_t parentQueueId = MessageQueueIF::NO_QUEUE;
|
||||
MessageQueueId_t powerswitchQueueId = MessageQueueIF::NO_QUEUE;
|
||||
|
||||
Countdown countdown;
|
||||
|
||||
|
@@ -59,6 +59,9 @@ class MonitorBase : public MonitorReporter<T> {
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
if (not poolVariable.isValid()) {
|
||||
return MonitoringIF::INVALID;
|
||||
}
|
||||
*sample = poolVariable.value;
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
@@ -5,6 +5,7 @@
|
||||
|
||||
#include "FreeRTOS.h"
|
||||
#include "fsfw/globalfunctions/timevalOperations.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterfacePrinter.h"
|
||||
#include "fsfw/osal/freertos/Timekeeper.h"
|
||||
#include "task.h"
|
||||
|
||||
@@ -47,8 +48,8 @@ ReturnValue_t Clock::getClock(timeval* time) {
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::getClockMonotonic(timeval* time) {
|
||||
// TODO: I don't actually know if the timekeeper is monotonic..
|
||||
return getClock_timeval(time);
|
||||
*time = Timekeeper::instance()->getMonotonicClockOffset() + getUptime();
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t Clock::getUptime(timeval* uptime) {
|
||||
@@ -58,7 +59,7 @@ ReturnValue_t Clock::getUptime(timeval* uptime) {
|
||||
}
|
||||
|
||||
timeval Clock::getUptime() {
|
||||
TickType_t ticksSinceStart = xTaskGetTickCount();
|
||||
TickType_t ticksSinceStart = Timekeeper::instance()->getTicks();
|
||||
return Timekeeper::ticksToTimeval(ticksSinceStart);
|
||||
}
|
||||
|
||||
|
@@ -17,7 +17,13 @@ Timekeeper* Timekeeper::instance() {
|
||||
return myinstance;
|
||||
}
|
||||
|
||||
void Timekeeper::setOffset(const timeval& offset) { this->offset = offset; }
|
||||
void Timekeeper::setOffset(const timeval& offset) {
|
||||
if (not monotonicClockInitialized) {
|
||||
this->monotonicClockOffset = offset;
|
||||
monotonicClockInitialized = true;
|
||||
}
|
||||
this->offset = offset;
|
||||
}
|
||||
|
||||
timeval Timekeeper::ticksToTimeval(TickType_t ticks) {
|
||||
timeval uptime;
|
||||
@@ -33,3 +39,7 @@ timeval Timekeeper::ticksToTimeval(TickType_t ticks) {
|
||||
}
|
||||
|
||||
TickType_t Timekeeper::getTicks() { return xTaskGetTickCount(); }
|
||||
|
||||
const timeval Timekeeper::getMonotonicClockOffset() const {
|
||||
return monotonicClockOffset;
|
||||
}
|
||||
|
@@ -18,9 +18,14 @@ class Timekeeper {
|
||||
Timekeeper();
|
||||
|
||||
timeval offset;
|
||||
// Set when offset is initialized the first time
|
||||
timeval monotonicClockOffset;
|
||||
bool monotonicClockInitialized = false;
|
||||
|
||||
static Timekeeper* myinstance;
|
||||
|
||||
void setMonotonicClockOffset(const timeval& monotonicClockOffset);
|
||||
|
||||
public:
|
||||
static Timekeeper* instance();
|
||||
virtual ~Timekeeper();
|
||||
@@ -34,6 +39,7 @@ class Timekeeper {
|
||||
|
||||
const timeval& getOffset() const;
|
||||
void setOffset(const timeval& offset);
|
||||
const timeval getMonotonicClockOffset() const;
|
||||
};
|
||||
|
||||
#endif /* FRAMEWORK_OSAL_FREERTOS_TIMEKEEPER_H_ */
|
||||
|
@@ -60,14 +60,14 @@ ReturnValue_t Fuse::check() {
|
||||
set.read();
|
||||
if (!healthHelper.healthTable->isHealthy(getObjectId())) {
|
||||
setAllMonitorsToUnchecked();
|
||||
set.setValid = false;
|
||||
set.setChildrenValidity(false);
|
||||
return set.commit();
|
||||
}
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
checkFuseState();
|
||||
calculateFusePower();
|
||||
// Check if power is valid and if fuse state is off or invalid.
|
||||
if (!set.setValid.value || (set.state == 0)) {
|
||||
if (!set.power.isValid() || (set.state == 0) || !set.state.isValid()) {
|
||||
result = powerMonitor.setToInvalid();
|
||||
} else {
|
||||
float lowLimit = 0.0;
|
||||
@@ -87,7 +87,7 @@ ReturnValue_t Fuse::check() {
|
||||
ReturnValue_t Fuse::serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const {
|
||||
ReturnValue_t result = returnvalue::FAILED;
|
||||
for (DeviceList::const_iterator iter = devices.begin(); iter != devices.end(); iter++) {
|
||||
for (auto iter = devices.begin(); iter != devices.end(); iter++) {
|
||||
result = (*iter)->serialize(buffer, size, maxSize, streamEndianness);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
@@ -98,7 +98,7 @@ ReturnValue_t Fuse::serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
|
||||
size_t Fuse::getSerializedSize() const {
|
||||
uint32_t size = 0;
|
||||
for (DeviceList::const_iterator iter = devices.begin(); iter != devices.end(); iter++) {
|
||||
for (auto iter = devices.begin(); iter != devices.end(); iter++) {
|
||||
size += (*iter)->getSerializedSize();
|
||||
}
|
||||
return size;
|
||||
@@ -119,12 +119,12 @@ uint8_t Fuse::getFuseId() const { return fuseId; }
|
||||
|
||||
void Fuse::calculateFusePower() {
|
||||
ReturnValue_t result1 = currentLimit.check();
|
||||
if (result1 != returnvalue::OK || !(set.setValid.value)) {
|
||||
set.powerValid = false;
|
||||
if (result1 != returnvalue::OK || !(set.voltage.isValid())) {
|
||||
set.power.setValid(false);
|
||||
}
|
||||
// Calculate fuse power.
|
||||
set.power = set.current.value * set.voltage.value;
|
||||
set.powerValid = true;
|
||||
set.power.setValid(true);
|
||||
}
|
||||
|
||||
ReturnValue_t Fuse::performOperation(uint8_t opCode) {
|
||||
@@ -169,7 +169,7 @@ void Fuse::checkCommandQueue() {
|
||||
}
|
||||
|
||||
void Fuse::checkFuseState() {
|
||||
if (!set.setValid.value) {
|
||||
if (!set.state.isValid()) {
|
||||
oldFuseState = 0;
|
||||
return;
|
||||
}
|
||||
@@ -182,7 +182,7 @@ void Fuse::checkFuseState() {
|
||||
}
|
||||
|
||||
float Fuse::getPower() {
|
||||
if (set.powerValid.value) {
|
||||
if (set.power.isValid()) {
|
||||
return set.power.value;
|
||||
} else {
|
||||
return 0.0;
|
||||
@@ -191,8 +191,7 @@ float Fuse::getPower() {
|
||||
|
||||
void Fuse::setDataPoolEntriesInvalid() {
|
||||
set.read();
|
||||
set.setValid = false;
|
||||
set.powerValid = false;
|
||||
set.setChildrenValidity(false);
|
||||
set.commit();
|
||||
}
|
||||
|
||||
@@ -220,7 +219,7 @@ bool Fuse::areSwitchesOfComponentOn(DeviceList::iterator iter) {
|
||||
return true;
|
||||
}
|
||||
|
||||
bool Fuse::isPowerValid() { return set.powerValid.value; }
|
||||
bool Fuse::isPowerValid() { return set.power.isValid(); }
|
||||
|
||||
ReturnValue_t Fuse::setHealth(HealthState health) {
|
||||
healthHelper.setHealth(health);
|
||||
|
@@ -29,16 +29,14 @@ class FuseSet : public datapool::StaticSharedSet<6> {
|
||||
public:
|
||||
static constexpr uint8_t FUSE_SET_ID = 0;
|
||||
|
||||
FuseSet(dp::SharedPool &sharedPool) : StaticSharedSet(sharedPool, FUSE_SET_ID) {}
|
||||
FuseSet(dp::SharedPool &sharedPool) : StaticSharedSet(sharedPool, FUSE_SET_ID, true) {}
|
||||
|
||||
FuseSet(object_id_t objectId) : StaticSharedSet(dp::sid_t(objectId, FUSE_SET_ID)) {}
|
||||
FuseSet(object_id_t objectId) : StaticSharedSet(dp::sid_t(objectId, FUSE_SET_ID), true) {}
|
||||
|
||||
dp::f32_t voltage = dp::f32_t(sid.objectId, FusePoolId::VOLTAGE, this);
|
||||
dp::f32_t current = dp::f32_t(sid.objectId, FusePoolId::CURRENT, this);
|
||||
dp::u8_t state = dp::u8_t(sid.objectId, FusePoolId::STATE, this);
|
||||
dp::f32_t power = dp::f32_t(sid.objectId, FusePoolId::POWER, this);
|
||||
dp::u8_t powerValid = dp::u8_t(sid.objectId, FusePoolId::POWER_VALID, this);
|
||||
dp::u8_t setValid = dp::u8_t(sid.objectId, FusePoolId::SET_VALID, this);
|
||||
};
|
||||
|
||||
class Fuse : public SystemObject,
|
||||
|
@@ -21,10 +21,11 @@ class PowerSensorSet : public dp::StaticSharedSet<6> {
|
||||
public:
|
||||
static constexpr uint8_t POWER_SENSOR_SET_ID = 0;
|
||||
|
||||
PowerSensorSet(dp::SharedPool &sharedPool) : StaticSharedSet(sharedPool, POWER_SENSOR_SET_ID) {}
|
||||
PowerSensorSet(dp::SharedPool &sharedPool)
|
||||
: StaticSharedSet(sharedPool, POWER_SENSOR_SET_ID, true) {}
|
||||
|
||||
PowerSensorSet(object_id_t objectId)
|
||||
: StaticSharedSet(dp::sid_t(objectId, POWER_SENSOR_SET_ID)) {}
|
||||
: StaticSharedSet(dp::sid_t(objectId, POWER_SENSOR_SET_ID), true) {}
|
||||
|
||||
dp::f32_t current{sid.objectId, PowerSensorPoolId::CURRENT, this};
|
||||
dp::f32_t voltage{sid.objectId, PowerSensorPoolId::VOLTAGE, this};
|
||||
|
@@ -49,7 +49,7 @@ class Service11TelecommandScheduling final : public PusServiceBase {
|
||||
|
||||
//! [EXPORT] : [COMMENT] Deletion of a TC from the map failed.
|
||||
//! P1: First 32 bit of request ID, P2. Last 32 bit of Request ID
|
||||
static constexpr Event TC_DELETION_FAILED = event::makeEvent(SUBSYSTEM_ID, 0, severity::MEDIUM);
|
||||
static constexpr Event TC_DELETION_FAILED = event::makeEvent<SUBSYSTEM_ID, 0, severity::MEDIUM>();
|
||||
|
||||
// The types of PUS-11 subservices
|
||||
enum Subservice : uint8_t {
|
||||
|
@@ -68,6 +68,9 @@ class ListVector : public SerializeIF {
|
||||
}
|
||||
explicit ListVector(List& list) : entry() { list.addSerializable(*this); }
|
||||
|
||||
const T* get() const { return entry; }
|
||||
T* getMut() { return entry; }
|
||||
|
||||
ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize,
|
||||
Endianness streamEndianness) const override {
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
|
@@ -53,17 +53,17 @@ void fsfwPrint(sif::PrintLevel printType, const char *fmt, va_list arg) {
|
||||
#endif
|
||||
|
||||
if (printType == sif::PrintLevel::INFO_LEVEL) {
|
||||
len += sprintf(bufferPosition + len, "INFO");
|
||||
len += sprintf(bufferPosition + len, "INFO ");
|
||||
}
|
||||
if (printType == sif::PrintLevel::DEBUG_LEVEL) {
|
||||
len += sprintf(bufferPosition + len, "DEBUG");
|
||||
len += sprintf(bufferPosition + len, "DEBUG ");
|
||||
}
|
||||
if (printType == sif::PrintLevel::WARNING_LEVEL) {
|
||||
len += sprintf(bufferPosition + len, "WARNING");
|
||||
}
|
||||
|
||||
if (printType == sif::PrintLevel::ERROR_LEVEL) {
|
||||
len += sprintf(bufferPosition + len, "ERROR");
|
||||
len += sprintf(bufferPosition + len, "ERROR ");
|
||||
}
|
||||
|
||||
#if FSFW_COLORED_OUTPUT == 1
|
||||
@@ -75,7 +75,7 @@ void fsfwPrint(sif::PrintLevel printType, const char *fmt, va_list arg) {
|
||||
/*
|
||||
* Log current time to terminal if desired.
|
||||
*/
|
||||
len += sprintf(bufferPosition + len, " | %lu:%02lu:%02lu.%03lu | ", (unsigned long)now.hour,
|
||||
len += sprintf(bufferPosition + len, " | %02lu:%02lu:%02lu.%03lu | ", (unsigned long)now.hour,
|
||||
(unsigned long)now.minute, (unsigned long)now.second,
|
||||
(unsigned long)now.usecond / 1000);
|
||||
|
||||
|
@@ -64,6 +64,11 @@ void SubsystemBase::executeTable(HybridIterator<ModeListEntry> tableIter, Submod
|
||||
|
||||
for (; tableIter.value != nullptr; ++tableIter) {
|
||||
object_id_t object = tableIter.value->getObject();
|
||||
|
||||
// As default, the objectId in the commandTable is the same as the one in the childrenMap.
|
||||
// The user has to specify otherwise if required.
|
||||
object = commandObjectIdToChildrenMapObjectId(object);
|
||||
|
||||
if ((iter = childrenMap.find(object)) == childrenMap.end()) {
|
||||
// illegal table entry, should only happen due to misconfigured mode table
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
@@ -79,22 +84,36 @@ void SubsystemBase::executeTable(HybridIterator<ModeListEntry> tableIter, Submod
|
||||
}
|
||||
|
||||
if (healthHelper.healthTable->hasHealth(object)) {
|
||||
if (healthHelper.healthTable->isFaulty(object)) {
|
||||
ModeMessage::setModeMessage(&command, ModeMessage::CMD_MODE_COMMAND, HasModesIF::MODE_OFF,
|
||||
SUBMODE_NONE);
|
||||
} else {
|
||||
if (modeHelper.isForced()) {
|
||||
ModeMessage::setModeMessage(&command, ModeMessage::CMD_MODE_COMMAND_FORCED,
|
||||
tableIter.value->getMode(), submodeToCommand);
|
||||
} else {
|
||||
if (healthHelper.healthTable->isCommandable(object)) {
|
||||
|
||||
switch (healthHelper.healthTable->getHealth(object)) {
|
||||
case NEEDS_RECOVERY:
|
||||
case FAULTY:
|
||||
case PERMANENT_FAULTY:
|
||||
ModeMessage::setModeMessage(&command, ModeMessage::CMD_MODE_COMMAND, HasModesIF::MODE_OFF,
|
||||
SUBMODE_NONE);
|
||||
break;
|
||||
case HEALTHY:
|
||||
if (modeHelper.isForced()) {
|
||||
ModeMessage::setModeMessage(&command, ModeMessage::CMD_MODE_COMMAND_FORCED,
|
||||
tableIter.value->getMode(), submodeToCommand);
|
||||
} else {
|
||||
ModeMessage::setModeMessage(&command, ModeMessage::CMD_MODE_COMMAND,
|
||||
tableIter.value->getMode(), submodeToCommand);
|
||||
}
|
||||
break;
|
||||
case EXTERNAL_CONTROL:
|
||||
if (modeHelper.isForced()) {
|
||||
ModeMessage::setModeMessage(&command, ModeMessage::CMD_MODE_COMMAND_FORCED,
|
||||
tableIter.value->getMode(), submodeToCommand);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
break;
|
||||
default:
|
||||
// This never happens
|
||||
break;
|
||||
}
|
||||
|
||||
} else {
|
||||
ModeMessage::setModeMessage(&command, ModeMessage::CMD_MODE_COMMAND,
|
||||
tableIter.value->getMode(), submodeToCommand);
|
||||
@@ -105,7 +124,11 @@ void SubsystemBase::executeTable(HybridIterator<ModeListEntry> tableIter, Submod
|
||||
continue; // don't send redundant mode commands (produces event spam), but still command if
|
||||
// mode is forced to reach lower levels
|
||||
}
|
||||
ReturnValue_t result = commandQueue->sendMessage(iter->second.commandQueue, &command);
|
||||
|
||||
// Get the messageQueueId if the receiver specified by the commandTable.
|
||||
// This the same MessageQueueId as stored in the childrenMap if the commanded object is part of the childrenMap.
|
||||
MessageQueueId_t commandedReceiver = ObjectManager::instance()->get<HasHealthIF>(tableIter->getObject())->getCommandQueue();
|
||||
ReturnValue_t result = commandQueue->sendMessage(commandedReceiver, &command);
|
||||
if (result == returnvalue::OK) {
|
||||
++commandsOutstanding;
|
||||
}
|
||||
@@ -339,3 +362,7 @@ ReturnValue_t SubsystemBase::registerChild(object_id_t childObjectId, MessageQue
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
object_id_t SubsystemBase::commandObjectIdToChildrenMapObjectId(object_id_t commandId) {
|
||||
return commandId;
|
||||
}
|
||||
|
@@ -153,6 +153,15 @@ class SubsystemBase : public SystemObject,
|
||||
virtual void announceMode(bool recursive) override;
|
||||
|
||||
virtual void modeChanged();
|
||||
|
||||
/**
|
||||
* @brief This converts the objectId of the object we want to send a mode command to into the
|
||||
* objectId of the corresponding object in the childrenMap for the current mode command.
|
||||
* As default implementation, this is the same objectId, and this functions returns it's input value
|
||||
*
|
||||
* It is up to the user to specify otherwise.
|
||||
*/
|
||||
virtual object_id_t commandObjectIdToChildrenMapObjectId(object_id_t commandId);
|
||||
};
|
||||
|
||||
#endif /* FSFW_SUBSYSTEM_SUBSYSTEMBASE_H_ */
|
||||
|
@@ -25,7 +25,7 @@ static constexpr ReturnValue_t INCORRECT_SECONDARY_HEADER = MAKE_RETURN_CODE(11)
|
||||
|
||||
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::TMTC_DISTRIBUTION;
|
||||
//! P1: Returnvalue, P2: 0 for TM issues, 1 for TC issues
|
||||
static constexpr Event HANDLE_PACKET_FAILED = event::makeEvent(SUBSYSTEM_ID, 0, severity::LOW);
|
||||
static constexpr Event HANDLE_PACKET_FAILED = event::makeEvent<SUBSYSTEM_ID, 0, severity::LOW>();
|
||||
|
||||
}; // namespace tmtcdistrib
|
||||
#endif // FSFW_TMTCPACKET_DEFINITIONS_H
|
||||
|
@@ -142,7 +142,7 @@ class TemperatureSensor : public AbstractTemperatureSensor {
|
||||
|
||||
deltaTime = (uptime.tv_sec + uptime.tv_usec / 1000000.) -
|
||||
(uptimeOfOldTemperature.tv_sec + uptimeOfOldTemperature.tv_usec / 1000000.);
|
||||
deltaTemp = oldTemperature - outputTemperature;
|
||||
deltaTemp = oldTemperature - outputTemperature.value;
|
||||
if (deltaTemp < 0) {
|
||||
deltaTemp = -deltaTemp;
|
||||
}
|
||||
@@ -160,13 +160,13 @@ class TemperatureSensor : public AbstractTemperatureSensor {
|
||||
outputTemperature.setValid(PoolVariableIF::INVALID);
|
||||
outputTemperature = thermal::INVALID_TEMPERATURE;
|
||||
} else {
|
||||
oldTemperature = outputTemperature;
|
||||
oldTemperature = outputTemperature.value;
|
||||
uptimeOfOldTemperature = uptime;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
float getTemperature() { return outputTemperature; }
|
||||
float getTemperature() { return outputTemperature.value; }
|
||||
|
||||
bool isValid() { return outputTemperature.isValid(); }
|
||||
|
||||
|
@@ -192,6 +192,8 @@ class Clock {
|
||||
static MutexIF *timeMutex;
|
||||
static uint16_t leapSeconds;
|
||||
static bool leapSecondsSet;
|
||||
static bool monotonicClockInitialized;
|
||||
static timeval monotonicClockOffset;
|
||||
};
|
||||
|
||||
#endif /* FSFW_TIMEMANAGER_CLOCK_H_ */
|
||||
|
@@ -1,3 +1,4 @@
|
||||
target_sources(
|
||||
${FSFW_TEST_TGT} PRIVATE testLocalPoolVariable.cpp testLocalPoolVector.cpp
|
||||
testDataSet.cpp testPeriodicHkHelper.cpp)
|
||||
${FSFW_TEST_TGT}
|
||||
PRIVATE testLocalPoolVariable.cpp testLocalPoolVector.cpp testSharedSet.cpp
|
||||
testPeriodicHkHelper.cpp testDataset.cpp)
|
||||
|
85
unittests/datapool/testDataset.cpp
Normal file
85
unittests/datapool/testDataset.cpp
Normal file
@@ -0,0 +1,85 @@
|
||||
#include <fsfw/housekeeping/Dataset.h>
|
||||
#include <fsfw/housekeeping/DatasetElement.h>
|
||||
#include <fsfw/serialize/SerializeElement.h>
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
|
||||
constexpr auto TEST_ID = dp::structure_id_t(1, 2);
|
||||
|
||||
class TestDatasetSmall : public hk::Dataset {
|
||||
public:
|
||||
TestDatasetSmall() : hk::Dataset(TEST_ID, false) {}
|
||||
|
||||
hk::lvar_u8 test0{*this};
|
||||
hk::lvar_u32 test1{*this};
|
||||
};
|
||||
|
||||
class TestDatasetLarger : public hk::Dataset {
|
||||
public:
|
||||
TestDatasetLarger() : hk::Dataset(TEST_ID, false) {}
|
||||
|
||||
hk::lvar_u8 test0{*this};
|
||||
hk::lvar_u32 test1{*this};
|
||||
hk::lvar_u16 test2{*this};
|
||||
hk::lvar_i32 test3{*this};
|
||||
hk::lvar_f32 test4{*this};
|
||||
hk::lvar_f64 test5{*this};
|
||||
hk::lvar_u8 test6{*this};
|
||||
hk::lvar_i16 test7{*this};
|
||||
hk::lvec_u16<2> test8{*this};
|
||||
};
|
||||
|
||||
TEST_CASE("Pool Dataset Test", "[datapool]") {
|
||||
TestDatasetSmall dataset;
|
||||
CHECK(dataset.getStructureId() == TEST_ID);
|
||||
CHECK(!dataset.test0.isValid());
|
||||
dataset.test0.setValid(true);
|
||||
CHECK(dataset.test0.isValid());
|
||||
|
||||
SECTION("Pool Dataset Serialization Test 1") {
|
||||
uint8_t buf[64]{};
|
||||
dataset.test0 = 55;
|
||||
dataset.test1 = 502392;
|
||||
size_t serLen = 0;
|
||||
CHECK(dataset.serialize(buf, serLen, sizeof(buf), SerializeIF::Endianness::NETWORK) ==
|
||||
returnvalue::OK);
|
||||
CHECK(buf[0] == 55);
|
||||
CHECK(serLen == 5);
|
||||
uint32_t readBack = 0;
|
||||
size_t dummy = 0;
|
||||
CHECK(SerializeAdapter::deSerialize(&readBack, buf + 1, &dummy,
|
||||
SerializeIF::Endianness::NETWORK) == returnvalue::OK);
|
||||
CHECK(readBack == 502392);
|
||||
CHECK(buf[5] == 0);
|
||||
}
|
||||
|
||||
SECTION("Pool Dataset Serialization With Validity") {
|
||||
uint8_t buf[64]{};
|
||||
dataset.test0 = 55;
|
||||
dataset.test1 = 502392;
|
||||
dataset.test0.setValid(true);
|
||||
dataset.test1.setValid(true);
|
||||
size_t serLen = 0;
|
||||
uint8_t* dataPtr = buf;
|
||||
dataset.serializeWithValidityBlob = true;
|
||||
CHECK(dataset.getSerializedSize() == 6);
|
||||
CHECK(dataset.serialize(&dataPtr, &serLen, sizeof(buf), SerializeIF::Endianness::NETWORK) ==
|
||||
returnvalue::OK);
|
||||
CHECK(buf[5] == 0b11000000);
|
||||
}
|
||||
|
||||
SECTION("Larger Pool Dataset Serialization With Validity") {
|
||||
uint8_t buf[64]{};
|
||||
TestDatasetLarger datasetLarge;
|
||||
datasetLarge.setChildrenValidity(true);
|
||||
size_t serLen = 0;
|
||||
uint8_t* dataPtr = buf;
|
||||
datasetLarge.serializeWithValidityBlob = true;
|
||||
CHECK(datasetLarge.serialize(&dataPtr, &serLen, sizeof(buf),
|
||||
SerializeIF::Endianness::NETWORK) == returnvalue::OK);
|
||||
CHECK(serLen == 32);
|
||||
CHECK(buf[30] == 0b11111111);
|
||||
CHECK(buf[31] == 0b10000000);
|
||||
CHECK(buf[32] == 0);
|
||||
}
|
||||
}
|
@@ -14,7 +14,7 @@
|
||||
using namespace returnvalue;
|
||||
using namespace lpool;
|
||||
|
||||
TEST_CASE("DataSetTest", "[DataSetTest]") {
|
||||
TEST_CASE("DataSetTest", "[datapool]") {
|
||||
auto queue = MessageQueueMock(1, MessageQueueIF::NO_QUEUE);
|
||||
TestPoolOwner poolOwner(queue, objects::TEST_LOCAL_POOL_OWNER_BASE);
|
||||
poolOwner.initialize();
|
||||
@@ -23,6 +23,7 @@ TEST_CASE("DataSetTest", "[DataSetTest]") {
|
||||
SECTION("BasicTest") {
|
||||
/* Test some basic functions */
|
||||
CHECK(localSet.getReportingEnabled() == false);
|
||||
CHECK(localSet.getSerializedSize() == 11);
|
||||
CHECK(localSet.getLocalPoolIdsSerializedSize() == 3 * sizeof(dp::id_t));
|
||||
CHECK(localSet.getStructureId() == lpool::testSid1);
|
||||
CHECK(localSet.getCreatorObjectId() == objects::TEST_LOCAL_POOL_OWNER_BASE);
|
||||
@@ -57,17 +58,23 @@ TEST_CASE("DataSetTest", "[DataSetTest]") {
|
||||
PoolReadGuard readHelper(&localSet);
|
||||
REQUIRE(readHelper.getReadResult() == returnvalue::OK);
|
||||
CHECK(localSet.localPoolVarUint8.value == 0);
|
||||
CHECK(!localSet.localPoolVarUint8.isValid());
|
||||
CHECK(localSet.localPoolVarFloat.value == Catch::Approx(0.0));
|
||||
CHECK(!localSet.localPoolVarFloat.isValid());
|
||||
CHECK(localSet.localPoolUint16Vec.value[0] == 0);
|
||||
CHECK(localSet.localPoolUint16Vec.value[1] == 0);
|
||||
CHECK(localSet.localPoolUint16Vec.value[2] == 0);
|
||||
CHECK(!localSet.localPoolUint16Vec.isValid());
|
||||
|
||||
// Now set new values, commit should be done by read helper automatically
|
||||
localSet.localPoolVarUint8 = 232;
|
||||
localSet.localPoolVarUint8.setValid(true);
|
||||
localSet.localPoolVarFloat = -2324.322;
|
||||
localSet.localPoolVarFloat.setValid(true);
|
||||
localSet.localPoolUint16Vec.value[0] = 232;
|
||||
localSet.localPoolUint16Vec.value[1] = 23923;
|
||||
localSet.localPoolUint16Vec.value[2] = 1;
|
||||
localSet.localPoolUint16Vec.setValid(true);
|
||||
}
|
||||
|
||||
// Zero out some values for next test
|
||||
@@ -85,10 +92,13 @@ TEST_CASE("DataSetTest", "[DataSetTest]") {
|
||||
PoolReadGuard readHelper(&localSet);
|
||||
REQUIRE(readHelper.getReadResult() == returnvalue::OK);
|
||||
CHECK(localSet.localPoolVarUint8.value == 232);
|
||||
CHECK(localSet.localPoolVarUint8.isValid());
|
||||
CHECK(localSet.localPoolVarFloat.value == Catch::Approx(-2324.322));
|
||||
CHECK(localSet.localPoolVarFloat.isValid());
|
||||
CHECK(localSet.localPoolUint16Vec.value[0] == 232);
|
||||
CHECK(localSet.localPoolUint16Vec.value[1] == 23923);
|
||||
CHECK(localSet.localPoolUint16Vec.value[2] == 1);
|
||||
CHECK(localSet.localPoolUint16Vec.isValid());
|
||||
|
||||
// Now we serialize these values into a buffer without the validity buffer
|
||||
maxSize = localSet.getSerializedSize();
|
||||
@@ -129,7 +139,7 @@ TEST_CASE("DataSetTest", "[DataSetTest]") {
|
||||
|
||||
SECTION("SharedDataSet") {
|
||||
object_id_t sharedSetId = objects::SHARED_SET_ID;
|
||||
SharedSet sharedSet(poolOwner.sharedPool, sharedSetId, 5);
|
||||
SharedSet sharedSet(poolOwner.sharedPool, sharedSetId, 5, false);
|
||||
localSet.localPoolVarUint8.setReadWriteMode(pool_rwm_t::VAR_WRITE);
|
||||
localSet.localPoolUint16Vec.setReadWriteMode(pool_rwm_t::VAR_WRITE);
|
||||
CHECK(sharedSet.registerVariable(&localSet.localPoolVarUint8) == returnvalue::OK);
|
||||
@@ -145,4 +155,24 @@ TEST_CASE("DataSetTest", "[DataSetTest]") {
|
||||
CHECK(sharedSet.commit() == returnvalue::OK);
|
||||
}
|
||||
}
|
||||
|
||||
SECTION("Serialize with Validity Blob") {
|
||||
localSet.updateValidityBlobSerialization(true);
|
||||
CHECK(!localSet.localPoolVarUint8.isValid());
|
||||
CHECK(!localSet.localPoolUint16Vec.isValid());
|
||||
CHECK(!localSet.localPoolVarFloat.isValid());
|
||||
localSet.setChildrenValidity(true);
|
||||
CHECK(localSet.localPoolVarUint8.isValid());
|
||||
CHECK(localSet.localPoolUint16Vec.isValid());
|
||||
CHECK(localSet.localPoolVarFloat.isValid());
|
||||
size_t serSize = 0;
|
||||
// Already reserve additional space for validity buffer, will be needed later
|
||||
uint8_t buffer[128]{};
|
||||
uint8_t* buffPtr = buffer;
|
||||
CHECK(localSet.getSerializedSize() == 12);
|
||||
CHECK(localSet.serialize(&buffPtr, &serSize, sizeof(buffer),
|
||||
SerializeIF::Endianness::MACHINE) == returnvalue::OK);
|
||||
CHECK(serSize == 12);
|
||||
CHECK(buffer[11] == 0b11100000);
|
||||
}
|
||||
}
|
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include <fsfw/housekeeping/GeneratesPeriodicHkIF.h>
|
||||
#include <fsfw/housekeeping/PeriodicHkHelper.h>
|
||||
#include <fsfw/objectmanager/SystemObject.h>
|
||||
|
||||
#include "poolDefinitions.h"
|
||||
|
@@ -45,9 +45,10 @@ class Dataset : public List {
|
||||
|
||||
class StaticTestDataset : public StaticSharedSet<3> {
|
||||
public:
|
||||
StaticTestDataset() : StaticSharedSet(lpool::testSid1) {}
|
||||
StaticTestDataset() : StaticSharedSet(lpool::testSid1, false) {}
|
||||
|
||||
StaticTestDataset(SharedPool& sharedPool, uint32_t setId) : StaticSharedSet(sharedPool, setId) {}
|
||||
StaticTestDataset(SharedPool& sharedPool, uint32_t setId)
|
||||
: StaticSharedSet(sharedPool, setId, false) {}
|
||||
|
||||
u8_t localPoolVarUint8{lpool::uint8VarGpid, this};
|
||||
f32_t localPoolVarFloat{lpool::floatVarGpid, this};
|
||||
@@ -58,10 +59,10 @@ class StaticTestDataset : public StaticSharedSet<3> {
|
||||
|
||||
class TestDataset : public SharedSet {
|
||||
public:
|
||||
TestDataset() : SharedSet(lpool::testSid2, lpool::dataSetMaxVariables) {}
|
||||
TestDataset() : SharedSet(lpool::testSid2, lpool::dataSetMaxVariables, false) {}
|
||||
|
||||
TestDataset(SharedPool& sharedPool, uint32_t setId)
|
||||
: SharedSet(sharedPool, setId, lpool::dataSetMaxVariables) {}
|
||||
: SharedSet(sharedPool, setId, lpool::dataSetMaxVariables, false) {}
|
||||
|
||||
u8_t localPoolVarUint8{lpool::uint8VarGpid, this};
|
||||
f32_t localPoolVarFloat{lpool::floatVarGpid, this};
|
||||
|
Reference in New Issue
Block a user