Merge branch 'development' into mueller/cmake-init

This commit is contained in:
Steffen Gaisser 2020-12-10 17:23:09 +01:00
commit 03cc343527
66 changed files with 2558 additions and 1382 deletions

View File

@ -15,6 +15,35 @@ a C file without issues
- The same is possible for the event reporting service (PUS5)
- PUS Health Service added, which allows to command and retrieve health via PUS packets
### Local Pool
- Interface of LocalPools has changed. LocalPool is not a template anymore. Instead the size and bucket number of the pools per page and the number of pages are passed to the ctor instead of two ctor arguments and a template parameter
### Parameter Service
- The API of the parameter service has been changed to prevent inconsistencies
between documentation and actual code and to clarify usage.
- The parameter ID now consists of:
1. Domain ID (1 byte)
2. Unique Identifier (1 byte)
3. Linear Index (2 bytes)
The linear index can be used for arrays as well as matrices.
The parameter load command now explicitely expects the ECSS PTC and PFC
information as well as the rows and column number. Rows and column will
default to one, which is equivalent to one scalar parameter (the most
important use-case)
### File System Interface
- A new interfaces specifies the functions for a software object which exposes the file system of a given hardware to use message based file handling (e.g. PUS commanding)
### Internal Error Reporter
- The new internal error reporter uses the local data pools. The pool IDs for
the exisiting three error values and the new error set will be hardcoded for
now, the the constructor for the internal error reporter just takes an object
ID for now.
### Device Handler Base
- There is an additional `PERFORM_OPERATION` step for the device handler base. It is important

View File

@ -1,16 +1,16 @@
#include "../subsystem/SubsystemBase.h"
#include "ControllerBase.h"
#include "../subsystem/SubsystemBase.h"
#include "../ipc/QueueFactory.h"
#include "../action/HasActionsIF.h"
ControllerBase::ControllerBase(uint32_t setObjectId, uint32_t parentId,
ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId,
size_t commandQueueDepth) :
SystemObject(setObjectId), parentId(parentId), mode(MODE_OFF), submode(
SUBMODE_NONE), commandQueue(NULL), modeHelper(
this), healthHelper(this, setObjectId),hkSwitcher(this),executingTask(NULL) {
commandQueue = QueueFactory::instance()->createMessageQueue(commandQueueDepth);
SystemObject(setObjectId), parentId(parentId), mode(MODE_OFF),
submode(SUBMODE_NONE), modeHelper(this),
healthHelper(this, setObjectId) {
commandQueue = QueueFactory::instance()->createMessageQueue(
commandQueueDepth);
}
ControllerBase::~ControllerBase() {
@ -24,9 +24,9 @@ ReturnValue_t ControllerBase::initialize() {
}
MessageQueueId_t parentQueue = 0;
if (parentId != 0) {
if (parentId != objects::NO_OBJECT) {
SubsystemBase *parent = objectManager->get<SubsystemBase>(parentId);
if (parent == NULL) {
if (parent == nullptr) {
return RETURN_FAILED;
}
parentQueue = parent->getCommandQueue();
@ -44,10 +44,6 @@ ReturnValue_t ControllerBase::initialize() {
return result;
}
result = hkSwitcher.initialize();
if (result != RETURN_OK) {
return result;
}
return RETURN_OK;
}
@ -56,26 +52,27 @@ MessageQueueId_t ControllerBase::getCommandQueue() const {
}
void ControllerBase::handleQueue() {
CommandMessage message;
ReturnValue_t result;
for (result = commandQueue->receiveMessage(&message); result == RETURN_OK;
result = commandQueue->receiveMessage(&message)) {
CommandMessage command;
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
for (result = commandQueue->receiveMessage(&command);
result == RETURN_OK;
result = commandQueue->receiveMessage(&command)) {
result = modeHelper.handleModeCommand(&message);
result = modeHelper.handleModeCommand(&command);
if (result == RETURN_OK) {
continue;
}
result = healthHelper.handleHealthCommand(&message);
result = healthHelper.handleHealthCommand(&command);
if (result == RETURN_OK) {
continue;
}
result = handleCommandMessage(&message);
result = handleCommandMessage(&command);
if (result == RETURN_OK) {
continue;
}
message.setToUnknownCommand();
commandQueue->reply(&message);
command.setToUnknownCommand();
commandQueue->reply(&command);
}
}
@ -106,7 +103,6 @@ void ControllerBase::announceMode(bool recursive) {
ReturnValue_t ControllerBase::performOperation(uint8_t opCode) {
handleQueue();
hkSwitcher.performOperation();
performControlOperation();
return RETURN_OK;
}
@ -135,3 +131,7 @@ void ControllerBase::setTaskIF(PeriodicTaskIF* task_){
void ControllerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) {
}
ReturnValue_t ControllerBase::initializeAfterTaskCreation() {
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,5 +1,5 @@
#ifndef CONTROLLERBASE_H_
#define CONTROLLERBASE_H_
#ifndef FSFW_CONTROLLER_CONTROLLERBASE_H_
#define FSFW_CONTROLLER_CONTROLLERBASE_H_
#include "../health/HasHealthIF.h"
#include "../health/HealthHelper.h"
@ -7,73 +7,88 @@
#include "../modes/ModeHelper.h"
#include "../objectmanager/SystemObject.h"
#include "../tasks/ExecutableObjectIF.h"
#include "../tasks/PeriodicTaskIF.h"
#include "../datapool/HkSwitchHelper.h"
/**
* @brief Generic base class for controller classes
* @details
* Implements common interfaces for controllers, which generally have
* a mode and a health state. This avoids boilerplate code.
*/
class ControllerBase: public HasModesIF,
public HasHealthIF,
public ExecutableObjectIF,
public SystemObject,
public HasReturnvaluesIF {
public:
static const Mode_t MODE_NORMAL = 2;
ControllerBase(uint32_t setObjectId, uint32_t parentId,
ControllerBase(object_id_t setObjectId, object_id_t parentId,
size_t commandQueueDepth = 3);
virtual ~ControllerBase();
ReturnValue_t initialize();
/** SystemObject override */
virtual ReturnValue_t initialize() override;
virtual MessageQueueId_t getCommandQueue() const;
virtual MessageQueueId_t getCommandQueue() const override;
virtual ReturnValue_t performOperation(uint8_t opCode);
virtual ReturnValue_t setHealth(HealthState health);
virtual HasHealthIF::HealthState getHealth();
/**
* Implementation of ExecutableObjectIF function
*
* Used to setup the reference of the task, that executes this component
* @param task_ Pointer to the taskIF of this task
*/
virtual void setTaskIF(PeriodicTaskIF* task_);
/** HasHealthIF overrides */
virtual ReturnValue_t setHealth(HealthState health) override;
virtual HasHealthIF::HealthState getHealth() override;
/** ExecutableObjectIF overrides */
virtual ReturnValue_t performOperation(uint8_t opCode) override;
virtual void setTaskIF(PeriodicTaskIF* task) override;
virtual ReturnValue_t initializeAfterTaskCreation() override;
protected:
const uint32_t parentId;
/**
* Implemented by child class. Handle command messages which are not
* mode or health messages.
* @param message
* @return
*/
virtual ReturnValue_t handleCommandMessage(CommandMessage *message) = 0;
/**
* Periodic helper, implemented by child class.
*/
virtual void performControlOperation() = 0;
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode) = 0;
const object_id_t parentId;
Mode_t mode;
Submode_t submode;
MessageQueueIF* commandQueue;
MessageQueueIF* commandQueue = nullptr;
ModeHelper modeHelper;
HealthHelper healthHelper;
HkSwitchHelper hkSwitcher;
/**
* Pointer to the task which executes this component, is invalid before setTaskIF was called.
* Pointer to the task which executes this component,
* is invalid before setTaskIF was called.
*/
PeriodicTaskIF* executingTask;
PeriodicTaskIF* executingTask = nullptr;
void handleQueue();
/** Handle mode and health messages */
virtual void handleQueue();
virtual ReturnValue_t handleCommandMessage(CommandMessage *message) = 0;
virtual void performControlOperation() = 0;
virtual ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t *msToReachTheMode) = 0;
/** Mode helpers */
virtual void modeChanged(Mode_t mode, Submode_t submode);
virtual void startTransition(Mode_t mode, Submode_t submode);
virtual void getMode(Mode_t *mode, Submode_t *submode);
virtual void setToExternalControl();
virtual void announceMode(bool recursive);
/** HK helpers */
virtual void changeHK(Mode_t mode, Submode_t submode, bool enable);
};
#endif /* CONTROLLERBASE_H_ */
#endif /* FSFW_CONTROLLER_CONTROLLERBASE_H_ */

View File

@ -1,10 +1,3 @@
/**
* @file MapPacketExtraction.cpp
* @brief This file defines the MapPacketExtraction class.
* @date 26.03.2013
* @author baetz
*/
#include "MapPacketExtraction.h"
#include "../ipc/QueueFactory.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
@ -12,14 +5,14 @@
#include "../tmtcpacket/SpacePacketBase.h"
#include "../tmtcservices/AcceptsTelecommandsIF.h"
#include "../tmtcservices/TmTcMessage.h"
#include <string.h>
#include <cstring>
MapPacketExtraction::MapPacketExtraction(uint8_t setMapId,
object_id_t setPacketDestination) :
lastSegmentationFlag(NO_SEGMENTATION), mapId(setMapId), packetLength(0), bufferPosition(
packetBuffer), packetDestination(setPacketDestination), packetStore(
NULL), tcQueueId(MessageQueueIF::NO_QUEUE) {
memset(packetBuffer, 0, sizeof(packetBuffer));
lastSegmentationFlag(NO_SEGMENTATION), mapId(setMapId),
bufferPosition(packetBuffer), packetDestination(setPacketDestination),
tcQueueId(MessageQueueIF::NO_QUEUE) {
std::memset(packetBuffer, 0, sizeof(packetBuffer));
}
ReturnValue_t MapPacketExtraction::extractPackets(TcTransferFrame* frame) {

View File

@ -1,12 +1,5 @@
/**
* @file MapPacketExtraction.h
* @brief This file defines the MapPacketExtraction class.
* @date 26.03.2013
* @author baetz
*/
#ifndef MAPPACKETEXTRACTION_H_
#define MAPPACKETEXTRACTION_H_
#ifndef FSFW_DATALINKLAYER_MAPPACKETEXTRACTION_H_
#define FSFW_DATALINKLAYER_MAPPACKETEXTRACTION_H_
#include "MapPacketExtractionIF.h"
#include "../objectmanager/ObjectManagerIF.h"
@ -20,17 +13,19 @@ class StorageManagerIF;
* The class implements the full MAP Packet Extraction functionality as described in the CCSDS
* TC Space Data Link Protocol. It internally stores incomplete segmented packets until they are
* fully received. All found packets are forwarded to a single distribution entity.
* @author B. Baetz
*/
class MapPacketExtraction: public MapPacketExtractionIF {
private:
static const uint32_t MAX_PACKET_SIZE = 4096;
uint8_t lastSegmentationFlag; //!< The segmentation flag of the last received frame.
uint8_t mapId; //!< MAP ID of this MAP Channel.
uint32_t packetLength; //!< Complete length of the current Space Packet.
uint32_t packetLength = 0; //!< Complete length of the current Space Packet.
uint8_t* bufferPosition; //!< Position to write to in the internal Packet buffer.
uint8_t packetBuffer[MAX_PACKET_SIZE]; //!< The internal Space Packet Buffer.
object_id_t packetDestination;
StorageManagerIF* packetStore; //!< Pointer to the store where full TC packets are stored.
//!< Pointer to the store where full TC packets are stored.
StorageManagerIF* packetStore = nullptr;
MessageQueueId_t tcQueueId; //!< QueueId to send found packets to the distributor.
/**
* Debug method to print the packet Buffer's content.
@ -75,4 +70,4 @@ public:
uint8_t getMapId() const;
};
#endif /* MAPPACKETEXTRACTION_H_ */
#endif /* FSFW_DATALINKLAYER_MAPPACKETEXTRACTION_H_ */

View File

@ -3,8 +3,6 @@
#include "DeviceTmReportingWrapper.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
#include "../datapoolglob/GlobalDataSet.h"
#include "../datapoolglob/GlobalPoolVariable.h"
#include "../objectmanager/ObjectManager.h"
#include "../storagemanager/StorageManagerIF.h"
#include "../thermal/ThermalComponentIF.h"
@ -13,9 +11,11 @@
#include "../ipc/MessageQueueMessage.h"
#include "../ipc/QueueFactory.h"
#include "../subsystem/SubsystemBase.h"
#include "../datapoollocal/LocalPoolVariable.h"
#include <iomanip>
object_id_t DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT;
object_id_t DeviceHandlerBase::rawDataReceiverId = objects::NO_OBJECT;
object_id_t DeviceHandlerBase::defaultFdirParentId = objects::NO_OBJECT;
@ -56,9 +56,10 @@ void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) {
}
void DeviceHandlerBase::setThermalStateRequestPoolIds(
uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId) {
this->deviceThermalRequestPoolId = thermalStatePoolId;
this->deviceThermalRequestPoolId = thermalRequestPoolId;
lp_id_t thermalStatePoolId, lp_id_t heaterRequestPoolId,
uint32_t thermalSetId) {
thermalSet = new DeviceHandlerThermalSet(this, thermalSetId,
thermalStatePoolId, heaterRequestPoolId);
}
@ -86,7 +87,6 @@ ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) {
decrementDeviceReplyMap();
fdirInstance->checkForFailures();
hkSwitcher.performOperation();
hkManager.performHkOperation();
performOperationHook();
return RETURN_OK;
}
@ -111,6 +111,9 @@ ReturnValue_t DeviceHandlerBase::performOperation(uint8_t counter) {
break;
case CommunicationAction::GET_READ:
doGetRead();
// This will be performed after datasets have been updated by the
// custom device implementation.
hkManager.performHkOperation();
break;
default:
break;
@ -208,16 +211,18 @@ ReturnValue_t DeviceHandlerBase::initialize() {
fillCommandAndReplyMap();
if(thermalSet != nullptr) {
//Set temperature target state to NON_OP.
GlobDataSet mySet;
gp_uint8_t thermalRequest(deviceThermalRequestPoolId, &mySet,
PoolVariableIF::VAR_WRITE);
mySet.read();
thermalRequest = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
mySet.commit(PoolVariableIF::VALID);
result = thermalSet->read();
if(result == HasReturnvaluesIF::RETURN_OK) {
thermalSet->heaterRequest.value =
ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
thermalSet->commit(PoolVariableIF::VALID);
}
}
return RETURN_OK;
}
void DeviceHandlerBase::decrementDeviceReplyMap() {
@ -505,15 +510,17 @@ void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) {
}
Clock::getUptime(&timeoutStart);
if (mode == MODE_OFF) {
GlobDataSet mySet;
gp_uint8_t thermalRequest(deviceThermalRequestPoolId, &mySet,
PoolVariableIF::VAR_READ_WRITE);
mySet.read();
if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) {
thermalRequest = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL;
if (mode == MODE_OFF and thermalSet != nullptr) {
ReturnValue_t result = thermalSet->read();
if(result == HasReturnvaluesIF::RETURN_OK) {
if (thermalSet->heaterRequest.value !=
ThermalComponentIF::STATE_REQUEST_IGNORE) {
thermalSet->heaterRequest.value = ThermalComponentIF::
STATE_REQUEST_NON_OPERATIONAL;
}
mySet.commit(PoolVariableIF::VALID);
thermalSet->heaterRequest.commit(PoolVariableIF::VALID);
}
}
changeHK(mode, submode, true);
}
@ -976,17 +983,15 @@ ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode,
}
if ((commandedMode == MODE_ON) && (mode == MODE_OFF)
&& (deviceThermalStatePoolId != PoolVariableIF::NO_PARAMETER)) {
GlobDataSet mySet;
gp_uint8_t thermalState(deviceThermalStatePoolId, &mySet,
PoolVariableIF::VAR_READ);
gp_uint8_t thermalRequest(deviceThermalRequestPoolId, &mySet,
PoolVariableIF::VAR_READ);
mySet.read();
if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) {
if (!ThermalComponentIF::isOperational(thermalState)) {
and (thermalSet != nullptr)) {
ReturnValue_t result = thermalSet->read();
if(result == HasReturnvaluesIF::RETURN_OK) {
if((thermalSet->heaterRequest.value !=
ThermalComponentIF::STATE_REQUEST_IGNORE) and (not
ThermalComponentIF::isOperational(
thermalSet->thermalState.value))) {
triggerEvent(ThermalComponentIF::TEMP_NOT_IN_OP_RANGE,
thermalState);
thermalSet->thermalState.value);
return NON_OP_TEMPERATURE;
}
}
@ -999,32 +1004,15 @@ void DeviceHandlerBase::startTransition(Mode_t commandedMode,
Submode_t commandedSubmode) {
switch (commandedMode) {
case MODE_ON:
if (mode == MODE_OFF) {
transitionSourceMode = _MODE_POWER_DOWN;
transitionSourceSubMode = SUBMODE_NONE;
setMode(_MODE_POWER_ON, commandedSubmode);
//already set the delay for the child transition so we don't need to call it twice
childTransitionDelay = getTransitionDelayMs(_MODE_START_UP,
MODE_ON);
triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode);
GlobDataSet mySet;
gp_int8_t thermalRequest(deviceThermalRequestPoolId,
&mySet, PoolVariableIF::VAR_READ_WRITE);
mySet.read();
if (thermalRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) {
thermalRequest = ThermalComponentIF::STATE_REQUEST_OPERATIONAL;
mySet.commit(PoolVariableIF::VALID);
}
} else {
setTransition(MODE_ON, commandedSubmode);
}
handleTransitionToOnMode(commandedMode, commandedSubmode);
break;
case MODE_OFF:
if (mode == MODE_OFF) {
triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode);
setMode(_MODE_POWER_DOWN, commandedSubmode);
} else {
//already set the delay for the child transition so we don't need to call it twice
// already set the delay for the child transition
// so we don't need to call it twice
childTransitionDelay = getTransitionDelayMs(mode, _MODE_POWER_DOWN);
transitionSourceMode = _MODE_POWER_DOWN;
transitionSourceSubMode = commandedSubmode;
@ -1050,6 +1038,33 @@ void DeviceHandlerBase::startTransition(Mode_t commandedMode,
}
}
void DeviceHandlerBase::handleTransitionToOnMode(Mode_t commandedMode,
Submode_t commandedSubmode) {
if (mode == MODE_OFF) {
transitionSourceMode = _MODE_POWER_DOWN;
transitionSourceSubMode = SUBMODE_NONE;
setMode(_MODE_POWER_ON, commandedSubmode);
// already set the delay for the child transition so we don't
// need to call it twice
childTransitionDelay = getTransitionDelayMs(_MODE_START_UP,
MODE_ON);
triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode);
if(thermalSet != nullptr) {
ReturnValue_t result = thermalSet->read();
if(result == HasReturnvaluesIF::RETURN_OK) {
if(thermalSet->heaterRequest !=
ThermalComponentIF::STATE_REQUEST_IGNORE) {
thermalSet->heaterRequest =
ThermalComponentIF::STATE_REQUEST_OPERATIONAL;
thermalSet->commit();
}
}
}
} else {
setTransition(MODE_ON, commandedSubmode);
}
}
void DeviceHandlerBase::getMode(Mode_t* mode, Submode_t* submode) {
*mode = this->mode;
*submode = this->submode;
@ -1222,10 +1237,12 @@ void DeviceHandlerBase::handleDeviceTM(SerializeIF* data,
}
}
//Try to cast to GlobDataSet and commit data.
if (!neverInDataPool) {
GlobDataSet* dataSet = dynamic_cast<GlobDataSet*>(data);
if (dataSet != NULL) {
dataSet->commit(PoolVariableIF::VALID);
if (not neverInDataPool) {
LocalPoolDataSetBase* dataSet =
dynamic_cast<LocalPoolDataSetBase*>(data);
if (dataSet != nullptr) {
dataSet->setValidity(true, true);
dataSet->commit();
}
}
}
@ -1262,7 +1279,8 @@ void DeviceHandlerBase::buildInternalCommand(void) {
if (result == BUSY) {
//so we can track misconfigurations
sif::debug << std::hex << getObjectId()
<< ": DHB::buildInternalCommand: Busy" << std::dec << std::endl;
<< ": DHB::buildInternalCommand: Busy" << std::dec
<< std::endl;
result = NOTHING_TO_SEND; //no need to report this
}
}
@ -1371,8 +1389,8 @@ bool DeviceHandlerBase::commandIsExecuting(DeviceCommandId_t commandId) {
void DeviceHandlerBase::changeHK(Mode_t mode, Submode_t submode, bool enable) {
}
void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task_){
executingTask = task_;
void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task){
executingTask = task;
}
// Default implementations empty.
@ -1385,6 +1403,12 @@ void DeviceHandlerBase::performOperationHook() {
ReturnValue_t DeviceHandlerBase::initializeLocalDataPool(
LocalDataPool &localDataPoolMap,
LocalDataPoolManager& poolManager) {
if(thermalSet != nullptr) {
localDataPoolMap.emplace(thermalSet->thermalStatePoolId,
new PoolEntry<DeviceHandlerIF::dh_thermal_state_t>);
localDataPoolMap.emplace(thermalSet->heaterRequestPoolId,
new PoolEntry<DeviceHandlerIF::dh_heater_request_t>);
}
return RETURN_OK;
}
@ -1429,3 +1453,9 @@ dur_millis_t DeviceHandlerBase::getPeriodicOperationFrequency() const {
return pstIntervalMs;
}
DeviceCommandId_t DeviceHandlerBase::getPendingCommand() const {
if(cookieInfo.pendingCommand != deviceCommandMap.end()) {
return cookieInfo.pendingCommand->first;
}
return DeviceHandlerIF::NO_COMMAND;
}

View File

@ -4,6 +4,7 @@
#include "DeviceHandlerIF.h"
#include "DeviceCommunicationIF.h"
#include "DeviceHandlerFailureIsolation.h"
#include "DeviceHandlerThermalSet.h"
#include "../objectmanager/SystemObject.h"
#include "../tasks/ExecutableObjectIF.h"
@ -103,8 +104,21 @@ public:
size_t cmdQueueSize = 20);
void setHkDestination(object_id_t hkDestination);
void setThermalStateRequestPoolIds(uint32_t thermalStatePoolId,
uint32_t thermalRequestPoolId);
/**
* If the device handler is controlled by the FSFW thermal building blocks,
* this function should be called to initialize all required components.
* The device handler will then take care of creating local pool entries
* for the device thermal state and device heating request.
* Custom local pool IDs can be assigned as well.
* @param thermalStatePoolId
* @param thermalRequestPoolId
*/
void setThermalStateRequestPoolIds(lp_id_t thermalStatePoolId =
DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID,
lp_id_t thermalRequestPoolId =
DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID,
uint32_t thermalSetId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID);
/**
* @brief Helper function to ease device handler development.
* This will instruct the transition to MODE_ON immediately
@ -694,19 +708,7 @@ protected:
//! and to send replies.
MessageQueueIF* commandQueue = nullptr;
/**
* this is the datapool variable with the thermal state of the device
*
* can be set to PoolVariableIF::NO_PARAMETER to deactivate thermal checking
*/
uint32_t deviceThermalStatePoolId = PoolVariableIF::NO_PARAMETER;
/**
* this is the datapool variable with the thermal request of the device
*
* can be set to PoolVariableIF::NO_PARAMETER to deactivate thermal checking
*/
uint32_t deviceThermalRequestPoolId = PoolVariableIF::NO_PARAMETER;
DeviceHandlerThermalSet* thermalSet = nullptr;
/**
* Optional Error code. Can be set in doStartUp(), doShutDown() and
@ -732,15 +734,28 @@ protected:
//! before setTaskIF was called.
PeriodicTaskIF* executingTask = nullptr;
static object_id_t powerSwitcherId; //!< Object which switches power on and off.
//!< Object which switches power on and off.
static object_id_t powerSwitcherId;
static object_id_t rawDataReceiverId; //!< Object which receives RAW data by default.
//!< Object which receives RAW data by default.
static object_id_t rawDataReceiverId;
//!< Object which may be the root cause of an identified fault.
static object_id_t defaultFdirParentId;
/**
* Helper function to get pending command. This is useful for devices
* like SPI sensors to identify the last sent command.
* This only returns the command sent in the last SEND_WRITE cycle.
* @return
*/
DeviceCommandId_t getPendingCommand() const;
static object_id_t defaultFdirParentId; //!< Object which may be the root cause of an identified fault.
/**
* Helper function to report a missed reply
*
* Can be overwritten by children to act on missed replies or to fake reporting Id.
* Can be overwritten by children to act on missed replies or to fake
* reporting Id.
*
* @param id of the missed reply
*/
@ -847,15 +862,18 @@ protected:
/**
* Build the device command to send for raw mode.
*
* This is only called in @c MODE_RAW. It is for the rare case that in raw mode packets
* are to be sent by the handler itself. It is NOT needed for the raw commanding service.
* Its only current use is in the STR handler which gets its raw packets from a different
* source.
* Also it can be used for transitional commands, to get the device ready for @c MODE_RAW
* This is only called in @c MODE_RAW. It is for the rare case that in
* raw mode packets are to be sent by the handler itself. It is NOT needed
* for the raw commanding service. Its only current use is in the STR
* handler which gets its raw packets from a different source.
* Also it can be used for transitional commands, to get the device ready
* for @c MODE_RAW
*
* As it is almost never used, there is a default implementation returning @c NOTHING_TO_SEND.
* As it is almost never used, there is a default implementation
* returning @c NOTHING_TO_SEND.
*
* #rawPacket and #rawPacketLen must be set by this method to the packet to be sent.
* #rawPacket and #rawPacketLen must be set by this method to the packet
* to be sent.
*
* @param[out] id the device command id built
* @return
@ -868,7 +886,9 @@ protected:
* Returns the delay cycle count of a reply.
* A count != 0 indicates that the command is already executed.
* @param deviceCommand The command to look for
* @return The current delay count. If the command does not exist (should never happen) it returns 0.
* @return
* The current delay count. If the command does not exist (should never
* happen) it returns 0.
*/
uint8_t getReplyDelayCycles(DeviceCommandId_t deviceCommand);
@ -878,20 +898,22 @@ protected:
* It gets space in the #IPCStore, copies data there, then sends a raw reply
* containing the store address.
*
* This method is virtual, as the STR has a different channel to send raw replies
* and overwrites it accordingly.
* This method is virtual, as the STR has a different channel to send
* raw replies and overwrites it accordingly.
*
* @param data data to send
* @param len length of @c data
* @param sendTo the messageQueueId of the one to send to
* @param isCommand marks the raw data as a command, the message then will be of type raw_command
* @param isCommand marks the raw data as a command, the message then
* will be of type raw_command
*/
virtual void replyRawData(const uint8_t *data, size_t len,
MessageQueueId_t sendTo, bool isCommand = false);
/**
* Calls replyRawData() with #defaultRawReceiver, but checks if wiretapping is active and if so,
* does not send the Data as the wiretapping will have sent it already
* Calls replyRawData() with #defaultRawReceiver, but checks if wiretapping
* is active and if so, does not send the data as the wiretapping will have
* sent it already
*/
void replyRawReplyIfnotWiretapped(const uint8_t *data, size_t len);
@ -903,17 +925,19 @@ protected:
/**
* Enable the reply checking for a command
*
* Is only called, if the command was sent (ie the getWriteReply was successful).
* Must ensure that all replies are activated and correctly linked to the command that initiated it.
* The default implementation looks for a reply with the same id as the command id in the replyMap or
* uses the alternativeReplyId if flagged so.
* When found, copies maxDelayCycles to delayCycles in the reply information and sets the command to
* expect one reply.
* Is only called, if the command was sent (i.e. the getWriteReply was
* successful). Must ensure that all replies are activated and correctly
* linked to the command that initiated it.
* The default implementation looks for a reply with the same id as the
* command id in the replyMap or uses the alternativeReplyId if flagged so.
* When found, copies maxDelayCycles to delayCycles in the reply information
* and sets the command to expect one reply.
*
* Can be overwritten by the child, if a command activates multiple replies
* or replyId differs from commandId.
* Notes for child implementations:
* - If the command was not found in the reply map, NO_REPLY_EXPECTED MUST be returned.
* - If the command was not found in the reply map,
* NO_REPLY_EXPECTED MUST be returned.
* - A failure code may be returned if something went fundamentally wrong.
*
* @param deviceCommand
@ -929,17 +953,20 @@ protected:
* get the state of the PCDU switches in the datapool
*
* @return
* - @c PowerSwitchIF::SWITCH_ON if all switches specified by #switches are on
* - @c PowerSwitchIF::SWITCH_OFF one of the switches specified by #switches are off
* - @c PowerSwitchIF::SWITCH_ON if all switches specified
* by #switches are on
* - @c PowerSwitchIF::SWITCH_OFF one of the switches specified by
* #switches are off
* - @c PowerSwitchIF::RETURN_FAILED if an error occured
*/
ReturnValue_t getStateOfSwitches(void);
/**
* set all datapool variables that are update periodically in normal mode invalid
*
* Child classes should provide an implementation which sets all those variables invalid
* which are set periodically during any normal mode.
* @brief Set all datapool variables that are update periodically in
* normal mode invalid
* @details TODO: Use local pools
* Child classes should provide an implementation which sets all those
* variables invalid which are set periodically during any normal mode.
*/
virtual void setNormalDatapoolEntriesInvalid() = 0;
@ -949,11 +976,12 @@ protected:
virtual void changeHK(Mode_t mode, Submode_t submode, bool enable);
/**
* Children can overwrite this function to suppress checking of the command Queue
* Children can overwrite this function to suppress checking of the
* command Queue
*
* This can be used when the child does not want to receive a command in a certain
* situation. Care must be taken that checking is not permanentely disabled as this
* would render the handler unusable.
* This can be used when the child does not want to receive a command in
* a certain situation. Care must be taken that checking is not
* permanentely disabled as this would render the handler unusable.
*
* @return whether checking the queue should NOT be done
*/
@ -992,17 +1020,20 @@ protected:
virtual void forwardEvent(Event event, uint32_t parameter1 = 0,
uint32_t parameter2 = 0) const;
/**
* Checks state of switches in conjunction with mode and triggers an event if they don't fit.
* Checks state of switches in conjunction with mode and triggers an event
* if they don't fit.
*/
virtual void checkSwitchState();
/**
* Reserved for the rare case where a device needs to perform additional operation cyclically in OFF mode.
* Reserved for the rare case where a device needs to perform additional
* operation cyclically in OFF mode.
*/
virtual void doOffActivity();
/**
* Reserved for the rare case where a device needs to perform additional operation cyclically in ON mode.
* Reserved for the rare case where a device needs to perform additional
* operation cyclically in ON mode.
*/
virtual void doOnActivity();
@ -1043,9 +1074,10 @@ private:
/**
* Information about a cookie.
*
* This is stored in a map for each cookie, to not only track the state, but also information
* about the sent command. Tracking this information is needed as
* the state of a commandId (waiting for reply) is done when a RMAP write reply is received.
* This is stored in a map for each cookie, to not only track the state,
* but also information about the sent command. Tracking this information
* is needed as the state of a commandId (waiting for reply) is done when a
* write reply is received.
*/
struct CookieInfo {
CookieState_t state;
@ -1102,10 +1134,14 @@ private:
/**
* Handle the device handler mode.
*
* - checks whether commands are valid for the current mode, rejects them accordingly
* - checks whether commanded mode transitions are required and calls handleCommandedModeTransition()
* - does the necessary action for the current mode or calls doChildStateMachine in modes @c MODE_TO_ON and @c MODE_TO_OFF
* - actions that happen in transitions (eg setting a timeout) are handled in setMode()
* - checks whether commands are valid for the current mode, rejects
* them accordingly
* - checks whether commanded mode transitions are required and calls
* handleCommandedModeTransition()
* - does the necessary action for the current mode or calls
* doChildStateMachine in modes @c MODE_TO_ON and @c MODE_TO_OFF
* - actions that happen in transitions (e.g. setting a timeout) are
* handled in setMode()
*/
void doStateMachine(void);
@ -1115,16 +1151,17 @@ private:
/**
* Decrement the counter for the timout of replies.
*
* This is called at the beginning of each cycle. It checks whether a reply has timed out (that means a reply was expected
* but not received).
* This is called at the beginning of each cycle. It checks whether a
* reply has timed out (that means a reply was expected but not received).
*/
void decrementDeviceReplyMap(void);
/**
* Convenience function to handle a reply.
*
* Called after scanForReply() has found a packet. Checks if the found id is in the #deviceCommandMap, if so,
* calls interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) for further action.
* Called after scanForReply() has found a packet. Checks if the found ID
* is in the #deviceCommandMap, if so, calls
* #interpretDeviceReply for further action.
*
* It also resets the timeout counter for the command id.
*
@ -1184,7 +1221,7 @@ private:
* @param[out] len
* @return
* - @c RETURN_OK @c data is valid
* - @c RETURN_FAILED IPCStore is NULL
* - @c RETURN_FAILED IPCStore is nullptr
* - the return value from the IPCStore if it was not @c RETURN_OK
*/
ReturnValue_t getStorageData(store_address_t storageAddress, uint8_t **data,
@ -1208,6 +1245,9 @@ private:
void parseReply(const uint8_t* receivedData,
size_t receivedDataLen);
void handleTransitionToOnMode(Mode_t commandedMode,
Submode_t commandedSubmode);
};
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */

View File

@ -7,21 +7,22 @@
#include "../ipc/MutexFactory.h"
const uint16_t EventManager::POOL_SIZES[N_POOLS] = {
sizeof(EventMatchTree::Node), sizeof(EventIdRangeMatcher),
sizeof(ReporterRangeMatcher) };
// If one checks registerListener calls, there are around 40 (to max 50)
// objects registering for certain events.
// Each listener requires 1 or 2 EventIdMatcher and 1 or 2 ReportRangeMatcher.
// So a good guess is 75 to a max of 100 pools required for each, which fits well.
const uint16_t EventManager::N_ELEMENTS[N_POOLS] = {
fsfwconfig::FSFW_EVENTMGMR_MATCHTREE_NODES ,
fsfwconfig::FSFW_EVENTMGMT_EVENTIDMATCHERS,
fsfwconfig::FSFW_EVENTMGMR_RANGEMATCHERS };
const LocalPool::LocalPoolConfig EventManager::poolConfig = {
{fsfwconfig::FSFW_EVENTMGMR_MATCHTREE_NODES,
sizeof(EventMatchTree::Node)},
{fsfwconfig::FSFW_EVENTMGMT_EVENTIDMATCHERS,
sizeof(EventIdRangeMatcher)},
{fsfwconfig::FSFW_EVENTMGMR_RANGEMATCHERS,
sizeof(ReporterRangeMatcher)}
};
EventManager::EventManager(object_id_t setObjectId) :
SystemObject(setObjectId),
factoryBackend(0, POOL_SIZES, N_ELEMENTS, false, true) {
factoryBackend(0, poolConfig, false, true) {
mutex = MutexFactory::instance()->createMutex();
eventReportQueue = QueueFactory::instance()->createMessageQueue(
MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE);
@ -113,7 +114,7 @@ ReturnValue_t EventManager::unsubscribeFromEventRange(MessageQueueId_t listener,
return result;
}
#ifdef DEBUG
#if FSFW_DEBUG_OUTPUT == 1
void EventManager::printEvent(EventMessage* message) {
const char *string = 0;

View File

@ -8,9 +8,11 @@
#include "../tasks/ExecutableObjectIF.h"
#include "../ipc/MessageQueueIF.h"
#include "../ipc/MutexIF.h"
#include <FSFWConfig.h>
#include <map>
#ifdef DEBUG
#if FSFW_DEBUG_OUTPUT == 1
// forward declaration, should be implemented by mission
extern const char* translateObject(object_id_t object);
extern const char* translateEvents(Event event);
@ -49,13 +51,15 @@ protected:
MutexIF* mutex = nullptr;
static const uint8_t N_POOLS = 3;
LocalPool<N_POOLS> factoryBackend;
LocalPool factoryBackend;
static const LocalPool::LocalPoolConfig poolConfig;
static const uint16_t POOL_SIZES[N_POOLS];
static const uint16_t N_ELEMENTS[N_POOLS];
void notifyListeners(EventMessage *message);
#ifdef DEBUG
#if FSFW_DEBUG_OUTPUT == 1
void printEvent(EventMessage *message);
#endif

View File

@ -0,0 +1,34 @@
#ifndef FSFW_INTERNALERROR_INTERNALERRORDATASET_H_
#define FSFW_INTERNALERROR_INTERNALERRORDATASET_H_
#include <fsfw/datapoollocal/StaticLocalDataSet.h>
#include <fsfw/datapoollocal/LocalPoolVariable.h>
enum errorPoolIds {
TM_HITS,
QUEUE_HITS,
STORE_HITS
};
class InternalErrorDataset: public StaticLocalDataSet<3 * sizeof(uint32_t)> {
public:
static constexpr uint8_t ERROR_SET_ID = 0;
InternalErrorDataset(HasLocalDataPoolIF* owner):
StaticLocalDataSet(owner, ERROR_SET_ID) {}
InternalErrorDataset(object_id_t objectId):
StaticLocalDataSet(sid_t(objectId , ERROR_SET_ID)) {}
lp_var_t<uint32_t> tmHits = lp_var_t<uint32_t>(hkManager->getOwner(),
TM_HITS, this);
lp_var_t<uint32_t> queueHits = lp_var_t<uint32_t>(hkManager->getOwner(),
QUEUE_HITS, this);
lp_var_t<uint32_t> storeHits = lp_var_t<uint32_t>(hkManager->getOwner(),
STORE_HITS, this);
};
#endif /* FSFW_INTERNALERROR_INTERNALERRORDATASET_H_ */

View File

@ -1,16 +1,16 @@
#include "../datapoolglob/GlobalDataSet.h"
#include "InternalErrorReporter.h"
#include "../datapoolglob/GlobalPoolVariable.h"
#include "../ipc/QueueFactory.h"
#include "../ipc/MutexFactory.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId,
uint32_t queuePoolId, uint32_t tmPoolId, uint32_t storePoolId) :
SystemObject(setObjectId), mutex(NULL), queuePoolId(queuePoolId),
tmPoolId(tmPoolId),storePoolId(storePoolId), queueHits(0), tmHits(0),
storeHits(0) {
uint32_t messageQueueDepth): SystemObject(setObjectId),
commandQueue(QueueFactory::instance()->
createMessageQueue(messageQueueDepth)),
poolManager(this, commandQueue),
internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID),
internalErrorDataset(this) {
mutex = MutexFactory::instance()->createMutex();
}
@ -18,28 +18,42 @@ InternalErrorReporter::~InternalErrorReporter() {
MutexFactory::instance()->deleteMutex(mutex);
}
void InternalErrorReporter::setDiagnosticPrintout(bool enable) {
this->diagnosticPrintout = enable;
}
ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) {
GlobDataSet mySet;
gp_uint32_t queueHitsInPool(queuePoolId, &mySet,
PoolVariableIF::VAR_READ_WRITE);
gp_uint32_t tmHitsInPool(tmPoolId, &mySet,
PoolVariableIF::VAR_READ_WRITE);
gp_uint32_t storeHitsInPool(storePoolId, &mySet,
PoolVariableIF::VAR_READ_WRITE);
mySet.read();
internalErrorDataset.read(INTERNAL_ERROR_MUTEX_TIMEOUT);
uint32_t newQueueHits = getAndResetQueueHits();
uint32_t newTmHits = getAndResetTmHits();
uint32_t newStoreHits = getAndResetStoreHits();
queueHitsInPool.value += newQueueHits;
tmHitsInPool.value += newTmHits;
storeHitsInPool.value += newStoreHits;
#ifdef DEBUG
if(diagnosticPrintout) {
if((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) {
sif::debug << "InternalErrorReporter::performOperation: Errors "
<< "occured!" << std::endl;
sif::debug << "Queue errors: " << newQueueHits << std::endl;
sif::debug << "TM errors: " << newTmHits << std::endl;
sif::debug << "Store errors: " << newStoreHits << std::endl;
}
}
#endif
mySet.commit(PoolVariableIF::VALID);
internalErrorDataset.queueHits.value += newQueueHits;
internalErrorDataset.storeHits.value += newStoreHits;
internalErrorDataset.tmHits.value += newTmHits;
internalErrorDataset.commit(INTERNAL_ERROR_MUTEX_TIMEOUT);
poolManager.performHkOperation();
CommandMessage message;
ReturnValue_t result = commandQueue->receiveMessage(&message);
if(result != MessageQueueIF::EMPTY) {
poolManager.handleHousekeepingMessage(&message);
}
return HasReturnvaluesIF::RETURN_OK;
}
@ -53,7 +67,7 @@ void InternalErrorReporter::lostTm() {
uint32_t InternalErrorReporter::getAndResetQueueHits() {
uint32_t value;
mutex->lockMutex(MutexIF::BLOCKING);
mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT);
value = queueHits;
queueHits = 0;
mutex->unlockMutex();
@ -62,21 +76,21 @@ uint32_t InternalErrorReporter::getAndResetQueueHits() {
uint32_t InternalErrorReporter::getQueueHits() {
uint32_t value;
mutex->lockMutex(MutexIF::BLOCKING);
mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT);
value = queueHits;
mutex->unlockMutex();
return value;
}
void InternalErrorReporter::incrementQueueHits() {
mutex->lockMutex(MutexIF::BLOCKING);
mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT);
queueHits++;
mutex->unlockMutex();
}
uint32_t InternalErrorReporter::getAndResetTmHits() {
uint32_t value;
mutex->lockMutex(MutexIF::BLOCKING);
mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT);
value = tmHits;
tmHits = 0;
mutex->unlockMutex();
@ -85,14 +99,14 @@ uint32_t InternalErrorReporter::getAndResetTmHits() {
uint32_t InternalErrorReporter::getTmHits() {
uint32_t value;
mutex->lockMutex(MutexIF::BLOCKING);
mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT);
value = tmHits;
mutex->unlockMutex();
return value;
}
void InternalErrorReporter::incrementTmHits() {
mutex->lockMutex(MutexIF::BLOCKING);
mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT);
tmHits++;
mutex->unlockMutex();
}
@ -103,7 +117,7 @@ void InternalErrorReporter::storeFull() {
uint32_t InternalErrorReporter::getAndResetStoreHits() {
uint32_t value;
mutex->lockMutex(MutexIF::BLOCKING);
mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT);
value = storeHits;
storeHits = 0;
mutex->unlockMutex();
@ -112,14 +126,65 @@ uint32_t InternalErrorReporter::getAndResetStoreHits() {
uint32_t InternalErrorReporter::getStoreHits() {
uint32_t value;
mutex->lockMutex(MutexIF::BLOCKING);
mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT);
value = storeHits;
mutex->unlockMutex();
return value;
}
void InternalErrorReporter::incrementStoreHits() {
mutex->lockMutex(MutexIF::BLOCKING);
mutex->lockMutex(MutexIF::WAITING, INTERNAL_ERROR_MUTEX_TIMEOUT);
storeHits++;
mutex->unlockMutex();
}
object_id_t InternalErrorReporter::getObjectId() const {
return SystemObject::getObjectId();
}
MessageQueueId_t InternalErrorReporter::getCommandQueue() const {
return this->commandQueue->getId();
}
ReturnValue_t InternalErrorReporter::initializeLocalDataPool(
LocalDataPool &localDataPoolMap, LocalDataPoolManager &poolManager) {
localDataPoolMap.emplace(errorPoolIds::TM_HITS,
new PoolEntry<uint32_t>());
localDataPoolMap.emplace(errorPoolIds::QUEUE_HITS,
new PoolEntry<uint32_t>());
localDataPoolMap.emplace(errorPoolIds::STORE_HITS,
new PoolEntry<uint32_t>());
poolManager.subscribeForPeriodicPacket(internalErrorSid, false,
getPeriodicOperationFrequency(), true);
internalErrorDataset.setValidity(true, true);
return HasReturnvaluesIF::RETURN_OK;
}
LocalDataPoolManager* InternalErrorReporter::getHkManagerHandle() {
return &poolManager;
}
dur_millis_t InternalErrorReporter::getPeriodicOperationFrequency() const {
return this->executingTask->getPeriodMs();
}
LocalPoolDataSetBase* InternalErrorReporter::getDataSetHandle(sid_t sid) {
return &internalErrorDataset;
}
void InternalErrorReporter::setTaskIF(PeriodicTaskIF *task) {
this->executingTask = task;
}
ReturnValue_t InternalErrorReporter::initialize() {
ReturnValue_t result = poolManager.initialize(commandQueue);
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
return SystemObject::initialize();
}
ReturnValue_t InternalErrorReporter::initializeAfterTaskCreation() {
return poolManager.initializeAfterTaskCreation();
}

View File

@ -1,37 +1,75 @@
#ifndef INTERNALERRORREPORTER_H_
#define INTERNALERRORREPORTER_H_
#ifndef FSFW_INTERNALERROR_INTERNALERRORREPORTER_H_
#define FSFW_INTERNALERROR_INTERNALERRORREPORTER_H_
#include "InternalErrorReporterIF.h"
#include "../tasks/PeriodicTaskIF.h"
#include "../internalError/InternalErrorDataset.h"
#include "../datapoollocal/LocalDataPoolManager.h"
#include "../tasks/ExecutableObjectIF.h"
#include "../objectmanager/SystemObject.h"
#include "../ipc/MutexIF.h"
/**
* @brief This class is used to track internal errors like lost telemetry,
* failed message sending or a full store.
* @details
* All functions were kept virtual so this class can be extended easily
* to store custom internal errors (e.g. communication interface errors).
*/
class InternalErrorReporter: public SystemObject,
public ExecutableObjectIF,
public InternalErrorReporterIF {
public InternalErrorReporterIF,
public HasLocalDataPoolIF {
public:
InternalErrorReporter(object_id_t setObjectId, uint32_t queuePoolId,
uint32_t tmPoolId, uint32_t storePoolId);
static constexpr uint8_t INTERNAL_ERROR_MUTEX_TIMEOUT = 20;
InternalErrorReporter(object_id_t setObjectId,
uint32_t messageQueueDepth = 5);
/**
* Enable diagnostic printout. Please note that this feature will
* only work if DEBUG has been supplied to the build defines.
* @param enable
*/
void setDiagnosticPrintout(bool enable);
virtual ~InternalErrorReporter();
virtual ReturnValue_t performOperation(uint8_t opCode);
virtual object_id_t getObjectId() const override;
virtual MessageQueueId_t getCommandQueue() const override;
virtual ReturnValue_t initializeLocalDataPool(
LocalDataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override;
virtual LocalDataPoolManager* getHkManagerHandle() override;
virtual dur_millis_t getPeriodicOperationFrequency() const override;
virtual LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override;
virtual ReturnValue_t initialize() override;
virtual ReturnValue_t initializeAfterTaskCreation() override;
virtual ReturnValue_t performOperation(uint8_t opCode) override;
virtual void queueMessageNotSent();
virtual void lostTm();
virtual void storeFull();
virtual void setTaskIF(PeriodicTaskIF* task) override;
protected:
MutexIF* mutex;
MessageQueueIF* commandQueue;
LocalDataPoolManager poolManager;
uint32_t queuePoolId;
uint32_t tmPoolId;
uint32_t storePoolId;
PeriodicTaskIF* executingTask = nullptr;
MutexIF* mutex = nullptr;
sid_t internalErrorSid;
InternalErrorDataset internalErrorDataset;
uint32_t queueHits;
uint32_t tmHits;
uint32_t storeHits;
bool diagnosticPrintout = true;
uint32_t queueHits = 0;
uint32_t tmHits = 0;
uint32_t storeHits = 0;
uint32_t getAndResetQueueHits();
uint32_t getQueueHits();
@ -47,4 +85,4 @@ protected:
};
#endif /* INTERNALERRORREPORTER_H_ */
#endif /* FSFW_INTERNALERROR_INTERNALERRORREPORTER_H_ */

80
memory/HasFileSystemIF.h Normal file
View File

@ -0,0 +1,80 @@
#ifndef FSFW_MEMORY_HASFILESYSTEMIF_H_
#define FSFW_MEMORY_HASFILESYSTEMIF_H_
#include "../returnvalues/HasReturnvaluesIF.h"
#include "../returnvalues/FwClassIds.h"
#include "../ipc/messageQueueDefinitions.h"
#include <cstddef>
/**
* @brief Generic interface for objects which expose a file system to enable
* message based file handling.
* @author J. Meier, R. Mueller
*/
class HasFileSystemIF {
public:
static constexpr uint8_t INTERFACE_ID = CLASS_ID::FILE_SYSTEM;
static constexpr ReturnValue_t FILE_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x00);
static constexpr ReturnValue_t FILE_ALREADY_EXISTS = MAKE_RETURN_CODE(0x01);
static constexpr ReturnValue_t FILE_LOCKED = MAKE_RETURN_CODE(0x02);
static constexpr ReturnValue_t DIRECTORY_DOES_NOT_EXIST = MAKE_RETURN_CODE(0x03);
static constexpr ReturnValue_t DIRECTORY_ALREADY_EXISTS = MAKE_RETURN_CODE(0x04);
static constexpr ReturnValue_t DIRECTORY_NOT_EMPTY = MAKE_RETURN_CODE(0x05);
static constexpr ReturnValue_t SEQUENCE_PACKET_MISSING_WRITE = MAKE_RETURN_CODE(0x06); //! P1: Sequence number missing
static constexpr ReturnValue_t SEQUENCE_PACKET_MISSING_READ = MAKE_RETURN_CODE(0x07); //! P1: Sequence number missing
virtual ~HasFileSystemIF() {}
/**
* Function to get the MessageQueueId_t of the implementing object
* @return MessageQueueId_t of the object
*/
virtual MessageQueueId_t getCommandQueue() const = 0;
/**
* Generic function to append to file.
* @param dirname Directory of the file
* @param filename The filename of the file
* @param data The data to write to the file
* @param size The size of the data to write
* @param packetNumber Current packet number. Can be used to verify that
* there are no missing packets.
* @param args Any other arguments which an implementation might require.
* @param bytesWritten Actual bytes written to file
* For large files the write procedure must be split in multiple calls
* to writeToFile
*/
virtual ReturnValue_t appendToFile(const char* repositoryPath,
const char* filename, const uint8_t* data, size_t size,
uint16_t packetNumber, void* args = nullptr) = 0;
/**
* Generic function to create a new file.
* @param repositoryPath
* @param filename
* @param data
* @param size
* @param args Any other arguments which an implementation might require.
* @return
*/
virtual ReturnValue_t createFile(const char* repositoryPath,
const char* filename, const uint8_t* data = nullptr,
size_t size = 0, void* args = nullptr) = 0;
/**
* Generic function to delete a file.
* @param repositoryPath
* @param filename
* @param args
* @return
*/
virtual ReturnValue_t deleteFile(const char* repositoryPath,
const char* filename, void* args = nullptr) = 0;
};
#endif /* FSFW_MEMORY_HASFILESYSTEMIF_H_ */

View File

@ -1,5 +1,5 @@
#ifndef FRAMEWORK_MONITORING_ABSLIMITMONITOR_H_
#define FRAMEWORK_MONITORING_ABSLIMITMONITOR_H_
#ifndef FSFW_MONITORING_ABSLIMITMONITOR_H_
#define FSFW_MONITORING_ABSLIMITMONITOR_H_
#include "MonitorBase.h"
#include <cmath>
@ -7,9 +7,14 @@
template<typename T>
class AbsLimitMonitor: public MonitorBase<T> {
public:
AbsLimitMonitor(object_id_t reporterId, uint8_t monitorId, uint32_t parameterId,
uint16_t confirmationLimit, T limit, Event violationEvent = MonitoringIF::VALUE_OUT_OF_RANGE, bool aboveIsViolation = true) :
MonitorBase<T>(reporterId, monitorId, parameterId, confirmationLimit), limit(limit), violationEvent(violationEvent), aboveIsViolation(aboveIsViolation) {
AbsLimitMonitor(object_id_t reporterId, uint8_t monitorId,
gp_id_t globalPoolId, uint16_t confirmationLimit, T limit,
Event violationEvent = MonitoringIF::VALUE_OUT_OF_RANGE,
bool aboveIsViolation = true) :
MonitorBase<T>(reporterId, monitorId, globalPoolId,
confirmationLimit),
limit(limit), violationEvent(violationEvent),
aboveIsViolation(aboveIsViolation) {
}
virtual ~AbsLimitMonitor() {
}
@ -32,8 +37,9 @@ public:
const ParameterWrapper *newValues, uint16_t startAtIndex) {
ReturnValue_t result = this->MonitorBase<T>::getParameter(domainId,
parameterId, parameterWrapper, newValues, startAtIndex);
//We'll reuse the DOMAIN_ID of MonitorReporter, as we know the parameterIds used there.
if (result != this->INVALID_MATRIX_ID) {
// We'll reuse the DOMAIN_ID of MonitorReporter,
// as we know the parameterIds used there.
if (result != this->INVALID_IDENTIFIER_ID) {
return result;
}
switch (parameterId) {
@ -41,7 +47,7 @@ public:
parameterWrapper->set(this->limit);
break;
default:
return this->INVALID_MATRIX_ID;
return this->INVALID_IDENTIFIER_ID;
}
return HasReturnvaluesIF::RETURN_OK;
}
@ -59,7 +65,9 @@ protected:
void sendTransitionEvent(T currentValue, ReturnValue_t state) {
switch (state) {
case MonitoringIF::OUT_OF_RANGE:
EventManagerIF::triggerEvent(this->reportingId, violationEvent, this->parameterId);
EventManagerIF::triggerEvent(this->reportingId,
violationEvent, this->globalPoolId.objectId,
this->globalPoolId.localPoolId);
break;
default:
break;
@ -70,4 +78,4 @@ protected:
const bool aboveIsViolation;
};
#endif /* FRAMEWORK_MONITORING_ABSLIMITMONITOR_H_ */
#endif /* FSFW_MONITORING_ABSLIMITMONITOR_H_ */

View File

@ -1,11 +1,5 @@
/**
* @file HasMonitorsIF.h
* @brief This file defines the HasMonitorsIF class.
* @date 28.07.2014
* @author baetz
*/
#ifndef HASMONITORSIF_H_
#define HASMONITORSIF_H_
#ifndef FSFW_MONITORING_HASMONITORSIF_H_
#define FSFW_MONITORING_HASMONITORSIF_H_
#include "../events/EventReportingProxyIF.h"
#include "../objectmanager/ObjectManagerIF.h"
@ -27,4 +21,4 @@ public:
}
};
#endif /* HASMONITORSIF_H_ */
#endif /* FSFW_MONITORING_HASMONITORSIF_H_ */

View File

@ -12,13 +12,15 @@
template<typename T>
class LimitMonitor: public MonitorBase<T> {
public:
LimitMonitor(object_id_t reporterId, uint8_t monitorId, uint32_t parameterId,
uint16_t confirmationLimit, T lowerLimit, T upperLimit,
Event belowLowEvent = MonitoringIF::VALUE_BELOW_LOW_LIMIT,
LimitMonitor(object_id_t reporterId, uint8_t monitorId,
gp_id_t globalPoolId, uint16_t confirmationLimit, T lowerLimit,
T upperLimit, Event belowLowEvent =
MonitoringIF::VALUE_BELOW_LOW_LIMIT,
Event aboveHighEvent = MonitoringIF::VALUE_ABOVE_HIGH_LIMIT) :
MonitorBase<T>(reporterId, monitorId, parameterId, confirmationLimit), lowerLimit(
lowerLimit), upperLimit(upperLimit), belowLowEvent(
belowLowEvent), aboveHighEvent(aboveHighEvent) {
MonitorBase<T>(reporterId, monitorId, globalPoolId,
confirmationLimit),
lowerLimit(lowerLimit), upperLimit(upperLimit),
belowLowEvent(belowLowEvent), aboveHighEvent(aboveHighEvent) {
}
virtual ~LimitMonitor() {
}
@ -41,7 +43,7 @@ public:
ReturnValue_t result = this->MonitorBase<T>::getParameter(domainId,
parameterId, parameterWrapper, newValues, startAtIndex);
//We'll reuse the DOMAIN_ID of MonitorReporter, as we know the parameterIds used there.
if (result != this->INVALID_MATRIX_ID) {
if (result != this->INVALID_IDENTIFIER_ID) {
return result;
}
switch (parameterId) {
@ -52,12 +54,13 @@ public:
parameterWrapper->set(this->upperLimit);
break;
default:
return this->INVALID_MATRIX_ID;
return this->INVALID_IDENTIFIER_ID;
}
return HasReturnvaluesIF::RETURN_OK;
}
bool isOutOfLimits() {
if (this->oldState == MonitoringIF::ABOVE_HIGH_LIMIT || this->oldState == MonitoringIF::BELOW_LOW_LIMIT) {
if (this->oldState == MonitoringIF::ABOVE_HIGH_LIMIT or
this->oldState == MonitoringIF::BELOW_LOW_LIMIT) {
return true;
} else {
return false;
@ -76,10 +79,12 @@ protected:
void sendTransitionEvent(T currentValue, ReturnValue_t state) {
switch (state) {
case MonitoringIF::BELOW_LOW_LIMIT:
EventManagerIF::triggerEvent(this->reportingId, belowLowEvent, this->parameterId);
EventManagerIF::triggerEvent(this->reportingId, belowLowEvent,
this->globalPoolId.objectId, this->globalPoolId.localPoolId);
break;
case MonitoringIF::ABOVE_HIGH_LIMIT:
EventManagerIF::triggerEvent(this->reportingId, aboveHighEvent, this->parameterId);
EventManagerIF::triggerEvent(this->reportingId, aboveHighEvent,
this->globalPoolId.objectId, this->globalPoolId.localPoolId);
break;
default:
break;

View File

@ -1,39 +1,50 @@
#ifndef MONITORBASE_H_
#define MONITORBASE_H_
#ifndef FSFW_MONITORING_MONITORBASE_H_
#define FSFW_MONITORING_MONITORBASE_H_
#include "LimitViolationReporter.h"
#include "MonitoringIF.h"
#include "MonitoringMessageContent.h"
#include "MonitorReporter.h"
#include "../datapoollocal/LocalPoolVariable.h"
#include "../datapoolglob/GlobalDataSet.h"
#include "../datapoolglob/PIDReader.h"
#include "../monitoring/LimitViolationReporter.h"
#include "../monitoring/MonitoringIF.h"
#include "../monitoring/MonitoringMessageContent.h"
#include "../monitoring/MonitorReporter.h"
/**
* Base class for monitoring of parameters.
* Can be used anywhere, specializations need to implement checkSample and should override sendTransitionEvent.
* Manages state handling, enabling and disabling of events/reports and forwarding of transition
* reports via MonitorReporter. In addition, it provides default implementations for fetching the parameter sample from
* the data pool and a simple confirmation counter.
* @brief Base class for monitoring of parameters.
* @details
* Can be used anywhere, specializations need to implement checkSample and
* should override sendTransitionEvent.
* Manages state handling, enabling and disabling of events/reports and
* forwarding of transition reports via MonitorReporter.
*
* In addition, it provides default implementations for fetching the
* parameter sample from the data pool and a simple confirmation counter.
*/
template<typename T>
class MonitorBase: public MonitorReporter<T> {
public:
MonitorBase(object_id_t reporterId, uint8_t monitorId,
uint32_t parameterId, uint16_t confirmationLimit) :
MonitorReporter<T>(reporterId, monitorId, parameterId, confirmationLimit) {
gp_id_t globalPoolId, uint16_t confirmationLimit):
MonitorReporter<T>(reporterId, monitorId, globalPoolId,
confirmationLimit),
poolVariable(globalPoolId) {
}
virtual ~MonitorBase() {
}
virtual ReturnValue_t check() {
// 1. Fetch sample of type T, return validity.
T sample = 0;
ReturnValue_t validity = fetchSample(&sample);
//2. If returning from fetch != OK, parameter is invalid. Report (if oldState is != invalidity).
// 2. If returning from fetch != OK, parameter is invalid.
// Report (if oldState is != invalidity).
if (validity != HasReturnvaluesIF::RETURN_OK) {
this->monitorStateIs(validity, sample, 0);
//3. Otherwise, check sample.
} else {
//3. Otherwise, check sample.
this->oldState = doCheck(sample);
}
return this->oldState;
@ -43,20 +54,25 @@ public:
ReturnValue_t currentState = checkSample(sample, &crossedLimit);
return this->monitorStateIs(currentState,sample, crossedLimit);
}
// Abstract or default.
virtual ReturnValue_t checkSample(T sample, T* crossedLimit) = 0;
protected:
virtual ReturnValue_t fetchSample(T* sample) {
GlobDataSet mySet;
PIDReader<T> parameter(this->parameterId, &mySet);
mySet.read();
if (!parameter.isValid()) {
ReturnValue_t result = poolVariable.read();
if(result != HasReturnvaluesIF::RETURN_OK) {
return result;
}
if (not poolVariable.isValid()) {
return MonitoringIF::INVALID;
}
*sample = parameter.value;
*sample = poolVariable.value;
return HasReturnvaluesIF::RETURN_OK;
}
LocalPoolVar<T> poolVariable;
};
#endif /* MONITORBASE_H_ */
#endif /* FSFW_MONITORING_MONITORBASE_H_ */

View File

@ -1,10 +1,12 @@
#ifndef FRAMEWORK_MONITORING_MONITORREPORTER_H_
#define FRAMEWORK_MONITORING_MONITORREPORTER_H_
#ifndef FSFW_MONITORING_MONITORREPORTER_H_
#define FSFW_MONITORING_MONITORREPORTER_H_
#include "../events/EventManagerIF.h"
#include "LimitViolationReporter.h"
#include "MonitoringIF.h"
#include "MonitoringMessageContent.h"
#include "../datapoollocal/locPoolDefinitions.h"
#include "../events/EventManagerIF.h"
#include "../parameters/HasParametersIF.h"
template<typename T>
@ -14,11 +16,14 @@ public:
static const uint8_t ENABLED = 1;
static const uint8_t DISABLED = 0;
MonitorReporter(object_id_t reportingId, uint8_t monitorId, uint32_t parameterId, uint16_t confirmationLimit) :
monitorId(monitorId), parameterId(parameterId), reportingId(
reportingId), oldState(MonitoringIF::UNCHECKED), reportingEnabled(
ENABLED), eventEnabled(ENABLED), currentCounter(0), confirmationLimit(
confirmationLimit) {
// TODO: Adapt to use SID instead of parameter ID.
MonitorReporter(object_id_t reportingId, uint8_t monitorId,
gp_id_t globalPoolId, uint16_t confirmationLimit) :
monitorId(monitorId), globalPoolId(globalPoolId),
reportingId(reportingId), oldState(MonitoringIF::UNCHECKED),
reportingEnabled(ENABLED), eventEnabled(ENABLED), currentCounter(0),
confirmationLimit(confirmationLimit) {
}
virtual ~MonitorReporter() {
@ -63,7 +68,7 @@ public:
parameterWrapper->set(this->eventEnabled);
break;
default:
return INVALID_MATRIX_ID;
return INVALID_IDENTIFIER_ID;
}
return HasReturnvaluesIF::RETURN_OK;
}
@ -91,7 +96,7 @@ public:
protected:
const uint8_t monitorId;
const uint32_t parameterId;
const gp_id_t globalPoolId;
object_id_t reportingId;
ReturnValue_t oldState;
@ -148,7 +153,8 @@ protected:
case HasReturnvaluesIF::RETURN_OK:
break;
default:
EventManagerIF::triggerEvent(reportingId, MonitoringIF::MONITOR_CHANGED_STATE, state);
EventManagerIF::triggerEvent(reportingId,
MonitoringIF::MONITOR_CHANGED_STATE, state);
break;
}
}
@ -159,14 +165,15 @@ protected:
* @param crossedLimit The limit crossed (if applicable).
* @param state Current state the monitor is in.
*/
virtual void sendTransitionReport(T parameterValue, T crossedLimit, ReturnValue_t state) {
MonitoringReportContent<T> report(parameterId,
virtual void sendTransitionReport(T parameterValue, T crossedLimit,
ReturnValue_t state) {
MonitoringReportContent<T> report(globalPoolId,
parameterValue, crossedLimit, oldState, state);
LimitViolationReporter::sendLimitViolationReport(&report);
}
ReturnValue_t setToState(ReturnValue_t state) {
if (oldState != state && reportingEnabled) {
MonitoringReportContent<T> report(parameterId, 0, 0, oldState,
MonitoringReportContent<T> report(globalPoolId, 0, 0, oldState,
state);
LimitViolationReporter::sendLimitViolationReport(&report);
oldState = state;
@ -175,4 +182,4 @@ protected:
}
};
#endif /* FRAMEWORK_MONITORING_MONITORREPORTER_H_ */
#endif /* FSFW_MONITORING_MONITORREPORTER_H_ */

View File

@ -1,8 +1,8 @@
#ifndef MONITORINGIF_H_
#define MONITORINGIF_H_
#ifndef FSFW_MONITORING_MONITORINGIF_H_
#define FSFW_MONITORING_MONITORINGIF_H_
#include "../memory/HasMemoryIF.h"
#include "MonitoringMessage.h"
#include "../memory/HasMemoryIF.h"
#include "../serialize/SerializeIF.h"
class MonitoringIF : public SerializeIF {
@ -64,4 +64,4 @@ public:
#endif /* MONITORINGIF_H_ */
#endif /* FSFW_MONITORING_MONITORINGIF_H_ */

View File

@ -3,6 +3,7 @@
#include "HasMonitorsIF.h"
#include "MonitoringIF.h"
#include "../datapoollocal/locPoolDefinitions.h"
#include "../objectmanager/ObjectManagerIF.h"
#include "../serialize/SerialBufferAdapter.h"
#include "../serialize/SerialFixedArrayListAdapter.h"
@ -16,12 +17,17 @@ void setStaticFrameworkObjectIds();
}
//PID(uint32_t), TYPE, LIMIT_ID, value,limitValue, previous, later, timestamp
/**
* @brief Does magic.
* @tparam T
*/
template<typename T>
class MonitoringReportContent: public SerialLinkedListAdapter<SerializeIF> {
friend void (Factory::setStaticFrameworkObjectIds)();
public:
SerializeElement<uint8_t> monitorId;
SerializeElement<uint32_t> parameterId;
SerializeElement<uint32_t> parameterObjectId;
SerializeElement<lp_id_t> localPoolId;
SerializeElement<T> parameterValue;
SerializeElement<T> limitValue;
SerializeElement<ReturnValue_t> oldState;
@ -30,20 +36,23 @@ public:
SerializeElement<SerialBufferAdapter<uint8_t>> timestampSerializer;
TimeStamperIF* timeStamper;
MonitoringReportContent() :
SerialLinkedListAdapter<SerializeIF>(
LinkedElement<SerializeIF>::Iterator(&parameterId)), monitorId(0), parameterId(
0), parameterValue(0), limitValue(0), oldState(0), newState(
0), rawTimestamp( { 0 }), timestampSerializer(rawTimestamp,
SerialLinkedListAdapter<SerializeIF>(&parameterObjectId),
monitorId(0), parameterObjectId(0),
localPoolId(0), parameterValue(0),
limitValue(0), oldState(0), newState(0),
rawTimestamp( { 0 }), timestampSerializer(rawTimestamp,
sizeof(rawTimestamp)), timeStamper(NULL) {
setAllNext();
}
MonitoringReportContent(uint32_t setPID, T value, T limitValue,
MonitoringReportContent(gp_id_t globalPoolId, T value, T limitValue,
ReturnValue_t oldState, ReturnValue_t newState) :
SerialLinkedListAdapter<SerializeIF>(
LinkedElement<SerializeIF>::Iterator(&parameterId)), monitorId(0), parameterId(
setPID), parameterValue(value), limitValue(limitValue), oldState(
oldState), newState(newState), timestampSerializer(rawTimestamp,
sizeof(rawTimestamp)), timeStamper(NULL) {
SerialLinkedListAdapter<SerializeIF>(&parameterObjectId),
monitorId(0), parameterObjectId(globalPoolId.objectId),
localPoolId(globalPoolId.localPoolId),
parameterValue(value), limitValue(limitValue),
oldState(oldState), newState(newState),
timestampSerializer(rawTimestamp, sizeof(rawTimestamp)),
timeStamper(NULL) {
setAllNext();
if (checkAndSetStamper()) {
timeStamper->addTimeStamp(rawTimestamp, sizeof(rawTimestamp));
@ -53,16 +62,16 @@ private:
static object_id_t timeStamperId;
void setAllNext() {
parameterId.setNext(&parameterValue);
parameterObjectId.setNext(&parameterValue);
parameterValue.setNext(&limitValue);
limitValue.setNext(&oldState);
oldState.setNext(&newState);
newState.setNext(&timestampSerializer);
}
bool checkAndSetStamper() {
if (timeStamper == NULL) {
if (timeStamper == nullptr) {
timeStamper = objectManager->get<TimeStamperIF>( timeStamperId );
if ( timeStamper == NULL ) {
if ( timeStamper == nullptr ) {
sif::error << "MonitoringReportContent::checkAndSetStamper: "
"Stamper not found!" << std::endl;
return false;

View File

@ -82,7 +82,7 @@ public:
parameterWrapper->set(limit);
break;
default:
return INVALID_MATRIX_ID;
return INVALID_IDENTIFIER_ID;
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,12 +1,16 @@
#ifndef FSFW_PARAMETERS_HASPARAMETERSIF_H_
#define FSFW_PARAMETERS_HASPARAMETERSIF_H_
#include "../parameters/ParameterWrapper.h"
#include "ParameterWrapper.h"
#include "../returnvalues/HasReturnvaluesIF.h"
#include <stdint.h>
#include <cstdint>
/** Each parameter is identified with a unique parameter ID */
typedef uint32_t ParameterId_t;
/**
* Each parameter is identified with a unique parameter ID
* The first byte of the parameter ID will denote the domain ID.
* The second and third byte will be the unique identifier number.
*/
using ParameterId_t = uint32_t;
/**
* @brief This interface is used by components which have modifiable
@ -16,16 +20,15 @@ typedef uint32_t ParameterId_t;
* ID is the domain ID which can be used to identify unqiue spacecraft domains
* (e.g. control and sensor domain in the AOCS controller).
*
* The second and third byte represent the matrix ID, which can represent
* a 8-bit row and column number and the last byte...
* The second byte is a unique identfier ID.
*
* Yeah, it it matrix ID oder parameter ID now and is index a 16 bit number
* of a 8 bit number now?
* The third and fourth byte can be used as a linear index for matrix or array
* parameter entries.
*/
class HasParametersIF {
public:
static const uint8_t INTERFACE_ID = CLASS_ID::HAS_PARAMETERS_IF;
static const ReturnValue_t INVALID_MATRIX_ID = MAKE_RETURN_CODE(0x01);
static const ReturnValue_t INVALID_IDENTIFIER_ID = MAKE_RETURN_CODE(0x01);
static const ReturnValue_t INVALID_DOMAIN_ID = MAKE_RETURN_CODE(0x02);
static const ReturnValue_t INVALID_VALUE = MAKE_RETURN_CODE(0x03);
static const ReturnValue_t READ_ONLY = MAKE_RETURN_CODE(0x05);
@ -34,33 +37,45 @@ public:
return id >> 24;
}
static uint16_t getMatrixId(ParameterId_t id) {
return id >> 8;
static uint8_t getUniqueIdentifierId(ParameterId_t id) {
return id >> 16;
}
static uint8_t getIndex(ParameterId_t id) {
/**
* Get the index of a parameter. Please note that the index is always a
* linear index. For a vector, this is straightforward.
* For a matrix, the linear indexing run from left to right, top to bottom.
* @param id
* @return
*/
static uint16_t getIndex(ParameterId_t id) {
return id;
}
static uint32_t getFullParameterId(uint8_t domainId, uint16_t parameterId,
uint8_t index) {
return (domainId << 24) + (parameterId << 8) + index;
static uint32_t getFullParameterId(uint8_t domainId,
uint8_t uniqueIdentifier, uint16_t linearIndex) {
return (domainId << 24) + (uniqueIdentifier << 16) + linearIndex;
}
virtual ~HasParametersIF() {}
/**
* This is the generic function overriden by child classes to set
* parameters. To set a parameter, the parameter wrapper is used with
* a variety of set functions. The provided values can be checked with
* newValues.
* Always set parameter before checking newValues!
*
* @param domainId
* @param parameterId
* @param parameterWrapper
* @param newValues
* @param startAtIndex
* @param startAtIndex Linear index, runs left to right, top to bottom for
* matrix indexes.
* @return
*/
virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId,
ParameterWrapper *parameterWrapper,
virtual ReturnValue_t getParameter(uint8_t domainId,
uint16_t uniqueIdentifier, ParameterWrapper *parameterWrapper,
const ParameterWrapper *newValues, uint16_t startAtIndex) = 0;
};

View File

@ -9,15 +9,20 @@ ParameterHelper::~ParameterHelper() {
}
ReturnValue_t ParameterHelper::handleParameterMessage(CommandMessage *message) {
if(storage == nullptr) {
// ParameterHelper was not initialized
return HasReturnvaluesIF::RETURN_FAILED;
}
ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED;
switch (message->getCommand()) {
case ParameterMessage::CMD_PARAMETER_DUMP: {
ParameterWrapper description;
uint8_t domain = HasParametersIF::getDomain(
ParameterMessage::getParameterId(message));
uint16_t parameterId = HasParametersIF::getMatrixId(
uint8_t uniqueIdentifier = HasParametersIF::getUniqueIdentifierId(
ParameterMessage::getParameterId(message));
result = owner->getParameter(domain, parameterId,
result = owner->getParameter(domain, uniqueIdentifier,
&description, &description, 0);
if (result == HasReturnvaluesIF::RETURN_OK) {
result = sendParameter(message->getSender(),
@ -26,49 +31,48 @@ ReturnValue_t ParameterHelper::handleParameterMessage(CommandMessage *message) {
}
break;
case ParameterMessage::CMD_PARAMETER_LOAD: {
uint8_t domain = HasParametersIF::getDomain(
ParameterMessage::getParameterId(message));
uint16_t parameterId = HasParametersIF::getMatrixId(
ParameterMessage::getParameterId(message));
uint8_t index = HasParametersIF::getIndex(
ParameterMessage::getParameterId(message));
ParameterId_t parameterId = 0;
uint8_t ptc = 0;
uint8_t pfc = 0;
uint8_t rows = 0;
uint8_t columns = 0;
store_address_t storeId = ParameterMessage::getParameterLoadCommand(
message, &parameterId, &ptc, &pfc, &rows, &columns);
Type type(Type::getActualType(ptc, pfc));
const uint8_t *storedStream = nullptr;
size_t storedStreamSize = 0;
result = storage->getData(
ParameterMessage::getStoreId(message), &storedStream,
&storedStreamSize);
uint8_t domain = HasParametersIF::getDomain(parameterId);
uint8_t uniqueIdentifier = HasParametersIF::getUniqueIdentifierId(
parameterId);
uint16_t linearIndex = HasParametersIF::getIndex(parameterId);
ConstStorageAccessor accessor(storeId);
result = storage->getData(storeId, accessor);
if (result != HasReturnvaluesIF::RETURN_OK) {
sif::error << "ParameterHelper::handleParameterMessage: Getting"
" store data failed for load command." << std::endl;
<< " store data failed for load command." << std::endl;
break;
}
ParameterWrapper streamWrapper;
result = streamWrapper.set(storedStream, storedStreamSize);
result = streamWrapper.set(type, rows, columns, accessor.data(),
accessor.size());
if(result != HasReturnvaluesIF::RETURN_OK) {
storage->deleteData(ParameterMessage::getStoreId(message));
break;
return result;
}
ParameterWrapper ownerWrapper;
result = owner->getParameter(domain, parameterId, &ownerWrapper,
&streamWrapper, index);
result = owner->getParameter(domain, uniqueIdentifier, &ownerWrapper,
&streamWrapper, linearIndex);
result = ownerWrapper.copyFrom(&streamWrapper, linearIndex);
if (result != HasReturnvaluesIF::RETURN_OK) {
storage->deleteData(ParameterMessage::getStoreId(message));
break;
return result;
}
result = ownerWrapper.copyFrom(&streamWrapper, index);
storage->deleteData(ParameterMessage::getStoreId(message));
if (result == HasReturnvaluesIF::RETURN_OK) {
result = sendParameter(message->getSender(),
ParameterMessage::getParameterId(message), &ownerWrapper);
}
}
break;
}
default:
return HasReturnvaluesIF::RETURN_FAILED;
}
@ -115,13 +119,11 @@ ReturnValue_t ParameterHelper::sendParameter(MessageQueueId_t to, uint32_t id,
ReturnValue_t ParameterHelper::initialize() {
ownerQueueId = owner->getCommandQueue();
storage = objectManager->get<StorageManagerIF>(objects::IPC_STORE);
if (storage == NULL) {
return HasReturnvaluesIF::RETURN_FAILED;
} else {
return HasReturnvaluesIF::RETURN_OK;
if (storage == nullptr) {
return ObjectManagerIF::CHILD_INIT_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
}
void ParameterHelper::rejectCommand(MessageQueueId_t to, ReturnValue_t reason,

View File

@ -25,10 +25,26 @@ void ParameterMessage::setParameterDumpReply(CommandMessage* message,
}
void ParameterMessage::setParameterLoadCommand(CommandMessage* message,
ParameterId_t id, store_address_t storageID) {
ParameterId_t id, store_address_t storeId, uint8_t ptc, uint8_t pfc,
uint8_t rows = 1, uint8_t columns = 1) {
message->setCommand(CMD_PARAMETER_LOAD);
message->setParameter(id);
message->setParameter2(storageID.raw);
message->setParameter2(storeId.raw);
uint32_t packedParameterSettings = (ptc << 24) | (pfc << 16) |
(rows << 8) | columns;
message->setParameter3(packedParameterSettings);
}
store_address_t ParameterMessage::getParameterLoadCommand(
const CommandMessage *message, ParameterId_t* parameterId, uint8_t *ptc,
uint8_t *pfc, uint8_t *rows, uint8_t *columns) {
*parameterId = message->getParameter2();
uint32_t packedParamSettings = message->getParameter3();
*ptc = packedParamSettings >> 24 & 0xff;
*pfc = packedParamSettings >> 16 & 0xff;
*rows = packedParamSettings >> 8 & 0xff;
*columns = packedParamSettings & 0xff;
return message->getParameter2();
}
void ParameterMessage::clear(CommandMessage* message) {

View File

@ -5,6 +5,20 @@
#include "../ipc/CommandMessage.h"
#include "../storagemanager/StorageManagerIF.h"
/**
* @brief ParameterMessage interface
* @details
* General structure of a parameter message:
* 1. 4-byte Object ID
* 2. 4-byte Parameter ID, first byte is Domain ID, second byte is unique
* identifier, third and fourth byte is linear index to start from
* 3. 4-byte Parameter Settings. First byte and second byte are the PTC and PFC
* ECSS type identifiers (see ECSS-E-ST-70-41C15 p.428 or Type class in
* globalfunctions). Third byte is the number of rows and fourth byte
* is the number of columns. For single variable parameters, this will
* be [1, 1].
*
*/
class ParameterMessage {
private:
ParameterMessage();
@ -20,8 +34,27 @@ public:
ParameterId_t id);
static void setParameterDumpReply(CommandMessage* message,
ParameterId_t id, store_address_t storageID);
/**
* Command to set a load parameter message. The CCSDS / ECSS type in
* form of a PTC and a PFC is expected. See ECSS-E-ST-70-41C15 p.428
* for all types or the Type class in globalfunctions.
* @param message
* @param id
* @param storeId
* @param ptc Type information according to CCSDS/ECSS standards
* @param pfc Type information according to CCSDS/ECSS standards
* @param rows Set number of rows in parameter set, minimum one.
* @param columns Set number of columns in parameter set, minimum one
*/
static void setParameterLoadCommand(CommandMessage* message,
ParameterId_t id, store_address_t storageID);
ParameterId_t id, store_address_t storeId, uint8_t ptc,
uint8_t pfc, uint8_t rows, uint8_t columns);
static store_address_t getParameterLoadCommand(
const CommandMessage* message, ParameterId_t* parameterId,
uint8_t* ptc, uint8_t* pfc, uint8_t* rows, uint8_t* columns) ;
static void clear(CommandMessage* message);
};

View File

@ -115,7 +115,7 @@ ReturnValue_t ParameterWrapper::deSerializeData(uint8_t startingRow,
uint8_t fromColumns) {
//treat from as a continuous Stream as we copy all of it
const uint8_t *fromAsStream = (const uint8_t*) from;
const uint8_t *fromAsStream = reinterpret_cast<const uint8_t*>(from);
size_t streamSize = fromRows * fromColumns * sizeof(T);
ReturnValue_t result = HasReturnvaluesIF::RETURN_OK;
@ -123,8 +123,9 @@ ReturnValue_t ParameterWrapper::deSerializeData(uint8_t startingRow,
for (uint8_t fromRow = 0; fromRow < fromRows; fromRow++) {
//get the start element of this row in data
T *dataWithDataType = ((T*) data)
+ (((startingRow + fromRow) * columns) + startingColumn);
uint16_t offset = (((startingRow + fromRow) *
static_cast<uint16_t>(columns)) + startingColumn);
T *dataWithDataType = static_cast<T*>(data) + offset;
for (uint8_t fromColumn = 0; fromColumn < fromColumns; fromColumn++) {
result = SerializeAdapter::deSerialize(
@ -159,6 +160,23 @@ ReturnValue_t ParameterWrapper::deSerialize(const uint8_t **buffer,
return copyFrom(&streamDescription, startWritingAtIndex);
}
ReturnValue_t ParameterWrapper::set(Type type, uint8_t rows, uint8_t columns,
const void *data, size_t dataSize) {
this->type = type;
this->rows = rows;
this->columns = columns;
size_t expectedSize = type.getSize() * rows * columns;
if (expectedSize < dataSize) {
return SerializeIF::STREAM_TOO_SHORT;
}
this->data = nullptr;
this->readonlyData = data;
pointsToStream = true;
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t ParameterWrapper::set(const uint8_t *stream, size_t streamSize,
const uint8_t **remainingStream, size_t *remainingSize) {
ReturnValue_t result = SerializeAdapter::deSerialize(&type, &stream,
@ -202,11 +220,13 @@ ReturnValue_t ParameterWrapper::set(const uint8_t *stream, size_t streamSize,
ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
uint16_t startWritingAtIndex) {
if (data == NULL) {
// TODO: Optional diagnostic output (which can be disabled in FSFWConfig)
// to determined faulty implementations and configuration errors quickly.
if (data == nullptr) {
return READONLY;
}
if (from->readonlyData == NULL) {
if (from->readonlyData == nullptr) {
return SOURCE_NOT_SET;
}
@ -214,9 +234,16 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
return DATATYPE_MISSMATCH;
}
// The smallest allowed value for rows and columns is one.
if(rows == 0 or columns == 0) {
return COLUMN_OR_ROWS_ZERO;
}
//check if from fits into this
uint8_t startingRow = startWritingAtIndex / columns;
uint8_t startingColumn = startWritingAtIndex % columns;
uint8_t startingRow = 0;
uint8_t startingColumn = 0;
ParameterWrapper::convertLinearIndexToRowAndColumn(startWritingAtIndex,
&startingRow, &startingColumn);
if ((from->rows > (rows - startingRow))
|| (from->columns > (columns - startingColumn))) {
@ -270,8 +297,8 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
//need a type to do arithmetic
uint8_t* typedData = static_cast<uint8_t*>(data);
for (uint8_t fromRow = 0; fromRow < from->rows; fromRow++) {
size_t offset = (((startingRow + fromRow) * columns) +
startingColumn) * typeSize;
size_t offset = (((startingRow + fromRow) * static_cast<uint16_t>(
columns)) + startingColumn) * typeSize;
std::memcpy(typedData + offset, from->readonlyData,
typeSize * from->columns);
}
@ -279,3 +306,18 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
return result;
}
void ParameterWrapper::convertLinearIndexToRowAndColumn(uint16_t index,
uint8_t *row, uint8_t *column) {
if(row == nullptr or column == nullptr) {
return;
}
// Integer division.
*row = index / columns;
*column = index % columns;
}
uint16_t ParameterWrapper::convertRowAndColumnToLinearIndex(uint8_t row,
uint8_t column) {
return row * columns + column;
}

View File

@ -22,6 +22,7 @@ public:
static const ReturnValue_t SOURCE_NOT_SET = MAKE_RETURN_CODE(0x05);
static const ReturnValue_t OUT_OF_BOUNDS = MAKE_RETURN_CODE(0x06);
static const ReturnValue_t NOT_SET = MAKE_RETURN_CODE(0x07);
static const ReturnValue_t COLUMN_OR_ROWS_ZERO = MAKE_RETURN_CODE(0x08);
ParameterWrapper();
ParameterWrapper(Type type, uint8_t rows, uint8_t columns, void *data);
@ -68,7 +69,7 @@ public:
template<typename T>
void set(const T *readonlyData, uint8_t rows, uint8_t columns) {
this->data = NULL;
this->data = nullptr;
this->readonlyData = readonlyData;
this->type = PodTypeConversion<T>::type;
this->rows = rows;
@ -97,14 +98,19 @@ public:
}
template<typename T>
void setMatrix(T& member) {
this->set(member[0], sizeof(member)/sizeof(member[0]), sizeof(member[0])/sizeof(member[0][0]));
this->set(member[0], sizeof(member)/sizeof(member[0]),
sizeof(member[0])/sizeof(member[0][0]));
}
template<typename T>
void setMatrix(const T& member) {
this->set(member[0], sizeof(member)/sizeof(member[0]), sizeof(member[0])/sizeof(member[0][0]));
this->set(member[0], sizeof(member)/sizeof(member[0]),
sizeof(member[0])/sizeof(member[0][0]));
}
ReturnValue_t set(Type type, uint8_t rows, uint8_t columns,
const void *data, size_t dataSize);
ReturnValue_t set(const uint8_t *stream, size_t streamSize,
const uint8_t **remainingStream = nullptr,
size_t *remainingSize = nullptr);
@ -113,6 +119,13 @@ public:
uint16_t startWritingAtIndex);
private:
void convertLinearIndexToRowAndColumn(uint16_t index,
uint8_t *row, uint8_t *column);
uint16_t convertRowAndColumnToLinearIndex(uint8_t row,
uint8_t column);
bool pointsToStream = false;
Type type;
@ -148,9 +161,9 @@ inline ReturnValue_t ParameterWrapper::getElement(T *value, uint8_t row,
if (pointsToStream) {
const uint8_t *streamWithType = static_cast<const uint8_t*>(readonlyData);
streamWithType += (row * columns + column) * type.getSize();
int32_t size = type.getSize();
size_t size = type.getSize();
return SerializeAdapter::deSerialize(value, &streamWithType,
&size, true);
&size, SerializeIF::Endianness::BIG);
}
else {
const T *dataWithType = static_cast<const T*>(readonlyData);

View File

@ -1,22 +1,25 @@
#include "Fuse.h"
#include "../monitoring/LimitViolationReporter.h"
#include "../monitoring/MonitoringMessageContent.h"
#include "../objectmanager/ObjectManagerIF.h"
#include "../power/Fuse.h"
#include "../serialize/SerialFixedArrayListAdapter.h"
#include "../ipc/QueueFactory.h"
object_id_t Fuse::powerSwitchId = 0;
Fuse::Fuse(object_id_t fuseObjectId, uint8_t fuseId, VariableIds ids,
Fuse::Fuse(object_id_t fuseObjectId, uint8_t fuseId,
sid_t variableSet, VariableIds ids,
float maxCurrent, uint16_t confirmationCount) :
SystemObject(fuseObjectId), oldFuseState(0), fuseId(fuseId), powerIF(
NULL), currentLimit(fuseObjectId, 1, ids.pidCurrent, confirmationCount,
maxCurrent, FUSE_CURRENT_HIGH), powerMonitor(fuseObjectId, 2,
GlobalDataPool::poolIdAndPositionToPid(ids.poolIdPower, 0),
confirmationCount), set(), voltage(ids.pidVoltage, &set), current(
ids.pidCurrent, &set), state(ids.pidState, &set), power(
ids.poolIdPower, &set, PoolVariableIF::VAR_READ_WRITE), commandQueue(
NULL), parameterHelper(this), healthHelper(this, fuseObjectId) {
SystemObject(fuseObjectId), oldFuseState(0), fuseId(fuseId),
currentLimit(fuseObjectId, 1, ids.pidCurrent, confirmationCount,
maxCurrent, FUSE_CURRENT_HIGH),
powerMonitor(fuseObjectId, 2, ids.poolIdPower,
confirmationCount),
set(variableSet), voltage(ids.pidVoltage, &set),
current(ids.pidCurrent, &set), state(ids.pidState, &set),
power(ids.poolIdPower, &set, PoolVariableIF::VAR_READ_WRITE),
parameterHelper(this), healthHelper(this, fuseObjectId) {
commandQueue = QueueFactory::instance()->createMessageQueue();
}
@ -75,7 +78,7 @@ ReturnValue_t Fuse::check() {
float lowLimit = 0.0;
float highLimit = RESIDUAL_POWER;
calculatePowerLimits(&lowLimit, &highLimit);
result = powerMonitor.checkPower(power, lowLimit, highLimit);
result = powerMonitor.checkPower(power.value, lowLimit, highLimit);
if (result == MonitoringIF::BELOW_LOW_LIMIT) {
reportEvents(POWER_BELOW_LOW_LIMIT);
} else if (result == MonitoringIF::ABOVE_HIGH_LIMIT) {
@ -132,7 +135,7 @@ void Fuse::calculateFusePower() {
return;
}
//Calculate fuse power.
power = current * voltage;
power.value = current.value * voltage.value;
power.setValid(PoolVariableIF::VALID);
}
@ -190,12 +193,12 @@ void Fuse::checkFuseState() {
reportEvents(FUSE_WENT_OFF);
}
}
oldFuseState = state;
oldFuseState = state.value;
}
float Fuse::getPower() {
if (power.isValid()) {
return power;
return power.value;
} else {
return 0.0;
}

View File

@ -1,17 +1,16 @@
#ifndef FUSE_H_
#define FUSE_H_
#ifndef FSFW_POWER_FUSE_H_
#define FSFW_POWER_FUSE_H_
#include "PowerComponentIF.h"
#include "PowerSwitchIF.h"
#include "../datapoolglob/GlobalDataSet.h"
#include "../datapoolglob/GlobalPoolVariable.h"
#include "../datapoolglob/PIDReader.h"
#include "../devicehandlers/HealthDevice.h"
#include "../monitoring/AbsLimitMonitor.h"
#include "../power/PowerComponentIF.h"
#include "../power/PowerSwitchIF.h"
#include "../returnvalues/HasReturnvaluesIF.h"
#include "../parameters/ParameterHelper.h"
#include <list>
#include "../datapoollocal/StaticLocalDataSet.h"
namespace Factory {
void setStaticFrameworkObjectIds();
}
@ -26,10 +25,10 @@ private:
static constexpr float RESIDUAL_POWER = 0.005 * 28.5; //!< This is the upper limit of residual power lost by fuses and switches. Worst case is Fuse and one of two switches on. See PCDU ICD 1.9 p29 bottom
public:
struct VariableIds {
uint32_t pidVoltage;
uint32_t pidCurrent;
uint32_t pidState;
uint32_t poolIdPower;
gp_id_t pidVoltage;
gp_id_t pidCurrent;
gp_id_t pidState;
gp_id_t poolIdPower;
};
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PCDU_1;
@ -39,8 +38,8 @@ public:
static const Event POWER_BELOW_LOW_LIMIT = MAKE_EVENT(5, severity::LOW); //!< PSS detected a fuse that violates its limits.
typedef std::list<PowerComponentIF*> DeviceList;
Fuse(object_id_t fuseObjectId, uint8_t fuseId, VariableIds ids,
float maxCurrent, uint16_t confirmationCount = 2);
Fuse(object_id_t fuseObjectId, uint8_t fuseId, sid_t variableSet,
VariableIds ids, float maxCurrent, uint16_t confirmationCount = 2);
virtual ~Fuse();
void addDevice(PowerComponentIF *set);
float getPower();
@ -70,7 +69,7 @@ public:
private:
uint8_t oldFuseState;
uint8_t fuseId;
PowerSwitchIF *powerIF; //could be static in our case.
PowerSwitchIF *powerIF = nullptr; //could be static in our case.
AbsLimitMonitor<float> currentLimit;
class PowerMonitor: public MonitorReporter<float> {
public:
@ -85,12 +84,14 @@ private:
};
PowerMonitor powerMonitor;
GlobDataSet set;
PIDReader<float> voltage;
PIDReader<float> current;
PIDReader<uint8_t> state;
gp_float_t power;
MessageQueueIF* commandQueue;
StaticLocalDataSet<3> set;
lp_var_t<float> voltage;
lp_var_t<float> current;
lp_var_t<uint8_t> state;
lp_var_t<float> power;
MessageQueueIF* commandQueue = nullptr;
ParameterHelper parameterHelper;
HealthHelper healthHelper;
static object_id_t powerSwitchId;
@ -103,4 +104,4 @@ private:
bool areSwitchesOfComponentOn(DeviceList::iterator iter);
};
#endif /* FUSE_H_ */
#endif /* FSFW_POWER_FUSE_H_ */

View File

@ -1,20 +1,15 @@
/**
* @file PowerComponent.cpp
* @brief This file defines the PowerComponent class.
* @date 28.08.2014
* @author baetz
*/
#include "PowerComponent.h"
#include "../serialize/SerializeAdapter.h"
PowerComponent::PowerComponent() :
deviceObjectId(0), switchId1(0xFF), switchId2(0xFF), doIHaveTwoSwitches(
false), min(0.0), max(0.0), moduleId(0) {
PowerComponent::PowerComponent(): switchId1(0xFF), switchId2(0xFF),
doIHaveTwoSwitches(false) {
}
PowerComponent::PowerComponent(object_id_t setId, uint8_t moduleId, float min, float max,
uint8_t switchId1, bool twoSwitches, uint8_t switchId2) :
deviceObjectId(setId), switchId1(switchId1), switchId2(switchId2), doIHaveTwoSwitches(
twoSwitches), min(min), max(max), moduleId(moduleId) {
PowerComponent::PowerComponent(object_id_t setId, uint8_t moduleId, float min,
float max, uint8_t switchId1, bool twoSwitches, uint8_t switchId2) :
deviceObjectId(setId), switchId1(switchId1), switchId2(switchId2),
doIHaveTwoSwitches(twoSwitches), min(min), max(max),
moduleId(moduleId) {
}
ReturnValue_t PowerComponent::serialize(uint8_t** buffer, size_t* size,
@ -80,7 +75,7 @@ ReturnValue_t PowerComponent::getParameter(uint8_t domainId,
parameterWrapper->set<>(max);
break;
default:
return INVALID_MATRIX_ID;
return INVALID_IDENTIFIER_ID;
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,13 +1,17 @@
#ifndef POWERCOMPONENT_H_
#define POWERCOMPONENT_H_
#ifndef FSFW_POWER_POWERCOMPONENT_H_
#define FSFW_POWER_POWERCOMPONENT_H_
#include "../objectmanager/SystemObjectIF.h"
#include "PowerComponentIF.h"
#include "../objectmanager/frameworkObjects.h"
#include "../objectmanager/SystemObjectIF.h"
class PowerComponent: public PowerComponentIF {
public:
PowerComponent(object_id_t setId, uint8_t moduleId, float min, float max, uint8_t switchId1,
bool twoSwitches = false, uint8_t switchId2 = 0xFF);
PowerComponent(object_id_t setId, uint8_t moduleId, float min, float max,
uint8_t switchId1, bool twoSwitches = false,
uint8_t switchId2 = 0xFF);
virtual object_id_t getDeviceObjectId();
@ -31,18 +35,18 @@ public:
ParameterWrapper *parameterWrapper,
const ParameterWrapper *newValues, uint16_t startAtIndex);
private:
const object_id_t deviceObjectId;
const object_id_t deviceObjectId = objects::NO_OBJECT;
const uint8_t switchId1;
const uint8_t switchId2;
const bool doIHaveTwoSwitches;
float min;
float max;
float min = 0.0;
float max = 0.0;
uint8_t moduleId;
uint8_t moduleId = 0;
PowerComponent();
};
#endif /* POWERCOMPONENT_H_ */
#endif /* FSFW_POWER_POWERCOMPONENT_H_ */

View File

@ -1,14 +1,13 @@
#ifndef POWERCOMPONENTIF_H_
#define POWERCOMPONENTIF_H_
#ifndef FSFW_POWER_POWERCOMPONENTIF_H_
#define FSFW_POWER_POWERCOMPONENTIF_H_
#include "../serialize/SerializeIF.h"
#include "../parameters/HasParametersIF.h"
#include "../objectmanager/SystemObjectIF.h"
class PowerComponentIF : public SerializeIF, public HasParametersIF {
public:
virtual ~PowerComponentIF() {
}
virtual ~PowerComponentIF() {}
virtual object_id_t getDeviceObjectId() = 0;
@ -21,4 +20,4 @@ public:
};
#endif /* POWERCOMPONENTIF_H_ */
#endif /* FSFW_POWER_POWERCOMPONENTIF_H_ */

View File

@ -1,14 +1,18 @@
#include "PowerSensor.h"
#include "../ipc/QueueFactory.h"
PowerSensor::PowerSensor(object_id_t setId, VariableIds ids,
PowerSensor::PowerSensor(object_id_t objectId, sid_t setId, VariableIds ids,
DefaultLimits limits, SensorEvents events, uint16_t confirmationCount) :
SystemObject(setId), commandQueue(NULL), parameterHelper(this), healthHelper(this, setId), set(), current(
ids.pidCurrent, &set), voltage(ids.pidVoltage, &set), power(
ids.poolIdPower, &set, PoolVariableIF::VAR_WRITE), currentLimit(
setId, MODULE_ID_CURRENT, ids.pidCurrent, confirmationCount,
SystemObject(objectId), parameterHelper(this),
healthHelper(this, objectId),
powerSensorSet(setId), current(ids.pidCurrent, &powerSensorSet),
voltage(ids.pidVoltage, &powerSensorSet),
power(ids.poolIdPower, &powerSensorSet, PoolVariableIF::VAR_WRITE),
currentLimit(objectId, MODULE_ID_CURRENT, ids.pidCurrent, confirmationCount,
limits.currentMin, limits.currentMax, events.currentLow,
events.currentHigh), voltageLimit(setId, MODULE_ID_VOLTAGE,
events.currentHigh),
voltageLimit(objectId, MODULE_ID_VOLTAGE,
ids.pidVoltage, confirmationCount, limits.voltageMin,
limits.voltageMax, events.voltageLow, events.voltageHigh) {
commandQueue = QueueFactory::instance()->createMessageQueue();
@ -19,13 +23,13 @@ PowerSensor::~PowerSensor() {
}
ReturnValue_t PowerSensor::calculatePower() {
set.read();
powerSensorSet.read();
ReturnValue_t result1 = HasReturnvaluesIF::RETURN_FAILED;
ReturnValue_t result2 = HasReturnvaluesIF::RETURN_FAILED;
if (healthHelper.healthTable->isHealthy(getObjectId()) && voltage.isValid()
&& current.isValid()) {
result1 = voltageLimit.doCheck(voltage);
result2 = currentLimit.doCheck(current);
result1 = voltageLimit.doCheck(voltage.value);
result2 = currentLimit.doCheck(current.value);
} else {
voltageLimit.setToInvalid();
currentLimit.setToInvalid();
@ -37,9 +41,9 @@ ReturnValue_t PowerSensor::calculatePower() {
power.setValid(PoolVariableIF::INVALID);
} else {
power.setValid(PoolVariableIF::VALID);
power = current * voltage;
power.value = current.value * voltage.value;
}
set.commit();
powerSensorSet.commit();
return result1;
}
@ -92,8 +96,8 @@ void PowerSensor::checkCommandQueue() {
}
void PowerSensor::setDataPoolEntriesInvalid() {
set.read();
set.commit(PoolVariableIF::INVALID);
powerSensorSet.read();
powerSensorSet.commit(PoolVariableIF::INVALID);
}
float PowerSensor::getPower() {

View File

@ -1,9 +1,7 @@
#ifndef POWERSENSOR_H_
#define POWERSENSOR_H_
#ifndef FSFW_POWER_POWERSENSOR_H_
#define FSFW_POWER_POWERSENSOR_H_
#include "../datapoolglob/GlobalDataSet.h"
#include "../datapoolglob/GlobalPoolVariable.h"
#include "../datapoolglob/PIDReader.h"
#include "../datapoollocal/StaticLocalDataSet.h"
#include "../devicehandlers/HealthDevice.h"
#include "../monitoring/LimitMonitor.h"
#include "../parameters/ParameterHelper.h"
@ -12,15 +10,18 @@
class PowerController;
/**
* @brief Does magic.
*/
class PowerSensor: public SystemObject,
public ReceivesParameterMessagesIF,
public HasHealthIF {
friend class PowerController;
public:
struct VariableIds {
uint32_t pidCurrent;
uint32_t pidVoltage;
uint32_t poolIdPower;
gp_id_t pidCurrent;
gp_id_t pidVoltage;
gp_id_t poolIdPower;
};
struct DefaultLimits {
float currentMin;
@ -34,8 +35,9 @@ public:
Event voltageLow;
Event voltageHigh;
};
PowerSensor(object_id_t setId, VariableIds setIds, DefaultLimits limits,
SensorEvents events, uint16_t confirmationCount = 0);
PowerSensor(object_id_t objectId, sid_t sid, VariableIds setIds,
DefaultLimits limits, SensorEvents events,
uint16_t confirmationCount = 0);
virtual ~PowerSensor();
ReturnValue_t calculatePower();
ReturnValue_t performOperation(uint8_t opCode);
@ -50,15 +52,19 @@ public:
ParameterWrapper *parameterWrapper,
const ParameterWrapper *newValues, uint16_t startAtIndex);
private:
MessageQueueIF* commandQueue;
MessageQueueIF* commandQueue = nullptr;
ParameterHelper parameterHelper;
HealthHelper healthHelper;
GlobDataSet set;
//GlobDataSet set;
StaticLocalDataSet<3> powerSensorSet;
//Variables in
PIDReader<float> current;
PIDReader<float> voltage;
lp_var_t<float> current;
lp_var_t<float> voltage;
//PIDReader<float> current;
//PIDReader<float> voltage;
//Variables out
gp_float_t power;
lp_var_t<float> power;
//gp_float_t power;
static const uint8_t MODULE_ID_CURRENT = 1;
static const uint8_t MODULE_ID_VOLTAGE = 2;
@ -68,4 +74,4 @@ protected:
LimitMonitor<float> voltageLimit;
};
#endif /* POWERSENSOR_H_ */
#endif /* FSFW_POWER_POWERSENSOR_H_ */

View File

@ -1,18 +1,16 @@
/**
* @file PowerSwitchIF.h
* @brief This file defines the PowerSwitchIF class.
* @date 20.03.2013
* @author baetz
*/
#ifndef POWERSWITCHIF_H_
#define POWERSWITCHIF_H_
#ifndef FSFW_POWER_POWERSWITCHIF_H_
#define FSFW_POWER_POWERSWITCHIF_H_
#include "../events/Event.h"
#include "../returnvalues/HasReturnvaluesIF.h"
/**
* This interface defines a connection to a device that is capable of turning on and off
* switches of devices identified by a switch ID.
*
* @brief This interface defines a connection to a device that is capable of
* turning on and off switches of devices identified by a switch ID.
* @details
* The virtual functions of this interface do not allow to make any assignments
* because they can be called asynchronosuly (const ending).
* @ingroup interfaces
*/
class PowerSwitchIF : public HasReturnvaluesIF {
public:
@ -72,4 +70,4 @@ public:
};
#endif /* POWERSWITCHIF_H_ */
#endif /* FSFW_POWER_POWERSWITCHIF_H_ */

View File

@ -1,15 +1,17 @@
#include "../objectmanager/ObjectManagerIF.h"
#include "PowerSwitcher.h"
#include "../objectmanager/ObjectManagerIF.h"
#include "../serviceinterface/ServiceInterfaceStream.h"
PowerSwitcher::PowerSwitcher(uint8_t setSwitch1, uint8_t setSwitch2,
PowerSwitcher::State_t setStartState):
state(setStartState), firstSwitch(setSwitch1), secondSwitch(setSwitch2), power(NULL) {
state(setStartState), firstSwitch(setSwitch1),
secondSwitch(setSwitch2) {
}
ReturnValue_t PowerSwitcher::initialize(object_id_t powerSwitchId) {
power = objectManager->get<PowerSwitchIF>(powerSwitchId);
if (power == NULL) {
if (power == nullptr) {
return HasReturnvaluesIF::RETURN_FAILED;
}
return HasReturnvaluesIF::RETURN_OK;
@ -17,19 +19,25 @@ ReturnValue_t PowerSwitcher::initialize(object_id_t powerSwitchId) {
ReturnValue_t PowerSwitcher::getStateOfSwitches() {
SwitchReturn_t result = howManySwitches();
switch (result) {
case ONE_SWITCH:
return power->getSwitchState(firstSwitch);
case TWO_SWITCHES:
if ((power->getSwitchState(firstSwitch) == PowerSwitchIF::SWITCH_ON)
&& (power->getSwitchState(secondSwitch) == PowerSwitchIF::SWITCH_ON)) {
case TWO_SWITCHES: {
ReturnValue_t firstSwitchState = power->getSwitchState(firstSwitch);
ReturnValue_t secondSwitchState = power->getSwitchState(firstSwitch);
if ((firstSwitchState == PowerSwitchIF::SWITCH_ON)
&& (secondSwitchState == PowerSwitchIF::SWITCH_ON)) {
return PowerSwitchIF::SWITCH_ON;
} else if ((power->getSwitchState(firstSwitch) == PowerSwitchIF::SWITCH_OFF)
&& (power->getSwitchState(secondSwitch) == PowerSwitchIF::SWITCH_OFF)) {
}
else if ((firstSwitchState == PowerSwitchIF::SWITCH_OFF)
&& (secondSwitchState == PowerSwitchIF::SWITCH_OFF)) {
return PowerSwitchIF::SWITCH_OFF;
} else {
}
else {
return HasReturnvaluesIF::RETURN_FAILED;
}
}
default:
return HasReturnvaluesIF::RETURN_FAILED;
}

View File

@ -1,6 +1,9 @@
#ifndef POWERSWITCHER_H_
#define POWERSWITCHER_H_
#ifndef FSFW_POWER_POWERSWITCHER_H_
#define FSFW_POWER_POWERSWITCHER_H_
#include "PowerSwitchIF.h"
#include "../objectmanager/SystemObjectIF.h"
#include "../returnvalues/HasReturnvaluesIF.h"
#include "../timemanager/Countdown.h"
@ -16,7 +19,8 @@ public:
static const uint8_t INTERFACE_ID = CLASS_ID::POWER_SWITCHER;
static const ReturnValue_t IN_POWER_TRANSITION = MAKE_RETURN_CODE(1);
static const ReturnValue_t SWITCH_STATE_MISMATCH = MAKE_RETURN_CODE(2);
PowerSwitcher( uint8_t setSwitch1, uint8_t setSwitch2 = NO_SWITCH, State_t setStartState = SWITCH_IS_OFF );
PowerSwitcher( uint8_t setSwitch1, uint8_t setSwitch2 = NO_SWITCH,
State_t setStartState = SWITCH_IS_OFF );
ReturnValue_t initialize(object_id_t powerSwitchId);
void turnOn();
void turnOff();
@ -29,7 +33,8 @@ public:
private:
uint8_t firstSwitch;
uint8_t secondSwitch;
PowerSwitchIF* power;
PowerSwitchIF* power = nullptr;
static const uint8_t NO_SWITCH = 0xFF;
enum SwitchReturn_t {
ONE_SWITCH = 1,
@ -42,4 +47,4 @@ private:
#endif /* POWERSWITCHER_H_ */
#endif /* FSFW_POWER_POWERSWITCHER_H_ */

View File

@ -20,9 +20,7 @@ class StorageManagerIF;
*/
class ConstStorageAccessor {
//! StorageManager classes have exclusive access to private variables.
template<uint8_t NUMBER_OF_POOLS>
friend class PoolManager;
template<uint8_t NUMBER_OF_POOLS>
friend class LocalPool;
public:
/**

View File

@ -0,0 +1,347 @@
#include "LocalPool.h"
#include <FSFWConfig.h>
#include <cstring>
LocalPool::LocalPool(object_id_t setObjectId, const LocalPoolConfig& poolConfig,
bool registered, bool spillsToHigherPools):
SystemObject(setObjectId, registered),
NUMBER_OF_POOLS(poolConfig.size()),
spillsToHigherPools(spillsToHigherPools) {
if(NUMBER_OF_POOLS == 0) {
sif::error << "LocalPool::LocalPool: Passed pool configuration is "
<< " invalid!" << std::endl;
}
max_pools_t index = 0;
for (const auto& currentPoolConfig: poolConfig) {
this->numberOfElements[index] = currentPoolConfig.first;
this->elementSizes[index] = currentPoolConfig.second;
store[index] = std::vector<uint8_t>(
numberOfElements[index] * elementSizes[index]);
sizeLists[index] = std::vector<size_type>(numberOfElements[index]);
for(auto& size: sizeLists[index]) {
size = STORAGE_FREE;
}
index++;
}
}
LocalPool::~LocalPool(void) {}
ReturnValue_t LocalPool::addData(store_address_t* storageId,
const uint8_t* data, size_t size, bool ignoreFault) {
ReturnValue_t status = reserveSpace(size, storageId, ignoreFault);
if (status == RETURN_OK) {
write(*storageId, data, size);
}
return status;
}
ReturnValue_t LocalPool::getData(store_address_t packetId,
const uint8_t **packetPtr, size_t *size) {
uint8_t* tempData = nullptr;
ReturnValue_t status = modifyData(packetId, &tempData, size);
*packetPtr = tempData;
return status;
}
ReturnValue_t LocalPool::getData(store_address_t storeId,
ConstStorageAccessor& storeAccessor) {
uint8_t* tempData = nullptr;
ReturnValue_t status = modifyData(storeId, &tempData,
&storeAccessor.size_);
storeAccessor.assignStore(this);
storeAccessor.constDataPointer = tempData;
return status;
}
ConstAccessorPair LocalPool::getData(store_address_t storeId) {
uint8_t* tempData = nullptr;
ConstStorageAccessor constAccessor(storeId, this);
ReturnValue_t status = modifyData(storeId, &tempData, &constAccessor.size_);
constAccessor.constDataPointer = tempData;
return ConstAccessorPair(status, std::move(constAccessor));
}
ReturnValue_t LocalPool::getFreeElement(store_address_t *storageId,
const size_t size, uint8_t **pData, bool ignoreFault) {
ReturnValue_t status = reserveSpace(size, storageId, ignoreFault);
if (status == RETURN_OK) {
*pData = &store[storageId->poolIndex][getRawPosition(*storageId)];
}
else {
*pData = nullptr;
}
return status;
}
AccessorPair LocalPool::modifyData(store_address_t storeId) {
StorageAccessor accessor(storeId, this);
ReturnValue_t status = modifyData(storeId, &accessor.dataPointer,
&accessor.size_);
accessor.assignConstPointer();
return AccessorPair(status, std::move(accessor));
}
ReturnValue_t LocalPool::modifyData(store_address_t storeId,
StorageAccessor& storeAccessor) {
storeAccessor.assignStore(this);
ReturnValue_t status = modifyData(storeId, &storeAccessor.dataPointer,
&storeAccessor.size_);
storeAccessor.assignConstPointer();
return status;
}
ReturnValue_t LocalPool::modifyData(store_address_t storeId,
uint8_t **packetPtr, size_t *size) {
ReturnValue_t status = RETURN_FAILED;
if (storeId.poolIndex >= NUMBER_OF_POOLS) {
return ILLEGAL_STORAGE_ID;
}
if ((storeId.packetIndex >= numberOfElements[storeId.poolIndex])) {
return ILLEGAL_STORAGE_ID;
}
if (sizeLists[storeId.poolIndex][storeId.packetIndex]
!= STORAGE_FREE) {
size_type packetPosition = getRawPosition(storeId);
*packetPtr = &store[storeId.poolIndex][packetPosition];
*size = sizeLists[storeId.poolIndex][storeId.packetIndex];
status = RETURN_OK;
}
else {
status = DATA_DOES_NOT_EXIST;
}
return status;
}
ReturnValue_t LocalPool::deleteData(store_address_t storeId) {
#if FSFW_VERBOSE_PRINTOUT == 2
sif::debug << "Delete: Pool: " << std::dec << storeId.poolIndex
<< " Index: " << storeId.packetIndex << std::endl;
#endif
ReturnValue_t status = RETURN_OK;
size_type pageSize = getPageSize(storeId.poolIndex);
if ((pageSize != 0) and
(storeId.packetIndex < numberOfElements[storeId.poolIndex])) {
uint16_t packetPosition = getRawPosition(storeId);
uint8_t* ptr = &store[storeId.poolIndex][packetPosition];
std::memset(ptr, 0, pageSize);
//Set free list
sizeLists[storeId.poolIndex][storeId.packetIndex] = STORAGE_FREE;
}
else {
//pool_index or packet_index is too large
sif::error << "LocalPool::deleteData: Illegal store ID, no deletion!"
<< std::endl;
status = ILLEGAL_STORAGE_ID;
}
return status;
}
ReturnValue_t LocalPool::deleteData(uint8_t *ptr, size_t size,
store_address_t *storeId) {
store_address_t localId;
ReturnValue_t result = ILLEGAL_ADDRESS;
for (uint16_t n = 0; n < NUMBER_OF_POOLS; n++) {
//Not sure if new allocates all stores in order. so better be careful.
if ((store[n].data() <= ptr) and
(&store[n][numberOfElements[n]*elementSizes[n]] > ptr)) {
localId.poolIndex = n;
uint32_t deltaAddress = ptr - store[n].data();
// Getting any data from the right "block" is ok.
// This is necessary, as IF's sometimes don't point to the first
// element of an object.
localId.packetIndex = deltaAddress / elementSizes[n];
result = deleteData(localId);
#if FSFW_VERBOSE_PRINTOUT == 2
if (deltaAddress % elementSizes[n] != 0) {
sif::error << "LocalPool::deleteData: Address not aligned!"
<< std::endl;
}
#endif
break;
}
}
if (storeId != nullptr) {
*storeId = localId;
}
return result;
}
ReturnValue_t LocalPool::initialize() {
ReturnValue_t result = SystemObject::initialize();
if (result != RETURN_OK) {
return result;
}
internalErrorReporter = objectManager->get<InternalErrorReporterIF>(
objects::INTERNAL_ERROR_REPORTER);
if (internalErrorReporter == nullptr){
return ObjectManagerIF::INTERNAL_ERR_REPORTER_UNINIT;
}
//Check if any pool size is large than the maximum allowed.
for (uint8_t count = 0; count < NUMBER_OF_POOLS; count++) {
if (elementSizes[count] >= STORAGE_FREE) {
sif::error << "LocalPool::initialize: Pool is too large! "
"Max. allowed size is: " << (STORAGE_FREE - 1) << std::endl;
return StorageManagerIF::POOL_TOO_LARGE;
}
}
return HasReturnvaluesIF::RETURN_OK;
}
void LocalPool::clearStore() {
for(auto& sizeList: sizeLists) {
for(auto& size: sizeList) {
size = STORAGE_FREE;
}
// std::memset(sizeList[index], 0xff,
// numberOfElements[index] * sizeof(size_type));
}
}
ReturnValue_t LocalPool::reserveSpace(const size_t size,
store_address_t *storeId, bool ignoreFault) {
ReturnValue_t status = getPoolIndex(size, &storeId->poolIndex);
if (status != RETURN_OK) {
sif::error << "LocalPool( " << std::hex << getObjectId() << std::dec
<< " )::reserveSpace: Packet too large." << std::endl;
return status;
}
status = findEmpty(storeId->poolIndex, &storeId->packetIndex);
while (status != RETURN_OK && spillsToHigherPools) {
status = getPoolIndex(size, &storeId->poolIndex, storeId->poolIndex + 1);
if (status != RETURN_OK) {
//We don't find any fitting pool anymore.
break;
}
status = findEmpty(storeId->poolIndex, &storeId->packetIndex);
}
if (status == RETURN_OK) {
#if FSFW_VERBOSE_PRINTOUT == 2
sif::debug << "Reserve: Pool: " << std::dec
<< storeId->poolIndex << " Index: " << storeId->packetIndex
<< std::endl;
#endif
sizeLists[storeId->poolIndex][storeId->packetIndex] = size;
}
else {
if ((not ignoreFault) and (internalErrorReporter != nullptr)) {
internalErrorReporter->storeFull();
}
}
return status;
}
void LocalPool::write(store_address_t storeId, const uint8_t *data,
size_t size) {
uint8_t* ptr = nullptr;
size_type packetPosition = getRawPosition(storeId);
// Size was checked before calling this function.
ptr = &store[storeId.poolIndex][packetPosition];
std::memcpy(ptr, data, size);
sizeLists[storeId.poolIndex][storeId.packetIndex] = size;
}
LocalPool::size_type LocalPool::getPageSize(max_pools_t poolIndex) {
if (poolIndex < NUMBER_OF_POOLS) {
return elementSizes[poolIndex];
}
else {
return 0;
}
}
void LocalPool::setToSpillToHigherPools(bool enable) {
this->spillsToHigherPools = enable;
}
ReturnValue_t LocalPool::getPoolIndex(size_t packetSize, uint16_t *poolIndex,
uint16_t startAtIndex) {
for (uint16_t n = startAtIndex; n < NUMBER_OF_POOLS; n++) {
#if FSFW_VERBOSE_PRINTOUT == 2
sif::debug << "LocalPool " << getObjectId() << "::getPoolIndex: Pool: "
<< n << ", Element Size: " << elementSizes[n] << std::endl;
#endif
if (elementSizes[n] >= packetSize) {
*poolIndex = n;
return RETURN_OK;
}
}
return DATA_TOO_LARGE;
}
LocalPool::size_type LocalPool::getRawPosition(store_address_t storeId) {
return storeId.packetIndex * elementSizes[storeId.poolIndex];
}
ReturnValue_t LocalPool::findEmpty(n_pool_elem_t poolIndex, uint16_t *element) {
ReturnValue_t status = DATA_STORAGE_FULL;
for (uint16_t foundElement = 0; foundElement < numberOfElements[poolIndex];
foundElement++) {
if (sizeLists[poolIndex][foundElement] == STORAGE_FREE) {
*element = foundElement;
status = RETURN_OK;
break;
}
}
return status;
}
size_t LocalPool::getTotalSize(size_t* additionalSize) {
size_t totalSize = 0;
size_t sizesSize = 0;
for(uint8_t idx = 0; idx < NUMBER_OF_POOLS; idx ++) {
totalSize += elementSizes[idx] * numberOfElements[idx];
sizesSize += numberOfElements[idx] * sizeof(size_type);
}
if(additionalSize != nullptr) {
*additionalSize = sizesSize;
}
return totalSize;
}
void LocalPool::getFillCount(uint8_t *buffer, uint8_t *bytesWritten) {
if(bytesWritten == nullptr or buffer == nullptr) {
return;
}
uint16_t reservedHits = 0;
uint8_t idx = 0;
uint16_t sum = 0;
for(; idx < NUMBER_OF_POOLS; idx ++) {
for(const auto& size: sizeLists[idx]) {
if(size != STORAGE_FREE) {
reservedHits++;
}
}
buffer[idx] = static_cast<float>(reservedHits) /
numberOfElements[idx] * 100;
*bytesWritten += 1;
sum += buffer[idx];
reservedHits = 0;
}
buffer[idx] = sum / NUMBER_OF_POOLS;
*bytesWritten += 1;
}
void LocalPool::clearPage(max_pools_t pageIndex) {
if(pageIndex >= NUMBER_OF_POOLS) {
return;
}
// Mark the storage as free
for(auto& size: sizeLists[pageIndex]) {
size = STORAGE_FREE;
}
// Set all the page content to 0.
std::memset(store[pageIndex].data(), 0, elementSizes[pageIndex]);
}

View File

@ -7,57 +7,93 @@
#include "../serviceinterface/ServiceInterfaceStream.h"
#include "../internalError/InternalErrorReporterIF.h"
#include "../storagemanager/StorageAccessor.h"
#include <cstring>
#include <vector>
#include <set>
#include <utility>
#include <limits>
/**
* @brief The LocalPool class provides an intermediate data storage with
* a fixed pool size policy.
* @details The class implements the StorageManagerIF interface. While the
* total number of pools is fixed, the element sizes in one pool and
* the number of pool elements per pool are set on construction.
* The full amount of memory is allocated on construction.
* The overhead is 4 byte per pool element to store the size
* information of each stored element.
* To maintain an "empty" information, the pool size is limited to
* 0xFFFF-1 bytes.
* @details
* The class implements the StorageManagerIF interface. While the total number
* of pools is fixed, the element sizes in one pool and the number of pool
* elements per pool are set on construction. The full amount of memory is
* allocated on construction.
* The overhead is 4 byte per pool element to store the size information of
* each stored element. To maintain an "empty" information, the pool size is
* limited to 0xFFFF-1 bytes.
* It is possible to store empty packets in the pool.
* The local pool is NOT thread-safe.
* @author Bastian Baetz
*/
template<uint8_t NUMBER_OF_POOLS = 5>
class LocalPool: public SystemObject, public StorageManagerIF {
public:
using pool_elem_size_t = size_type;
using n_pool_elem_t = uint16_t;
using LocalPoolCfgPair = std::pair<n_pool_elem_t, pool_elem_size_t>;
// The configuration needs to be provided with the pool sizes ascending
// but the number of pool elements as the first value is more intuitive.
// Therefore, a custom comparator was provided.
struct LocalPoolConfigCmp
{
bool operator ()(const LocalPoolCfgPair &a,
const LocalPoolCfgPair &b) const
{
if(a.second < b.second) {
return true;
}
else if(a.second > b.second) {
return false;
}
else {
if(a.first < b.first) {
return true;
}
else {
return false;
}
}
}
};
using LocalPoolConfig = std::multiset<LocalPoolCfgPair, LocalPoolConfigCmp>;
/**
* @brief This definition generally sets the number of different sized pools.
* @details This must be less than the maximum number of pools (currently 0xff).
* @brief This definition generally sets the number of
* different sized pools. It is derived from the number of pairs
* inside the LocalPoolConfig set on object creation.
* @details
* This must be less than the maximum number of pools (currently 0xff).
*/
// static const uint32_t NUMBER_OF_POOLS;
const max_pools_t NUMBER_OF_POOLS;
/**
* @brief This is the default constructor for a pool manager instance.
* @details By passing two arrays of size NUMBER_OF_POOLS, the constructor
* allocates memory (with @c new) for store and size_list. These
* regions are all set to zero on start up.
* @details
* The pool is configured by passing a set of pairs into the constructor.
* The first value of that pair determines the number of one elements on
* the respective page of the pool while the second value determines how
* many elements with that size are created on that page.
* All regions are to zero on start up.
* @param setObjectId The object identifier to be set. This allows for
* multiple instances of LocalPool in the system.
* @param element_sizes An array of size NUMBER_OF_POOLS in which the size
* of a single element in each pool is determined.
* <b>The sizes must be provided in ascending order.
* </b>
* @param n_elements An array of size NUMBER_OF_POOLS in which the
* number of elements for each pool is determined.
* The position of these values correspond to those in
* element_sizes.
* @param registered Register the pool in object manager or not.
* Default is false (local pool).
* @param poolConfig
* This is a set of pairs to configure the number of pages in the pool,
* the size of an element on a page, the number of elements on a page
* and the total size of the pool at once while also implicitely
* sorting the pairs in the right order.
* @param registered
* Determines whether the pool is registered in the object manager or not.
* @param spillsToHigherPools A variable to determine whether
* higher n pools are used if the store is full.
*/
LocalPool(object_id_t setObjectId,
const uint16_t element_sizes[NUMBER_OF_POOLS],
const uint16_t n_elements[NUMBER_OF_POOLS],
bool registered = false,
bool spillsToHigherPools = false);
LocalPool(object_id_t setObjectId, const LocalPoolConfig& poolConfig,
bool registered = false, bool spillsToHigherPools = false);
void setToSpillToHigherPools(bool enable);
/**
* @brief In the LocalPool's destructor all allocated memory is freed.
*/
@ -66,25 +102,49 @@ public:
/**
* Documentation: See StorageManagerIF.h
*/
ReturnValue_t addData(store_address_t* storageId, const uint8_t * data,
ReturnValue_t addData(store_address_t* storeId, const uint8_t * data,
size_t size, bool ignoreFault = false) override;
ReturnValue_t getFreeElement(store_address_t* storageId,const size_t size,
uint8_t** p_data, bool ignoreFault = false) override;
ReturnValue_t getFreeElement(store_address_t* storeId,const size_t size,
uint8_t** pData, bool ignoreFault = false) override;
ConstAccessorPair getData(store_address_t packet_id) override;
ReturnValue_t getData(store_address_t packet_id, ConstStorageAccessor&) override;
ReturnValue_t getData(store_address_t packet_id, const uint8_t** packet_ptr,
ConstAccessorPair getData(store_address_t storeId) override;
ReturnValue_t getData(store_address_t storeId,
ConstStorageAccessor& constAccessor) override;
ReturnValue_t getData(store_address_t storeId,
const uint8_t** packet_ptr, size_t * size) override;
AccessorPair modifyData(store_address_t storeId) override;
ReturnValue_t modifyData(store_address_t storeId,
StorageAccessor& storeAccessor) override;
ReturnValue_t modifyData(store_address_t storeId, uint8_t** packet_ptr,
size_t * size) override;
AccessorPair modifyData(store_address_t packet_id) override;
ReturnValue_t modifyData(store_address_t packet_id, StorageAccessor&) override;
ReturnValue_t modifyData(store_address_t packet_id, uint8_t** packet_ptr,
size_t * size) override;
virtual ReturnValue_t deleteData(store_address_t) override;
virtual ReturnValue_t deleteData(store_address_t storeId) override;
virtual ReturnValue_t deleteData(uint8_t* ptr, size_t size,
store_address_t* storeId = NULL) override;
store_address_t* storeId = nullptr) override;
/**
* Get the total size of allocated memory for pool data.
* There is an additional overhead of the sizes of elements which will
* be assigned to additionalSize
* @return
*/
size_t getTotalSize(size_t* additionalSize) override;
/**
* Get the fill count of the pool. Each character inside the provided
* buffer will be assigned to a rounded percentage fill count for each
* page. The last written byte (at the index bytesWritten - 1)
* will contain the total fill count of the pool as a mean of the
* percentages of single pages.
* @param buffer
* @param maxSize
*/
void getFillCount(uint8_t* buffer, uint8_t* bytesWritten) override;
void clearStore() override;
void clearPage(max_pools_t pageIndex) override;
ReturnValue_t initialize() override;
protected:
/**
@ -94,43 +154,48 @@ protected:
* @return - #RETURN_OK on success,
* - the return codes of #getPoolIndex or #findEmpty otherwise.
*/
virtual ReturnValue_t reserveSpace(const uint32_t size,
virtual ReturnValue_t reserveSpace(const size_t size,
store_address_t* address, bool ignoreFault);
InternalErrorReporterIF *internalErrorReporter;
private:
/**
* Indicates that this element is free.
* This value limits the maximum size of a pool. Change to larger data type
* if increase is required.
* This value limits the maximum size of a pool.
* Change to larger data type if increase is required.
*/
static const uint32_t STORAGE_FREE = 0xFFFFFFFF;
static const size_type STORAGE_FREE = std::numeric_limits<size_type>::max();
/**
* @brief In this array, the element sizes of each pool is stored.
* @details The sizes are maintained for internal pool management. The sizes
* must be set in ascending order on construction.
*/
uint32_t element_sizes[NUMBER_OF_POOLS];
std::vector<size_type> elementSizes =
std::vector<size_type>(NUMBER_OF_POOLS);
/**
* @brief n_elements stores the number of elements per pool.
* @details These numbers are maintained for internal pool management.
*/
uint16_t n_elements[NUMBER_OF_POOLS];
std::vector<uint16_t> numberOfElements =
std::vector<uint16_t>(NUMBER_OF_POOLS);
/**
* @brief store represents the actual memory pool.
* @details It is an array of pointers to memory, which was allocated with
* a @c new call on construction.
*/
uint8_t* store[NUMBER_OF_POOLS];
std::vector<std::vector<uint8_t>> store =
std::vector<std::vector<uint8_t>>(NUMBER_OF_POOLS);
/**
* @brief The size_list attribute stores the size values of every pool element.
* @details As the number of elements is determined on construction, the size list
* is also dynamically allocated there.
*/
uint32_t* size_list[NUMBER_OF_POOLS];
std::vector<std::vector<size_type>> sizeLists =
std::vector<std::vector<size_type>>(NUMBER_OF_POOLS);
//! A variable to determine whether higher n pools are used if
//! the store is full.
bool spillsToHigherPools;
bool spillsToHigherPools = false;
/**
* @brief This method safely stores the given data in the given packet_id.
* @details It also sets the size in size_list. The method does not perform
@ -139,30 +204,24 @@ private:
* @param data The data to be stored.
* @param size The size of the data to be stored.
*/
void write(store_address_t packet_id, const uint8_t* data, size_t size);
void write(store_address_t packetId, const uint8_t* data, size_t size);
/**
* @brief A helper method to read the element size of a certain pool.
* @param pool_index The pool in which to look.
* @return Returns the size of an element or 0.
*/
uint32_t getPageSize(uint16_t pool_index);
/**
* @brief This helper method looks up a fitting pool for a given size.
* @details The pools are looked up in ascending order, so the first that
* fits is used.
* @param packet_size The size of the data to be stored.
* @return Returns the pool that fits or StorageManagerIF::INVALID_ADDRESS.
*/
size_type getPageSize(max_pools_t poolIndex);
/**
* @brief This helper method looks up a fitting pool for a given size.
* @details The pools are looked up in ascending order, so the first that
* fits is used.
* @param packet_size The size of the data to be stored.
* @param[out] poolIndex The fitting pool index found.
* @return - #RETURN_OK on success,
* - #DATA_TOO_LARGE otherwise.
* @return - @c RETURN_OK on success,
* - @c DATA_TOO_LARGE otherwise.
*/
ReturnValue_t getPoolIndex(size_t packet_size, uint16_t* poolIndex,
ReturnValue_t getPoolIndex(size_t packetSize, uint16_t* poolIndex,
uint16_t startAtIndex = 0);
/**
* @brief This helper method calculates the true array position in store
@ -172,7 +231,7 @@ private:
* @param packet_id The packet id to look up.
* @return Returns the position of the data in store.
*/
uint32_t getRawPosition(store_address_t packet_id);
size_type getRawPosition(store_address_t storeId);
/**
* @brief This is a helper method to find an empty element in a given pool.
* @details The method searches size_list for the first empty element, so
@ -182,9 +241,9 @@ private:
* @return - #RETURN_OK on success,
* - #DATA_STORAGE_FULL if the store is full
*/
ReturnValue_t findEmpty(uint16_t pool_index, uint16_t* element);
ReturnValue_t findEmpty(n_pool_elem_t poolIndex, uint16_t* element);
InternalErrorReporterIF *internalErrorReporter = nullptr;
};
#include "LocalPool.tpp"
#endif /* FSFW_STORAGEMANAGER_LOCALPOOL_H_ */

View File

@ -0,0 +1,60 @@
#include "PoolManager.h"
#include <FSFWConfig.h>
PoolManager::PoolManager(object_id_t setObjectId,
const LocalPoolConfig& localPoolConfig):
LocalPool(setObjectId, localPoolConfig, true) {
mutex = MutexFactory::instance()->createMutex();
}
PoolManager::~PoolManager(void) {
MutexFactory::instance()->deleteMutex(mutex);
}
ReturnValue_t PoolManager::reserveSpace(const size_t size,
store_address_t* address, bool ignoreFault) {
MutexHelper mutexHelper(mutex, MutexIF::TimeoutType::WAITING,
mutexTimeoutMs);
ReturnValue_t status = LocalPool::reserveSpace(size,
address,ignoreFault);
return status;
}
ReturnValue_t PoolManager::deleteData(
store_address_t storeId) {
#if FSFW_VERBOSE_PRINTOUT == 2
sif::debug << "PoolManager( " << translateObject(getObjectId()) <<
" )::deleteData from store " << storeId.poolIndex <<
". id is "<< storeId.packetIndex << std::endl;
#endif
MutexHelper mutexHelper(mutex, MutexIF::TimeoutType::WAITING,
mutexTimeoutMs);
return LocalPool::deleteData(storeId);
}
ReturnValue_t PoolManager::deleteData(uint8_t* buffer,
size_t size, store_address_t* storeId) {
MutexHelper mutexHelper(mutex, MutexIF::TimeoutType::WAITING, 20);
ReturnValue_t status = LocalPool::deleteData(buffer,
size, storeId);
return status;
}
void PoolManager::setMutexTimeout(
uint32_t mutexTimeoutMs) {
this->mutexTimeoutMs = mutexTimeoutMs;
}
ReturnValue_t PoolManager::lockMutex(MutexIF::TimeoutType timeoutType,
uint32_t timeoutMs) {
return mutex->lockMutex(timeoutType, timeoutMs);
}
ReturnValue_t PoolManager::unlockMutex() {
return mutex->unlockMutex();
}

View File

@ -9,16 +9,20 @@
/**
* @brief The PoolManager class provides an intermediate data storage with
* a fixed pool size policy for inter-process communication.
* @details Uses local pool calls but is thread safe by protecting the call
* with a lock.
* @details
* Uses local pool calls but is thread safe by protecting most calls
* with a lock. The developer can lock the pool with the provided API
* if the lock needs to persists beyond the function call.
*
* Other than that, the class provides the same interface as the LocalPool
* class. The class is always registered as a system object as it is assumed
* it will always be used concurrently (if this is not the case, it is
* recommended to use the LocalPool class instead).
* @author Bastian Baetz
*/
template <uint8_t NUMBER_OF_POOLS = 5>
class PoolManager : public LocalPool<NUMBER_OF_POOLS> {
class PoolManager: public LocalPool {
public:
PoolManager(object_id_t setObjectId,
const uint16_t element_sizes[NUMBER_OF_POOLS],
const uint16_t n_elements[NUMBER_OF_POOLS]);
PoolManager(object_id_t setObjectId, const LocalPoolConfig& poolConfig);
/**
* @brief In the PoolManager's destructor all allocated memory
@ -26,6 +30,12 @@ public:
*/
virtual ~PoolManager();
/**
* Set the default mutex timeout for internal calls.
* @param mutexTimeoutMs
*/
void setMutexTimeout(uint32_t mutexTimeoutMs);
/**
* @brief LocalPool overrides for thread-safety. Decorator function
* which wraps LocalPool calls with a mutex protection.
@ -34,12 +44,23 @@ public:
ReturnValue_t deleteData(uint8_t* buffer, size_t size,
store_address_t* storeId = nullptr) override;
void setMutexTimeout(uint32_t mutexTimeoutMs);
/**
* The developer is allowed to lock the mutex in case the lock needs
* to persist beyond the function calls which are not protected by the
* class.
* @param timeoutType
* @param timeoutMs
* @return
*/
ReturnValue_t lockMutex(MutexIF::TimeoutType timeoutType,
uint32_t timeoutMs);
ReturnValue_t unlockMutex();
protected:
//! Default mutex timeout value to prevent permanent blocking.
uint32_t mutexTimeoutMs = 20;
ReturnValue_t reserveSpace(const uint32_t size, store_address_t* address,
ReturnValue_t reserveSpace(const size_t size, store_address_t* address,
bool ignoreFault) override;
/**
@ -51,6 +72,4 @@ protected:
MutexIF* mutex;
};
#include "PoolManager.tpp"
#endif /* FSFW_STORAGEMANAGER_POOLMANAGER_H_ */

View File

@ -10,9 +10,7 @@ class StorageManagerIF;
*/
class StorageAccessor: public ConstStorageAccessor {
//! StorageManager classes have exclusive access to private variables.
template<uint8_t NUMBER_OF_POOLS>
friend class PoolManager;
template<uint8_t NUMBER_OF_POOLS>
friend class LocalPool;
public:
StorageAccessor(store_address_t storeId);

View File

@ -28,6 +28,9 @@ using ConstAccessorPair = std::pair<ReturnValue_t, ConstStorageAccessor>;
*/
class StorageManagerIF : public HasReturnvaluesIF {
public:
using size_type = size_t;
using max_pools_t = uint8_t;
static const uint8_t INTERFACE_ID = CLASS_ID::STORAGE_MANAGER_IF; //!< The unique ID for return codes for this interface.
static const ReturnValue_t DATA_TOO_LARGE = MAKE_RETURN_CODE(1); //!< This return code indicates that the data to be stored is too large for the store.
static const ReturnValue_t DATA_STORAGE_FULL = MAKE_RETURN_CODE(2); //!< This return code indicates that a data storage is full.
@ -40,7 +43,9 @@ public:
static const Event GET_DATA_FAILED = MAKE_EVENT(0, severity::LOW);
static const Event STORE_DATA_FAILED = MAKE_EVENT(1, severity::LOW);
static const uint32_t INVALID_ADDRESS = 0xFFFFFFFF; //!< Indicates an invalid (i.e unused) storage address.
//!< Indicates an invalid (i.e unused) storage address.
static const uint32_t INVALID_ADDRESS = 0xFFFFFFFF;
/**
* @brief This is the empty virtual destructor as required for C++ interfaces.
*/
@ -164,6 +169,22 @@ public:
* Use with care!
*/
virtual void clearStore() = 0;
/**
* Clears a page in the store. Use with care!
* @param pageIndex
*/
virtual void clearPage(uint8_t pageIndex) = 0;
/**
* Get the fill count of the pool. The exact form will be implementation
* dependant.
* @param buffer
* @param bytesWritten
*/
virtual void getFillCount(uint8_t* buffer, uint8_t* bytesWritten) = 0;
virtual size_t getTotalSize(size_t* additionalSize) = 0;
};
#endif /* FSFW_STORAGEMANAGER_STORAGEMANAGERIF_H_ */

View File

@ -3,16 +3,21 @@
#include <cstdint>
namespace storeId {
static constexpr uint32_t INVALID_STORE_ADDRESS = 0xffffffff;
}
/**
* This union defines the type that identifies where a data packet is
* stored in the store. It comprises of a raw part to read it as raw value and
* a structured part to use it in pool-like stores.
*/
union store_address_t {
/**
* Default Constructor, initializing to INVALID_ADDRESS
*/
store_address_t():raw(0xFFFFFFFF){}
store_address_t(): raw(storeId::INVALID_STORE_ADDRESS){}
/**
* Constructor to create an address object using the raw address
*
@ -28,7 +33,7 @@ union store_address_t {
* @param packetIndex
*/
store_address_t(uint16_t poolIndex, uint16_t packetIndex):
pool_index(poolIndex),packet_index(packetIndex){}
poolIndex(poolIndex), packetIndex(packetIndex){}
/**
* A structure with two elements to access the store address pool-like.
*/
@ -36,11 +41,11 @@ union store_address_t {
/**
* The index in which pool the packet lies.
*/
uint16_t pool_index;
uint16_t poolIndex;
/**
* The position in the chosen pool.
*/
uint16_t packet_index;
uint16_t packetIndex;
};
/**
* Alternative access to the raw value.

View File

@ -44,19 +44,19 @@ ReturnValue_t AbstractTemperatureSensor::performHealthOp() {
}
void AbstractTemperatureSensor::handleCommandQueue() {
CommandMessage message;
ReturnValue_t result = commandQueue->receiveMessage(&message);
CommandMessage command;
ReturnValue_t result = commandQueue->receiveMessage(&command);
if (result == HasReturnvaluesIF::RETURN_OK) {
result = healthHelper.handleHealthCommand(&message);
result = healthHelper.handleHealthCommand(&command);
if (result == HasReturnvaluesIF::RETURN_OK) {
return;
}
result = parameterHelper.handleParameterMessage(&message);
result = parameterHelper.handleParameterMessage(&command);
if (result == HasReturnvaluesIF::RETURN_OK) {
return;
}
message.setToUnknownCommand();
commandQueue->reply(&message);
command.setToUnknownCommand();
commandQueue->reply(&command);
}
}

View File

@ -10,6 +10,16 @@
#include "ThermalModuleIF.h"
#include "tcsDefinitions.h"
/**
* @defgroup thermal Thermal Components
* @brief Contains all components related to thermal tasks (sensors, heaters)
*/
/**
* @brief Base class for Temperature Sensor, implements all important interfaces.
* Please use the TemperatureSensor class to implement the actual sensors.
* @ingroup thermal
*/
class AbstractTemperatureSensor: public HasHealthIF,
public SystemObject,
public ExecutableObjectIF,

View File

@ -0,0 +1,22 @@
/**
* \file AcceptsThermalMessagesIF.h
*
* \date 16.02.2020
*/
#ifndef FRAMEWORK_THERMAL_ACCEPTSTHERMALMESSAGESIF_H_
#define FRAMEWORK_THERMAL_ACCEPTSTHERMALMESSAGESIF_H_
#include "../ipc/MessageQueueSenderIF.h"
class AcceptsThermalMessagesIF {
public:
/**
* @brief This is the empty virtual destructor as required for C++ interfaces.
*/
virtual ~AcceptsThermalMessagesIF() { }
virtual MessageQueueId_t getReceptionQueue() const = 0;
};
#endif /* FRAMEWORK_THERMAL_ACCEPTSTHERMALMESSAGESIF_H_ */

View File

@ -1,96 +0,0 @@
#ifndef MISSION_CONTROLLERS_TCS_CORECOMPONENT_H_
#define MISSION_CONTROLLERS_TCS_CORECOMPONENT_H_
#include "../datapoolglob/GlobalDataSet.h"
#include "../datapoolglob/GlobalPoolVariable.h"
#include "../thermal/ThermalComponentIF.h"
#include "../thermal/AbstractTemperatureSensor.h"
#include "../thermal/ThermalModule.h"
#include "../thermal/ThermalMonitor.h"
// TODO: Documentaiton, how to use this? only use Thermal Component, which inherits core component?
class CoreComponent: public ThermalComponentIF {
public:
struct Parameters {
float lowerOpLimit;
float upperOpLimit;
float heaterOn;
float hysteresis;
float heaterSwitchoff;
};
static const uint16_t COMPONENT_TEMP_CONFIRMATION = 5;
CoreComponent(object_id_t reportingObjectId, uint8_t domainId, uint32_t temperaturePoolId,
uint32_t targetStatePoolId, uint32_t currentStatePoolId,
uint32_t requestPoolId, GlobDataSet *dataSet,
AbstractTemperatureSensor *sensor,
AbstractTemperatureSensor *firstRedundantSensor,
AbstractTemperatureSensor *secondRedundantSensor,
ThermalModuleIF *thermalModule, Parameters parameters,
Priority priority, StateRequest initialTargetState =
ThermalComponentIF::STATE_REQUEST_OPERATIONAL);
virtual ~CoreComponent();
virtual HeaterRequest performOperation(uint8_t opCode);
void markStateIgnored();
object_id_t getObjectId();
uint8_t getDomainId() const;
virtual float getLowerOpLimit();
ReturnValue_t setTargetState(int8_t newState);
virtual void setOutputInvalid();
virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId,
ParameterWrapper *parameterWrapper,
const ParameterWrapper *newValues, uint16_t startAtIndex);
protected:
AbstractTemperatureSensor *sensor;
AbstractTemperatureSensor *firstRedundantSensor;
AbstractTemperatureSensor *secondRedundantSensor;
ThermalModuleIF *thermalModule;
gp_float_t temperature;
gp_int8_t targetState;
gp_int8_t currentState;
gp_uint8_t heaterRequest;
bool isHeating;
bool isSafeComponent;
float minTemp;
float maxTemp;
Parameters parameters;
ThermalMonitor temperatureMonitor;
const uint8_t domainId;
virtual float getTemperature();
virtual State getState(float temperature, Parameters parameters,
int8_t targetState);
virtual void checkLimits(State state);
virtual HeaterRequest getHeaterRequest(int8_t targetState,
float temperature, Parameters parameters);
virtual State getIgnoredState(int8_t state);
void updateMinMaxTemp();
virtual Parameters getParameters();
};
#endif /* MISSION_CONTROLLERS_TCS_CORECOMPONENT_H_ */

View File

@ -279,14 +279,14 @@ ReturnValue_t Heater::initialize() {
}
void Heater::handleQueue() {
CommandMessage message;
ReturnValue_t result = commandQueue->receiveMessage(&message);
CommandMessage command;
ReturnValue_t result = commandQueue->receiveMessage(&command);
if (result == HasReturnvaluesIF::RETURN_OK) {
result = healthHelper.handleHealthCommand(&message);
result = healthHelper.handleHealthCommand(&command);
if (result == HasReturnvaluesIF::RETURN_OK) {
return;
}
parameterHelper.handleParameterMessage(&message);
parameterHelper.handleParameterMessage(&command);
}
}
@ -301,7 +301,7 @@ ReturnValue_t Heater::getParameter(uint8_t domainId, uint16_t parameterId,
parameterWrapper->set(heaterOnCountdown.timeout);
break;
default:
return INVALID_MATRIX_ID;
return INVALID_IDENTIFIER_ID;
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,7 +1,7 @@
#ifndef REDUNDANTHEATER_H_
#define REDUNDANTHEATER_H_
#include "Heater.h"
#include "../thermal/Heater.h"
class RedundantHeater {
public:
@ -10,15 +10,14 @@ public:
Parameters(uint32_t objectIdHeater0, uint32_t objectIdHeater1,
uint8_t switch0Heater0, uint8_t switch1Heater0,
uint8_t switch0Heater1, uint8_t switch1Heater1) :
objectIdHeater0(objectIdHeater0), objectIdHeater1(
objectIdHeater1), switch0Heater0(switch0Heater0), switch1Heater0(
switch1Heater0), switch0Heater1(switch0Heater1), switch1Heater1(
switch1Heater1) {
objectIdHeater0(objectIdHeater0), objectIdHeater1(objectIdHeater1),
switch0Heater0(switch0Heater0),switch1Heater0(switch1Heater0),
switch0Heater1(switch0Heater1), switch1Heater1(switch1Heater1) {
}
Parameters() :
objectIdHeater0(0), objectIdHeater1(0), switch0Heater0(0), switch1Heater0(
0), switch0Heater1(0), switch1Heater1(0) {
objectIdHeater0(0), objectIdHeater1(0), switch0Heater0(0),
switch1Heater0(0), switch0Heater1(0), switch1Heater1(0) {
}
uint32_t objectIdHeater0;

View File

@ -1,40 +1,101 @@
#ifndef TEMPERATURESENSOR_H_
#define TEMPERATURESENSOR_H_
#include "../datapool/DataSet.h"
#include "AbstractTemperatureSensor.h"
#include "../thermal/AbstractTemperatureSensor.h"
#include "../datapoolglob/GlobalDataSet.h"
#include "../datapoolglob/GlobalPoolVariable.h"
#include "../monitoring/LimitMonitor.h"
template<typename T>
/**
* @brief This building block handles non-linear value conversion and
* range checks for analog temperature sensors.
* @details This class can be used to perform all necessary tasks for temperature sensors.
* A sensor can be instantiated by calling the constructor.
* The temperature is calculated from an input value with
* the calculateOutputTemperature() function. Range checking and
* limit monitoring is performed automatically.
* The inputType specifies the type of the raw input while the
* limitType specifies the type of the upper and lower limit to check against.
* @ingroup thermal
*/
template<typename inputType, typename limitType = inputType>
class TemperatureSensor: public AbstractTemperatureSensor {
public:
/**
* This structure contains parameters required for range checking
* and the conversion from the input value to the output temperature.
* a, b and c can be any parameters required to calculate the output
* temperature from the input value, depending on the formula used.
*
* The parameters a,b and c are used in the calculateOutputTemperature() call.
*
* The lower and upper limits can be specified in any type, for example float for C values
* or any other type for raw values.
*/
struct Parameters {
float a;
float b;
float c;
T lowerLimit;
T upperLimit;
float gradient;
limitType lowerLimit;
limitType upperLimit;
float maxGradient;
};
/**
* Forward declaration for explicit instantiation of used parameters.
*/
struct UsedParameters {
UsedParameters(Parameters parameters) :
a(parameters.a), b(parameters.b), c(parameters.c), gradient(
parameters.gradient) {
}
a(parameters.a), b(parameters.b), c(parameters.c),
gradient(parameters.maxGradient) {}
float a;
float b;
float c;
float gradient;
};
static const uint16_t ADDRESS_A = 0;
static const uint16_t ADDRESS_B = 1;
static const uint16_t ADDRESS_C = 2;
static const uint16_t ADDRESS_GRADIENT = 3;
/**
* Instantiate Temperature Sensor Object.
* @param setObjectid objectId of the sensor object
* @param inputValue Input value which is converted to a temperature
* @param poolVariable Pool Variable to store the temperature value
* @param vectorIndex Vector Index for the sensor monitor
* @param parameters Calculation parameters, temperature limits, gradient limit
* @param datapoolId Datapool ID of the output temperature
* @param outputSet Output dataset for the output temperature to fetch it with read()
* @param thermalModule respective thermal module, if it has one
*/
TemperatureSensor(object_id_t setObjectid,
inputType *inputValue, PoolVariableIF *poolVariable,
uint8_t vectorIndex, uint32_t datapoolId, Parameters parameters = {0, 0, 0, 0, 0, 0},
GlobDataSet *outputSet = NULL, ThermalModuleIF *thermalModule = NULL) :
AbstractTemperatureSensor(setObjectid, thermalModule), parameters(parameters),
inputValue(inputValue), poolVariable(poolVariable),
outputTemperature(datapoolId, outputSet, PoolVariableIF::VAR_WRITE),
sensorMonitor(setObjectid, DOMAIN_ID_SENSOR,
GlobalDataPool::poolIdAndPositionToPid(poolVariable->getDataPoolId(), vectorIndex),
DEFAULT_CONFIRMATION_COUNT, parameters.lowerLimit, parameters.upperLimit,
TEMP_SENSOR_LOW, TEMP_SENSOR_HIGH),
oldTemperature(20), uptimeOfOldTemperature( { INVALID_TEMPERATURE, 0 }) {
}
protected:
/**
* This formula is used to calculate the temperature from an input value
* with an arbitrary type.
* A default implementation is provided but can be replaced depending
* on the required calculation.
* @param inputTemperature
* @return
*/
virtual float calculateOutputTemperature(inputType inputValue) {
return parameters.a * inputValue * inputValue
+ parameters.b * inputValue + parameters.c;
}
static const uint16_t DEFAULT_CONFIRMATION_COUNT = 1; //!< Changed due to issue with later temperature checking even tough the sensor monitor was confirming already (Was 10 before with comment = Correlates to a 10s confirmation time. Chosen rather large, should not be so bad for components and helps survive glitches.)
static const uint8_t DOMAIN_ID_SENSOR = 1;
private:
void setInvalid() {
outputTemperature = INVALID_TEMPERATURE;
@ -47,22 +108,17 @@ protected:
UsedParameters parameters;
T *inputTemperature;
inputType * inputValue;
PoolVariableIF *poolVariable;
PoolVariable<float> outputTemperature;
gp_float_t outputTemperature;
LimitMonitor<T> sensorMonitor;
LimitMonitor<limitType> sensorMonitor;
float oldTemperature;
timeval uptimeOfOldTemperature;
virtual float calculateOutputTemperature(T inputTemperature) {
return parameters.a * inputTemperature * inputTemperature
+ parameters.b * inputTemperature + parameters.c;
}
void doChildOperation() {
if (!poolVariable->isValid()
|| !healthHelper.healthTable->isHealthy(getObjectId())) {
@ -70,7 +126,7 @@ protected:
return;
}
outputTemperature = calculateOutputTemperature(*inputTemperature);
outputTemperature = calculateOutputTemperature(*inputValue);
outputTemperature.setValid(PoolVariableIF::VALID);
timeval uptime;
@ -78,7 +134,7 @@ protected:
if (uptimeOfOldTemperature.tv_sec != INVALID_UPTIME) {
//In theory, we could use an AbsValueMonitor to monitor the gradient.
//But this would require storing the gradient in DP and quite some overhead.
//But this would require storing the maxGradient in DP and quite some overhead.
//The concept of delta limits is a bit strange anyway.
float deltaTime;
float deltaTemp;
@ -96,8 +152,8 @@ protected:
}
}
//Check is done against raw limits. SHOULDDO: Why? Using °C would be more easy to handle.
sensorMonitor.doCheck(*inputTemperature);
//Check is done against raw limits. SHOULDDO: Why? Using <EFBFBD>C would be more easy to handle.
sensorMonitor.doCheck(outputTemperature.value);
if (sensorMonitor.isOutOfLimits()) {
uptimeOfOldTemperature.tv_sec = INVALID_UPTIME;
@ -110,23 +166,6 @@ protected:
}
public:
TemperatureSensor(object_id_t setObjectid,
T *inputTemperature, PoolVariableIF *poolVariable,
uint8_t vectorIndex, Parameters parameters, uint32_t datapoolId,
DataSet *outputSet, ThermalModuleIF *thermalModule) :
AbstractTemperatureSensor(setObjectid, thermalModule), parameters(
parameters), inputTemperature(inputTemperature), poolVariable(
poolVariable), outputTemperature(datapoolId, outputSet,
PoolVariableIF::VAR_WRITE), sensorMonitor(setObjectid,
DOMAIN_ID_SENSOR,
DataPool::poolIdAndPositionToPid(
poolVariable->getDataPoolId(), vectorIndex),
DEFAULT_CONFIRMATION_COUNT, parameters.lowerLimit,
parameters.upperLimit, TEMP_SENSOR_LOW, TEMP_SENSOR_HIGH), oldTemperature(
20), uptimeOfOldTemperature( { INVALID_TEMPERATURE, 0 }) {
}
float getTemperature() {
return outputTemperature;
}
@ -135,6 +174,15 @@ public:
return outputTemperature.isValid();
}
static const uint16_t ADDRESS_A = 0;
static const uint16_t ADDRESS_B = 1;
static const uint16_t ADDRESS_C = 2;
static const uint16_t ADDRESS_GRADIENT = 3;
static const uint16_t DEFAULT_CONFIRMATION_COUNT = 1; //!< Changed due to issue with later temperature checking even tough the sensor monitor was confirming already (Was 10 before with comment = Correlates to a 10s confirmation time. Chosen rather large, should not be so bad for components and helps survive glitches.)
static const uint8_t DOMAIN_ID_SENSOR = 1;
virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId,
ParameterWrapper *parameterWrapper,
const ParameterWrapper *newValues, uint16_t startAtIndex) {
@ -160,7 +208,7 @@ public:
parameterWrapper->set(parameters.gradient);
break;
default:
return INVALID_MATRIX_ID;
return INVALID_IDENTIFIER_ID;
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,20 +1,20 @@
#include "ThermalComponent.h"
ThermalComponent::ThermalComponent(object_id_t reportingObjectId,
uint8_t domainId, uint32_t temperaturePoolId,
uint32_t targetStatePoolId, uint32_t currentStatePoolId,
uint32_t requestPoolId, GlobDataSet* dataSet,
uint8_t domainId, gp_id_t temperaturePoolId,
gp_id_t targetStatePoolId, gp_id_t currentStatePoolId,
gp_id_t requestPoolId, LocalPoolDataSetBase* dataSet,
AbstractTemperatureSensor* sensor,
AbstractTemperatureSensor* firstRedundantSensor,
AbstractTemperatureSensor* secondRedundantSensor,
ThermalModuleIF* thermalModule, Parameters parameters,
Priority priority) :
CoreComponent(reportingObjectId, domainId, temperaturePoolId,
ThermalComponentCore(reportingObjectId, domainId, temperaturePoolId,
targetStatePoolId, currentStatePoolId, requestPoolId, dataSet,
sensor, firstRedundantSensor, secondRedundantSensor,
thermalModule,{ parameters.lowerOpLimit, parameters.upperOpLimit,
parameters.heaterOn, parameters.hysteresis, parameters.heaterSwitchoff },
priority, ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL),
{ parameters.lowerOpLimit, parameters.upperOpLimit,
parameters.heaterOn, parameters.hysteresis,
parameters.heaterSwitchoff },
ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL),
nopParameters({ parameters.lowerNopLimit, parameters.upperNopLimit }) {
}
@ -22,22 +22,22 @@ ThermalComponent::~ThermalComponent() {
}
ReturnValue_t ThermalComponent::setTargetState(int8_t newState) {
GlobDataSet mySet;
gp_int8_t writableTargetState(targetState.getDataPoolId(),
&mySet, PoolVariableIF::VAR_READ_WRITE);
mySet.read();
if ((writableTargetState == STATE_REQUEST_OPERATIONAL)
&& (newState != STATE_REQUEST_IGNORE)) {
targetState.setReadWriteMode(pool_rwm_t::VAR_READ_WRITE);
targetState.read();
if ((targetState == STATE_REQUEST_OPERATIONAL)
and (newState != STATE_REQUEST_IGNORE)) {
return HasReturnvaluesIF::RETURN_FAILED;
}
switch (newState) {
case STATE_REQUEST_NON_OPERATIONAL:
writableTargetState = newState;
mySet.commit(PoolVariableIF::VALID);
targetState = newState;
targetState.setValid(true);
targetState.commit(PoolVariableIF::VALID);
return HasReturnvaluesIF::RETURN_OK;
default:
return CoreComponent::setTargetState(newState);
return ThermalComponentCore::setTargetState(newState);
}
return HasReturnvaluesIF::RETURN_OK;
}
ReturnValue_t ThermalComponent::setLimits(const uint8_t* data, size_t size) {
@ -57,11 +57,11 @@ ReturnValue_t ThermalComponent::setLimits(const uint8_t* data, size_t size) {
}
ThermalComponentIF::State ThermalComponent::getState(float temperature,
CoreComponent::Parameters parameters, int8_t targetState) {
ThermalComponentCore::Parameters parameters, int8_t targetState) {
if (temperature < nopParameters.lowerNopLimit) {
return OUT_OF_RANGE_LOW;
} else {
State state = CoreComponent::getState(temperature, parameters,
State state = ThermalComponentCore::getState(temperature, parameters,
targetState);
if (state != NON_OPERATIONAL_HIGH
&& state != NON_OPERATIONAL_HIGH_IGNORED) {
@ -78,8 +78,9 @@ ThermalComponentIF::State ThermalComponent::getState(float temperature,
}
void ThermalComponent::checkLimits(ThermalComponentIF::State state) {
if (targetState == STATE_REQUEST_OPERATIONAL || targetState == STATE_REQUEST_IGNORE) {
CoreComponent::checkLimits(state);
if ((targetState == STATE_REQUEST_OPERATIONAL) or
(targetState == STATE_REQUEST_IGNORE)) {
ThermalComponentCore::checkLimits(state);
return;
}
// If component is not operational, it checks the NOP limits.
@ -89,7 +90,7 @@ void ThermalComponent::checkLimits(ThermalComponentIF::State state) {
ThermalComponentIF::HeaterRequest ThermalComponent::getHeaterRequest(
int8_t targetState, float temperature,
CoreComponent::Parameters parameters) {
ThermalComponentCore::Parameters parameters) {
if (targetState == STATE_REQUEST_IGNORE) {
isHeating = false;
return HEATER_DONT_CARE;
@ -142,16 +143,16 @@ ThermalComponentIF::State ThermalComponent::getIgnoredState(int8_t state) {
case OUT_OF_RANGE_HIGH_IGNORED:
return OUT_OF_RANGE_HIGH_IGNORED;
default:
return CoreComponent::getIgnoredState(state);
return ThermalComponentCore::getIgnoredState(state);
}
}
ReturnValue_t ThermalComponent::getParameter(uint8_t domainId,
uint16_t parameterId, ParameterWrapper* parameterWrapper,
const ParameterWrapper* newValues, uint16_t startAtIndex) {
ReturnValue_t result = CoreComponent::getParameter(domainId, parameterId,
ReturnValue_t result = ThermalComponentCore::getParameter(domainId, parameterId,
parameterWrapper, newValues, startAtIndex);
if (result != INVALID_MATRIX_ID) {
if (result != INVALID_IDENTIFIER_ID) {
return result;
}
switch (parameterId) {
@ -162,7 +163,7 @@ ReturnValue_t ThermalComponent::getParameter(uint8_t domainId,
parameterWrapper->set(nopParameters.upperNopLimit);
break;
default:
return INVALID_MATRIX_ID;
return INVALID_IDENTIFIER_ID;
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -1,12 +1,14 @@
#ifndef THERMALCOMPONENT_H_
#define THERMALCOMPONENT_H_
#ifndef FSFW_THERMAL_THERMALCOMPONENT_H_
#define FSFW_THERMAL_THERMALCOMPONENT_H_
#include "CoreComponent.h"
#include "ThermalComponentCore.h"
/**
* What is it. How to use
* @brief
* @details
* Some more documentation.
*/
class ThermalComponent: public CoreComponent {
class ThermalComponent: public ThermalComponentCore {
public:
struct Parameters {
float lowerNopLimit;
@ -42,9 +44,10 @@ public:
* @param parameters
* @param priority
*/
ThermalComponent(object_id_t reportingObjectId, uint8_t domainId, uint32_t temperaturePoolId,
uint32_t targetStatePoolId, uint32_t currentStatePoolId, uint32_t requestPoolId,
GlobDataSet *dataSet, AbstractTemperatureSensor *sensor,
ThermalComponent(object_id_t reportingObjectId, uint8_t domainId,
gp_id_t temperaturePoolId, gp_id_t targetStatePoolId,
gp_id_t currentStatePoolId, gp_id_t requestPoolId,
LocalPoolDataSetBase *dataSet, AbstractTemperatureSensor *sensor,
AbstractTemperatureSensor *firstRedundantSensor,
AbstractTemperatureSensor *secondRedundantSensor,
ThermalModuleIF *thermalModule, Parameters parameters,
@ -63,15 +66,15 @@ protected:
NopParameters nopParameters;
State getState(float temperature, CoreComponent::Parameters parameters,
State getState(float temperature, ThermalComponentCore::Parameters parameters,
int8_t targetState);
virtual void checkLimits(State state);
virtual HeaterRequest getHeaterRequest(int8_t targetState, float temperature,
CoreComponent::Parameters parameters);
ThermalComponentCore::Parameters parameters);
State getIgnoredState(int8_t state);
};
#endif /* THERMALCOMPONENT_H_ */
#endif /* FSFW_THERMAL_THERMALCOMPONENT_H_ */

View File

@ -1,50 +1,73 @@
#include "CoreComponent.h"
#include "ThermalComponentCore.h"
CoreComponent::CoreComponent(object_id_t reportingObjectId, uint8_t domainId,
uint32_t temperaturePoolId, uint32_t targetStatePoolId,
uint32_t currentStatePoolId, uint32_t requestPoolId, GlobDataSet* dataSet,
AbstractTemperatureSensor* sensor,
AbstractTemperatureSensor* firstRedundantSensor,
AbstractTemperatureSensor* secondRedundantSensor,
ThermalModuleIF* thermalModule, Parameters parameters,
Priority priority, StateRequest initialTargetState) :
sensor(sensor), firstRedundantSensor(firstRedundantSensor), secondRedundantSensor(
secondRedundantSensor), thermalModule(thermalModule), temperature(
temperaturePoolId, dataSet, PoolVariableIF::VAR_WRITE), targetState(
targetStatePoolId, dataSet, PoolVariableIF::VAR_READ), currentState(
currentStatePoolId, dataSet, PoolVariableIF::VAR_WRITE), heaterRequest(
requestPoolId, dataSet, PoolVariableIF::VAR_WRITE), isHeating(
false), isSafeComponent(priority == SAFE), minTemp(999), maxTemp(
AbstractTemperatureSensor::ZERO_KELVIN_C), parameters(
parameters), temperatureMonitor(reportingObjectId,
domainId + 1,
GlobalDataPool::poolIdAndPositionToPid(temperaturePoolId, 0),
COMPONENT_TEMP_CONFIRMATION), domainId(domainId) {
if (thermalModule != NULL) {
ThermalComponentCore::ThermalComponentCore(object_id_t reportingObjectId,
uint8_t domainId, gp_id_t temperaturePoolId,
gp_id_t targetStatePoolId, gp_id_t currentStatePoolId,
gp_id_t requestPoolId, LocalPoolDataSetBase* dataSet,
Parameters parameters, StateRequest initialTargetState) :
temperature(temperaturePoolId, dataSet, PoolVariableIF::VAR_WRITE),
targetState(targetStatePoolId, dataSet, PoolVariableIF::VAR_READ),
currentState(currentStatePoolId, dataSet, PoolVariableIF::VAR_WRITE),
heaterRequest(requestPoolId, dataSet, PoolVariableIF::VAR_WRITE),
parameters(parameters), domainId(domainId),
temperatureMonitor(reportingObjectId, domainId + 1,temperaturePoolId,
COMPONENT_TEMP_CONFIRMATION) {
//Set thermal state once, then leave to operator.
targetState.setReadWriteMode(PoolVariableIF::VAR_WRITE);
ReturnValue_t result = targetState.read();
if(result == HasReturnvaluesIF::RETURN_OK) {
targetState = initialTargetState;
targetState.setValid(true);
targetState.commit();
}
targetState.setReadWriteMode(PoolVariableIF::VAR_READ);
}
void ThermalComponentCore::addSensor(AbstractTemperatureSensor* sensor) {
this->sensor = sensor;
}
void ThermalComponentCore::addFirstRedundantSensor(
AbstractTemperatureSensor *firstRedundantSensor) {
this->firstRedundantSensor = firstRedundantSensor;
}
void ThermalComponentCore::addSecondRedundantSensor(
AbstractTemperatureSensor *secondRedundantSensor) {
this->secondRedundantSensor = secondRedundantSensor;
}
void ThermalComponentCore::addThermalModule(ThermalModule *thermalModule,
Priority priority) {
this->thermalModule = thermalModule;
if(thermalModule != nullptr) {
thermalModule->registerComponent(this, priority);
}
//Set thermal state once, then leave to operator.
GlobDataSet mySet;
gp_uint8_t writableTargetState(targetStatePoolId, &mySet,
PoolVariableIF::VAR_WRITE);
writableTargetState = initialTargetState;
mySet.commit(PoolVariableIF::VALID);
}
CoreComponent::~CoreComponent() {
void ThermalComponentCore::setPriority(Priority priority) {
if(priority == SAFE) {
this->isSafeComponent = true;
}
}
ThermalComponentIF::HeaterRequest CoreComponent::performOperation(uint8_t opCode) {
ThermalComponentCore::~ThermalComponentCore() {
}
ThermalComponentIF::HeaterRequest ThermalComponentCore::performOperation(
uint8_t opCode) {
HeaterRequest request = HEATER_DONT_CARE;
//SHOULDDO: Better pass db_float_t* to getTemperature and set it invalid if invalid.
temperature = getTemperature();
updateMinMaxTemp();
if ((temperature != INVALID_TEMPERATURE)) {
if (temperature != INVALID_TEMPERATURE) {
temperature.setValid(PoolVariableIF::VALID);
State state = getState(temperature, getParameters(), targetState);
State state = getState(temperature.value, getParameters(),
targetState.value);
currentState = state;
checkLimits(state);
request = getHeaterRequest(targetState, temperature, getParameters());
request = getHeaterRequest(targetState.value, temperature.value,
getParameters());
} else {
temperatureMonitor.setToInvalid();
temperature.setValid(PoolVariableIF::INVALID);
@ -57,42 +80,45 @@ ThermalComponentIF::HeaterRequest CoreComponent::performOperation(uint8_t opCode
return request;
}
void CoreComponent::markStateIgnored() {
currentState = getIgnoredState(currentState);
void ThermalComponentCore::markStateIgnored() {
currentState = getIgnoredState(currentState.value);
}
object_id_t CoreComponent::getObjectId() {
object_id_t ThermalComponentCore::getObjectId() {
return temperatureMonitor.getReporterId();
return 0;
}
float CoreComponent::getLowerOpLimit() {
float ThermalComponentCore::getLowerOpLimit() {
return parameters.lowerOpLimit;
}
ReturnValue_t CoreComponent::setTargetState(int8_t newState) {
GlobDataSet mySet;
gp_uint8_t writableTargetState(targetState.getDataPoolId(),
&mySet, PoolVariableIF::VAR_READ_WRITE);
mySet.read();
if ((writableTargetState == STATE_REQUEST_OPERATIONAL)
&& (newState != STATE_REQUEST_IGNORE)) {
ReturnValue_t ThermalComponentCore::setTargetState(int8_t newState) {
targetState.setReadWriteMode(pool_rwm_t::VAR_READ_WRITE);
targetState.read();
if((targetState == STATE_REQUEST_OPERATIONAL) and
(newState != STATE_REQUEST_IGNORE)) {
return HasReturnvaluesIF::RETURN_FAILED;
}
switch (newState) {
case STATE_REQUEST_HEATING:
case STATE_REQUEST_IGNORE:
case STATE_REQUEST_OPERATIONAL:
writableTargetState = newState;
targetState = newState;
break;
case STATE_REQUEST_NON_OPERATIONAL:
default:
return INVALID_TARGET_STATE;
}
mySet.commit(PoolVariableIF::VALID);
targetState.setValid(true);
targetState.commit();
return HasReturnvaluesIF::RETURN_OK;
}
void CoreComponent::setOutputInvalid() {
void ThermalComponentCore::setOutputInvalid() {
temperature = INVALID_TEMPERATURE;
temperature.setValid(PoolVariableIF::INVALID);
currentState.setValid(PoolVariableIF::INVALID);
@ -101,20 +127,22 @@ void CoreComponent::setOutputInvalid() {
temperatureMonitor.setToUnchecked();
}
float CoreComponent::getTemperature() {
if ((sensor != NULL) && (sensor->isValid())) {
float ThermalComponentCore::getTemperature() {
if ((sensor != nullptr) && (sensor->isValid())) {
return sensor->getTemperature();
}
if ((firstRedundantSensor != NULL) && (firstRedundantSensor->isValid())) {
if ((firstRedundantSensor != nullptr) &&
(firstRedundantSensor->isValid())) {
return firstRedundantSensor->getTemperature();
}
if ((secondRedundantSensor != NULL) && (secondRedundantSensor->isValid())) {
if ((secondRedundantSensor != nullptr) &&
(secondRedundantSensor->isValid())) {
return secondRedundantSensor->getTemperature();
}
if (thermalModule != NULL) {
if (thermalModule != nullptr) {
float temperature = thermalModule->getTemperature();
if (temperature != ThermalModuleIF::INVALID_TEMPERATURE) {
return temperature;
@ -126,7 +154,7 @@ float CoreComponent::getTemperature() {
}
}
ThermalComponentIF::State CoreComponent::getState(float temperature,
ThermalComponentIF::State ThermalComponentCore::getState(float temperature,
Parameters parameters, int8_t targetState) {
ThermalComponentIF::State state;
@ -144,14 +172,14 @@ ThermalComponentIF::State CoreComponent::getState(float temperature,
return state;
}
void CoreComponent::checkLimits(ThermalComponentIF::State state) {
void ThermalComponentCore::checkLimits(ThermalComponentIF::State state) {
//Checks operational limits only.
temperatureMonitor.translateState(state, temperature.value,
getParameters().lowerOpLimit, getParameters().upperOpLimit);
}
ThermalComponentIF::HeaterRequest CoreComponent::getHeaterRequest(
ThermalComponentIF::HeaterRequest ThermalComponentCore::getHeaterRequest(
int8_t targetState, float temperature, Parameters parameters) {
if (targetState == STATE_REQUEST_IGNORE) {
isHeating = false;
@ -177,7 +205,7 @@ ThermalComponentIF::HeaterRequest CoreComponent::getHeaterRequest(
return HEATER_DONT_CARE;
}
ThermalComponentIF::State CoreComponent::getIgnoredState(int8_t state) {
ThermalComponentIF::State ThermalComponentCore::getIgnoredState(int8_t state) {
switch (state) {
case NON_OPERATIONAL_LOW:
return NON_OPERATIONAL_LOW_IGNORED;
@ -197,27 +225,27 @@ ThermalComponentIF::State CoreComponent::getIgnoredState(int8_t state) {
}
}
void CoreComponent::updateMinMaxTemp() {
void ThermalComponentCore::updateMinMaxTemp() {
if (temperature == INVALID_TEMPERATURE) {
return;
}
if (temperature < minTemp) {
minTemp = temperature;
minTemp = static_cast<float>(temperature);
}
if (temperature > maxTemp) {
maxTemp = temperature;
maxTemp = static_cast<float>(temperature);
}
}
uint8_t CoreComponent::getDomainId() const {
uint8_t ThermalComponentCore::getDomainId() const {
return domainId;
}
CoreComponent::Parameters CoreComponent::getParameters() {
ThermalComponentCore::Parameters ThermalComponentCore::getParameters() {
return parameters;
}
ReturnValue_t CoreComponent::getParameter(uint8_t domainId,
ReturnValue_t ThermalComponentCore::getParameter(uint8_t domainId,
uint16_t parameterId, ParameterWrapper* parameterWrapper,
const ParameterWrapper* newValues, uint16_t startAtIndex) {
ReturnValue_t result = temperatureMonitor.getParameter(domainId,
@ -251,7 +279,7 @@ ReturnValue_t CoreComponent::getParameter(uint8_t domainId,
parameterWrapper->set(parameters.upperOpLimit);
break;
default:
return INVALID_MATRIX_ID;
return INVALID_IDENTIFIER_ID;
}
return HasReturnvaluesIF::RETURN_OK;
}

View File

@ -0,0 +1,117 @@
#ifndef FSFW_THERMAL_THERMALCOMPONENTCORE_H_
#define FSFW_THERMAL_THERMALCOMPONENTCORE_H_
#include "ThermalMonitorReporter.h"
#include "ThermalComponentIF.h"
#include "AbstractTemperatureSensor.h"
#include "ThermalModule.h"
#include "../datapoollocal/LocalPoolVariable.h"
/**
* @brief
* @details
*/
class ThermalComponentCore: public ThermalComponentIF {
public:
struct Parameters {
float lowerOpLimit;
float upperOpLimit;
float heaterOn;
float hysteresis;
float heaterSwitchoff;
};
static const uint16_t COMPONENT_TEMP_CONFIRMATION = 5;
/**
* Some documentation
* @param reportingObjectId
* @param domainId
* @param temperaturePoolId
* @param targetStatePoolId
* @param currentStatePoolId
* @param requestPoolId
* @param dataSet
* @param parameters
* @param initialTargetState
*/
ThermalComponentCore(object_id_t reportingObjectId, uint8_t domainId,
gp_id_t temperaturePoolId, gp_id_t targetStatePoolId,
gp_id_t currentStatePoolId, gp_id_t requestPoolId,
LocalPoolDataSetBase* dataSet, Parameters parameters,
StateRequest initialTargetState =
ThermalComponentIF::STATE_REQUEST_OPERATIONAL);
void addSensor(AbstractTemperatureSensor* firstRedundantSensor);
void addFirstRedundantSensor(
AbstractTemperatureSensor* firstRedundantSensor);
void addSecondRedundantSensor(
AbstractTemperatureSensor* secondRedundantSensor);
void addThermalModule(ThermalModule* thermalModule, Priority priority);
void setPriority(Priority priority);
virtual ~ThermalComponentCore();
virtual HeaterRequest performOperation(uint8_t opCode);
void markStateIgnored();
object_id_t getObjectId();
uint8_t getDomainId() const;
virtual float getLowerOpLimit();
ReturnValue_t setTargetState(int8_t newState);
virtual void setOutputInvalid();
virtual ReturnValue_t getParameter(uint8_t domainId, uint16_t parameterId,
ParameterWrapper *parameterWrapper,
const ParameterWrapper *newValues, uint16_t startAtIndex);
protected:
AbstractTemperatureSensor *sensor = nullptr;
AbstractTemperatureSensor *firstRedundantSensor = nullptr;
AbstractTemperatureSensor *secondRedundantSensor = nullptr;
ThermalModuleIF *thermalModule = nullptr;
lp_var_t<float> temperature;
lp_var_t<int8_t> targetState;
lp_var_t<int8_t> currentState;
lp_var_t<uint8_t> heaterRequest;
bool isHeating = false;
bool isSafeComponent = false;
float minTemp = 999;
float maxTemp = AbstractTemperatureSensor::ZERO_KELVIN_C;
Parameters parameters;
const uint8_t domainId;
ThermalMonitorReporter temperatureMonitor;
virtual float getTemperature();
virtual State getState(float temperature, Parameters parameters,
int8_t targetState);
virtual void checkLimits(State state);
virtual HeaterRequest getHeaterRequest(int8_t targetState,
float temperature, Parameters parameters);
virtual State getIgnoredState(int8_t state);
void updateMinMaxTemp();
virtual Parameters getParameters();
};
#endif /* FSFW_THERMAL_THERMALCOMPONENT_CORE_H_ */

View File

@ -1,28 +1,31 @@
#include "../monitoring/LimitViolationReporter.h"
#include "../monitoring/MonitoringMessageContent.h"
#include "ThermalModule.h"
#include "AbstractTemperatureSensor.h"
ThermalModule::ThermalModule(uint32_t moduleTemperaturePoolId,
uint32_t currentStatePoolId, uint32_t targetStatePoolId,
GlobDataSet *dataSet, Parameters parameters,
#include "../monitoring/LimitViolationReporter.h"
#include "../monitoring/MonitoringMessageContent.h"
ThermalModule::ThermalModule(gp_id_t moduleTemperaturePoolId,
gp_id_t currentStatePoolId, gp_id_t targetStatePoolId,
LocalPoolDataSetBase *dataSet, Parameters parameters,
RedundantHeater::Parameters heaterParameters) :
oldStrategy(ACTIVE_SINGLE), survivalTargetTemp(0), targetTemp(0), heating(
false), parameters(parameters), moduleTemperature(
moduleTemperaturePoolId, dataSet, PoolVariableIF::VAR_WRITE), currentState(
currentStatePoolId, dataSet, PoolVariableIF::VAR_WRITE), targetState(
targetStatePoolId, dataSet, PoolVariableIF::VAR_READ) {
oldStrategy(ACTIVE_SINGLE), parameters(parameters),
moduleTemperature(moduleTemperaturePoolId, dataSet,
PoolVariableIF::VAR_WRITE),
currentState(currentStatePoolId, dataSet, PoolVariableIF::VAR_WRITE),
targetState(targetStatePoolId, dataSet, PoolVariableIF::VAR_READ) {
heater = new RedundantHeater(heaterParameters);
}
ThermalModule::ThermalModule(uint32_t moduleTemperaturePoolId, GlobDataSet* dataSet) :
oldStrategy(ACTIVE_SINGLE), survivalTargetTemp(0), targetTemp(0), heating(
false), parameters( { 0, 0 }), moduleTemperature(
moduleTemperaturePoolId, dataSet, PoolVariableIF::VAR_WRITE), heater(
NULL), currentState(PoolVariableIF::INVALID, dataSet,
PoolVariableIF::VAR_WRITE), targetState(PoolVariableIF::INVALID,
dataSet, PoolVariableIF::VAR_READ) {
ThermalModule::ThermalModule(gp_id_t moduleTemperaturePoolId,
LocalPoolDataSetBase* dataSet) :
oldStrategy(ACTIVE_SINGLE), parameters( { 0, 0 }),
moduleTemperature(moduleTemperaturePoolId, dataSet,
PoolVariableIF::VAR_WRITE),
currentState(gp_id_t(), dataSet,
PoolVariableIF::VAR_WRITE),
targetState(gp_id_t(), dataSet,
PoolVariableIF::VAR_READ) {
}
ThermalModule::~ThermalModule() {
@ -30,7 +33,7 @@ ThermalModule::~ThermalModule() {
}
void ThermalModule::performOperation(uint8_t opCode) {
if (heater != NULL) {
if (heater != nullptr) {
heater->performOperation(0);
}
}
@ -42,7 +45,7 @@ void ThermalModule::performMode(Strategy strategy) {
ThermalComponentIF::HeaterRequest componentHeaterRequest =
letComponentsPerformAndDeciceIfWeNeedToHeat(safeOnly);
if (heater == NULL) {
if (heater == nullptr) {
informComponentsAboutHeaterState(false, NONE);
return;
}
@ -53,7 +56,7 @@ void ThermalModule::performMode(Strategy strategy) {
//Components overwrite the module request.
heating = ((componentHeaterRequest
== ThermalComponentIF::HEATER_REQUEST_ON)
|| (componentHeaterRequest
or (componentHeaterRequest
== ThermalComponentIF::HEATER_REQUEST_EMERGENCY_ON));
}
@ -76,7 +79,7 @@ void ThermalModule::performMode(Strategy strategy) {
}
float ThermalModule::getTemperature() {
return moduleTemperature;
return moduleTemperature.value;
}
void ThermalModule::registerSensor(AbstractTemperatureSensor * sensor) {
@ -85,7 +88,8 @@ void ThermalModule::registerSensor(AbstractTemperatureSensor * sensor) {
void ThermalModule::registerComponent(ThermalComponentIF* component,
ThermalComponentIF::Priority priority) {
components.push_back(ComponentData( { component, priority, ThermalComponentIF::HEATER_DONT_CARE }));
components.push_back(ComponentData( { component, priority,
ThermalComponentIF::HEATER_DONT_CARE }));
}
void ThermalModule::calculateTemperature() {
@ -94,12 +98,13 @@ void ThermalModule::calculateTemperature() {
std::list<AbstractTemperatureSensor *>::iterator iter = sensors.begin();
for (; iter != sensors.end(); iter++) {
if ((*iter)->isValid()) {
moduleTemperature = moduleTemperature + (*iter)->getTemperature();
moduleTemperature = moduleTemperature.value +
(*iter)->getTemperature();
numberOfValidSensors++;
}
}
if (numberOfValidSensors != 0) {
moduleTemperature = moduleTemperature / numberOfValidSensors;
moduleTemperature = moduleTemperature.value / numberOfValidSensors;
moduleTemperature.setValid(PoolVariableIF::VALID);
} else {
moduleTemperature = INVALID_TEMPERATURE;
@ -117,9 +122,10 @@ ThermalComponentIF* ThermalModule::findComponent(object_id_t objectId) {
return NULL;
}
ThermalComponentIF::HeaterRequest ThermalModule::letComponentsPerformAndDeciceIfWeNeedToHeat(
bool safeOnly) {
ThermalComponentIF::HeaterRequest heaterRequests[ThermalComponentIF::NUMBER_OF_PRIORITIES];
ThermalComponentIF::HeaterRequest
ThermalModule::letComponentsPerformAndDeciceIfWeNeedToHeat(bool safeOnly) {
ThermalComponentIF::HeaterRequest
heaterRequests[ThermalComponentIF::NUMBER_OF_PRIORITIES];
survivalTargetTemp = -999;
targetTemp = -999;
@ -224,7 +230,7 @@ bool ThermalModule::calculateModuleHeaterRequestAndSetModuleStatus(
limit = survivalTargetTemp;
}
if (moduleTemperature >= limit) {
if (moduleTemperature.value >= limit) {
currentState = OPERATIONAL;
} else {
currentState = NON_OPERATIONAL;
@ -250,15 +256,16 @@ bool ThermalModule::calculateModuleHeaterRequestAndSetModuleStatus(
}
void ThermalModule::setHeating(bool on) {
GlobDataSet mySet;
gp_int8_t writableTargetState(targetState.getDataPoolId(),
&mySet, PoolVariableIF::VAR_WRITE);
ReturnValue_t result = targetState.read();
if(result == HasReturnvaluesIF::RETURN_OK) {
if(on) {
writableTargetState = STATE_REQUEST_HEATING;
} else {
writableTargetState = STATE_REQUEST_PASSIVE;
targetState.value = STATE_REQUEST_HEATING;
}
mySet.commit(PoolVariableIF::VALID);
else {
targetState.value = STATE_REQUEST_PASSIVE;
}
}
targetState.setValid(true);
}
void ThermalModule::updateTargetTemperatures(ThermalComponentIF* component,

View File

@ -1,14 +1,18 @@
#ifndef THERMALMODULE_H_
#define THERMALMODULE_H_
#ifndef FSFW_THERMAL_THERMALMODULE_H_
#define FSFW_THERMAL_THERMALMODULE_H_
#include "../datapoolglob/GlobalDataSet.h"
#include "../datapoolglob/GlobalPoolVariable.h"
#include "../devicehandlers/HealthDevice.h"
#include "../events/EventReportingProxyIF.h"
#include "ThermalModuleIF.h"
#include <list>
#include "tcsDefinitions.h"
#include "RedundantHeater.h"
#include "../datapoollocal/LocalPoolDataSetBase.h"
#include "../datapoollocal/LocalPoolVariable.h"
#include "../devicehandlers/HealthDevice.h"
#include "../events/EventReportingProxyIF.h"
#include <list>
class PowerSwitchIF;
/**
@ -22,11 +26,12 @@ public:
float hysteresis;
};
ThermalModule(uint32_t moduleTemperaturePoolId, uint32_t currentStatePoolId,
uint32_t targetStatePoolId, GlobDataSet *dataSet, Parameters parameters,
RedundantHeater::Parameters heaterParameters);
ThermalModule(gp_id_t moduleTemperaturePoolId, gp_id_t currentStatePoolId,
gp_id_t targetStatePoolId, LocalPoolDataSetBase *dataSet,
Parameters parameters, RedundantHeater::Parameters heaterParameters);
ThermalModule(uint32_t moduleTemperaturePoolId, GlobDataSet *dataSet);
ThermalModule(gp_id_t moduleTemperaturePoolId,
LocalPoolDataSetBase *dataSet);
virtual ~ThermalModule();
@ -62,20 +67,20 @@ protected:
Strategy oldStrategy;
float survivalTargetTemp;
float survivalTargetTemp = 0.0;
float targetTemp;
float targetTemp = 0.0;
bool heating;
bool heating = false;
Parameters parameters;
gp_float_t moduleTemperature;
lp_var_t<float> moduleTemperature;
RedundantHeater *heater;
RedundantHeater *heater = nullptr;
gp_int8_t currentState;
gp_int8_t targetState;
lp_var_t<int8_t> currentState;
lp_var_t<int8_t> targetState;
std::list<AbstractTemperatureSensor *> sensors;
std::list<ComponentData> components;
@ -92,4 +97,4 @@ protected:
void updateTargetTemperatures(ThermalComponentIF *component, bool isSafe);
};
#endif /* THERMALMODULE_H_ */
#endif /* FSFW_THERMAL_THERMALMODULE_H_ */

View File

@ -1,23 +0,0 @@
#ifndef FRAMEWORK_THERMAL_THERMALMONITOR_H_
#define FRAMEWORK_THERMAL_THERMALMONITOR_H_
#include "../monitoring/MonitorReporter.h"
#include "ThermalComponentIF.h"
class ThermalMonitor: public MonitorReporter<float> {
public:
template<typename ... Args>
ThermalMonitor(Args ... args) :
MonitorReporter<float>(std::forward<Args>(args)...) {
}
~ThermalMonitor();
ReturnValue_t translateState(ThermalComponentIF::State state, float sample,
float lowerLimit, float upperLimit, bool componentIsOperational = true);
bool isAboveHighLimit();
protected:
virtual void sendTransitionEvent(float currentValue, ReturnValue_t state);
};
#endif /* FRAMEWORK_THERMAL_THERMALMONITOR_H_ */

View File

@ -1,10 +1,12 @@
#include "ThermalMonitor.h"
#include "ThermalMonitorReporter.h"
#include "ThermalComponentIF.h"
#include "../monitoring/MonitoringIF.h"
ThermalMonitor::~ThermalMonitor() {
ThermalMonitorReporter::~ThermalMonitorReporter() {
}
void ThermalMonitor::sendTransitionEvent(float currentValue,
void ThermalMonitorReporter::sendTransitionEvent(float currentValue,
ReturnValue_t state) {
switch (state) {
case MonitoringIF::BELOW_LOW_LIMIT:
@ -28,7 +30,7 @@ void ThermalMonitor::sendTransitionEvent(float currentValue,
}
}
bool ThermalMonitor::isAboveHighLimit() {
bool ThermalMonitorReporter::isAboveHighLimit() {
if (oldState == ThermalComponentIF::ABOVE_OPERATIONAL_LIMIT) {
return true;
} else {
@ -36,7 +38,8 @@ bool ThermalMonitor::isAboveHighLimit() {
}
}
ReturnValue_t ThermalMonitor::translateState(ThermalComponentIF::State state, float sample, float lowerLimit,
ReturnValue_t ThermalMonitorReporter::translateState(
ThermalComponentIF::State state, float sample, float lowerLimit,
float upperLimit, bool componentIsOperational) {
if (ThermalComponentIF::isIgnoredState(state)) {
setToUnchecked();
@ -44,10 +47,12 @@ ReturnValue_t ThermalMonitor::translateState(ThermalComponentIF::State state, fl
}
switch (state) {
case ThermalComponentIF::OUT_OF_RANGE_LOW:
return monitorStateIs(MonitoringIF::BELOW_LOW_LIMIT, sample, lowerLimit);
return monitorStateIs(MonitoringIF::BELOW_LOW_LIMIT, sample,
lowerLimit);
case ThermalComponentIF::NON_OPERATIONAL_LOW:
if (componentIsOperational) {
return monitorStateIs(ThermalComponentIF::BELOW_OPERATIONAL_LIMIT, sample, lowerLimit);
return monitorStateIs(ThermalComponentIF::BELOW_OPERATIONAL_LIMIT,
sample, lowerLimit);
} else {
return monitorStateIs(HasReturnvaluesIF::RETURN_OK, sample, 0.0);
}
@ -55,12 +60,14 @@ ReturnValue_t ThermalMonitor::translateState(ThermalComponentIF::State state, fl
return monitorStateIs(HasReturnvaluesIF::RETURN_OK, sample, 0.0);
case ThermalComponentIF::NON_OPERATIONAL_HIGH:
if (componentIsOperational) {
return monitorStateIs(ThermalComponentIF::ABOVE_OPERATIONAL_LIMIT, sample, upperLimit);
return monitorStateIs(ThermalComponentIF::ABOVE_OPERATIONAL_LIMIT,
sample, upperLimit);
} else {
return monitorStateIs(HasReturnvaluesIF::RETURN_OK, sample, 0.0);
}
case ThermalComponentIF::OUT_OF_RANGE_HIGH:
return monitorStateIs(MonitoringIF::ABOVE_HIGH_LIMIT, sample, upperLimit);
return monitorStateIs(MonitoringIF::ABOVE_HIGH_LIMIT, sample,
upperLimit);
default:
//Never reached, all states covered.
return HasReturnvaluesIF::RETURN_FAILED;

View File

@ -0,0 +1,28 @@
#ifndef FSFW_THERMAL_THERMALMONITORREPORTER_H_
#define FSFW_THERMAL_THERMALMONITORREPORTER_H_
#include "ThermalComponentIF.h"
#include "../monitoring/MonitorReporter.h"
/**
* @brief Monitor Reporter implementation for thermal components.
*/
class ThermalMonitorReporter: public MonitorReporter<float> {
public:
template<typename ... Args>
ThermalMonitorReporter(Args ... args) :
MonitorReporter<float>(std::forward<Args>(args)...) {
}
~ThermalMonitorReporter();
ReturnValue_t translateState(ThermalComponentIF::State state, float sample,
float lowerLimit, float upperLimit,
bool componentIsOperational = true);
bool isAboveHighLimit();
protected:
virtual void sendTransitionEvent(float currentValue, ReturnValue_t state);
};
#endif /* FSFW_THERMAL_THERMALMONITORREPORTERREPORTER_H_ */

View File

@ -2,7 +2,7 @@
#define TCSDEFINITIONS_H_
static const uint32_t INVALID_TEMPERATURE = 999;
static const float INVALID_TEMPERATURE = 999;
#endif /* TCSDEFINITIONS_H_ */

View File

@ -3,19 +3,30 @@
#include "ServiceMatcher.h"
#include "SubserviceMatcher.h"
// This should be configurable..
const LocalPool::LocalPoolConfig PacketMatchTree::poolConfig = {
{10, sizeof(ServiceMatcher)},
{20, sizeof(SubServiceMatcher)},
{2, sizeof(ApidMatcher)},
{40, sizeof(PacketMatchTree::Node)}
};
PacketMatchTree::PacketMatchTree(Node* root) :
MatchTree<TmPacketMinimal*>(root, 2), factoryBackend(0, POOL_SIZES,
N_ELEMENTS, false, true), factory(&factoryBackend) {
MatchTree<TmPacketMinimal*>(root, 2),
factoryBackend(0, poolConfig, false, true),
factory(&factoryBackend) {
}
PacketMatchTree::PacketMatchTree(iterator root) :
MatchTree<TmPacketMinimal*>(root.element, 2), factoryBackend(0,
POOL_SIZES, N_ELEMENTS, false, true), factory(&factoryBackend) {
MatchTree<TmPacketMinimal*>(root.element, 2),
factoryBackend(0, poolConfig, false, true),
factory(&factoryBackend) {
}
PacketMatchTree::PacketMatchTree() :
MatchTree<TmPacketMinimal*>((Node*) NULL, 2), factoryBackend(0,
POOL_SIZES, N_ELEMENTS, false, true), factory(&factoryBackend) {
MatchTree<TmPacketMinimal*>((Node*) NULL, 2),
factoryBackend(0, poolConfig, false, true),
factory(&factoryBackend) {
}
PacketMatchTree::~PacketMatchTree() {
@ -172,11 +183,6 @@ ReturnValue_t PacketMatchTree::initialize() {
return factoryBackend.initialize();
}
const uint16_t PacketMatchTree::POOL_SIZES[N_POOLS] = { sizeof(ServiceMatcher),
sizeof(SubServiceMatcher), sizeof(ApidMatcher),
sizeof(PacketMatchTree::Node) };
//Maximum number of types and subtypes to filter should be more than sufficient.
const uint16_t PacketMatchTree::N_ELEMENTS[N_POOLS] = { 10, 20, 2, 40 };
ReturnValue_t PacketMatchTree::changeMatch(bool addToMatch, uint16_t apid,
uint8_t type, uint8_t subtype) {

View File

@ -23,8 +23,9 @@ protected:
ReturnValue_t cleanUpElement(iterator position);
private:
static const uint8_t N_POOLS = 4;
LocalPool<N_POOLS> factoryBackend;
LocalPool factoryBackend;
PlacementFactory factory;
static const LocalPool::LocalPoolConfig poolConfig;
static const uint16_t POOL_SIZES[N_POOLS];
static const uint16_t N_ELEMENTS[N_POOLS];
template<typename VALUE_T, typename INSERTION_T>

View File

@ -1,296 +1,295 @@
//#include "CatchDefinitions.h"
//
//#include <config/objects/Factory.h>
//#include <fsfw/objectmanager/ObjectManager.h>
//#include <fsfw/storagemanager/LocalPool.h>
//
//#include <catch.hpp>
//#include <CatchDefinitions.h>
//
//#include <cstring>
//
//
//TEST_CASE( "Local Pool Simple Tests [1 Pool]" , "[TestPool]") {
//// uint16_t numberOfElements[1] = {1};
//// uint16_t sizeofElements[1] = {10};
// LocalPool::LocalPoolConfig config = {{1, 10}};
// LocalPool simplePool(0, config);
// std::array<uint8_t, 20> testDataArray;
// std::array<uint8_t, 20> receptionArray;
// store_address_t testStoreId;
// ReturnValue_t result = retval::CATCH_FAILED;
// uint8_t *pointer = nullptr;
// const uint8_t * constPointer = nullptr;
//
// for(size_t i = 0; i < testDataArray.size(); i++) {
// testDataArray[i] = i;
// }
// size_t size = 10;
//
// SECTION ( "Basic tests") {
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
// REQUIRE(result == retval::CATCH_OK);
// result = simplePool.getData(testStoreId, &constPointer, &size);
// REQUIRE(result == retval::CATCH_OK);
// memcpy(receptionArray.data(), constPointer, size);
// for(size_t i = 0; i < size; i++) {
// CHECK(receptionArray[i] == i );
// }
// memset(receptionArray.data(), 0, size);
// result = simplePool.modifyData(testStoreId, &pointer, &size);
// memcpy(receptionArray.data(), pointer, size);
// REQUIRE(result == retval::CATCH_OK);
// for(size_t i = 0; i < size; i++) {
// CHECK(receptionArray[i] == i );
// }
// result = simplePool.deleteData(testStoreId);
// REQUIRE(result == retval::CATCH_OK);
// result = simplePool.addData(&testStoreId, testDataArray.data(), 15);
// CHECK (result == (int) StorageManagerIF::DATA_TOO_LARGE);
// }
//
// SECTION ( "Reservation Tests ") {
// pointer = nullptr;
// result = simplePool.getFreeElement(&testStoreId, size, &pointer);
// REQUIRE (result == retval::CATCH_OK);
// memcpy(pointer, testDataArray.data(), size);
// constPointer = nullptr;
// result = simplePool.getData(testStoreId, &constPointer, &size);
//
// REQUIRE (result == retval::CATCH_OK);
// memcpy(receptionArray.data(), constPointer, size);
// for(size_t i = 0; i < size; i++) {
// CHECK(receptionArray[i] == i );
// }
// }
//
// SECTION ( "Add, delete, add, add when full") {
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
// REQUIRE(result == retval::CATCH_OK);
// result = simplePool.getData(testStoreId, &constPointer, &size);
// REQUIRE( result == retval::CATCH_OK);
// memcpy(receptionArray.data(), constPointer, size);
// for(size_t i = 0; i < size; i++) {
// CHECK(receptionArray[i] == i );
// }
//
// result = simplePool.deleteData(testStoreId);
// REQUIRE(result == retval::CATCH_OK);
//
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
// REQUIRE(result == retval::CATCH_OK);
// result = simplePool.getData(testStoreId, &constPointer, &size);
// REQUIRE( result == retval::CATCH_OK);
// memcpy(receptionArray.data(), constPointer, size);
// for(size_t i = 0; i < size; i++) {
// CHECK(receptionArray[i] == i );
// }
//
// store_address_t newAddress;
// result = simplePool.addData(&newAddress, testDataArray.data(), size);
// REQUIRE(result == (int) StorageManagerIF::DATA_STORAGE_FULL);
//
// // Packet Index to high intentionally
// newAddress.packetIndex = 2;
// pointer = testDataArray.data();
// result = simplePool.modifyData(newAddress, &pointer, &size);
// REQUIRE(result == (int) StorageManagerIF::ILLEGAL_STORAGE_ID);
//
// result = simplePool.deleteData(newAddress);
// REQUIRE(result == (int) StorageManagerIF::ILLEGAL_STORAGE_ID);
//
// newAddress.packetIndex = 0;
// newAddress.poolIndex = 2;
// result = simplePool.deleteData(newAddress);
// REQUIRE(result == (int) StorageManagerIF::ILLEGAL_STORAGE_ID);
// }
//
// SECTION ( "Initialize and clear store, delete with pointer") {
// result = simplePool.initialize();
// REQUIRE(result == retval::CATCH_OK);
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
// REQUIRE(result == retval::CATCH_OK);
// simplePool.clearStore();
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
// REQUIRE(result == retval::CATCH_OK);
// result = simplePool.modifyData(testStoreId, &pointer, &size);
// REQUIRE(result == retval::CATCH_OK);
// store_address_t newId;
// result = simplePool.deleteData(pointer, size, &testStoreId);
// REQUIRE(result == retval::CATCH_OK);
// REQUIRE(testStoreId.raw != (uint32_t) StorageManagerIF::INVALID_ADDRESS);
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
// REQUIRE(result == retval::CATCH_OK);
// }
//}
//
//int runIdx = 0;
//
//TEST_CASE( "Local Pool Extended Tests [3 Pools]" , "[TestPool2]") {
// LocalPool::LocalPoolConfig* config;
// if(runIdx == 0) {
// config = new LocalPool::LocalPoolConfig{{10, 5}, {5, 10}, {2, 20}};
// }
// else {
// // shufle the order, they should be sort implictely so that the
// // order is ascending for the page sizes.
// config = new LocalPool::LocalPoolConfig{{5, 10}, {2, 20}, {10, 5}};
// size_t lastSize = 0;
// for(const auto& pair: *config) {
// CHECK(pair.second > lastSize);
// lastSize = pair.second;
// }
// }
// runIdx++;
//
// LocalPool simplePool(0, *config);
// std::array<uint8_t, 20> testDataArray;
// std::array<uint8_t, 20> receptionArray;
// store_address_t testStoreId;
// ReturnValue_t result = retval::CATCH_FAILED;
// for(size_t i = 0; i < testDataArray.size(); i++) {
// testDataArray[i] = i;
// }
// size_t size = 0;
//
// SECTION ("Basic tests") {
// size = 8;
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
// REQUIRE(result == retval::CATCH_OK);
// // Should be on second page of the pool now for 8 bytes
// CHECK(testStoreId.poolIndex == 1);
// CHECK(testStoreId.packetIndex == 0);
//
// size = 15;
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
// REQUIRE(result == retval::CATCH_OK);
// // Should be on third page of the pool now for 15 bytes
// CHECK(testStoreId.poolIndex == 2);
// CHECK(testStoreId.packetIndex == 0);
//
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
// REQUIRE(result == retval::CATCH_OK);
// // Should be on third page of the pool now for 15 bytes
// CHECK(testStoreId.poolIndex == 2);
// CHECK(testStoreId.packetIndex == 1);
//
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
// // Should be on third page of the pool now for 15 bytes
// REQUIRE(result == (int) LocalPool::DATA_STORAGE_FULL);
//
// size = 8;
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
// REQUIRE(result == retval::CATCH_OK);
// // Should still work
// CHECK(testStoreId.poolIndex == 1);
// CHECK(testStoreId.packetIndex == 1);
//
// // fill the rest of the pool
// for(uint8_t idx = 2; idx < 5; idx++) {
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
// REQUIRE(result == retval::CATCH_OK);
// CHECK(testStoreId.poolIndex == 1);
// CHECK(testStoreId.packetIndex == idx);
// }
// }
//
// SECTION ("Fill Count and Clearing") {
// //SECTION("Basic tests");
// uint8_t bytesWritten = 0;
// simplePool.getFillCount(receptionArray.data(), &bytesWritten);
// // fill count should be all zeros now.
// CHECK(bytesWritten == 4);
// CHECK(receptionArray[0] == 0);
// CHECK(receptionArray[1] == 0);
// CHECK(receptionArray[2] == 0);
// CHECK(receptionArray[3] == 0);
//
// // now fill the store completely.
// size = 5;
// for(uint8_t idx = 0; idx < 10; idx++) {
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
// REQUIRE(result == retval::CATCH_OK);
// CHECK(testStoreId.poolIndex == 0);
// CHECK(testStoreId.packetIndex == idx);
// }
// size = 10;
// for(uint8_t idx = 0; idx < 5; idx++) {
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
// REQUIRE(result == retval::CATCH_OK);
// CHECK(testStoreId.poolIndex == 1);
// CHECK(testStoreId.packetIndex == idx);
// }
// size = 20;
// for(uint8_t idx = 0; idx < 2; idx++) {
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
// REQUIRE(result == retval::CATCH_OK);
// CHECK(testStoreId.poolIndex == 2);
// CHECK(testStoreId.packetIndex == idx);
// }
// bytesWritten = 0;
// simplePool.getFillCount(receptionArray.data(), &bytesWritten);
// // fill count should be all 100 now.
// CHECK(bytesWritten == 4);
// CHECK(receptionArray[0] == 100);
// CHECK(receptionArray[1] == 100);
// CHECK(receptionArray[2] == 100);
// CHECK(receptionArray[3] == 100);
//
// // now clear the store
// simplePool.clearStore();
// bytesWritten = 0;
// simplePool.getFillCount(receptionArray.data(), &bytesWritten);
// CHECK(bytesWritten == 4);
// CHECK(receptionArray[0] == 0);
// CHECK(receptionArray[1] == 0);
// CHECK(receptionArray[2] == 0);
// CHECK(receptionArray[3] == 0);
//
// // now fill one page
// size = 5;
// for(uint8_t idx = 0; idx < 10; idx++) {
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
// REQUIRE(result == retval::CATCH_OK);
// CHECK(testStoreId.poolIndex == 0);
// CHECK(testStoreId.packetIndex == idx);
// }
// bytesWritten = 0;
// simplePool.getFillCount(receptionArray.data(), &bytesWritten);
// // First page full, median fill count is 33 %
// CHECK(bytesWritten == 4);
// CHECK(receptionArray[0] == 100);
// CHECK(receptionArray[1] == 0);
// CHECK(receptionArray[2] == 0);
// CHECK(receptionArray[3] == 33);
//
// // now fill second page
// size = 10;
// for(uint8_t idx = 0; idx < 5; idx++) {
// result = simplePool.addData(&testStoreId, testDataArray.data(), size);
// REQUIRE(result == retval::CATCH_OK);
// CHECK(testStoreId.poolIndex == 1);
// CHECK(testStoreId.packetIndex == idx);
// }
// bytesWritten = 0;
// simplePool.getFillCount(receptionArray.data(), &bytesWritten);
// // First and second page full, median fill count is 66 %
// CHECK(bytesWritten == 4);
// CHECK(receptionArray[0] == 100);
// CHECK(receptionArray[1] == 100);
// CHECK(receptionArray[2] == 0);
// CHECK(receptionArray[3] == 66);
//
// // now clear first page
// simplePool.clearPage(0);
// bytesWritten = 0;
// simplePool.getFillCount(receptionArray.data(), &bytesWritten);
// // Second page full, median fill count is 33 %
// CHECK(bytesWritten == 4);
// CHECK(receptionArray[0] == 0);
// CHECK(receptionArray[1] == 100);
// CHECK(receptionArray[2] == 0);
// CHECK(receptionArray[3] == 33);
// }
//
// delete(config);
//}
#include "CatchDefinitions.h"
#include <fsfw/objectmanager/ObjectManager.h>
#include <fsfw/storagemanager/LocalPool.h>
#include <catch.hpp>
#include <CatchDefinitions.h>
#include <cstring>
TEST_CASE( "Local Pool Simple Tests [1 Pool]" , "[TestPool]") {
// uint16_t numberOfElements[1] = {1};
// uint16_t sizeofElements[1] = {10};
LocalPool::LocalPoolConfig config = {{1, 10}};
LocalPool simplePool(0, config);
std::array<uint8_t, 20> testDataArray;
std::array<uint8_t, 20> receptionArray;
store_address_t testStoreId;
ReturnValue_t result = retval::CATCH_FAILED;
uint8_t *pointer = nullptr;
const uint8_t * constPointer = nullptr;
for(size_t i = 0; i < testDataArray.size(); i++) {
testDataArray[i] = i;
}
size_t size = 10;
SECTION ( "Basic tests") {
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
REQUIRE(result == retval::CATCH_OK);
result = simplePool.getData(testStoreId, &constPointer, &size);
REQUIRE(result == retval::CATCH_OK);
memcpy(receptionArray.data(), constPointer, size);
for(size_t i = 0; i < size; i++) {
CHECK(receptionArray[i] == i );
}
memset(receptionArray.data(), 0, size);
result = simplePool.modifyData(testStoreId, &pointer, &size);
memcpy(receptionArray.data(), pointer, size);
REQUIRE(result == retval::CATCH_OK);
for(size_t i = 0; i < size; i++) {
CHECK(receptionArray[i] == i );
}
result = simplePool.deleteData(testStoreId);
REQUIRE(result == retval::CATCH_OK);
result = simplePool.addData(&testStoreId, testDataArray.data(), 15);
CHECK (result == (int) StorageManagerIF::DATA_TOO_LARGE);
}
SECTION ( "Reservation Tests ") {
pointer = nullptr;
result = simplePool.getFreeElement(&testStoreId, size, &pointer);
REQUIRE (result == retval::CATCH_OK);
memcpy(pointer, testDataArray.data(), size);
constPointer = nullptr;
result = simplePool.getData(testStoreId, &constPointer, &size);
REQUIRE (result == retval::CATCH_OK);
memcpy(receptionArray.data(), constPointer, size);
for(size_t i = 0; i < size; i++) {
CHECK(receptionArray[i] == i );
}
}
SECTION ( "Add, delete, add, add when full") {
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
REQUIRE(result == retval::CATCH_OK);
result = simplePool.getData(testStoreId, &constPointer, &size);
REQUIRE( result == retval::CATCH_OK);
memcpy(receptionArray.data(), constPointer, size);
for(size_t i = 0; i < size; i++) {
CHECK(receptionArray[i] == i );
}
result = simplePool.deleteData(testStoreId);
REQUIRE(result == retval::CATCH_OK);
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
REQUIRE(result == retval::CATCH_OK);
result = simplePool.getData(testStoreId, &constPointer, &size);
REQUIRE( result == retval::CATCH_OK);
memcpy(receptionArray.data(), constPointer, size);
for(size_t i = 0; i < size; i++) {
CHECK(receptionArray[i] == i );
}
store_address_t newAddress;
result = simplePool.addData(&newAddress, testDataArray.data(), size);
REQUIRE(result == (int) StorageManagerIF::DATA_STORAGE_FULL);
// Packet Index to high intentionally
newAddress.packetIndex = 2;
pointer = testDataArray.data();
result = simplePool.modifyData(newAddress, &pointer, &size);
REQUIRE(result == (int) StorageManagerIF::ILLEGAL_STORAGE_ID);
result = simplePool.deleteData(newAddress);
REQUIRE(result == (int) StorageManagerIF::ILLEGAL_STORAGE_ID);
newAddress.packetIndex = 0;
newAddress.poolIndex = 2;
result = simplePool.deleteData(newAddress);
REQUIRE(result == (int) StorageManagerIF::ILLEGAL_STORAGE_ID);
}
SECTION ( "Initialize and clear store, delete with pointer") {
result = simplePool.initialize();
REQUIRE(result == retval::CATCH_OK);
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
REQUIRE(result == retval::CATCH_OK);
simplePool.clearStore();
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
REQUIRE(result == retval::CATCH_OK);
result = simplePool.modifyData(testStoreId, &pointer, &size);
REQUIRE(result == retval::CATCH_OK);
store_address_t newId;
result = simplePool.deleteData(pointer, size, &testStoreId);
REQUIRE(result == retval::CATCH_OK);
REQUIRE(testStoreId.raw != (uint32_t) StorageManagerIF::INVALID_ADDRESS);
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
REQUIRE(result == retval::CATCH_OK);
}
}
int runIdx = 0;
TEST_CASE( "Local Pool Extended Tests [3 Pools]" , "[TestPool2]") {
LocalPool::LocalPoolConfig* config;
if(runIdx == 0) {
config = new LocalPool::LocalPoolConfig{{10, 5}, {5, 10}, {2, 20}};
}
else {
// shufle the order, they should be sort implictely so that the
// order is ascending for the page sizes.
config = new LocalPool::LocalPoolConfig{{5, 10}, {2, 20}, {10, 5}};
size_t lastSize = 0;
for(const auto& pair: *config) {
CHECK(pair.second > lastSize);
lastSize = pair.second;
}
}
runIdx++;
LocalPool simplePool(0, *config);
std::array<uint8_t, 20> testDataArray;
std::array<uint8_t, 20> receptionArray;
store_address_t testStoreId;
ReturnValue_t result = retval::CATCH_FAILED;
for(size_t i = 0; i < testDataArray.size(); i++) {
testDataArray[i] = i;
}
size_t size = 0;
SECTION ("Basic tests") {
size = 8;
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
REQUIRE(result == retval::CATCH_OK);
// Should be on second page of the pool now for 8 bytes
CHECK(testStoreId.poolIndex == 1);
CHECK(testStoreId.packetIndex == 0);
size = 15;
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
REQUIRE(result == retval::CATCH_OK);
// Should be on third page of the pool now for 15 bytes
CHECK(testStoreId.poolIndex == 2);
CHECK(testStoreId.packetIndex == 0);
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
REQUIRE(result == retval::CATCH_OK);
// Should be on third page of the pool now for 15 bytes
CHECK(testStoreId.poolIndex == 2);
CHECK(testStoreId.packetIndex == 1);
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
// Should be on third page of the pool now for 15 bytes
REQUIRE(result == (int) LocalPool::DATA_STORAGE_FULL);
size = 8;
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
REQUIRE(result == retval::CATCH_OK);
// Should still work
CHECK(testStoreId.poolIndex == 1);
CHECK(testStoreId.packetIndex == 1);
// fill the rest of the pool
for(uint8_t idx = 2; idx < 5; idx++) {
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
REQUIRE(result == retval::CATCH_OK);
CHECK(testStoreId.poolIndex == 1);
CHECK(testStoreId.packetIndex == idx);
}
}
SECTION ("Fill Count and Clearing") {
//SECTION("Basic tests");
uint8_t bytesWritten = 0;
simplePool.getFillCount(receptionArray.data(), &bytesWritten);
// fill count should be all zeros now.
CHECK(bytesWritten == 4);
CHECK(receptionArray[0] == 0);
CHECK(receptionArray[1] == 0);
CHECK(receptionArray[2] == 0);
CHECK(receptionArray[3] == 0);
// now fill the store completely.
size = 5;
for(uint8_t idx = 0; idx < 10; idx++) {
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
REQUIRE(result == retval::CATCH_OK);
CHECK(testStoreId.poolIndex == 0);
CHECK(testStoreId.packetIndex == idx);
}
size = 10;
for(uint8_t idx = 0; idx < 5; idx++) {
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
REQUIRE(result == retval::CATCH_OK);
CHECK(testStoreId.poolIndex == 1);
CHECK(testStoreId.packetIndex == idx);
}
size = 20;
for(uint8_t idx = 0; idx < 2; idx++) {
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
REQUIRE(result == retval::CATCH_OK);
CHECK(testStoreId.poolIndex == 2);
CHECK(testStoreId.packetIndex == idx);
}
bytesWritten = 0;
simplePool.getFillCount(receptionArray.data(), &bytesWritten);
// fill count should be all 100 now.
CHECK(bytesWritten == 4);
CHECK(receptionArray[0] == 100);
CHECK(receptionArray[1] == 100);
CHECK(receptionArray[2] == 100);
CHECK(receptionArray[3] == 100);
// now clear the store
simplePool.clearStore();
bytesWritten = 0;
simplePool.getFillCount(receptionArray.data(), &bytesWritten);
CHECK(bytesWritten == 4);
CHECK(receptionArray[0] == 0);
CHECK(receptionArray[1] == 0);
CHECK(receptionArray[2] == 0);
CHECK(receptionArray[3] == 0);
// now fill one page
size = 5;
for(uint8_t idx = 0; idx < 10; idx++) {
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
REQUIRE(result == retval::CATCH_OK);
CHECK(testStoreId.poolIndex == 0);
CHECK(testStoreId.packetIndex == idx);
}
bytesWritten = 0;
simplePool.getFillCount(receptionArray.data(), &bytesWritten);
// First page full, median fill count is 33 %
CHECK(bytesWritten == 4);
CHECK(receptionArray[0] == 100);
CHECK(receptionArray[1] == 0);
CHECK(receptionArray[2] == 0);
CHECK(receptionArray[3] == 33);
// now fill second page
size = 10;
for(uint8_t idx = 0; idx < 5; idx++) {
result = simplePool.addData(&testStoreId, testDataArray.data(), size);
REQUIRE(result == retval::CATCH_OK);
CHECK(testStoreId.poolIndex == 1);
CHECK(testStoreId.packetIndex == idx);
}
bytesWritten = 0;
simplePool.getFillCount(receptionArray.data(), &bytesWritten);
// First and second page full, median fill count is 66 %
CHECK(bytesWritten == 4);
CHECK(receptionArray[0] == 100);
CHECK(receptionArray[1] == 100);
CHECK(receptionArray[2] == 0);
CHECK(receptionArray[3] == 66);
// now clear first page
simplePool.clearPage(0);
bytesWritten = 0;
simplePool.getFillCount(receptionArray.data(), &bytesWritten);
// Second page full, median fill count is 33 %
CHECK(bytesWritten == 4);
CHECK(receptionArray[0] == 0);
CHECK(receptionArray[1] == 100);
CHECK(receptionArray[2] == 0);
CHECK(receptionArray[3] == 33);
}
delete(config);
}