Merge branch 'develop' into srv20_error_msgs
This commit is contained in:
commit
a1dd4dcbc1
12
CHANGELOG.md
12
CHANGELOG.md
@ -234,7 +234,6 @@ https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
|
||||
- https://gitlab.kitware.com/cmake/cmake/-/issues/21696
|
||||
Easiest solution for now: Keep this option OFF by default.
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/616
|
||||
- Linux HAL: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1
|
||||
- Dedicated Version class and constant `fsfw::FSFW_VERSION` containing version information
|
||||
inside `fsfw/version.h`
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/559
|
||||
@ -249,6 +248,17 @@ https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/593
|
||||
PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/590
|
||||
- `Subsystem`: New API to add table and sequence entries
|
||||
|
||||
## HAL
|
||||
|
||||
- SPI: Cache the SPI device in the communication interface. Architecturally, this makes a
|
||||
lot more sense because each ComIF should be responsible for one SPI bus.
|
||||
- SPI: Move the empty transfer to update the line polarity to separate function. This means
|
||||
it is not automatically called when calling the setter function for SPI speed and mode.
|
||||
The user should call this function after locking the CS mutex if multiple SPI devices with
|
||||
differing speeds and modes are attached to one bus.
|
||||
- SPI: Getter functions for SPI speed and mode.
|
||||
- I2C: Add wiretapping option for I2C. Enabled with `FSFW_HAL_I2C_WIRETAPPING` defined to 1.
|
||||
|
||||
## Fixed
|
||||
|
||||
- TCP TMTC Server: `MutexGuard` was not created properly in
|
||||
|
@ -196,7 +196,7 @@ message(
|
||||
)
|
||||
|
||||
# Check whether the user has already installed ETL first
|
||||
find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} QUIET)
|
||||
find_package(${FSFW_ETL_LIB_NAME} ${FSFW_ETL_LIB_MAJOR_VERSION} CONFIG QUIET)
|
||||
# Not installed, so use FetchContent to download and provide etl
|
||||
if(NOT ${FSFW_ETL_LIB_NAME}_FOUND)
|
||||
message(
|
||||
|
@ -51,7 +51,10 @@ exclude_patterns = ["_build", "Thumbs.db", ".DS_Store"]
|
||||
html_theme = "alabaster"
|
||||
|
||||
html_theme_options = {
|
||||
"extra_nav_links": {"Impressum" : "https://www.uni-stuttgart.de/impressum", "Datenschutz": "https://info.irs.uni-stuttgart.de/datenschutz/datenschutzWebmit.html"}
|
||||
"extra_nav_links": {
|
||||
"Impressum": "https://www.uni-stuttgart.de/impressum",
|
||||
"Datenschutz": "https://info.irs.uni-stuttgart.de/datenschutz/datenschutzWebmit.html",
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -16,8 +16,8 @@ class CommandActionHelper {
|
||||
public:
|
||||
explicit CommandActionHelper(CommandsActionsIF* owner);
|
||||
virtual ~CommandActionHelper();
|
||||
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, const uint8_t* data,
|
||||
uint32_t size);
|
||||
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId,
|
||||
const uint8_t* data = nullptr, uint32_t size = 0);
|
||||
ReturnValue_t commandAction(object_id_t commandTo, ActionId_t actionId, SerializeIF* data);
|
||||
ReturnValue_t initialize();
|
||||
ReturnValue_t handleReply(CommandMessage* reply);
|
||||
|
@ -2,7 +2,10 @@
|
||||
#define FSFW_CFDP_H
|
||||
|
||||
#include "cfdp/definitions.h"
|
||||
#include "cfdp/handler/CfdpHandler.h"
|
||||
#include "cfdp/handler/DestHandler.h"
|
||||
#include "cfdp/handler/FaultHandlerBase.h"
|
||||
#include "cfdp/helpers.h"
|
||||
#include "cfdp/tlv/Lv.h"
|
||||
#include "cfdp/tlv/StringLv.h"
|
||||
#include "cfdp/tlv/Tlv.h"
|
||||
|
@ -1 +1,3 @@
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE FaultHandlerBase.cpp UserBase.cpp)
|
||||
target_sources(
|
||||
${LIB_FSFW_NAME} PRIVATE SourceHandler.cpp DestHandler.cpp
|
||||
FaultHandlerBase.cpp UserBase.cpp CfdpHandler.cpp)
|
||||
|
134
src/fsfw/cfdp/handler/CfdpHandler.cpp
Normal file
134
src/fsfw/cfdp/handler/CfdpHandler.cpp
Normal file
@ -0,0 +1,134 @@
|
||||
#include "CfdpHandler.h"
|
||||
|
||||
#include "fsfw/cfdp/pdu/AckPduReader.h"
|
||||
#include "fsfw/cfdp/pdu/PduHeaderReader.h"
|
||||
#include "fsfw/globalfunctions/arrayprinter.h"
|
||||
#include "fsfw/ipc/QueueFactory.h"
|
||||
#include "fsfw/tmtcservices/TmTcMessage.h"
|
||||
|
||||
using namespace returnvalue;
|
||||
using namespace cfdp;
|
||||
|
||||
CfdpHandler::CfdpHandler(const FsfwHandlerParams& fsfwParams, const CfdpHandlerCfg& cfdpCfg)
|
||||
: SystemObject(fsfwParams.objectId),
|
||||
msgQueue(fsfwParams.msgQueue),
|
||||
destHandler(
|
||||
DestHandlerParams(LocalEntityCfg(cfdpCfg.id, cfdpCfg.indicCfg, cfdpCfg.faultHandler),
|
||||
cfdpCfg.userHandler, cfdpCfg.remoteCfgProvider, cfdpCfg.packetInfoList,
|
||||
cfdpCfg.lostSegmentsList),
|
||||
FsfwParams(fsfwParams.packetDest, nullptr, this, fsfwParams.tcStore,
|
||||
fsfwParams.tmStore)) {
|
||||
destHandler.setMsgQueue(msgQueue);
|
||||
}
|
||||
|
||||
[[nodiscard]] const char* CfdpHandler::getName() const { return "CFDP Handler"; }
|
||||
|
||||
[[nodiscard]] uint32_t CfdpHandler::getIdentifier() const {
|
||||
return destHandler.getDestHandlerParams().cfg.localId.getValue();
|
||||
}
|
||||
|
||||
[[nodiscard]] MessageQueueId_t CfdpHandler::getRequestQueue() const { return msgQueue.getId(); }
|
||||
|
||||
ReturnValue_t CfdpHandler::initialize() {
|
||||
ReturnValue_t result = destHandler.initialize();
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
tcStore = destHandler.getTcStore();
|
||||
tmStore = destHandler.getTmStore();
|
||||
|
||||
return SystemObject::initialize();
|
||||
}
|
||||
|
||||
ReturnValue_t CfdpHandler::performOperation(uint8_t operationCode) {
|
||||
// TODO: Receive TC packets and route them to source and dest handler, depending on which is
|
||||
// correct or more appropriate
|
||||
ReturnValue_t status;
|
||||
ReturnValue_t result = OK;
|
||||
TmTcMessage tmtcMsg;
|
||||
for (status = msgQueue.receiveMessage(&tmtcMsg); status == returnvalue::OK;
|
||||
status = msgQueue.receiveMessage(&tmtcMsg)) {
|
||||
result = handleCfdpPacket(tmtcMsg);
|
||||
if (result != OK) {
|
||||
status = result;
|
||||
}
|
||||
}
|
||||
auto& fsmRes = destHandler.performStateMachine();
|
||||
// TODO: Error handling?
|
||||
while (fsmRes.callStatus == CallStatus::CALL_AGAIN) {
|
||||
destHandler.performStateMachine();
|
||||
// TODO: Error handling?
|
||||
}
|
||||
return status;
|
||||
}
|
||||
|
||||
ReturnValue_t CfdpHandler::handleCfdpPacket(TmTcMessage& msg) {
|
||||
auto accessorPair = tcStore->getData(msg.getStorageId());
|
||||
if (accessorPair.first != OK) {
|
||||
return accessorPair.first;
|
||||
}
|
||||
PduHeaderReader reader(accessorPair.second.data(), accessorPair.second.size());
|
||||
ReturnValue_t result = reader.parseData();
|
||||
if (result != returnvalue::OK) {
|
||||
return INVALID_PDU_FORMAT;
|
||||
}
|
||||
// The CFDP distributor should have taken care of ensuring the destination ID is correct
|
||||
PduType type = reader.getPduType();
|
||||
// Only the destination handler can process these PDUs
|
||||
if (type == PduType::FILE_DATA) {
|
||||
// Disable auto-deletion of packet
|
||||
accessorPair.second.release();
|
||||
PacketInfo info(type, msg.getStorageId());
|
||||
result = destHandler.passPacket(info);
|
||||
} else {
|
||||
// Route depending on PDU type and directive type if applicable. It retrieves directive type
|
||||
// from the raw stream for better performance (with sanity and directive code check).
|
||||
// The routing is based on section 4.5 of the CFDP standard which specifies the PDU forwarding
|
||||
// procedure.
|
||||
|
||||
// PDU header only. Invalid supplied data. A directive packet should have a valid data field
|
||||
// with at least one byte being the directive code
|
||||
const uint8_t* pduDataField = reader.getPduDataField();
|
||||
if (pduDataField == nullptr) {
|
||||
return INVALID_PDU_FORMAT;
|
||||
}
|
||||
if (not FileDirectiveReader::checkFileDirective(pduDataField[0])) {
|
||||
return INVALID_DIRECTIVE_FIELD;
|
||||
}
|
||||
auto directive = static_cast<FileDirective>(pduDataField[0]);
|
||||
|
||||
auto passToDestHandler = [&]() {
|
||||
accessorPair.second.release();
|
||||
PacketInfo info(type, msg.getStorageId(), directive);
|
||||
result = destHandler.passPacket(info);
|
||||
};
|
||||
auto passToSourceHandler = [&]() {
|
||||
|
||||
};
|
||||
if (directive == FileDirective::METADATA or directive == FileDirective::EOF_DIRECTIVE or
|
||||
directive == FileDirective::PROMPT) {
|
||||
// Section b) of 4.5.3: These PDUs should always be targeted towards the file receiver a.k.a.
|
||||
// the destination handler
|
||||
passToDestHandler();
|
||||
} else if (directive == FileDirective::FINISH or directive == FileDirective::NAK or
|
||||
directive == FileDirective::KEEP_ALIVE) {
|
||||
// Section c) of 4.5.3: These PDUs should always be targeted towards the file sender a.k.a.
|
||||
// the source handler
|
||||
passToSourceHandler();
|
||||
} else if (directive == FileDirective::ACK) {
|
||||
// Section a): Recipient depends of the type of PDU that is being acknowledged. We can simply
|
||||
// extract the PDU type from the raw stream. If it is an EOF PDU, this packet is passed to
|
||||
// the source handler, for a Finished PDU, it is passed to the destination handler.
|
||||
FileDirective ackedDirective;
|
||||
if (not AckPduReader::checkAckedDirectiveField(pduDataField[1], ackedDirective)) {
|
||||
return INVALID_ACK_DIRECTIVE_FIELDS;
|
||||
}
|
||||
if (ackedDirective == FileDirective::EOF_DIRECTIVE) {
|
||||
passToSourceHandler();
|
||||
} else if (ackedDirective == FileDirective::FINISH) {
|
||||
passToDestHandler();
|
||||
}
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
71
src/fsfw/cfdp/handler/CfdpHandler.h
Normal file
71
src/fsfw/cfdp/handler/CfdpHandler.h
Normal file
@ -0,0 +1,71 @@
|
||||
#ifndef FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H
|
||||
#define FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "fsfw/cfdp/handler/DestHandler.h"
|
||||
#include "fsfw/objectmanager/SystemObject.h"
|
||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
|
||||
#include "fsfw/tmtcservices/TmTcMessage.h"
|
||||
|
||||
struct FsfwHandlerParams {
|
||||
FsfwHandlerParams(object_id_t objectId, HasFileSystemIF& vfs, AcceptsTelemetryIF& packetDest,
|
||||
StorageManagerIF& tcStore, StorageManagerIF& tmStore, MessageQueueIF& msgQueue)
|
||||
: objectId(objectId),
|
||||
vfs(vfs),
|
||||
packetDest(packetDest),
|
||||
tcStore(tcStore),
|
||||
tmStore(tmStore),
|
||||
msgQueue(msgQueue) {}
|
||||
object_id_t objectId{};
|
||||
HasFileSystemIF& vfs;
|
||||
AcceptsTelemetryIF& packetDest;
|
||||
StorageManagerIF& tcStore;
|
||||
StorageManagerIF& tmStore;
|
||||
MessageQueueIF& msgQueue;
|
||||
};
|
||||
|
||||
struct CfdpHandlerCfg {
|
||||
CfdpHandlerCfg(cfdp::EntityId localId, cfdp::IndicationCfg indicationCfg,
|
||||
cfdp::UserBase& userHandler, cfdp::FaultHandlerBase& userFaultHandler,
|
||||
cfdp::PacketInfoListBase& packetInfo, cfdp::LostSegmentsListBase& lostSegmentsList,
|
||||
cfdp::RemoteConfigTableIF& remoteCfgProvider)
|
||||
: id(std::move(localId)),
|
||||
indicCfg(indicationCfg),
|
||||
packetInfoList(packetInfo),
|
||||
lostSegmentsList(lostSegmentsList),
|
||||
remoteCfgProvider(remoteCfgProvider),
|
||||
userHandler(userHandler),
|
||||
faultHandler(userFaultHandler) {}
|
||||
|
||||
cfdp::EntityId id;
|
||||
cfdp::IndicationCfg indicCfg;
|
||||
cfdp::PacketInfoListBase& packetInfoList;
|
||||
cfdp::LostSegmentsListBase& lostSegmentsList;
|
||||
cfdp::RemoteConfigTableIF& remoteCfgProvider;
|
||||
cfdp::UserBase& userHandler;
|
||||
cfdp::FaultHandlerBase& faultHandler;
|
||||
};
|
||||
|
||||
class CfdpHandler : public SystemObject, public ExecutableObjectIF, public AcceptsTelecommandsIF {
|
||||
public:
|
||||
explicit CfdpHandler(const FsfwHandlerParams& fsfwParams, const CfdpHandlerCfg& cfdpCfg);
|
||||
|
||||
[[nodiscard]] const char* getName() const override;
|
||||
[[nodiscard]] uint32_t getIdentifier() const override;
|
||||
[[nodiscard]] MessageQueueId_t getRequestQueue() const override;
|
||||
|
||||
ReturnValue_t initialize() override;
|
||||
ReturnValue_t performOperation(uint8_t operationCode) override;
|
||||
|
||||
private:
|
||||
MessageQueueIF& msgQueue;
|
||||
cfdp::DestHandler destHandler;
|
||||
StorageManagerIF* tcStore = nullptr;
|
||||
StorageManagerIF* tmStore = nullptr;
|
||||
|
||||
ReturnValue_t handleCfdpPacket(TmTcMessage& msg);
|
||||
};
|
||||
|
||||
#endif // FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H
|
490
src/fsfw/cfdp/handler/DestHandler.cpp
Normal file
490
src/fsfw/cfdp/handler/DestHandler.cpp
Normal file
@ -0,0 +1,490 @@
|
||||
#include "DestHandler.h"
|
||||
|
||||
#include <etl/crc32.h>
|
||||
|
||||
#include <utility>
|
||||
|
||||
#include "fsfw/FSFW.h"
|
||||
#include "fsfw/cfdp/pdu/EofPduReader.h"
|
||||
#include "fsfw/cfdp/pdu/FileDataReader.h"
|
||||
#include "fsfw/cfdp/pdu/FinishedPduCreator.h"
|
||||
#include "fsfw/cfdp/pdu/PduHeaderReader.h"
|
||||
#include "fsfw/objectmanager.h"
|
||||
#include "fsfw/tmtcservices/TmTcMessage.h"
|
||||
|
||||
using namespace returnvalue;
|
||||
|
||||
cfdp::DestHandler::DestHandler(DestHandlerParams params, FsfwParams fsfwParams)
|
||||
: tlvVec(params.maxTlvsInOnePdu),
|
||||
userTlvVec(params.maxTlvsInOnePdu),
|
||||
dp(std::move(params)),
|
||||
fp(fsfwParams),
|
||||
tp(params.maxFilenameLen) {
|
||||
tp.pduConf.direction = cfdp::Direction::TOWARDS_SENDER;
|
||||
}
|
||||
|
||||
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::performStateMachine() {
|
||||
ReturnValue_t result;
|
||||
uint8_t errorIdx = 0;
|
||||
fsmRes.resetOfIteration();
|
||||
if (fsmRes.step == TransactionStep::IDLE) {
|
||||
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
|
||||
if (infoIter->pduType == PduType::FILE_DIRECTIVE and
|
||||
infoIter->directiveType == FileDirective::METADATA) {
|
||||
result = handleMetadataPdu(*infoIter);
|
||||
checkAndHandleError(result, errorIdx);
|
||||
// Store data was deleted in PDU handler because a store guard is used
|
||||
dp.packetListRef.erase(infoIter++);
|
||||
} else {
|
||||
infoIter++;
|
||||
}
|
||||
}
|
||||
if (fsmRes.step == TransactionStep::IDLE) {
|
||||
// To decrease the already high complexity of the software, all packets arriving before
|
||||
// a metadata PDU are deleted.
|
||||
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
|
||||
fp.tcStore->deleteData(infoIter->storeId);
|
||||
infoIter++;
|
||||
}
|
||||
dp.packetListRef.clear();
|
||||
}
|
||||
|
||||
if (fsmRes.step != TransactionStep::IDLE) {
|
||||
fsmRes.callStatus = CallStatus::CALL_AGAIN;
|
||||
}
|
||||
return updateFsmRes(errorIdx);
|
||||
}
|
||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
|
||||
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
|
||||
for (auto infoIter = dp.packetListRef.begin(); infoIter != dp.packetListRef.end();) {
|
||||
if (infoIter->pduType == PduType::FILE_DATA) {
|
||||
result = handleFileDataPdu(*infoIter);
|
||||
checkAndHandleError(result, errorIdx);
|
||||
// Store data was deleted in PDU handler because a store guard is used
|
||||
dp.packetListRef.erase(infoIter++);
|
||||
} else if (infoIter->pduType == PduType::FILE_DIRECTIVE and
|
||||
infoIter->directiveType == FileDirective::EOF_DIRECTIVE) {
|
||||
// TODO: Support for check timer missing
|
||||
result = handleEofPdu(*infoIter);
|
||||
checkAndHandleError(result, errorIdx);
|
||||
// Store data was deleted in PDU handler because a store guard is used
|
||||
dp.packetListRef.erase(infoIter++);
|
||||
} else {
|
||||
infoIter++;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (fsmRes.step == TransactionStep::TRANSFER_COMPLETION) {
|
||||
result = handleTransferCompletion();
|
||||
checkAndHandleError(result, errorIdx);
|
||||
}
|
||||
if (fsmRes.step == TransactionStep::SENDING_FINISHED_PDU) {
|
||||
result = sendFinishedPdu();
|
||||
checkAndHandleError(result, errorIdx);
|
||||
finish();
|
||||
}
|
||||
return updateFsmRes(errorIdx);
|
||||
}
|
||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
|
||||
// TODO: Will be implemented at a later stage
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "CFDP state machine for acknowledged mode not implemented yet" << std::endl;
|
||||
#endif
|
||||
}
|
||||
return updateFsmRes(errorIdx);
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::passPacket(PacketInfo packet) {
|
||||
if (dp.packetListRef.full()) {
|
||||
return FAILED;
|
||||
}
|
||||
dp.packetListRef.push_back(packet);
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::initialize() {
|
||||
if (fp.tmStore == nullptr) {
|
||||
fp.tmStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TM_STORE);
|
||||
if (fp.tmStore == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (fp.tcStore == nullptr) {
|
||||
fp.tcStore = ObjectManager::instance()->get<StorageManagerIF>(objects::TC_STORE);
|
||||
if (fp.tcStore == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
}
|
||||
|
||||
if (fp.msgQueue == nullptr) {
|
||||
return FAILED;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleMetadataPdu(const PacketInfo& info) {
|
||||
// Process metadata PDU
|
||||
auto constAccessorPair = fp.tcStore->getData(info.storeId);
|
||||
if (constAccessorPair.first != OK) {
|
||||
// TODO: This is not a CFDP error. Event and/or warning?
|
||||
return constAccessorPair.first;
|
||||
}
|
||||
cfdp::StringLv sourceFileName;
|
||||
cfdp::StringLv destFileName;
|
||||
MetadataInfo metadataInfo(tp.fileSize, sourceFileName, destFileName);
|
||||
cfdp::Tlv* tlvArrayAsPtr = tlvVec.data();
|
||||
metadataInfo.setOptionsArray(&tlvArrayAsPtr, std::nullopt, tlvVec.size());
|
||||
MetadataPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(),
|
||||
metadataInfo);
|
||||
ReturnValue_t result = reader.parseData();
|
||||
// TODO: The standard does not really specify what happens if this kind of error happens
|
||||
// I think it might be a good idea to cache some sort of error code, which
|
||||
// is translated into a warning and/or event by an upper layer
|
||||
if (result != OK) {
|
||||
return handleMetadataParseError(result, constAccessorPair.second.data(),
|
||||
constAccessorPair.second.size());
|
||||
}
|
||||
return startTransaction(reader, metadataInfo);
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleFileDataPdu(const cfdp::PacketInfo& info) {
|
||||
// Process file data PDU
|
||||
auto constAccessorPair = fp.tcStore->getData(info.storeId);
|
||||
if (constAccessorPair.first != OK) {
|
||||
// TODO: This is not a CFDP error. Event and/or warning?
|
||||
return constAccessorPair.first;
|
||||
}
|
||||
cfdp::FileSize offset;
|
||||
FileDataInfo fdInfo(offset);
|
||||
FileDataReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), fdInfo);
|
||||
ReturnValue_t result = reader.parseData();
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
size_t fileSegmentLen = 0;
|
||||
const uint8_t* fileData = fdInfo.getFileData(&fileSegmentLen);
|
||||
FileOpParams fileOpParams(tp.destName.data(), fileSegmentLen);
|
||||
fileOpParams.offset = offset.value();
|
||||
if (dp.cfg.indicCfg.fileSegmentRecvIndicRequired) {
|
||||
FileSegmentRecvdParams segParams;
|
||||
segParams.offset = offset.value();
|
||||
segParams.id = tp.transactionId;
|
||||
segParams.length = fileSegmentLen;
|
||||
segParams.recContState = fdInfo.getRecordContinuationState();
|
||||
size_t segmentMetadatLen = 0;
|
||||
auto* segMetadata = fdInfo.getSegmentMetadata(&segmentMetadatLen);
|
||||
segParams.segmentMetadata = {segMetadata, segmentMetadatLen};
|
||||
dp.user.fileSegmentRecvdIndication(segParams);
|
||||
}
|
||||
result = dp.user.vfs.writeToFile(fileOpParams, fileData);
|
||||
if (offset.value() + fileSegmentLen > tp.progress) {
|
||||
tp.progress = offset.value() + fileSegmentLen;
|
||||
}
|
||||
if (result != returnvalue::OK) {
|
||||
// TODO: Proper Error handling
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "File write error" << std::endl;
|
||||
#endif
|
||||
} else {
|
||||
tp.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleEofPdu(const cfdp::PacketInfo& info) {
|
||||
// Process EOF PDU
|
||||
auto constAccessorPair = fp.tcStore->getData(info.storeId);
|
||||
if (constAccessorPair.first != OK) {
|
||||
// TODO: This is not a CFDP error. Event and/or warning?
|
||||
return constAccessorPair.first;
|
||||
}
|
||||
EofInfo eofInfo(nullptr);
|
||||
EofPduReader reader(constAccessorPair.second.data(), constAccessorPair.second.size(), eofInfo);
|
||||
ReturnValue_t result = reader.parseData();
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
// TODO: Error handling
|
||||
if (eofInfo.getConditionCode() == ConditionCode::NO_ERROR) {
|
||||
tp.crc = eofInfo.getChecksum();
|
||||
uint64_t fileSizeFromEof = eofInfo.getFileSize().value();
|
||||
// CFDP 4.6.1.2.9: Declare file size error if progress exceeds file size
|
||||
if (fileSizeFromEof > tp.progress) {
|
||||
// TODO: File size error
|
||||
}
|
||||
tp.fileSize.setFileSize(fileSizeFromEof, std::nullopt);
|
||||
}
|
||||
if (dp.cfg.indicCfg.eofRecvIndicRequired) {
|
||||
dp.user.eofRecvIndication(getTransactionId());
|
||||
}
|
||||
if (fsmRes.step == TransactionStep::RECEIVING_FILE_DATA_PDUS) {
|
||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
|
||||
fsmRes.step = TransactionStep::TRANSFER_COMPLETION;
|
||||
} else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
|
||||
fsmRes.step = TransactionStep::SENDING_ACK_PDU;
|
||||
}
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleMetadataParseError(ReturnValue_t result,
|
||||
const uint8_t* rawData, size_t maxSize) {
|
||||
// TODO: try to extract destination ID for error
|
||||
// TODO: Invalid metadata PDU.
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "Parsing Metadata PDU failed with code " << result << std::endl;
|
||||
#else
|
||||
#endif
|
||||
PduHeaderReader headerReader(rawData, maxSize);
|
||||
result = headerReader.parseData();
|
||||
if (result != OK) {
|
||||
// TODO: Now this really should not happen. Warning or error,
|
||||
// yield or cache appropriate returnvalue
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "Parsing Header failed" << std::endl;
|
||||
#else
|
||||
#endif
|
||||
// TODO: Trigger appropriate event
|
||||
return result;
|
||||
}
|
||||
cfdp::EntityId destId;
|
||||
headerReader.getDestId(destId);
|
||||
RemoteEntityCfg* remoteCfg;
|
||||
if (not dp.remoteCfgTable.getRemoteCfg(destId, &remoteCfg)) {
|
||||
// TODO: No remote config for dest ID. I consider this a configuration error, which is not
|
||||
// covered by the standard.
|
||||
// Warning or error, yield or cache appropriate returnvalue
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "No remote config exists for destination ID" << std::endl;
|
||||
#else
|
||||
#endif
|
||||
// TODO: Trigger appropriate event
|
||||
}
|
||||
// TODO: Appropriate returnvalue?
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::startTransaction(MetadataPduReader& reader, MetadataInfo& info) {
|
||||
if (fsmRes.state != CfdpStates::IDLE) {
|
||||
// According to standard, discard metadata PDU if we are busy
|
||||
return OK;
|
||||
}
|
||||
ReturnValue_t result = OK;
|
||||
fsmRes.step = TransactionStep::TRANSACTION_START;
|
||||
if (reader.getTransmissionMode() == TransmissionMode::UNACKNOWLEDGED) {
|
||||
fsmRes.state = CfdpStates::BUSY_CLASS_1_NACKED;
|
||||
} else if (reader.getTransmissionMode() == TransmissionMode::ACKNOWLEDGED) {
|
||||
fsmRes.state = CfdpStates::BUSY_CLASS_2_ACKED;
|
||||
}
|
||||
tp.checksumType = info.getChecksumType();
|
||||
tp.closureRequested = info.isClosureRequested();
|
||||
size_t sourceNameSize = 0;
|
||||
const uint8_t* sourceNamePtr = info.getSourceFileName().getValue(&sourceNameSize);
|
||||
if (sourceNameSize > tp.sourceName.size()) {
|
||||
// TODO: Warning, event etc.
|
||||
return FAILED;
|
||||
}
|
||||
std::memcpy(tp.sourceName.data(), sourceNamePtr, sourceNameSize);
|
||||
tp.sourceName[sourceNameSize] = '\0';
|
||||
size_t destNameSize = 0;
|
||||
const uint8_t* destNamePtr = info.getDestFileName().getValue(&destNameSize);
|
||||
if (destNameSize > tp.destName.size()) {
|
||||
// TODO: Warning, event etc.
|
||||
return FAILED;
|
||||
}
|
||||
std::memcpy(tp.destName.data(), destNamePtr, destNameSize);
|
||||
tp.destName[destNameSize] = '\0';
|
||||
reader.fillConfig(tp.pduConf);
|
||||
tp.pduConf.direction = Direction::TOWARDS_SENDER;
|
||||
tp.transactionId.entityId = tp.pduConf.sourceId;
|
||||
tp.transactionId.seqNum = tp.pduConf.seqNum;
|
||||
if (not dp.remoteCfgTable.getRemoteCfg(tp.pduConf.sourceId, &tp.remoteCfg)) {
|
||||
// TODO: Warning, event etc.
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "cfdp::DestHandler" << __func__
|
||||
<< ": No remote configuration found for destination ID "
|
||||
<< tp.pduConf.sourceId.getValue() << std::endl;
|
||||
#endif
|
||||
return FAILED;
|
||||
}
|
||||
// If both dest name size and source name size are 0, we are dealing with a metadata only PDU,
|
||||
// so there is no need to create a file or truncate an existing file
|
||||
if (destNameSize > 0 and sourceNameSize > 0) {
|
||||
FilesystemParams fparams(tp.destName.data());
|
||||
// TODO: Filesystem errors?
|
||||
if (dp.user.vfs.fileExists(fparams)) {
|
||||
dp.user.vfs.truncateFile(fparams);
|
||||
} else {
|
||||
result = dp.user.vfs.createFile(fparams);
|
||||
if (result != OK) {
|
||||
// TODO: Handle FS error. This is probably a case for the filestore rejection mechanism of
|
||||
// CFDP.
|
||||
// In any case, it does not really make sense to continue here
|
||||
}
|
||||
}
|
||||
}
|
||||
fsmRes.step = TransactionStep::RECEIVING_FILE_DATA_PDUS;
|
||||
MetadataRecvdParams params(tp.transactionId, tp.pduConf.sourceId);
|
||||
params.fileSize = tp.fileSize.getSize();
|
||||
params.destFileName = tp.destName.data();
|
||||
params.sourceFileName = tp.sourceName.data();
|
||||
params.msgsToUserArray = dynamic_cast<MessageToUserTlv*>(userTlvVec.data());
|
||||
params.msgsToUserLen = info.getOptionsLen();
|
||||
dp.user.metadataRecvdIndication(params);
|
||||
return result;
|
||||
}
|
||||
|
||||
cfdp::CfdpStates cfdp::DestHandler::getCfdpState() const { return fsmRes.state; }
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::handleTransferCompletion() {
|
||||
ReturnValue_t result;
|
||||
if (tp.checksumType != ChecksumType::NULL_CHECKSUM) {
|
||||
result = checksumVerification();
|
||||
if (result != OK) {
|
||||
// TODO: Warning / error handling?
|
||||
}
|
||||
} else {
|
||||
tp.conditionCode = ConditionCode::NO_ERROR;
|
||||
}
|
||||
result = noticeOfCompletion();
|
||||
if (result != OK) {
|
||||
}
|
||||
if (fsmRes.state == CfdpStates::BUSY_CLASS_1_NACKED) {
|
||||
if (tp.closureRequested) {
|
||||
fsmRes.step = TransactionStep::SENDING_FINISHED_PDU;
|
||||
} else {
|
||||
finish();
|
||||
}
|
||||
} else if (fsmRes.state == CfdpStates::BUSY_CLASS_2_ACKED) {
|
||||
fsmRes.step = TransactionStep::SENDING_FINISHED_PDU;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
void cfdp::DestHandler::finish() {
|
||||
tp.reset();
|
||||
dp.packetListRef.clear();
|
||||
fsmRes.state = CfdpStates::IDLE;
|
||||
fsmRes.step = TransactionStep::IDLE;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::checksumVerification() {
|
||||
std::array<uint8_t, 1024> buf{};
|
||||
// TODO: Checksum verification and notice of completion
|
||||
etl::crc32 crcCalc;
|
||||
uint64_t currentOffset = 0;
|
||||
FileOpParams params(tp.destName.data(), tp.fileSize.value());
|
||||
while (currentOffset < tp.fileSize.value()) {
|
||||
uint64_t readLen;
|
||||
if (currentOffset + buf.size() > tp.fileSize.value()) {
|
||||
readLen = tp.fileSize.value() - currentOffset;
|
||||
} else {
|
||||
readLen = buf.size();
|
||||
}
|
||||
if (readLen > 0) {
|
||||
params.offset = currentOffset;
|
||||
params.size = readLen;
|
||||
auto result = dp.user.vfs.readFromFile(params, buf.data(), buf.size());
|
||||
if (result != OK) {
|
||||
// TODO: I think this is a case for a filestore rejection, but it might sense to print
|
||||
// a warning or trigger an event because this should generally not happen
|
||||
return FAILED;
|
||||
}
|
||||
crcCalc.add(buf.begin(), buf.begin() + readLen);
|
||||
}
|
||||
currentOffset += readLen;
|
||||
}
|
||||
|
||||
uint32_t value = crcCalc.value();
|
||||
if (value == tp.crc) {
|
||||
tp.conditionCode = ConditionCode::NO_ERROR;
|
||||
tp.deliveryCode = FileDeliveryCode::DATA_COMPLETE;
|
||||
} else {
|
||||
// TODO: Proper error handling
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "CRC check for file " << tp.destName.data() << " failed" << std::endl;
|
||||
#endif
|
||||
tp.conditionCode = ConditionCode::FILE_CHECKSUM_FAILURE;
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::noticeOfCompletion() {
|
||||
if (dp.cfg.indicCfg.transactionFinishedIndicRequired) {
|
||||
TransactionFinishedParams params(tp.transactionId, tp.conditionCode, tp.deliveryCode,
|
||||
tp.deliveryStatus);
|
||||
dp.user.transactionFinishedIndication(params);
|
||||
}
|
||||
return OK;
|
||||
}
|
||||
|
||||
ReturnValue_t cfdp::DestHandler::sendFinishedPdu() {
|
||||
FinishedInfo info(tp.conditionCode, tp.deliveryCode, tp.deliveryStatus);
|
||||
FinishPduCreator finishedPdu(tp.pduConf, info);
|
||||
store_address_t storeId;
|
||||
uint8_t* dataPtr = nullptr;
|
||||
ReturnValue_t result =
|
||||
fp.tmStore->getFreeElement(&storeId, finishedPdu.getSerializedSize(), &dataPtr);
|
||||
if (result != OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "cfdp::DestHandler:sendFinishedPdu: Getting store slot failed" << std::endl;
|
||||
#endif
|
||||
fp.eventReporter->forwardEvent(events::STORE_ERROR, result, 0);
|
||||
return result;
|
||||
}
|
||||
size_t serLen = 0;
|
||||
result = finishedPdu.serialize(dataPtr, serLen, finishedPdu.getSerializedSize());
|
||||
if (result != OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "cfdp::DestHandler::sendFinishedPdu: Serializing Finished PDU failed"
|
||||
<< std::endl;
|
||||
#endif
|
||||
fp.eventReporter->forwardEvent(events::SERIALIZATION_ERROR, result, 0);
|
||||
return result;
|
||||
}
|
||||
TmTcMessage msg(storeId);
|
||||
result = fp.msgQueue->sendMessage(fp.packetDest.getReportReceptionQueue(), &msg);
|
||||
if (result != OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "cfdp::DestHandler::sendFinishedPdu: Sending PDU failed" << std::endl;
|
||||
#endif
|
||||
fp.eventReporter->forwardEvent(events::MSG_QUEUE_ERROR, result, 0);
|
||||
return result;
|
||||
}
|
||||
fsmRes.packetsSent++;
|
||||
return OK;
|
||||
}
|
||||
|
||||
cfdp::DestHandler::TransactionStep cfdp::DestHandler::getTransactionStep() const {
|
||||
return fsmRes.step;
|
||||
}
|
||||
|
||||
const cfdp::DestHandler::FsmResult& cfdp::DestHandler::updateFsmRes(uint8_t errors) {
|
||||
fsmRes.errors = errors;
|
||||
fsmRes.result = OK;
|
||||
if (fsmRes.errors > 0) {
|
||||
fsmRes.result = FAILED;
|
||||
}
|
||||
return fsmRes;
|
||||
}
|
||||
|
||||
const cfdp::TransactionId& cfdp::DestHandler::getTransactionId() const { return tp.transactionId; }
|
||||
|
||||
void cfdp::DestHandler::checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx) {
|
||||
if (result != OK and errorIdx < 3) {
|
||||
fsmRes.errorCodes[errorIdx] = result;
|
||||
errorIdx++;
|
||||
}
|
||||
}
|
||||
|
||||
void cfdp::DestHandler::setMsgQueue(MessageQueueIF& queue) { fp.msgQueue = &queue; }
|
||||
|
||||
void cfdp::DestHandler::setEventReporter(EventReportingProxyIF& reporter) {
|
||||
fp.eventReporter = &reporter;
|
||||
}
|
||||
|
||||
const cfdp::DestHandlerParams& cfdp::DestHandler::getDestHandlerParams() const { return dp; }
|
||||
|
||||
StorageManagerIF* cfdp::DestHandler::getTmStore() const { return fp.tmStore; }
|
||||
StorageManagerIF* cfdp::DestHandler::getTcStore() const { return fp.tcStore; }
|
202
src/fsfw/cfdp/handler/DestHandler.h
Normal file
202
src/fsfw/cfdp/handler/DestHandler.h
Normal file
@ -0,0 +1,202 @@
|
||||
#ifndef FSFW_CFDP_CFDPDESTHANDLER_H
|
||||
#define FSFW_CFDP_CFDPDESTHANDLER_H
|
||||
|
||||
#include <etl/list.h>
|
||||
#include <etl/set.h>
|
||||
|
||||
#include <optional>
|
||||
#include <utility>
|
||||
|
||||
#include "RemoteConfigTableIF.h"
|
||||
#include "UserBase.h"
|
||||
#include "defs.h"
|
||||
#include "fsfw/cfdp/handler/mib.h"
|
||||
#include "fsfw/cfdp/pdu/MetadataPduReader.h"
|
||||
#include "fsfw/cfdp/pdu/PduConfig.h"
|
||||
#include "fsfw/container/DynamicFIFO.h"
|
||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
||||
#include "fsfw/storagemanager/storeAddress.h"
|
||||
#include "fsfw/tmtcservices/AcceptsTelemetryIF.h"
|
||||
|
||||
namespace cfdp {
|
||||
|
||||
struct PacketInfo {
|
||||
PacketInfo(PduType type, store_address_t storeId,
|
||||
std::optional<FileDirective> directive = std::nullopt)
|
||||
: pduType(type), directiveType(directive), storeId(storeId) {}
|
||||
|
||||
PduType pduType = PduType::FILE_DATA;
|
||||
std::optional<FileDirective> directiveType = FileDirective::INVALID_DIRECTIVE;
|
||||
store_address_t storeId = store_address_t::invalid();
|
||||
PacketInfo() = default;
|
||||
};
|
||||
|
||||
template <size_t SIZE>
|
||||
using LostSegmentsList = etl::set<etl::pair<uint64_t, uint64_t>, SIZE>;
|
||||
template <size_t SIZE>
|
||||
using PacketInfoList = etl::list<PacketInfo, SIZE>;
|
||||
using LostSegmentsListBase = etl::iset<etl::pair<uint64_t, uint64_t>>;
|
||||
using PacketInfoListBase = etl::ilist<PacketInfo>;
|
||||
|
||||
struct DestHandlerParams {
|
||||
DestHandlerParams(LocalEntityCfg cfg, UserBase& user, RemoteConfigTableIF& remoteCfgTable,
|
||||
PacketInfoListBase& packetList,
|
||||
// TODO: This container can potentially take tons of space. For a better
|
||||
// memory efficient implementation, an additional abstraction could be
|
||||
// be used so users can use uint32_t as the pair type
|
||||
LostSegmentsListBase& lostSegmentsContainer)
|
||||
: cfg(std::move(cfg)),
|
||||
user(user),
|
||||
remoteCfgTable(remoteCfgTable),
|
||||
packetListRef(packetList),
|
||||
lostSegmentsContainer(lostSegmentsContainer) {}
|
||||
|
||||
LocalEntityCfg cfg;
|
||||
UserBase& user;
|
||||
RemoteConfigTableIF& remoteCfgTable;
|
||||
|
||||
PacketInfoListBase& packetListRef;
|
||||
LostSegmentsListBase& lostSegmentsContainer;
|
||||
uint8_t maxTlvsInOnePdu = 10;
|
||||
size_t maxFilenameLen = 255;
|
||||
};
|
||||
|
||||
struct FsfwParams {
|
||||
FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue,
|
||||
EventReportingProxyIF* eventReporter, StorageManagerIF& tcStore,
|
||||
StorageManagerIF& tmStore)
|
||||
: FsfwParams(packetDest, msgQueue, eventReporter) {
|
||||
this->tcStore = &tcStore;
|
||||
this->tmStore = &tmStore;
|
||||
}
|
||||
|
||||
FsfwParams(AcceptsTelemetryIF& packetDest, MessageQueueIF* msgQueue,
|
||||
EventReportingProxyIF* eventReporter)
|
||||
: packetDest(packetDest), msgQueue(msgQueue), eventReporter(eventReporter) {}
|
||||
AcceptsTelemetryIF& packetDest;
|
||||
MessageQueueIF* msgQueue;
|
||||
EventReportingProxyIF* eventReporter = nullptr;
|
||||
StorageManagerIF* tcStore = nullptr;
|
||||
StorageManagerIF* tmStore = nullptr;
|
||||
};
|
||||
|
||||
enum class CallStatus { DONE, CALL_AFTER_DELAY, CALL_AGAIN };
|
||||
|
||||
class DestHandler {
|
||||
public:
|
||||
enum class TransactionStep {
|
||||
IDLE = 0,
|
||||
TRANSACTION_START = 1,
|
||||
RECEIVING_FILE_DATA_PDUS = 2,
|
||||
SENDING_ACK_PDU = 3,
|
||||
TRANSFER_COMPLETION = 4,
|
||||
SENDING_FINISHED_PDU = 5
|
||||
};
|
||||
|
||||
struct FsmResult {
|
||||
public:
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
CallStatus callStatus = CallStatus::CALL_AFTER_DELAY;
|
||||
TransactionStep step = TransactionStep::IDLE;
|
||||
CfdpStates state = CfdpStates::IDLE;
|
||||
uint32_t packetsSent = 0;
|
||||
uint8_t errors = 0;
|
||||
std::array<ReturnValue_t, 3> errorCodes = {};
|
||||
void resetOfIteration() {
|
||||
result = returnvalue::OK;
|
||||
callStatus = CallStatus::CALL_AFTER_DELAY;
|
||||
packetsSent = 0;
|
||||
errors = 0;
|
||||
errorCodes.fill(returnvalue::OK);
|
||||
}
|
||||
};
|
||||
/**
|
||||
* Will be returned if it is advisable to call the state machine operation call again
|
||||
*/
|
||||
ReturnValue_t PARTIAL_SUCCESS = returnvalue::makeCode(0, 2);
|
||||
ReturnValue_t FAILURE = returnvalue::makeCode(0, 3);
|
||||
explicit DestHandler(DestHandlerParams handlerParams, FsfwParams fsfwParams);
|
||||
|
||||
/**
|
||||
*
|
||||
* @return
|
||||
* - @c returnvalue::OK State machine OK for this execution cycle
|
||||
* - @c CALL_FSM_AGAIN State machine should be called again.
|
||||
*/
|
||||
const FsmResult& performStateMachine();
|
||||
void setMsgQueue(MessageQueueIF& queue);
|
||||
void setEventReporter(EventReportingProxyIF& reporter);
|
||||
|
||||
ReturnValue_t passPacket(PacketInfo packet);
|
||||
|
||||
ReturnValue_t initialize();
|
||||
|
||||
[[nodiscard]] CfdpStates getCfdpState() const;
|
||||
[[nodiscard]] TransactionStep getTransactionStep() const;
|
||||
[[nodiscard]] const TransactionId& getTransactionId() const;
|
||||
[[nodiscard]] const DestHandlerParams& getDestHandlerParams() const;
|
||||
[[nodiscard]] StorageManagerIF* getTcStore() const;
|
||||
[[nodiscard]] StorageManagerIF* getTmStore() const;
|
||||
|
||||
private:
|
||||
struct TransactionParams {
|
||||
// Initialize char vectors with length + 1 for 0 termination
|
||||
explicit TransactionParams(size_t maxFileNameLen)
|
||||
: sourceName(maxFileNameLen + 1), destName(maxFileNameLen + 1) {}
|
||||
|
||||
void reset() {
|
||||
pduConf = PduConfig();
|
||||
transactionId = TransactionId();
|
||||
std::fill(sourceName.begin(), sourceName.end(), '\0');
|
||||
std::fill(destName.begin(), destName.end(), '\0');
|
||||
fileSize.setFileSize(0, false);
|
||||
conditionCode = ConditionCode::NO_ERROR;
|
||||
deliveryCode = FileDeliveryCode::DATA_INCOMPLETE;
|
||||
deliveryStatus = FileDeliveryStatus::DISCARDED_DELIBERATELY;
|
||||
crc = 0;
|
||||
progress = 0;
|
||||
remoteCfg = nullptr;
|
||||
closureRequested = false;
|
||||
checksumType = ChecksumType::NULL_CHECKSUM;
|
||||
}
|
||||
|
||||
ChecksumType checksumType = ChecksumType::NULL_CHECKSUM;
|
||||
bool closureRequested = false;
|
||||
std::vector<char> sourceName;
|
||||
std::vector<char> destName;
|
||||
cfdp::FileSize fileSize;
|
||||
TransactionId transactionId;
|
||||
PduConfig pduConf;
|
||||
ConditionCode conditionCode = ConditionCode::NO_ERROR;
|
||||
FileDeliveryCode deliveryCode = FileDeliveryCode::DATA_INCOMPLETE;
|
||||
FileDeliveryStatus deliveryStatus = FileDeliveryStatus::DISCARDED_DELIBERATELY;
|
||||
uint32_t crc = 0;
|
||||
uint64_t progress = 0;
|
||||
RemoteEntityCfg* remoteCfg = nullptr;
|
||||
};
|
||||
|
||||
std::vector<cfdp::Tlv> tlvVec;
|
||||
std::vector<cfdp::Tlv> userTlvVec;
|
||||
DestHandlerParams dp;
|
||||
FsfwParams fp;
|
||||
TransactionParams tp;
|
||||
FsmResult fsmRes;
|
||||
|
||||
ReturnValue_t startTransaction(MetadataPduReader& reader, MetadataInfo& info);
|
||||
ReturnValue_t handleMetadataPdu(const PacketInfo& info);
|
||||
ReturnValue_t handleFileDataPdu(const PacketInfo& info);
|
||||
ReturnValue_t handleEofPdu(const PacketInfo& info);
|
||||
ReturnValue_t handleMetadataParseError(ReturnValue_t result, const uint8_t* rawData,
|
||||
size_t maxSize);
|
||||
ReturnValue_t handleTransferCompletion();
|
||||
ReturnValue_t sendFinishedPdu();
|
||||
ReturnValue_t noticeOfCompletion();
|
||||
ReturnValue_t checksumVerification();
|
||||
const FsmResult& updateFsmRes(uint8_t errors);
|
||||
void checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx);
|
||||
void finish();
|
||||
};
|
||||
|
||||
} // namespace cfdp
|
||||
|
||||
#endif // FSFW_CFDP_CFDPDESTHANDLER_H
|
1
src/fsfw/cfdp/handler/SourceHandler.cpp
Normal file
1
src/fsfw/cfdp/handler/SourceHandler.cpp
Normal file
@ -0,0 +1 @@
|
||||
#include "SourceHandler.h"
|
6
src/fsfw/cfdp/handler/SourceHandler.h
Normal file
6
src/fsfw/cfdp/handler/SourceHandler.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef FSFW_CFDP_CFDPSOURCEHANDLER_H
|
||||
#define FSFW_CFDP_CFDPSOURCEHANDLER_H
|
||||
|
||||
class SourceHandler {};
|
||||
|
||||
#endif // FSFW_CFDP_CFDPSOURCEHANDLER_H
|
@ -5,5 +5,15 @@ namespace cfdp {
|
||||
|
||||
enum class CfdpStates { IDLE, BUSY_CLASS_1_NACKED, BUSY_CLASS_2_ACKED, SUSPENDED };
|
||||
|
||||
}
|
||||
static constexpr uint8_t SSID = SUBSYSTEM_ID::CFDP;
|
||||
|
||||
namespace events {
|
||||
|
||||
static constexpr Event STORE_ERROR = event::makeEvent(SSID, 0, severity::LOW);
|
||||
static constexpr Event MSG_QUEUE_ERROR = event::makeEvent(SSID, 1, severity::LOW);
|
||||
static constexpr Event SERIALIZATION_ERROR = event::makeEvent(SSID, 2, severity::LOW);
|
||||
|
||||
} // namespace events
|
||||
|
||||
} // namespace cfdp
|
||||
#endif // FSFW_CFDP_HANDLER_DEFS_H
|
||||
|
@ -12,6 +12,7 @@ template <typename T, size_t MAX_SIZE, typename count_t = uint8_t>
|
||||
class FixedArrayList : public ArrayList<T, count_t> {
|
||||
static_assert(MAX_SIZE <= std::numeric_limits<count_t>::max(),
|
||||
"count_t is not large enough to hold MAX_SIZE");
|
||||
static_assert(MAX_SIZE > 0, "MAX_SIZE is 0");
|
||||
|
||||
private:
|
||||
T data[MAX_SIZE];
|
||||
|
@ -4,48 +4,31 @@
|
||||
#include "fsfw/ipc/QueueFactory.h"
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
#include "fsfw/subsystem/SubsystemBase.h"
|
||||
#include "fsfw/subsystem/helper.h"
|
||||
|
||||
ControllerBase::ControllerBase(object_id_t setObjectId, object_id_t parentId,
|
||||
size_t commandQueueDepth)
|
||||
ControllerBase::ControllerBase(object_id_t setObjectId, size_t commandQueueDepth)
|
||||
: SystemObject(setObjectId),
|
||||
parentId(parentId),
|
||||
mode(MODE_OFF),
|
||||
submode(SUBMODE_NONE),
|
||||
modeHelper(this),
|
||||
healthHelper(this, setObjectId) {
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(commandQueueDepth);
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
commandQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
}
|
||||
|
||||
ControllerBase::~ControllerBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
||||
|
||||
ReturnValue_t ControllerBase::initialize() {
|
||||
ReturnValue_t result = SystemObject::initialize();
|
||||
ReturnValue_t result = modeHelper.initialize();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
MessageQueueId_t parentQueue = 0;
|
||||
if (parentId != objects::NO_OBJECT) {
|
||||
auto* parent = ObjectManager::instance()->get<SubsystemBase>(parentId);
|
||||
if (parent == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
parentQueue = parent->getCommandQueue();
|
||||
|
||||
parent->registerChild(getObjectId());
|
||||
}
|
||||
|
||||
result = healthHelper.initialize(parentQueue);
|
||||
result = healthHelper.initialize();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = modeHelper.initialize(parentQueue);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return returnvalue::OK;
|
||||
return SystemObject::initialize();
|
||||
}
|
||||
|
||||
MessageQueueId_t ControllerBase::getCommandQueue() const { return commandQueue->getId(); }
|
||||
@ -118,3 +101,13 @@ void ControllerBase::setTaskIF(PeriodicTaskIF* task_) { executingTask = task_; }
|
||||
void ControllerBase::changeHK(Mode_t mode_, Submode_t submode_, bool enable) {}
|
||||
|
||||
ReturnValue_t ControllerBase::initializeAfterTaskCreation() { return returnvalue::OK; }
|
||||
|
||||
const HasHealthIF* ControllerBase::getOptHealthIF() const { return this; }
|
||||
|
||||
const HasModesIF& ControllerBase::getModeIF() const { return *this; }
|
||||
|
||||
ModeTreeChildIF& ControllerBase::getModeTreeChildIF() { return *this; }
|
||||
|
||||
ReturnValue_t ControllerBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
|
||||
return modetree::connectModeTreeParent(parent, *this, &healthHelper, modeHelper);
|
||||
}
|
||||
|
@ -6,6 +6,9 @@
|
||||
#include "fsfw/modes/HasModesIF.h"
|
||||
#include "fsfw/modes/ModeHelper.h"
|
||||
#include "fsfw/objectmanager/SystemObject.h"
|
||||
#include "fsfw/subsystem/HasModeTreeChildrenIF.h"
|
||||
#include "fsfw/subsystem/ModeTreeChildIF.h"
|
||||
#include "fsfw/subsystem/ModeTreeConnectionIF.h"
|
||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||
#include "fsfw/tasks/PeriodicTaskIF.h"
|
||||
|
||||
@ -18,13 +21,18 @@
|
||||
class ControllerBase : public HasModesIF,
|
||||
public HasHealthIF,
|
||||
public ExecutableObjectIF,
|
||||
public ModeTreeChildIF,
|
||||
public ModeTreeConnectionIF,
|
||||
public SystemObject {
|
||||
public:
|
||||
static const Mode_t MODE_NORMAL = 2;
|
||||
|
||||
ControllerBase(object_id_t setObjectId, object_id_t parentId, size_t commandQueueDepth = 3);
|
||||
ControllerBase(object_id_t setObjectId, size_t commandQueueDepth = 3);
|
||||
~ControllerBase() override;
|
||||
|
||||
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF &parent) override;
|
||||
ModeTreeChildIF &getModeTreeChildIF() override;
|
||||
|
||||
/** SystemObject override */
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
@ -38,6 +46,8 @@ class ControllerBase : public HasModesIF,
|
||||
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
void setTaskIF(PeriodicTaskIF *task) override;
|
||||
ReturnValue_t initializeAfterTaskCreation() override;
|
||||
const HasHealthIF *getOptHealthIF() const override;
|
||||
const HasModesIF &getModeIF() const override;
|
||||
|
||||
protected:
|
||||
/**
|
||||
@ -56,8 +66,6 @@ class ControllerBase : public HasModesIF,
|
||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t *msToReachTheMode) override = 0;
|
||||
|
||||
const object_id_t parentId;
|
||||
|
||||
Mode_t mode;
|
||||
|
||||
Submode_t submode;
|
||||
|
@ -1,8 +1,7 @@
|
||||
#include "fsfw/controller/ExtendedControllerBase.h"
|
||||
|
||||
ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId, object_id_t parentId,
|
||||
size_t commandQueueDepth)
|
||||
: ControllerBase(objectId, parentId, commandQueueDepth),
|
||||
ExtendedControllerBase::ExtendedControllerBase(object_id_t objectId, size_t commandQueueDepth)
|
||||
: ControllerBase(objectId, commandQueueDepth),
|
||||
poolManager(this, commandQueue),
|
||||
actionHelper(this, commandQueue) {}
|
||||
|
||||
|
@ -17,7 +17,7 @@ class ExtendedControllerBase : public ControllerBase,
|
||||
public HasActionsIF,
|
||||
public HasLocalDataPoolIF {
|
||||
public:
|
||||
ExtendedControllerBase(object_id_t objectId, object_id_t parentId, size_t commandQueueDepth = 3);
|
||||
ExtendedControllerBase(object_id_t objectId, size_t commandQueueDepth = 3);
|
||||
~ExtendedControllerBase() override;
|
||||
|
||||
/* SystemObjectIF overrides */
|
||||
|
@ -570,6 +570,10 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage(CommandMessage* me
|
||||
|
||||
CommandMessage reply;
|
||||
if (result != returnvalue::OK) {
|
||||
if (result == WRONG_HK_PACKET_TYPE) {
|
||||
printWarningOrError(sif::OutputTypes::OUT_WARNING, "handleHousekeepingMessage",
|
||||
WRONG_HK_PACKET_TYPE);
|
||||
}
|
||||
HousekeepingMessage::setHkRequestFailureReply(&reply, sid, result);
|
||||
} else {
|
||||
HousekeepingMessage::setHkRequestSuccessReply(&reply, sid);
|
||||
@ -825,6 +829,8 @@ void LocalDataPoolManager::printWarningOrError(sif::OutputTypes outputType,
|
||||
errorPrint = "Dataset not found";
|
||||
} else if (error == POOLOBJECT_NOT_FOUND) {
|
||||
errorPrint = "Pool Object not found";
|
||||
} else if (error == WRONG_HK_PACKET_TYPE) {
|
||||
errorPrint = "Wrong Packet Type";
|
||||
} else if (error == returnvalue::FAILED) {
|
||||
if (outputType == sif::OutputTypes::OUT_WARNING) {
|
||||
errorPrint = "Generic Warning";
|
||||
|
@ -162,6 +162,7 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
|
||||
object_id_t getCreatorObjectId();
|
||||
|
||||
bool getReportingEnabled() const;
|
||||
void setReportingEnabled(bool enabled);
|
||||
|
||||
/**
|
||||
* Returns the current periodic HK generation interval this set
|
||||
@ -189,7 +190,6 @@ class LocalPoolDataSetBase : public PoolDataSetBase, public MarkChangedIF {
|
||||
* Used for periodic generation.
|
||||
*/
|
||||
bool reportingEnabled = false;
|
||||
void setReportingEnabled(bool enabled);
|
||||
|
||||
void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval,
|
||||
uint8_t nonDiagIntervalFactor = 5);
|
||||
|
@ -1,7 +1,7 @@
|
||||
#include "fsfw/devicehandlers/AssemblyBase.h"
|
||||
|
||||
AssemblyBase::AssemblyBase(object_id_t objectId, object_id_t parentId, uint16_t commandQueueDepth)
|
||||
: SubsystemBase(objectId, parentId, MODE_OFF, commandQueueDepth),
|
||||
AssemblyBase::AssemblyBase(object_id_t objectId, uint16_t commandQueueDepth)
|
||||
: SubsystemBase(objectId, MODE_OFF, commandQueueDepth),
|
||||
internalState(STATE_NONE),
|
||||
recoveryState(RECOVERY_IDLE),
|
||||
recoveringDevice(childrenMap.end()),
|
||||
@ -26,11 +26,7 @@ void AssemblyBase::performChildOperation() {
|
||||
|
||||
void AssemblyBase::startTransition(Mode_t mode, Submode_t submode) {
|
||||
doStartTransition(mode, submode);
|
||||
if (modeHelper.isForced()) {
|
||||
triggerEvent(FORCING_MODE, mode, submode);
|
||||
} else {
|
||||
triggerEvent(CHANGING_MODE, mode, submode);
|
||||
}
|
||||
triggerModeHelperEvents(mode, submode);
|
||||
}
|
||||
|
||||
void AssemblyBase::doStartTransition(Mode_t mode, Submode_t submode) {
|
||||
@ -77,9 +73,10 @@ bool AssemblyBase::handleChildrenChangedHealth() {
|
||||
}
|
||||
HealthState healthState = healthHelper.healthTable->getHealth(iter->first);
|
||||
if (healthState == HasHealthIF::NEEDS_RECOVERY) {
|
||||
triggerEvent(TRYING_RECOVERY);
|
||||
triggerEvent(TRYING_RECOVERY, iter->first, 0);
|
||||
recoveryState = RECOVERY_STARTED;
|
||||
recoveringDevice = iter;
|
||||
// The user needs to take care of commanding the children off in commandChildren
|
||||
doStartTransition(targetMode, targetSubmode);
|
||||
} else {
|
||||
triggerEvent(CHILD_CHANGED_HEALTH);
|
||||
@ -228,6 +225,9 @@ ReturnValue_t AssemblyBase::handleHealthReply(CommandMessage* message) {
|
||||
bool AssemblyBase::checkAndHandleRecovery() {
|
||||
switch (recoveryState) {
|
||||
case RECOVERY_STARTED:
|
||||
// The recovery was already start in #handleChildrenChangedHealth and we just need
|
||||
// to wait for an off time period.
|
||||
// TODO: make time period configurable
|
||||
recoveryState = RECOVERY_WAIT;
|
||||
recoveryOffTimer.resetTimer();
|
||||
return true;
|
||||
@ -266,3 +266,11 @@ void AssemblyBase::overwriteDeviceHealth(object_id_t objectId, HasHealthIF::Heal
|
||||
modeHelper.setForced(true);
|
||||
sendHealthCommand(childrenMap[objectId].commandQueue, EXTERNAL_CONTROL);
|
||||
}
|
||||
|
||||
void AssemblyBase::triggerModeHelperEvents(Mode_t mode, Submode_t submode) {
|
||||
if (modeHelper.isForced()) {
|
||||
triggerEvent(FORCING_MODE, mode, submode);
|
||||
} else {
|
||||
triggerEvent(CHANGING_MODE, mode, submode);
|
||||
}
|
||||
}
|
||||
|
@ -12,7 +12,8 @@
|
||||
* Documentation: Dissertation Baetz p.156, 157.
|
||||
*
|
||||
* This class reduces the complexity of controller components which would
|
||||
* otherwise be needed for the handling of redundant devices.
|
||||
* otherwise be needed for the handling of redundant devices. However, it can also be used to
|
||||
* manage the mode keeping and recovery of non-redundant devices
|
||||
*
|
||||
* The template class monitors mode and health state of its children
|
||||
* and checks availability of devices on every detected change.
|
||||
@ -26,11 +27,9 @@
|
||||
*
|
||||
* Important:
|
||||
*
|
||||
* The implementation must call registerChild(object_id_t child)
|
||||
* for all commanded children during initialization.
|
||||
* The implementation must call #registerChild for all commanded children during initialization.
|
||||
* The implementation must call the initialization function of the base class.
|
||||
* (This will call the function in SubsystemBase)
|
||||
*
|
||||
*/
|
||||
class AssemblyBase : public SubsystemBase {
|
||||
public:
|
||||
@ -42,14 +41,15 @@ class AssemblyBase : public SubsystemBase {
|
||||
static const ReturnValue_t NEED_TO_CHANGE_HEALTH = MAKE_RETURN_CODE(0x05);
|
||||
static const ReturnValue_t NOT_ENOUGH_CHILDREN_IN_CORRECT_STATE = MAKE_RETURN_CODE(0xa1);
|
||||
|
||||
AssemblyBase(object_id_t objectId, object_id_t parentId, uint16_t commandQueueDepth = 8);
|
||||
AssemblyBase(object_id_t objectId, uint16_t commandQueueDepth = 8);
|
||||
virtual ~AssemblyBase();
|
||||
|
||||
protected:
|
||||
/**
|
||||
* Command children to reach [mode,submode] combination
|
||||
* Can be done by setting #commandsOutstanding correctly,
|
||||
* or using executeTable()
|
||||
* Command children to reach [mode,submode] combination. Can be done by setting
|
||||
* #commandsOutstanding correctly, or using #executeTable. In case of an FDIR recovery,
|
||||
* the user needs to ensure that the target devices are healthy. If a device is not healthy,
|
||||
* a recovery might be on-going and the device needs to be commanded to off first.
|
||||
* @param mode
|
||||
* @param submode
|
||||
* @return
|
||||
@ -120,8 +120,19 @@ class AssemblyBase : public SubsystemBase {
|
||||
|
||||
virtual ReturnValue_t handleHealthReply(CommandMessage *message);
|
||||
|
||||
virtual void performChildOperation();
|
||||
/**
|
||||
* @brief Default periodic handler
|
||||
* @details
|
||||
* This is the default periodic handler which will be called by the SubsystemBase
|
||||
* performOperation. It performs the child transitions or reacts to changed health/mode states
|
||||
* of children objects
|
||||
*/
|
||||
virtual void performChildOperation() override;
|
||||
|
||||
/**
|
||||
* This function handles changed mode or health states of children
|
||||
* @return
|
||||
*/
|
||||
bool handleChildrenChanged();
|
||||
|
||||
/**
|
||||
@ -134,12 +145,37 @@ class AssemblyBase : public SubsystemBase {
|
||||
|
||||
bool handleChildrenChangedHealth();
|
||||
|
||||
/**
|
||||
* Core transition handler. The default implementation will only do something if
|
||||
* #commandsOutstanding is smaller or equal to zero, which means that all mode commands
|
||||
* from the #doPerformTransition call were executed successfully.
|
||||
*
|
||||
* Unless a second step was requested, the function will then use #checkChildrenState to
|
||||
* determine whether the target mode was reached.
|
||||
*
|
||||
* There is some special handling for certain (internal) modes:
|
||||
* - A second step is necessary. #commandChildren will be performed again
|
||||
* - The device health was overwritten. #commandChildren will be called
|
||||
* - A recovery is ongoing. #checkAndHandleRecovery will be called.
|
||||
*/
|
||||
virtual void handleChildrenTransition();
|
||||
|
||||
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, uint32_t *msToReachTheMode);
|
||||
|
||||
/**
|
||||
* Calls #doStartTransition and triggers an informative event as well that the mode will
|
||||
* change
|
||||
* @param mode
|
||||
* @param submode
|
||||
*/
|
||||
virtual void startTransition(Mode_t mode, Submode_t submode);
|
||||
|
||||
/**
|
||||
* This function starts the transition by setting the internal #targetSubmode and #targetMode
|
||||
* variables and then calling the #commandChildren function.
|
||||
* @param mode
|
||||
* @param submode
|
||||
*/
|
||||
virtual void doStartTransition(Mode_t mode, Submode_t submode);
|
||||
|
||||
virtual bool isInTransition();
|
||||
@ -160,7 +196,7 @@ class AssemblyBase : public SubsystemBase {
|
||||
* Manages recovery of a device
|
||||
* @return true if recovery is still ongoing, false else.
|
||||
*/
|
||||
bool checkAndHandleRecovery();
|
||||
virtual bool checkAndHandleRecovery();
|
||||
|
||||
/**
|
||||
* Helper method to overwrite health state of one of the children.
|
||||
@ -168,6 +204,8 @@ class AssemblyBase : public SubsystemBase {
|
||||
* @param objectId Must be a registered child.
|
||||
*/
|
||||
void overwriteDeviceHealth(object_id_t objectId, HasHealthIF::HealthState oldHealth);
|
||||
|
||||
void triggerModeHelperEvents(Mode_t mode, Submode_t submode);
|
||||
};
|
||||
|
||||
#endif /* FSFW_DEVICEHANDLERS_ASSEMBLYBASE_H_ */
|
||||
|
@ -3,17 +3,12 @@
|
||||
#include "fsfw/subsystem/SubsystemBase.h"
|
||||
|
||||
ChildHandlerBase::ChildHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication,
|
||||
CookieIF* cookie, object_id_t hkDestination,
|
||||
uint32_t thermalStatePoolId, uint32_t thermalRequestPoolId,
|
||||
object_id_t parent, FailureIsolationBase* customFdir,
|
||||
size_t cmdQueueSize)
|
||||
CookieIF* cookie, HasModeTreeChildrenIF& parent,
|
||||
FailureIsolationBase* customFdir, size_t cmdQueueSize)
|
||||
: DeviceHandlerBase(setObjectId, deviceCommunication, cookie,
|
||||
(customFdir == nullptr ? &childHandlerFdir : customFdir), cmdQueueSize),
|
||||
parentId(parent),
|
||||
childHandlerFdir(setObjectId) {
|
||||
this->setHkDestination(hkDestination);
|
||||
this->setThermalStateRequestPoolIds(thermalStatePoolId, thermalRequestPoolId);
|
||||
}
|
||||
parent(parent),
|
||||
childHandlerFdir(setObjectId) {}
|
||||
|
||||
ChildHandlerBase::~ChildHandlerBase() {}
|
||||
|
||||
@ -23,21 +18,5 @@ ReturnValue_t ChildHandlerBase::initialize() {
|
||||
return result;
|
||||
}
|
||||
|
||||
MessageQueueId_t parentQueue = 0;
|
||||
|
||||
if (parentId != objects::NO_OBJECT) {
|
||||
SubsystemBase* parent = ObjectManager::instance()->get<SubsystemBase>(parentId);
|
||||
if (parent == NULL) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
parentQueue = parent->getCommandQueue();
|
||||
|
||||
parent->registerChild(getObjectId());
|
||||
}
|
||||
|
||||
healthHelper.setParentQueue(parentQueue);
|
||||
|
||||
modeHelper.setParentQueue(parentQueue);
|
||||
|
||||
return returnvalue::OK;
|
||||
return DeviceHandlerBase::connectModeTreeParent(parent);
|
||||
}
|
||||
|
@ -1,22 +1,23 @@
|
||||
#ifndef FSFW_DEVICEHANDLER_CHILDHANDLERBASE_H_
|
||||
#define FSFW_DEVICEHANDLER_CHILDHANDLERBASE_H_
|
||||
|
||||
#include <fsfw/subsystem/HasModeTreeChildrenIF.h>
|
||||
|
||||
#include "ChildHandlerFDIR.h"
|
||||
#include "DeviceHandlerBase.h"
|
||||
|
||||
class ChildHandlerBase : public DeviceHandlerBase {
|
||||
public:
|
||||
ChildHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, CookieIF* cookie,
|
||||
object_id_t hkDestination, uint32_t thermalStatePoolId,
|
||||
uint32_t thermalRequestPoolId, object_id_t parent = objects::NO_OBJECT,
|
||||
FailureIsolationBase* customFdir = nullptr, size_t cmdQueueSize = 20);
|
||||
HasModeTreeChildrenIF& parent, FailureIsolationBase* customFdir = nullptr,
|
||||
size_t cmdQueueSize = 20);
|
||||
|
||||
virtual ~ChildHandlerBase();
|
||||
|
||||
virtual ReturnValue_t initialize();
|
||||
|
||||
protected:
|
||||
const uint32_t parentId;
|
||||
HasModeTreeChildrenIF& parent;
|
||||
ChildHandlerFDIR childHandlerFdir;
|
||||
};
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
#include "fsfw/devicehandlers/DeviceHandlerBase.h"
|
||||
#include "DeviceHandlerBase.h"
|
||||
|
||||
#include "fsfw/datapoollocal/LocalPoolVariable.h"
|
||||
#include "fsfw/devicehandlers/AcceptsDeviceResponsesIF.h"
|
||||
@ -12,6 +12,7 @@
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
#include "fsfw/storagemanager/StorageManagerIF.h"
|
||||
#include "fsfw/subsystem/SubsystemBase.h"
|
||||
#include "fsfw/subsystem/helper.h"
|
||||
#include "fsfw/thermal/ThermalComponentIF.h"
|
||||
|
||||
object_id_t DeviceHandlerBase::powerSwitcherId = objects::NO_OBJECT;
|
||||
@ -22,8 +23,6 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
|
||||
CookieIF* comCookie, FailureIsolationBase* fdirInstance,
|
||||
size_t cmdQueueSize)
|
||||
: SystemObject(setObjectId),
|
||||
mode(MODE_OFF),
|
||||
submode(SUBMODE_NONE),
|
||||
wiretappingMode(OFF),
|
||||
storedRawData(StorageManagerIF::INVALID_ADDRESS),
|
||||
deviceCommunicationId(deviceCommunication),
|
||||
@ -38,10 +37,13 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
|
||||
defaultFDIRUsed(fdirInstance == nullptr),
|
||||
switchOffWasReported(false),
|
||||
childTransitionDelay(5000),
|
||||
mode(MODE_OFF),
|
||||
submode(SUBMODE_NONE),
|
||||
transitionSourceMode(_MODE_POWER_DOWN),
|
||||
transitionSourceSubMode(SUBMODE_NONE) {
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE);
|
||||
cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
insertInCommandMap(RAW_COMMAND_ID);
|
||||
cookieInfo.state = COOKIE_UNUSED;
|
||||
cookieInfo.pendingCommand = deviceCommandMap.end();
|
||||
@ -49,9 +51,6 @@ DeviceHandlerBase::DeviceHandlerBase(object_id_t setObjectId, object_id_t device
|
||||
printWarningOrError(sif::OutputTypes::OUT_ERROR, "DeviceHandlerBase", returnvalue::FAILED,
|
||||
"Invalid cookie");
|
||||
}
|
||||
if (this->fdirInstance == nullptr) {
|
||||
this->fdirInstance = new DeviceHandlerFailureIsolation(setObjectId, defaultFdirParentId);
|
||||
}
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::setHkDestination(object_id_t hkDestination) {
|
||||
@ -129,6 +128,10 @@ ReturnValue_t DeviceHandlerBase::initialize() {
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
if (this->fdirInstance == nullptr) {
|
||||
this->fdirInstance =
|
||||
new DeviceHandlerFailureIsolation(this->getObjectId(), defaultFdirParentId);
|
||||
}
|
||||
|
||||
communicationInterface =
|
||||
ObjectManager::instance()->get<DeviceCommunicationIF>(deviceCommunicationId);
|
||||
@ -352,7 +355,6 @@ void DeviceHandlerBase::doStateMachine() {
|
||||
currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
|
||||
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0);
|
||||
setMode(_MODE_POWER_DOWN);
|
||||
callChildStatemachine();
|
||||
break;
|
||||
}
|
||||
ReturnValue_t switchState = getStateOfSwitches();
|
||||
@ -366,13 +368,12 @@ void DeviceHandlerBase::doStateMachine() {
|
||||
}
|
||||
} break;
|
||||
case _MODE_WAIT_OFF: {
|
||||
uint32_t currentUptime;
|
||||
Clock::getUptime(¤tUptime);
|
||||
|
||||
if (powerSwitcher == nullptr) {
|
||||
setMode(MODE_OFF);
|
||||
break;
|
||||
}
|
||||
uint32_t currentUptime;
|
||||
Clock::getUptime(¤tUptime);
|
||||
if (currentUptime - timeoutStart >= powerSwitcher->getSwitchDelayMs()) {
|
||||
triggerEvent(MODE_TRANSITION_FAILED, PowerSwitchIF::SWITCH_TIMEOUT, 0);
|
||||
setMode(MODE_ERROR_ON);
|
||||
@ -567,13 +568,25 @@ void DeviceHandlerBase::setTransition(Mode_t modeTo, Submode_t submodeTo) {
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::setMode(Mode_t newMode, uint8_t newSubmode) {
|
||||
/* TODO: This will probably be done by the LocalDataPoolManager now */
|
||||
// changeHK(mode, submode, false);
|
||||
/**
|
||||
* handle transition from OFF to NORMAL by continuing towards normal when ON is reached
|
||||
*/
|
||||
if (newMode == MODE_ON and continueToNormal) {
|
||||
continueToNormal = false;
|
||||
mode = _MODE_TO_NORMAL;
|
||||
return;
|
||||
}
|
||||
|
||||
submode = newSubmode;
|
||||
mode = newMode;
|
||||
modeChanged();
|
||||
setNormalDatapoolEntriesInvalid();
|
||||
if (newMode == MODE_OFF) {
|
||||
disableCommandsAndReplies();
|
||||
}
|
||||
if (!isTransitionalMode()) {
|
||||
// clear this flag when a non-transitional Mode is reached to be safe
|
||||
continueToNormal = false;
|
||||
modeHelper.modeChanged(newMode, newSubmode);
|
||||
announceMode(false);
|
||||
}
|
||||
@ -1058,8 +1071,7 @@ Mode_t DeviceHandlerBase::getBaseMode(Mode_t transitionMode) {
|
||||
return transitionMode & ~(TRANSITION_MODE_BASE_ACTION_MASK | TRANSITION_MODE_CHILD_ACTION_MASK);
|
||||
}
|
||||
|
||||
// SHOULDDO: Allow transition from OFF to NORMAL to reduce complexity in assemblies. And, by the
|
||||
// way, throw away DHB and write a new one:
|
||||
// SHOULDDO: throw away DHB and write a new one:
|
||||
// - Include power and thermal completely, but more modular :-)
|
||||
// - Don't use modes for state transitions, reduce FSM (Finte State Machine) complexity.
|
||||
// - Modularization?
|
||||
@ -1071,11 +1083,10 @@ ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode, Submode_
|
||||
if ((mode == MODE_ERROR_ON) && (commandedMode != MODE_OFF)) {
|
||||
return TRANS_NOT_ALLOWED;
|
||||
}
|
||||
if ((commandedMode == MODE_NORMAL) && (mode == MODE_OFF)) {
|
||||
return TRANS_NOT_ALLOWED;
|
||||
}
|
||||
|
||||
if ((commandedMode == MODE_ON) && (mode == MODE_OFF) and (thermalSet != nullptr)) {
|
||||
// Do not check thermal state for MODE_RAW
|
||||
if ((mode == MODE_OFF) and ((commandedMode == MODE_ON) or (commandedMode == MODE_NORMAL)) and
|
||||
(thermalSet != nullptr)) {
|
||||
ReturnValue_t result = thermalSet->read();
|
||||
if (result == returnvalue::OK) {
|
||||
if ((thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) and
|
||||
@ -1090,6 +1101,7 @@ ReturnValue_t DeviceHandlerBase::checkModeCommand(Mode_t commandedMode, Submode_
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::startTransition(Mode_t commandedMode, Submode_t commandedSubmode) {
|
||||
continueToNormal = false;
|
||||
switch (commandedMode) {
|
||||
case MODE_ON:
|
||||
handleTransitionToOnMode(commandedMode, commandedSubmode);
|
||||
@ -1119,8 +1131,9 @@ void DeviceHandlerBase::startTransition(Mode_t commandedMode, Submode_t commande
|
||||
case MODE_NORMAL:
|
||||
if (mode != MODE_OFF) {
|
||||
setTransition(MODE_NORMAL, commandedSubmode);
|
||||
} else {
|
||||
replyReturnvalueToCommand(HasModesIF::TRANS_NOT_ALLOWED);
|
||||
} else { // mode is off
|
||||
continueToNormal = true;
|
||||
handleTransitionToOnMode(MODE_NORMAL, commandedSubmode);
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -1278,6 +1291,7 @@ void DeviceHandlerBase::handleDeviceTm(const SerializeIF& dataSet, DeviceCommand
|
||||
if (iter->second.command != deviceCommandMap.end()) {
|
||||
MessageQueueId_t queueId = iter->second.command->second.sendReplyTo;
|
||||
|
||||
// This may fail, but we'll ignore the fault.
|
||||
if (queueId != NO_COMMANDER) {
|
||||
// This may fail, but we'll ignore the fault.
|
||||
actionHelper.reportData(queueId, replyId, const_cast<SerializeIF*>(&dataSet));
|
||||
@ -1456,6 +1470,8 @@ void DeviceHandlerBase::setTaskIF(PeriodicTaskIF* task) { executingTask = task;
|
||||
void DeviceHandlerBase::debugInterface(uint8_t positionTracker, object_id_t objectId,
|
||||
uint32_t parameter) {}
|
||||
|
||||
Submode_t DeviceHandlerBase::getInitialSubmode() { return SUBMODE_NONE; }
|
||||
|
||||
void DeviceHandlerBase::performOperationHook() {}
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
|
||||
@ -1478,7 +1494,7 @@ ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() {
|
||||
this->poolManager.initializeAfterTaskCreation();
|
||||
|
||||
if (setStartupImmediately) {
|
||||
startTransition(MODE_ON, SUBMODE_NONE);
|
||||
startTransition(MODE_ON, getInitialSubmode());
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
@ -1562,3 +1578,52 @@ MessageQueueId_t DeviceHandlerBase::getCommanderQueueId(DeviceCommandId_t replyI
|
||||
}
|
||||
return commandIter->second.sendReplyTo;
|
||||
}
|
||||
|
||||
void DeviceHandlerBase::setCustomFdir(FailureIsolationBase* fdir) { this->fdirInstance = fdir; }
|
||||
|
||||
void DeviceHandlerBase::setPowerSwitcher(PowerSwitchIF* switcher) {
|
||||
this->powerSwitcher = switcher;
|
||||
}
|
||||
|
||||
Mode_t DeviceHandlerBase::getMode() { return mode; }
|
||||
|
||||
Submode_t DeviceHandlerBase::getSubmode() { return submode; }
|
||||
|
||||
void DeviceHandlerBase::disableCommandsAndReplies() {
|
||||
for (auto& command : deviceCommandMap) {
|
||||
if (command.second.isExecuting) {
|
||||
command.second.isExecuting = false;
|
||||
}
|
||||
}
|
||||
for (auto& reply : deviceReplyMap) {
|
||||
if (!reply.second.periodic) {
|
||||
if (reply.second.countdown != nullptr) {
|
||||
reply.second.countdown->timeOut();
|
||||
} else {
|
||||
reply.second.delayCycles = 0;
|
||||
}
|
||||
reply.second.active = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
|
||||
return modetree::connectModeTreeParent(parent, *this, &healthHelper, modeHelper);
|
||||
}
|
||||
|
||||
const HasHealthIF* DeviceHandlerBase::getOptHealthIF() const { return this; }
|
||||
|
||||
const HasModesIF& DeviceHandlerBase::getModeIF() const { return *this; }
|
||||
|
||||
ModeTreeChildIF& DeviceHandlerBase::getModeTreeChildIF() { return *this; }
|
||||
|
||||
ReturnValue_t DeviceHandlerBase::finishAction(bool success, DeviceCommandId_t action,
|
||||
ReturnValue_t result) {
|
||||
auto commandIter = deviceCommandMap.find(action);
|
||||
if (commandIter == deviceCommandMap.end()) {
|
||||
return MessageQueueIF::NO_QUEUE;
|
||||
}
|
||||
commandIter->second.isExecuting = false;
|
||||
actionHelper.finish(success, commandIter->second.sendReplyTo, action, result);
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
@ -21,6 +21,7 @@
|
||||
#include "fsfw/returnvalues/returnvalue.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
#include "fsfw/serviceinterface/serviceInterfaceDefintions.h"
|
||||
#include "fsfw/subsystem/ModeTreeConnectionIF.h"
|
||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||
#include "fsfw/tasks/PeriodicTaskIF.h"
|
||||
|
||||
@ -83,6 +84,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
public HasModesIF,
|
||||
public HasHealthIF,
|
||||
public HasActionsIF,
|
||||
public ModeTreeChildIF,
|
||||
public ModeTreeConnectionIF,
|
||||
public ReceivesParameterMessagesIF,
|
||||
public HasLocalDataPoolIF {
|
||||
friend void(Factory::setStaticFrameworkObjectIds)();
|
||||
@ -102,6 +105,56 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
DeviceHandlerBase(object_id_t setObjectId, object_id_t deviceCommunication, CookieIF *comCookie,
|
||||
FailureIsolationBase *fdirInstance = nullptr, size_t cmdQueueSize = 20);
|
||||
|
||||
void setCustomFdir(FailureIsolationBase *fdir);
|
||||
void setPowerSwitcher(PowerSwitchIF *switcher);
|
||||
|
||||
/**
|
||||
* extending the modes of DeviceHandler IF for internal state machine
|
||||
*/
|
||||
static constexpr uint8_t TRANSITION_MODE_CHILD_ACTION_MASK = 0x20;
|
||||
static constexpr uint8_t TRANSITION_MODE_BASE_ACTION_MASK = 0x10;
|
||||
//! This is a transitional state which can not be commanded. The device
|
||||
//! handler performs all commands to get the device in a state ready to
|
||||
//! perform commands. When this is completed, the mode changes to @c MODE_ON.
|
||||
static const Mode_t _MODE_START_UP = TRANSITION_MODE_CHILD_ACTION_MASK | 5;
|
||||
//! This is a transitional state which can not be commanded.
|
||||
//! The device handler performs all actions and commands to get the device
|
||||
//! shut down. When the device is off, the mode changes to @c MODE_OFF.
|
||||
//! It is possible to set the mode to _MODE_SHUT_DOWN to use the to off
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_SHUT_DOWN = TRANSITION_MODE_CHILD_ACTION_MASK | 6;
|
||||
//! It is possible to set the mode to _MODE_TO_ON to use the to on
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_TO_ON = TRANSITION_MODE_CHILD_ACTION_MASK | HasModesIF::MODE_ON;
|
||||
//! It is possible to set the mode to _MODE_TO_RAW to use the to raw
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_TO_RAW = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_RAW;
|
||||
//! It is possible to set the mode to _MODE_TO_NORMAL to use the to normal
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_TO_NORMAL = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_NORMAL;
|
||||
//! This is a transitional state which can not be commanded.
|
||||
//! The device is shut down and ready to be switched off.
|
||||
//! After the command to set the switch off has been sent,
|
||||
//! the mode changes to @c _MODE_WAIT_OFF
|
||||
static const Mode_t _MODE_POWER_DOWN = TRANSITION_MODE_BASE_ACTION_MASK | 1;
|
||||
//! This is a transitional state which can not be commanded. The device
|
||||
//! will be switched on in this state. After the command to set the switch
|
||||
//! on has been sent, the mode changes to @c _MODE_WAIT_ON.
|
||||
static const Mode_t _MODE_POWER_ON = TRANSITION_MODE_BASE_ACTION_MASK | 2;
|
||||
//! This is a transitional state which can not be commanded. The switch has
|
||||
//! been commanded off and the handler waits for it to be off.
|
||||
//! When the switch is off, the mode changes to @c MODE_OFF.
|
||||
static const Mode_t _MODE_WAIT_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 3;
|
||||
//! This is a transitional state which can not be commanded. The switch
|
||||
//! has been commanded on and the handler waits for it to be on.
|
||||
//! When the switch is on, the mode changes to @c _MODE_TO_ON.
|
||||
static const Mode_t _MODE_WAIT_ON = TRANSITION_MODE_BASE_ACTION_MASK | 4;
|
||||
//! This is a transitional state which can not be commanded. The switch has
|
||||
//! been commanded off and is off now. This state is only to do an RMAP
|
||||
//! cycle once more where the doSendRead() function will set the mode to
|
||||
//! MODE_OFF. The reason to do this is to get rid of stuck packets in the IO Board.
|
||||
static const Mode_t _MODE_SWITCH_IS_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 5;
|
||||
|
||||
void setHkDestination(object_id_t hkDestination);
|
||||
|
||||
/**
|
||||
@ -117,6 +170,10 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
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);
|
||||
|
||||
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF &parent) override;
|
||||
ModeTreeChildIF &getModeTreeChildIF() override;
|
||||
|
||||
/**
|
||||
* @brief Helper function to ease device handler development.
|
||||
* This will instruct the transition to MODE_ON immediately
|
||||
@ -162,7 +219,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* @param counter Specifies which Action to perform
|
||||
* @return returnvalue::OK for successful execution
|
||||
*/
|
||||
virtual ReturnValue_t performOperation(uint8_t counter) override;
|
||||
ReturnValue_t performOperation(uint8_t counter) override;
|
||||
|
||||
/**
|
||||
* @brief Initializes the device handler
|
||||
@ -172,14 +229,14 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* Calls fillCommandAndReplyMap().
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t initialize() override;
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
/**
|
||||
* @brief Intialization steps performed after all tasks have been created.
|
||||
* This function will be called by the executing task.
|
||||
* @return
|
||||
*/
|
||||
virtual ReturnValue_t initializeAfterTaskCreation() override;
|
||||
ReturnValue_t initializeAfterTaskCreation() override;
|
||||
|
||||
/** Destructor. */
|
||||
virtual ~DeviceHandlerBase();
|
||||
@ -196,6 +253,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
virtual object_id_t getObjectId() const override;
|
||||
|
||||
/**
|
||||
* This is a helper method for classes which are parent nodes in the mode tree.
|
||||
* It registers the passed queue as the destination for mode and health messages.
|
||||
* @param parentQueueId
|
||||
*/
|
||||
virtual void setParentQueue(MessageQueueId_t parentQueueId);
|
||||
@ -395,6 +454,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
*/
|
||||
virtual ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) = 0;
|
||||
MessageQueueId_t getCommanderQueueId(DeviceCommandId_t replyId) const;
|
||||
ReturnValue_t finishAction(bool success, DeviceCommandId_t action, ReturnValue_t result);
|
||||
|
||||
/**
|
||||
* Helper function to get pending command. This is useful for devices
|
||||
* like SPI sensors to identify the last sent command.
|
||||
@ -463,14 +524,14 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* @brief This is a helper method to insert replies in the reply map.
|
||||
* @param deviceCommand Identifier of the reply to add.
|
||||
* @param maxDelayCycles The maximum number of delay cycles the reply waits
|
||||
* until it times out.
|
||||
* until it times out.
|
||||
* @param periodic Indicates if the command is periodic (i.e. it is sent
|
||||
* by the device repeatedly without request) or not. Default is aperiodic (0).
|
||||
* Please note that periodic replies are disabled by default. You can enable them with
|
||||
* #updatePeriodicReply
|
||||
* by the device repeatedly without request) or not. Default is aperiodic (0).
|
||||
* Please note that periodic replies are disabled by default. You can enable them with
|
||||
* #updatePeriodicReply
|
||||
* @param countdown Instead of using maxDelayCycles to timeout a device reply it is also possible
|
||||
* to provide a pointer to a Countdown object which will signal the timeout
|
||||
* when expired
|
||||
* to provide a pointer to a Countdown object which will signal the timeout
|
||||
* when expired
|
||||
* @return - @c returnvalue::OK when the command was successfully inserted,
|
||||
* - @c returnvalue::FAILED else.
|
||||
*/
|
||||
@ -655,6 +716,12 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
virtual void debugInterface(uint8_t positionTracker = 0, object_id_t objectId = 0,
|
||||
uint32_t parameter = 0);
|
||||
|
||||
/**
|
||||
* @brief Can be overwritten by a child to specify the initial submode when device has been set
|
||||
* to startup immediately.
|
||||
*/
|
||||
virtual Submode_t getInitialSubmode();
|
||||
|
||||
protected:
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_BASE;
|
||||
|
||||
@ -684,15 +751,18 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
size_t rawPacketLen = 0;
|
||||
|
||||
/**
|
||||
* The mode the device handler is currently in.
|
||||
* This should never be changed directly but only with setMode()
|
||||
* Get the current mode
|
||||
*
|
||||
* set via setMode()
|
||||
*/
|
||||
Mode_t mode;
|
||||
Mode_t getMode();
|
||||
|
||||
/**
|
||||
* The submode the device handler is currently in.
|
||||
* This should never be changed directly but only with setMode()
|
||||
* Get the current Submode
|
||||
*
|
||||
* set via setMode()
|
||||
*/
|
||||
Submode_t submode;
|
||||
Submode_t getSubmode();
|
||||
|
||||
/** This is the counter value from performOperation(). */
|
||||
uint8_t pstStep = 0;
|
||||
@ -773,11 +843,18 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* This is used to keep track of pending replies.
|
||||
*/
|
||||
struct DeviceReplyInfo {
|
||||
//! For Command-Reply combinations:
|
||||
//! The maximum number of cycles the handler should wait for a reply
|
||||
//! to this command.
|
||||
//!
|
||||
//! Reply Only:
|
||||
//! For periodic replies, this variable will be the number of delay cycles between the replies.
|
||||
//! For the non-periodic variant, this variable is not used as there is no meaningful
|
||||
//! definition for delay
|
||||
uint16_t maxDelayCycles;
|
||||
//! The currently remaining cycles the handler should wait for a reply,
|
||||
//! 0 means there is no reply expected
|
||||
//! This variable will be set to #maxDelayCycles if a reply is expected.
|
||||
//! For non-periodic replies without a command, this variable is unused.
|
||||
//! A runtime value of 0 means there is no reply is currently expected.
|
||||
uint16_t delayCycles;
|
||||
size_t replyLen = 0; //!< Expected size of the reply.
|
||||
//! if this is !=0, the delayCycles will not be reset to 0 but to
|
||||
@ -833,6 +910,7 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
/** Pointer to the used FDIR instance. If not provided by child,
|
||||
* default class is instantiated. */
|
||||
FailureIsolationBase *fdirInstance;
|
||||
object_id_t parent = objects::NO_OBJECT;
|
||||
|
||||
//! To correctly delete the default instance.
|
||||
bool defaultFDIRUsed;
|
||||
@ -873,8 +951,8 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* Do the transition to the main modes (MODE_ON, MODE_NORMAL and MODE_RAW).
|
||||
*
|
||||
* If the transition is complete, the mode should be set to the target mode,
|
||||
* which can be deduced from the current mode which is
|
||||
* [_MODE_TO_ON, _MODE_TO_NORMAL, _MODE_TO_RAW]
|
||||
* which can be deduced from the current mode (which is
|
||||
* [_MODE_TO_ON, _MODE_TO_NORMAL, _MODE_TO_RAW]) using getBaseMode()
|
||||
*
|
||||
* The intended target submode is already set.
|
||||
* The origin submode can be read in subModeFrom.
|
||||
@ -941,6 +1019,9 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
*/
|
||||
LocalDataPoolManager *getHkManagerHandle() override;
|
||||
|
||||
const HasHealthIF *getOptHealthIF() const override;
|
||||
const HasModesIF &getModeIF() const override;
|
||||
|
||||
/**
|
||||
* Returns the delay cycle count of a reply.
|
||||
* A count != 0 indicates that the command is already executed.
|
||||
@ -1120,6 +1201,22 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
*/
|
||||
virtual ReturnValue_t doSendReadHook();
|
||||
|
||||
/**
|
||||
* Send a RMAP getRead command.
|
||||
*
|
||||
* The size of the getRead command is #maxDeviceReplyLen.
|
||||
* This is always executed, independently from the current mode.
|
||||
*/
|
||||
virtual void doSendRead(void);
|
||||
/**
|
||||
* Check the getRead reply and the contained data.
|
||||
*
|
||||
* If data was received scanForReply() and, if successful, handleReply()
|
||||
* are called. If the current mode is @c MODE_RAW, the received packet
|
||||
* is sent to the commanding object via commandQueue.
|
||||
*/
|
||||
virtual void doGetRead();
|
||||
|
||||
private:
|
||||
/**
|
||||
* State a cookie is in.
|
||||
@ -1170,6 +1267,18 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
*/
|
||||
uint32_t childTransitionDelay;
|
||||
|
||||
/**
|
||||
* The mode the device handler is currently in.
|
||||
* This should not be changed directly but only with setMode()
|
||||
*/
|
||||
Mode_t mode;
|
||||
|
||||
/**
|
||||
* The submode the device handler is currently in.
|
||||
* This should not be changed directly but only with setMode()
|
||||
*/
|
||||
Submode_t submode;
|
||||
|
||||
/**
|
||||
* @brief The mode the current transition originated from
|
||||
*
|
||||
@ -1187,6 +1296,15 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
*/
|
||||
Submode_t transitionSourceSubMode;
|
||||
|
||||
/**
|
||||
* used to make the state machine continue from ON to NOMAL when
|
||||
* a Device is commanded to NORMAL in OFF mode
|
||||
*
|
||||
* set in startTransition()
|
||||
* evaluated in setMode() to continue to NORMAL when ON is reached
|
||||
*/
|
||||
bool continueToNormal;
|
||||
|
||||
/**
|
||||
* read the command queue
|
||||
*/
|
||||
@ -1255,21 +1373,6 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
* - if the action was successful, the reply timout counter is initialized
|
||||
*/
|
||||
void doGetWrite(void);
|
||||
/**
|
||||
* Send a RMAP getRead command.
|
||||
*
|
||||
* The size of the getRead command is #maxDeviceReplyLen.
|
||||
* This is always executed, independently from the current mode.
|
||||
*/
|
||||
void doSendRead(void);
|
||||
/**
|
||||
* Check the getRead reply and the contained data.
|
||||
*
|
||||
* If data was received scanForReply() and, if successful, handleReply()
|
||||
* are called. If the current mode is @c MODE_RAW, the received packet
|
||||
* is sent to the commanding object via commandQueue.
|
||||
*/
|
||||
void doGetRead(void);
|
||||
|
||||
/**
|
||||
* @brief Resets replies which use a timeout to detect missed replies.
|
||||
@ -1323,6 +1426,11 @@ class DeviceHandlerBase : public DeviceHandlerIF,
|
||||
void printWarningOrError(sif::OutputTypes errorType, const char *functionName,
|
||||
ReturnValue_t errorCode = returnvalue::FAILED,
|
||||
const char *errorPrint = nullptr);
|
||||
|
||||
/**
|
||||
* @brief Disables all commands and replies when device is set to MODE_OFF
|
||||
*/
|
||||
void disableCommandsAndReplies();
|
||||
};
|
||||
|
||||
#endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ */
|
||||
|
@ -29,6 +29,7 @@ ReturnValue_t DeviceHandlerFailureIsolation::eventReceived(EventMessage* event)
|
||||
switch (event->getEvent()) {
|
||||
case HasModesIF::MODE_TRANSITION_FAILED:
|
||||
case HasModesIF::OBJECT_IN_INVALID_MODE:
|
||||
case DeviceHandlerIF::DEVICE_WANTS_HARD_REBOOT:
|
||||
// We'll try a recovery as long as defined in MAX_REBOOT.
|
||||
// Might cause some AssemblyBase cycles, so keep number low.
|
||||
handleRecovery(event->getEvent());
|
||||
|
@ -24,9 +24,6 @@ class DeviceHandlerIF {
|
||||
static const DeviceCommandId_t RAW_COMMAND_ID = -1;
|
||||
static const DeviceCommandId_t NO_COMMAND_ID = -2;
|
||||
|
||||
static constexpr uint8_t TRANSITION_MODE_CHILD_ACTION_MASK = 0x20;
|
||||
static constexpr uint8_t TRANSITION_MODE_BASE_ACTION_MASK = 0x10;
|
||||
|
||||
using dh_heater_request_t = uint8_t;
|
||||
using dh_thermal_state_t = int8_t;
|
||||
|
||||
@ -54,47 +51,6 @@ class DeviceHandlerIF {
|
||||
//! device still is powered. In this mode, only a mode change to @c MODE_OFF
|
||||
//! can be commanded, which tries to switch off the device again.
|
||||
static const Mode_t MODE_ERROR_ON = 4;
|
||||
//! This is a transitional state which can not be commanded. The device
|
||||
//! handler performs all commands to get the device in a state ready to
|
||||
//! perform commands. When this is completed, the mode changes to @c MODE_ON.
|
||||
static const Mode_t _MODE_START_UP = TRANSITION_MODE_CHILD_ACTION_MASK | 5;
|
||||
//! This is a transitional state which can not be commanded.
|
||||
//! The device handler performs all actions and commands to get the device
|
||||
//! shut down. When the device is off, the mode changes to @c MODE_OFF.
|
||||
//! It is possible to set the mode to _MODE_SHUT_DOWN to use the to off
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_SHUT_DOWN = TRANSITION_MODE_CHILD_ACTION_MASK | 6;
|
||||
//! It is possible to set the mode to _MODE_TO_ON to use the to on
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_TO_ON = TRANSITION_MODE_CHILD_ACTION_MASK | HasModesIF::MODE_ON;
|
||||
//! It is possible to set the mode to _MODE_TO_RAW to use the to raw
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_TO_RAW = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_RAW;
|
||||
//! It is possible to set the mode to _MODE_TO_NORMAL to use the to normal
|
||||
//! transition if available.
|
||||
static const Mode_t _MODE_TO_NORMAL = TRANSITION_MODE_CHILD_ACTION_MASK | MODE_NORMAL;
|
||||
//! This is a transitional state which can not be commanded.
|
||||
//! The device is shut down and ready to be switched off.
|
||||
//! After the command to set the switch off has been sent,
|
||||
//! the mode changes to @c MODE_WAIT_OFF
|
||||
static const Mode_t _MODE_POWER_DOWN = TRANSITION_MODE_BASE_ACTION_MASK | 1;
|
||||
//! This is a transitional state which can not be commanded. The device
|
||||
//! will be switched on in this state. After the command to set the switch
|
||||
//! on has been sent, the mode changes to @c MODE_WAIT_ON.
|
||||
static const Mode_t _MODE_POWER_ON = TRANSITION_MODE_BASE_ACTION_MASK | 2;
|
||||
//! This is a transitional state which can not be commanded. The switch has
|
||||
//! been commanded off and the handler waits for it to be off.
|
||||
//! When the switch is off, the mode changes to @c MODE_OFF.
|
||||
static const Mode_t _MODE_WAIT_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 3;
|
||||
//! This is a transitional state which can not be commanded. The switch
|
||||
//! has been commanded on and the handler waits for it to be on.
|
||||
//! When the switch is on, the mode changes to @c MODE_TO_ON.
|
||||
static const Mode_t _MODE_WAIT_ON = TRANSITION_MODE_BASE_ACTION_MASK | 4;
|
||||
//! This is a transitional state which can not be commanded. The switch has
|
||||
//! been commanded off and is off now. This state is only to do an RMAP
|
||||
//! cycle once more where the doSendRead() function will set the mode to
|
||||
//! MODE_OFF. The reason to do this is to get rid of stuck packets in the IO Board.
|
||||
static const Mode_t _MODE_SWITCH_IS_OFF = TRANSITION_MODE_BASE_ACTION_MASK | 5;
|
||||
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CDH;
|
||||
static const Event DEVICE_BUILDING_COMMAND_FAILED = MAKE_EVENT(0, severity::LOW);
|
||||
@ -109,6 +65,7 @@ class DeviceHandlerIF {
|
||||
static const Event INVALID_DEVICE_COMMAND = MAKE_EVENT(8, severity::LOW);
|
||||
static const Event MONITORING_LIMIT_EXCEEDED = MAKE_EVENT(9, severity::LOW);
|
||||
static const Event MONITORING_AMBIGUOUS = MAKE_EVENT(10, severity::HIGH);
|
||||
static const Event DEVICE_WANTS_HARD_REBOOT = MAKE_EVENT(11, severity::HIGH);
|
||||
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::DEVICE_HANDLER_IF;
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
#ifndef FSFW_DEVICEHANDLERS_DEVICETMREPORTINGWRAPPER_H_
|
||||
#define FSFW_DEVICEHANDLERS_DEVICETMREPORTINGWRAPPER_H_
|
||||
|
||||
#include "../action/HasActionsIF.h"
|
||||
#include "../objectmanager/SystemObjectIF.h"
|
||||
#include "../serialize/SerializeIF.h"
|
||||
#include "fsfw/action/HasActionsIF.h"
|
||||
#include "fsfw/objectmanager/SystemObjectIF.h"
|
||||
#include "fsfw/serialize/SerializeIF.h"
|
||||
|
||||
class DeviceTmReportingWrapper : public SerializeIF {
|
||||
public:
|
||||
|
@ -8,7 +8,9 @@ HealthDevice::HealthDevice(object_id_t setObjectId, MessageQueueId_t parentQueue
|
||||
parentQueue(parentQueue),
|
||||
commandQueue(),
|
||||
healthHelper(this, setObjectId) {
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(3);
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
}
|
||||
|
||||
HealthDevice::~HealthDevice() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
||||
|
@ -18,8 +18,9 @@ const LocalPool::LocalPoolConfig EventManager::poolConfig = {
|
||||
EventManager::EventManager(object_id_t setObjectId)
|
||||
: SystemObject(setObjectId), factoryBackend(0, poolConfig, false, true) {
|
||||
mutex = MutexFactory::instance()->createMutex();
|
||||
eventReportQueue = QueueFactory::instance()->createMessageQueue(MAX_EVENTS_PER_CYCLE,
|
||||
EventMessage::EVENT_MESSAGE_SIZE);
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
eventReportQueue = QueueFactory::instance()->createMessageQueue(
|
||||
MAX_EVENTS_PER_CYCLE, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
|
||||
}
|
||||
|
||||
EventManager::~EventManager() {
|
||||
@ -46,9 +47,20 @@ ReturnValue_t EventManager::performOperation(uint8_t opCode) {
|
||||
|
||||
void EventManager::notifyListeners(EventMessage* message) {
|
||||
lockMutex();
|
||||
for (auto iter = listenerList.begin(); iter != listenerList.end(); ++iter) {
|
||||
if (iter->second.match(message)) {
|
||||
MessageQueueSenderIF::sendMessage(iter->first, message, message->getSender());
|
||||
for (auto& listener : listenerList) {
|
||||
if (listener.second.match(message)) {
|
||||
ReturnValue_t result =
|
||||
MessageQueueSenderIF::sendMessage(listener.first, message, message->getSender());
|
||||
if (result != returnvalue::OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << std::hex << "EventManager::notifyListeners: MSG to 0x" << std::setfill('0')
|
||||
<< std::setw(8) << listener.first << " failed with result 0x" << std::setw(4)
|
||||
<< result << std::setfill(' ') << std::endl;
|
||||
#else
|
||||
sif::printError("Sending message to listener 0x%08x failed with result %04x\n",
|
||||
listener.first, result);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
unlockMutex();
|
||||
@ -194,4 +206,19 @@ void EventManager::printUtility(sif::OutputTypes printType, EventMessage* messag
|
||||
}
|
||||
}
|
||||
|
||||
void EventManager::printListeners() {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::info << "Event manager listener MQ IDs:" << std::setfill('0') << std::hex << std::endl;
|
||||
for (auto& listener : listenerList) {
|
||||
sif::info << "0x" << std::setw(8) << listener.first << std::endl;
|
||||
}
|
||||
sif::info << std::dec << std::setfill(' ');
|
||||
#else
|
||||
sif::printInfo("Event manager listener MQ IDs:\n");
|
||||
for (auto& listener : listenerList) {
|
||||
sif::printInfo("0x%08x\n", listener.first);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif /* FSFW_OBJ_EVENT_TRANSLATION == 1 */
|
||||
|
@ -43,6 +43,7 @@ class EventManager : public EventManagerIF, public ExecutableObjectIF, public Sy
|
||||
object_id_t reporterFrom = 0, object_id_t reporterTo = 0,
|
||||
bool reporterInverted = false);
|
||||
ReturnValue_t performOperation(uint8_t opCode);
|
||||
void printListeners();
|
||||
|
||||
protected:
|
||||
MessageQueueIF* eventReportQueue = nullptr;
|
||||
|
@ -33,6 +33,7 @@ enum : uint8_t {
|
||||
PUS_SERVICE_23 = 103,
|
||||
MGM_LIS3MDL = 106,
|
||||
MGM_RM3100 = 107,
|
||||
CFDP = 108,
|
||||
|
||||
FW_SUBSYSTEM_ID_RANGE
|
||||
};
|
||||
|
@ -9,8 +9,9 @@
|
||||
FailureIsolationBase::FailureIsolationBase(object_id_t owner, object_id_t parent,
|
||||
uint8_t messageDepth, uint8_t parameterDomainBase)
|
||||
: ownerId(owner), faultTreeParent(parent), parameterDomainBase(parameterDomainBase) {
|
||||
eventQueue =
|
||||
QueueFactory::instance()->createMessageQueue(messageDepth, EventMessage::EVENT_MESSAGE_SIZE);
|
||||
auto mqArgs = MqArgs(owner, static_cast<void*>(this));
|
||||
eventQueue = QueueFactory::instance()->createMessageQueue(
|
||||
messageDepth, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
|
||||
}
|
||||
|
||||
FailureIsolationBase::~FailureIsolationBase() {
|
||||
@ -61,11 +62,12 @@ ReturnValue_t FailureIsolationBase::initialize() {
|
||||
ObjectManager::instance()->get<ConfirmsFailuresIF>(faultTreeParent);
|
||||
if (parentIF == nullptr) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "FailureIsolationBase::intialize: Parent object"
|
||||
<< "invalid." << std::endl;
|
||||
#endif
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "Make sure it implements ConfirmsFailuresIF." << std::endl;
|
||||
sif::error << "FailureIsolationBase::intialize: Parent object "
|
||||
<< "invalid" << std::endl;
|
||||
sif::error << "Make sure it implements ConfirmsFailuresIF" << std::endl;
|
||||
#else
|
||||
sif::printError("FailureIsolationBase::intialize: Parent object invalid\n");
|
||||
sif::printError("Make sure it implements ConfirmsFailuresIF\n");
|
||||
#endif
|
||||
return ObjectManagerIF::CHILD_INIT_FAILED;
|
||||
return returnvalue::FAILED;
|
||||
|
@ -12,13 +12,12 @@
|
||||
class FailureIsolationBase : public ConfirmsFailuresIF, public HasParametersIF {
|
||||
public:
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::FDIR_1;
|
||||
static const Event FDIR_CHANGED_STATE =
|
||||
MAKE_EVENT(1, severity::INFO); //!< FDIR has an internal state, which changed from par2
|
||||
//!< (oldState) to par1 (newState).
|
||||
static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(
|
||||
2, severity::MEDIUM); //!< FDIR tries to restart device. Par1: event that caused recovery.
|
||||
static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(
|
||||
3, severity::MEDIUM); //!< FDIR turns off device. Par1: event that caused recovery.
|
||||
//! FDIR has an internal state, which changed from par2 (oldState) to par1 (newState).
|
||||
static const Event FDIR_CHANGED_STATE = MAKE_EVENT(1, severity::INFO);
|
||||
//! FDIR tries to restart device. Par1: event that caused recovery.
|
||||
static const Event FDIR_STARTS_RECOVERY = MAKE_EVENT(2, severity::MEDIUM);
|
||||
//! FDIR turns off device. Par1: event that caused recovery.
|
||||
static const Event FDIR_TURNS_OFF_DEVICE = MAKE_EVENT(3, severity::MEDIUM);
|
||||
|
||||
FailureIsolationBase(object_id_t owner, object_id_t parent = objects::NO_OBJECT,
|
||||
uint8_t messageDepth = 10, uint8_t parameterDomainBase = 0xF0);
|
||||
|
@ -40,6 +40,7 @@ class HasFileSystemIF {
|
||||
//! [EXPORT] : P1: Can be file system specific error code
|
||||
static constexpr ReturnValue_t GENERIC_FILE_ERROR = MAKE_RETURN_CODE(0);
|
||||
static constexpr ReturnValue_t GENERIC_DIR_ERROR = MAKE_RETURN_CODE(1);
|
||||
static constexpr ReturnValue_t FILESYSTEM_INACTIVE = MAKE_RETURN_CODE(2);
|
||||
static constexpr ReturnValue_t GENERIC_RENAME_ERROR = MAKE_RETURN_CODE(3);
|
||||
|
||||
//! [EXPORT] : File system is currently busy
|
||||
|
@ -16,26 +16,24 @@ class HasHealthIF {
|
||||
};
|
||||
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::HAS_HEALTH_IF;
|
||||
static const ReturnValue_t OBJECT_NOT_HEALTHY = MAKE_RETURN_CODE(1);
|
||||
static const ReturnValue_t INVALID_HEALTH_STATE = MAKE_RETURN_CODE(2);
|
||||
static constexpr ReturnValue_t OBJECT_NOT_HEALTHY = returnvalue::makeCode(INTERFACE_ID, 1);
|
||||
static constexpr ReturnValue_t INVALID_HEALTH_STATE = returnvalue::makeCode(INTERFACE_ID, 2);
|
||||
static constexpr ReturnValue_t IS_EXTERNALLY_CONTROLLED = returnvalue::makeCode(INTERFACE_ID, 3);
|
||||
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER_1;
|
||||
//! P1: New Health, P2: Old Health
|
||||
static const Event HEALTH_INFO = MAKE_EVENT(6, severity::INFO);
|
||||
static const Event CHILD_CHANGED_HEALTH = MAKE_EVENT(7, severity::INFO);
|
||||
static const Event CHILD_PROBLEMS = MAKE_EVENT(8, severity::LOW);
|
||||
static const Event OVERWRITING_HEALTH =
|
||||
MAKE_EVENT(9, severity::LOW); //!< Assembly overwrites health information of children to keep
|
||||
//!< satellite alive.
|
||||
static const Event TRYING_RECOVERY =
|
||||
MAKE_EVENT(10, severity::MEDIUM); //!< Someone starts a recovery of a component (typically
|
||||
//!< power-cycle). No parameters.
|
||||
static const Event RECOVERY_STEP =
|
||||
MAKE_EVENT(11, severity::MEDIUM); //!< Recovery is ongoing. Comes twice during recovery. P1:
|
||||
//!< 0 for the first, 1 for the second event. P2: 0
|
||||
static const Event RECOVERY_DONE = MAKE_EVENT(
|
||||
12,
|
||||
severity::MEDIUM); //!< Recovery was completed. Not necessarily successful. No parameters.
|
||||
|
||||
//! Assembly overwrites health information of children to keep satellite alive.
|
||||
static const Event OVERWRITING_HEALTH = MAKE_EVENT(9, severity::LOW);
|
||||
//! Someone starts a recovery of a component (typically power-cycle). No parameters.
|
||||
static const Event TRYING_RECOVERY = MAKE_EVENT(10, severity::MEDIUM);
|
||||
//! Recovery is ongoing. Comes twice during recovery.
|
||||
//! P1: 0 for the first, 1 for the second event. P2: 0
|
||||
static const Event RECOVERY_STEP = MAKE_EVENT(11, severity::MEDIUM);
|
||||
//! Recovery was completed. Not necessarily successful. No parameters.
|
||||
static const Event RECOVERY_DONE = MAKE_EVENT(12, severity::MEDIUM);
|
||||
virtual ~HasHealthIF() {}
|
||||
|
||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||
|
@ -7,11 +7,13 @@
|
||||
|
||||
InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, 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();
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void *>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
}
|
||||
|
||||
InternalErrorReporter::~InternalErrorReporter() { MutexFactory::instance()->deleteMutex(mutex); }
|
||||
@ -36,15 +38,14 @@ ReturnValue_t InternalErrorReporter::performOperation(uint8_t opCode) {
|
||||
if ((newQueueHits > 0) or (newTmHits > 0) or (newStoreHits > 0)) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
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;
|
||||
<< "occured: Queue | TM | Store : " << newQueueHits << " | " << newTmHits << " | "
|
||||
<< newStoreHits << std::endl;
|
||||
#else
|
||||
sif::printDebug("InternalErrorReporter::performOperation: Errors occured!\n");
|
||||
sif::printDebug("Queue errors: %lu\n", static_cast<unsigned int>(newQueueHits));
|
||||
sif::printDebug("TM errors: %lu\n", static_cast<unsigned int>(newTmHits));
|
||||
sif::printDebug("Store errors: %lu\n", static_cast<unsigned int>(newStoreHits));
|
||||
sif::printDebug(
|
||||
"InternalErrorReporter::performOperation: Errors occured: Queue | TM | Store: %lu | %lu "
|
||||
"| %lu\n",
|
||||
static_cast<unsigned int>(newQueueHits), static_cast<unsigned int>(newTmHits),
|
||||
static_cast<unsigned int>(newStoreHits));
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -34,7 +34,7 @@ class CommandMessageIF {
|
||||
static const Command_t CMD_NONE = MAKE_COMMAND_ID(0);
|
||||
static const Command_t REPLY_COMMAND_OK = MAKE_COMMAND_ID(1);
|
||||
//! Reply indicating that the current command was rejected,
|
||||
//! par1 should contain the error code
|
||||
//! Parameter 1 should contain the error code
|
||||
static const Command_t REPLY_REJECTED = MAKE_COMMAND_ID(2);
|
||||
|
||||
virtual ~CommandMessageIF(){};
|
||||
|
@ -19,32 +19,33 @@ class HasModesIF {
|
||||
static const ReturnValue_t INVALID_SUBMODE = MAKE_RETURN_CODE(0x04);
|
||||
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SYSTEM_MANAGER;
|
||||
static const Event CHANGING_MODE =
|
||||
MAKE_EVENT(0, severity::INFO); //!< An object announces changing the mode. p1: target mode.
|
||||
//!< p2: target submode
|
||||
static const Event MODE_INFO = MAKE_EVENT(
|
||||
1,
|
||||
severity::INFO); //!< An Object announces its mode; parameter1 is mode, parameter2 is submode
|
||||
//! An object announces changing the mode. p1: target mode. p2: target submode
|
||||
static const Event CHANGING_MODE = MAKE_EVENT(0, severity::INFO);
|
||||
//! An Object announces its mode; parameter1 is mode, parameter2 is submode
|
||||
static const Event MODE_INFO = MAKE_EVENT(1, severity::INFO);
|
||||
static const Event FALLBACK_FAILED = MAKE_EVENT(2, severity::HIGH);
|
||||
static const Event MODE_TRANSITION_FAILED = MAKE_EVENT(3, severity::LOW);
|
||||
static const Event CANT_KEEP_MODE = MAKE_EVENT(4, severity::HIGH);
|
||||
static const Event OBJECT_IN_INVALID_MODE =
|
||||
MAKE_EVENT(5, severity::LOW); //!< Indicates a bug or configuration failure: Object is in a
|
||||
//!< mode it should never be in.
|
||||
static const Event FORCING_MODE = MAKE_EVENT(
|
||||
6, severity::MEDIUM); //!< The mode is changed, but for some reason, the change is forced,
|
||||
//!< i.e. EXTERNAL_CONTROL ignored. p1: target mode. p2: target submode
|
||||
static const Event MODE_CMD_REJECTED =
|
||||
MAKE_EVENT(7, severity::LOW); //!< A mode command was rejected by the called object. Par1:
|
||||
//!< called object id, Par2: return code.
|
||||
//! Indicates a bug or configuration failure: Object is in a mode it should never be in.
|
||||
static const Event OBJECT_IN_INVALID_MODE = MAKE_EVENT(5, severity::LOW);
|
||||
//! The mode is changed, but for some reason, the change is forced, i.e. EXTERNAL_CONTROL ignored.
|
||||
//! p1: target mode. p2: target submode
|
||||
static const Event FORCING_MODE = MAKE_EVENT(6, severity::MEDIUM);
|
||||
//! A mode command was rejected by the called object. Par1: called object id, Par2: return code.
|
||||
static const Event MODE_CMD_REJECTED = MAKE_EVENT(7, severity::LOW);
|
||||
|
||||
static const Mode_t MODE_ON =
|
||||
1; //!< The device is powered and ready to perform operations. In this mode, no commands are
|
||||
//!< sent by the device handler itself, but direct commands van be commanded and will be
|
||||
//!< interpreted
|
||||
static const Mode_t MODE_OFF = 0; //!< The device is powered off. The only command accepted in
|
||||
//!< this mode is a mode change to on.
|
||||
static const Submode_t SUBMODE_NONE = 0; //!< To avoid checks against magic number "0".
|
||||
//! The device is powered and ready to perform operations. In this mode, no commands are
|
||||
//! sent by the device handler itself, but direct commands van be commanded and will be
|
||||
//! interpreted
|
||||
static constexpr Mode_t MODE_ON = 1;
|
||||
//! The device is powered off. The only command accepted in this mode is a mode change to on.
|
||||
static constexpr Mode_t MODE_OFF = 0;
|
||||
|
||||
static constexpr Mode_t MODE_INVALID = -1;
|
||||
static constexpr Mode_t MODE_UNDEFINED = -2;
|
||||
|
||||
//! To avoid checks against magic number "0".
|
||||
static const Submode_t SUBMODE_NONE = 0;
|
||||
|
||||
virtual ~HasModesIF() {}
|
||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||
|
@ -24,3 +24,13 @@ void ModeMessage::setCantReachMode(CommandMessage* message, ReturnValue_t reason
|
||||
message->setParameter(reason);
|
||||
message->setParameter2(0);
|
||||
}
|
||||
|
||||
void ModeMessage::setModeAnnounceMessage(CommandMessage& message, bool recursive) {
|
||||
Command_t cmd;
|
||||
if (recursive) {
|
||||
cmd = CMD_MODE_ANNOUNCE_RECURSIVELY;
|
||||
} else {
|
||||
cmd = CMD_MODE_ANNOUNCE;
|
||||
}
|
||||
message.setCommand(cmd);
|
||||
}
|
||||
|
@ -1,43 +1,42 @@
|
||||
#ifndef FSFW_MODES_MODEMESSAGE_H_
|
||||
#define FSFW_MODES_MODEMESSAGE_H_
|
||||
|
||||
#include "../ipc/CommandMessage.h"
|
||||
#include "fsfw/ipc/CommandMessage.h"
|
||||
|
||||
typedef uint32_t Mode_t;
|
||||
typedef uint8_t Submode_t;
|
||||
|
||||
class ModeMessage {
|
||||
private:
|
||||
ModeMessage();
|
||||
|
||||
public:
|
||||
static const uint8_t MESSAGE_ID = messagetypes::MODE_COMMAND;
|
||||
static const Command_t CMD_MODE_COMMAND =
|
||||
MAKE_COMMAND_ID(0x01); //!> Command to set the specified Mode, replies are: REPLY_MODE_REPLY,
|
||||
//! REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any replies,
|
||||
//! as this will break the subsystem mode machine!!
|
||||
static const Command_t CMD_MODE_COMMAND_FORCED = MAKE_COMMAND_ID(
|
||||
0xF1); //!> Command to set the specified Mode, regardless of external control flag, replies
|
||||
//! are: REPLY_MODE_REPLY, REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any
|
||||
//! replies, as this will break the subsystem mode machine!!
|
||||
static const Command_t REPLY_MODE_REPLY =
|
||||
MAKE_COMMAND_ID(0x02); //!> Reply to a CMD_MODE_COMMAND or CMD_MODE_READ
|
||||
static const Command_t REPLY_MODE_INFO =
|
||||
MAKE_COMMAND_ID(0x03); //!> Unrequested info about the current mode (used for composites to
|
||||
//! inform their container of a changed mode)
|
||||
static const Command_t REPLY_CANT_REACH_MODE = MAKE_COMMAND_ID(
|
||||
0x04); //!> Reply in case a mode command can't be executed. Par1: returnCode, Par2: 0
|
||||
static const Command_t REPLY_WRONG_MODE_REPLY =
|
||||
MAKE_COMMAND_ID(0x05); //!> Reply to a CMD_MODE_COMMAND, indicating that a mode was commanded
|
||||
//! and a transition started but was aborted; the parameters contain
|
||||
//! the mode that was reached
|
||||
static const Command_t CMD_MODE_READ = MAKE_COMMAND_ID(
|
||||
0x06); //!> Command to read the current mode and reply with a REPLY_MODE_REPLY
|
||||
static const Command_t CMD_MODE_ANNOUNCE = MAKE_COMMAND_ID(
|
||||
0x07); //!> Command to trigger an ModeInfo Event. This command does NOT have a reply.
|
||||
static const Command_t CMD_MODE_ANNOUNCE_RECURSIVELY =
|
||||
MAKE_COMMAND_ID(0x08); //!> Command to trigger an ModeInfo Event and to send this command to
|
||||
//! every child. This command does NOT have a reply.
|
||||
//!> Command to set the specified Mode, replies are: REPLY_MODE_REPLY,
|
||||
//! REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any replies,
|
||||
//! as this will break the subsystem mode machine!!
|
||||
static const Command_t CMD_MODE_COMMAND = MAKE_COMMAND_ID(0x01);
|
||||
//!> Command to set the specified Mode, regardless of external control flag, replies
|
||||
//! are: REPLY_MODE_REPLY, REPLY_WRONG_MODE_REPLY, and REPLY_REJECTED; don't add any
|
||||
//! replies, as this will break the subsystem mode machine!!
|
||||
static const Command_t CMD_MODE_COMMAND_FORCED = MAKE_COMMAND_ID(0xF1);
|
||||
//!> Reply to a CMD_MODE_COMMAND or CMD_MODE_READ
|
||||
static const Command_t REPLY_MODE_REPLY = MAKE_COMMAND_ID(0x02);
|
||||
//!> Unrequested info about the current mode (used for composites to
|
||||
//! inform their container of a changed mode)
|
||||
static const Command_t REPLY_MODE_INFO = MAKE_COMMAND_ID(0x03);
|
||||
//!> Reply in case a mode command can't be executed. Par1: returnCode, Par2: 0
|
||||
static const Command_t REPLY_CANT_REACH_MODE = MAKE_COMMAND_ID(0x04);
|
||||
//!> Reply to a CMD_MODE_COMMAND, indicating that a mode was commanded
|
||||
//! and a transition started but was aborted; the parameters contain
|
||||
//! the mode that was reached
|
||||
static const Command_t REPLY_WRONG_MODE_REPLY = MAKE_COMMAND_ID(0x05);
|
||||
//!> Command to read the current mode and reply with a REPLY_MODE_REPLY
|
||||
static const Command_t CMD_MODE_READ = MAKE_COMMAND_ID(0x06);
|
||||
//!> Command to trigger an ModeInfo Event. This command does NOT have a reply.
|
||||
static const Command_t CMD_MODE_ANNOUNCE = MAKE_COMMAND_ID(0x07);
|
||||
//!> Command to trigger an ModeInfo Event and to send this command to
|
||||
//! every child. This command does NOT have a reply.
|
||||
static const Command_t CMD_MODE_ANNOUNCE_RECURSIVELY = MAKE_COMMAND_ID(0x08);
|
||||
|
||||
ModeMessage() = delete;
|
||||
|
||||
static Mode_t getMode(const CommandMessage* message);
|
||||
static Submode_t getSubmode(const CommandMessage* message);
|
||||
@ -45,6 +44,7 @@ class ModeMessage {
|
||||
|
||||
static void setModeMessage(CommandMessage* message, Command_t command, Mode_t mode,
|
||||
Submode_t submode);
|
||||
static void setModeAnnounceMessage(CommandMessage& message, bool recursive);
|
||||
static void setCantReachMode(CommandMessage* message, ReturnValue_t reason);
|
||||
static void clear(CommandMessage* message);
|
||||
};
|
||||
|
@ -95,13 +95,16 @@ void ObjectManager::initialize() {
|
||||
for (auto const& it : objectList) {
|
||||
result = it.second->initialize();
|
||||
if (result != returnvalue::OK) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
object_id_t var = it.first;
|
||||
sif::error << "ObjectManager::initialize: Object 0x" << std::hex << std::setw(8)
|
||||
<< std::setfill('0') << var
|
||||
<< " failed to "
|
||||
"initialize with code 0x"
|
||||
<< result << std::dec << std::setfill(' ') << std::endl;
|
||||
<< std::setfill('0') << it.first << " failed to initialize with code 0x" << result
|
||||
<< std::dec << std::setfill(' ') << std::endl;
|
||||
#else
|
||||
sif::printError(
|
||||
"ObjectManager::initialize: Object 0x%08x failed to initialize with code 0x%04x\n", var,
|
||||
it.first);
|
||||
#endif
|
||||
#endif
|
||||
errorCount++;
|
||||
}
|
||||
|
@ -16,7 +16,9 @@ elseif(FSFW_OSAL MATCHES "host")
|
||||
|
||||
else()
|
||||
|
||||
message(WARNING "The OS_FSFW variable was not set. Assuming host OS..")
|
||||
message(
|
||||
WARNING
|
||||
"${MSG_PREFIX} The FSFW_OSAL variable was not set. Assuming host OS..")
|
||||
# Not set. Assumuing this is a host build, try to determine host OS
|
||||
if(WIN32)
|
||||
add_subdirectory(host)
|
||||
|
@ -26,12 +26,12 @@
|
||||
const std::string TcpTmTcServer::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT;
|
||||
|
||||
TcpTmTcServer::TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
|
||||
size_t receptionBufferSize, size_t ringBufferSize,
|
||||
std::string customTcpServerPort, ReceptionModes receptionMode)
|
||||
TcpTmTcServer::TcpConfig cfg, size_t receptionBufferSize,
|
||||
size_t ringBufferSize, ReceptionModes receptionMode)
|
||||
: SystemObject(objectId),
|
||||
tmtcBridgeId(tmtcTcpBridge),
|
||||
receptionMode(receptionMode),
|
||||
tcpConfig(std::move(customTcpServerPort)),
|
||||
tcpConfig(cfg),
|
||||
receptionBuffer(receptionBufferSize),
|
||||
ringBuffer(ringBufferSize, true) {}
|
||||
|
||||
@ -91,6 +91,15 @@ ReturnValue_t TcpTmTcServer::initialize() {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
if (tcpConfig.reuseAddr) {
|
||||
unsigned int enable = 1;
|
||||
setsockopt(listenerTcpSocket, SOL_SOCKET, SO_REUSEADDR, &enable, sizeof(enable));
|
||||
}
|
||||
if (tcpConfig.reusePort) {
|
||||
unsigned int enable = 1;
|
||||
setsockopt(listenerTcpSocket, SOL_SOCKET, SO_REUSEPORT, &enable, sizeof(enable));
|
||||
}
|
||||
|
||||
// Bind to the address found by getaddrinfo
|
||||
retval = bind(listenerTcpSocket, addrResult->ai_addr, static_cast<int>(addrResult->ai_addrlen));
|
||||
if (retval == SOCKET_ERROR) {
|
||||
@ -274,6 +283,8 @@ ReturnValue_t TcpTmTcServer::handleTmSending(socket_t connSocket, bool& tmSent)
|
||||
ConstStorageAccessor storeAccessor(storeId);
|
||||
ReturnValue_t result = tmStore->getData(storeId, storeAccessor);
|
||||
if (result != returnvalue::OK) {
|
||||
// Invalid entry, pop FIFO
|
||||
tmtcBridge->tmFifo->pop();
|
||||
return result;
|
||||
}
|
||||
if (wiretappingEnabled) {
|
||||
|
@ -41,11 +41,11 @@ class SpacePacketParser;
|
||||
*/
|
||||
class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableObjectIF {
|
||||
public:
|
||||
enum class ReceptionModes { SPACE_PACKETS };
|
||||
|
||||
struct TcpConfig {
|
||||
public:
|
||||
explicit TcpConfig(std::string tcpPort) : tcpPort(std::move(tcpPort)) {}
|
||||
TcpConfig(bool reuseAddr, bool reusePort) : reuseAddr(reuseAddr), reusePort(reusePort) {}
|
||||
TcpConfig(std::string tcpPort, bool reuseAddr, bool reusePort)
|
||||
: tcpPort(std::move(tcpPort)), reuseAddr(reuseAddr), reusePort(reusePort) {}
|
||||
|
||||
/**
|
||||
* Passed to the recv call
|
||||
@ -63,8 +63,23 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
|
||||
*/
|
||||
int tcpTmFlags = 0;
|
||||
|
||||
const std::string tcpPort;
|
||||
/**
|
||||
* Sets the SO_REUSEADDR option on the socket. See
|
||||
* https://man7.org/linux/man-pages/man7/socket.7.html for more details. This option is
|
||||
* especially useful in a debugging and development environment where an OBSW image might be
|
||||
* re-flashed oftentimes and where all incoming telecommands are received on a dedicated TCP
|
||||
* port.
|
||||
*/
|
||||
bool reuseAddr = false;
|
||||
/**
|
||||
* Sets the SO_REUSEPORT option on the socket. See
|
||||
* https://man7.org/linux/man-pages/man7/socket.7.html for more details.
|
||||
*/
|
||||
bool reusePort = false;
|
||||
|
||||
std::string tcpPort = DEFAULT_SERVER_PORT;
|
||||
};
|
||||
enum class ReceptionModes { SPACE_PACKETS };
|
||||
|
||||
static const std::string DEFAULT_SERVER_PORT;
|
||||
|
||||
@ -80,10 +95,9 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb
|
||||
* size will be the Ethernet MTU size
|
||||
* @param customTcpServerPort The user can specify another port than the default (7301) here.
|
||||
*/
|
||||
TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge,
|
||||
TcpTmTcServer(object_id_t objectId, object_id_t tmtcTcpBridge, TcpTmTcServer::TcpConfig cfg,
|
||||
size_t receptionBufferSize = RING_BUFFER_SIZE,
|
||||
size_t ringBufferSize = RING_BUFFER_SIZE,
|
||||
std::string customTcpServerPort = DEFAULT_SERVER_PORT,
|
||||
ReceptionModes receptionMode = ReceptionModes::SPACE_PACKETS);
|
||||
~TcpTmTcServer() override;
|
||||
|
||||
|
@ -66,7 +66,8 @@ class HasParametersIF {
|
||||
* @param newValues
|
||||
* @param startAtIndex Linear index, runs left to right, top to bottom for
|
||||
* matrix indexes.
|
||||
* @return
|
||||
* @return returnvalue::OK if parameter is valid and a set function of the parameter wrapper was
|
||||
* called.
|
||||
*/
|
||||
virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueIdentifier,
|
||||
ParameterWrapper *parameterWrapper,
|
||||
|
@ -211,9 +211,13 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
|
||||
if (data == nullptr) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "ParameterWrapper::copyFrom: Called on read-only variable!" << std::endl;
|
||||
sif::warning << "ParameterWrapper::copyFrom: Called on read-only variable or "
|
||||
"data pointer not set"
|
||||
<< std::endl;
|
||||
#else
|
||||
sif::printWarning("ParameterWrapper::copyFrom: Called on read-only variable!\n");
|
||||
sif::printWarning(
|
||||
"ParameterWrapper::copyFrom: Called on read-only variable "
|
||||
"or data pointer not set\n");
|
||||
#endif
|
||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||
return READONLY;
|
||||
@ -222,9 +226,9 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
|
||||
if (from->readonlyData == nullptr) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "ParameterWrapper::copyFrom: Source not set!" << std::endl;
|
||||
sif::warning << "ParameterWrapper::copyFrom: Source not set" << std::endl;
|
||||
#else
|
||||
sif::printWarning("ParameterWrapper::copyFrom: Source not set!\n");
|
||||
sif::printWarning("ParameterWrapper::copyFrom: Source not set\n");
|
||||
#endif
|
||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||
return SOURCE_NOT_SET;
|
||||
@ -233,9 +237,9 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
|
||||
if (type != from->type) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "ParameterWrapper::copyFrom: Datatype missmatch!" << std::endl;
|
||||
sif::warning << "ParameterWrapper::copyFrom: Datatype missmatch" << std::endl;
|
||||
#else
|
||||
sif::printWarning("ParameterWrapper::copyFrom: Datatype missmatch!\n");
|
||||
sif::printWarning("ParameterWrapper::copyFrom: Datatype missmatch\n");
|
||||
#endif
|
||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||
return DATATYPE_MISSMATCH;
|
||||
@ -245,9 +249,9 @@ ReturnValue_t ParameterWrapper::copyFrom(const ParameterWrapper *from,
|
||||
if (rows == 0 or columns == 0) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "ParameterWrapper::copyFrom: Columns or rows zero!" << std::endl;
|
||||
sif::warning << "ParameterWrapper::copyFrom: Columns or rows zero" << std::endl;
|
||||
#else
|
||||
sif::printWarning("ParameterWrapper::copyFrom: Columns or rows zero!\n");
|
||||
sif::printWarning("ParameterWrapper::copyFrom: Columns or rows zero\n");
|
||||
#endif
|
||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||
return COLUMN_OR_ROWS_ZERO;
|
||||
|
@ -29,9 +29,9 @@ class PowerSwitchIF {
|
||||
static const ReturnValue_t FUSE_ON = MAKE_RETURN_CODE(3);
|
||||
static const ReturnValue_t FUSE_OFF = MAKE_RETURN_CODE(4);
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PCDU_2;
|
||||
static const Event SWITCH_WENT_OFF = MAKE_EVENT(
|
||||
0, severity::LOW); //!< Someone detected that a switch went off which shouldn't. Severity:
|
||||
//!< Low, Parameter1: switchId1, Parameter2: switchId2
|
||||
//!< Someone detected that a switch went off which shouldn't. Severity:
|
||||
//!< Low, Parameter1: switchId1, Parameter2: switchId2
|
||||
static const Event SWITCH_WENT_OFF = MAKE_EVENT(0, severity::LOW);
|
||||
/**
|
||||
* send a direct command to the Power Unit to enable/disable the specified switch.
|
||||
*
|
||||
|
@ -3,7 +3,7 @@
|
||||
#include <fsfw/ipc/QueueFactory.h>
|
||||
#include <fsfw/power/PowerSwitchIF.h>
|
||||
|
||||
PowerSwitcherComponent::PowerSwitcherComponent(object_id_t objectId, PowerSwitchIF *pwrSwitcher,
|
||||
PowerSwitcherComponent::PowerSwitcherComponent(object_id_t objectId, PowerSwitchIF* pwrSwitcher,
|
||||
power::Switch_t pwrSwitch)
|
||||
: SystemObject(objectId),
|
||||
switcher(pwrSwitcher, pwrSwitch),
|
||||
@ -54,7 +54,7 @@ ReturnValue_t PowerSwitcherComponent::initialize() {
|
||||
|
||||
MessageQueueId_t PowerSwitcherComponent::getCommandQueue() const { return queue->getId(); }
|
||||
|
||||
void PowerSwitcherComponent::getMode(Mode_t *mode, Submode_t *submode) {
|
||||
void PowerSwitcherComponent::getMode(Mode_t* mode, Submode_t* submode) {
|
||||
*mode = this->mode;
|
||||
*submode = this->submode;
|
||||
}
|
||||
@ -65,7 +65,7 @@ ReturnValue_t PowerSwitcherComponent::setHealth(HealthState health) {
|
||||
}
|
||||
|
||||
ReturnValue_t PowerSwitcherComponent::checkModeCommand(Mode_t mode, Submode_t submode,
|
||||
uint32_t *msToReachTheMode) {
|
||||
uint32_t* msToReachTheMode) {
|
||||
*msToReachTheMode = 5000;
|
||||
if (mode != MODE_ON and mode != MODE_OFF) {
|
||||
return TRANS_NOT_ALLOWED;
|
||||
@ -105,3 +105,15 @@ void PowerSwitcherComponent::setMode(Mode_t newMode, Submode_t newSubmode) {
|
||||
}
|
||||
|
||||
HasHealthIF::HealthState PowerSwitcherComponent::getHealth() { return healthHelper.getHealth(); }
|
||||
|
||||
const HasHealthIF* PowerSwitcherComponent::getOptHealthIF() const { return this; }
|
||||
|
||||
const HasModesIF& PowerSwitcherComponent::getModeIF() const { return *this; }
|
||||
|
||||
ReturnValue_t PowerSwitcherComponent::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
|
||||
return parent.registerChild(*this);
|
||||
}
|
||||
|
||||
object_id_t PowerSwitcherComponent::getObjectId() const { return SystemObject::getObjectId(); }
|
||||
|
||||
ModeTreeChildIF& PowerSwitcherComponent::getModeTreeChildIF() { return *this; }
|
||||
|
@ -8,6 +8,8 @@
|
||||
#include <fsfw/objectmanager/SystemObject.h>
|
||||
#include <fsfw/power/PowerSwitcher.h>
|
||||
#include <fsfw/power/definitions.h>
|
||||
#include <fsfw/subsystem/ModeTreeChildIF.h>
|
||||
#include <fsfw/subsystem/ModeTreeConnectionIF.h>
|
||||
#include <fsfw/tasks/ExecutableObjectIF.h>
|
||||
|
||||
class PowerSwitchIF;
|
||||
@ -24,12 +26,17 @@ class PowerSwitchIF;
|
||||
*/
|
||||
class PowerSwitcherComponent : public SystemObject,
|
||||
public ExecutableObjectIF,
|
||||
public ModeTreeChildIF,
|
||||
public ModeTreeConnectionIF,
|
||||
public HasModesIF,
|
||||
public HasHealthIF {
|
||||
public:
|
||||
PowerSwitcherComponent(object_id_t objectId, PowerSwitchIF *pwrSwitcher,
|
||||
power::Switch_t pwrSwitch);
|
||||
|
||||
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF &parent) override;
|
||||
ModeTreeChildIF &getModeTreeChildIF() override;
|
||||
|
||||
private:
|
||||
MessageQueueIF *queue = nullptr;
|
||||
PowerSwitcher switcher;
|
||||
@ -56,6 +63,10 @@ class PowerSwitcherComponent : public SystemObject,
|
||||
|
||||
ReturnValue_t setHealth(HealthState health) override;
|
||||
HasHealthIF::HealthState getHealth() override;
|
||||
|
||||
object_id_t getObjectId() const override;
|
||||
const HasHealthIF *getOptHealthIF() const override;
|
||||
const HasModesIF &getModeIF() const override;
|
||||
};
|
||||
|
||||
#endif /* _FSFW_POWER_POWERSWITCHERCOMPONENT_H_ */
|
||||
|
@ -20,6 +20,7 @@ ReturnValue_t CService200ModeCommanding::isValidSubservice(uint8_t subservice) {
|
||||
case (Subservice::COMMAND_MODE_COMMAND):
|
||||
case (Subservice::COMMAND_MODE_READ):
|
||||
case (Subservice::COMMAND_MODE_ANNCOUNCE):
|
||||
case (Subservice::COMMAND_MODE_ANNOUNCE_RECURSIVELY):
|
||||
return returnvalue::OK;
|
||||
default:
|
||||
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
|
||||
@ -53,15 +54,26 @@ ReturnValue_t CService200ModeCommanding::checkInterfaceAndAcquireMessageQueue(
|
||||
ReturnValue_t CService200ModeCommanding::prepareCommand(CommandMessage *message, uint8_t subservice,
|
||||
const uint8_t *tcData, size_t tcDataLen,
|
||||
uint32_t *state, object_id_t objectId) {
|
||||
ModePacket modeCommandPacket;
|
||||
ReturnValue_t result =
|
||||
modeCommandPacket.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
if (subservice == Subservice::COMMAND_MODE_ANNCOUNCE or
|
||||
subservice == Subservice::COMMAND_MODE_ANNOUNCE_RECURSIVELY) {
|
||||
bool recursive = true;
|
||||
if (subservice == Subservice::COMMAND_MODE_ANNCOUNCE) {
|
||||
recursive = false;
|
||||
}
|
||||
ModeMessage::setModeAnnounceMessage(*message, recursive);
|
||||
} else {
|
||||
ModePacket modeCommandPacket;
|
||||
ReturnValue_t result =
|
||||
modeCommandPacket.deSerialize(&tcData, &tcDataLen, SerializeIF::Endianness::BIG);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
ModeMessage::setModeMessage(message, ModeMessage::CMD_MODE_COMMAND, modeCommandPacket.getMode(),
|
||||
modeCommandPacket.getSubmode());
|
||||
}
|
||||
|
||||
ModeMessage::setModeMessage(message, ModeMessage::CMD_MODE_COMMAND, modeCommandPacket.getMode(),
|
||||
modeCommandPacket.getSubmode());
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -2,12 +2,12 @@
|
||||
|
||||
#include <cstddef>
|
||||
|
||||
#include "fsfw/globalfunctions/CRC.h"
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
#include "fsfw/serialize/SerializeAdapter.h"
|
||||
#include "fsfw/serviceinterface.h"
|
||||
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
|
||||
#include "fsfw/tmtcpacket/pus/tc/PusTcIF.h"
|
||||
#include "fsfw/globalfunctions/CRC.h"
|
||||
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
|
||||
|
||||
static constexpr auto DEF_END = SerializeIF::Endianness::BIG;
|
||||
|
||||
@ -79,7 +79,7 @@ inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::performService
|
||||
// NOTE: The iterator is increased in the loop here. Increasing the iterator as for-loop arg
|
||||
// does not work in this case as we are deleting the current element here.
|
||||
for (auto it = telecommandMap.begin(); it != telecommandMap.end();) {
|
||||
if (it->first <= tNow.tv_sec) {
|
||||
if (it->first <= static_cast<uint32_t>(tNow.tv_sec)) {
|
||||
if (schedulingEnabled) {
|
||||
// release tc
|
||||
TmTcMessage releaseMsg(it->second.storeAddr);
|
||||
@ -180,7 +180,7 @@ inline ReturnValue_t Service11TelecommandScheduling<MAX_NUM_TCS>::doInsertActivi
|
||||
if (CRC::crc16ccitt(data, size) != 0) {
|
||||
return CONTAINED_TC_CRC_MISSMATCH;
|
||||
}
|
||||
|
||||
|
||||
// store currentPacket and receive the store address
|
||||
store_address_t addr{};
|
||||
if (tcStore->addData(&addr, data, size) != returnvalue::OK ||
|
||||
|
@ -1,5 +1,7 @@
|
||||
#include "fsfw/pus/Service17Test.h"
|
||||
|
||||
#include <fsfw/serialize/SerializeElement.h>
|
||||
|
||||
#include "fsfw/FSFW.h"
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
#include "fsfw/objectmanager/SystemObject.h"
|
||||
@ -31,6 +33,15 @@ ReturnValue_t Service17Test::handleRequest(uint8_t subservice) {
|
||||
}
|
||||
return tmHelper.storeAndSendTmPacket();
|
||||
}
|
||||
case Subservice::PING_WITH_DATA: {
|
||||
SerializeElement<uint32_t> receivedDataLen = currentPacket.getUserDataLen();
|
||||
ReturnValue_t result =
|
||||
tmHelper.prepareTmPacket(Subservice::PING_WITH_DATA_REPORT_WITH_SIZE, receivedDataLen);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
return tmHelper.storeAndSendTmPacket();
|
||||
}
|
||||
default:
|
||||
return AcceptsTelecommandsIF::INVALID_SUBSERVICE;
|
||||
}
|
||||
|
@ -32,6 +32,9 @@ class Service17Test : public PusServiceBase {
|
||||
CONNECTION_TEST_REPORT = 2,
|
||||
//! [EXPORT] : [COMMAND] Trigger test reply and test event
|
||||
EVENT_TRIGGER_TEST = 128,
|
||||
PING_WITH_DATA = 129,
|
||||
//! [EXPORT] : [COMMAND] Report which reports the sent user data size
|
||||
PING_WITH_DATA_REPORT_WITH_SIZE = 130
|
||||
};
|
||||
|
||||
explicit Service17Test(PsbParams params);
|
||||
|
@ -208,17 +208,17 @@ ReturnValue_t Service3Housekeeping::handleReply(const CommandMessage* reply,
|
||||
ReturnValue_t error = returnvalue::FAILED;
|
||||
HousekeepingMessage::getHkRequestFailureReply(reply, &error);
|
||||
failureParameter2 = error;
|
||||
return CommandingServiceBase::EXECUTION_COMPLETE;
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
default:
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "Service3Housekeeping::handleReply: Invalid reply with "
|
||||
<< "reply command " << command << "!" << std::endl;
|
||||
<< "reply command " << command << std::endl;
|
||||
#else
|
||||
sif::printWarning(
|
||||
"Service3Housekeeping::handleReply: Invalid reply with "
|
||||
"reply command %hu!\n",
|
||||
"reply command %hu\n",
|
||||
command);
|
||||
#endif
|
||||
return CommandingServiceBase::INVALID_REPLY;
|
||||
@ -248,19 +248,28 @@ void Service3Housekeeping::handleUnrequestedReply(CommandMessage* reply) {
|
||||
case (HousekeepingMessage::HK_REQUEST_FAILURE): {
|
||||
break;
|
||||
}
|
||||
case (CommandMessage::REPLY_REJECTED): {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "Service3Housekeeping::handleUnrequestedReply: Unexpected reply "
|
||||
"rejected with error code"
|
||||
<< reply->getParameter() << std::endl;
|
||||
#else
|
||||
#endif
|
||||
break;
|
||||
}
|
||||
|
||||
default: {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "Service3Housekeeping::handleUnrequestedReply: Invalid reply with reply "
|
||||
"command "
|
||||
<< command << "!" << std::endl;
|
||||
<< command << "" << std::endl;
|
||||
#else
|
||||
sif::printWarning(
|
||||
"Service3Housekeeping::handleUnrequestedReply: Invalid reply with "
|
||||
"reply command %hu!\n",
|
||||
"reply command %hu\n",
|
||||
command);
|
||||
#endif
|
||||
return;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -275,6 +284,7 @@ void Service3Housekeeping::handleUnrequestedReply(CommandMessage* reply) {
|
||||
"Could not generate reply!\n");
|
||||
#endif
|
||||
}
|
||||
CommandingServiceBase::handleUnrequestedReply(reply);
|
||||
}
|
||||
|
||||
MessageQueueId_t Service3Housekeeping::getHkQueue() const { return commandQueue->getId(); }
|
||||
|
@ -13,8 +13,10 @@ Service5EventReporting::Service5EventReporting(PsbParams params, size_t maxNumbe
|
||||
storeHelper(params.apid),
|
||||
tmHelper(params.serviceId, storeHelper, sendHelper),
|
||||
maxNumberReportsPerCycle(maxNumberReportsPerCycle) {
|
||||
auto mqArgs = MqArgs(getObjectId(), static_cast<void*>(this));
|
||||
psbParams.name = "PUS 5 Event Reporting";
|
||||
eventQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth);
|
||||
eventQueue = QueueFactory::instance()->createMessageQueue(
|
||||
messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
}
|
||||
|
||||
Service5EventReporting::~Service5EventReporting() {
|
||||
@ -38,9 +40,6 @@ ReturnValue_t Service5EventReporting::performService() {
|
||||
}
|
||||
}
|
||||
}
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "Service5EventReporting::generateEventReport: Too many events" << std::endl;
|
||||
#endif
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
|
@ -42,7 +42,7 @@
|
||||
class Service5EventReporting : public PusServiceBase {
|
||||
public:
|
||||
Service5EventReporting(PsbParams params, size_t maxNumberReportsPerCycle = 10,
|
||||
uint32_t messageQueueDepth = 10);
|
||||
uint32_t messageQueueDepth = 20);
|
||||
~Service5EventReporting() override;
|
||||
|
||||
/***
|
||||
|
@ -6,10 +6,10 @@
|
||||
class Service9TimeManagement : public PusServiceBase {
|
||||
public:
|
||||
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_9;
|
||||
static constexpr Event CLOCK_SET =
|
||||
MAKE_EVENT(0, severity::INFO); //!< Clock has been set. P1: New Uptime. P2: Old Uptime
|
||||
static constexpr Event CLOCK_SET_FAILURE =
|
||||
MAKE_EVENT(1, severity::LOW); //!< Clock could not be set. P1: Returncode.
|
||||
//!< Clock has been set. P1: New Uptime. P2: Old Uptime
|
||||
static constexpr Event CLOCK_SET = MAKE_EVENT(0, severity::INFO);
|
||||
//!< Clock could not be set. P1: Returncode.
|
||||
static constexpr Event CLOCK_SET_FAILURE = MAKE_EVENT(1, severity::LOW);
|
||||
|
||||
static constexpr uint8_t CLASS_ID = CLASS_ID::PUS_SERVICE_9;
|
||||
|
||||
|
@ -1,9 +1,9 @@
|
||||
#ifndef FSFW_PUS_SERVICEPACKETS_SERVICE200PACKETS_H_
|
||||
#define FSFW_PUS_SERVICEPACKETS_SERVICE200PACKETS_H_
|
||||
|
||||
#include "../../modes/ModeMessage.h"
|
||||
#include "../../serialize/SerialLinkedListAdapter.h"
|
||||
#include "../../serialize/SerializeIF.h"
|
||||
#include "fsfw/modes/ModeMessage.h"
|
||||
#include "fsfw/serialize/SerialLinkedListAdapter.h"
|
||||
#include "fsfw/serialize/SerializeIF.h"
|
||||
|
||||
/**
|
||||
* @brief Subservice 1, 2, 3, 4, 5
|
||||
|
@ -1,3 +1,4 @@
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE Subsystem.cpp SubsystemBase.cpp)
|
||||
target_sources(${LIB_FSFW_NAME} PRIVATE Subsystem.cpp SubsystemBase.cpp
|
||||
helper.cpp)
|
||||
|
||||
add_subdirectory(modes)
|
||||
|
13
src/fsfw/subsystem/HasModeTreeChildrenIF.h
Normal file
13
src/fsfw/subsystem/HasModeTreeChildrenIF.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef FSFW_SUBSYSTEM_HASMODETREECHILDRENIF_H_
|
||||
#define FSFW_SUBSYSTEM_HASMODETREECHILDRENIF_H_
|
||||
|
||||
#include "ModeTreeChildIF.h"
|
||||
|
||||
class HasModeTreeChildrenIF {
|
||||
public:
|
||||
virtual ~HasModeTreeChildrenIF() = default;
|
||||
virtual ReturnValue_t registerChild(const ModeTreeChildIF& child) = 0;
|
||||
virtual MessageQueueId_t getCommandQueue() const = 0;
|
||||
};
|
||||
|
||||
#endif // FSFW_SUBSYSTEM_HASMODETREECHILDRENIF_H_
|
15
src/fsfw/subsystem/ModeTreeChildIF.h
Normal file
15
src/fsfw/subsystem/ModeTreeChildIF.h
Normal file
@ -0,0 +1,15 @@
|
||||
#ifndef FSFW_SUBSYSTEM_MODETREECHILDIF_H_
|
||||
#define FSFW_SUBSYSTEM_MODETREECHILDIF_H_
|
||||
|
||||
#include <fsfw/health/HasHealthIF.h>
|
||||
#include <fsfw/modes/HasModesIF.h>
|
||||
|
||||
class ModeTreeChildIF {
|
||||
public:
|
||||
virtual ~ModeTreeChildIF() = default;
|
||||
virtual object_id_t getObjectId() const = 0;
|
||||
virtual const HasHealthIF* getOptHealthIF() const = 0;
|
||||
virtual const HasModesIF& getModeIF() const = 0;
|
||||
};
|
||||
|
||||
#endif /* FSFW_SUBSYSTEM_MODETREECHILDIF_H_ */
|
13
src/fsfw/subsystem/ModeTreeConnectionIF.h
Normal file
13
src/fsfw/subsystem/ModeTreeConnectionIF.h
Normal file
@ -0,0 +1,13 @@
|
||||
#ifndef FSFW_SUBSYSTEM_MODES_MODETREECONNECTIONIF_H_
|
||||
#define FSFW_SUBSYSTEM_MODES_MODETREECONNECTIONIF_H_
|
||||
|
||||
#include "fsfw/subsystem/HasModeTreeChildrenIF.h"
|
||||
|
||||
class ModeTreeConnectionIF {
|
||||
public:
|
||||
virtual ~ModeTreeConnectionIF() = default;
|
||||
virtual ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF& parent) = 0;
|
||||
virtual ModeTreeChildIF& getModeTreeChildIF() = 0;
|
||||
};
|
||||
|
||||
#endif /* FSFW_SRC_FSFW_SUBSYSTEM_MODES_MODETREECONNECTIONIF_H_ */
|
@ -9,9 +9,9 @@
|
||||
#include "fsfw/serialize/SerialLinkedListAdapter.h"
|
||||
#include "fsfw/serialize/SerializeElement.h"
|
||||
|
||||
Subsystem::Subsystem(object_id_t setObjectId, object_id_t parent, uint32_t maxNumberOfSequences,
|
||||
Subsystem::Subsystem(object_id_t setObjectId, uint32_t maxNumberOfSequences,
|
||||
uint32_t maxNumberOfTables)
|
||||
: SubsystemBase(setObjectId, parent, 0),
|
||||
: SubsystemBase(setObjectId, 0),
|
||||
isInTransition(false),
|
||||
childrenChangedHealth(false),
|
||||
currentTargetTable(),
|
||||
@ -36,6 +36,13 @@ ReturnValue_t Subsystem::checkSequence(HybridIterator<ModeListEntry> iter,
|
||||
|
||||
for (; iter.value != nullptr; ++iter) {
|
||||
if (!existsModeTable(iter->getTableId())) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
using namespace std;
|
||||
sif::warning << "Subsystem::checkSequence: "
|
||||
<< "Object " << setfill('0') << hex << "0x" << setw(8) << getObjectId()
|
||||
<< setw(0) << ": Mode table for mode ID "
|
||||
<< "0x" << setw(8) << iter->getTableId() << " does not exist" << dec << endl;
|
||||
#endif
|
||||
return TABLE_DOES_NOT_EXIST;
|
||||
} else {
|
||||
ReturnValue_t result = checkTable(getTable(iter->getTableId()));
|
||||
|
@ -33,8 +33,12 @@ struct SequenceEntry : public TableSequenceBase {
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief TODO: documentation missing
|
||||
* @brief This class extends the SubsystemBase to perform the management of mode tables
|
||||
* and mode sequences
|
||||
* @details
|
||||
* This class is able to use mode tables and sequences to command all its children into the
|
||||
* right mode. Fallback sequences can be used to handle failed transitions or have a fallback
|
||||
* in case a component can't keep its current mode.
|
||||
*/
|
||||
class Subsystem : public SubsystemBase, public HasModeSequenceIF {
|
||||
public:
|
||||
@ -62,8 +66,7 @@ class Subsystem : public SubsystemBase, public HasModeSequenceIF {
|
||||
* @param maxNumberOfSequences
|
||||
* @param maxNumberOfTables
|
||||
*/
|
||||
Subsystem(object_id_t setObjectId, object_id_t parent, uint32_t maxNumberOfSequences,
|
||||
uint32_t maxNumberOfTables);
|
||||
Subsystem(object_id_t setObjectId, uint32_t maxNumberOfSequences, uint32_t maxNumberOfTables);
|
||||
virtual ~Subsystem();
|
||||
|
||||
ReturnValue_t addSequence(SequenceEntry sequence);
|
||||
|
@ -1,50 +1,24 @@
|
||||
#include "fsfw/subsystem/SubsystemBase.h"
|
||||
|
||||
#include "fsfw/FSFW.h"
|
||||
#include "fsfw/ipc/QueueFactory.h"
|
||||
#include "fsfw/objectmanager/ObjectManager.h"
|
||||
#include "fsfw/serviceinterface/ServiceInterface.h"
|
||||
#include "fsfw/serviceinterface.h"
|
||||
#include "fsfw/subsystem/helper.h"
|
||||
|
||||
SubsystemBase::SubsystemBase(object_id_t setObjectId, object_id_t parent, Mode_t initialMode,
|
||||
SubsystemBase::SubsystemBase(object_id_t setObjectId, Mode_t initialMode,
|
||||
uint16_t commandQueueDepth)
|
||||
: SystemObject(setObjectId),
|
||||
mode(initialMode),
|
||||
commandQueue(QueueFactory::instance()->createMessageQueue(commandQueueDepth,
|
||||
CommandMessage::MAX_MESSAGE_SIZE)),
|
||||
healthHelper(this, setObjectId),
|
||||
modeHelper(this),
|
||||
parentId(parent) {}
|
||||
modeHelper(this) {
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
commandQueueDepth, CommandMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
}
|
||||
|
||||
SubsystemBase::~SubsystemBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); }
|
||||
|
||||
ReturnValue_t SubsystemBase::registerChild(object_id_t objectId) {
|
||||
ChildInfo info;
|
||||
|
||||
HasModesIF* child = ObjectManager::instance()->get<HasModesIF>(objectId);
|
||||
// This is a rather ugly hack to have the changedHealth info for all
|
||||
// children available.
|
||||
HasHealthIF* healthChild = ObjectManager::instance()->get<HasHealthIF>(objectId);
|
||||
if (child == nullptr) {
|
||||
if (healthChild == nullptr) {
|
||||
return CHILD_DOESNT_HAVE_MODES;
|
||||
} else {
|
||||
info.commandQueue = healthChild->getCommandQueue();
|
||||
info.mode = MODE_OFF;
|
||||
}
|
||||
} else {
|
||||
info.commandQueue = child->getCommandQueue();
|
||||
info.mode = -1; // intentional to force an initial command during system startup
|
||||
}
|
||||
|
||||
info.submode = SUBMODE_NONE;
|
||||
info.healthChanged = false;
|
||||
|
||||
auto resultPair = childrenMap.emplace(objectId, info);
|
||||
if (not resultPair.second) {
|
||||
return COULD_NOT_INSERT_CHILD;
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t SubsystemBase::checkStateAgainstTable(HybridIterator<ModeListEntry> tableIter,
|
||||
Submode_t targetSubmode) {
|
||||
std::map<object_id_t, ChildInfo>::iterator childIter;
|
||||
@ -84,7 +58,8 @@ void SubsystemBase::executeTable(HybridIterator<ModeListEntry> tableIter, Submod
|
||||
if ((iter = childrenMap.find(object)) == childrenMap.end()) {
|
||||
// illegal table entry, should only happen due to misconfigured mode table
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::debug << std::hex << getObjectId() << ": invalid mode table entry" << std::endl;
|
||||
sif::debug << std::hex << SystemObject::getObjectId() << ": invalid mode table entry"
|
||||
<< std::endl;
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
@ -155,36 +130,15 @@ ReturnValue_t SubsystemBase::updateChildChangedHealth(MessageQueueId_t queue, bo
|
||||
MessageQueueId_t SubsystemBase::getCommandQueue() const { return commandQueue->getId(); }
|
||||
|
||||
ReturnValue_t SubsystemBase::initialize() {
|
||||
MessageQueueId_t parentQueue = MessageQueueIF::NO_QUEUE;
|
||||
ReturnValue_t result = SystemObject::initialize();
|
||||
|
||||
ReturnValue_t result = modeHelper.initialize();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
if (parentId != objects::NO_OBJECT) {
|
||||
SubsystemBase* parent = ObjectManager::instance()->get<SubsystemBase>(parentId);
|
||||
if (parent == nullptr) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
parentQueue = parent->getCommandQueue();
|
||||
|
||||
parent->registerChild(getObjectId());
|
||||
}
|
||||
|
||||
result = healthHelper.initialize(parentQueue);
|
||||
|
||||
result = healthHelper.initialize();
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
result = modeHelper.initialize(parentQueue);
|
||||
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
return returnvalue::OK;
|
||||
return SystemObject::initialize();
|
||||
}
|
||||
|
||||
ReturnValue_t SubsystemBase::performOperation(uint8_t opCode) {
|
||||
@ -237,8 +191,14 @@ ReturnValue_t SubsystemBase::handleModeReply(CommandMessage* message) {
|
||||
}
|
||||
|
||||
ReturnValue_t SubsystemBase::checkTable(HybridIterator<ModeListEntry> tableIter) {
|
||||
for (; tableIter.value != NULL; ++tableIter) {
|
||||
for (; tableIter.value != nullptr; ++tableIter) {
|
||||
if (childrenMap.find(tableIter.value->getObject()) == childrenMap.end()) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
using namespace std;
|
||||
sif::warning << "SubsystemBase::checkTable: Could not find object " << setfill('0') << hex
|
||||
<< "0x" << setw(8) << tableIter.value->getObject() << " in object " << setw(8)
|
||||
<< setw(0) << "0x" << setw(8) << SystemObject::getObjectId() << dec << std::endl;
|
||||
#endif
|
||||
return TABLE_CONTAINS_INVALID_OBJECT_ID;
|
||||
}
|
||||
}
|
||||
@ -323,4 +283,33 @@ ReturnValue_t SubsystemBase::setHealth(HealthState health) {
|
||||
|
||||
HasHealthIF::HealthState SubsystemBase::getHealth() { return healthHelper.getHealth(); }
|
||||
|
||||
ReturnValue_t SubsystemBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
|
||||
return modetree::connectModeTreeParent(parent, *this, &healthHelper, modeHelper);
|
||||
}
|
||||
|
||||
object_id_t SubsystemBase::getObjectId() const { return SystemObject::getObjectId(); }
|
||||
|
||||
void SubsystemBase::modeChanged() {}
|
||||
|
||||
ReturnValue_t SubsystemBase::registerChild(const ModeTreeChildIF& child) {
|
||||
ChildInfo info;
|
||||
|
||||
const HasModesIF& modeChild = child.getModeIF();
|
||||
// intentional to force an initial command during system startup
|
||||
info.commandQueue = modeChild.getCommandQueue();
|
||||
info.mode = HasModesIF::MODE_UNDEFINED;
|
||||
info.submode = SUBMODE_NONE;
|
||||
info.healthChanged = false;
|
||||
|
||||
auto resultPair = childrenMap.emplace(child.getObjectId(), info);
|
||||
if (not resultPair.second) {
|
||||
return COULD_NOT_INSERT_CHILD;
|
||||
}
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
const HasHealthIF* SubsystemBase::getOptHealthIF() const { return this; }
|
||||
|
||||
const HasModesIF& SubsystemBase::getModeIF() const { return *this; }
|
||||
|
||||
ModeTreeChildIF& SubsystemBase::getModeTreeChildIF() { return *this; }
|
||||
|
@ -3,23 +3,35 @@
|
||||
|
||||
#include <map>
|
||||
|
||||
#include "../container/HybridIterator.h"
|
||||
#include "../health/HasHealthIF.h"
|
||||
#include "../health/HealthHelper.h"
|
||||
#include "../ipc/MessageQueueIF.h"
|
||||
#include "../modes/HasModesIF.h"
|
||||
#include "../objectmanager/SystemObject.h"
|
||||
#include "../returnvalues/returnvalue.h"
|
||||
#include "../tasks/ExecutableObjectIF.h"
|
||||
#include "fsfw/container/HybridIterator.h"
|
||||
#include "fsfw/health/HasHealthIF.h"
|
||||
#include "fsfw/health/HealthHelper.h"
|
||||
#include "fsfw/ipc/MessageQueueIF.h"
|
||||
#include "fsfw/modes/HasModesIF.h"
|
||||
#include "fsfw/objectmanager/SystemObject.h"
|
||||
#include "fsfw/returnvalues/returnvalue.h"
|
||||
#include "fsfw/subsystem/HasModeTreeChildrenIF.h"
|
||||
#include "fsfw/subsystem/ModeTreeConnectionIF.h"
|
||||
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||
#include "modes/HasModeSequenceIF.h"
|
||||
|
||||
/**
|
||||
* @defgroup subsystems Subsystem Objects
|
||||
* Contains all Subsystem and Assemblies
|
||||
* All Subsystem and Assemblies can derive from this class. It contains helper classes to
|
||||
* perform mode and health handling, which allows OBSW developers to build a mode tree for
|
||||
* the whole satellite.
|
||||
*
|
||||
* Aside from setting up a mode tree and being able to executing mode tables, this class does not
|
||||
* provide an implementation on what to do with the features. To build a mode tree, helper classes
|
||||
* like the #AssemblyBase or the #Subsystem class extend and use the functionality of the base
|
||||
* class.
|
||||
*/
|
||||
class SubsystemBase : public SystemObject,
|
||||
public HasModesIF,
|
||||
public HasHealthIF,
|
||||
public HasModeTreeChildrenIF,
|
||||
public ModeTreeConnectionIF,
|
||||
public ModeTreeChildIF,
|
||||
public ExecutableObjectIF {
|
||||
public:
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::SUBSYSTEM_BASE;
|
||||
@ -29,32 +41,34 @@ class SubsystemBase : public SystemObject,
|
||||
static const ReturnValue_t COULD_NOT_INSERT_CHILD = MAKE_RETURN_CODE(0x04);
|
||||
static const ReturnValue_t TABLE_CONTAINS_INVALID_OBJECT_ID = MAKE_RETURN_CODE(0x05);
|
||||
|
||||
SubsystemBase(object_id_t setObjectId, object_id_t parent, Mode_t initialMode = 0,
|
||||
uint16_t commandQueueDepth = 8);
|
||||
SubsystemBase(object_id_t setObjectId, Mode_t initialMode = 0, uint16_t commandQueueDepth = 8);
|
||||
virtual ~SubsystemBase();
|
||||
|
||||
virtual MessageQueueId_t getCommandQueue() const override;
|
||||
|
||||
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF &parent) override;
|
||||
ModeTreeChildIF &getModeTreeChildIF() override;
|
||||
|
||||
/**
|
||||
* Function to register the child objects.
|
||||
* Performs a checks if the child does implement HasHealthIF and/or HasModesIF
|
||||
*
|
||||
* Also adds them to the internal childrenMap.
|
||||
* Also adds them to the internal childrenMap.
|
||||
*
|
||||
* @param objectId
|
||||
* @return returnvalue::OK if successful
|
||||
* CHILD_DOESNT_HAVE_MODES if Child is no HasHealthIF and no HasModesIF
|
||||
* COULD_NOT_INSERT_CHILD If the Child could not be added to the ChildrenMap
|
||||
* CHILD_DOESNT_HAVE_MODES if Child is no HasHealthIF and no HasModesIF
|
||||
* COULD_NOT_INSERT_CHILD If the Child could not be added to the ChildrenMap
|
||||
*/
|
||||
ReturnValue_t registerChild(object_id_t objectId);
|
||||
ReturnValue_t registerChild(const ModeTreeChildIF &child) override;
|
||||
|
||||
virtual ReturnValue_t initialize() override;
|
||||
ReturnValue_t initialize() override;
|
||||
|
||||
virtual ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||
|
||||
virtual ReturnValue_t setHealth(HealthState health) override;
|
||||
ReturnValue_t setHealth(HealthState health) override;
|
||||
|
||||
virtual HasHealthIF::HealthState getHealth() override;
|
||||
HasHealthIF::HealthState getHealth() override;
|
||||
|
||||
protected:
|
||||
struct ChildInfo {
|
||||
@ -81,8 +95,6 @@ class SubsystemBase : public SystemObject,
|
||||
|
||||
ModeHelper modeHelper;
|
||||
|
||||
const object_id_t parentId;
|
||||
|
||||
typedef std::map<object_id_t, ChildInfo> ChildrenMap;
|
||||
ChildrenMap childrenMap;
|
||||
|
||||
@ -95,6 +107,7 @@ class SubsystemBase : public SystemObject,
|
||||
Submode_t targetSubmode);
|
||||
|
||||
/**
|
||||
* This function takes care of sending all according mode commands specified inside a mode table.
|
||||
* We need to know the target Submode, as children are able to inherit the submode
|
||||
* Still, we have a default for all child implementations which do not use submode inheritance
|
||||
*/
|
||||
@ -128,6 +141,10 @@ class SubsystemBase : public SystemObject,
|
||||
|
||||
virtual void getMode(Mode_t *mode, Submode_t *submode) override;
|
||||
|
||||
object_id_t getObjectId() const override;
|
||||
const HasHealthIF *getOptHealthIF() const override;
|
||||
const HasModesIF &getModeIF() const override;
|
||||
|
||||
virtual void setToExternalControl() override;
|
||||
|
||||
virtual void announceMode(bool recursive) override;
|
||||
|
15
src/fsfw/subsystem/helper.cpp
Normal file
15
src/fsfw/subsystem/helper.cpp
Normal file
@ -0,0 +1,15 @@
|
||||
#include "helper.h"
|
||||
|
||||
ReturnValue_t modetree::connectModeTreeParent(HasModeTreeChildrenIF& parent,
|
||||
const ModeTreeChildIF& child,
|
||||
HealthHelper* healthHelper, ModeHelper& modeHelper) {
|
||||
ReturnValue_t result = parent.registerChild(child);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
if (healthHelper != nullptr) {
|
||||
healthHelper->setParentQueue(parent.getCommandQueue());
|
||||
}
|
||||
modeHelper.setParentQueue(parent.getCommandQueue());
|
||||
return returnvalue::OK;
|
||||
}
|
14
src/fsfw/subsystem/helper.h
Normal file
14
src/fsfw/subsystem/helper.h
Normal file
@ -0,0 +1,14 @@
|
||||
#ifndef FSFW_SUBSYSTEM_HELPER_H_
|
||||
#define FSFW_SUBSYSTEM_HELPER_H_
|
||||
|
||||
#include "HasModeTreeChildrenIF.h"
|
||||
#include "fsfw/health/HealthHelper.h"
|
||||
|
||||
namespace modetree {
|
||||
|
||||
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF& parent, const ModeTreeChildIF& child,
|
||||
HealthHelper* healthHelper, ModeHelper& modeHelper);
|
||||
|
||||
}
|
||||
|
||||
#endif /* FSFW_SRC_FSFW_SUBSYSTEM_HELPER_H_ */
|
@ -4,14 +4,13 @@
|
||||
|
||||
AbstractTemperatureSensor::AbstractTemperatureSensor(object_id_t setObjectid,
|
||||
ThermalModuleIF *thermalModule)
|
||||
: SystemObject(setObjectid),
|
||||
commandQueue(NULL),
|
||||
healthHelper(this, setObjectid),
|
||||
parameterHelper(this) {
|
||||
if (thermalModule != NULL) {
|
||||
: SystemObject(setObjectid), healthHelper(this, setObjectid), parameterHelper(this) {
|
||||
if (thermalModule != nullptr) {
|
||||
thermalModule->registerSensor(this);
|
||||
}
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue();
|
||||
auto mqArgs = MqArgs(setObjectid, static_cast<void *>(this));
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(
|
||||
3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
}
|
||||
|
||||
AbstractTemperatureSensor::~AbstractTemperatureSensor() {
|
||||
|
@ -51,7 +51,7 @@ class AbstractTemperatureSensor : public HasHealthIF,
|
||||
HasHealthIF::HealthState getHealth();
|
||||
|
||||
protected:
|
||||
MessageQueueIF* commandQueue;
|
||||
MessageQueueIF* commandQueue = nullptr;
|
||||
HealthHelper healthHelper;
|
||||
ParameterHelper parameterHelper;
|
||||
|
||||
|
@ -12,7 +12,9 @@ Heater::Heater(uint32_t objectId, uint8_t switch0, uint8_t switch1)
|
||||
switch1(switch1),
|
||||
heaterOnCountdown(10800000) /*about two orbits*/,
|
||||
parameterHelper(this) {
|
||||
eventQueue = QueueFactory::instance()->createMessageQueue();
|
||||
auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
|
||||
eventQueue = QueueFactory::instance()->createMessageQueue(
|
||||
3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
}
|
||||
|
||||
Heater::~Heater() { QueueFactory::instance()->deleteMessageQueue(eventQueue); }
|
||||
|
@ -13,9 +13,9 @@ class ThermalComponentIF : public HasParametersIF {
|
||||
static const Event COMPONENT_TEMP_HIGH = MAKE_EVENT(2, severity::LOW);
|
||||
static const Event COMPONENT_TEMP_OOL_LOW = MAKE_EVENT(3, severity::LOW);
|
||||
static const Event COMPONENT_TEMP_OOL_HIGH = MAKE_EVENT(4, severity::LOW);
|
||||
static const Event TEMP_NOT_IN_OP_RANGE = MAKE_EVENT(
|
||||
5, severity::LOW); //!< Is thrown when a device should start-up, but the temperature is out
|
||||
//!< of OP range. P1: thermalState of the component, P2: 0
|
||||
//!< Is thrown when a device should start-up, but the temperature is out
|
||||
//!< of OP range. P1: thermalState of the component, P2: 0
|
||||
static const Event TEMP_NOT_IN_OP_RANGE = MAKE_EVENT(5, severity::LOW);
|
||||
|
||||
static const uint8_t INTERFACE_ID = CLASS_ID::THERMAL_COMPONENT_IF;
|
||||
static const ReturnValue_t INVALID_TARGET_STATE = MAKE_RETURN_CODE(1);
|
||||
|
@ -1,7 +1,11 @@
|
||||
#include "fsfw/timemanager/Countdown.h"
|
||||
|
||||
Countdown::Countdown(uint32_t initialTimeout) : timeout(initialTimeout) {
|
||||
setTimeout(initialTimeout);
|
||||
Countdown::Countdown(uint32_t initialTimeout, bool startImmediately) : timeout(initialTimeout) {
|
||||
if (startImmediately) {
|
||||
setTimeout(initialTimeout);
|
||||
} else {
|
||||
timeout = initialTimeout;
|
||||
}
|
||||
}
|
||||
|
||||
Countdown::~Countdown() {}
|
||||
|
@ -26,8 +26,9 @@ class Countdown {
|
||||
* Otherwise a call to hasTimedOut might return True.
|
||||
*
|
||||
* @param initialTimeout Countdown duration in milliseconds
|
||||
* @param startImmediately Set to false if countdown should not be started immediately
|
||||
*/
|
||||
Countdown(uint32_t initialTimeout = 0);
|
||||
Countdown(uint32_t initialTimeout = 0, bool startImmediately = true);
|
||||
~Countdown();
|
||||
/**
|
||||
* Call to set a new countdown duration.
|
||||
|
@ -33,50 +33,47 @@ class TmStoreBackendIF : public HasParametersIF {
|
||||
static const ReturnValue_t INVALID_REQUEST = MAKE_RETURN_CODE(15);
|
||||
|
||||
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::MEMORY;
|
||||
static const Event STORE_SEND_WRITE_FAILED =
|
||||
MAKE_EVENT(0, severity::LOW); //!< Initiating sending data to store failed. Low, par1:
|
||||
//!< returnCode, par2: integer (debug info)
|
||||
static const Event STORE_WRITE_FAILED = MAKE_EVENT(
|
||||
1, severity::LOW); //!< Data was sent, but writing failed. Low, par1: returnCode, par2: 0
|
||||
static const Event STORE_SEND_READ_FAILED =
|
||||
MAKE_EVENT(2, severity::LOW); //!< Initiating reading data from store failed. Low, par1:
|
||||
//!< returnCode, par2: 0
|
||||
static const Event STORE_READ_FAILED = MAKE_EVENT(
|
||||
3, severity::LOW); //!< Data was requested, but access failed. Low, par1: returnCode, par2: 0
|
||||
static const Event UNEXPECTED_MSG =
|
||||
MAKE_EVENT(4, severity::LOW); //!< An unexpected TM packet or data message occurred. Low,
|
||||
//!< par1: 0, par2: integer (debug info)
|
||||
static const Event STORING_FAILED = MAKE_EVENT(
|
||||
5, severity::LOW); //!< Storing data failed. May simply be a full store. Low, par1:
|
||||
//!< returnCode, par2: integer (sequence count of failed packet).
|
||||
static const Event TM_DUMP_FAILED =
|
||||
MAKE_EVENT(6, severity::LOW); //!< Dumping retrieved data failed. Low, par1: returnCode,
|
||||
//!< par2: integer (sequence count of failed packet).
|
||||
static const Event STORE_INIT_FAILED =
|
||||
MAKE_EVENT(7, severity::LOW); //!< Corrupted init data or read error. Low, par1: returnCode,
|
||||
//!< par2: integer (debug info)
|
||||
static const Event STORE_INIT_EMPTY = MAKE_EVENT(
|
||||
8, severity::INFO); //!< Store was not initialized. Starts empty. Info, parameters both zero.
|
||||
static const Event STORE_CONTENT_CORRUPTED =
|
||||
MAKE_EVENT(9, severity::LOW); //!< Data was read out, but it is inconsistent. Low par1:
|
||||
//!< Memory address of corruption, par2: integer (debug info)
|
||||
static const Event STORE_INITIALIZE =
|
||||
MAKE_EVENT(10, severity::INFO); //!< Info event indicating the store will be initialized,
|
||||
//!< either at boot or after IOB switch. Info. pars: 0
|
||||
static const Event INIT_DONE = MAKE_EVENT(
|
||||
11, severity::INFO); //!< Info event indicating the store was successfully initialized,
|
||||
//!< either at boot or after IOB switch. Info. pars: 0
|
||||
static const Event DUMP_FINISHED = MAKE_EVENT(
|
||||
12, severity::INFO); //!< Info event indicating that dumping finished successfully. par1:
|
||||
//!< Number of dumped packets. par2: APID/SSC (16bits each)
|
||||
static const Event DELETION_FINISHED = MAKE_EVENT(
|
||||
13, severity::INFO); //!< Info event indicating that deletion finished successfully. par1:
|
||||
//!< Number of deleted packets. par2: APID/SSC (16bits each)
|
||||
static const Event DELETION_FAILED = MAKE_EVENT(
|
||||
14,
|
||||
severity::LOW); //!< Info event indicating that something went wrong during deletion. pars: 0
|
||||
static const Event AUTO_CATALOGS_SENDING_FAILED =
|
||||
MAKE_EVENT(15, severity::INFO); //!< Info that the a auto catalog report failed
|
||||
//! Initiating sending data to store failed. Low, par1:
|
||||
//! returnCode, par2: integer (debug info)
|
||||
static const Event STORE_SEND_WRITE_FAILED = MAKE_EVENT(0, severity::LOW);
|
||||
//! Data was sent, but writing failed. Low, par1: returnCode, par2: 0
|
||||
static const Event STORE_WRITE_FAILED = MAKE_EVENT(1, severity::LOW);
|
||||
//! Initiating reading data from store failed. Low, par1: returnCode, par2: 0
|
||||
static const Event STORE_SEND_READ_FAILED = MAKE_EVENT(2, severity::LOW);
|
||||
//! Data was requested, but access failed. Low, par1: returnCode, par2: 0
|
||||
static const Event STORE_READ_FAILED = MAKE_EVENT(3, severity::LOW);
|
||||
//! An unexpected TM packet or data message occurred. Low, par1: 0, par2: integer (debug info)
|
||||
static const Event UNEXPECTED_MSG = MAKE_EVENT(4, severity::LOW);
|
||||
//! Storing data failed. May simply be a full store. Low, par1: returnCode,
|
||||
//! par2: integer (sequence count of failed packet).
|
||||
static const Event STORING_FAILED = MAKE_EVENT(5, severity::LOW);
|
||||
//! Dumping retrieved data failed. Low, par1: returnCode,
|
||||
//! par2: integer (sequence count of failed packet).
|
||||
static const Event TM_DUMP_FAILED = MAKE_EVENT(6, severity::LOW);
|
||||
//! Corrupted init data or read error. Low, par1: returnCode, par2: integer (debug info)
|
||||
//! Store was not initialized. Starts empty. Info, parameters both zero.
|
||||
static const Event STORE_INIT_FAILED = MAKE_EVENT(7, severity::LOW);
|
||||
//! Data was read out, but it is inconsistent. Low par1:
|
||||
//! Memory address of corruption, par2: integer (debug info)
|
||||
static const Event STORE_INIT_EMPTY = MAKE_EVENT(8, severity::INFO);
|
||||
|
||||
static const Event STORE_CONTENT_CORRUPTED = MAKE_EVENT(9, severity::LOW);
|
||||
//! Info event indicating the store will be initialized, either at boot or after IOB switch.
|
||||
//! Info. pars: 0
|
||||
static const Event STORE_INITIALIZE = MAKE_EVENT(10, severity::INFO);
|
||||
//! Info event indicating the store was successfully initialized, either at boot or after
|
||||
//! IOB switch. Info. pars: 0
|
||||
static const Event INIT_DONE = MAKE_EVENT(11, severity::INFO);
|
||||
//! Info event indicating that dumping finished successfully.
|
||||
//! par1: Number of dumped packets. par2: APID/SSC (16bits each)
|
||||
static const Event DUMP_FINISHED = MAKE_EVENT(12, severity::INFO);
|
||||
//! Info event indicating that deletion finished successfully.
|
||||
//! par1:Number of deleted packets. par2: APID/SSC (16bits each)
|
||||
static const Event DELETION_FINISHED = MAKE_EVENT(13, severity::INFO);
|
||||
//! Info event indicating that something went wrong during deletion. pars: 0
|
||||
static const Event DELETION_FAILED = MAKE_EVENT(14, severity::LOW);
|
||||
//! Info that the a auto catalog report failed
|
||||
static const Event AUTO_CATALOGS_SENDING_FAILED = MAKE_EVENT(15, severity::INFO);
|
||||
|
||||
virtual ~TmStoreBackendIF() {}
|
||||
|
||||
|
@ -27,8 +27,10 @@ CommandingServiceBase::CommandingServiceBase(object_id_t setObjectId, uint16_t a
|
||||
verificationReporter(verificationReporter),
|
||||
commandMap(numberOfParallelCommands),
|
||||
name(name) {
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(queueDepth);
|
||||
requestQueue = QueueFactory::instance()->createMessageQueue(queueDepth);
|
||||
auto mqArgs = MqArgs(setObjectId, static_cast<void*>(this));
|
||||
size_t mqSz = MessageQueueMessage::MAX_MESSAGE_SIZE;
|
||||
commandQueue = QueueFactory::instance()->createMessageQueue(queueDepth, mqSz, &mqArgs);
|
||||
requestQueue = QueueFactory::instance()->createMessageQueue(queueDepth, mqSz, &mqArgs);
|
||||
}
|
||||
|
||||
void CommandingServiceBase::setPacketSource(object_id_t packetSource_) {
|
||||
@ -223,7 +225,7 @@ void CommandingServiceBase::handleReplyHandlerResult(ReturnValue_t result, Comma
|
||||
|
||||
// In case a new command is to be sent immediately, this is performed here.
|
||||
// If no new command is sent, only analyse reply result by initializing
|
||||
// sendResult as RETURN_OK
|
||||
// sendResult as returnvalue::OK
|
||||
ReturnValue_t sendResult = returnvalue::OK;
|
||||
if (nextCommand->getCommand() != CommandMessage::CMD_NONE) {
|
||||
sendResult = commandQueue->sendMessage(reply->getSender(), nextCommand);
|
||||
|
@ -27,8 +27,8 @@ ReturnValue_t PusServiceBase::performOperation(uint8_t opCode) {
|
||||
ReturnValue_t result = performService();
|
||||
if (result != returnvalue::OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "PusService " << psbParams.serviceId << ": performService returned with "
|
||||
<< static_cast<uint16_t>(result) << std::endl;
|
||||
sif::error << "PusService " << static_cast<int>(psbParams.serviceId)
|
||||
<< ": performService returned with " << static_cast<uint16_t>(result) << std::endl;
|
||||
#endif
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
@ -16,7 +16,9 @@ TmTcBridge::TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDes
|
||||
tcDestination(tcDestination)
|
||||
|
||||
{
|
||||
tmTcReceptionQueue = QueueFactory::instance()->createMessageQueue(TMTC_RECEPTION_QUEUE_DEPTH);
|
||||
auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
|
||||
tmTcReceptionQueue = QueueFactory::instance()->createMessageQueue(
|
||||
TMTC_RECEPTION_QUEUE_DEPTH, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
|
||||
}
|
||||
|
||||
TmTcBridge::~TmTcBridge() { QueueFactory::instance()->deleteMessageQueue(tmTcReceptionQueue); }
|
||||
@ -35,7 +37,7 @@ ReturnValue_t TmTcBridge::setNumberOfSentPacketsPerCycle(uint8_t sentPacketsPerC
|
||||
}
|
||||
}
|
||||
|
||||
ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored(uint8_t maxNumberOfPacketsStored) {
|
||||
ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored(unsigned int maxNumberOfPacketsStored) {
|
||||
if (maxNumberOfPacketsStored <= LIMIT_DOWNLINK_PACKETS_STORED) {
|
||||
this->maxNumberOfPacketsStored = maxNumberOfPacketsStored;
|
||||
return returnvalue::OK;
|
||||
@ -171,15 +173,18 @@ ReturnValue_t TmTcBridge::storeDownlinkData(TmTcMessage* message) {
|
||||
}
|
||||
|
||||
if (tmFifo->full()) {
|
||||
if (warningSwitch) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "TmTcBridge::storeDownlinkData: TM downlink max. number "
|
||||
"of stored packet IDs reached!"
|
||||
<< std::endl;
|
||||
sif::warning << "TmTcBridge::storeDownlinkData: TM downlink max. number "
|
||||
"of stored packet IDs reached!"
|
||||
<< std::endl;
|
||||
#else
|
||||
sif::printWarning(
|
||||
"TmTcBridge::storeDownlinkData: TM downlink max. number "
|
||||
"of stored packet IDs reached!\n");
|
||||
sif::printWarning(
|
||||
"TmTcBridge::storeDownlinkData: TM downlink max. number "
|
||||
"of stored packet IDs reached!\n");
|
||||
#endif
|
||||
warningSwitch = false;
|
||||
}
|
||||
if (overwriteOld) {
|
||||
tmFifo->retrieve(&storeId);
|
||||
tmStore->deleteData(storeId);
|
||||
@ -221,6 +226,7 @@ ReturnValue_t TmTcBridge::handleStoredTm() {
|
||||
packetSentCounter++;
|
||||
|
||||
if (tmFifo->empty()) {
|
||||
warningSwitch = true;
|
||||
tmStored = false;
|
||||
}
|
||||
tmStore->deleteData(storeId);
|
||||
|
@ -17,7 +17,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
|
||||
public:
|
||||
static constexpr uint8_t TMTC_RECEPTION_QUEUE_DEPTH = 20;
|
||||
static constexpr uint8_t LIMIT_STORED_DATA_SENT_PER_CYCLE = 15;
|
||||
static constexpr uint8_t LIMIT_DOWNLINK_PACKETS_STORED = 200;
|
||||
static constexpr unsigned int LIMIT_DOWNLINK_PACKETS_STORED = 1000;
|
||||
|
||||
static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 5;
|
||||
static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10;
|
||||
@ -42,7 +42,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
|
||||
* @return -@c returnvalue::OK if value was set successfully
|
||||
* -@c returnvalue::FAILED otherwise, stored value stays the same
|
||||
*/
|
||||
ReturnValue_t setMaxNumberOfPacketsStored(uint8_t maxNumberOfPacketsStored);
|
||||
ReturnValue_t setMaxNumberOfPacketsStored(unsigned int maxNumberOfPacketsStored);
|
||||
|
||||
/**
|
||||
* This will set up the bridge to overwrite old data in the FIFO.
|
||||
@ -91,6 +91,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
|
||||
//! by default, so telemetry will be handled immediately.
|
||||
bool communicationLinkUp = true;
|
||||
bool tmStored = false;
|
||||
bool warningSwitch = true;
|
||||
bool overwriteOld = true;
|
||||
uint8_t packetSentCounter = 0;
|
||||
|
||||
@ -152,7 +153,7 @@ class TmTcBridge : public AcceptsTelemetryIF,
|
||||
*/
|
||||
DynamicFIFO<store_address_t>* tmFifo = nullptr;
|
||||
uint8_t sentPacketsPerCycle = DEFAULT_STORED_DATA_SENT_PER_CYCLE;
|
||||
uint8_t maxNumberOfPacketsStored = DEFAULT_DOWNLINK_PACKETS_STORED;
|
||||
unsigned int maxNumberOfPacketsStored = DEFAULT_DOWNLINK_PACKETS_STORED;
|
||||
};
|
||||
|
||||
#endif /* FSFW_TMTCSERVICES_TMTCBRIDGE_H_ */
|
||||
|
@ -46,9 +46,9 @@ class GpioIF {
|
||||
* an ouput or input gpio.
|
||||
*
|
||||
* @param gpioId A unique number which specifies the GPIO to read.
|
||||
* @param gpioState State of GPIO will be written to this pointer.
|
||||
* @param gpioState State of GPIO will be written to this reference
|
||||
*/
|
||||
virtual ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) = 0;
|
||||
virtual ReturnValue_t readGpio(gpioId_t gpioId, gpio::Levels& gpioState) = 0;
|
||||
};
|
||||
|
||||
#endif /* COMMON_GPIO_GPIOIF_H_ */
|
||||
|
@ -17,7 +17,7 @@ using gpioId_t = uint16_t;
|
||||
|
||||
namespace gpio {
|
||||
|
||||
enum class Levels : int { LOW = 0, HIGH = 1, NONE = 99 };
|
||||
enum class Levels : int { LOW = 0, HIGH = 1, FAILED = -1, NONE = 99 };
|
||||
|
||||
enum class Direction : int { IN = 0, OUT = 1 };
|
||||
|
||||
|
@ -252,6 +252,8 @@ ReturnValue_t GyroHandlerL3GD20H::initializeLocalDataPool(localpool::DataPool &l
|
||||
localDataPoolMap.emplace(L3GD20H::ANG_VELOC_Y, new PoolEntry<float>({0.0}));
|
||||
localDataPoolMap.emplace(L3GD20H::ANG_VELOC_Z, new PoolEntry<float>({0.0}));
|
||||
localDataPoolMap.emplace(L3GD20H::TEMPERATURE, new PoolEntry<float>({0.0}));
|
||||
poolManager.subscribeForRegularPeriodicPacket(
|
||||
subdp::RegularHkPeriodicParams(dataset.getSid(), false, 10.0));
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
|
@ -195,7 +195,7 @@ ReturnValue_t MgmLIS3MDLHandler::scanForReply(const uint8_t *start, size_t len,
|
||||
#endif
|
||||
return DeviceHandlerIF::INVALID_DATA;
|
||||
}
|
||||
if (mode == _MODE_START_UP) {
|
||||
if (getMode() == _MODE_START_UP) {
|
||||
commandExecuted = true;
|
||||
}
|
||||
|
||||
@ -224,7 +224,7 @@ ReturnValue_t MgmLIS3MDLHandler::scanForReply(const uint8_t *start, size_t len,
|
||||
return DeviceHandlerIF::INVALID_DATA;
|
||||
}
|
||||
|
||||
if (mode == _MODE_START_UP) {
|
||||
if (getMode() == _MODE_START_UP) {
|
||||
commandExecuted = true;
|
||||
}
|
||||
}
|
||||
@ -371,13 +371,16 @@ float MgmLIS3MDLHandler::getSensitivityFactor(MGMLIS3MDL::Sensitivies sens) {
|
||||
|
||||
ReturnValue_t MgmLIS3MDLHandler::enableTemperatureSensor(const uint8_t *commandData,
|
||||
size_t commandDataLen) {
|
||||
if (commandData == nullptr) {
|
||||
return INVALID_COMMAND_PARAMETER;
|
||||
}
|
||||
triggerEvent(CHANGE_OF_SETUP_PARAMETER);
|
||||
uint32_t size = 2;
|
||||
commandBuffer[0] = writeCommand(MGMLIS3MDL::CTRL_REG1);
|
||||
if (commandDataLen > 1) {
|
||||
return INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS;
|
||||
}
|
||||
switch (*commandData) {
|
||||
switch (commandData[0]) {
|
||||
case (MGMLIS3MDL::ON): {
|
||||
commandBuffer[1] = registers[0] | (1 << 7);
|
||||
break;
|
||||
|
@ -169,7 +169,7 @@ ReturnValue_t MgmRM3100Handler::interpretDeviceReply(DeviceCommandId_t id, const
|
||||
case (RM3100::CONFIGURE_CYCLE_COUNT):
|
||||
case (RM3100::CONFIGURE_TMRC): {
|
||||
// We can only check whether write was successful with read operation
|
||||
if (mode == _MODE_START_UP) {
|
||||
if (getMode() == _MODE_START_UP) {
|
||||
commandExecuted = true;
|
||||
}
|
||||
break;
|
||||
@ -192,7 +192,7 @@ ReturnValue_t MgmRM3100Handler::interpretDeviceReply(DeviceCommandId_t id, const
|
||||
if (packet[1] == tmrcRegValue) {
|
||||
commandExecuted = true;
|
||||
// Reading TMRC was commanded. Trigger event to inform ground
|
||||
if (mode != _MODE_START_UP) {
|
||||
if (getMode() != _MODE_START_UP) {
|
||||
triggerEvent(tmrcSet, tmrcRegValue, 0);
|
||||
}
|
||||
} else {
|
||||
@ -211,7 +211,7 @@ ReturnValue_t MgmRM3100Handler::interpretDeviceReply(DeviceCommandId_t id, const
|
||||
return DeviceHandlerIF::DEVICE_REPLY_INVALID;
|
||||
}
|
||||
// Reading TMRC was commanded. Trigger event to inform ground
|
||||
if (mode != _MODE_START_UP) {
|
||||
if (getMode() != _MODE_START_UP) {
|
||||
uint32_t eventParam1 = (cycleCountX << 16) | cycleCountY;
|
||||
triggerEvent(cycleCountersSet, eventParam1, cycleCountZ);
|
||||
}
|
||||
@ -329,8 +329,8 @@ ReturnValue_t MgmRM3100Handler::handleDataReadout(const uint8_t *packet) {
|
||||
|
||||
// Now scale to physical value in microtesla
|
||||
float fieldStrengthX = fieldStrengthRawX * scaleFactorX;
|
||||
float fieldStrengthY = fieldStrengthRawY * scaleFactorX;
|
||||
float fieldStrengthZ = fieldStrengthRawZ * scaleFactorX;
|
||||
float fieldStrengthY = fieldStrengthRawY * scaleFactorY;
|
||||
float fieldStrengthZ = fieldStrengthRawZ * scaleFactorZ;
|
||||
|
||||
if (periodicPrintout) {
|
||||
if (debugDivider.checkAndIncrement()) {
|
||||
|
@ -6,7 +6,7 @@
|
||||
#include "fsfw/FSFW.h"
|
||||
#include "fsfw/serviceinterface.h"
|
||||
|
||||
UnixFileGuard::UnixFileGuard(std::string device, int* fileDescriptor, int flags,
|
||||
UnixFileGuard::UnixFileGuard(const std::string& device, int* fileDescriptor, int flags,
|
||||
std::string diagnosticPrefix)
|
||||
: fileDescriptor(fileDescriptor) {
|
||||
if (fileDescriptor == nullptr) {
|
||||
|
@ -15,7 +15,7 @@ class UnixFileGuard {
|
||||
|
||||
static constexpr ReturnValue_t OPEN_FILE_FAILED = 1;
|
||||
|
||||
UnixFileGuard(std::string device, int* fileDescriptor, int flags,
|
||||
UnixFileGuard(const std::string& device, int* fileDescriptor, int flags,
|
||||
std::string diagnosticPrefix = "");
|
||||
|
||||
virtual ~UnixFileGuard();
|
||||
|
27
src/fsfw_hal/linux/gpio/Gpio.h
Normal file
27
src/fsfw_hal/linux/gpio/Gpio.h
Normal file
@ -0,0 +1,27 @@
|
||||
#ifndef FSFW_HAL_SRC_FSFW_HAL_LINUX_GPIO_GPIO_H_
|
||||
#define FSFW_HAL_SRC_FSFW_HAL_LINUX_GPIO_GPIO_H_
|
||||
|
||||
#include "fsfw_hal/common/gpio/GpioIF.h"
|
||||
#include "fsfw_hal/common/gpio/gpioDefinitions.h"
|
||||
|
||||
/**
|
||||
* @brief Additional abstraction layer for handling GPIOs.
|
||||
*
|
||||
* @author J. Meier
|
||||
*/
|
||||
class Gpio {
|
||||
public:
|
||||
Gpio(gpioId_t gpioId, GpioIF* gpioIF) : gpioId(gpioId), gpioIF(gpioIF) {
|
||||
if (gpioIF == nullptr) {
|
||||
sif::error << "Gpio::Gpio: Invalid GpioIF" << std::endl;
|
||||
}
|
||||
}
|
||||
ReturnValue_t pullHigh() { return gpioIF->pullHigh(gpioId); }
|
||||
ReturnValue_t pullLow() { return gpioIF->pullLow(gpioId); }
|
||||
|
||||
private:
|
||||
gpioId_t gpioId = gpio::NO_GPIO;
|
||||
GpioIF* gpioIF = nullptr;
|
||||
};
|
||||
|
||||
#endif /* FSFW_HAL_SRC_FSFW_HAL_LINUX_GPIO_GPIO_H_ */
|
@ -214,7 +214,7 @@ ReturnValue_t LinuxLibgpioIF::configureRegularGpio(gpioId_t gpioId, struct gpiod
|
||||
}
|
||||
|
||||
ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId) {
|
||||
gpioMapIter = gpioMap.find(gpioId);
|
||||
auto gpioMapIter = gpioMap.find(gpioId);
|
||||
if (gpioMapIter == gpioMap.end()) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "LinuxLibgpioIF::pullHigh: Unknown GPIO ID " << gpioId << std::endl;
|
||||
@ -244,7 +244,7 @@ ReturnValue_t LinuxLibgpioIF::pullHigh(gpioId_t gpioId) {
|
||||
}
|
||||
|
||||
ReturnValue_t LinuxLibgpioIF::pullLow(gpioId_t gpioId) {
|
||||
gpioMapIter = gpioMap.find(gpioId);
|
||||
auto gpioMapIter = gpioMap.find(gpioId);
|
||||
if (gpioMapIter == gpioMap.end()) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "LinuxLibgpioIF::pullLow: Unknown GPIO ID " << gpioId << std::endl;
|
||||
@ -294,8 +294,8 @@ ReturnValue_t LinuxLibgpioIF::driveGpio(gpioId_t gpioId, GpiodRegularBase& regul
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, int* gpioState) {
|
||||
gpioMapIter = gpioMap.find(gpioId);
|
||||
ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, gpio::Levels& gpioState) {
|
||||
auto gpioMapIter = gpioMap.find(gpioId);
|
||||
if (gpioMapIter == gpioMap.end()) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::warning << "LinuxLibgpioIF::readGpio: Unknown GPIOD ID " << gpioId << std::endl;
|
||||
@ -313,7 +313,10 @@ ReturnValue_t LinuxLibgpioIF::readGpio(gpioId_t gpioId, int* gpioState) {
|
||||
if (regularGpio == nullptr) {
|
||||
return GPIO_TYPE_FAILURE;
|
||||
}
|
||||
*gpioState = gpiod_line_get_value(regularGpio->lineHandle);
|
||||
gpioState = static_cast<gpio::Levels>(gpiod_line_get_value(regularGpio->lineHandle));
|
||||
if (gpioState == gpio::Levels::FAILED) {
|
||||
return GPIO_GET_VALUE_FAILED;
|
||||
}
|
||||
} else {
|
||||
auto gpioCallback = dynamic_cast<GpioCallback*>(gpioMapIter->second);
|
||||
if (gpioCallback->callback == nullptr) {
|
||||
@ -374,7 +377,7 @@ ReturnValue_t LinuxLibgpioIF::checkForConflictsById(gpioId_t gpioIdToCheck,
|
||||
gpio::GpioTypes expectedType,
|
||||
GpioMap& mapToAdd) {
|
||||
// Cross check with private map
|
||||
gpioMapIter = gpioMap.find(gpioIdToCheck);
|
||||
auto gpioMapIter = gpioMap.find(gpioIdToCheck);
|
||||
if (gpioMapIter != gpioMap.end()) {
|
||||
auto& gpioType = gpioMapIter->second->gpioType;
|
||||
bool eraseDuplicateDifferentType = false;
|
||||
|
@ -25,6 +25,8 @@ class LinuxLibgpioIF : public GpioIF, public SystemObject {
|
||||
static constexpr ReturnValue_t GPIO_INVALID_INSTANCE = returnvalue::makeCode(gpioRetvalId, 4);
|
||||
static constexpr ReturnValue_t GPIO_DUPLICATE_DETECTED = returnvalue::makeCode(gpioRetvalId, 5);
|
||||
static constexpr ReturnValue_t GPIO_INIT_FAILED = returnvalue::makeCode(gpioRetvalId, 6);
|
||||
// Will be returned if getting the line value failed. Error type will be set to errno in this case
|
||||
static constexpr ReturnValue_t GPIO_GET_VALUE_FAILED = returnvalue::makeCode(gpioRetvalId, 7);
|
||||
|
||||
LinuxLibgpioIF(object_id_t objectId);
|
||||
virtual ~LinuxLibgpioIF();
|
||||
@ -32,7 +34,7 @@ class LinuxLibgpioIF : public GpioIF, public SystemObject {
|
||||
ReturnValue_t addGpios(GpioCookie* gpioCookie) override;
|
||||
ReturnValue_t pullHigh(gpioId_t gpioId) override;
|
||||
ReturnValue_t pullLow(gpioId_t gpioId) override;
|
||||
ReturnValue_t readGpio(gpioId_t gpioId, int* gpioState) override;
|
||||
ReturnValue_t readGpio(gpioId_t gpioId, gpio::Levels& gpioState) override;
|
||||
|
||||
private:
|
||||
static const size_t MAX_CHIPNAME_LENGTH = 11;
|
||||
@ -42,7 +44,6 @@ class LinuxLibgpioIF : public GpioIF, public SystemObject {
|
||||
|
||||
// Holds the information and configuration of all used GPIOs
|
||||
GpioUnorderedMap gpioMap;
|
||||
GpioUnorderedMapIter gpioMapIter;
|
||||
|
||||
/**
|
||||
* @brief This functions drives line of a GPIO specified by the GPIO ID.
|
||||
|
@ -109,14 +109,17 @@ ReturnValue_t I2cComIF::sendMessage(CookieIF* cookie, const uint8_t* sendData, s
|
||||
}
|
||||
|
||||
if (write(fd, sendData, sendLen) != static_cast<int>(sendLen)) {
|
||||
i2cCookie->errorCounter++;
|
||||
if (i2cCookie->errorCounter < 3) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "I2cComIF::sendMessage: Failed to send data to I2C "
|
||||
"device with error code "
|
||||
<< errno << ". Error description: " << strerror(errno) << std::endl;
|
||||
sif::error << "I2cComIF::sendMessage: Failed to send data to I2C "
|
||||
"device with error code "
|
||||
<< errno << ". Error description: " << strerror(errno) << std::endl;
|
||||
#endif
|
||||
}
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
i2cCookie->errorCounter = 0;
|
||||
#if FSFW_HAL_I2C_WIRETAPPING == 1
|
||||
sif::info << "Sent I2C data to bus " << deviceFile << ":" << std::endl;
|
||||
arrayprinter::print(sendData, sendLen);
|
||||
@ -180,10 +183,6 @@ ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLe
|
||||
}
|
||||
#else
|
||||
#endif
|
||||
#endif
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::debug << "I2cComIF::requestReceiveMessage: Read " << readLen << " of " << requestLen
|
||||
<< " bytes" << std::endl;
|
||||
#endif
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
@ -27,6 +27,8 @@ class I2cCookie : public CookieIF {
|
||||
size_t getMaxReplyLen() const;
|
||||
std::string getDeviceFile() const;
|
||||
|
||||
uint8_t errorCounter = 0;
|
||||
|
||||
private:
|
||||
address_t i2cAddress = 0;
|
||||
size_t maxReplyLen = 0;
|
||||
|
@ -2,6 +2,7 @@
|
||||
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <fsfw_hal/linux/serial/SerialComIF.h>
|
||||
#include <termios.h>
|
||||
#include <unistd.h>
|
||||
|
||||
|
43
src/fsfw_hal/linux/spi/ManualCsLockGuard.h
Normal file
43
src/fsfw_hal/linux/spi/ManualCsLockGuard.h
Normal file
@ -0,0 +1,43 @@
|
||||
#pragma once
|
||||
|
||||
#include "fsfw/ipc/MutexIF.h"
|
||||
#include "fsfw/returnvalues/returnvalue.h"
|
||||
#include "fsfw_hal/common/gpio/GpioIF.h"
|
||||
|
||||
class ManualCsLockWrapper {
|
||||
public:
|
||||
ManualCsLockWrapper(MutexIF* lock, GpioIF* gpioIF, SpiCookie* cookie,
|
||||
MutexIF::TimeoutType type = MutexIF::TimeoutType::BLOCKING,
|
||||
uint32_t timeoutMs = 0)
|
||||
: lock(lock), gpioIF(gpioIF), cookie(cookie), type(type), timeoutMs(timeoutMs) {
|
||||
if (cookie == nullptr) {
|
||||
// TODO: Error? Or maybe throw exception..
|
||||
return;
|
||||
}
|
||||
cookie->setCsLockManual(true);
|
||||
lockResult = lock->lockMutex(type, timeoutMs);
|
||||
if (lockResult != returnvalue::OK) {
|
||||
return;
|
||||
}
|
||||
gpioResult = gpioIF->pullLow(cookie->getChipSelectPin());
|
||||
}
|
||||
|
||||
~ManualCsLockWrapper() {
|
||||
if (gpioResult == returnvalue::OK) {
|
||||
gpioIF->pullHigh(cookie->getChipSelectPin());
|
||||
}
|
||||
cookie->setCsLockManual(false);
|
||||
if (lockResult == returnvalue::OK) {
|
||||
lock->unlockMutex();
|
||||
}
|
||||
}
|
||||
ReturnValue_t lockResult;
|
||||
ReturnValue_t gpioResult;
|
||||
|
||||
private:
|
||||
MutexIF* lock;
|
||||
GpioIF* gpioIF;
|
||||
SpiCookie* cookie;
|
||||
MutexIF::TimeoutType type;
|
||||
uint32_t timeoutMs = 0;
|
||||
};
|
@ -15,19 +15,9 @@
|
||||
#include "fsfw_hal/linux/spi/SpiCookie.h"
|
||||
#include "fsfw_hal/linux/utility.h"
|
||||
|
||||
SpiComIF::SpiComIF(object_id_t objectId, GpioIF* gpioComIF)
|
||||
: SystemObject(objectId), gpioComIF(gpioComIF) {
|
||||
if (gpioComIF == nullptr) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "SpiComIF::SpiComIF: GPIO communication interface invalid!" << std::endl;
|
||||
#else
|
||||
sif::printError("SpiComIF::SpiComIF: GPIO communication interface invalid!\n");
|
||||
#endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */
|
||||
#endif /* FSFW_VERBOSE_LEVEL >= 1 */
|
||||
}
|
||||
|
||||
spiMutex = MutexFactory::instance()->createMutex();
|
||||
SpiComIF::SpiComIF(object_id_t objectId, std::string devname, GpioIF& gpioComIF)
|
||||
: SystemObject(objectId), gpioComIF(gpioComIF), dev(std::move(devname)) {
|
||||
csMutex = MutexFactory::instance()->createMutex();
|
||||
}
|
||||
|
||||
ReturnValue_t SpiComIF::initializeInterface(CookieIF* cookie) {
|
||||
@ -75,7 +65,7 @@ ReturnValue_t SpiComIF::initializeInterface(CookieIF* cookie) {
|
||||
/* Pull CS high in any case to be sure that device is inactive */
|
||||
gpioId_t gpioId = spiCookie->getChipSelectPin();
|
||||
if (gpioId != gpio::NO_GPIO) {
|
||||
gpioComIF->pullHigh(gpioId);
|
||||
gpioComIF.pullHigh(gpioId);
|
||||
}
|
||||
|
||||
uint32_t spiSpeed = 0;
|
||||
@ -85,8 +75,7 @@ ReturnValue_t SpiComIF::initializeInterface(CookieIF* cookie) {
|
||||
spiCookie->getSpiParameters(spiMode, spiSpeed, ¶ms);
|
||||
|
||||
int fileDescriptor = 0;
|
||||
UnixFileGuard fileHelper(spiCookie->getSpiDevice(), &fileDescriptor, O_RDWR,
|
||||
"SpiComIF::initializeInterface");
|
||||
UnixFileGuard fileHelper(dev, &fileDescriptor, O_RDWR, "SpiComIF::initializeInterface");
|
||||
if (fileHelper.getOpenResult() != returnvalue::OK) {
|
||||
return fileHelper.getOpenResult();
|
||||
}
|
||||
@ -182,8 +171,7 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
|
||||
int retval = 0;
|
||||
/* Prepare transfer */
|
||||
int fileDescriptor = 0;
|
||||
std::string device = spiCookie->getSpiDevice();
|
||||
UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR, "SpiComIF::sendMessage");
|
||||
UnixFileGuard fileHelper(dev, &fileDescriptor, O_RDWR, "SpiComIF::sendMessage");
|
||||
if (fileHelper.getOpenResult() != returnvalue::OK) {
|
||||
return OPENING_FILE_FAILED;
|
||||
}
|
||||
@ -196,21 +184,28 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
|
||||
|
||||
bool fullDuplex = spiCookie->isFullDuplex();
|
||||
gpioId_t gpioId = spiCookie->getChipSelectPin();
|
||||
bool csLockManual = spiCookie->getCsLockManual();
|
||||
|
||||
/* Pull SPI CS low. For now, no support for active high given */
|
||||
if (gpioId != gpio::NO_GPIO) {
|
||||
result = spiMutex->lockMutex(timeoutType, timeoutMs);
|
||||
MutexIF::TimeoutType csType;
|
||||
dur_millis_t csTimeout = 0;
|
||||
// Pull SPI CS low. For now, no support for active high given
|
||||
if (gpioId != gpio::NO_GPIO and not csLockManual) {
|
||||
spiCookie->getMutexParams(csType, csTimeout);
|
||||
result = csMutex->lockMutex(csType, csTimeout);
|
||||
if (result != returnvalue::OK) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "SpiComIF::sendMessage: Failed to lock mutex" << std::endl;
|
||||
sif::error << "SpiComIF::sendMessage: Failed to lock mutex with code "
|
||||
<< "0x" << std::hex << std::setfill('0') << std::setw(4) << result << std::dec
|
||||
<< std::endl;
|
||||
#else
|
||||
sif::printError("SpiComIF::sendMessage: Failed to lock mutex\n");
|
||||
sif::printError("SpiComIF::sendMessage: Failed to lock mutex with code %d\n", result);
|
||||
#endif
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
result = gpioComIF->pullLow(gpioId);
|
||||
updateLinePolarity(fileDescriptor);
|
||||
result = gpioComIF.pullLow(gpioId);
|
||||
if (result != returnvalue::OK) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
@ -221,6 +216,8 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
} else {
|
||||
updateLinePolarity(fileDescriptor);
|
||||
}
|
||||
|
||||
/* Execute transfer */
|
||||
@ -248,9 +245,9 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const
|
||||
}
|
||||
}
|
||||
|
||||
if (gpioId != gpio::NO_GPIO) {
|
||||
gpioComIF->pullHigh(gpioId);
|
||||
result = spiMutex->unlockMutex();
|
||||
if (gpioId != gpio::NO_GPIO and not csLockManual) {
|
||||
gpioComIF.pullHigh(gpioId);
|
||||
result = csMutex->unlockMutex();
|
||||
if (result != returnvalue::OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "SpiComIF::sendMessage: Failed to unlock mutex" << std::endl;
|
||||
@ -278,9 +275,8 @@ ReturnValue_t SpiComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLe
|
||||
|
||||
ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) {
|
||||
ReturnValue_t result = returnvalue::OK;
|
||||
std::string device = spiCookie->getSpiDevice();
|
||||
int fileDescriptor = 0;
|
||||
UnixFileGuard fileHelper(device, &fileDescriptor, O_RDWR, "SpiComIF::requestReceiveMessage");
|
||||
UnixFileGuard fileHelper(dev, &fileDescriptor, O_RDWR, "SpiComIF::requestReceiveMessage");
|
||||
if (fileHelper.getOpenResult() != returnvalue::OK) {
|
||||
return OPENING_FILE_FAILED;
|
||||
}
|
||||
@ -292,16 +288,26 @@ ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) {
|
||||
return result;
|
||||
}
|
||||
|
||||
bool csLockManual = spiCookie->getCsLockManual();
|
||||
gpioId_t gpioId = spiCookie->getChipSelectPin();
|
||||
if (gpioId != gpio::NO_GPIO) {
|
||||
result = spiMutex->lockMutex(timeoutType, timeoutMs);
|
||||
MutexIF::TimeoutType csType;
|
||||
dur_millis_t csTimeout = 0;
|
||||
if (gpioId != gpio::NO_GPIO and not csLockManual) {
|
||||
spiCookie->getMutexParams(csType, csTimeout);
|
||||
result = csMutex->lockMutex(csType, csTimeout);
|
||||
if (result != returnvalue::OK) {
|
||||
#if FSFW_VERBOSE_LEVEL >= 1
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "SpiComIF::getSendSuccess: Failed to lock mutex" << std::endl;
|
||||
sif::error << "SpiComIF::sendMessage: Failed to lock mutex with code "
|
||||
<< "0x" << std::hex << std::setfill('0') << std::setw(4) << result << std::dec
|
||||
<< std::endl;
|
||||
#else
|
||||
sif::printError("SpiComIF::sendMessage: Failed to lock mutex with code %d\n", result);
|
||||
#endif
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
gpioComIF->pullLow(gpioId);
|
||||
gpioComIF.pullLow(gpioId);
|
||||
}
|
||||
|
||||
if (read(fileDescriptor, rxBuf, readSize) != static_cast<ssize_t>(readSize)) {
|
||||
@ -315,9 +321,9 @@ ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) {
|
||||
result = HALF_DUPLEX_TRANSFER_FAILED;
|
||||
}
|
||||
|
||||
if (gpioId != gpio::NO_GPIO) {
|
||||
gpioComIF->pullHigh(gpioId);
|
||||
result = spiMutex->unlockMutex();
|
||||
if (gpioId != gpio::NO_GPIO and not csLockManual) {
|
||||
gpioComIF.pullHigh(gpioId);
|
||||
result = csMutex->unlockMutex();
|
||||
if (result != returnvalue::OK) {
|
||||
#if FSFW_CPP_OSTREAM_ENABLED == 1
|
||||
sif::error << "SpiComIF::getSendSuccess: Failed to unlock mutex" << std::endl;
|
||||
@ -346,15 +352,7 @@ ReturnValue_t SpiComIF::readReceivedMessage(CookieIF* cookie, uint8_t** buffer,
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
MutexIF* SpiComIF::getMutex(MutexIF::TimeoutType* timeoutType, uint32_t* timeoutMs) {
|
||||
if (timeoutType != nullptr) {
|
||||
*timeoutType = this->timeoutType;
|
||||
}
|
||||
if (timeoutMs != nullptr) {
|
||||
*timeoutMs = this->timeoutMs;
|
||||
}
|
||||
return spiMutex;
|
||||
}
|
||||
MutexIF* SpiComIF::getCsMutex() { return csMutex; }
|
||||
|
||||
void SpiComIF::performSpiWiretapping(SpiCookie* spiCookie) {
|
||||
if (spiCookie == nullptr) {
|
||||
@ -389,7 +387,7 @@ ReturnValue_t SpiComIF::getReadBuffer(address_t spiAddress, uint8_t** buffer) {
|
||||
return returnvalue::OK;
|
||||
}
|
||||
|
||||
GpioIF* SpiComIF::getGpioInterface() { return gpioComIF; }
|
||||
GpioIF& SpiComIF::getGpioInterface() { return gpioComIF; }
|
||||
|
||||
void SpiComIF::setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed) {
|
||||
int retval = ioctl(spiFd, SPI_IOC_WR_MODE, reinterpret_cast<uint8_t*>(&mode));
|
||||
@ -401,11 +399,27 @@ void SpiComIF::setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed)
|
||||
if (retval != 0) {
|
||||
utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Setting SPI speed failed");
|
||||
}
|
||||
// This updates the SPI clock default polarity. Only setting the mode does not update
|
||||
// the line state, which can be an issue on mode switches because the clock line will
|
||||
// switch the state after the chip select is pulled low
|
||||
}
|
||||
|
||||
void SpiComIF::getSpiSpeedAndMode(int spiFd, spi::SpiModes& mode, uint32_t& speed) const {
|
||||
uint8_t tmpMode = 0;
|
||||
int retval = ioctl(spiFd, SPI_IOC_RD_MODE, &tmpMode);
|
||||
if (retval != 0) {
|
||||
utility::handleIoctlError("SpiComIF::getSpiSpeedAndMode: Reading SPI mode failed");
|
||||
}
|
||||
mode = static_cast<spi::SpiModes>(tmpMode);
|
||||
|
||||
retval = ioctl(spiFd, SPI_IOC_RD_MAX_SPEED_HZ, &speed);
|
||||
if (retval != 0) {
|
||||
utility::handleIoctlError("SpiComIF::getSpiSpeedAndMode: Getting SPI speed failed");
|
||||
}
|
||||
}
|
||||
|
||||
const std::string& SpiComIF::getSpiDev() const { return dev; }
|
||||
|
||||
void SpiComIF::updateLinePolarity(int spiFd) {
|
||||
clockUpdateTransfer.len = 0;
|
||||
retval = ioctl(spiFd, SPI_IOC_MESSAGE(1), &clockUpdateTransfer);
|
||||
int retval = ioctl(spiFd, SPI_IOC_MESSAGE(1), &clockUpdateTransfer);
|
||||
if (retval != 0) {
|
||||
utility::handleIoctlError("SpiComIF::setSpiSpeedAndMode: Updating SPI default clock failed");
|
||||
}
|
||||
|
@ -31,7 +31,7 @@ class SpiComIF : public DeviceCommunicationIF, public SystemObject {
|
||||
static constexpr ReturnValue_t HALF_DUPLEX_TRANSFER_FAILED =
|
||||
returnvalue::makeCode(spiRetvalId, 2);
|
||||
|
||||
SpiComIF(object_id_t objectId, GpioIF* gpioComIF);
|
||||
SpiComIF(object_id_t objectId, std::string devname, GpioIF& gpioComIF);
|
||||
|
||||
ReturnValue_t initializeInterface(CookieIF* cookie) override;
|
||||
ReturnValue_t sendMessage(CookieIF* cookie, const uint8_t* sendData, size_t sendLen) override;
|
||||
@ -43,7 +43,8 @@ class SpiComIF : public DeviceCommunicationIF, public SystemObject {
|
||||
* @brief This function returns the mutex which can be used to protect the spi bus when
|
||||
* the chip select must be driven from outside of the com if.
|
||||
*/
|
||||
MutexIF* getMutex(MutexIF::TimeoutType* timeoutType = nullptr, uint32_t* timeoutMs = nullptr);
|
||||
MutexIF* getCsMutex();
|
||||
void setMutexParams(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs);
|
||||
|
||||
/**
|
||||
* Perform a regular send operation using Linux iotcl. This is public so it can be used
|
||||
@ -56,8 +57,22 @@ class SpiComIF : public DeviceCommunicationIF, public SystemObject {
|
||||
ReturnValue_t performRegularSendOperation(SpiCookie* spiCookie, const uint8_t* sendData,
|
||||
size_t sendLen);
|
||||
|
||||
GpioIF* getGpioInterface();
|
||||
GpioIF& getGpioInterface();
|
||||
void setSpiSpeedAndMode(int spiFd, spi::SpiModes mode, uint32_t speed);
|
||||
void getSpiSpeedAndMode(int spiFd, spi::SpiModes& mode, uint32_t& speed) const;
|
||||
|
||||
/**
|
||||
* This updates the SPI clock default polarity. Only setting the mode does not update
|
||||
* the line state, which can be an issue on mode switches because the clock line will
|
||||
* switch the state after the chip select is pulled low.
|
||||
*
|
||||
* It is recommended to call this function after #setSpiSpeedAndMode and after locking the
|
||||
* CS mutex if the SPI bus has multiple SPI devices with different speed and SPI modes attached.
|
||||
* @param spiFd
|
||||
*/
|
||||
void updateLinePolarity(int spiFd);
|
||||
|
||||
const std::string& getSpiDev() const;
|
||||
void performSpiWiretapping(SpiCookie* spiCookie);
|
||||
|
||||
ReturnValue_t getReadBuffer(address_t spiAddress, uint8_t** buffer);
|
||||
@ -68,11 +83,15 @@ class SpiComIF : public DeviceCommunicationIF, public SystemObject {
|
||||
std::vector<uint8_t> replyBuffer;
|
||||
};
|
||||
|
||||
GpioIF* gpioComIF = nullptr;
|
||||
|
||||
MutexIF* spiMutex = nullptr;
|
||||
MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
|
||||
uint32_t timeoutMs = 20;
|
||||
GpioIF& gpioComIF;
|
||||
std::string dev = "";
|
||||
/**
|
||||
* Protects the chip select operations. Lock when GPIO is pulled low, unlock after it was
|
||||
* pulled high
|
||||
*/
|
||||
MutexIF* csMutex = nullptr;
|
||||
// MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING;
|
||||
// uint32_t timeoutMs = DEFAULT_MUTEX_TIMEOUT;
|
||||
spi_ioc_transfer clockUpdateTransfer = {};
|
||||
|
||||
using SpiDeviceMap = std::unordered_map<address_t, SpiInstance>;
|
||||
|
@ -1,26 +1,25 @@
|
||||
#include "SpiCookie.h"
|
||||
|
||||
SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev,
|
||||
const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed)
|
||||
: SpiCookie(spi::SpiComIfModes::REGULAR, spiAddress, chipSelect, spiDev, maxSize, spiMode,
|
||||
spiSpeed, nullptr, nullptr) {}
|
||||
|
||||
SpiCookie::SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxSize,
|
||||
SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, const size_t maxSize,
|
||||
spi::SpiModes spiMode, uint32_t spiSpeed)
|
||||
: SpiCookie(spiAddress, gpio::NO_GPIO, spiDev, maxSize, spiMode, spiSpeed) {}
|
||||
: SpiCookie(spi::SpiComIfModes::REGULAR, spiAddress, chipSelect, maxSize, spiMode, spiSpeed,
|
||||
nullptr, nullptr) {}
|
||||
|
||||
SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev,
|
||||
const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed,
|
||||
SpiCookie::SpiCookie(address_t spiAddress, const size_t maxSize, spi::SpiModes spiMode,
|
||||
uint32_t spiSpeed)
|
||||
: SpiCookie(spiAddress, gpio::NO_GPIO, maxSize, spiMode, spiSpeed) {}
|
||||
|
||||
SpiCookie::SpiCookie(address_t spiAddress, gpioId_t chipSelect, const size_t maxSize,
|
||||
spi::SpiModes spiMode, uint32_t spiSpeed,
|
||||
spi::send_callback_function_t callback, void* args)
|
||||
: SpiCookie(spi::SpiComIfModes::CALLBACK, spiAddress, chipSelect, spiDev, maxSize, spiMode,
|
||||
spiSpeed, callback, args) {}
|
||||
: SpiCookie(spi::SpiComIfModes::CALLBACK, spiAddress, chipSelect, maxSize, spiMode, spiSpeed,
|
||||
callback, args) {}
|
||||
|
||||
SpiCookie::SpiCookie(spi::SpiComIfModes comIfMode, address_t spiAddress, gpioId_t chipSelect,
|
||||
std::string spiDev, const size_t maxSize, spi::SpiModes spiMode,
|
||||
uint32_t spiSpeed, spi::send_callback_function_t callback, void* args)
|
||||
const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed,
|
||||
spi::send_callback_function_t callback, void* args)
|
||||
: spiAddress(spiAddress),
|
||||
chipSelectPin(chipSelect),
|
||||
spiDevice(spiDev),
|
||||
comIfMode(comIfMode),
|
||||
maxSize(maxSize),
|
||||
spiMode(spiMode),
|
||||
@ -50,8 +49,6 @@ size_t SpiCookie::getMaxBufferSize() const { return maxSize; }
|
||||
|
||||
address_t SpiCookie::getSpiAddress() const { return spiAddress; }
|
||||
|
||||
std::string SpiCookie::getSpiDevice() const { return spiDevice; }
|
||||
|
||||
void SpiCookie::setThreeWireSpi(bool enable) { uncommonParameters.threeWireSpi = enable; }
|
||||
|
||||
void SpiCookie::setLsbFirst(bool enable) { uncommonParameters.lsbFirst = enable; }
|
||||
@ -107,3 +104,17 @@ void SpiCookie::getCallback(spi::send_callback_function_t* callback, void** args
|
||||
*callback = this->sendCallback;
|
||||
*args = this->callbackArgs;
|
||||
}
|
||||
|
||||
void SpiCookie::setCsLockManual(bool enable) { manualCsLock = enable; }
|
||||
|
||||
bool SpiCookie::getCsLockManual() const { return manualCsLock; }
|
||||
|
||||
void SpiCookie::getMutexParams(MutexIF::TimeoutType& csTimeoutType, dur_millis_t& csTimeout) const {
|
||||
csTimeoutType = this->csTimeoutType;
|
||||
csTimeout = this->csTimeout;
|
||||
}
|
||||
|
||||
void SpiCookie::setMutexParams(MutexIF::TimeoutType csTimeoutType, dur_millis_t csTimeout) {
|
||||
this->csTimeoutType = csTimeoutType;
|
||||
this->csTimeout = csTimeout;
|
||||
}
|
||||
|
@ -2,6 +2,8 @@
|
||||
#define LINUX_SPI_SPICOOKIE_H_
|
||||
|
||||
#include <fsfw/devicehandlers/CookieIF.h>
|
||||
#include <fsfw/ipc/MutexIF.h>
|
||||
#include <fsfw/timemanager/clockDefinitions.h>
|
||||
#include <linux/spi/spidev.h>
|
||||
|
||||
#include "../../common/gpio/gpioDefinitions.h"
|
||||
@ -20,6 +22,8 @@
|
||||
*/
|
||||
class SpiCookie : public CookieIF {
|
||||
public:
|
||||
static constexpr dur_millis_t DEFAULT_MUTEX_TIMEOUT = 20;
|
||||
|
||||
/**
|
||||
* Each SPI device will have a corresponding cookie. The cookie is used by the communication
|
||||
* interface and contains device specific information like the largest expected size to be
|
||||
@ -29,23 +33,22 @@ class SpiCookie : public CookieIF {
|
||||
* @param spiDev
|
||||
* @param maxSize
|
||||
*/
|
||||
SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, const size_t maxSize,
|
||||
spi::SpiModes spiMode, uint32_t spiSpeed);
|
||||
SpiCookie(address_t spiAddress, gpioId_t chipSelect, const size_t maxSize, spi::SpiModes spiMode,
|
||||
uint32_t spiSpeed);
|
||||
|
||||
/**
|
||||
* Like constructor above, but without a dedicated GPIO CS. Can be used for hardware
|
||||
* slave select or if CS logic is performed with decoders.
|
||||
*/
|
||||
SpiCookie(address_t spiAddress, std::string spiDev, const size_t maxReplySize,
|
||||
spi::SpiModes spiMode, uint32_t spiSpeed);
|
||||
SpiCookie(address_t spiAddress, const size_t maxReplySize, spi::SpiModes spiMode,
|
||||
uint32_t spiSpeed);
|
||||
|
||||
/**
|
||||
* Use the callback mode of the SPI communication interface. The user can pass the callback
|
||||
* function here or by using the setter function #setCallbackMode
|
||||
*/
|
||||
SpiCookie(address_t spiAddress, gpioId_t chipSelect, std::string spiDev, const size_t maxSize,
|
||||
spi::SpiModes spiMode, uint32_t spiSpeed, spi::send_callback_function_t callback,
|
||||
void* args);
|
||||
SpiCookie(address_t spiAddress, gpioId_t chipSelect, const size_t maxSize, spi::SpiModes spiMode,
|
||||
uint32_t spiSpeed, spi::send_callback_function_t callback, void* args);
|
||||
|
||||
/**
|
||||
* Get the callback function
|
||||
@ -55,7 +58,6 @@ class SpiCookie : public CookieIF {
|
||||
void getCallback(spi::send_callback_function_t* callback, void** args);
|
||||
|
||||
address_t getSpiAddress() const;
|
||||
std::string getSpiDevice() const;
|
||||
gpioId_t getChipSelectPin() const;
|
||||
size_t getMaxBufferSize() const;
|
||||
|
||||
@ -139,9 +141,42 @@ class SpiCookie : public CookieIF {
|
||||
*/
|
||||
void activateCsDeselect(bool deselectCs, uint16_t delayUsecs);
|
||||
|
||||
void getMutexParams(MutexIF::TimeoutType& csTimeoutType, dur_millis_t& csTimeout) const;
|
||||
void setMutexParams(MutexIF::TimeoutType csTimeoutType, dur_millis_t csTimeout);
|
||||
|
||||
void setCsLockManual(bool enable);
|
||||
bool getCsLockManual() const;
|
||||
|
||||
spi_ioc_transfer* getTransferStructHandle();
|
||||
|
||||
private:
|
||||
address_t spiAddress;
|
||||
gpioId_t chipSelectPin;
|
||||
|
||||
spi::SpiComIfModes comIfMode;
|
||||
|
||||
// Required for regular mode
|
||||
const size_t maxSize;
|
||||
spi::SpiModes spiMode;
|
||||
/**
|
||||
* If this is set to true, the SPI ComIF will not perform any mutex locking for the
|
||||
* CS mechanism. The user is responsible to locking and unlocking the mutex for the
|
||||
* whole duration of the transfers.
|
||||
*/
|
||||
bool manualCsLock = false;
|
||||
uint32_t spiSpeed;
|
||||
bool halfDuplex = false;
|
||||
|
||||
MutexIF::TimeoutType csTimeoutType = MutexIF::TimeoutType::WAITING;
|
||||
dur_millis_t csTimeout = DEFAULT_MUTEX_TIMEOUT;
|
||||
|
||||
// Required for callback mode
|
||||
spi::send_callback_function_t sendCallback = nullptr;
|
||||
void* callbackArgs = nullptr;
|
||||
|
||||
struct spi_ioc_transfer spiTransferStruct = {};
|
||||
UncommonParameters uncommonParameters;
|
||||
|
||||
/**
|
||||
* Internal constructor which initializes every field
|
||||
* @param spiAddress
|
||||
@ -154,27 +189,8 @@ class SpiCookie : public CookieIF {
|
||||
* @param args
|
||||
*/
|
||||
SpiCookie(spi::SpiComIfModes comIfMode, address_t spiAddress, gpioId_t chipSelect,
|
||||
std::string spiDev, const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed,
|
||||
const size_t maxSize, spi::SpiModes spiMode, uint32_t spiSpeed,
|
||||
spi::send_callback_function_t callback, void* args);
|
||||
|
||||
address_t spiAddress;
|
||||
gpioId_t chipSelectPin;
|
||||
std::string spiDevice;
|
||||
|
||||
spi::SpiComIfModes comIfMode;
|
||||
|
||||
// Required for regular mode
|
||||
const size_t maxSize;
|
||||
spi::SpiModes spiMode;
|
||||
uint32_t spiSpeed;
|
||||
bool halfDuplex = false;
|
||||
|
||||
// Required for callback mode
|
||||
spi::send_callback_function_t sendCallback = nullptr;
|
||||
void* callbackArgs = nullptr;
|
||||
|
||||
struct spi_ioc_transfer spiTransferStruct = {};
|
||||
UncommonParameters uncommonParameters;
|
||||
};
|
||||
|
||||
#endif /* LINUX_SPI_SPICOOKIE_H_ */
|
||||
|
@ -2,19 +2,17 @@
|
||||
|
||||
#include <fsfw/objectmanager/ObjectManager.h>
|
||||
|
||||
TestAssembly::TestAssembly(object_id_t objectId, object_id_t parentId, object_id_t testDevice0,
|
||||
object_id_t testDevice1)
|
||||
: AssemblyBase(objectId, parentId),
|
||||
deviceHandler0Id(testDevice0),
|
||||
deviceHandler1Id(testDevice1) {
|
||||
TestAssembly::TestAssembly(object_id_t objectId, object_id_t parentId, ModeTreeChildIF& testDevice0,
|
||||
ModeTreeChildIF& testDevice1)
|
||||
: AssemblyBase(objectId, parentId), deviceHandler0(testDevice0), deviceHandler1(testDevice1) {
|
||||
ModeListEntry newModeListEntry;
|
||||
newModeListEntry.setObject(testDevice0);
|
||||
newModeListEntry.setObject(testDevice0.getObjectId());
|
||||
newModeListEntry.setMode(MODE_OFF);
|
||||
newModeListEntry.setSubmode(SUBMODE_NONE);
|
||||
|
||||
commandTable.insert(newModeListEntry);
|
||||
|
||||
newModeListEntry.setObject(testDevice1);
|
||||
newModeListEntry.setObject(testDevice1.getObjectId());
|
||||
newModeListEntry.setMode(MODE_OFF);
|
||||
newModeListEntry.setSubmode(SUBMODE_NONE);
|
||||
|
||||
@ -43,8 +41,8 @@ ReturnValue_t TestAssembly::commandChildren(Mode_t mode, Submode_t submode) {
|
||||
commandTable[1].setMode(MODE_OFF);
|
||||
commandTable[1].setSubmode(SUBMODE_NONE);
|
||||
// We try to prefer 0 here but we try to switch to 1 even if it might fail
|
||||
if (isDeviceAvailable(deviceHandler0Id)) {
|
||||
if (childrenMap[deviceHandler0Id].mode == MODE_ON) {
|
||||
if (isDeviceAvailable(deviceHandler0.getObjectId())) {
|
||||
if (childrenMap[deviceHandler0.getObjectId()].mode == MODE_ON) {
|
||||
commandTable[0].setMode(mode);
|
||||
commandTable[0].setSubmode(SUBMODE_NONE);
|
||||
} else {
|
||||
@ -53,7 +51,7 @@ ReturnValue_t TestAssembly::commandChildren(Mode_t mode, Submode_t submode) {
|
||||
result = NEED_SECOND_STEP;
|
||||
}
|
||||
} else {
|
||||
if (childrenMap[deviceHandler1Id].mode == MODE_ON) {
|
||||
if (childrenMap[deviceHandler1.getObjectId()].mode == MODE_ON) {
|
||||
commandTable[1].setMode(mode);
|
||||
commandTable[1].setSubmode(SUBMODE_NONE);
|
||||
} else {
|
||||
@ -64,7 +62,7 @@ ReturnValue_t TestAssembly::commandChildren(Mode_t mode, Submode_t submode) {
|
||||
}
|
||||
} else {
|
||||
// Dual Mode Normal
|
||||
if (childrenMap[deviceHandler0Id].mode == MODE_ON) {
|
||||
if (childrenMap[deviceHandler0.getObjectId()].mode == MODE_ON) {
|
||||
commandTable[0].setMode(mode);
|
||||
commandTable[0].setSubmode(SUBMODE_NONE);
|
||||
} else {
|
||||
@ -72,7 +70,7 @@ ReturnValue_t TestAssembly::commandChildren(Mode_t mode, Submode_t submode) {
|
||||
commandTable[0].setSubmode(SUBMODE_NONE);
|
||||
result = NEED_SECOND_STEP;
|
||||
}
|
||||
if (childrenMap[deviceHandler1Id].mode == MODE_ON) {
|
||||
if (childrenMap[deviceHandler1.getObjectId()].mode == MODE_ON) {
|
||||
commandTable[1].setMode(mode);
|
||||
commandTable[1].setSubmode(SUBMODE_NONE);
|
||||
} else {
|
||||
@ -89,7 +87,7 @@ ReturnValue_t TestAssembly::commandChildren(Mode_t mode, Submode_t submode) {
|
||||
commandTable[1].setMode(MODE_OFF);
|
||||
commandTable[1].setSubmode(SUBMODE_NONE);
|
||||
// We try to prefer 0 here but we try to switch to 1 even if it might fail
|
||||
if (isDeviceAvailable(deviceHandler0Id)) {
|
||||
if (isDeviceAvailable(deviceHandler0.getObjectId())) {
|
||||
commandTable[0].setMode(MODE_ON);
|
||||
commandTable[0].setSubmode(SUBMODE_NONE);
|
||||
} else {
|
||||
@ -133,23 +131,14 @@ ReturnValue_t TestAssembly::initialize() {
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
handler0 = ObjectManager::instance()->get<TestDevice>(deviceHandler0Id);
|
||||
handler1 = ObjectManager::instance()->get<TestDevice>(deviceHandler1Id);
|
||||
auto* handler0 = ObjectManager::instance()->get<TestDevice>(deviceHandler0.getObjectId());
|
||||
auto* handler1 = ObjectManager::instance()->get<TestDevice>(deviceHandler1.getObjectId());
|
||||
if ((handler0 == nullptr) or (handler1 == nullptr)) {
|
||||
return returnvalue::FAILED;
|
||||
}
|
||||
|
||||
handler0->setParentQueue(this->getCommandQueue());
|
||||
handler1->setParentQueue(this->getCommandQueue());
|
||||
|
||||
result = registerChild(deviceHandler0Id);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
result = registerChild(deviceHandler1Id);
|
||||
if (result != returnvalue::OK) {
|
||||
return result;
|
||||
}
|
||||
handler0->connectModeTreeParent(*this);
|
||||
handler1->connectModeTreeParent(*this);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user