fsfw/datapoollocal/LocalDataPoolManager.h

397 lines
14 KiB
C
Raw Normal View History

2020-09-26 15:35:10 +02:00
#ifndef FSFW_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_
#define FSFW_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_
2020-07-09 00:59:10 +02:00
2020-09-06 14:57:05 +02:00
#include "HasLocalDataPoolIF.h"
#include "../housekeeping/HousekeepingPacketDownlink.h"
2020-09-06 14:57:05 +02:00
#include "../housekeeping/HousekeepingMessage.h"
2020-09-19 15:58:34 +02:00
#include "../housekeeping/PeriodicHousekeepingHelper.h"
#include "../datapool/DataSetIF.h"
2020-09-06 14:57:05 +02:00
#include "../datapool/PoolEntry.h"
#include "../objectmanager/SystemObjectIF.h"
#include "../ipc/MutexIF.h"
#include "../ipc/CommandMessage.h"
#include "../ipc/MessageQueueIF.h"
#include "../ipc/MutexHelper.h"
2020-05-17 01:17:11 +02:00
#include <map>
2020-08-23 21:00:25 +02:00
namespace Factory {
void setStaticFrameworkObjectIds();
}
class LocalDataSetBase;
2020-11-03 23:23:05 +01:00
class HousekeepingPacketUpdate;
2020-08-23 21:00:25 +02:00
2020-06-07 02:22:18 +02:00
/**
2020-09-19 01:17:43 +02:00
* @brief This class is the managing instance for the local data pool.
2020-06-07 02:22:18 +02:00
* @details
* The actual data pool structure is a member of this class. Any class which
* has a local data pool shall have this manager class as a member and implement
2020-07-09 00:59:10 +02:00
* the HasLocalDataPoolIF.
2020-06-07 02:22:18 +02:00
*
* The manager offers some adaption points and functions which can be used
* by the owning class to simplify data handling significantly.
*
* Please ensure that both initialize and initializeAfterTaskCreation are
* called at some point by the owning class in the respective functions of the
* same name!
*
2020-06-07 02:22:18 +02:00
* Users of the data pool use the helper classes LocalDataSet,
* LocalPoolVariable and LocalPoolVector to access pool entries in
* a thread-safe and efficient way.
*
* The local data pools employ a blackboard logic: Only the most recent
* value is stored. The helper classes offer a read() and commit() interface
* through the PoolVariableIF which is used to read and update values.
* Each pool entry has a valid state too.
2020-09-19 01:17:43 +02:00
* @author R. Mueller
2020-06-07 02:22:18 +02:00
*/
class LocalDataPoolManager {
2020-11-18 21:15:14 +01:00
template<typename T> friend class LocalPoolVar;
template<typename T, uint16_t vecSize> friend class LocalPoolVector;
2020-11-18 21:15:48 +01:00
friend class LocalPoolDataSetBase;
2020-08-23 21:00:25 +02:00
friend void (Factory::setStaticFrameworkObjectIds)();
2020-05-17 01:17:11 +02:00
public:
2020-06-19 03:03:17 +02:00
static constexpr uint8_t INTERFACE_ID = CLASS_ID::HOUSEKEEPING_MANAGER;
2020-09-19 01:17:43 +02:00
static constexpr ReturnValue_t POOL_ENTRY_NOT_FOUND = MAKE_RETURN_CODE(0x00);
static constexpr ReturnValue_t POOL_ENTRY_TYPE_CONFLICT = MAKE_RETURN_CODE(0x01);
2020-06-19 03:03:17 +02:00
2020-09-19 01:17:43 +02:00
static constexpr ReturnValue_t QUEUE_OR_DESTINATION_NOT_SET = MAKE_RETURN_CODE(0x02);
2020-05-17 01:17:11 +02:00
2020-09-19 01:17:43 +02:00
static constexpr ReturnValue_t WRONG_HK_PACKET_TYPE = MAKE_RETURN_CODE(0x03);
static constexpr ReturnValue_t REPORTING_STATUS_UNCHANGED = MAKE_RETURN_CODE(0x04);
2020-09-19 17:14:09 +02:00
static constexpr ReturnValue_t PERIODIC_HELPER_INVALID = MAKE_RETURN_CODE(0x05);
2020-09-28 22:38:36 +02:00
2020-06-30 21:22:26 +02:00
/**
* This constructor is used by a class which wants to implement
* a personal local data pool. The queueToUse can be supplied if it
* is already known.
*
* initialize() has to be called in any case before using the object!
* @param owner
* @param queueToUse
* @param appendValidityBuffer Specify whether a buffer containing the
* validity state is generated when serializing or deserializing packets.
2020-06-30 21:22:26 +02:00
*/
2020-07-09 00:59:10 +02:00
LocalDataPoolManager(HasLocalDataPoolIF* owner, MessageQueueIF* queueToUse,
2020-06-30 21:22:26 +02:00
bool appendValidityBuffer = true);
2020-07-09 00:59:10 +02:00
virtual~ LocalDataPoolManager();
2020-06-30 21:22:26 +02:00
/**
* Assigns the queue to use. Make sure to call this in the #initialize
* function of the owner.
2020-06-30 21:22:26 +02:00
* @param queueToUse
2020-08-08 19:43:28 +02:00
* @param nonDiagInvlFactor See #setNonDiagnosticIntervalFactor doc
2020-06-30 21:22:26 +02:00
* @return
*/
2020-08-24 22:08:27 +02:00
ReturnValue_t initialize(MessageQueueIF* queueToUse);
2020-09-28 22:38:36 +02:00
/**
* Initializes the map by calling the map initialization function and
* setting the periodic factor for non-diagnostic packets.
* Don't forget to call this in the #initializeAfterTaskCreation call of
* the owner, otherwise the map will be invalid!
2020-09-28 22:38:36 +02:00
* @param nonDiagInvlFactor
* @return
*/
ReturnValue_t initializeAfterTaskCreation(
uint8_t nonDiagInvlFactor = 5);
2020-08-08 19:43:28 +02:00
2020-09-28 23:21:21 +02:00
/**
2020-10-14 00:50:24 +02:00
* @brief This should be called in the periodic handler of the owner.
* @details
* This in generally called in the #performOperation function of the owner.
2020-09-28 23:21:21 +02:00
* It performs all the periodic functionalities of the data pool manager,
* for example generating periodic HK packets.
* Marked virtual as an adaption point for custom data pool managers.
2020-09-28 23:21:21 +02:00
* @return
*/
virtual ReturnValue_t performHkOperation();
2020-09-28 23:21:21 +02:00
2020-08-23 23:24:48 +02:00
/**
2020-10-14 00:50:24 +02:00
* @brief Subscribe for the generation of periodic packets.
* @details
2020-10-14 16:46:00 +02:00
* This subscription mechanism will generally be used by the data creator
* to generate housekeeping packets which are downlinked directly.
2020-08-23 23:24:48 +02:00
* @return
*/
ReturnValue_t subscribeForPeriodicPacket(sid_t sid, bool enableReporting,
float collectionInterval, bool isDiagnostics,
object_id_t packetDestination = defaultHkDestination);
2020-10-14 00:50:24 +02:00
/**
* @brief Subscribe for the generation of packets if the dataset
* is marked as changed.
2020-10-14 16:46:00 +02:00
* @details
* This subscription mechanism will generally be used by the data creator.
2020-10-14 00:50:24 +02:00
* @param sid
* @param isDiagnostics
* @param packetDestination
* @return
*/
2020-10-14 12:42:30 +02:00
ReturnValue_t subscribeForUpdatePackets(sid_t sid, bool reportingEnabled,
bool isDiagnostics,
2020-10-14 00:50:24 +02:00
object_id_t packetDestination = defaultHkDestination);
/**
* @brief Subscribe for a notification message which will be sent
* if a dataset has changed.
2020-10-14 16:46:00 +02:00
* @details
* This subscription mechanism will generally be used internally by
* other software components.
* @param setId Set ID of the set to receive update messages from.
* @param destinationObject
2020-10-14 00:50:24 +02:00
* @param targetQueueId
2020-10-14 16:46:00 +02:00
* @param generateSnapshot If this is set to true, a copy of the current
* data with a timestamp will be generated and sent via message.
* Otherwise, only an notification message is sent.
2020-10-14 00:50:24 +02:00
* @return
*/
2020-10-14 16:46:00 +02:00
ReturnValue_t subscribeForSetUpdateMessages(const uint32_t setId,
object_id_t destinationObject,
MessageQueueId_t targetQueueId,
bool generateSnapshot);
2020-10-14 00:50:24 +02:00
/**
* @brief Subscribe for an notification message which will be sent if a
* pool variable has changed.
2020-10-14 16:46:00 +02:00
* @details
* This subscription mechanism will generally be used internally by
* other software components.
* @param localPoolId Pool ID of the pool variable
* @param destinationObject
2020-10-14 00:50:24 +02:00
* @param targetQueueId
2020-10-14 16:46:00 +02:00
* @param generateSnapshot If this is set to true, a copy of the current
* data with a timestamp will be generated and sent via message.
* Otherwise, only an notification message is sent.
2020-10-14 00:50:24 +02:00
* @return
*/
2020-10-14 16:46:00 +02:00
ReturnValue_t subscribeForVariableUpdateMessages(const lp_id_t localPoolId,
object_id_t destinationObject,
MessageQueueId_t targetQueueId,
bool generateSnapshot);
2020-10-14 00:50:24 +02:00
2020-08-08 19:43:28 +02:00
/**
* Non-Diagnostics packets usually have a lower minimum sampling frequency
* than diagnostic packets.
* A factor can be specified to determine the minimum sampling frequency
* for non-diagnostic packets. The minimum sampling frequency of the
* diagnostics packets,which is usually jusst the period of the
* performOperation calls, is multiplied with that factor.
* @param factor
*/
void setNonDiagnosticIntervalFactor(uint8_t nonDiagInvlFactor);
2020-07-09 16:31:33 +02:00
2020-10-14 00:50:24 +02:00
/**
* @brief The manager is also able to handle housekeeping messages.
* @details
* This most commonly is used to handle messages for the housekeeping
* interface, but the manager is also able to handle update notifications
* and calls a special function which can be overriden by a child class
* to handle data set or pool variable updates. This is relevant
* for classes like controllers which have their own local datapool
* but pull their data from other local datapools.
* @param message
* @return
*/
virtual ReturnValue_t handleHousekeepingMessage(CommandMessage* message);
2020-05-17 01:17:11 +02:00
2020-06-30 21:22:26 +02:00
/**
* Generate a housekeeping packet with a given SID.
* @param sid
* @return
*/
2020-08-24 22:08:27 +02:00
ReturnValue_t generateHousekeepingPacket(sid_t sid,
2020-09-19 01:17:43 +02:00
LocalPoolDataSetBase* dataSet, bool forDownlink,
MessageQueueId_t destination = MessageQueueIF::NO_QUEUE);
2020-09-28 21:09:56 +02:00
HasLocalDataPoolIF* getOwner();
2020-05-17 01:17:11 +02:00
2020-06-05 20:35:08 +02:00
ReturnValue_t printPoolEntry(lp_id_t localPoolId);
2020-07-09 00:59:10 +02:00
/**
* Different types of housekeeping reporting are possible.
2020-09-19 15:58:34 +02:00
* 1. PERIODIC:
* HK packets are generated in fixed intervals and sent to
2020-07-16 11:45:23 +02:00
* destination. Fromat will be raw.
2020-09-19 15:58:34 +02:00
* 2. UPDATE_NOTIFICATION:
* Notification will be sent out if HK data has changed.
* 3. UPDATE_SNAPSHOT:
* HK packets are only generated if explicitely requested.
2020-07-16 11:45:23 +02:00
* Propably not necessary, just use multiple local data sets or
* shared datasets.
2020-07-09 00:59:10 +02:00
*/
enum class ReportingType: uint8_t {
2020-08-23 21:52:44 +02:00
//! Periodic generation of HK packets.
2020-07-09 00:59:10 +02:00
PERIODIC,
//! Housekeeping packet will be generated if values have changed.
UPDATE_HK,
2020-08-23 21:52:44 +02:00
//! Update notification will be sent out as message.
2020-08-23 21:00:25 +02:00
UPDATE_NOTIFICATION,
2020-08-23 21:52:44 +02:00
//! Notification will be sent out as message and a snapshot of the
//! current data will be generated.
2020-08-23 21:00:25 +02:00
UPDATE_SNAPSHOT,
2020-07-09 00:59:10 +02:00
};
2020-09-19 15:58:34 +02:00
/**
* Different data types are possible in the HK receiver map.
* For example, updates can be requested for full datasets or
* for single pool variables. Periodic reporting is only possible for
* data sets.
*/
enum class DataType: uint8_t {
LOCAL_POOL_VARIABLE,
DATA_SET
};
2020-06-30 21:22:26 +02:00
/* Copying forbidden */
LocalDataPoolManager(const LocalDataPoolManager &) = delete;
LocalDataPoolManager operator=(const LocalDataPoolManager&) = delete;
2020-07-09 00:59:10 +02:00
2020-06-05 20:35:08 +02:00
private:
2020-07-09 00:59:10 +02:00
LocalDataPool localPoolMap;
2020-08-08 19:43:28 +02:00
//! Every housekeeping data manager has a mutex to protect access
//! to it's data pool.
2020-07-09 00:59:10 +02:00
MutexIF* mutex = nullptr;
2020-09-26 16:38:07 +02:00
2020-07-09 00:59:10 +02:00
/** The class which actually owns the manager (and its datapool). */
HasLocalDataPoolIF* owner = nullptr;
2020-08-08 19:43:28 +02:00
uint8_t nonDiagnosticIntervalFactor = 0;
2020-08-23 21:00:25 +02:00
/** Default receiver for periodic HK packets */
static object_id_t defaultHkDestination;
2020-09-19 01:17:43 +02:00
MessageQueueId_t hkDestinationId = MessageQueueIF::NO_QUEUE;
2020-08-23 21:00:25 +02:00
2020-10-14 12:42:30 +02:00
union DataId {
DataId(): sid() {};
sid_t sid;
lp_id_t localPoolId;
};
2020-08-08 19:43:28 +02:00
/** The data pool manager will keep an internal map of HK receivers. */
2020-07-09 00:59:10 +02:00
struct HkReceiver {
2020-09-19 15:58:34 +02:00
/** Object ID of receiver */
object_id_t objectId = objects::NO_OBJECT;
DataType dataType = DataType::DATA_SET;
2020-08-08 19:56:42 +02:00
DataId dataId;
2020-07-09 00:59:10 +02:00
ReportingType reportingType = ReportingType::PERIODIC;
2020-08-23 23:24:48 +02:00
MessageQueueId_t destinationQueue = MessageQueueIF::NO_QUEUE;
2020-07-09 00:59:10 +02:00
};
2020-09-19 15:58:34 +02:00
/** This vector will contain the list of HK receivers. */
using HkReceivers = std::vector<struct HkReceiver>;
2020-07-09 00:59:10 +02:00
2020-09-19 15:58:34 +02:00
HkReceivers hkReceiversMap;
2020-07-09 00:59:10 +02:00
2020-10-14 12:42:30 +02:00
struct HkUpdateResetHelper {
DataType dataType = DataType::DATA_SET;
DataId dataId;
uint8_t updateCounter;
uint8_t currentUpdateCounter;
};
using HkUpdateResetList = std::vector<struct HkUpdateResetHelper>;
// Will only be created when needed.
HkUpdateResetList* hkUpdateResetList = nullptr;
2020-07-09 00:59:10 +02:00
/** This is the map holding the actual data. Should only be initialized
* once ! */
bool mapInitialized = false;
/** This specifies whether a validity buffer is appended at the end
* of generated housekeeping packets. */
bool appendValidityBuffer = true;
2020-06-30 21:22:26 +02:00
/**
* @brief Queue used for communication, for example commands.
* Is also used to send messages. Can be set either in the constructor
* or in the initialize() function.
*/
2020-06-19 03:03:17 +02:00
MessageQueueIF* hkQueue = nullptr;
2020-06-30 21:22:26 +02:00
/** Global IPC store is used to store all packets. */
2020-06-07 18:53:55 +02:00
StorageManagerIF* ipcStore = nullptr;
2020-06-05 20:35:08 +02:00
/**
* Get the pointer to the mutex. Can be used to lock the data pool
2020-11-18 21:15:14 +01:00
* externally. Use with care and don't forget to unlock locked mutexes!
2020-06-05 20:35:08 +02:00
* For now, only friend classes can accss this function.
* @return
*/
MutexIF* getMutexHandle();
/**
* Read a variable by supplying its local pool ID and assign the pool
* entry to the supplied PoolEntry pointer. The type of the pool entry
* is deduced automatically. This call is not thread-safe!
* For now, only friend classes like LocalPoolVar may access this
* function.
* @tparam T Type of the pool entry
* @param localPoolId Pool ID of the variable to read
* @param poolVar [out] Corresponding pool entry will be assigned to the
* supplied pointer.
* @return
*/
2020-06-07 02:22:18 +02:00
template <class T> ReturnValue_t fetchPoolEntry(lp_id_t localPoolId,
PoolEntry<T> **poolEntry);
2020-06-05 20:35:08 +02:00
2020-10-14 00:50:24 +02:00
/**
* This function is used to fill the local data pool map with pool
* entries. It should only be called once by the pool owner.
* @param localDataPoolMap
* @return
*/
ReturnValue_t initializeHousekeepingPoolEntriesOnce();
ReturnValue_t serializeHkPacketIntoStore(
HousekeepingPacketDownlink& hkPacket,
store_address_t& storeId, bool forDownlink, size_t* serializedSize);
2020-08-08 19:43:28 +02:00
2020-09-19 15:58:34 +02:00
void performPeriodicHkGeneration(HkReceiver& hkReceiver);
2020-09-19 01:17:43 +02:00
ReturnValue_t togglePeriodicGeneration(sid_t sid, bool enable,
bool isDiagnostics);
ReturnValue_t changeCollectionInterval(sid_t sid,
float newCollectionInterval, bool isDiagnostics);
2020-09-19 15:58:34 +02:00
ReturnValue_t generateSetStructurePacket(sid_t sid, bool isDiagnostics);
2020-10-14 12:42:30 +02:00
void handleHkUpdateResetListInsertion(DataType dataType, DataId dataId);
void handleChangeResetLogic(DataType type,
DataId dataId, MarkChangedIF* toReset);
void resetHkUpdateResetHelper();
2020-11-03 15:28:55 +01:00
ReturnValue_t handleHkUpdate(HkReceiver& hkReceiver,
ReturnValue_t& status);
ReturnValue_t handleNotificationUpdate(HkReceiver& hkReceiver,
ReturnValue_t& status);
ReturnValue_t handleNotificationSnapshot(HkReceiver& hkReceiver,
ReturnValue_t& status);
2020-11-03 23:23:05 +01:00
ReturnValue_t addUpdateToStore(HousekeepingPacketUpdate& updatePacket,
store_address_t& storeId);
2020-05-17 01:17:11 +02:00
};
2020-06-07 02:22:18 +02:00
2020-05-17 01:17:11 +02:00
template<class T> inline
2020-06-07 02:22:18 +02:00
ReturnValue_t LocalDataPoolManager::fetchPoolEntry(lp_id_t localPoolId,
2020-06-05 20:35:08 +02:00
PoolEntry<T> **poolEntry) {
2020-07-09 00:59:10 +02:00
auto poolIter = localPoolMap.find(localPoolId);
if (poolIter == localPoolMap.end()) {
sif::warning << "HousekeepingManager::fechPoolEntry: Pool entry "
"not found." << std::endl;
2020-06-19 03:03:17 +02:00
return POOL_ENTRY_NOT_FOUND;
2020-05-17 01:17:11 +02:00
}
2020-06-05 20:35:08 +02:00
*poolEntry = dynamic_cast< PoolEntry<T>* >(poolIter->second);
if(*poolEntry == nullptr) {
sif::debug << "HousekeepingManager::fetchPoolEntry:"
" Pool entry not found." << std::endl;
2020-06-19 03:03:17 +02:00
return POOL_ENTRY_TYPE_CONFLICT;
2020-05-17 01:17:11 +02:00
}
return HasReturnvaluesIF::RETURN_OK;
}
2020-06-05 20:35:08 +02:00
2020-09-26 15:35:10 +02:00
#endif /* FSFW_DATAPOOLLOCAL_LOCALDATAPOOLMANAGER_H_ */