diff --git a/.idea/cmake.xml b/.idea/cmake.xml new file mode 100644 index 000000000..b0a4921a9 --- /dev/null +++ b/.idea/cmake.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index 693e59e7c..9f5bb9bbc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -10,8 +10,13 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## Fixes +- The `PusTmCreator` API only accepted 255 bytes of source data. It can now accept source + data with a size limited only by the size of `size_t`. +- Important bugfix in CFDP PDU header format: The entity length field and the transaction sequence + number fields stored the actual length of the field instead of the length minus 1 like specified + in the CFDP standard. - PUS Health Service: Size check for set health command. - Perform operation completion for announce health command. + Perform operation completion for announce health command. https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/746 - Linux OSAL `getUptime` fix: Check validity of `/proc/uptime` file before reading uptime. https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/745 @@ -22,8 +27,11 @@ and this project adheres to [Semantic Versioning](http://semver.org/). - add CFDP subsystem ID https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/742 +- `PusTmZcWriter` now exposes API to set message counter field. ## Changed + +- HK generation is now countdown based. - Bump ETL version to 20.35.14 https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/748 - Renamed `PCDU_2` subsystem ID to `POWER_SWITCH_IF`. @@ -32,6 +40,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/). https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/743 - Assert that `FixedArrayList` is larger than 0 at compile time. https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/740 +- Health functions are virtual now. # [v6.0.0] 2023-02-10 @@ -107,6 +116,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## Added +- `CServiceHealthCommanding`: Add announce all health info implementation + PR: https://egit.irs.uni-stuttgart.de/eive/fsfw/pulls/122 - Empty constructor for `CdsShortTimeStamper` which does not do an object manager registration. PR: https://egit.irs.uni-stuttgart.de/fsfw/fsfw/pulls/730 - `Service9TimeManagement`: Add `DUMP_TIME` (129) subservice. diff --git a/docs/conf.py b/docs/conf.py index a4232026b..dad85e61b 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -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", + } } diff --git a/src/fsfw/action/ActionHelper.cpp b/src/fsfw/action/ActionHelper.cpp index fd6c8afba..81a1a727c 100644 --- a/src/fsfw/action/ActionHelper.cpp +++ b/src/fsfw/action/ActionHelper.cpp @@ -59,17 +59,24 @@ void ActionHelper::setQueueToUse(MessageQueueIF* queue) { queueToUse = queue; } void ActionHelper::prepareExecution(MessageQueueId_t commandedBy, ActionId_t actionId, store_address_t dataAddress) { + bool hasAdditionalData = false; const uint8_t* dataPtr = nullptr; size_t size = 0; - ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size); - if (result != returnvalue::OK) { - CommandMessage reply; - ActionMessage::setStepReply(&reply, actionId, 0, result); - queueToUse->sendMessage(commandedBy, &reply); - return; + ReturnValue_t result; + if (dataAddress != store_address_t::invalid()) { + hasAdditionalData = true; + ReturnValue_t result = ipcStore->getData(dataAddress, &dataPtr, &size); + if (result != returnvalue::OK) { + CommandMessage reply; + ActionMessage::setStepReply(&reply, actionId, 0, result); + queueToUse->sendMessage(commandedBy, &reply); + return; + } } result = owner->executeAction(actionId, commandedBy, dataPtr, size); - ipcStore->deleteData(dataAddress); + if (hasAdditionalData) { + ipcStore->deleteData(dataAddress); + } if (result == HasActionsIF::EXECUTION_FINISHED) { CommandMessage reply; ActionMessage::setCompletionReply(&reply, actionId, true, result); diff --git a/src/fsfw/action/CommandActionHelper.h b/src/fsfw/action/CommandActionHelper.h index 55176e09b..ac8ed1ba8 100644 --- a/src/fsfw/action/CommandActionHelper.h +++ b/src/fsfw/action/CommandActionHelper.h @@ -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); diff --git a/src/fsfw/cfdp.h b/src/fsfw/cfdp.h index 86086432d..b26459783 100644 --- a/src/fsfw/cfdp.h +++ b/src/fsfw/cfdp.h @@ -2,7 +2,9 @@ #define FSFW_CFDP_H #include "cfdp/definitions.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" diff --git a/src/fsfw/cfdp/handler/CMakeLists.txt b/src/fsfw/cfdp/handler/CMakeLists.txt index 901308060..7ad995c03 100644 --- a/src/fsfw/cfdp/handler/CMakeLists.txt +++ b/src/fsfw/cfdp/handler/CMakeLists.txt @@ -1 +1,2 @@ -target_sources(${LIB_FSFW_NAME} PRIVATE FaultHandlerBase.cpp UserBase.cpp) +target_sources(${LIB_FSFW_NAME} PRIVATE SourceHandler.cpp DestHandler.cpp + FaultHandlerBase.cpp UserBase.cpp) diff --git a/src/fsfw/cfdp/handler/DestHandler.cpp b/src/fsfw/cfdp/handler/DestHandler.cpp new file mode 100644 index 000000000..4ffa797ff --- /dev/null +++ b/src/fsfw/cfdp/handler/DestHandler.cpp @@ -0,0 +1,546 @@ +#include "DestHandler.h" + +#include + +#include + +#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(objects::TM_STORE); + if (fp.tmStore == nullptr) { + return FAILED; + } + } + + if (fp.tcStore == nullptr) { + fp.tcStore = ObjectManager::instance()->get(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 (result != returnvalue::OK) { + // TODO: Proper Error handling +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::error << "cfdp::DestHandler: VFS file write error with code 0x" << std::hex << std::setw(2) + << result << std::endl; +#endif + tp.vfsErrorCount++; + if (tp.vfsErrorCount < 3) { + // TODO: Provide execution step as parameter + fp.eventReporter->forwardEvent(events::FILESTORE_ERROR, static_cast(fsmRes.step), + result); + } + return result; + } else { + tp.deliveryStatus = FileDeliveryStatus::RETAINED_IN_FILESTORE; + tp.vfsErrorCount = 0; + } + if (offset.value() + fileSegmentLen > tp.progress) { + tp.progress = offset.value() + fileSegmentLen; + } + 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; + size_t sourceNameSize = 0; + + const uint8_t* sourceNamePtr = info.getSourceFileName().getValue(&sourceNameSize); + if (sourceNameSize + 1 > tp.sourceName.size()) { + fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "source filename too large"); + 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 + 1 > tp.destName.size()) { + fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "dest filename too large"); + return FAILED; + } + std::memcpy(tp.destName.data(), destNamePtr, destNameSize); + tp.destName[destNameSize] = '\0'; + + // 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()); + // handling to allow only specifying target directory. Example: + // Source path /test/hello.txt, dest path /tmp -> dest path /tmp/hello.txt + if (dp.user.vfs.isDirectory(tp.destName.data())) { + result = tryBuildingAbsoluteDestName(destNameSize); + if (result != OK) { + return result; + } + } + if (dp.user.vfs.fileExists(fparams)) { + result = dp.user.vfs.truncateFile(fparams); + if (result != returnvalue::OK) { + fileErrorHandler(events::FILESTORE_ERROR, result, "file truncation error"); + return FAILED; + // TODO: Relevant for filestore rejection error? + } + } else { + result = dp.user.vfs.createFile(fparams); + if (result != OK) { + fileErrorHandler(events::FILESTORE_ERROR, result, "file creation error"); + return FAILED; + // TODO: Relevant for filestore rejection error? + } + } + } + EntityId sourceId; + reader.getSourceId(sourceId); + if (not dp.remoteCfgTable.getRemoteCfg(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; + } + 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(); + reader.fillConfig(tp.pduConf); + tp.pduConf.direction = Direction::TOWARDS_SENDER; + tp.transactionId.entityId = tp.pduConf.sourceId; + tp.transactionId.seqNum = tp.pduConf.seqNum; + 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(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; +} + +ReturnValue_t cfdp::DestHandler::tryBuildingAbsoluteDestName(size_t destNameSize) { + char baseNameBuf[tp.destName.size()]{}; + FilesystemParams fparamsSrc(tp.sourceName.data()); + size_t baseNameLen = 0; + ReturnValue_t result = + dp.user.vfs.getBaseFilename(fparamsSrc, baseNameBuf, sizeof(baseNameBuf), baseNameLen); + if (result != returnvalue::OK or baseNameLen == 0) { + fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, "error retrieving source base name"); + return FAILED; + } + // Destination name + slash + base name + null termination + if (destNameSize + 1 + baseNameLen + 1 > tp.destName.size()) { + fileErrorHandler(events::FILENAME_TOO_LARGE_ERROR, 0, + "dest filename too large after adding source base name"); + return FAILED; + } + tp.destName[destNameSize++] = '/'; + std::memcpy(tp.destName.data() + destNameSize, baseNameBuf, baseNameLen); + destNameSize += baseNameLen; + tp.destName[destNameSize++] = '\0'; + return OK; +} + +void cfdp::DestHandler::fileErrorHandler(Event event, ReturnValue_t result, const char* info) { + fp.eventReporter->forwardEvent(events::FILENAME_TOO_LARGE_ERROR, + static_cast(fsmRes.step), result); +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "cfdp::DestHandler: " << info << std::endl; +#endif +} + +void cfdp::DestHandler::finish() { + tp.reset(); + dp.packetListRef.clear(); + fsmRes.state = CfdpStates::IDLE; + fsmRes.step = TransactionStep::IDLE; +} + +ReturnValue_t cfdp::DestHandler::checksumVerification() { + std::array 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; } diff --git a/src/fsfw/cfdp/handler/DestHandler.h b/src/fsfw/cfdp/handler/DestHandler.h new file mode 100644 index 000000000..9057b3f56 --- /dev/null +++ b/src/fsfw/cfdp/handler/DestHandler.h @@ -0,0 +1,206 @@ +#ifndef FSFW_CFDP_CFDPDESTHANDLER_H +#define FSFW_CFDP_CFDPDESTHANDLER_H + +#include +#include + +#include +#include + +#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 directive = std::nullopt) + : pduType(type), directiveType(directive), storeId(storeId) {} + + PduType pduType = PduType::FILE_DATA; + std::optional directiveType = FileDirective::INVALID_DIRECTIVE; + store_address_t storeId = store_address_t::invalid(); + PacketInfo() = default; +}; + +template +using LostSegmentsList = etl::set, SIZE>; +template +using PacketInfoList = etl::list; +using LostSegmentsListBase = etl::iset>; +using PacketInfoListBase = etl::ilist; + +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 : uint8_t { + 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 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; + vfsErrorCount = 0; + checksumType = ChecksumType::NULL_CHECKSUM; + } + + ChecksumType checksumType = ChecksumType::NULL_CHECKSUM; + bool closureRequested = false; + uint16_t vfsErrorCount = 0; + std::vector sourceName; + std::vector 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 tlvVec; + std::vector 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 tryBuildingAbsoluteDestName(size_t destNameSize); + ReturnValue_t sendFinishedPdu(); + ReturnValue_t noticeOfCompletion(); + ReturnValue_t checksumVerification(); + void fileErrorHandler(Event event, ReturnValue_t result, const char* info); + const FsmResult& updateFsmRes(uint8_t errors); + void checkAndHandleError(ReturnValue_t result, uint8_t& errorIdx); + void finish(); +}; + +} // namespace cfdp + +#endif // FSFW_CFDP_CFDPDESTHANDLER_H diff --git a/src/fsfw/cfdp/handler/SourceHandler.cpp b/src/fsfw/cfdp/handler/SourceHandler.cpp new file mode 100644 index 000000000..513b25f37 --- /dev/null +++ b/src/fsfw/cfdp/handler/SourceHandler.cpp @@ -0,0 +1 @@ +#include "SourceHandler.h" diff --git a/src/fsfw/cfdp/handler/SourceHandler.h b/src/fsfw/cfdp/handler/SourceHandler.h new file mode 100644 index 000000000..319cf2583 --- /dev/null +++ b/src/fsfw/cfdp/handler/SourceHandler.h @@ -0,0 +1,6 @@ +#ifndef FSFW_CFDP_CFDPSOURCEHANDLER_H +#define FSFW_CFDP_CFDPSOURCEHANDLER_H + +class SourceHandler {}; + +#endif // FSFW_CFDP_CFDPSOURCEHANDLER_H diff --git a/src/fsfw/cfdp/handler/defs.h b/src/fsfw/cfdp/handler/defs.h index 9e837a96b..5f17ca2dd 100644 --- a/src/fsfw/cfdp/handler/defs.h +++ b/src/fsfw/cfdp/handler/defs.h @@ -5,5 +5,18 @@ 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); +static constexpr Event FILESTORE_ERROR = event::makeEvent(SSID, 3, severity::LOW); +//! [EXPORT] : [COMMENT] P1: Transaction step ID, P2: 0 for source file name, 1 for dest file name +static constexpr Event FILENAME_TOO_LARGE_ERROR = event::makeEvent(SSID, 4, severity::LOW); + +} // namespace events + +} // namespace cfdp #endif // FSFW_CFDP_HANDLER_DEFS_H diff --git a/src/fsfw/cfdp/pdu/HeaderCreator.cpp b/src/fsfw/cfdp/pdu/HeaderCreator.cpp index 296885756..2db3953c9 100644 --- a/src/fsfw/cfdp/pdu/HeaderCreator.cpp +++ b/src/fsfw/cfdp/pdu/HeaderCreator.cpp @@ -24,8 +24,8 @@ ReturnValue_t HeaderCreator::serialize(uint8_t **buffer, size_t *size, size_t ma *buffer += 1; **buffer = pduDataFieldLen & 0x00ff; *buffer += 1; - **buffer = segmentationCtrl << 7 | pduConf.sourceId.getWidth() << 4 | segmentMetadataFlag << 3 | - pduConf.seqNum.getWidth(); + **buffer = segmentationCtrl << 7 | ((pduConf.sourceId.getWidth() - 1) << 4) | + segmentMetadataFlag << 3 | (pduConf.seqNum.getWidth() - 1); *buffer += 1; *size += 4; ReturnValue_t result = pduConf.sourceId.serialize(buffer, size, maxSize, streamEndianness); diff --git a/src/fsfw/cfdp/pdu/HeaderReader.cpp b/src/fsfw/cfdp/pdu/HeaderReader.cpp index 9edf2394d..de3d29066 100644 --- a/src/fsfw/cfdp/pdu/HeaderReader.cpp +++ b/src/fsfw/cfdp/pdu/HeaderReader.cpp @@ -78,11 +78,11 @@ cfdp::SegmentationControl PduHeaderReader::getSegmentationControl() const { } cfdp::WidthInBytes PduHeaderReader::getLenEntityIds() const { - return static_cast((pointers.fixedHeader->fourthByte >> 4) & 0x07); + return static_cast(((pointers.fixedHeader->fourthByte >> 4) & 0b111) + 1); } cfdp::WidthInBytes PduHeaderReader::getLenSeqNum() const { - return static_cast(pointers.fixedHeader->fourthByte & 0x07); + return static_cast((pointers.fixedHeader->fourthByte & 0b111) + 1); } cfdp::SegmentMetadataFlag PduHeaderReader::getSegmentMetadataFlag() const { diff --git a/src/fsfw/controller/ControllerBase.cpp b/src/fsfw/controller/ControllerBase.cpp index a9d19ef28..2c151f5a9 100644 --- a/src/fsfw/controller/ControllerBase.cpp +++ b/src/fsfw/controller/ControllerBase.cpp @@ -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(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(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(); } @@ -75,7 +58,7 @@ void ControllerBase::handleQueue() { void ControllerBase::startTransition(Mode_t mode_, Submode_t submode_) { changeHK(this->mode, this->submode, false); - triggerEvent(CHANGING_MODE, mode, submode); + triggerEvent(CHANGING_MODE, mode_, submode_); mode = mode_; submode = submode_; modeHelper.modeChanged(mode, submode); @@ -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); +} diff --git a/src/fsfw/controller/ControllerBase.h b/src/fsfw/controller/ControllerBase.h index 56c28585b..da140e494 100644 --- a/src/fsfw/controller/ControllerBase.h +++ b/src/fsfw/controller/ControllerBase.h @@ -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; diff --git a/src/fsfw/controller/ExtendedControllerBase.cpp b/src/fsfw/controller/ExtendedControllerBase.cpp index 4d5c90c84..58db35636 100644 --- a/src/fsfw/controller/ExtendedControllerBase.cpp +++ b/src/fsfw/controller/ExtendedControllerBase.cpp @@ -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) {} diff --git a/src/fsfw/controller/ExtendedControllerBase.h b/src/fsfw/controller/ExtendedControllerBase.h index b5583a880..04a795281 100644 --- a/src/fsfw/controller/ExtendedControllerBase.h +++ b/src/fsfw/controller/ExtendedControllerBase.h @@ -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 */ diff --git a/src/fsfw/coordinates/Sgp4Propagator.cpp b/src/fsfw/coordinates/Sgp4Propagator.cpp index e79ffef5e..62c2670e8 100644 --- a/src/fsfw/coordinates/Sgp4Propagator.cpp +++ b/src/fsfw/coordinates/Sgp4Propagator.cpp @@ -166,9 +166,9 @@ ReturnValue_t Sgp4Propagator::propagate(double* position, double* velocity, time timeval timeSinceEpoch = time - epoch; double minutesSinceEpoch = timeSinceEpoch.tv_sec / 60. + timeSinceEpoch.tv_usec / 60000000.; - double yearsSinceEpoch = minutesSinceEpoch / 60 / 24 / 365; + double monthsSinceEpoch = minutesSinceEpoch / 60 / 24 / 30; - if ((yearsSinceEpoch > 1) || (yearsSinceEpoch < -1)) { + if ((monthsSinceEpoch > 1) || (monthsSinceEpoch < -1)) { return TLE_TOO_OLD; } diff --git a/src/fsfw/datapoollocal/LocalDataPoolManager.cpp b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp index fa76d2a7c..32de8e6bc 100644 --- a/src/fsfw/datapoollocal/LocalDataPoolManager.cpp +++ b/src/fsfw/datapoollocal/LocalDataPoolManager.cpp @@ -70,8 +70,7 @@ ReturnValue_t LocalDataPoolManager::initialize(MessageQueueIF* queueToUse) { return returnvalue::OK; } -ReturnValue_t LocalDataPoolManager::initializeAfterTaskCreation(uint8_t nonDiagInvlFactor) { - setNonDiagnosticIntervalFactor(nonDiagInvlFactor); +ReturnValue_t LocalDataPoolManager::initializeAfterTaskCreation() { return initializeHousekeepingPoolEntriesOnce(); } @@ -506,9 +505,9 @@ ReturnValue_t LocalDataPoolManager::handleHousekeepingMessage(CommandMessage* me float newCollIntvl = 0; HousekeepingMessage::getCollectionIntervalModificationCommand(message, &newCollIntvl); if (command == HousekeepingMessage::MODIFY_DIAGNOSTICS_REPORT_COLLECTION_INTERVAL) { - result = changeCollectionInterval(sid, newCollIntvl, true); + result = changeCollectionInterval(sid, newCollIntvl); } else { - result = changeCollectionInterval(sid, newCollIntvl, false); + result = changeCollectionInterval(sid, newCollIntvl); } break; } @@ -570,6 +569,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); @@ -657,10 +660,6 @@ ReturnValue_t LocalDataPoolManager::serializeHkPacketIntoStore(HousekeepingPacke return hkPacket.serialize(&dataPtr, serializedSize, maxSize, SerializeIF::Endianness::MACHINE); } -void LocalDataPoolManager::setNonDiagnosticIntervalFactor(uint8_t nonDiagInvlFactor) { - this->nonDiagnosticIntervalFactor = nonDiagInvlFactor; -} - void LocalDataPoolManager::performPeriodicHkGeneration(HkReceiver& receiver) { sid_t sid = receiver.dataId.sid; LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); @@ -714,15 +713,15 @@ ReturnValue_t LocalDataPoolManager::togglePeriodicGeneration(sid_t sid, bool ena if ((LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and enable) or (not LocalPoolDataSetAttorney::getReportingEnabled(*dataSet) and not enable)) { - return REPORTING_STATUS_UNCHANGED; + return returnvalue::OK; } LocalPoolDataSetAttorney::setReportingEnabled(*dataSet, enable); return returnvalue::OK; } -ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid, float newCollectionInterval, - bool isDiagnostics) { +ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid, + float newCollectionInterval) { LocalPoolDataSetBase* dataSet = HasLocalDpIFManagerAttorney::getDataSetHandle(owner, sid); if (dataSet == nullptr) { printWarningOrError(sif::OutputTypes::OUT_WARNING, "changeCollectionInterval", @@ -730,11 +729,6 @@ ReturnValue_t LocalDataPoolManager::changeCollectionInterval(sid_t sid, float ne return DATASET_NOT_FOUND; } - bool targetIsDiagnostics = LocalPoolDataSetAttorney::isDiagnostics(*dataSet); - if ((targetIsDiagnostics and not isDiagnostics) or (not targetIsDiagnostics and isDiagnostics)) { - return WRONG_HK_PACKET_TYPE; - } - PeriodicHousekeepingHelper* periodicHelper = LocalPoolDataSetAttorney::getPeriodicHelper(*dataSet); @@ -825,6 +819,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"; diff --git a/src/fsfw/datapoollocal/LocalDataPoolManager.h b/src/fsfw/datapoollocal/LocalDataPoolManager.h index 8f369ea06..cd0d4f623 100644 --- a/src/fsfw/datapoollocal/LocalDataPoolManager.h +++ b/src/fsfw/datapoollocal/LocalDataPoolManager.h @@ -102,7 +102,7 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces * @param nonDiagInvlFactor * @return */ - ReturnValue_t initializeAfterTaskCreation(uint8_t nonDiagInvlFactor = 5); + ReturnValue_t initializeAfterTaskCreation(); /** * @brief This should be called in the periodic handler of the owner. @@ -152,17 +152,6 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces MessageQueueId_t targetQueueId, bool generateSnapshot) override; - /** - * Non-Diagnostics packets usually have a lower minimum sampling frequency - * than diagnostic packets. - * A factor can be specified to determine the minimum sampling frequency - * for non-diagnostic packets. The minimum sampling frequency of the - * diagnostics packets,which is usually jusst the period of the - * performOperation calls, is multiplied with that factor. - * @param factor - */ - void setNonDiagnosticIntervalFactor(uint8_t nonDiagInvlFactor); - /** * @brief The manager is also able to handle housekeeping messages. * @details @@ -185,6 +174,7 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces ReturnValue_t generateHousekeepingPacket(sid_t sid, LocalPoolDataSetBase* dataSet, bool forDownlink, MessageQueueId_t destination = MessageQueueIF::NO_QUEUE); + ReturnValue_t changeCollectionInterval(sid_t sid, float newCollectionInterval); HasLocalDataPoolIF* getOwner(); @@ -348,8 +338,6 @@ class LocalDataPoolManager : public ProvidesDataPoolSubscriptionIF, public Acces void performPeriodicHkGeneration(HkReceiver& hkReceiver); ReturnValue_t togglePeriodicGeneration(sid_t sid, bool enable, bool isDiagnostics); - ReturnValue_t changeCollectionInterval(sid_t sid, float newCollectionInterval, - bool isDiagnostics); ReturnValue_t generateSetStructurePacket(sid_t sid, bool isDiagnostics); void handleHkUpdateResetListInsertion(DataType dataType, DataId dataId); diff --git a/src/fsfw/datapoollocal/LocalPoolDataSetBase.cpp b/src/fsfw/datapoollocal/LocalPoolDataSetBase.cpp index 38aad828b..289954462 100644 --- a/src/fsfw/datapoollocal/LocalPoolDataSetBase.cpp +++ b/src/fsfw/datapoollocal/LocalPoolDataSetBase.cpp @@ -250,9 +250,8 @@ void LocalPoolDataSetBase::setReportingEnabled(bool reportingEnabled) { bool LocalPoolDataSetBase::getReportingEnabled() const { return reportingEnabled; } void LocalPoolDataSetBase::initializePeriodicHelper(float collectionInterval, - dur_millis_t minimumPeriodicInterval, - uint8_t nonDiagIntervalFactor) { - periodicHelper->initialize(collectionInterval, minimumPeriodicInterval, nonDiagIntervalFactor); + dur_millis_t minimumPeriodicInterval) { + periodicHelper->initialize(collectionInterval, minimumPeriodicInterval); } void LocalPoolDataSetBase::setChanged(bool changed) { this->changed = changed; } diff --git a/src/fsfw/datapoollocal/LocalPoolDataSetBase.h b/src/fsfw/datapoollocal/LocalPoolDataSetBase.h index 17cf8be2e..7aec77eaa 100644 --- a/src/fsfw/datapoollocal/LocalPoolDataSetBase.h +++ b/src/fsfw/datapoollocal/LocalPoolDataSetBase.h @@ -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,10 +190,8 @@ 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); + void initializePeriodicHelper(float collectionInterval, dur_millis_t minimumPeriodicInterval); /** * If the valid state of a dataset is always relevant to the whole diff --git a/src/fsfw/datapoollocal/internal/LocalPoolDataSetAttorney.h b/src/fsfw/datapoollocal/internal/LocalPoolDataSetAttorney.h index e7dbd0c70..6f9a3b27b 100644 --- a/src/fsfw/datapoollocal/internal/LocalPoolDataSetAttorney.h +++ b/src/fsfw/datapoollocal/internal/LocalPoolDataSetAttorney.h @@ -12,10 +12,8 @@ class LocalPoolDataSetAttorney { static bool isDiagnostics(LocalPoolDataSetBase& set) { return set.isDiagnostics(); } static void initializePeriodicHelper(LocalPoolDataSetBase& set, float collectionInterval, - uint32_t minimumPeriodicIntervalMs, - uint8_t nonDiagIntervalFactor = 5) { - set.initializePeriodicHelper(collectionInterval, minimumPeriodicIntervalMs, - nonDiagIntervalFactor); + uint32_t minimumPeriodicIntervalMs) { + set.initializePeriodicHelper(collectionInterval, minimumPeriodicIntervalMs); } static void setReportingEnabled(LocalPoolDataSetBase& set, bool enabled) { diff --git a/src/fsfw/devicehandlers/AssemblyBase.cpp b/src/fsfw/devicehandlers/AssemblyBase.cpp index 63178ab95..14575e69f 100644 --- a/src/fsfw/devicehandlers/AssemblyBase.cpp +++ b/src/fsfw/devicehandlers/AssemblyBase.cpp @@ -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); + } +} diff --git a/src/fsfw/devicehandlers/AssemblyBase.h b/src/fsfw/devicehandlers/AssemblyBase.h index ec0847f16..5e0d826f1 100644 --- a/src/fsfw/devicehandlers/AssemblyBase.h +++ b/src/fsfw/devicehandlers/AssemblyBase.h @@ -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_ */ diff --git a/src/fsfw/devicehandlers/ChildHandlerBase.cpp b/src/fsfw/devicehandlers/ChildHandlerBase.cpp index ecd4cfc8d..37af39dc5 100644 --- a/src/fsfw/devicehandlers/ChildHandlerBase.cpp +++ b/src/fsfw/devicehandlers/ChildHandlerBase.cpp @@ -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(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); } diff --git a/src/fsfw/devicehandlers/ChildHandlerBase.h b/src/fsfw/devicehandlers/ChildHandlerBase.h index 19d48a24a..c98baf3de 100644 --- a/src/fsfw/devicehandlers/ChildHandlerBase.h +++ b/src/fsfw/devicehandlers/ChildHandlerBase.h @@ -1,22 +1,23 @@ #ifndef FSFW_DEVICEHANDLER_CHILDHANDLERBASE_H_ #define FSFW_DEVICEHANDLER_CHILDHANDLERBASE_H_ +#include + #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; }; diff --git a/src/fsfw/devicehandlers/DeviceCommunicationIF.h b/src/fsfw/devicehandlers/DeviceCommunicationIF.h index a5546a36a..cf8272407 100644 --- a/src/fsfw/devicehandlers/DeviceCommunicationIF.h +++ b/src/fsfw/devicehandlers/DeviceCommunicationIF.h @@ -49,6 +49,7 @@ class DeviceCommunicationIF { // is this needed if there is no open/close call? static const ReturnValue_t NOT_ACTIVE = MAKE_RETURN_CODE(0x05); static const ReturnValue_t TOO_MUCH_DATA = MAKE_RETURN_CODE(0x06); + static constexpr ReturnValue_t BUSY = MAKE_RETURN_CODE(0x07); virtual ~DeviceCommunicationIF() {} diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp index bc528128f..00d6c4519 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.cpp @@ -1,4 +1,4 @@ -#include "fsfw/devicehandlers/DeviceHandlerBase.h" +#include "DeviceHandlerBase.h" #include "fsfw/datapool/PoolReadGuard.h" #include "fsfw/datapoollocal/LocalPoolVariable.h" @@ -13,6 +13,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; @@ -23,8 +24,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), @@ -39,10 +38,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(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(); @@ -50,21 +52,13 @@ 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) { this->hkDestination = hkDestination; } -void DeviceHandlerBase::setThermalStateRequestPoolIds(lp_id_t thermalStatePoolId, - lp_id_t heaterRequestPoolId, - uint32_t thermalSetId) { - thermalSet = - new DeviceHandlerThermalSet(this, thermalSetId, thermalStatePoolId, heaterRequestPoolId); -} +void DeviceHandlerBase::enableThermalModule(ThermalStateCfg cfg) { this->thermalStateCfg = cfg; } DeviceHandlerBase::~DeviceHandlerBase() { if (comCookie != nullptr) { @@ -130,6 +124,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(deviceCommunicationId); @@ -224,12 +222,11 @@ ReturnValue_t DeviceHandlerBase::initialize() { fillCommandAndReplyMap(); if (thermalSet != nullptr) { + PoolReadGuard pg(thermalSet); // Set temperature target state to NON_OP. - result = thermalSet->read(); - if (result == returnvalue::OK) { + if (pg.getReadResult() == returnvalue::OK) { thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; thermalSet->heaterRequest.setValid(true); - thermalSet->commit(); } } @@ -353,7 +350,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(); @@ -367,13 +363,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); @@ -381,7 +376,7 @@ void DeviceHandlerBase::doStateMachine() { } ReturnValue_t switchState = getStateOfSwitches(); if ((switchState == PowerSwitchIF::SWITCH_OFF) || (switchState == NO_SWITCH)) { - setMode(_MODE_SWITCH_IS_OFF); + setMode(MODE_OFF, SUBMODE_NONE); } } break; case MODE_OFF: @@ -394,9 +389,6 @@ void DeviceHandlerBase::doStateMachine() { case MODE_NORMAL: case MODE_ERROR_ON: break; - case _MODE_SWITCH_IS_OFF: - setMode(MODE_OFF, SUBMODE_NONE); - break; default: triggerEvent(OBJECT_IN_INVALID_MODE, mode, submode); setMode(_MODE_POWER_DOWN, 0); @@ -568,25 +560,40 @@ 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; + // TODO: Check whether the following two lines are okay to do so. + transitionSourceMode = MODE_ON; + transitionSourceSubMode = newSubmode; + 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); } Clock::getUptime(&timeoutStart); if (mode == MODE_OFF and thermalSet != nullptr) { - ReturnValue_t result = thermalSet->read(); - if (result == returnvalue::OK) { + PoolReadGuard pg(thermalSet); + if (pg.getReadResult() == returnvalue::OK) { if (thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) { thermalSet->heaterRequest.value = ThermalComponentIF::STATE_REQUEST_NON_OPERATIONAL; } - thermalSet->heaterRequest.commit(PoolVariableIF::VALID); + thermalSet->heaterRequest.setValid(true); } } /* TODO: This will probably be done by the LocalDataPoolManager now */ @@ -1059,8 +1066,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? @@ -1072,13 +1078,12 @@ 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)) { - ReturnValue_t result = thermalSet->read(); - if (result == returnvalue::OK) { + // Do not check thermal state for MODE_RAW + if ((mode == MODE_OFF) and ((commandedMode == MODE_ON) or (commandedMode == MODE_NORMAL)) and + (thermalSet != nullptr)) { + PoolReadGuard pg(thermalSet); + if (pg.getReadResult() == returnvalue::OK) { if ((thermalSet->heaterRequest.value != ThermalComponentIF::STATE_REQUEST_IGNORE) and (not ThermalComponentIF::isOperational(thermalSet->thermalState.value))) { triggerEvent(ThermalComponentIF::TEMP_NOT_IN_OP_RANGE, thermalSet->thermalState.value); @@ -1091,6 +1096,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); @@ -1120,8 +1126,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; } @@ -1137,11 +1144,10 @@ void DeviceHandlerBase::handleTransitionToOnMode(Mode_t commandedMode, Submode_t childTransitionDelay = getTransitionDelayMs(_MODE_START_UP, MODE_ON); triggerEvent(CHANGING_MODE, commandedMode, commandedSubmode); if (thermalSet != nullptr) { - ReturnValue_t result = thermalSet->read(); - if (result == returnvalue::OK) { + PoolReadGuard pg(thermalSet); + if (pg.getReadResult() == returnvalue::OK) { if (thermalSet->heaterRequest != ThermalComponentIF::STATE_REQUEST_IGNORE) { thermalSet->heaterRequest = ThermalComponentIF::STATE_REQUEST_OPERATIONAL; - thermalSet->commit(); } } } @@ -1279,6 +1285,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(&dataSet)); @@ -1457,15 +1464,17 @@ 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, LocalDataPoolManager& poolManager) { - if (thermalSet != nullptr) { - localDataPoolMap.emplace(thermalSet->thermalStatePoolId, - new PoolEntry); - localDataPoolMap.emplace(thermalSet->heaterRequestPoolId, - new PoolEntry); + if (thermalStateCfg.has_value()) { + localDataPoolMap.emplace(thermalStateCfg.value().thermalStatePoolId, + new PoolEntry()); + localDataPoolMap.emplace(thermalStateCfg.value().thermalRequestPoolId, + new PoolEntry()); } return returnvalue::OK; } @@ -1478,8 +1487,12 @@ ReturnValue_t DeviceHandlerBase::initializeAfterTaskCreation() { } this->poolManager.initializeAfterTaskCreation(); + if (thermalStateCfg.has_value()) { + ThermalStateCfg& cfg = thermalStateCfg.value(); + thermalSet = new DeviceHandlerThermalSet(this, cfg); + } if (setStartupImmediately) { - startTransition(MODE_ON, SUBMODE_NONE); + startTransition(MODE_ON, getInitialSubmode()); } return returnvalue::OK; } @@ -1566,3 +1579,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; +} diff --git a/src/fsfw/devicehandlers/DeviceHandlerBase.h b/src/fsfw/devicehandlers/DeviceHandlerBase.h index 700e960d1..08298bdc4 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerBase.h +++ b/src/fsfw/devicehandlers/DeviceHandlerBase.h @@ -2,6 +2,7 @@ #define FSFW_DEVICEHANDLERS_DEVICEHANDLERBASE_H_ #include +#include #include "DeviceCommunicationIF.h" #include "DeviceHandlerFailureIsolation.h" @@ -21,6 +22,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 +85,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 +106,51 @@ 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; + void setHkDestination(object_id_t hkDestination); /** @@ -110,13 +159,12 @@ class DeviceHandlerBase : public DeviceHandlerIF, * The device handler will then take care of creating local pool entries * for the device thermal state and device heating request. * Custom local pool IDs can be assigned as well. - * @param thermalStatePoolId - * @param thermalRequestPoolId */ - void setThermalStateRequestPoolIds( - lp_id_t thermalStatePoolId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID, - lp_id_t thermalRequestPoolId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID, - uint32_t thermalSetId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID); + void enableThermalModule(ThermalStateCfg cfg); + + 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 +210,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 +220,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 +244,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); @@ -207,8 +257,8 @@ class DeviceHandlerBase : public DeviceHandlerIF, Mode_t getTransitionSourceMode() const; Submode_t getTransitionSourceSubMode() const; virtual void getMode(Mode_t *mode, Submode_t *submode); - HealthState getHealth(); - ReturnValue_t setHealth(HealthState health); + virtual HealthState getHealth() override; + virtual ReturnValue_t setHealth(HealthState health) override; virtual ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueId, ParameterWrapper *parameterWrapper, const ParameterWrapper *newValues, @@ -395,6 +445,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 +515,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 +707,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 +742,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 +834,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 +901,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; @@ -853,6 +922,8 @@ class DeviceHandlerBase : public DeviceHandlerIF, //! Object which may be the root cause of an identified fault. static object_id_t defaultFdirParentId; + std::optional thermalStateCfg; + /** * @brief Send a reply to a received device handler command. * @@ -873,8 +944,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 +1012,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 +1194,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 +1260,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 +1289,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 +1366,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 +1419,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_ */ diff --git a/src/fsfw/devicehandlers/DeviceHandlerFailureIsolation.cpp b/src/fsfw/devicehandlers/DeviceHandlerFailureIsolation.cpp index a3ac9ff7b..d3e5753fe 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerFailureIsolation.cpp +++ b/src/fsfw/devicehandlers/DeviceHandlerFailureIsolation.cpp @@ -10,8 +10,9 @@ object_id_t DeviceHandlerFailureIsolation::powerConfirmationId = objects::NO_OBJECT; -DeviceHandlerFailureIsolation::DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent) - : FailureIsolationBase(owner, parent), +DeviceHandlerFailureIsolation::DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent, + uint8_t eventQueueDepth) + : FailureIsolationBase(owner, parent, eventQueueDepth), strangeReplyCount(DEFAULT_MAX_STRANGE_REPLIES, DEFAULT_STRANGE_REPLIES_TIME_MS, parameterDomainBase++), missedReplyCount(DEFAULT_MAX_MISSED_REPLY_COUNT, DEFAULT_MISSED_REPLY_TIME_MS, @@ -29,6 +30,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()); diff --git a/src/fsfw/devicehandlers/DeviceHandlerFailureIsolation.h b/src/fsfw/devicehandlers/DeviceHandlerFailureIsolation.h index 6007ceb8d..4835af99f 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerFailureIsolation.h +++ b/src/fsfw/devicehandlers/DeviceHandlerFailureIsolation.h @@ -13,7 +13,8 @@ class DeviceHandlerFailureIsolation : public FailureIsolationBase { friend class Heater; public: - DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent); + DeviceHandlerFailureIsolation(object_id_t owner, object_id_t parent, + uint8_t eventQueueDepth = 10); ~DeviceHandlerFailureIsolation(); ReturnValue_t initialize(); void triggerEvent(Event event, uint32_t parameter1 = 0, uint32_t parameter2 = 0); diff --git a/src/fsfw/devicehandlers/DeviceHandlerIF.h b/src/fsfw/devicehandlers/DeviceHandlerIF.h index 1fc63d3b2..5e1fdd2f7 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerIF.h +++ b/src/fsfw/devicehandlers/DeviceHandlerIF.h @@ -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; @@ -179,4 +136,10 @@ class DeviceHandlerIF { virtual MessageQueueId_t getCommandQueue() const = 0; }; +struct ThermalStateCfg { + 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; +}; + #endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERIF_H_ */ diff --git a/src/fsfw/devicehandlers/DeviceHandlerThermalSet.h b/src/fsfw/devicehandlers/DeviceHandlerThermalSet.h index 944d7c0f8..49ebd5f46 100644 --- a/src/fsfw/devicehandlers/DeviceHandlerThermalSet.h +++ b/src/fsfw/devicehandlers/DeviceHandlerThermalSet.h @@ -7,27 +7,21 @@ class DeviceHandlerThermalSet : public StaticLocalDataSet<2> { public: - DeviceHandlerThermalSet( - HasLocalDataPoolIF* hkOwner, uint32_t setId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID, - lp_id_t thermalStateId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID, - lp_id_t heaterRequestId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID) - : DeviceHandlerThermalSet(hkOwner->getObjectId(), setId, thermalStateId, heaterRequestId) {} + DeviceHandlerThermalSet(HasLocalDataPoolIF* hkOwner, ThermalStateCfg cfg) + : DeviceHandlerThermalSet(hkOwner->getObjectId(), cfg) {} - DeviceHandlerThermalSet( - object_id_t deviceHandler, uint32_t setId = DeviceHandlerIF::DEFAULT_THERMAL_SET_ID, - lp_id_t thermalStateId = DeviceHandlerIF::DEFAULT_THERMAL_STATE_POOL_ID, - lp_id_t thermalStateRequestId = DeviceHandlerIF::DEFAULT_THERMAL_HEATING_REQUEST_POOL_ID) - : StaticLocalDataSet(sid_t(deviceHandler, setId)), - thermalStatePoolId(thermalStateId), - heaterRequestPoolId(thermalStateRequestId) {} + DeviceHandlerThermalSet(object_id_t deviceHandler, ThermalStateCfg cfg) + : StaticLocalDataSet(sid_t(deviceHandler, cfg.thermalSetId)), + thermalStatePoolId(cfg.thermalStatePoolId), + heaterRequestPoolId(cfg.thermalRequestPoolId) {} const lp_id_t thermalStatePoolId; const lp_id_t heaterRequestPoolId; lp_var_t thermalState = - lp_var_t(thermalStatePoolId, sid.objectId, this); + lp_var_t(sid.objectId, thermalStatePoolId, this); lp_var_t heaterRequest = - lp_var_t(heaterRequestPoolId, sid.objectId, this); + lp_var_t(sid.objectId, heaterRequestPoolId, this); }; #endif /* FSFW_DEVICEHANDLERS_DEVICEHANDLERTHERMALSET_H_ */ diff --git a/src/fsfw/devicehandlers/DeviceTmReportingWrapper.h b/src/fsfw/devicehandlers/DeviceTmReportingWrapper.h index ae385f4c7..344cef011 100644 --- a/src/fsfw/devicehandlers/DeviceTmReportingWrapper.h +++ b/src/fsfw/devicehandlers/DeviceTmReportingWrapper.h @@ -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: diff --git a/src/fsfw/devicehandlers/HealthDevice.cpp b/src/fsfw/devicehandlers/HealthDevice.cpp index 4c09964a4..d3a70c77b 100644 --- a/src/fsfw/devicehandlers/HealthDevice.cpp +++ b/src/fsfw/devicehandlers/HealthDevice.cpp @@ -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(this)); + commandQueue = QueueFactory::instance()->createMessageQueue( + 3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs); } HealthDevice::~HealthDevice() { QueueFactory::instance()->deleteMessageQueue(commandQueue); } @@ -27,11 +29,10 @@ ReturnValue_t HealthDevice::initialize() { if (result != returnvalue::OK) { return result; } - if (parentQueue != 0) { + if (parentQueue != MessageQueueIF::NO_QUEUE) { return healthHelper.initialize(parentQueue); - } else { - return healthHelper.initialize(); } + return healthHelper.initialize(); } MessageQueueId_t HealthDevice::getCommandQueue() const { return commandQueue->getId(); } diff --git a/src/fsfw/devicehandlers/HealthDevice.h b/src/fsfw/devicehandlers/HealthDevice.h index f4c3520fb..a5c28cf75 100644 --- a/src/fsfw/devicehandlers/HealthDevice.h +++ b/src/fsfw/devicehandlers/HealthDevice.h @@ -29,10 +29,8 @@ class HealthDevice : public SystemObject, public ExecutableObjectIF, public HasH protected: HealthState lastHealth; - MessageQueueId_t parentQueue; + MessageQueueId_t parentQueue = MessageQueueIF::NO_QUEUE; MessageQueueIF* commandQueue; - - public: HealthHelper healthHelper; }; diff --git a/src/fsfw/events/EventManager.cpp b/src/fsfw/events/EventManager.cpp index 8bd26282a..f5cc99c68 100644 --- a/src/fsfw/events/EventManager.cpp +++ b/src/fsfw/events/EventManager.cpp @@ -15,11 +15,12 @@ const LocalPool::LocalPoolConfig EventManager::poolConfig = { {fsfwconfig::FSFW_EVENTMGMT_EVENTIDMATCHERS, sizeof(EventIdRangeMatcher)}, {fsfwconfig::FSFW_EVENTMGMR_RANGEMATCHERS, sizeof(ReporterRangeMatcher)}}; -EventManager::EventManager(object_id_t setObjectId) +EventManager::EventManager(object_id_t setObjectId, uint32_t eventQueueDepth) : 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(this)); + eventReportQueue = QueueFactory::instance()->createMessageQueue( + eventQueueDepth, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs); } EventManager::~EventManager() { @@ -47,9 +48,21 @@ 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 << " for event 0x" << std::setw(4) + << message->getEventId() << " 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(); @@ -200,4 +213,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 */ diff --git a/src/fsfw/events/EventManager.h b/src/fsfw/events/EventManager.h index 0e6dace04..9064adda2 100644 --- a/src/fsfw/events/EventManager.h +++ b/src/fsfw/events/EventManager.h @@ -21,9 +21,9 @@ extern const char* translateEvents(Event event); class EventManager : public EventManagerIF, public ExecutableObjectIF, public SystemObject { public: - static const uint16_t MAX_EVENTS_PER_CYCLE = 80; + static const uint16_t DEFAULT_MAX_EVENTS_PER_CYCLE = 80; - EventManager(object_id_t setObjectId); + EventManager(object_id_t setObjectId, uint32_t eventQueueDepth); virtual ~EventManager(); void setMutexTimeout(MutexIF::TimeoutType timeoutType, uint32_t timeoutMs); @@ -44,6 +44,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; diff --git a/src/fsfw/fdir/FailureIsolationBase.cpp b/src/fsfw/fdir/FailureIsolationBase.cpp index 0d3b02149..b6dd3773e 100644 --- a/src/fsfw/fdir/FailureIsolationBase.cpp +++ b/src/fsfw/fdir/FailureIsolationBase.cpp @@ -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(this)); + eventQueue = QueueFactory::instance()->createMessageQueue( + messageDepth, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs); } FailureIsolationBase::~FailureIsolationBase() { @@ -61,11 +62,12 @@ ReturnValue_t FailureIsolationBase::initialize() { ObjectManager::instance()->get(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; diff --git a/src/fsfw/fdir/FailureIsolationBase.h b/src/fsfw/fdir/FailureIsolationBase.h index 543ad6cc8..42d82d760 100644 --- a/src/fsfw/fdir/FailureIsolationBase.h +++ b/src/fsfw/fdir/FailureIsolationBase.h @@ -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); diff --git a/src/fsfw/fdir/FaultCounter.cpp b/src/fsfw/fdir/FaultCounter.cpp index eea088173..9ef359aa8 100644 --- a/src/fsfw/fdir/FaultCounter.cpp +++ b/src/fsfw/fdir/FaultCounter.cpp @@ -68,7 +68,7 @@ ReturnValue_t FaultCounter::getParameter(uint8_t domainId, uint8_t uniqueId, parameterWrapper->set(faultCount); break; case ParameterIds::TIMEOUT: - parameterWrapper->set(timer.timeout); + parameterWrapper->set(timer.getTimeoutMs()); break; default: return INVALID_IDENTIFIER_ID; diff --git a/src/fsfw/filesystem/HasFileSystemIF.h b/src/fsfw/filesystem/HasFileSystemIF.h index 6f7112ad4..a507938e3 100644 --- a/src/fsfw/filesystem/HasFileSystemIF.h +++ b/src/fsfw/filesystem/HasFileSystemIF.h @@ -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 @@ -73,6 +74,12 @@ class HasFileSystemIF { return MessageQueueIF::NO_QUEUE; } + // Get the base filename without the full directory path + virtual ReturnValue_t getBaseFilename(FilesystemParams params, char* nameBuf, size_t maxLen, + size_t& baseNameLen) = 0; + + virtual bool isDirectory(const char* path) = 0; + virtual bool fileExists(FilesystemParams params) = 0; /** diff --git a/src/fsfw/globalfunctions/DleParser.h b/src/fsfw/globalfunctions/DleParser.h index 9802017a5..48df05436 100644 --- a/src/fsfw/globalfunctions/DleParser.h +++ b/src/fsfw/globalfunctions/DleParser.h @@ -18,8 +18,11 @@ */ class DleParser { public: + //! [EXPORT] : [SKIP] static constexpr ReturnValue_t NO_PACKET_FOUND = returnvalue::makeCode(1, 1); + //! [EXPORT] : [SKIP] static constexpr ReturnValue_t POSSIBLE_PACKET_LOSS = returnvalue::makeCode(1, 2); + using BufPair = std::pair; enum class ContextType { NONE, PACKET_FOUND, ERROR }; diff --git a/src/fsfw/globalfunctions/math/VectorOperations.h b/src/fsfw/globalfunctions/math/VectorOperations.h index 197cd46a8..b8f6b00f6 100644 --- a/src/fsfw/globalfunctions/math/VectorOperations.h +++ b/src/fsfw/globalfunctions/math/VectorOperations.h @@ -53,8 +53,9 @@ class VectorOperations { mulScalar(vector, 1 / norm(vector, size), normalizedVector, size); } - static T maxAbsValue(const T *vector, uint8_t size, uint8_t *index = 0) { - T max = -1; + static T maxAbsValue(const T *vector, uint8_t size, uint8_t *index = nullptr) { + T max = vector[size - 1]; + uint8_t foundIndex = size - 1; for (; size > 0; size--) { T abs = vector[size - 1]; @@ -64,24 +65,35 @@ class VectorOperations { if (abs > max) { max = abs; if (index != 0) { - *index = size - 1; + foundIndex = size - 1; } } } + + if (index != nullptr) { + *index = foundIndex; + } + return max; } - static T maxValue(const T *vector, uint8_t size, uint8_t *index = 0) { - T max = -1; + static T maxValue(const T *vector, uint8_t size, uint8_t *index = nullptr) { + T max = vector[size - 1]; + uint8_t foundIndex = size - 1; for (; size > 0; size--) { if (vector[size - 1] > max) { max = vector[size - 1]; if (index != 0) { - *index = size - 1; + foundIndex = size - 1; } } } + + if (index != nullptr) { + *index = foundIndex; + } + return max; } diff --git a/src/fsfw/housekeeping/PeriodicHousekeepingHelper.cpp b/src/fsfw/housekeeping/PeriodicHousekeepingHelper.cpp index 0c2bef96d..ec34330a5 100644 --- a/src/fsfw/housekeeping/PeriodicHousekeepingHelper.cpp +++ b/src/fsfw/housekeeping/PeriodicHousekeepingHelper.cpp @@ -3,85 +3,37 @@ #include #include "fsfw/datapoollocal/LocalPoolDataSetBase.h" +#include "fsfw/serviceinterface.h" PeriodicHousekeepingHelper::PeriodicHousekeepingHelper(LocalPoolDataSetBase* owner) : owner(owner) {} void PeriodicHousekeepingHelper::initialize(float collectionInterval, - dur_millis_t minimumPeriodicInterval, - uint8_t nonDiagIntervalFactor) { + dur_millis_t minimumPeriodicInterval) { this->minimumPeriodicInterval = minimumPeriodicInterval; - this->nonDiagIntervalFactor = nonDiagIntervalFactor; - collectionIntervalTicks = intervalSecondsToIntervalTicks(collectionInterval); - /* This will cause a checkOpNecessary call to be true immediately. I think it's okay - if a HK packet is generated immediately instead of waiting one generation cycle. */ - internalTickCounter = collectionIntervalTicks; + changeCollectionInterval(collectionInterval); } float PeriodicHousekeepingHelper::getCollectionIntervalInSeconds() const { - return intervalTicksToSeconds(collectionIntervalTicks); + return collectionInterval; } bool PeriodicHousekeepingHelper::checkOpNecessary() { - if (internalTickCounter >= collectionIntervalTicks) { - internalTickCounter = 1; + if (hkGenerationCd.hasTimedOut()) { + hkGenerationCd.resetTimer(); return true; } - internalTickCounter++; return false; } -uint32_t PeriodicHousekeepingHelper::intervalSecondsToIntervalTicks( - float collectionIntervalSeconds) { - if (owner == nullptr) { - return 0; - } - bool isDiagnostics = owner->isDiagnostics(); - - /* Avoid division by zero */ - if (minimumPeriodicInterval == 0) { - if (isDiagnostics) { - /* Perform operation each cycle */ - return 1; - } else { - return nonDiagIntervalFactor; - } - } else { - dur_millis_t intervalInMs = collectionIntervalSeconds * 1000; - uint32_t divisor = minimumPeriodicInterval; - if (not isDiagnostics) { - /* We need to multiply the divisor because non-diagnostics only - allow a multiple of the minimum periodic interval */ - divisor *= nonDiagIntervalFactor; - } - uint32_t ticks = std::ceil(static_cast(intervalInMs) / divisor); - if (not isDiagnostics) { - /* Now we need to multiply the calculated ticks with the factor as as well - because the minimum tick count to generate a non-diagnostic is the factor itself. - - Example calculation for non-diagnostic with - 0.4 second interval and 0.2 second task interval. - Resultant tick count of 5 is equal to operation each second. - - Examle calculation for non-diagnostic with 2.0 second interval and 0.2 second - task interval. - Resultant tick count of 10 is equal to operatin every 2 seconds. - - Example calculation for diagnostic with 0.4 second interval and 0.3 - second task interval. Resulting tick count of 2 is equal to operation - every 0.6 seconds. */ - ticks *= nonDiagIntervalFactor; - } - return ticks; - } -} - -float PeriodicHousekeepingHelper::intervalTicksToSeconds(uint32_t collectionInterval) const { - /* Number of ticks times the minimum interval is in milliseconds, so we divide by 1000 to get - the value in seconds */ - return static_cast(collectionInterval * minimumPeriodicInterval / 1000.0); -} - void PeriodicHousekeepingHelper::changeCollectionInterval(float newIntervalSeconds) { - collectionIntervalTicks = intervalSecondsToIntervalTicks(newIntervalSeconds); + uint32_t intervalMs = newIntervalSeconds * 1000; + if (newIntervalSeconds <= 0) { + intervalMs = minimumPeriodicInterval; + newIntervalSeconds = static_cast(minimumPeriodicInterval) / 1000.0; + } + collectionInterval = newIntervalSeconds; + hkGenerationCd.setTimeout(intervalMs); + // We want an immediate HK packet at the start, so time out the generation CD immediately. + hkGenerationCd.timeOut(); } diff --git a/src/fsfw/housekeeping/PeriodicHousekeepingHelper.h b/src/fsfw/housekeeping/PeriodicHousekeepingHelper.h index 8b6245ba6..1586649cb 100644 --- a/src/fsfw/housekeeping/PeriodicHousekeepingHelper.h +++ b/src/fsfw/housekeeping/PeriodicHousekeepingHelper.h @@ -4,6 +4,7 @@ #include #include "fsfw/timemanager/Clock.h" +#include "fsfw/timemanager/Countdown.h" class LocalPoolDataSetBase; @@ -11,8 +12,7 @@ class PeriodicHousekeepingHelper { public: PeriodicHousekeepingHelper(LocalPoolDataSetBase* owner); - void initialize(float collectionInterval, dur_millis_t minimumPeriodicInterval, - uint8_t nonDiagIntervalFactor); + void initialize(float collectionInterval, dur_millis_t minimumPeriodicInterval); void changeCollectionInterval(float newInterval); float getCollectionIntervalInSeconds() const; @@ -20,14 +20,10 @@ class PeriodicHousekeepingHelper { private: LocalPoolDataSetBase* owner = nullptr; - uint8_t nonDiagIntervalFactor = 0; - - uint32_t intervalSecondsToIntervalTicks(float collectionIntervalSeconds); - float intervalTicksToSeconds(uint32_t collectionInterval) const; + Countdown hkGenerationCd; + float collectionInterval = 0.0; dur_millis_t minimumPeriodicInterval = 0; - uint32_t internalTickCounter = 1; - uint32_t collectionIntervalTicks = 0; }; #endif /* FSFW_HOUSEKEEPING_PERIODICHOUSEKEEPINGHELPER_H_ */ diff --git a/src/fsfw/internalerror/InternalErrorReporter.cpp b/src/fsfw/internalerror/InternalErrorReporter.cpp index fb2dc8a61..44910801d 100644 --- a/src/fsfw/internalerror/InternalErrorReporter.cpp +++ b/src/fsfw/internalerror/InternalErrorReporter.cpp @@ -5,13 +5,19 @@ #include "fsfw/ipc/QueueFactory.h" #include "fsfw/serviceinterface/ServiceInterface.h" -InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth) +InternalErrorReporter::InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth, + bool enableSetByDefault, float generationFrequency) : SystemObject(setObjectId), poolManager(this, commandQueue), + enableSetByDefault(enableSetByDefault), + generationFrequency(generationFrequency), internalErrorSid(setObjectId, InternalErrorDataset::ERROR_SET_ID), internalErrorDataset(this) { commandQueue = QueueFactory::instance()->createMessageQueue(messageQueueDepth); mutex = MutexFactory::instance()->createMutex(); + auto mqArgs = MqArgs(setObjectId, static_cast(this)); + commandQueue = QueueFactory::instance()->createMessageQueue( + messageQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs); } InternalErrorReporter::~InternalErrorReporter() { @@ -39,15 +45,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(newQueueHits)); - sif::printDebug("TM errors: %lu\n", static_cast(newTmHits)); - sif::printDebug("Store errors: %lu\n", static_cast(newStoreHits)); + sif::printDebug( + "InternalErrorReporter::performOperation: Errors occured: Queue | TM | Store: %lu | %lu " + "| %lu\n", + static_cast(newQueueHits), static_cast(newTmHits), + static_cast(newStoreHits)); #endif } } @@ -132,9 +137,8 @@ ReturnValue_t InternalErrorReporter::initializeLocalDataPool(localpool::DataPool localDataPoolMap.emplace(errorPoolIds::TM_HITS, &tmHitsEntry); localDataPoolMap.emplace(errorPoolIds::QUEUE_HITS, &queueHitsEntry); localDataPoolMap.emplace(errorPoolIds::STORE_HITS, &storeHitsEntry); - poolManager.subscribeForDiagPeriodicPacket(subdp::DiagnosticsHkPeriodicParams( - internalErrorSid, false, - static_cast(getPeriodicOperationFrequency()) / static_cast(1000.0))); + poolManager.subscribeForRegularPeriodicPacket( + subdp::RegularHkPeriodicParams(internalErrorSid, enableSetByDefault, generationFrequency)); internalErrorDataset.setValidity(true, true); return returnvalue::OK; } diff --git a/src/fsfw/internalerror/InternalErrorReporter.h b/src/fsfw/internalerror/InternalErrorReporter.h index ca82d1a4f..f845410b6 100644 --- a/src/fsfw/internalerror/InternalErrorReporter.h +++ b/src/fsfw/internalerror/InternalErrorReporter.h @@ -21,7 +21,8 @@ class InternalErrorReporter : public SystemObject, public InternalErrorReporterIF, public HasLocalDataPoolIF { public: - InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth = 5); + InternalErrorReporter(object_id_t setObjectId, uint32_t messageQueueDepth, + bool enableSetByDefault, float generationFrequency); /** * Enable diagnostic printout. Please note that this feature will @@ -63,6 +64,8 @@ class InternalErrorReporter : public SystemObject, MutexIF* mutex = nullptr; MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING; uint32_t timeoutMs = 20; + bool enableSetByDefault; + float generationFrequency; sid_t internalErrorSid; InternalErrorDataset internalErrorDataset; diff --git a/src/fsfw/ipc/CommandMessageIF.h b/src/fsfw/ipc/CommandMessageIF.h index dc8f71099..e714ca702 100644 --- a/src/fsfw/ipc/CommandMessageIF.h +++ b/src/fsfw/ipc/CommandMessageIF.h @@ -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(){}; diff --git a/src/fsfw/ipc/MutexGuard.h b/src/fsfw/ipc/MutexGuard.h index f6d2f25f3..9887f3965 100644 --- a/src/fsfw/ipc/MutexGuard.h +++ b/src/fsfw/ipc/MutexGuard.h @@ -7,14 +7,17 @@ class MutexGuard { public: MutexGuard(MutexIF* mutex, MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::BLOCKING, - uint32_t timeoutMs = 0) + uint32_t timeoutMs = 0, const char* context = nullptr) : internalMutex(mutex) { + if (context == nullptr) { + context = "unknown"; + } if (mutex == nullptr) { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "MutexGuard: Passed mutex is invalid!" << std::endl; + sif::error << "MutexGuard::" << context << ": Passed mutex is invalid!" << std::endl; #else - sif::printError("MutexGuard: Passed mutex is invalid!\n"); + sif::printError("MutexGuard::%s: Passed mutex is invalid!\n", context); #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FSFW_VERBOSE_LEVEL >= 1 */ return; @@ -23,11 +26,11 @@ class MutexGuard { #if FSFW_VERBOSE_LEVEL >= 1 if (result == MutexIF::MUTEX_TIMEOUT) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "MutexGuard: Lock of mutex failed with timeout of " << timeoutMs - << " milliseconds!" << std::endl; + sif::error << "MutexGuard::" << context << ": Lock of mutex failed with timeout of " + << timeoutMs << " milliseconds!" << std::endl; #else - sif::printError("MutexGuard: Lock of mutex failed with timeout of %lu milliseconds\n", - timeoutMs); + sif::printError("MutexGuard::%s: Lock of mutex failed with timeout of %lu milliseconds\n", + context, timeoutMs); #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ } else if (result != returnvalue::OK) { diff --git a/src/fsfw/modes/HasModesIF.h b/src/fsfw/modes/HasModesIF.h index 599975f81..ca207559f 100644 --- a/src/fsfw/modes/HasModesIF.h +++ b/src/fsfw/modes/HasModesIF.h @@ -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; diff --git a/src/fsfw/modes/ModeMessage.h b/src/fsfw/modes/ModeMessage.h index c00e6c9ef..9a3c2cc01 100644 --- a/src/fsfw/modes/ModeMessage.h +++ b/src/fsfw/modes/ModeMessage.h @@ -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); diff --git a/src/fsfw/objectmanager/ObjectManager.cpp b/src/fsfw/objectmanager/ObjectManager.cpp index 29c1b2fcc..2193d3a54 100644 --- a/src/fsfw/objectmanager/ObjectManager.cpp +++ b/src/fsfw/objectmanager/ObjectManager.cpp @@ -109,13 +109,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++; } diff --git a/src/fsfw/objectmanager/frameworkObjects.h b/src/fsfw/objectmanager/frameworkObjects.h index 9487147d9..bf153cae9 100644 --- a/src/fsfw/objectmanager/frameworkObjects.h +++ b/src/fsfw/objectmanager/frameworkObjects.h @@ -15,6 +15,7 @@ enum framework_objects : object_id_t { PUS_SERVICE_8_FUNCTION_MGMT = 0x53000008, PUS_SERVICE_9_TIME_MGMT = 0x53000009, PUS_SERVICE_11_TC_SCHEDULER = 0x53000011, + PUS_SERVICE_15_TM_STORAGE = 0x53000015, PUS_SERVICE_17_TEST = 0x53000017, PUS_SERVICE_20_PARAMETERS = 0x53000020, PUS_SERVICE_200_MODE_MGMT = 0x53000200, diff --git a/src/fsfw/osal/common/TcpIpBase.cpp b/src/fsfw/osal/common/TcpIpBase.cpp index 486a5171f..3e760f0e2 100644 --- a/src/fsfw/osal/common/TcpIpBase.cpp +++ b/src/fsfw/osal/common/TcpIpBase.cpp @@ -41,6 +41,7 @@ int TcpIpBase::closeSocket(socket_t socket) { #elif defined(PLATFORM_UNIX) return close(socket); #endif + return -1; } int TcpIpBase::getLastSocketError() { @@ -49,4 +50,5 @@ int TcpIpBase::getLastSocketError() { #elif defined(PLATFORM_UNIX) return errno; #endif + return 0; } diff --git a/src/fsfw/osal/common/TcpTmTcBridge.cpp b/src/fsfw/osal/common/TcpTmTcBridge.cpp index f99a8bc19..0bf3ab28d 100644 --- a/src/fsfw/osal/common/TcpTmTcBridge.cpp +++ b/src/fsfw/osal/common/TcpTmTcBridge.cpp @@ -16,9 +16,9 @@ #endif -TcpTmTcBridge::TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination, object_id_t tmStoreId, - object_id_t tcStoreId) - : TmTcBridge("TCP TMTC Bridge", objectId, tcDestination, tmStoreId, tcStoreId) { +TcpTmTcBridge::TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination, + uint32_t msgQueueDepth, object_id_t tmStoreId, object_id_t tcStoreId) + : TmTcBridge("TCP TMTC Bridge", objectId, tcDestination, msgQueueDepth, tmStoreId, tcStoreId) { mutex = MutexFactory::instance()->createMutex(); // Connection is always up, TM is requested by connecting to server and receiving packets registerCommConnect(); diff --git a/src/fsfw/osal/common/TcpTmTcBridge.h b/src/fsfw/osal/common/TcpTmTcBridge.h index 504592cc3..b330ba2ae 100644 --- a/src/fsfw/osal/common/TcpTmTcBridge.h +++ b/src/fsfw/osal/common/TcpTmTcBridge.h @@ -38,7 +38,7 @@ class TcpTmTcBridge : public TmTcBridge { * @param tmStoreId TM store object ID. It is recommended to the default object ID * @param tcStoreId TC store object ID. It is recommended to the default object ID */ - TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination, + TcpTmTcBridge(object_id_t objectId, object_id_t tcDestination, uint32_t msgQueueDepth, object_id_t tmStoreId = objects::TM_STORE, object_id_t tcStoreId = objects::TC_STORE); virtual ~TcpTmTcBridge(); diff --git a/src/fsfw/osal/common/TcpTmTcServer.cpp b/src/fsfw/osal/common/TcpTmTcServer.cpp index 903d87528..42417f847 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.cpp +++ b/src/fsfw/osal/common/TcpTmTcServer.cpp @@ -283,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) { diff --git a/src/fsfw/osal/common/TcpTmTcServer.h b/src/fsfw/osal/common/TcpTmTcServer.h index 009a1680e..b8c6ea2c2 100644 --- a/src/fsfw/osal/common/TcpTmTcServer.h +++ b/src/fsfw/osal/common/TcpTmTcServer.h @@ -79,6 +79,7 @@ class TcpTmTcServer : public SystemObject, public TcpIpBase, public ExecutableOb */ bool reusePort = false; }; + enum class ReceptionModes { SPACE_PACKETS }; static const std::string DEFAULT_SERVER_PORT; diff --git a/src/fsfw/osal/common/UdpTmTcBridge.cpp b/src/fsfw/osal/common/UdpTmTcBridge.cpp index c0848ceba..d6014ec78 100644 --- a/src/fsfw/osal/common/UdpTmTcBridge.cpp +++ b/src/fsfw/osal/common/UdpTmTcBridge.cpp @@ -20,9 +20,9 @@ const std::string UdpTmTcBridge::DEFAULT_SERVER_PORT = tcpip::DEFAULT_SERVER_PORT; UdpTmTcBridge::UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, - const std::string &udpServerPort_, object_id_t tmStoreId, - object_id_t tcStoreId) - : TmTcBridge("UDP TMTC Bridge", objectId, tcDestination, tmStoreId, tcStoreId) { + uint32_t msgQueueDepth, const std::string &udpServerPort_, + object_id_t tmStoreId, object_id_t tcStoreId) + : TmTcBridge("UDP TMTC Bridge", objectId, tcDestination, msgQueueDepth, tmStoreId, tcStoreId) { if (udpServerPort_.empty()) { udpServerPort = DEFAULT_SERVER_PORT; } else { @@ -126,10 +126,7 @@ ReturnValue_t UdpTmTcBridge::sendTm(const uint8_t *data, size_t dataLen) { tcpip::handleError(tcpip::Protocol::UDP, tcpip::ErrorSources::SENDTO_CALL); } #if FSFW_CPP_OSTREAM_ENABLED == 1 && FSFW_UDP_SEND_WIRETAPPING_ENABLED == 1 - sif::debug << "TmTcUdpBridge::sendTm: " << bytesSent - << " bytes were" - " sent." - << std::endl; + sif::debug << "TmTcUdpBridge::sendTm: " << bytesSent << " bytes were sent" << std::endl; #endif return returnvalue::OK; } diff --git a/src/fsfw/osal/common/UdpTmTcBridge.h b/src/fsfw/osal/common/UdpTmTcBridge.h index 92829c468..ce8adb4c8 100644 --- a/src/fsfw/osal/common/UdpTmTcBridge.h +++ b/src/fsfw/osal/common/UdpTmTcBridge.h @@ -29,7 +29,7 @@ class UdpTmTcBridge : public TmTcBridge, public TcpIpBase { /* The ports chosen here should not be used by any other process. */ static const std::string DEFAULT_SERVER_PORT; - UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, + UdpTmTcBridge(object_id_t objectId, object_id_t tcDestination, uint32_t msgQueueDepth, const std::string& udpServerPort = "", object_id_t tmStoreId = objects::TM_STORE, object_id_t tcStoreId = objects::TC_STORE); ~UdpTmTcBridge() override; diff --git a/src/fsfw/osal/host/Clock.cpp b/src/fsfw/osal/host/Clock.cpp index dbf6529c9..2a3c94bc8 100644 --- a/src/fsfw/osal/host/Clock.cpp +++ b/src/fsfw/osal/host/Clock.cpp @@ -47,7 +47,32 @@ ReturnValue_t Clock::setClock(const timeval* time) { return returnvalue::OK; } -ReturnValue_t Clock::getClock_timeval(timeval* time) { +ReturnValue_t Clock::getClockMonotonic(timeval* time) { +#if defined(PLATFORM_WIN) + // TODO: Implement with std::chrono::steady_clock.. or in some other way. I am not even sure + // whether this is possible with steady_clock. The conversion we have to do here just to be + // generic is kind of awkward.. + return returnvalue::FAILED; +#elif defined(PLATFORM_UNIX) + timespec timeMonotonic; + int status = clock_gettime(CLOCK_MONOTONIC_RAW, &timeMonotonic); + if (status != 0) { + return returnvalue::FAILED; + } + time->tv_sec = timeMonotonic.tv_sec; + time->tv_usec = timeMonotonic.tv_nsec / 1000.0; + return returnvalue::OK; +#else +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "Clock::getUptime: Not implemented for found OS!" << std::endl; +#else + sif::printWarning("Clock::getUptime: Not implemented for found OS!\n"); +#endif + return returnvalue::FAILED; +#endif +} + +ReturnValue_t Clock::getClock(timeval* time) { #if defined(PLATFORM_WIN) auto now = std::chrono::system_clock::now(); auto secondsChrono = std::chrono::time_point_cast(now); @@ -75,6 +100,8 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) { #endif } +ReturnValue_t Clock::getClock_timeval(timeval* time) { return Clock::getClock(time); } + ReturnValue_t Clock::getClock_usecs(uint64_t* time) { if (time == nullptr) { return returnvalue::FAILED; diff --git a/src/fsfw/osal/host/TaskFactory.cpp b/src/fsfw/osal/host/TaskFactory.cpp index 0a27241b1..d9552923e 100644 --- a/src/fsfw/osal/host/TaskFactory.cpp +++ b/src/fsfw/osal/host/TaskFactory.cpp @@ -20,16 +20,18 @@ TaskFactory::~TaskFactory() = default; TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; } -PeriodicTaskIF* TaskFactory::createPeriodicTask( - TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_, - TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) { +PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_, TaskPriority taskPriority_, + TaskStackSize stackSize_, + TaskPeriod periodInSeconds_, + TaskDeadlineMissedFunction deadLineMissedFunction_, + void* args) { return new PeriodicTask(name_, taskPriority_, stackSize_, periodInSeconds_, deadLineMissedFunction_); } FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask( TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_, - TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) { + TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_, void* args) { return new FixedTimeslotTask(name_, taskPriority_, stackSize_, periodInSeconds_, deadLineMissedFunction_); } diff --git a/src/fsfw/osal/linux/Clock.cpp b/src/fsfw/osal/linux/Clock.cpp index 7dd960e5a..209dba56f 100644 --- a/src/fsfw/osal/linux/Clock.cpp +++ b/src/fsfw/osal/linux/Clock.cpp @@ -42,7 +42,7 @@ ReturnValue_t Clock::setClock(const timeval* time) { return returnvalue::OK; } -ReturnValue_t Clock::getClock_timeval(timeval* time) { +ReturnValue_t Clock::getClock(timeval* time) { timespec timeUnix{}; int status = clock_gettime(CLOCK_REALTIME, &timeUnix); if (status != 0) { @@ -53,6 +53,8 @@ ReturnValue_t Clock::getClock_timeval(timeval* time) { return returnvalue::OK; } +ReturnValue_t Clock::getClock_timeval(timeval* time) { return Clock::getClock(time); } + ReturnValue_t Clock::getClock_usecs(uint64_t* time) { timeval timeVal{}; ReturnValue_t result = getClock_timeval(&timeVal); @@ -64,6 +66,17 @@ ReturnValue_t Clock::getClock_usecs(uint64_t* time) { return returnvalue::OK; } +ReturnValue_t Clock::getClockMonotonic(timeval* time) { + timespec timeMonotonic{}; + int status = clock_gettime(CLOCK_MONOTONIC_RAW, &timeMonotonic); + if (status != 0) { + return returnvalue::FAILED; + } + time->tv_sec = timeMonotonic.tv_sec; + time->tv_usec = timeMonotonic.tv_nsec / 1000.0; + return returnvalue::OK; +} + timeval Clock::getUptime() { timeval uptime{}; auto result = getUptime(&uptime); diff --git a/src/fsfw/osal/linux/FixedTimeslotTask.cpp b/src/fsfw/osal/linux/FixedTimeslotTask.cpp index 34729c22e..0709f52f2 100644 --- a/src/fsfw/osal/linux/FixedTimeslotTask.cpp +++ b/src/fsfw/osal/linux/FixedTimeslotTask.cpp @@ -7,10 +7,15 @@ const size_t PeriodicTaskIF::MINIMUM_STACK_SIZE = PTHREAD_STACK_MIN; FixedTimeslotTask::FixedTimeslotTask(const char* name_, TaskPriority priority_, size_t stackSize_, - TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_) + TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_, + PosixThreadArgs* args) : FixedTimeslotTaskBase(periodSeconds_, dlmFunc_), - posixThread(name_, priority_, stackSize_), - started(false) {} + posixThread(name_, SchedulingPolicy::REGULAR, priority_, stackSize_), + started(false) { + if (args != nullptr) { + posixThread.setSchedPolicy(args->policy); + } +} void* FixedTimeslotTask::taskEntryPoint(void* arg) { // The argument is re-interpreted as PollingTask. diff --git a/src/fsfw/osal/linux/FixedTimeslotTask.h b/src/fsfw/osal/linux/FixedTimeslotTask.h index 1f5766a2e..0957bedc7 100644 --- a/src/fsfw/osal/linux/FixedTimeslotTask.h +++ b/src/fsfw/osal/linux/FixedTimeslotTask.h @@ -23,7 +23,8 @@ class FixedTimeslotTask : public FixedTimeslotTaskBase { * @param deadlineMissedFunc_ */ FixedTimeslotTask(const char* name_, TaskPriority priority_, size_t stackSize_, - TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_); + TaskPeriod periodSeconds_, TaskDeadlineMissedFunction dlmFunc_, + PosixThreadArgs* args); ~FixedTimeslotTask() override = default; ReturnValue_t startTask() override; diff --git a/src/fsfw/osal/linux/PeriodicPosixTask.cpp b/src/fsfw/osal/linux/PeriodicPosixTask.cpp index 556a0367e..5f1256d70 100644 --- a/src/fsfw/osal/linux/PeriodicPosixTask.cpp +++ b/src/fsfw/osal/linux/PeriodicPosixTask.cpp @@ -4,10 +4,15 @@ #include "fsfw/tasks/ExecutableObjectIF.h" PeriodicPosixTask::PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, - TaskPeriod period_, TaskDeadlineMissedFunction dlmFunc_) + TaskPeriod period_, TaskDeadlineMissedFunction dlmFunc_, + PosixThreadArgs* args) : PeriodicTaskBase(period_, dlmFunc_), - posixThread(name_, priority_, stackSize_), - started(false) {} + posixThread(name_, SchedulingPolicy::REGULAR, priority_, stackSize_), + started(false) { + if (args != nullptr) { + posixThread.setSchedPolicy(args->policy); + } +} void* PeriodicPosixTask::taskEntryPoint(void* arg) { // The argument is re-interpreted as PollingTask. diff --git a/src/fsfw/osal/linux/PeriodicPosixTask.h b/src/fsfw/osal/linux/PeriodicPosixTask.h index 085c10b97..eac14f0c7 100644 --- a/src/fsfw/osal/linux/PeriodicPosixTask.h +++ b/src/fsfw/osal/linux/PeriodicPosixTask.h @@ -24,7 +24,7 @@ class PeriodicPosixTask : public PeriodicTaskBase { * @param deadlineMissedFunc_ */ PeriodicPosixTask(const char* name_, int priority_, size_t stackSize_, TaskPeriod period_, - TaskDeadlineMissedFunction dlmFunc_); + TaskDeadlineMissedFunction dlmFunc_, PosixThreadArgs* args); ~PeriodicPosixTask() override = default; /** diff --git a/src/fsfw/osal/linux/PosixThread.cpp b/src/fsfw/osal/linux/PosixThread.cpp index 811d58e2f..f420b3268 100644 --- a/src/fsfw/osal/linux/PosixThread.cpp +++ b/src/fsfw/osal/linux/PosixThread.cpp @@ -7,8 +7,9 @@ #include "fsfw/osal/linux/unixUtility.h" #include "fsfw/serviceinterface/ServiceInterface.h" -PosixThread::PosixThread(const char* name_, int priority_, size_t stackSize_) - : thread(0), priority(priority_), stackSize(stackSize_) { +PosixThread::PosixThread(const char* name_, SchedulingPolicy schedPolciy, int priority_, + size_t stackSize_) + : thread(0), schedPolicy(schedPolciy), priority(priority_), stackSize(stackSize_) { name[0] = '\0'; std::strncat(name, name_, PTHREAD_MAX_NAMELEN - 1); } @@ -178,20 +179,30 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) { #ifndef FSFW_USE_REALTIME_FOR_LINUX #error "Please define FSFW_USE_REALTIME_FOR_LINUX with either 0 or 1" #endif + if (schedPolicy == SchedulingPolicy::RR) { + // RR -> This needs root privileges for the process #if FSFW_USE_REALTIME_FOR_LINUX == 1 - // FIFO -> This needs root privileges for the process - status = pthread_attr_setschedpolicy(&attributes, SCHED_FIFO); - if (status != 0) { - utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setschedpolicy"); + status = pthread_attr_setschedpolicy(&attributes, SCHED_RR); + if (status != 0) { + utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setschedpolicy"); + } + sched_param scheduleParams; + scheduleParams.sched_priority = priority; + status = pthread_attr_setschedparam(&attributes, &scheduleParams); + if (status != 0) { +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning << "PosixThread: Setting priority failed" << std::endl; +#endif + } +#else +#if FSFW_CPP_OSTREAM_ENABLED == 1 + sif::warning + << "Real time priorities are only allowed if FSFW_USE_REALTIME_FOR_LINUX is set to 1" + << std::endl; +#endif +#endif } - sched_param scheduleParams; - scheduleParams.__sched_priority = priority; - status = pthread_attr_setschedparam(&attributes, &scheduleParams); - if (status != 0) { - utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_setschedparam"); - } -#endif // Set Signal Mask for suspend until startTask is called sigset_t waitSignal; sigemptyset(&waitSignal); @@ -243,3 +254,5 @@ void PosixThread::createTask(void* (*fnc_)(void*), void* arg_) { utility::printUnixErrorGeneric(CLASS_NAME, "createTask", "pthread_attr_destroy"); } } + +void PosixThread::setSchedPolicy(SchedulingPolicy policy) { this->schedPolicy = policy; } diff --git a/src/fsfw/osal/linux/PosixThread.h b/src/fsfw/osal/linux/PosixThread.h index add41bf68..133a9884a 100644 --- a/src/fsfw/osal/linux/PosixThread.h +++ b/src/fsfw/osal/linux/PosixThread.h @@ -9,10 +9,15 @@ #include "../../returnvalues/returnvalue.h" +enum SchedulingPolicy { REGULAR, RR }; +struct PosixThreadArgs { + SchedulingPolicy policy = SchedulingPolicy::REGULAR; +}; + class PosixThread { public: static constexpr uint8_t PTHREAD_MAX_NAMELEN = 16; - PosixThread(const char* name_, int priority_, size_t stackSize_); + PosixThread(const char* name_, SchedulingPolicy schedPolicy, int priority_, size_t stackSize_); virtual ~PosixThread(); /** * Set the Thread to sleep state @@ -20,6 +25,9 @@ class PosixThread { * @return Returns Failed if sleep fails */ static ReturnValue_t sleep(uint64_t ns); + + void setSchedPolicy(SchedulingPolicy policy); + /** * @brief Function to suspend the task until SIGUSR1 was received * @@ -72,6 +80,7 @@ class PosixThread { private: char name[PTHREAD_MAX_NAMELEN]; + SchedulingPolicy schedPolicy; int priority; size_t stackSize = 0; diff --git a/src/fsfw/osal/linux/TaskFactory.cpp b/src/fsfw/osal/linux/TaskFactory.cpp index bacc4311c..c93f3fded 100644 --- a/src/fsfw/osal/linux/TaskFactory.cpp +++ b/src/fsfw/osal/linux/TaskFactory.cpp @@ -12,18 +12,20 @@ TaskFactory::~TaskFactory() = default; TaskFactory* TaskFactory::instance() { return TaskFactory::factoryInstance; } -PeriodicTaskIF* TaskFactory::createPeriodicTask( - TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_, - TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) { +PeriodicTaskIF* TaskFactory::createPeriodicTask(TaskName name_, TaskPriority taskPriority_, + TaskStackSize stackSize_, + TaskPeriod periodInSeconds_, + TaskDeadlineMissedFunction deadLineMissedFunction_, + void* args) { return new PeriodicPosixTask(name_, taskPriority_, stackSize_, periodInSeconds_, - deadLineMissedFunction_); + deadLineMissedFunction_, reinterpret_cast(args)); } FixedTimeslotTaskIF* TaskFactory::createFixedTimeslotTask( TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_, - TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_) { + TaskPeriod periodInSeconds_, TaskDeadlineMissedFunction deadLineMissedFunction_, void* args) { return new FixedTimeslotTask(name_, taskPriority_, stackSize_, periodInSeconds_, - deadLineMissedFunction_); + deadLineMissedFunction_, reinterpret_cast(args)); } ReturnValue_t TaskFactory::deleteTask(PeriodicTaskIF* task) { diff --git a/src/fsfw/parameters/HasParametersIF.h b/src/fsfw/parameters/HasParametersIF.h index d586cebab..8dc996449 100644 --- a/src/fsfw/parameters/HasParametersIF.h +++ b/src/fsfw/parameters/HasParametersIF.h @@ -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, diff --git a/src/fsfw/parameters/ParameterWrapper.cpp b/src/fsfw/parameters/ParameterWrapper.cpp index 522a68b1e..ad1d2a51e 100644 --- a/src/fsfw/parameters/ParameterWrapper.cpp +++ b/src/fsfw/parameters/ParameterWrapper.cpp @@ -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; diff --git a/src/fsfw/power/DummyPowerSwitcher.cpp b/src/fsfw/power/DummyPowerSwitcher.cpp index 952a5a575..80b4cc4a2 100644 --- a/src/fsfw/power/DummyPowerSwitcher.cpp +++ b/src/fsfw/power/DummyPowerSwitcher.cpp @@ -6,7 +6,11 @@ DummyPowerSwitcher::DummyPowerSwitcher(object_id_t objectId, size_t numberOfSwit : SystemObject(objectId, registerGlobally), switcherList(numberOfSwitches), fuseList(numberOfFuses), - switchDelayMs(switchDelayMs) {} + switchDelayMs(switchDelayMs) { + for (auto &switchState : switcherList) { + switchState = PowerSwitchIF::SWITCH_UNKNOWN; + } +} void DummyPowerSwitcher::setInitialSwitcherList(std::vector switcherList) { this->switcherList = switcherList; diff --git a/src/fsfw/power/PowerSwitcherComponent.cpp b/src/fsfw/power/PowerSwitcherComponent.cpp index b6b67a83a..39a8a2d0f 100644 --- a/src/fsfw/power/PowerSwitcherComponent.cpp +++ b/src/fsfw/power/PowerSwitcherComponent.cpp @@ -2,8 +2,9 @@ #include #include +#include -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), @@ -28,6 +29,9 @@ ReturnValue_t PowerSwitcherComponent::performOperation(uint8_t opCode) { continue; } } + if (getHealth() == FAULTY) { + performFaultyOperation(); + } if (switcher.active()) { switcher.doStateMachine(); auto currState = switcher.getState(); @@ -54,7 +58,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 +69,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 +109,17 @@ 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 modetree::connectModeTreeParent(parent, *this, &healthHelper, modeHelper); +} + +object_id_t PowerSwitcherComponent::getObjectId() const { return SystemObject::getObjectId(); } + +ModeTreeChildIF& PowerSwitcherComponent::getModeTreeChildIF() { return *this; } + +void PowerSwitcherComponent::performFaultyOperation() {} diff --git a/src/fsfw/power/PowerSwitcherComponent.h b/src/fsfw/power/PowerSwitcherComponent.h index 01689befd..8c74e76f9 100644 --- a/src/fsfw/power/PowerSwitcherComponent.h +++ b/src/fsfw/power/PowerSwitcherComponent.h @@ -1,5 +1,4 @@ -#ifndef _FSFW_POWER_POWERSWITCHERCOMPONENT_H_ -#define _FSFW_POWER_POWERSWITCHERCOMPONENT_H_ +#pragma once #include #include @@ -8,6 +7,8 @@ #include #include #include +#include +#include #include class PowerSwitchIF; @@ -24,17 +25,24 @@ 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); - private: - MessageQueueIF *queue = nullptr; + ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF &parent) override; + ModeTreeChildIF &getModeTreeChildIF() override; + + protected: PowerSwitcher switcher; - Mode_t mode = MODE_OFF; + private: + MessageQueueIF *queue = nullptr; + + Mode_t mode = MODE_UNDEFINED; Submode_t submode = 0; ModeHelper modeHelper; @@ -42,20 +50,23 @@ class PowerSwitcherComponent : public SystemObject, void setMode(Mode_t newMode, Submode_t newSubmode); - virtual ReturnValue_t performOperation(uint8_t opCode) override; + ReturnValue_t performOperation(uint8_t opCode) override; ReturnValue_t initialize() override; - MessageQueueId_t getCommandQueue() const override; + [[nodiscard]] MessageQueueId_t getCommandQueue() const override; void getMode(Mode_t *mode, Submode_t *submode) override; ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, uint32_t *msToReachTheMode) override; void startTransition(Mode_t mode, Submode_t submode) override; + virtual void performFaultyOperation(); void setToExternalControl() override; void announceMode(bool recursive) override; ReturnValue_t setHealth(HealthState health) override; HasHealthIF::HealthState getHealth() override; -}; -#endif /* _FSFW_POWER_POWERSWITCHERCOMPONENT_H_ */ + [[nodiscard]] object_id_t getObjectId() const override; + [[nodiscard]] const HasHealthIF *getOptHealthIF() const override; + [[nodiscard]] const HasModesIF &getModeIF() const override; +}; diff --git a/src/fsfw/pus/Service11TelecommandScheduling.tpp b/src/fsfw/pus/Service11TelecommandScheduling.tpp index ac08f02ca..8352f85db 100644 --- a/src/fsfw/pus/Service11TelecommandScheduling.tpp +++ b/src/fsfw/pus/Service11TelecommandScheduling.tpp @@ -79,7 +79,7 @@ inline ReturnValue_t Service11TelecommandScheduling::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(tNow.tv_sec)) { if (schedulingEnabled) { // release tc TmTcMessage releaseMsg(it->second.storeAddr); @@ -160,7 +160,7 @@ inline ReturnValue_t Service11TelecommandScheduling::doInsertActivi // (See requirement for Time margin) timeval tNow = {}; Clock::getClock_timeval(&tNow); - if (timestamp - tNow.tv_sec <= RELEASE_TIME_MARGIN_SECONDS) { + if (timestamp < static_cast(tNow.tv_sec + RELEASE_TIME_MARGIN_SECONDS)) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "Service11TelecommandScheduling::doInsertActivity: Release time too close to " "current time" diff --git a/src/fsfw/pus/Service17Test.cpp b/src/fsfw/pus/Service17Test.cpp index bea2eeb83..35fc7c9db 100644 --- a/src/fsfw/pus/Service17Test.cpp +++ b/src/fsfw/pus/Service17Test.cpp @@ -1,5 +1,7 @@ #include "fsfw/pus/Service17Test.h" +#include + #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 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; } diff --git a/src/fsfw/pus/Service17Test.h b/src/fsfw/pus/Service17Test.h index f2ec6e4f5..d3b6a6dc6 100644 --- a/src/fsfw/pus/Service17Test.h +++ b/src/fsfw/pus/Service17Test.h @@ -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); diff --git a/src/fsfw/pus/Service3Housekeeping.cpp b/src/fsfw/pus/Service3Housekeeping.cpp index 3ce93c706..c6fac20c7 100644 --- a/src/fsfw/pus/Service3Housekeeping.cpp +++ b/src/fsfw/pus/Service3Housekeeping.cpp @@ -4,9 +4,10 @@ #include "fsfw/objectmanager/ObjectManager.h" #include "fsfw/pus/servicepackets/Service3Packets.h" -Service3Housekeeping::Service3Housekeeping(object_id_t objectId, uint16_t apid, uint8_t serviceId) - : CommandingServiceBase(objectId, apid, "PUS 3 HK", serviceId, NUM_OF_PARALLEL_COMMANDS, - COMMAND_TIMEOUT_SECONDS) {} +Service3Housekeeping::Service3Housekeeping(object_id_t objectId, uint16_t apid, uint8_t serviceId, + uint32_t queueDepth, uint8_t numParallelCommands) + : CommandingServiceBase(objectId, apid, "PUS 3 HK", serviceId, numParallelCommands, + COMMAND_TIMEOUT_SECONDS, queueDepth) {} Service3Housekeeping::~Service3Housekeeping() {} @@ -208,17 +209,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 +249,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 +285,7 @@ void Service3Housekeeping::handleUnrequestedReply(CommandMessage* reply) { "Could not generate reply!\n"); #endif } + CommandingServiceBase::handleUnrequestedReply(reply); } MessageQueueId_t Service3Housekeeping::getHkQueue() const { return commandQueue->getId(); } diff --git a/src/fsfw/pus/Service3Housekeeping.h b/src/fsfw/pus/Service3Housekeeping.h index 70f157625..10004bc6c 100644 --- a/src/fsfw/pus/Service3Housekeeping.h +++ b/src/fsfw/pus/Service3Housekeeping.h @@ -28,7 +28,8 @@ class Service3Housekeeping : public CommandingServiceBase, public AcceptsHkPacke static constexpr uint8_t NUM_OF_PARALLEL_COMMANDS = 4; static constexpr uint16_t COMMAND_TIMEOUT_SECONDS = 60; - Service3Housekeeping(object_id_t objectId, uint16_t apid, uint8_t serviceId); + Service3Housekeeping(object_id_t objectId, uint16_t apid, uint8_t serviceId, uint32_t queueDepth, + uint8_t numParallelCommands); virtual ~Service3Housekeeping(); protected: diff --git a/src/fsfw/pus/Service5EventReporting.cpp b/src/fsfw/pus/Service5EventReporting.cpp index 9145920ca..b4b9b03dc 100644 --- a/src/fsfw/pus/Service5EventReporting.cpp +++ b/src/fsfw/pus/Service5EventReporting.cpp @@ -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(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; } diff --git a/src/fsfw/pus/Service5EventReporting.h b/src/fsfw/pus/Service5EventReporting.h index 1f4e5a3ae..0c7382260 100644 --- a/src/fsfw/pus/Service5EventReporting.h +++ b/src/fsfw/pus/Service5EventReporting.h @@ -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; /*** diff --git a/src/fsfw/pus/Service8FunctionManagement.cpp b/src/fsfw/pus/Service8FunctionManagement.cpp index 8b7c6972f..2607adcac 100644 --- a/src/fsfw/pus/Service8FunctionManagement.cpp +++ b/src/fsfw/pus/Service8FunctionManagement.cpp @@ -9,11 +9,11 @@ #include "fsfw/serviceinterface/ServiceInterface.h" Service8FunctionManagement::Service8FunctionManagement(object_id_t objectId, uint16_t apid, - uint8_t serviceId, + uint8_t serviceId, size_t queueDepth, uint8_t numParallelCommands, uint16_t commandTimeoutSeconds) : CommandingServiceBase(objectId, apid, "PUS 8 Functional Commanding", serviceId, - numParallelCommands, commandTimeoutSeconds) {} + numParallelCommands, commandTimeoutSeconds, queueDepth) {} Service8FunctionManagement::~Service8FunctionManagement() {} diff --git a/src/fsfw/pus/Service8FunctionManagement.h b/src/fsfw/pus/Service8FunctionManagement.h index 38aaf4f4b..0ec715b81 100644 --- a/src/fsfw/pus/Service8FunctionManagement.h +++ b/src/fsfw/pus/Service8FunctionManagement.h @@ -31,7 +31,8 @@ class Service8FunctionManagement : public CommandingServiceBase { public: Service8FunctionManagement(object_id_t objectId, uint16_t apid, uint8_t serviceId, - uint8_t numParallelCommands = 4, uint16_t commandTimeoutSeconds = 60); + size_t queueDepth, uint8_t numParallelCommands = 4, + uint16_t commandTimeoutSeconds = 60); ~Service8FunctionManagement() override; protected: diff --git a/src/fsfw/pus/servicepackets/Service200Packets.h b/src/fsfw/pus/servicepackets/Service200Packets.h index 701e3f09f..3e1df55a0 100644 --- a/src/fsfw/pus/servicepackets/Service200Packets.h +++ b/src/fsfw/pus/servicepackets/Service200Packets.h @@ -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 diff --git a/src/fsfw/storagemanager/PoolManager.cpp b/src/fsfw/storagemanager/PoolManager.cpp index 840a7dcc2..665edbd95 100644 --- a/src/fsfw/storagemanager/PoolManager.cpp +++ b/src/fsfw/storagemanager/PoolManager.cpp @@ -3,14 +3,14 @@ #include "fsfw/FSFW.h" PoolManager::PoolManager(object_id_t setObjectId, const LocalPoolConfig& localPoolConfig) - : LocalPool(setObjectId, localPoolConfig, true) { + : LocalPool(setObjectId, localPoolConfig, true, true) { mutex = MutexFactory::instance()->createMutex(); } PoolManager::~PoolManager() { MutexFactory::instance()->deleteMutex(mutex); } ReturnValue_t PoolManager::reserveSpace(const size_t size, store_address_t* address) { - MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs); + MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs, LOCK_CTX); ReturnValue_t status = LocalPool::reserveSpace(size, address); return status; } @@ -22,12 +22,12 @@ ReturnValue_t PoolManager::deleteData(store_address_t storeId) { << storeId.poolIndex << ". id is " << storeId.packetIndex << std::endl; #endif #endif - MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs); + MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs, LOCK_CTX); return LocalPool::deleteData(storeId); } ReturnValue_t PoolManager::deleteData(uint8_t* buffer, size_t size, store_address_t* storeId) { - MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, 20); + MutexGuard mutexHelper(mutex, MutexIF::TimeoutType::WAITING, mutexTimeoutMs, LOCK_CTX); ReturnValue_t status = LocalPool::deleteData(buffer, size, storeId); return status; } diff --git a/src/fsfw/storagemanager/PoolManager.h b/src/fsfw/storagemanager/PoolManager.h index aa8c93ddc..d4bb9f0d1 100644 --- a/src/fsfw/storagemanager/PoolManager.h +++ b/src/fsfw/storagemanager/PoolManager.h @@ -56,6 +56,7 @@ class PoolManager : public LocalPool { protected: //! Default mutex timeout value to prevent permanent blocking. uint32_t mutexTimeoutMs = 20; + static constexpr char LOCK_CTX[] = "PoolManager"; ReturnValue_t reserveSpace(size_t size, store_address_t* address) override; diff --git a/src/fsfw/subsystem/CMakeLists.txt b/src/fsfw/subsystem/CMakeLists.txt index 164c90f7e..95dce8a51 100644 --- a/src/fsfw/subsystem/CMakeLists.txt +++ b/src/fsfw/subsystem/CMakeLists.txt @@ -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) diff --git a/src/fsfw/subsystem/HasModeTreeChildrenIF.h b/src/fsfw/subsystem/HasModeTreeChildrenIF.h new file mode 100644 index 000000000..3458d008c --- /dev/null +++ b/src/fsfw/subsystem/HasModeTreeChildrenIF.h @@ -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_ diff --git a/src/fsfw/subsystem/ModeTreeChildIF.h b/src/fsfw/subsystem/ModeTreeChildIF.h new file mode 100644 index 000000000..6f8d8d86d --- /dev/null +++ b/src/fsfw/subsystem/ModeTreeChildIF.h @@ -0,0 +1,15 @@ +#ifndef FSFW_SUBSYSTEM_MODETREECHILDIF_H_ +#define FSFW_SUBSYSTEM_MODETREECHILDIF_H_ + +#include +#include + +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_ */ diff --git a/src/fsfw/subsystem/ModeTreeConnectionIF.h b/src/fsfw/subsystem/ModeTreeConnectionIF.h new file mode 100644 index 000000000..4fe54ada6 --- /dev/null +++ b/src/fsfw/subsystem/ModeTreeConnectionIF.h @@ -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_ */ diff --git a/src/fsfw/subsystem/Subsystem.cpp b/src/fsfw/subsystem/Subsystem.cpp index b2af5ac37..ad3afb2b4 100644 --- a/src/fsfw/subsystem/Subsystem.cpp +++ b/src/fsfw/subsystem/Subsystem.cpp @@ -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 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())); diff --git a/src/fsfw/subsystem/Subsystem.h b/src/fsfw/subsystem/Subsystem.h index 855c8f7ab..209258214 100644 --- a/src/fsfw/subsystem/Subsystem.h +++ b/src/fsfw/subsystem/Subsystem.h @@ -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); diff --git a/src/fsfw/subsystem/SubsystemBase.cpp b/src/fsfw/subsystem/SubsystemBase.cpp index 86ee251a1..4f62a889e 100644 --- a/src/fsfw/subsystem/SubsystemBase.cpp +++ b/src/fsfw/subsystem/SubsystemBase.cpp @@ -1,52 +1,27 @@ #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(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(objectId); - // This is a rather ugly hack to have the changedHealth info for all - // children available. - HasHealthIF* healthChild = ObjectManager::instance()->get(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 tableIter, Submode_t targetSubmode) { + using namespace mode; std::map::iterator childIter; for (; tableIter.value != NULL; ++tableIter) { @@ -60,13 +35,21 @@ ReturnValue_t SubsystemBase::checkStateAgainstTable(HybridIteratorgetSubmode(); + // Check submodes here. + uint8_t mask; + bool submodesAllowedMask = tableIter.value->submodesAllowed(&mask); + uint8_t submodeToCheckAgainst = tableIter.value->getSubmode(); if (tableIter.value->inheritSubmode()) { submodeToCheckAgainst = targetSubmode; } - - if (childIter->second.submode != submodeToCheckAgainst) { - return returnvalue::FAILED; + if (submodesAllowedMask) { + if ((childIter->second.submode | mask) != mask) { + return returnvalue::FAILED; + } + } else { + if (childIter->second.submode != submodeToCheckAgainst) { + return returnvalue::FAILED; + } } } return returnvalue::OK; @@ -84,7 +67,8 @@ void SubsystemBase::executeTable(HybridIterator 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; } @@ -142,6 +126,20 @@ ReturnValue_t SubsystemBase::updateChildMode(MessageQueueId_t queue, Mode_t mode return CHILD_NOT_FOUND; } +ReturnValue_t SubsystemBase::updateChildModeByObjId(object_id_t objectId, Mode_t mode, + Submode_t submode) { + std::map::iterator iter; + + for (iter = childrenMap.begin(); iter != childrenMap.end(); iter++) { + if (iter->first == objectId) { + iter->second.mode = mode; + iter->second.submode = submode; + return returnvalue::OK; + } + } + return CHILD_NOT_FOUND; +} + ReturnValue_t SubsystemBase::updateChildChangedHealth(MessageQueueId_t queue, bool changedHealth) { for (auto iter = childrenMap.begin(); iter != childrenMap.end(); iter++) { if (iter->second.commandQueue == queue) { @@ -155,36 +153,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(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 +214,14 @@ ReturnValue_t SubsystemBase::handleModeReply(CommandMessage* message) { } ReturnValue_t SubsystemBase::checkTable(HybridIterator 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 +306,36 @@ 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) { + return registerChild(child.getObjectId(), child.getModeIF().getCommandQueue()); +} + +const HasHealthIF* SubsystemBase::getOptHealthIF() const { return this; } + +const HasModesIF& SubsystemBase::getModeIF() const { return *this; } + +ModeTreeChildIF& SubsystemBase::getModeTreeChildIF() { return *this; } + +ReturnValue_t SubsystemBase::registerChild(object_id_t childObjectId, MessageQueueId_t childQueue) { + ChildInfo info; + + // intentional to force an initial command during system startup + info.commandQueue = childQueue; + info.mode = HasModesIF::MODE_UNDEFINED; + info.submode = SUBMODE_NONE; + info.healthChanged = false; + + auto resultPair = childrenMap.emplace(childObjectId, info); + if (not resultPair.second) { + return COULD_NOT_INSERT_CHILD; + } + return returnvalue::OK; +} diff --git a/src/fsfw/subsystem/SubsystemBase.h b/src/fsfw/subsystem/SubsystemBase.h index 6db9efa51..072b4ca42 100644 --- a/src/fsfw/subsystem/SubsystemBase.h +++ b/src/fsfw/subsystem/SubsystemBase.h @@ -3,23 +3,35 @@ #include -#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,36 @@ 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; + // TODO: Add this to HasModeTreeChildrenIF. + ReturnValue_t registerChild(object_id_t childObjectId, MessageQueueId_t childQueue); - 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 +97,6 @@ class SubsystemBase : public SystemObject, ModeHelper modeHelper; - const object_id_t parentId; - typedef std::map ChildrenMap; ChildrenMap childrenMap; @@ -95,6 +109,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 */ @@ -102,6 +117,7 @@ class SubsystemBase : public SystemObject, Submode_t targetSubmode = SUBMODE_NONE); ReturnValue_t updateChildMode(MessageQueueId_t queue, Mode_t mode, Submode_t submode); + ReturnValue_t updateChildModeByObjId(object_id_t objectId, Mode_t mode, Submode_t submode); ReturnValue_t updateChildChangedHealth(MessageQueueId_t queue, bool changedHealth = true); @@ -128,6 +144,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; diff --git a/src/fsfw/subsystem/helper.cpp b/src/fsfw/subsystem/helper.cpp new file mode 100644 index 000000000..7b29825a9 --- /dev/null +++ b/src/fsfw/subsystem/helper.cpp @@ -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; +} diff --git a/src/fsfw/subsystem/helper.h b/src/fsfw/subsystem/helper.h new file mode 100644 index 000000000..7a394e49a --- /dev/null +++ b/src/fsfw/subsystem/helper.h @@ -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_ */ diff --git a/src/fsfw/subsystem/modes/ModeDefinitions.h b/src/fsfw/subsystem/modes/ModeDefinitions.h index d22bcd954..70a66fa6c 100644 --- a/src/fsfw/subsystem/modes/ModeDefinitions.h +++ b/src/fsfw/subsystem/modes/ModeDefinitions.h @@ -1,111 +1,126 @@ #ifndef FSFW_SUBSYSTEM_MODES_MODEDEFINITIONS_H_ #define FSFW_SUBSYSTEM_MODES_MODEDEFINITIONS_H_ -#include "../../modes/HasModesIF.h" -#include "../../objectmanager/SystemObjectIF.h" -#include "../../serialize/SerialLinkedListAdapter.h" -#include "../../serialize/SerializeIF.h" +#include "fsfw/modes/HasModesIF.h" +#include "fsfw/objectmanager/SystemObjectIF.h" +#include "fsfw/serialize/SerialLinkedListAdapter.h" +#include "fsfw/serialize/SerializeIF.h" -class ModeListEntry : public SerializeIF, public LinkedElement { +namespace mode { +enum SpecialSubmodeFlags : uint8_t { INHERIT = 1 << 0, ALLOWED_MASK = 1 << 1 }; +} + +class ModeListEntry : public SerialLinkedListAdapter, + public LinkedElement { public: - ModeListEntry() : LinkedElement(this) {} + static constexpr uint8_t ALL_SUBMODES_ALLOWED_MASK = 0xff; - uint32_t value1 = 0; - uint32_t value2 = 0; - uint8_t value3 = 0; - uint8_t value4 = 0; + ModeListEntry() : SerialLinkedListAdapter(), LinkedElement(this) { setLinks(); } - virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, - Endianness streamEndianness) const { - ReturnValue_t result; + SerializeElement value1 = 0; + SerializeElement value2 = 0; + SerializeElement value3 = 0; + SerializeElement value4 = 0; + SerializeElement value5 = 0; - result = SerializeAdapter::serialize(&value1, buffer, size, maxSize, streamEndianness); - - if (result != returnvalue::OK) { - return result; - } - result = SerializeAdapter::serialize(&value2, buffer, size, maxSize, streamEndianness); - - if (result != returnvalue::OK) { - return result; - } - result = SerializeAdapter::serialize(&value3, buffer, size, maxSize, streamEndianness); - - if (result != returnvalue::OK) { - return result; - } - - result = SerializeAdapter::serialize(&value4, buffer, size, maxSize, streamEndianness); - - return result; + ModeListEntry(const ModeListEntry& other) + : SerialLinkedListAdapter(), LinkedElement(this) { + value1.entry = other.value1.entry; + value2.entry = other.value2.entry; + value3.entry = other.value3.entry; + value4.entry = other.value4.entry; + value5.entry = other.value5.entry; + setLinks(); } - virtual size_t getSerializedSize() const { - return sizeof(value1) + sizeof(value2) + sizeof(value3) + sizeof(value4); + ModeListEntry& operator=(const ModeListEntry& other) { + this->value1.entry = other.value1.entry; + this->value2.entry = other.value2.entry; + this->value3.entry = other.value3.entry; + this->value4.entry = other.value4.entry; + this->value5.entry = other.value5.entry; + return *this; } - virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, - Endianness streamEndianness) { - ReturnValue_t result; - - result = SerializeAdapter::deSerialize(&value1, buffer, size, streamEndianness); - - if (result != returnvalue::OK) { - return result; - } - result = SerializeAdapter::deSerialize(&value2, buffer, size, streamEndianness); - - if (result != returnvalue::OK) { - return result; - } - result = SerializeAdapter::deSerialize(&value3, buffer, size, streamEndianness); - - if (result != returnvalue::OK) { - return result; - } - result = SerializeAdapter::deSerialize(&value4, buffer, size, streamEndianness); - - return result; + void setLinks() { + setStart(&value1); + value1.setNext(&value2); + value2.setNext(&value3); + value3.setNext(&value4); + value4.setNext(&value5); } // for Sequences - Mode_t getTableId() const { return value1; } + Mode_t getTableId() const { return value1.entry; } - void setTableId(Mode_t tableId) { this->value1 = tableId; } + void setTableId(Mode_t tableId) { this->value1.entry = tableId; } - uint8_t getWaitSeconds() const { return value2; } + uint8_t getWaitSeconds() const { return value2.entry; } - void setWaitSeconds(uint8_t waitSeconds) { this->value2 = waitSeconds; } + void setWaitSeconds(uint8_t waitSeconds) { this->value2.entry = waitSeconds; } - bool checkSuccess() const { return value3 == 1; } + bool checkSuccess() const { return value3.entry == 1; } - void setCheckSuccess(bool checkSuccess) { this->value3 = checkSuccess; } + void setCheckSuccess(bool checkSuccess) { this->value3.entry = checkSuccess; } // for Tables - object_id_t getObject() const { return value1; } + object_id_t getObject() const { return value1.entry; } - void setObject(object_id_t object) { this->value1 = object; } + void setObject(object_id_t object) { this->value1.entry = object; } - Mode_t getMode() const { return value2; } + Mode_t getMode() const { return value2.entry; } - void setMode(Mode_t mode) { this->value2 = mode; } + void setMode(Mode_t mode) { this->value2.entry = mode; } - Submode_t getSubmode() const { return value3; } + Submode_t getSubmode() const { return value3.entry; } - void setSubmode(Submode_t submode) { this->value3 = submode; } + void setSubmode(Submode_t submode) { this->value3.entry = submode; } - bool inheritSubmode() const { return value4 == 1; } - - void setInheritSubmode(bool inherit) { - if (inherit) { - value4 = 1; - } else { - value4 = 0; + bool inheritSubmode() const { + return (value4.entry & mode::SpecialSubmodeFlags::INHERIT) == + mode::SpecialSubmodeFlags::INHERIT; + } + bool submodesAllowed(uint8_t* mask) const { + bool submodesAllowed = (value4.entry & mode::SpecialSubmodeFlags::ALLOWED_MASK) == + mode::SpecialSubmodeFlags::ALLOWED_MASK; + if (submodesAllowed and mask != nullptr) { + *mask = value5.entry; } + return submodesAllowed; } - bool operator==(ModeListEntry other) { - return ((value1 == other.value1) && (value2 == other.value2) && (value3 == other.value3)); + /** + * Enable the inheritance of submodes. This is relevant for both the execution + * of mode tables and for mode checking. + */ + void enableInheritSubmode() { value4.entry |= mode::SpecialSubmodeFlags::INHERIT; } + /** + * Disable the inheritance of submodes. This is relevant for both the execution + * of mode tables and for mode checking. + */ + void disableInheritSubmode() { value4.entry &= ~mode::SpecialSubmodeFlags::INHERIT; } + + /** + * Specialization of @enableSubmodeAllowed which allows all submodes. + */ + void allowAllSubmodes() { enableSubmodeAllowed(ALL_SUBMODES_ALLOWED_MASK); } + + /** + * Enable an allowed submode mask for mode checks. Any submode which contains bits + * outside of the mask will be declined. + * + * For example, for a mask of 0b11, only the modes 0b00, 0b01 and 0b11 will be accepted. + */ + void enableSubmodeAllowed(uint8_t mask) { + value4.entry |= mode::SpecialSubmodeFlags::ALLOWED_MASK; + value5.entry = mask; + } + /** + * Enforce the equality of submodes for mode checks. This is the default. + */ + void disableSubmodeAllowed() { + value4.entry &= ~mode::SpecialSubmodeFlags::ALLOWED_MASK; + value5.entry = 0; } }; diff --git a/src/fsfw/tasks/FixedTimeslotTaskBase.cpp b/src/fsfw/tasks/FixedTimeslotTaskBase.cpp index 3327deaed..0e1e3c5d0 100644 --- a/src/fsfw/tasks/FixedTimeslotTaskBase.cpp +++ b/src/fsfw/tasks/FixedTimeslotTaskBase.cpp @@ -15,10 +15,10 @@ ReturnValue_t FixedTimeslotTaskBase::addSlot(object_id_t execId, ExecutableObjec uint32_t slotTimeMs, int8_t executionStep) { if (execObj == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::error << "Component 0x" << std::hex << std::setw(8) << std::setfill('0') << execObj + sif::error << "Component 0x" << std::hex << std::setw(8) << std::setfill('0') << execId << std::setfill(' ') << " not found, not adding it to PST" << std::dec << std::endl; #else - sif::printError("Component 0x%08x not found, not adding it to PST\n"); + sif::printError("Component 0x%08x not found, not adding it to PST\n", execId); #endif return returnvalue::FAILED; } diff --git a/src/fsfw/tasks/TaskFactory.h b/src/fsfw/tasks/TaskFactory.h index 828c533e3..e9b96a776 100644 --- a/src/fsfw/tasks/TaskFactory.h +++ b/src/fsfw/tasks/TaskFactory.h @@ -47,7 +47,8 @@ class TaskFactory { */ PeriodicTaskIF* createPeriodicTask(TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_, TaskPeriod periodInSeconds_, - TaskDeadlineMissedFunction deadLineMissedFunction_); + TaskDeadlineMissedFunction deadLineMissedFunction_, + void* args = nullptr); /** * The meaning for the variables for fixed timeslot tasks is the same as for periodic tasks. @@ -62,7 +63,8 @@ class TaskFactory { FixedTimeslotTaskIF* createFixedTimeslotTask(TaskName name_, TaskPriority taskPriority_, TaskStackSize stackSize_, TaskPeriod periodInSeconds_, - TaskDeadlineMissedFunction deadLineMissedFunction_); + TaskDeadlineMissedFunction deadLineMissedFunction_, + void* args = nullptr); /** * Function to be called to delete a task diff --git a/src/fsfw/thermal/AbstractTemperatureSensor.cpp b/src/fsfw/thermal/AbstractTemperatureSensor.cpp index fc182bf1a..7687bd387 100644 --- a/src/fsfw/thermal/AbstractTemperatureSensor.cpp +++ b/src/fsfw/thermal/AbstractTemperatureSensor.cpp @@ -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(this)); + commandQueue = QueueFactory::instance()->createMessageQueue( + 3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs); } AbstractTemperatureSensor::~AbstractTemperatureSensor() { diff --git a/src/fsfw/thermal/AbstractTemperatureSensor.h b/src/fsfw/thermal/AbstractTemperatureSensor.h index 0c6493fee..b790b0cae 100644 --- a/src/fsfw/thermal/AbstractTemperatureSensor.h +++ b/src/fsfw/thermal/AbstractTemperatureSensor.h @@ -51,7 +51,7 @@ class AbstractTemperatureSensor : public HasHealthIF, HasHealthIF::HealthState getHealth(); protected: - MessageQueueIF* commandQueue; + MessageQueueIF* commandQueue = nullptr; HealthHelper healthHelper; ParameterHelper parameterHelper; diff --git a/src/fsfw/thermal/Heater.cpp b/src/fsfw/thermal/Heater.cpp index 64348106a..da78a74a3 100644 --- a/src/fsfw/thermal/Heater.cpp +++ b/src/fsfw/thermal/Heater.cpp @@ -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(this)); + eventQueue = QueueFactory::instance()->createMessageQueue( + 3, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs); } Heater::~Heater() { QueueFactory::instance()->deleteMessageQueue(eventQueue); } @@ -281,7 +283,7 @@ ReturnValue_t Heater::getParameter(uint8_t domainId, uint8_t uniqueId, } switch (uniqueId) { case 0: - parameterWrapper->set(heaterOnCountdown.timeout); + parameterWrapper->set(heaterOnCountdown.getTimeoutMs()); break; default: return INVALID_IDENTIFIER_ID; diff --git a/src/fsfw/thermal/ThermalComponentIF.h b/src/fsfw/thermal/ThermalComponentIF.h index 0ab22d855..023d77587 100644 --- a/src/fsfw/thermal/ThermalComponentIF.h +++ b/src/fsfw/thermal/ThermalComponentIF.h @@ -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); diff --git a/src/fsfw/timemanager/CCSDSTime.cpp b/src/fsfw/timemanager/CCSDSTime.cpp index cb0d57587..7ca1f7f19 100644 --- a/src/fsfw/timemanager/CCSDSTime.cpp +++ b/src/fsfw/timemanager/CCSDSTime.cpp @@ -246,6 +246,20 @@ ReturnValue_t CCSDSTime::convertFromASCII(Clock::TimeOfDay_t* to, const uint8_t* return UNSUPPORTED_TIME_FORMAT; } +ReturnValue_t CCSDSTime::convertToAsciiWithSecs(int8_t* to, const Clock::TimeOfDay_t* from, + uint8_t length) { + if (from == nullptr or to == nullptr) { + return returnvalue::FAILED; + } + int count = snprintf(reinterpret_cast(to), length, + "%4" SCNu32 "-%2" SCNu32 "-%2" SCNu32 "T%2" SCNu32 ":%2" SCNu32 ":%2" SCNu32, + from->year, from->month, from->day, from->hour, from->minute, from->second); + if (count >= length) { + return returnvalue::FAILED; + } + return returnvalue::OK; +} + ReturnValue_t CCSDSTime::checkCcs(const uint8_t* time, uint8_t length) { const Ccs_mseconds* time_struct = reinterpret_cast(time); diff --git a/src/fsfw/timemanager/CCSDSTime.h b/src/fsfw/timemanager/CCSDSTime.h index 77801cecc..03a8ea8f8 100644 --- a/src/fsfw/timemanager/CCSDSTime.h +++ b/src/fsfw/timemanager/CCSDSTime.h @@ -207,7 +207,8 @@ class CCSDSTime { static ReturnValue_t convertFromASCII(Clock::TimeOfDay_t *to, uint8_t const *from, uint8_t length); - + static ReturnValue_t convertToAsciiWithSecs(int8_t *to, const Clock::TimeOfDay_t *from, + uint8_t length); static uint32_t subsecondsToMicroseconds(uint16_t subseconds); private: diff --git a/src/fsfw/timemanager/Clock.h b/src/fsfw/timemanager/Clock.h index 83bc3d9f8..6fe6486c8 100644 --- a/src/fsfw/timemanager/Clock.h +++ b/src/fsfw/timemanager/Clock.h @@ -49,6 +49,13 @@ class Clock { * @return -@c returnvalue::OK on success. Otherwise, the OS failure code is returned. */ static ReturnValue_t setClock(const timeval *time); + + /** + * @deprecated Use getClock instead, which does the same. + * @param time + * @return + */ + static ReturnValue_t getClock_timeval(timeval *time); /** * This system call returns the current system clock in timeval format. * The timval format has the fields @c tv_sec with seconds and @c tv_usec with @@ -56,7 +63,18 @@ class Clock { * @param time A pointer to a timeval struct where the current time is stored. * @return @c returnvalue::OK on success. Otherwise, the OS failure code is returned. */ - static ReturnValue_t getClock_timeval(timeval *time); + static ReturnValue_t getClock(timeval *time); + + /** + * Retrieve a monotonic clock. This clock this is also more suited for measuring elapsed times + * between two time points, but less suited when the absolute time is required. + * + * Implementation example: A generic UNIX implementation can use CLOCK_MONOTONIC_RAW with + * `clock_gettime`. + * @param time + * @return + */ + static ReturnValue_t getClockMonotonic(timeval *time); /** * Get the time since boot in a timeval struct diff --git a/src/fsfw/timemanager/Countdown.cpp b/src/fsfw/timemanager/Countdown.cpp index a8ba78cbb..5e743efe7 100644 --- a/src/fsfw/timemanager/Countdown.cpp +++ b/src/fsfw/timemanager/Countdown.cpp @@ -1,45 +1,62 @@ #include "fsfw/timemanager/Countdown.h" -Countdown::Countdown(uint32_t initialTimeout) : timeout(initialTimeout) { - setTimeout(initialTimeout); +#include "fsfw/globalfunctions/timevalOperations.h" + +Countdown::Countdown(uint32_t initialTimeout, bool startImmediately) { + if (startImmediately) { + setTimeout(initialTimeout); + } else { + timeout.tv_sec = initialTimeout / 1000; + timeout.tv_usec = (initialTimeout % 1000) * 1000; + } } -Countdown::~Countdown() {} +Countdown::~Countdown() = default; ReturnValue_t Countdown::setTimeout(uint32_t milliseconds) { - ReturnValue_t returnValue = Clock::getUptime(&startTime); - timeout = milliseconds; - return returnValue; + timeout.tv_sec = milliseconds / 1000; + timeout.tv_usec = (milliseconds % 1000) * 1000; + return Clock::getClockMonotonic(&startTime); } bool Countdown::hasTimedOut() const { - if (uint32_t(this->getCurrentTime() - startTime) >= timeout) { + // Account for system clock going back in time. + if (getCurrentTime() < startTime) { return true; - } else { - return false; } + if (getCurrentTime() - startTime >= timeout) { + return true; + } + return false; } bool Countdown::isBusy() const { return !hasTimedOut(); } -ReturnValue_t Countdown::resetTimer() { return setTimeout(timeout); } +ReturnValue_t Countdown::resetTimer() { return setTimeoutTv(timeout); } void Countdown::timeOut() { startTime = this->getCurrentTime() - timeout; } uint32_t Countdown::getRemainingMillis() const { - // We fetch the time before the if-statement - // to be sure that the return is in - // range 0 <= number <= timeout - uint32_t currentTime = this->getCurrentTime(); if (this->hasTimedOut()) { return 0; - } else { - return (startTime + timeout) - currentTime; } + timeval remainingMillisTv = (startTime + timeout) - this->getCurrentTime(); + return remainingMillisTv.tv_sec * 1000 + remainingMillisTv.tv_usec / 1000; } -uint32_t Countdown::getCurrentTime() const { - uint32_t currentTime; - Clock::getUptime(¤tTime); +uint32_t Countdown::timevalToMs(timeval &tv) { return tv.tv_sec * 1000 + tv.tv_usec / 1000; } + +ReturnValue_t Countdown::setTimeoutTv(timeval tv) { + timeout = tv; + return Clock::getClockMonotonic(&startTime); +} + +uint32_t Countdown::getTimeoutMs() const { return timeout.tv_sec * 1000 + timeout.tv_usec / 1000; } + +timeval Countdown::getTimeout() const { return timeout; } + +timeval Countdown::getCurrentTime() const { + timeval currentTime{}; + Clock::getClockMonotonic(¤tTime); return currentTime; } diff --git a/src/fsfw/timemanager/Countdown.h b/src/fsfw/timemanager/Countdown.h index 44be2b1ac..44a1d4ad3 100644 --- a/src/fsfw/timemanager/Countdown.h +++ b/src/fsfw/timemanager/Countdown.h @@ -6,6 +6,10 @@ /** * * Countdown keeps track of a timespan. + * This class uses the system clock internally to achieve + * a high resolution. This means that the API is only partially + * resistant against time jumps. The user must take care to account + * for time jumps in some from if this relevant. * * Countdown::resetTimer restarts the timer. * Countdown::setTimeout sets a new countdown duration and resets. @@ -26,8 +30,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. @@ -38,6 +43,8 @@ class Countdown { * @return Returnvalue from Clock::getUptime */ ReturnValue_t setTimeout(uint32_t milliseconds); + ReturnValue_t setTimeoutTv(timeval tv); + /** * Returns true if the countdown duration has passed. * @@ -60,22 +67,31 @@ class Countdown { * Returns the remaining milliseconds (0 if timeout) */ uint32_t getRemainingMillis() const; + + uint32_t getTimeoutMs() const; + + timeval getTimeout() const; + /** * Makes hasTimedOut() return true */ void timeOut(); - /** - * Internal countdown duration in milliseconds - */ - uint32_t timeout; + + static inline uint32_t timevalToMs(timeval& tv); private: /** - * Last time the timer was started (uptime) + * Start time of the countdown. */ - uint32_t startTime = 0; + timeval startTime{}; - uint32_t getCurrentTime() const; + /** + * Timeout as timeval type. The countdown has timed out when the + * current time exceeds the start time plus the timeout. + */ + timeval timeout{}; + + timeval getCurrentTime() const; }; #endif /* FSFW_TIMEMANAGER_COUNTDOWN_H_ */ diff --git a/src/fsfw/timemanager/Stopwatch.cpp b/src/fsfw/timemanager/Stopwatch.cpp index 05d5c0e8b..ad39f1b39 100644 --- a/src/fsfw/timemanager/Stopwatch.cpp +++ b/src/fsfw/timemanager/Stopwatch.cpp @@ -9,10 +9,10 @@ Stopwatch::Stopwatch(bool displayOnDestruction, StopwatchDisplayMode displayMode) : displayOnDestruction(displayOnDestruction), displayMode(displayMode) { // Measures start time on initialization. - Clock::getUptime(&startTime); + Clock::getClockMonotonic(&startTime); } -void Stopwatch::start() { Clock::getUptime(&startTime); } +void Stopwatch::start() { Clock::getClockMonotonic(&startTime); } dur_millis_t Stopwatch::stop(bool display) { stopInternal(); @@ -63,6 +63,6 @@ StopwatchDisplayMode Stopwatch::getDisplayMode() const { return displayMode; } void Stopwatch::stopInternal() { timeval endTime; - Clock::getUptime(&endTime); + Clock::getClockMonotonic(&endTime); elapsedTime = endTime - startTime; } diff --git a/src/fsfw/tmstorage/TmStoreBackendIF.h b/src/fsfw/tmstorage/TmStoreBackendIF.h index 84c94f772..cd0149c56 100644 --- a/src/fsfw/tmstorage/TmStoreBackendIF.h +++ b/src/fsfw/tmstorage/TmStoreBackendIF.h @@ -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() {} diff --git a/src/fsfw/tmstorage/TmStoreFrontendIF.h b/src/fsfw/tmstorage/TmStoreFrontendIF.h index 56bcd7fab..1e3dd5791 100644 --- a/src/fsfw/tmstorage/TmStoreFrontendIF.h +++ b/src/fsfw/tmstorage/TmStoreFrontendIF.h @@ -6,47 +6,12 @@ #include "fsfw/returnvalues/returnvalue.h" #include "tmStorageConf.h" -class TmPacketMinimal; -class SpacePacketBase; +class PusTmReader; +class SpacePacketReader; class TmStoreBackendIF; class TmStoreFrontendIF { public: - virtual TmStoreBackendIF* getBackend() const = 0; - - /** - * What do I need to implement here? - * This is propably used by PUS Service 15 so we should propably check for messages.. - * Provide base implementation? - * @param opCode - * @return - */ - virtual ReturnValue_t performOperation(uint8_t opCode) = 0; - /** - * Callback from the back-end to indicate a certain packet was received. - * front-end takes care of discarding/downloading the packet. - * @param packet Pointer to the newly received Space Packet. - * @param address Start address of the packet found - * @param isLastPacket Indicates if no more packets can be fetched. - * @return If more packets shall be fetched, returnvalue::OK must be returned. - * Any other code stops fetching packets. - */ - virtual ReturnValue_t packetRetrieved(TmPacketMinimal* packet, uint32_t address) = 0; - virtual void noMorePacketsInStore() = 0; - virtual void handleRetrievalFailed(ReturnValue_t errorCode, uint32_t parameter1 = 0, - uint32_t parameter2 = 0) = 0; - /** - * To get the queue where commands shall be sent. - * @return Id of command queue. - */ - virtual MessageQueueId_t getCommandQueue() const = 0; - virtual ReturnValue_t fetchPackets(ApidSsc start, ApidSsc end) = 0; - virtual ReturnValue_t deletePackets(ApidSsc upTo) = 0; - virtual ReturnValue_t checkPacket(SpacePacketBase* tmPacket) = 0; - virtual bool isEnabled() const = 0; - virtual void setEnabled(bool enabled) = 0; - virtual void resetDownlinkedPacketCount() = 0; - virtual ReturnValue_t setDumpTarget(object_id_t dumpTarget) = 0; static const uint8_t INTERFACE_ID = CLASS_ID::TM_STORE_FRONTEND_IF; static const ReturnValue_t BUSY = MAKE_RETURN_CODE(1); static const ReturnValue_t LAST_PACKET_FOUND = MAKE_RETURN_CODE(2); @@ -57,7 +22,38 @@ class TmStoreFrontendIF { static const ReturnValue_t ALL_DELETED = MAKE_RETURN_CODE(7); static const ReturnValue_t INVALID_DATA = MAKE_RETURN_CODE(8); static const ReturnValue_t NOT_READY = MAKE_RETURN_CODE(9); - virtual ~TmStoreFrontendIF() {} + + virtual ~TmStoreFrontendIF() = default; + + /** + * To get the queue where commands shall be sent. + * @return Id of command queue. + */ + virtual MessageQueueId_t getCommandQueue() const = 0; + + virtual TmStoreBackendIF* getBackend() const = 0; + + /** + * Callback from the back-end to indicate a certain packet was received. + * front-end takes care of discarding/downloading the packet. + * @param packet Pointer to the newly received Space Packet. + * @param address Start address of the packet found + * @param isLastPacket Indicates if no more packets can be fetched. + * @return If more packets shall be fetched, returnvalue::OK must be returned. + * Any other code stops fetching packets. + */ + virtual ReturnValue_t packetRetrieved(PusTmReader* packet, uint32_t address) = 0; + virtual void noMorePacketsInStore() = 0; + virtual void handleRetrievalFailed(ReturnValue_t errorCode, uint32_t parameter1 = 0, + uint32_t parameter2 = 0) = 0; + + virtual ReturnValue_t fetchPackets(ApidSsc start, ApidSsc end) = 0; + virtual ReturnValue_t deletePackets(ApidSsc upTo) = 0; + virtual ReturnValue_t checkPacket(SpacePacketReader* tmPacket) = 0; + virtual bool isEnabled() const = 0; + virtual void setEnabled(bool enabled) = 0; + virtual void resetDownlinkedPacketCount() = 0; + virtual ReturnValue_t setDumpTarget(object_id_t dumpTarget) = 0; }; #endif /* FSFW_TMTCSERVICES_TMSTOREFRONTENDIF_H_ */ diff --git a/src/fsfw/tmstorage/TmStoreFrontendSimpleIF.h b/src/fsfw/tmstorage/TmStoreFrontendSimpleIF.h new file mode 100644 index 000000000..5089f37de --- /dev/null +++ b/src/fsfw/tmstorage/TmStoreFrontendSimpleIF.h @@ -0,0 +1,15 @@ +#ifndef FSFW_SRC_FSFW_TMSTORAGE_TMSTOREBACKENDSIMPLEIF_H_ +#define FSFW_SRC_FSFW_TMSTORAGE_TMSTOREBACKENDSIMPLEIF_H_ + +#include + +class TmStoreFrontendSimpleIF { + public: + virtual ~TmStoreFrontendSimpleIF() = default; + + virtual MessageQueueId_t getCommandQueue() const = 0; + + private: +}; + +#endif /* FSFW_SRC_FSFW_TMSTORAGE_TMSTOREBACKENDSIMPLEIF_H_ */ diff --git a/src/fsfw/tmstorage/TmStorePackets.h b/src/fsfw/tmstorage/TmStorePackets.h index e519b3b77..22ed3c216 100644 --- a/src/fsfw/tmstorage/TmStorePackets.h +++ b/src/fsfw/tmstorage/TmStorePackets.h @@ -1,6 +1,10 @@ #ifndef FSFW_TMSTORAGE_TMSTOREPACKETS_H_ #define FSFW_TMSTORAGE_TMSTOREPACKETS_H_ +#include + +#include + #include "fsfw/globalfunctions/timevalOperations.h" #include "fsfw/serialize/SerialBufferAdapter.h" #include "fsfw/serialize/SerialFixedArrayListAdapter.h" @@ -24,7 +28,7 @@ class ServiceSubservice : public SerialLinkedListAdapter { class ApidSsc : public SerializeIF { public: - ApidSsc() : apid(SpacePacketBase::LIMIT_APID), ssc(0) {} + ApidSsc() : apid(ccsds::LIMIT_APID), ssc(0) {} ApidSsc(uint16_t apid, uint16_t ssc) : apid(apid), ssc(ssc) {} uint16_t apid; uint16_t ssc; @@ -62,51 +66,59 @@ class ChangeSelectionDefinition : public SerialLinkedListAdapter { class TmPacketInformation : public SerializeIF { public: - TmPacketInformation(TmPacketMinimal* packet) { setContent(packet); } - TmPacketInformation() - : apid(SpacePacketBase::LIMIT_APID), + TmPacketInformation(PusTmReader* packet, size_t timestampLen) : rawTimestamp(timestampLen) { + setContent(packet); + } + TmPacketInformation(size_t timestampLen) + : apid(ccsds::LIMIT_APID), sourceSequenceCount(0), serviceType(0), serviceSubtype(0), - subCounter(0) {} + subCounter(0), + rawTimestamp(timestampLen) {} void reset() { - apid = SpacePacketBase::LIMIT_APID; + apid = ccsds::LIMIT_APID; sourceSequenceCount = 0; serviceType = 0; serviceSubtype = 0; subCounter = 0; - memset(rawTimestamp, 0, sizeof(rawTimestamp)); + memset(rawTimestamp.data(), 0, rawTimestamp.size()); } - void setContent(TmPacketMinimal* packet) { - apid = packet->getAPID(); - sourceSequenceCount = packet->getPacketSequenceCount(); + void setContent(PusTmReader* packet) { + apid = packet->getApid(); + sourceSequenceCount = packet->getSequenceCount(); serviceType = packet->getService(); serviceSubtype = packet->getSubService(); - subCounter = packet->getPacketSubcounter(); - memset(rawTimestamp, 0, sizeof(rawTimestamp)); - const uint8_t* pField = NULL; - uint32_t size = 0; - ReturnValue_t result = packet->getPacketTimeRaw(&pField, &size); - if (result != returnvalue::OK) { - return; - } - if (*pField == CCSDSTime::P_FIELD_CDS_SHORT && size <= TimeStamperIF::MISSION_TIMESTAMP_SIZE) { - // Shortcut to avoid converting CDS back and forth. - memcpy(rawTimestamp, pField, size); - return; - } - timeval time = {0, 0}; - result = packet->getPacketTime(&time); - if (result != returnvalue::OK) { - return; - } - - CCSDSTime::CDS_short cdsFormat; - result = CCSDSTime::convertToCcsds(&cdsFormat, &time); - if (result != returnvalue::OK) { - return; - } - memcpy(rawTimestamp, &cdsFormat, sizeof(cdsFormat)); + subCounter = packet->getMessageTypeCounter(); + memset(rawTimestamp.data(), 0, rawTimestamp.size()); + // TODO: Fix all of this + // const uint8_t* pField = NULL; + // uint32_t size = 0; + // auto* timeReader = packet->getTimeReader(); + // ReturnValue_t result = packet->getPacketTimeRaw(&pField, &size); + // if (result != returnvalue::OK) { + // return; + //} + // if (*pField == CCSDSTime::P_FIELD_CDS_SHORT && size <= TimeStamperIF::MISSION_TIMESTAMP_SIZE) + // { + // Shortcut to avoid converting CDS back and forth. + // TODO: Fix + // memcpy(rawTimestamp, pField, size); + // return; + // } + // timeval time = {0, 0}; + // result = packet->getPacketTime(&time); + // if (result != returnvalue::OK) { + // return; + // } + // + // CCSDSTime::CDS_short cdsFormat; + // result = CCSDSTime::convertToCcsds(&cdsFormat, &time); + // if (result != returnvalue::OK) { + // return; + // } + // TODO: Fix + // memcpy(rawTimestamp, &cdsFormat, sizeof(cdsFormat)); } void setContent(TmPacketInformation* content) { apid = content->apid; @@ -114,9 +126,10 @@ class TmPacketInformation : public SerializeIF { serviceType = content->serviceType; serviceSubtype = content->serviceSubtype; subCounter = content->subCounter; - memcpy(rawTimestamp, content->rawTimestamp, sizeof(rawTimestamp)); + // TODO: Fix + // memcpy(rawTimestamp, content->rawTimestamp, sizeof(rawTimestamp)); } - bool isValid() const { return (apid < SpacePacketBase::LIMIT_APID) ? true : false; } + bool isValid() const { return (apid < ccsds::LIMIT_APID) ? true : false; } static void reset(TmPacketInformation* packet) { packet->reset(); } static bool isOlderThan(const TmPacketInformation* packet, const timeval* cmpTime) { @@ -216,7 +229,7 @@ class TmPacketInformation : public SerializeIF { if (result != returnvalue::OK) { return result; } - SerialBufferAdapter adapter(rawTimestamp, sizeof(rawTimestamp)); + SerialBufferAdapter adapter(rawTimestamp.data(), rawTimestamp.size()); return adapter.serialize(buffer, size, maxSize, streamEndianness); } @@ -227,7 +240,7 @@ class TmPacketInformation : public SerializeIF { size += SerializeAdapter::getSerializedSize(&serviceType); size += SerializeAdapter::getSerializedSize(&serviceSubtype); size += SerializeAdapter::getSerializedSize(&subCounter); - SerialBufferAdapter adapter(rawTimestamp, sizeof(rawTimestamp)); + SerialBufferAdapter adapter(rawTimestamp.data(), rawTimestamp.size()); size += adapter.getSerializedSize(); return size; }; @@ -253,7 +266,7 @@ class TmPacketInformation : public SerializeIF { if (result != returnvalue::OK) { return result; } - SerialBufferAdapter adapter(rawTimestamp, sizeof(rawTimestamp)); + SerialBufferAdapter adapter(rawTimestamp.data(), rawTimestamp.size()); return adapter.deSerialize(buffer, size, streamEndianness); } @@ -263,6 +276,6 @@ class TmPacketInformation : public SerializeIF { uint8_t serviceType; uint8_t serviceSubtype; uint8_t subCounter; - uint8_t rawTimestamp[TimeStamperIF::MISSION_TIMESTAMP_SIZE]; + std::vector rawTimestamp; }; #endif /* FSFW_TMSTORAGE_TMSTOREPACKETS_H_ */ diff --git a/src/fsfw/tmtcpacket/pus/tm/PusTmCreator.h b/src/fsfw/tmtcpacket/pus/tm/PusTmCreator.h index 626d873e0..19922b2fe 100644 --- a/src/fsfw/tmtcpacket/pus/tm/PusTmCreator.h +++ b/src/fsfw/tmtcpacket/pus/tm/PusTmCreator.h @@ -40,7 +40,7 @@ struct PusTmParams { size_t dataLen) : secHeader(service, subservice, timeStamper), adapter(data, dataLen), sourceData(&adapter) {} PusTmSecHeader secHeader; - SerialBufferAdapter adapter; + SerialBufferAdapter adapter; const SerializeIF* sourceData = nullptr; }; diff --git a/src/fsfw/tmtcpacket/pus/tm/PusTmZcWriter.cpp b/src/fsfw/tmtcpacket/pus/tm/PusTmZcWriter.cpp index 6a9f62350..d897aff9b 100644 --- a/src/fsfw/tmtcpacket/pus/tm/PusTmZcWriter.cpp +++ b/src/fsfw/tmtcpacket/pus/tm/PusTmZcWriter.cpp @@ -24,3 +24,9 @@ void PusTmZeroCopyWriter::updateErrorControl() { crcStart[0] = (crc16 >> 8) & 0xff; crcStart[1] = crc16 & 0xff; } + +void PusTmZeroCopyWriter::setMessageCount(uint16_t msgCount) { + size_t serSize = 0; + SerializeAdapter::serialize(&msgCount, const_cast(pointers.secHeaderStart + 3), + &serSize, 2, SerializeIF::Endianness::NETWORK); +} diff --git a/src/fsfw/tmtcpacket/pus/tm/PusTmZcWriter.h b/src/fsfw/tmtcpacket/pus/tm/PusTmZcWriter.h index 36c43f517..66ef14056 100644 --- a/src/fsfw/tmtcpacket/pus/tm/PusTmZcWriter.h +++ b/src/fsfw/tmtcpacket/pus/tm/PusTmZcWriter.h @@ -14,6 +14,7 @@ class PusTmZeroCopyWriter : public PusTmReader { PusTmZeroCopyWriter(TimeReaderIF& timeReader, uint8_t* data, size_t size); void setSequenceCount(uint16_t seqCount); + void setMessageCount(uint16_t msgCount); void updateErrorControl(); private: diff --git a/src/fsfw/tmtcservices/CommandingServiceBase.cpp b/src/fsfw/tmtcservices/CommandingServiceBase.cpp index 1ec5c0d81..0cdcc6536 100644 --- a/src/fsfw/tmtcservices/CommandingServiceBase.cpp +++ b/src/fsfw/tmtcservices/CommandingServiceBase.cpp @@ -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(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); diff --git a/src/fsfw/tmtcservices/PusServiceBase.cpp b/src/fsfw/tmtcservices/PusServiceBase.cpp index 9598e536e..fbabbd708 100644 --- a/src/fsfw/tmtcservices/PusServiceBase.cpp +++ b/src/fsfw/tmtcservices/PusServiceBase.cpp @@ -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(result) << std::endl; + sif::error << "PusService " << static_cast(psbParams.serviceId) + << ": performService returned with " << static_cast(result) << std::endl; #endif return returnvalue::FAILED; } diff --git a/src/fsfw/tmtcservices/TmTcBridge.cpp b/src/fsfw/tmtcservices/TmTcBridge.cpp index ba851a856..f098103ee 100644 --- a/src/fsfw/tmtcservices/TmTcBridge.cpp +++ b/src/fsfw/tmtcservices/TmTcBridge.cpp @@ -8,7 +8,7 @@ #define TMTCBRIDGE_WIRETAPPING 0 TmTcBridge::TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDestination, - object_id_t tmStoreId, object_id_t tcStoreId) + uint32_t msgQueueDepth, object_id_t tmStoreId, object_id_t tcStoreId) : SystemObject(objectId), name(name), tmStoreId(tmStoreId), @@ -18,7 +18,7 @@ TmTcBridge::TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDes { auto mqArgs = MqArgs(objectId, static_cast(this)); tmTcReceptionQueue = QueueFactory::instance()->createMessageQueue( - TMTC_RECEPTION_QUEUE_DEPTH, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs); + msgQueueDepth, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs); } TmTcBridge::~TmTcBridge() { QueueFactory::instance()->deleteMessageQueue(tmTcReceptionQueue); } diff --git a/src/fsfw/tmtcservices/TmTcBridge.h b/src/fsfw/tmtcservices/TmTcBridge.h index 3df3419cb..858793cc1 100644 --- a/src/fsfw/tmtcservices/TmTcBridge.h +++ b/src/fsfw/tmtcservices/TmTcBridge.h @@ -15,7 +15,6 @@ class TmTcBridge : public AcceptsTelemetryIF, public ExecutableObjectIF, public SystemObject { public: - static constexpr uint8_t TMTC_RECEPTION_QUEUE_DEPTH = 20; static constexpr uint8_t LIMIT_STORED_DATA_SENT_PER_CYCLE = 15; static constexpr unsigned int LIMIT_DOWNLINK_PACKETS_STORED = 500; @@ -23,7 +22,7 @@ class TmTcBridge : public AcceptsTelemetryIF, static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10; TmTcBridge(const char* name, object_id_t objectId, object_id_t tcDestination, - object_id_t tmStoreId, object_id_t tcStoreId); + uint32_t msgQueueDepth, object_id_t tmStoreId, object_id_t tcStoreId); ~TmTcBridge() override; /** diff --git a/src/fsfw_hal/common/gpio/GpioIF.h b/src/fsfw_hal/common/gpio/GpioIF.h index a8abb126f..20ae8a261 100644 --- a/src/fsfw_hal/common/gpio/GpioIF.h +++ b/src/fsfw_hal/common/gpio/GpioIF.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_ */ diff --git a/src/fsfw_hal/common/gpio/gpioDefinitions.h b/src/fsfw_hal/common/gpio/gpioDefinitions.h index 9f8b5e32c..1f921a577 100644 --- a/src/fsfw_hal/common/gpio/gpioDefinitions.h +++ b/src/fsfw_hal/common/gpio/gpioDefinitions.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 }; diff --git a/src/fsfw_hal/common/spi/spiCommon.h b/src/fsfw_hal/common/spi/spiCommon.h index bee86823a..072363a59 100644 --- a/src/fsfw_hal/common/spi/spiCommon.h +++ b/src/fsfw_hal/common/spi/spiCommon.h @@ -5,8 +5,18 @@ namespace spi { +static constexpr uint8_t CLASS_ID = CLASS_ID::HAL_SPI; +static constexpr ReturnValue_t OPENING_FILE_FAILED = returnvalue::makeCode(CLASS_ID, 0); +/* Full duplex (ioctl) transfer failure */ +static constexpr ReturnValue_t FULL_DUPLEX_TRANSFER_FAILED = returnvalue::makeCode(CLASS_ID, 1); +/* Half duplex (read/write) transfer failure */ +static constexpr ReturnValue_t HALF_DUPLEX_TRANSFER_FAILED = returnvalue::makeCode(CLASS_ID, 2); +static constexpr ReturnValue_t TIMEOUT = returnvalue::makeCode(CLASS_ID, 3); +static constexpr ReturnValue_t BUSY = returnvalue::makeCode(CLASS_ID, 4); +static constexpr ReturnValue_t GENERIC_ERROR = returnvalue::makeCode(CLASS_ID, 5); + enum SpiModes : uint8_t { MODE_0, MODE_1, MODE_2, MODE_3 }; -} +} // namespace spi #endif /* FSFW_HAL_COMMON_SPI_SPICOMMON_H_ */ diff --git a/src/fsfw_hal/devicehandlers/CMakeLists.txt b/src/fsfw_hal/devicehandlers/CMakeLists.txt index 17139416c..e5999ad53 100644 --- a/src/fsfw_hal/devicehandlers/CMakeLists.txt +++ b/src/fsfw_hal/devicehandlers/CMakeLists.txt @@ -1,3 +1,5 @@ target_sources( ${LIB_FSFW_NAME} PRIVATE GyroL3GD20Handler.cpp MgmRM3100Handler.cpp MgmLIS3MDLHandler.cpp) + +add_subdirectory(devicedefinitions) diff --git a/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp b/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp index 1ffc60f10..c71f34ce8 100644 --- a/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp +++ b/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.cpp @@ -46,17 +46,17 @@ ReturnValue_t GyroHandlerL3GD20H::buildTransitionDeviceCommand(DeviceCommandId_t return NOTHING_TO_SEND; } case (InternalState::CONFIGURE): { - *id = L3GD20H::CONFIGURE_CTRL_REGS; + *id = l3gd20h::CONFIGURE_CTRL_REGS; uint8_t command[5]; - command[0] = L3GD20H::CTRL_REG_1_VAL; - command[1] = L3GD20H::CTRL_REG_2_VAL; - command[2] = L3GD20H::CTRL_REG_3_VAL; - command[3] = L3GD20H::CTRL_REG_4_VAL; - command[4] = L3GD20H::CTRL_REG_5_VAL; + command[0] = l3gd20h::CTRL_REG_1_VAL; + command[1] = l3gd20h::CTRL_REG_2_VAL; + command[2] = l3gd20h::CTRL_REG_3_VAL; + command[3] = l3gd20h::CTRL_REG_4_VAL; + command[4] = l3gd20h::CTRL_REG_5_VAL; return buildCommandFromCommand(*id, command, 5); } case (InternalState::CHECK_REGS): { - *id = L3GD20H::READ_REGS; + *id = l3gd20h::READ_REGS; return buildCommandFromCommand(*id, nullptr, 0); } default: @@ -76,7 +76,7 @@ ReturnValue_t GyroHandlerL3GD20H::buildTransitionDeviceCommand(DeviceCommandId_t } ReturnValue_t GyroHandlerL3GD20H::buildNormalDeviceCommand(DeviceCommandId_t *id) { - *id = L3GD20H::READ_REGS; + *id = l3gd20h::READ_REGS; return buildCommandFromCommand(*id, nullptr, 0); } @@ -84,15 +84,15 @@ ReturnValue_t GyroHandlerL3GD20H::buildCommandFromCommand(DeviceCommandId_t devi const uint8_t *commandData, size_t commandDataLen) { switch (deviceCommand) { - case (L3GD20H::READ_REGS): { - commandBuffer[0] = L3GD20H::READ_START | L3GD20H::AUTO_INCREMENT_MASK | L3GD20H::READ_MASK; - std::memset(commandBuffer + 1, 0, L3GD20H::READ_LEN); + case (l3gd20h::READ_REGS): { + commandBuffer[0] = l3gd20h::READ_START | l3gd20h::AUTO_INCREMENT_MASK | l3gd20h::READ_MASK; + std::memset(commandBuffer + 1, 0, l3gd20h::READ_LEN); rawPacket = commandBuffer; - rawPacketLen = L3GD20H::READ_LEN + 1; + rawPacketLen = l3gd20h::READ_LEN + 1; break; } - case (L3GD20H::CONFIGURE_CTRL_REGS): { - commandBuffer[0] = L3GD20H::CTRL_REG_1 | L3GD20H::AUTO_INCREMENT_MASK; + case (l3gd20h::CONFIGURE_CTRL_REGS): { + commandBuffer[0] = l3gd20h::CTRL_REG_1 | l3gd20h::AUTO_INCREMENT_MASK; if (commandData == nullptr or commandDataLen != 5) { return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; } @@ -103,15 +103,15 @@ ReturnValue_t GyroHandlerL3GD20H::buildCommandFromCommand(DeviceCommandId_t devi ctrlReg4Value = commandData[3]; ctrlReg5Value = commandData[4]; - bool fsH = ctrlReg4Value & L3GD20H::SET_FS_1; - bool fsL = ctrlReg4Value & L3GD20H::SET_FS_0; + bool fsH = ctrlReg4Value & l3gd20h::SET_FS_1; + bool fsL = ctrlReg4Value & l3gd20h::SET_FS_0; if (not fsH and not fsL) { - sensitivity = L3GD20H::SENSITIVITY_00; + sensitivity = l3gd20h::SENSITIVITY_00; } else if (not fsH and fsL) { - sensitivity = L3GD20H::SENSITIVITY_01; + sensitivity = l3gd20h::SENSITIVITY_01; } else { - sensitivity = L3GD20H::SENSITIVITY_11; + sensitivity = l3gd20h::SENSITIVITY_11; } commandBuffer[1] = ctrlReg1Value; @@ -124,8 +124,8 @@ ReturnValue_t GyroHandlerL3GD20H::buildCommandFromCommand(DeviceCommandId_t devi rawPacketLen = 6; break; } - case (L3GD20H::READ_CTRL_REGS): { - commandBuffer[0] = L3GD20H::READ_START | L3GD20H::AUTO_INCREMENT_MASK | L3GD20H::READ_MASK; + case (l3gd20h::READ_CTRL_REGS): { + commandBuffer[0] = l3gd20h::READ_START | l3gd20h::AUTO_INCREMENT_MASK | l3gd20h::READ_MASK; std::memset(commandBuffer + 1, 0, 5); rawPacket = commandBuffer; @@ -151,11 +151,11 @@ ReturnValue_t GyroHandlerL3GD20H::interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) { ReturnValue_t result = returnvalue::OK; switch (id) { - case (L3GD20H::CONFIGURE_CTRL_REGS): { + case (l3gd20h::CONFIGURE_CTRL_REGS): { commandExecuted = true; break; } - case (L3GD20H::READ_CTRL_REGS): { + case (l3gd20h::READ_CTRL_REGS): { if (packet[1] == ctrlReg1Value and packet[2] == ctrlReg2Value and packet[3] == ctrlReg3Value and packet[4] == ctrlReg4Value and packet[5] == ctrlReg5Value) { @@ -167,7 +167,7 @@ ReturnValue_t GyroHandlerL3GD20H::interpretDeviceReply(DeviceCommandId_t id, } break; } - case (L3GD20H::READ_REGS): { + case (l3gd20h::READ_REGS): { if (packet[1] != ctrlReg1Value and packet[2] != ctrlReg2Value and packet[3] != ctrlReg3Value and packet[4] != ctrlReg4Value and packet[5] != ctrlReg5Value) { @@ -178,16 +178,16 @@ ReturnValue_t GyroHandlerL3GD20H::interpretDeviceReply(DeviceCommandId_t id, } } - statusReg = packet[L3GD20H::STATUS_IDX]; + statusReg = packet[l3gd20h::STATUS_IDX]; - int16_t angVelocXRaw = packet[L3GD20H::OUT_X_H] << 8 | packet[L3GD20H::OUT_X_L]; - int16_t angVelocYRaw = packet[L3GD20H::OUT_Y_H] << 8 | packet[L3GD20H::OUT_Y_L]; - int16_t angVelocZRaw = packet[L3GD20H::OUT_Z_H] << 8 | packet[L3GD20H::OUT_Z_L]; + int16_t angVelocXRaw = packet[l3gd20h::OUT_X_H] << 8 | packet[l3gd20h::OUT_X_L]; + int16_t angVelocYRaw = packet[l3gd20h::OUT_Y_H] << 8 | packet[l3gd20h::OUT_Y_L]; + int16_t angVelocZRaw = packet[l3gd20h::OUT_Z_H] << 8 | packet[l3gd20h::OUT_Z_L]; float angVelocX = angVelocXRaw * sensitivity; float angVelocY = angVelocYRaw * sensitivity; float angVelocZ = angVelocZRaw * sensitivity; - int8_t temperaturOffset = (-1) * packet[L3GD20H::TEMPERATURE_IDX]; + int8_t temperaturOffset = (-1) * packet[l3gd20h::TEMPERATURE_IDX]; float temperature = 25.0 + temperaturOffset; if (periodicPrintout) { if (debugDivider.checkAndIncrement()) { @@ -248,17 +248,19 @@ void GyroHandlerL3GD20H::setToGoToNormalMode(bool enable) { this->goNormalModeIm ReturnValue_t GyroHandlerL3GD20H::initializeLocalDataPool(localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { - localDataPoolMap.emplace(L3GD20H::ANG_VELOC_X, new PoolEntry({0.0})); - localDataPoolMap.emplace(L3GD20H::ANG_VELOC_Y, new PoolEntry({0.0})); - localDataPoolMap.emplace(L3GD20H::ANG_VELOC_Z, new PoolEntry({0.0})); - localDataPoolMap.emplace(L3GD20H::TEMPERATURE, new PoolEntry({0.0})); + localDataPoolMap.emplace(l3gd20h::ANG_VELOC_X, new PoolEntry({0.0})); + localDataPoolMap.emplace(l3gd20h::ANG_VELOC_Y, new PoolEntry({0.0})); + localDataPoolMap.emplace(l3gd20h::ANG_VELOC_Z, new PoolEntry({0.0})); + localDataPoolMap.emplace(l3gd20h::TEMPERATURE, new PoolEntry({0.0})); + poolManager.subscribeForRegularPeriodicPacket( + subdp::RegularHkPeriodicParams(dataset.getSid(), false, 10.0)); return returnvalue::OK; } void GyroHandlerL3GD20H::fillCommandAndReplyMap() { - insertInCommandAndReplyMap(L3GD20H::READ_REGS, 1, &dataset); - insertInCommandAndReplyMap(L3GD20H::CONFIGURE_CTRL_REGS, 1); - insertInCommandAndReplyMap(L3GD20H::READ_CTRL_REGS, 1); + insertInCommandAndReplyMap(l3gd20h::READ_REGS, 1, &dataset); + insertInCommandAndReplyMap(l3gd20h::CONFIGURE_CTRL_REGS, 1); + insertInCommandAndReplyMap(l3gd20h::READ_CTRL_REGS, 1); } void GyroHandlerL3GD20H::modeChanged() { internalState = InternalState::NONE; } diff --git a/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h b/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h index 7c1ebdac1..9897dc002 100644 --- a/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h +++ b/src/fsfw_hal/devicehandlers/GyroL3GD20Handler.h @@ -3,8 +3,7 @@ #include #include - -#include "devicedefinitions/GyroL3GD20Definitions.h" +#include /** * @brief Device Handler for the L3GD20H gyroscope sensor @@ -59,9 +58,9 @@ class GyroHandlerL3GD20H : public DeviceHandlerBase { uint32_t transitionDelayMs = 0; GyroPrimaryDataset dataset; - float absLimitX = L3GD20H::RANGE_DPS_00; - float absLimitY = L3GD20H::RANGE_DPS_00; - float absLimitZ = L3GD20H::RANGE_DPS_00; + float absLimitX = l3gd20h::RANGE_DPS_00; + float absLimitY = l3gd20h::RANGE_DPS_00; + float absLimitZ = l3gd20h::RANGE_DPS_00; enum class InternalState { NONE, CONFIGURE, CHECK_REGS, NORMAL }; InternalState internalState = InternalState::NONE; @@ -70,16 +69,16 @@ class GyroHandlerL3GD20H : public DeviceHandlerBase { uint8_t statusReg = 0; bool goNormalModeImmediately = false; - uint8_t ctrlReg1Value = L3GD20H::CTRL_REG_1_VAL; - uint8_t ctrlReg2Value = L3GD20H::CTRL_REG_2_VAL; - uint8_t ctrlReg3Value = L3GD20H::CTRL_REG_3_VAL; - uint8_t ctrlReg4Value = L3GD20H::CTRL_REG_4_VAL; - uint8_t ctrlReg5Value = L3GD20H::CTRL_REG_5_VAL; + uint8_t ctrlReg1Value = l3gd20h::CTRL_REG_1_VAL; + uint8_t ctrlReg2Value = l3gd20h::CTRL_REG_2_VAL; + uint8_t ctrlReg3Value = l3gd20h::CTRL_REG_3_VAL; + uint8_t ctrlReg4Value = l3gd20h::CTRL_REG_4_VAL; + uint8_t ctrlReg5Value = l3gd20h::CTRL_REG_5_VAL; - uint8_t commandBuffer[L3GD20H::READ_LEN + 1]; + uint8_t commandBuffer[l3gd20h::READ_LEN + 1]; // Set default value - float sensitivity = L3GD20H::SENSITIVITY_00; + float sensitivity = l3gd20h::SENSITIVITY_00; bool periodicPrintout = false; PeriodicOperationDivider debugDivider = PeriodicOperationDivider(3); diff --git a/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp b/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp index 9cb16c355..a66745e1b 100644 --- a/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp +++ b/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.cpp @@ -10,11 +10,11 @@ MgmLIS3MDLHandler::MgmLIS3MDLHandler(object_id_t objectId, object_id_t deviceCom dataset(this), transitionDelay(transitionDelay) { // Set to default values right away - registers[0] = MGMLIS3MDL::CTRL_REG1_DEFAULT; - registers[1] = MGMLIS3MDL::CTRL_REG2_DEFAULT; - registers[2] = MGMLIS3MDL::CTRL_REG3_DEFAULT; - registers[3] = MGMLIS3MDL::CTRL_REG4_DEFAULT; - registers[4] = MGMLIS3MDL::CTRL_REG5_DEFAULT; + registers[0] = mgmLis3::CTRL_REG1_DEFAULT; + registers[1] = mgmLis3::CTRL_REG2_DEFAULT; + registers[2] = mgmLis3::CTRL_REG3_DEFAULT; + registers[3] = mgmLis3::CTRL_REG4_DEFAULT; + registers[4] = mgmLis3::CTRL_REG5_DEFAULT; } MgmLIS3MDLHandler::~MgmLIS3MDLHandler() {} @@ -63,15 +63,15 @@ ReturnValue_t MgmLIS3MDLHandler::buildTransitionDeviceCommand(DeviceCommandId_t return DeviceHandlerBase::NOTHING_TO_SEND; } case (InternalState::STATE_FIRST_CONTACT): { - *id = MGMLIS3MDL::IDENTIFY_DEVICE; + *id = mgmLis3::IDENTIFY_DEVICE; break; } case (InternalState::STATE_SETUP): { - *id = MGMLIS3MDL::SETUP_MGM; + *id = mgmLis3::SETUP_MGM; break; } case (InternalState::STATE_CHECK_REGISTERS): { - *id = MGMLIS3MDL::READ_CONFIG_AND_DATA; + *id = mgmLis3::READ_CONFIG_AND_DATA; break; } default: { @@ -88,28 +88,12 @@ ReturnValue_t MgmLIS3MDLHandler::buildTransitionDeviceCommand(DeviceCommandId_t return buildCommandFromCommand(*id, NULL, 0); } -uint8_t MgmLIS3MDLHandler::readCommand(uint8_t command, bool continuousCom) { - command |= (1 << MGMLIS3MDL::RW_BIT); - if (continuousCom == true) { - command |= (1 << MGMLIS3MDL::MS_BIT); - } - return command; -} - -uint8_t MgmLIS3MDLHandler::writeCommand(uint8_t command, bool continuousCom) { - command &= ~(1 << MGMLIS3MDL::RW_BIT); - if (continuousCom == true) { - command |= (1 << MGMLIS3MDL::MS_BIT); - } - return command; -} - void MgmLIS3MDLHandler::setupMgm() { - registers[0] = MGMLIS3MDL::CTRL_REG1_DEFAULT; - registers[1] = MGMLIS3MDL::CTRL_REG2_DEFAULT; - registers[2] = MGMLIS3MDL::CTRL_REG3_DEFAULT; - registers[3] = MGMLIS3MDL::CTRL_REG4_DEFAULT; - registers[4] = MGMLIS3MDL::CTRL_REG5_DEFAULT; + registers[0] = mgmLis3::CTRL_REG1_DEFAULT; + registers[1] = mgmLis3::CTRL_REG2_DEFAULT; + registers[2] = mgmLis3::CTRL_REG3_DEFAULT; + registers[3] = mgmLis3::CTRL_REG4_DEFAULT; + registers[4] = mgmLis3::CTRL_REG5_DEFAULT; prepareCtrlRegisterWrite(); } @@ -117,11 +101,11 @@ void MgmLIS3MDLHandler::setupMgm() { ReturnValue_t MgmLIS3MDLHandler::buildNormalDeviceCommand(DeviceCommandId_t *id) { // Data/config register will be read in an alternating manner. if (communicationStep == CommunicationStep::DATA) { - *id = MGMLIS3MDL::READ_CONFIG_AND_DATA; + *id = mgmLis3::READ_CONFIG_AND_DATA; communicationStep = CommunicationStep::TEMPERATURE; return buildCommandFromCommand(*id, NULL, 0); } else { - *id = MGMLIS3MDL::READ_TEMPERATURE; + *id = mgmLis3::READ_TEMPERATURE; communicationStep = CommunicationStep::DATA; return buildCommandFromCommand(*id, NULL, 0); } @@ -131,33 +115,33 @@ ReturnValue_t MgmLIS3MDLHandler::buildCommandFromCommand(DeviceCommandId_t devic const uint8_t *commandData, size_t commandDataLen) { switch (deviceCommand) { - case (MGMLIS3MDL::READ_CONFIG_AND_DATA): { + case (mgmLis3::READ_CONFIG_AND_DATA): { std::memset(commandBuffer, 0, sizeof(commandBuffer)); - commandBuffer[0] = readCommand(MGMLIS3MDL::CTRL_REG1, true); + commandBuffer[0] = mgmLis3::readCommand(mgmLis3::CTRL_REG1, true); rawPacket = commandBuffer; - rawPacketLen = MGMLIS3MDL::NR_OF_DATA_AND_CFG_REGISTERS + 1; + rawPacketLen = mgmLis3::NR_OF_DATA_AND_CFG_REGISTERS + 1; return returnvalue::OK; } - case (MGMLIS3MDL::READ_TEMPERATURE): { + case (mgmLis3::READ_TEMPERATURE): { std::memset(commandBuffer, 0, 3); - commandBuffer[0] = readCommand(MGMLIS3MDL::TEMP_LOWBYTE, true); + commandBuffer[0] = mgmLis3::readCommand(mgmLis3::TEMP_LOWBYTE, true); rawPacket = commandBuffer; rawPacketLen = 3; return returnvalue::OK; } - case (MGMLIS3MDL::IDENTIFY_DEVICE): { + case (mgmLis3::IDENTIFY_DEVICE): { return identifyDevice(); } - case (MGMLIS3MDL::TEMP_SENSOR_ENABLE): { + case (mgmLis3::TEMP_SENSOR_ENABLE): { return enableTemperatureSensor(commandData, commandDataLen); } - case (MGMLIS3MDL::SETUP_MGM): { + case (mgmLis3::SETUP_MGM): { setupMgm(); return returnvalue::OK; } - case (MGMLIS3MDL::ACCURACY_OP_MODE_SET): { + case (mgmLis3::ACCURACY_OP_MODE_SET): { return setOperatingMode(commandData, commandDataLen); } default: @@ -168,7 +152,7 @@ ReturnValue_t MgmLIS3MDLHandler::buildCommandFromCommand(DeviceCommandId_t devic ReturnValue_t MgmLIS3MDLHandler::identifyDevice() { uint32_t size = 2; - commandBuffer[0] = readCommand(MGMLIS3MDL::IDENTIFY_DEVICE_REG_ADDR); + commandBuffer[0] = mgmLis3::readCommand(mgmLis3::IDENTIFY_DEVICE_REG_ADDR); commandBuffer[1] = 0x00; rawPacket = commandBuffer; @@ -180,9 +164,9 @@ ReturnValue_t MgmLIS3MDLHandler::identifyDevice() { ReturnValue_t MgmLIS3MDLHandler::scanForReply(const uint8_t *start, size_t len, DeviceCommandId_t *foundId, size_t *foundLen) { *foundLen = len; - if (len == MGMLIS3MDL::NR_OF_DATA_AND_CFG_REGISTERS + 1) { + if (len == mgmLis3::NR_OF_DATA_AND_CFG_REGISTERS + 1) { *foundLen = len; - *foundId = MGMLIS3MDL::READ_CONFIG_AND_DATA; + *foundId = mgmLis3::READ_CONFIG_AND_DATA; // Check validity by checking config registers if (start[1] != registers[0] or start[2] != registers[1] or start[3] != registers[2] or start[4] != registers[3] or start[5] != registers[4]) { @@ -195,21 +179,21 @@ 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; } - } else if (len == MGMLIS3MDL::TEMPERATURE_REPLY_LEN) { + } else if (len == mgmLis3::TEMPERATURE_REPLY_LEN) { *foundLen = len; - *foundId = MGMLIS3MDL::READ_TEMPERATURE; - } else if (len == MGMLIS3MDL::SETUP_REPLY_LEN) { + *foundId = mgmLis3::READ_TEMPERATURE; + } else if (len == mgmLis3::SETUP_REPLY_LEN) { *foundLen = len; - *foundId = MGMLIS3MDL::SETUP_MGM; + *foundId = mgmLis3::SETUP_MGM; } else if (len == SINGLE_COMMAND_ANSWER_LEN) { *foundLen = len; *foundId = getPendingCommand(); - if (*foundId == MGMLIS3MDL::IDENTIFY_DEVICE) { - if (start[1] != MGMLIS3MDL::DEVICE_ID) { + if (*foundId == mgmLis3::IDENTIFY_DEVICE) { + if (start[1] != mgmLis3::DEVICE_ID) { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "MGMHandlerLIS3MDL::scanForReply: " @@ -224,7 +208,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; } } @@ -241,30 +225,31 @@ ReturnValue_t MgmLIS3MDLHandler::scanForReply(const uint8_t *start, size_t len, } ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) { switch (id) { - case MGMLIS3MDL::IDENTIFY_DEVICE: { + case mgmLis3::IDENTIFY_DEVICE: { break; } - case MGMLIS3MDL::SETUP_MGM: { + case mgmLis3::SETUP_MGM: { break; } - case MGMLIS3MDL::READ_CONFIG_AND_DATA: { + case mgmLis3::READ_CONFIG_AND_DATA: { + using namespace mgmLis3; // TODO: Store configuration in new local datasets. float sensitivityFactor = getSensitivityFactor(getSensitivity(registers[2])); int16_t mgmMeasurementRawX = - packet[MGMLIS3MDL::X_HIGHBYTE_IDX] << 8 | packet[MGMLIS3MDL::X_LOWBYTE_IDX]; + packet[mgmLis3::X_HIGHBYTE_IDX] << 8 | packet[mgmLis3::X_LOWBYTE_IDX]; int16_t mgmMeasurementRawY = - packet[MGMLIS3MDL::Y_HIGHBYTE_IDX] << 8 | packet[MGMLIS3MDL::Y_LOWBYTE_IDX]; + packet[mgmLis3::Y_HIGHBYTE_IDX] << 8 | packet[mgmLis3::Y_LOWBYTE_IDX]; int16_t mgmMeasurementRawZ = - packet[MGMLIS3MDL::Z_HIGHBYTE_IDX] << 8 | packet[MGMLIS3MDL::Z_LOWBYTE_IDX]; + packet[mgmLis3::Z_HIGHBYTE_IDX] << 8 | packet[mgmLis3::Z_LOWBYTE_IDX]; // Target value in microtesla float mgmX = static_cast(mgmMeasurementRawX) * sensitivityFactor * - MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; + mgmLis3::GAUSS_TO_MICROTESLA_FACTOR; float mgmY = static_cast(mgmMeasurementRawY) * sensitivityFactor * - MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; + mgmLis3::GAUSS_TO_MICROTESLA_FACTOR; float mgmZ = static_cast(mgmMeasurementRawZ) * sensitivityFactor * - MGMLIS3MDL::GAUSS_TO_MICROTESLA_FACTOR; + mgmLis3::GAUSS_TO_MICROTESLA_FACTOR; if (periodicPrintout) { if (debugDivider.checkAndIncrement()) { @@ -306,7 +291,7 @@ ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, cons break; } - case MGMLIS3MDL::READ_TEMPERATURE: { + case mgmLis3::READ_TEMPERATURE: { int16_t tempValueRaw = packet[2] << 8 | packet[1]; float tempValue = 25.0 + ((static_cast(tempValueRaw)) / 8.0); if (periodicPrintout) { @@ -334,55 +319,23 @@ ReturnValue_t MgmLIS3MDLHandler::interpretDeviceReply(DeviceCommandId_t id, cons return returnvalue::OK; } -MGMLIS3MDL::Sensitivies MgmLIS3MDLHandler::getSensitivity(uint8_t ctrlRegister2) { - bool fs0Set = ctrlRegister2 & (1 << MGMLIS3MDL::FSO); // Checks if FS0 bit is set - bool fs1Set = ctrlRegister2 & (1 << MGMLIS3MDL::FS1); // Checks if FS1 bit is set - - if (fs0Set && fs1Set) - return MGMLIS3MDL::Sensitivies::GAUSS_16; - else if (!fs0Set && fs1Set) - return MGMLIS3MDL::Sensitivies::GAUSS_12; - else if (fs0Set && !fs1Set) - return MGMLIS3MDL::Sensitivies::GAUSS_8; - else - return MGMLIS3MDL::Sensitivies::GAUSS_4; -} - -float MgmLIS3MDLHandler::getSensitivityFactor(MGMLIS3MDL::Sensitivies sens) { - switch (sens) { - case (MGMLIS3MDL::GAUSS_4): { - return MGMLIS3MDL::FIELD_LSB_PER_GAUSS_4_SENS; - } - case (MGMLIS3MDL::GAUSS_8): { - return MGMLIS3MDL::FIELD_LSB_PER_GAUSS_8_SENS; - } - case (MGMLIS3MDL::GAUSS_12): { - return MGMLIS3MDL::FIELD_LSB_PER_GAUSS_12_SENS; - } - case (MGMLIS3MDL::GAUSS_16): { - return MGMLIS3MDL::FIELD_LSB_PER_GAUSS_16_SENS; - } - default: { - // Should never happen - return MGMLIS3MDL::FIELD_LSB_PER_GAUSS_4_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); + commandBuffer[0] = mgmLis3::writeCommand(mgmLis3::CTRL_REG1); if (commandDataLen > 1) { return INVALID_NUMBER_OR_LENGTH_OF_PARAMETERS; } - switch (*commandData) { - case (MGMLIS3MDL::ON): { + switch (commandData[0]) { + case (mgmLis3::ON): { commandBuffer[1] = registers[0] | (1 << 7); break; } - case (MGMLIS3MDL::OFF): { + case (mgmLis3::OFF): { commandBuffer[1] = registers[0] & ~(1 << 7); break; } @@ -405,23 +358,23 @@ ReturnValue_t MgmLIS3MDLHandler::setOperatingMode(const uint8_t *commandData, } switch (commandData[0]) { - case MGMLIS3MDL::LOW: - registers[0] = (registers[0] & (~(1 << MGMLIS3MDL::OM1))) & (~(1 << MGMLIS3MDL::OM0)); - registers[3] = (registers[3] & (~(1 << MGMLIS3MDL::OMZ1))) & (~(1 << MGMLIS3MDL::OMZ0)); + case mgmLis3::LOW: + registers[0] = (registers[0] & (~(1 << mgmLis3::OM1))) & (~(1 << mgmLis3::OM0)); + registers[3] = (registers[3] & (~(1 << mgmLis3::OMZ1))) & (~(1 << mgmLis3::OMZ0)); break; - case MGMLIS3MDL::MEDIUM: - registers[0] = (registers[0] & (~(1 << MGMLIS3MDL::OM1))) | (1 << MGMLIS3MDL::OM0); - registers[3] = (registers[3] & (~(1 << MGMLIS3MDL::OMZ1))) | (1 << MGMLIS3MDL::OMZ0); + case mgmLis3::MEDIUM: + registers[0] = (registers[0] & (~(1 << mgmLis3::OM1))) | (1 << mgmLis3::OM0); + registers[3] = (registers[3] & (~(1 << mgmLis3::OMZ1))) | (1 << mgmLis3::OMZ0); break; - case MGMLIS3MDL::HIGH: - registers[0] = (registers[0] | (1 << MGMLIS3MDL::OM1)) & (~(1 << MGMLIS3MDL::OM0)); - registers[3] = (registers[3] | (1 << MGMLIS3MDL::OMZ1)) & (~(1 << MGMLIS3MDL::OMZ0)); + case mgmLis3::HIGH: + registers[0] = (registers[0] | (1 << mgmLis3::OM1)) & (~(1 << mgmLis3::OM0)); + registers[3] = (registers[3] | (1 << mgmLis3::OMZ1)) & (~(1 << mgmLis3::OMZ0)); break; - case MGMLIS3MDL::ULTRA: - registers[0] = (registers[0] | (1 << MGMLIS3MDL::OM1)) | (1 << MGMLIS3MDL::OM0); - registers[3] = (registers[3] | (1 << MGMLIS3MDL::OMZ1)) | (1 << MGMLIS3MDL::OMZ0); + case mgmLis3::ULTRA: + registers[0] = (registers[0] | (1 << mgmLis3::OM1)) | (1 << mgmLis3::OM0); + registers[3] = (registers[3] | (1 << mgmLis3::OMZ1)) | (1 << mgmLis3::OMZ0); break; default: break; @@ -431,24 +384,24 @@ ReturnValue_t MgmLIS3MDLHandler::setOperatingMode(const uint8_t *commandData, } void MgmLIS3MDLHandler::fillCommandAndReplyMap() { - insertInCommandAndReplyMap(MGMLIS3MDL::READ_CONFIG_AND_DATA, 1, &dataset); - insertInCommandAndReplyMap(MGMLIS3MDL::READ_TEMPERATURE, 1); - insertInCommandAndReplyMap(MGMLIS3MDL::SETUP_MGM, 1); - insertInCommandAndReplyMap(MGMLIS3MDL::IDENTIFY_DEVICE, 1); - insertInCommandAndReplyMap(MGMLIS3MDL::TEMP_SENSOR_ENABLE, 1); - insertInCommandAndReplyMap(MGMLIS3MDL::ACCURACY_OP_MODE_SET, 1); + insertInCommandAndReplyMap(mgmLis3::READ_CONFIG_AND_DATA, 1, &dataset); + insertInCommandAndReplyMap(mgmLis3::READ_TEMPERATURE, 1); + insertInCommandAndReplyMap(mgmLis3::SETUP_MGM, 1); + insertInCommandAndReplyMap(mgmLis3::IDENTIFY_DEVICE, 1); + insertInCommandAndReplyMap(mgmLis3::TEMP_SENSOR_ENABLE, 1); + insertInCommandAndReplyMap(mgmLis3::ACCURACY_OP_MODE_SET, 1); } void MgmLIS3MDLHandler::setToGoToNormalMode(bool enable) { this->goToNormalMode = enable; } ReturnValue_t MgmLIS3MDLHandler::prepareCtrlRegisterWrite() { - commandBuffer[0] = writeCommand(MGMLIS3MDL::CTRL_REG1, true); + commandBuffer[0] = mgmLis3::writeCommand(mgmLis3::CTRL_REG1, true); - for (size_t i = 0; i < MGMLIS3MDL::NR_OF_CTRL_REGISTERS; i++) { + for (size_t i = 0; i < mgmLis3::NR_OF_CTRL_REGISTERS; i++) { commandBuffer[i + 1] = registers[i]; } rawPacket = commandBuffer; - rawPacketLen = MGMLIS3MDL::NR_OF_CTRL_REGISTERS + 1; + rawPacketLen = mgmLis3::NR_OF_CTRL_REGISTERS + 1; // We dont have to check if this is working because we just did i return returnvalue::OK; @@ -464,8 +417,8 @@ void MgmLIS3MDLHandler::modeChanged(void) { internalState = InternalState::STATE ReturnValue_t MgmLIS3MDLHandler::initializeLocalDataPool(localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { - localDataPoolMap.emplace(MGMLIS3MDL::FIELD_STRENGTHS, &mgmXYZ); - localDataPoolMap.emplace(MGMLIS3MDL::TEMPERATURE_CELCIUS, &temperature); + localDataPoolMap.emplace(mgmLis3::FIELD_STRENGTHS, &mgmXYZ); + localDataPoolMap.emplace(mgmLis3::TEMPERATURE_CELCIUS, &temperature); poolManager.subscribeForRegularPeriodicPacket({dataset.getSid(), false, 10.0}); return returnvalue::OK; } diff --git a/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h b/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h index 3626a2b08..78b3b38c9 100644 --- a/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h +++ b/src/fsfw_hal/devicehandlers/MgmLIS3MDLHandler.h @@ -1,7 +1,8 @@ #ifndef MISSION_DEVICES_MGMLIS3MDLHANDLER_H_ #define MISSION_DEVICES_MGMLIS3MDLHANDLER_H_ -#include "devicedefinitions/MgmLIS3HandlerDefs.h" +#include + #include "fsfw/devicehandlers/DeviceHandlerBase.h" #include "fsfw/globalfunctions/PeriodicOperationDivider.h" @@ -66,7 +67,7 @@ class MgmLIS3MDLHandler : public DeviceHandlerBase { LocalDataPoolManager &poolManager) override; private: - MGMLIS3MDL::MgmPrimaryDataset dataset; + mgmLis3::MgmPrimaryDataset dataset; // Length a single command SPI answer static const uint8_t SINGLE_COMMAND_ANSWER_LEN = 2; @@ -74,7 +75,7 @@ class MgmLIS3MDLHandler : public DeviceHandlerBase { // Single SPI command has 2 bytes, first for adress, second for content size_t singleComandSize = 2; // Has the size for all adresses of the lis3mdl + the continous write bit - uint8_t commandBuffer[MGMLIS3MDL::NR_OF_DATA_AND_CFG_REGISTERS + 1]; + uint8_t commandBuffer[mgmLis3::NR_OF_DATA_AND_CFG_REGISTERS + 1]; float absLimitX = 100; float absLimitY = 100; @@ -85,7 +86,7 @@ class MgmLIS3MDLHandler : public DeviceHandlerBase { * registers when we want to change something. * --> everytime we change set a register we have to save it */ - uint8_t registers[MGMLIS3MDL::NR_OF_CTRL_REGISTERS]; + uint8_t registers[mgmLis3::NR_OF_CTRL_REGISTERS]; uint8_t statusRegister = 0; bool goToNormalMode = false; @@ -107,35 +108,6 @@ class MgmLIS3MDLHandler : public DeviceHandlerBase { /*------------------------------------------------------------------------*/ /* Device specific commands and variables */ /*------------------------------------------------------------------------*/ - /** - * Sets the read bit for the command - * @param single command to set the read-bit at - * @param boolean to select a continuous read bit, default = false - */ - uint8_t readCommand(uint8_t command, bool continuousCom = false); - - /** - * Sets the write bit for the command - * @param single command to set the write-bit at - * @param boolean to select a continuous write bit, default = false - */ - uint8_t writeCommand(uint8_t command, bool continuousCom = false); - - /** - * This Method gets the full scale for the measurement range - * e.g.: +- 4 gauss. See p.25 datasheet. - * @return The ReturnValue does not contain the sign of the value - */ - MGMLIS3MDL::Sensitivies getSensitivity(uint8_t ctrlReg2); - - /** - * The 16 bit value needs to be multiplied with a sensitivity factor - * which depends on the sensitivity configuration - * - * @param sens Configured sensitivity of the LIS3 device - * @return Multiplication factor to get the sensor value from raw data. - */ - float getSensitivityFactor(MGMLIS3MDL::Sensitivies sens); /** * This Command detects the device ID diff --git a/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp b/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp index 307d0a558..c17e3abce 100644 --- a/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp +++ b/src/fsfw_hal/devicehandlers/MgmRM3100Handler.cpp @@ -63,21 +63,21 @@ ReturnValue_t MgmRM3100Handler::buildTransitionDeviceCommand(DeviceCommandId_t * return NOTHING_TO_SEND; } case (InternalState::CONFIGURE_CMM): { - *id = RM3100::CONFIGURE_CMM; + *id = mgmRm3100::CONFIGURE_CMM; break; } case (InternalState::READ_CMM): { - *id = RM3100::READ_CMM; + *id = mgmRm3100::READ_CMM; break; } case (InternalState::STATE_CONFIGURE_TMRC): { - commandBuffer[0] = RM3100::TMRC_DEFAULT_VALUE; + commandBuffer[0] = mgmRm3100::TMRC_DEFAULT_VALUE; commandLen = 1; - *id = RM3100::CONFIGURE_TMRC; + *id = mgmRm3100::CONFIGURE_TMRC; break; } case (InternalState::STATE_READ_TMRC): { - *id = RM3100::READ_TMRC; + *id = mgmRm3100::READ_TMRC; break; } default: @@ -103,42 +103,42 @@ ReturnValue_t MgmRM3100Handler::buildCommandFromCommand(DeviceCommandId_t device const uint8_t *commandData, size_t commandDataLen) { switch (deviceCommand) { - case (RM3100::CONFIGURE_CMM): { - commandBuffer[0] = RM3100::CMM_REGISTER; - commandBuffer[1] = RM3100::CMM_VALUE; + case (mgmRm3100::CONFIGURE_CMM): { + commandBuffer[0] = mgmRm3100::CMM_REGISTER; + commandBuffer[1] = mgmRm3100::CMM_VALUE; rawPacket = commandBuffer; rawPacketLen = 2; break; } - case (RM3100::READ_CMM): { - commandBuffer[0] = RM3100::CMM_REGISTER | RM3100::READ_MASK; + case (mgmRm3100::READ_CMM): { + commandBuffer[0] = mgmRm3100::CMM_REGISTER | mgmRm3100::READ_MASK; commandBuffer[1] = 0; rawPacket = commandBuffer; rawPacketLen = 2; break; } - case (RM3100::CONFIGURE_TMRC): { + case (mgmRm3100::CONFIGURE_TMRC): { return handleTmrcConfigCommand(deviceCommand, commandData, commandDataLen); } - case (RM3100::READ_TMRC): { - commandBuffer[0] = RM3100::TMRC_REGISTER | RM3100::READ_MASK; + case (mgmRm3100::READ_TMRC): { + commandBuffer[0] = mgmRm3100::TMRC_REGISTER | mgmRm3100::READ_MASK; commandBuffer[1] = 0; rawPacket = commandBuffer; rawPacketLen = 2; break; } - case (RM3100::CONFIGURE_CYCLE_COUNT): { + case (mgmRm3100::CONFIGURE_CYCLE_COUNT): { return handleCycleCountConfigCommand(deviceCommand, commandData, commandDataLen); } - case (RM3100::READ_CYCLE_COUNT): { - commandBuffer[0] = RM3100::CYCLE_COUNT_START_REGISTER | RM3100::READ_MASK; + case (mgmRm3100::READ_CYCLE_COUNT): { + commandBuffer[0] = mgmRm3100::CYCLE_COUNT_START_REGISTER | mgmRm3100::READ_MASK; std::memset(commandBuffer + 1, 0, 6); rawPacket = commandBuffer; rawPacketLen = 7; break; } - case (RM3100::READ_DATA): { - commandBuffer[0] = RM3100::MEASUREMENT_REG_START | RM3100::READ_MASK; + case (mgmRm3100::READ_DATA): { + commandBuffer[0] = mgmRm3100::MEASUREMENT_REG_START | mgmRm3100::READ_MASK; std::memset(commandBuffer + 1, 0, 9); rawPacketLen = 10; break; @@ -150,7 +150,7 @@ ReturnValue_t MgmRM3100Handler::buildCommandFromCommand(DeviceCommandId_t device } ReturnValue_t MgmRM3100Handler::buildNormalDeviceCommand(DeviceCommandId_t *id) { - *id = RM3100::READ_DATA; + *id = mgmRm3100::READ_DATA; return buildCommandFromCommand(*id, nullptr, 0); } @@ -165,16 +165,16 @@ ReturnValue_t MgmRM3100Handler::scanForReply(const uint8_t *start, size_t len, ReturnValue_t MgmRM3100Handler::interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) { ReturnValue_t result = returnvalue::OK; switch (id) { - case (RM3100::CONFIGURE_CMM): - case (RM3100::CONFIGURE_CYCLE_COUNT): - case (RM3100::CONFIGURE_TMRC): { + case (mgmRm3100::CONFIGURE_CMM): + case (mgmRm3100::CONFIGURE_CYCLE_COUNT): + case (mgmRm3100::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; } - case (RM3100::READ_CMM): { + case (mgmRm3100::READ_CMM): { uint8_t cmmValue = packet[1]; // We clear the seventh bit in any case // because this one is zero sometimes for some reason @@ -188,11 +188,11 @@ ReturnValue_t MgmRM3100Handler::interpretDeviceReply(DeviceCommandId_t id, const } break; } - case (RM3100::READ_TMRC): { + case (mgmRm3100::READ_TMRC): { 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 { @@ -202,7 +202,7 @@ ReturnValue_t MgmRM3100Handler::interpretDeviceReply(DeviceCommandId_t id, const } break; } - case (RM3100::READ_CYCLE_COUNT): { + case (mgmRm3100::READ_CYCLE_COUNT): { uint16_t cycleCountX = packet[1] << 8 | packet[2]; uint16_t cycleCountY = packet[3] << 8 | packet[4]; uint16_t cycleCountZ = packet[5] << 8 | packet[6]; @@ -211,13 +211,13 @@ 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); } break; } - case (RM3100::READ_DATA): { + case (mgmRm3100::READ_DATA): { result = handleDataReadout(packet); break; } @@ -244,7 +244,7 @@ ReturnValue_t MgmRM3100Handler::handleCycleCountConfigCommand(DeviceCommandId_t return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; } - commandBuffer[0] = RM3100::CYCLE_COUNT_VALUE; + commandBuffer[0] = mgmRm3100::CYCLE_COUNT_VALUE; std::memcpy(commandBuffer + 1, &cycleCountRegValueX, 2); std::memcpy(commandBuffer + 3, &cycleCountRegValueY, 2); std::memcpy(commandBuffer + 5, &cycleCountRegValueZ, 2); @@ -255,7 +255,7 @@ ReturnValue_t MgmRM3100Handler::handleCycleCountConfigCommand(DeviceCommandId_t ReturnValue_t MgmRM3100Handler::handleCycleCommand(bool oneCycleValue, const uint8_t *commandData, size_t commandDataLen) { - RM3100::CycleCountCommand command(oneCycleValue); + mgmRm3100::CycleCountCommand command(oneCycleValue); ReturnValue_t result = command.deSerialize(&commandData, &commandDataLen, SerializeIF::Endianness::BIG); if (result != returnvalue::OK) { @@ -284,7 +284,7 @@ ReturnValue_t MgmRM3100Handler::handleTmrcConfigCommand(DeviceCommandId_t device return DeviceHandlerIF::INVALID_COMMAND_PARAMETER; } - commandBuffer[0] = RM3100::TMRC_REGISTER; + commandBuffer[0] = mgmRm3100::TMRC_REGISTER; commandBuffer[1] = commandData[0]; tmrcRegValue = commandData[0]; rawPacketLen = 2; @@ -293,23 +293,23 @@ ReturnValue_t MgmRM3100Handler::handleTmrcConfigCommand(DeviceCommandId_t device } void MgmRM3100Handler::fillCommandAndReplyMap() { - insertInCommandAndReplyMap(RM3100::CONFIGURE_CMM, 3); - insertInCommandAndReplyMap(RM3100::READ_CMM, 3); + insertInCommandAndReplyMap(mgmRm3100::CONFIGURE_CMM, 3); + insertInCommandAndReplyMap(mgmRm3100::READ_CMM, 3); - insertInCommandAndReplyMap(RM3100::CONFIGURE_TMRC, 3); - insertInCommandAndReplyMap(RM3100::READ_TMRC, 3); + insertInCommandAndReplyMap(mgmRm3100::CONFIGURE_TMRC, 3); + insertInCommandAndReplyMap(mgmRm3100::READ_TMRC, 3); - insertInCommandAndReplyMap(RM3100::CONFIGURE_CYCLE_COUNT, 3); - insertInCommandAndReplyMap(RM3100::READ_CYCLE_COUNT, 3); + insertInCommandAndReplyMap(mgmRm3100::CONFIGURE_CYCLE_COUNT, 3); + insertInCommandAndReplyMap(mgmRm3100::READ_CYCLE_COUNT, 3); - insertInCommandAndReplyMap(RM3100::READ_DATA, 3, &primaryDataset); + insertInCommandAndReplyMap(mgmRm3100::READ_DATA, 3, &primaryDataset); } void MgmRM3100Handler::modeChanged() { internalState = InternalState::NONE; } ReturnValue_t MgmRM3100Handler::initializeLocalDataPool(localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { - localDataPoolMap.emplace(RM3100::FIELD_STRENGTHS, &mgmXYZ); + localDataPoolMap.emplace(mgmRm3100::FIELD_STRENGTHS, &mgmXYZ); poolManager.subscribeForRegularPeriodicPacket({primaryDataset.getSid(), false, 10.0}); return returnvalue::OK; } diff --git a/src/fsfw_hal/devicehandlers/MgmRM3100Handler.h b/src/fsfw_hal/devicehandlers/MgmRM3100Handler.h index d45b24041..1e56bc9d3 100644 --- a/src/fsfw_hal/devicehandlers/MgmRM3100Handler.h +++ b/src/fsfw_hal/devicehandlers/MgmRM3100Handler.h @@ -1,7 +1,8 @@ #ifndef MISSION_DEVICES_MGMRM3100HANDLER_H_ #define MISSION_DEVICES_MGMRM3100HANDLER_H_ -#include "devicedefinitions/MgmRM3100HandlerDefs.h" +#include + #include "fsfw/devicehandlers/DeviceHandlerBase.h" #include "fsfw/globalfunctions/PeriodicOperationDivider.h" @@ -69,19 +70,19 @@ class MgmRM3100Handler : public DeviceHandlerBase { }; InternalState internalState = InternalState::NONE; bool commandExecuted = false; - RM3100::Rm3100PrimaryDataset primaryDataset; + mgmRm3100::Rm3100PrimaryDataset primaryDataset; uint8_t commandBuffer[10]; uint8_t commandBufferLen = 0; - uint8_t cmmRegValue = RM3100::CMM_VALUE; - uint8_t tmrcRegValue = RM3100::TMRC_DEFAULT_VALUE; - uint16_t cycleCountRegValueX = RM3100::CYCLE_COUNT_VALUE; - uint16_t cycleCountRegValueY = RM3100::CYCLE_COUNT_VALUE; - uint16_t cycleCountRegValueZ = RM3100::CYCLE_COUNT_VALUE; - float scaleFactorX = 1.0 / RM3100::DEFAULT_GAIN; - float scaleFactorY = 1.0 / RM3100::DEFAULT_GAIN; - float scaleFactorZ = 1.0 / RM3100::DEFAULT_GAIN; + uint8_t cmmRegValue = mgmRm3100::CMM_VALUE; + uint8_t tmrcRegValue = mgmRm3100::TMRC_DEFAULT_VALUE; + uint16_t cycleCountRegValueX = mgmRm3100::CYCLE_COUNT_VALUE; + uint16_t cycleCountRegValueY = mgmRm3100::CYCLE_COUNT_VALUE; + uint16_t cycleCountRegValueZ = mgmRm3100::CYCLE_COUNT_VALUE; + float scaleFactorX = 1.0 / mgmRm3100::DEFAULT_GAIN; + float scaleFactorY = 1.0 / mgmRm3100::DEFAULT_GAIN; + float scaleFactorZ = 1.0 / mgmRm3100::DEFAULT_GAIN; bool goToNormalModeAtStartup = false; uint32_t transitionDelay; diff --git a/src/fsfw_hal/devicehandlers/devicedefinitions/CMakeLists.txt b/src/fsfw_hal/devicehandlers/devicedefinitions/CMakeLists.txt new file mode 100644 index 000000000..2d874fb56 --- /dev/null +++ b/src/fsfw_hal/devicehandlers/devicedefinitions/CMakeLists.txt @@ -0,0 +1 @@ +target_sources(${LIB_FSFW_NAME} PRIVATE gyroL3gHelpers.cpp mgmLis3Helpers.cpp) diff --git a/src/fsfw_hal/devicehandlers/devicedefinitions/gyroL3gHelpers.cpp b/src/fsfw_hal/devicehandlers/devicedefinitions/gyroL3gHelpers.cpp new file mode 100644 index 000000000..13f00b102 --- /dev/null +++ b/src/fsfw_hal/devicehandlers/devicedefinitions/gyroL3gHelpers.cpp @@ -0,0 +1,14 @@ +#include + +float l3gd20h::ctrlReg4ToSensitivity(uint8_t reg) { + bool fsH = reg & l3gd20h::SET_FS_1; + bool fsL = reg & l3gd20h::SET_FS_0; + + if (not fsH and not fsL) { + return l3gd20h::SENSITIVITY_00; + } else if (not fsH and fsL) { + return l3gd20h::SENSITIVITY_01; + } else { + return l3gd20h::SENSITIVITY_11; + } +} diff --git a/src/fsfw_hal/devicehandlers/devicedefinitions/GyroL3GD20Definitions.h b/src/fsfw_hal/devicehandlers/devicedefinitions/gyroL3gHelpers.h similarity index 84% rename from src/fsfw_hal/devicehandlers/devicedefinitions/GyroL3GD20Definitions.h rename to src/fsfw_hal/devicehandlers/devicedefinitions/gyroL3gHelpers.h index 2a85ff3e7..0135a04c1 100644 --- a/src/fsfw_hal/devicehandlers/devicedefinitions/GyroL3GD20Definitions.h +++ b/src/fsfw_hal/devicehandlers/devicedefinitions/gyroL3gHelpers.h @@ -6,7 +6,9 @@ #include -namespace L3GD20H { +namespace l3gd20h { + +float ctrlReg4ToSensitivity(uint8_t reg); /* Actual size is 15 but we round up a bit */ static constexpr size_t MAX_BUFFER_SIZE = 16; @@ -71,8 +73,10 @@ static constexpr uint8_t CTRL_REG_4_VAL = SET_BLE; /* Register 5 */ static constexpr uint8_t SET_REBOOT_MEM = 1 << 7; static constexpr uint8_t SET_FIFO_ENB = 1 << 6; +static constexpr uint8_t SET_OUT_SEL_1 = 1 << 1; +static constexpr uint8_t SET_OUT_SEL_0 = 1 << 0; -static constexpr uint8_t CTRL_REG_5_VAL = 0b00000000; +static constexpr uint8_t CTRL_REG_5_VAL = SET_OUT_SEL_1 | SET_OUT_SEL_0; /* Possible range values in degrees per second (DPS). */ static constexpr uint16_t RANGE_DPS_00 = 245; @@ -103,31 +107,33 @@ static constexpr DeviceCommandId_t READ_REGS = 0; static constexpr DeviceCommandId_t CONFIGURE_CTRL_REGS = 1; static constexpr DeviceCommandId_t READ_CTRL_REGS = 2; +static constexpr DeviceCommandId_t REQUEST = 0x70; +static constexpr DeviceCommandId_t REPLY = 0x77; + static constexpr uint32_t GYRO_DATASET_ID = READ_REGS; enum GyroPoolIds : lp_id_t { ANG_VELOC_X, ANG_VELOC_Y, ANG_VELOC_Z, TEMPERATURE }; -} // namespace L3GD20H +} // namespace l3gd20h class GyroPrimaryDataset : public StaticLocalDataSet<5> { public: /** Constructor for data users like controllers */ GyroPrimaryDataset(object_id_t mgmId) - : StaticLocalDataSet(sid_t(mgmId, L3GD20H::GYRO_DATASET_ID)) { + : StaticLocalDataSet(sid_t(mgmId, l3gd20h::GYRO_DATASET_ID)) { setAllVariablesReadOnly(); } - - /* Angular velocities in degrees per second (DPS) */ - lp_var_t angVelocX = lp_var_t(sid.objectId, L3GD20H::ANG_VELOC_X, this); - lp_var_t angVelocY = lp_var_t(sid.objectId, L3GD20H::ANG_VELOC_Y, this); - lp_var_t angVelocZ = lp_var_t(sid.objectId, L3GD20H::ANG_VELOC_Z, this); - lp_var_t temperature = lp_var_t(sid.objectId, L3GD20H::TEMPERATURE, this); - - private: - friend class GyroHandlerL3GD20H; /** Constructor for the data creator */ GyroPrimaryDataset(HasLocalDataPoolIF* hkOwner) - : StaticLocalDataSet(hkOwner, L3GD20H::GYRO_DATASET_ID) {} + : StaticLocalDataSet(hkOwner, l3gd20h::GYRO_DATASET_ID) {} + + /* Angular velocities in degrees per second (DPS) */ + lp_var_t angVelocX = lp_var_t(sid.objectId, l3gd20h::ANG_VELOC_X, this); + lp_var_t angVelocY = lp_var_t(sid.objectId, l3gd20h::ANG_VELOC_Y, this); + lp_var_t angVelocZ = lp_var_t(sid.objectId, l3gd20h::ANG_VELOC_Z, this); + lp_var_t temperature = lp_var_t(sid.objectId, l3gd20h::TEMPERATURE, this); + + private: }; #endif /* MISSION_DEVICES_DEVICEDEFINITIONS_GYROL3GD20DEFINITIONS_H_ */ diff --git a/src/fsfw_hal/devicehandlers/devicedefinitions/mgmLis3Helpers.cpp b/src/fsfw_hal/devicehandlers/devicedefinitions/mgmLis3Helpers.cpp new file mode 100644 index 000000000..3609ea013 --- /dev/null +++ b/src/fsfw_hal/devicehandlers/devicedefinitions/mgmLis3Helpers.cpp @@ -0,0 +1,52 @@ +#include "mgmLis3Helpers.h" + +uint8_t mgmLis3::readCommand(uint8_t command, bool continuousCom) { + command |= (1 << mgmLis3::RW_BIT); + if (continuousCom == true) { + command |= (1 << mgmLis3::MS_BIT); + } + return command; +} + +uint8_t mgmLis3::writeCommand(uint8_t command, bool continuousCom) { + command &= ~(1 << mgmLis3::RW_BIT); + if (continuousCom == true) { + command |= (1 << mgmLis3::MS_BIT); + } + return command; +} + +mgmLis3::Sensitivies mgmLis3::getSensitivity(uint8_t ctrlRegister2) { + bool fs0Set = ctrlRegister2 & (1 << mgmLis3::FSO); // Checks if FS0 bit is set + bool fs1Set = ctrlRegister2 & (1 << mgmLis3::FS1); // Checks if FS1 bit is set + + if (fs0Set && fs1Set) + return mgmLis3::Sensitivies::GAUSS_16; + else if (!fs0Set && fs1Set) + return mgmLis3::Sensitivies::GAUSS_12; + else if (fs0Set && !fs1Set) + return mgmLis3::Sensitivies::GAUSS_8; + else + return mgmLis3::Sensitivies::GAUSS_4; +} + +float mgmLis3::getSensitivityFactor(mgmLis3::Sensitivies sens) { + switch (sens) { + case (mgmLis3::GAUSS_4): { + return mgmLis3::FIELD_LSB_PER_GAUSS_4_SENS; + } + case (mgmLis3::GAUSS_8): { + return mgmLis3::FIELD_LSB_PER_GAUSS_8_SENS; + } + case (mgmLis3::GAUSS_12): { + return mgmLis3::FIELD_LSB_PER_GAUSS_12_SENS; + } + case (mgmLis3::GAUSS_16): { + return mgmLis3::FIELD_LSB_PER_GAUSS_16_SENS; + } + default: { + // Should never happen + return mgmLis3::FIELD_LSB_PER_GAUSS_4_SENS; + } + } +} diff --git a/src/fsfw_hal/devicehandlers/devicedefinitions/MgmLIS3HandlerDefs.h b/src/fsfw_hal/devicehandlers/devicedefinitions/mgmLis3Helpers.h similarity index 86% rename from src/fsfw_hal/devicehandlers/devicedefinitions/MgmLIS3HandlerDefs.h rename to src/fsfw_hal/devicehandlers/devicedefinitions/mgmLis3Helpers.h index 34237637e..8d47a2008 100644 --- a/src/fsfw_hal/devicehandlers/devicedefinitions/MgmLIS3HandlerDefs.h +++ b/src/fsfw_hal/devicehandlers/devicedefinitions/mgmLis3Helpers.h @@ -7,13 +7,43 @@ #include -namespace MGMLIS3MDL { +namespace mgmLis3 { enum Set { ON, OFF }; enum OpMode { LOW, MEDIUM, HIGH, ULTRA }; enum Sensitivies : uint8_t { GAUSS_4 = 4, GAUSS_8 = 8, GAUSS_12 = 12, GAUSS_16 = 16 }; +/** + * Sets the read bit for the command + * @param single command to set the read-bit at + * @param boolean to select a continuous read bit, default = false + */ +uint8_t readCommand(uint8_t command, bool continuousCom = false); + +/** + * Sets the write bit for the command + * @param single command to set the write-bit at + * @param boolean to select a continuous write bit, default = false + */ +uint8_t writeCommand(uint8_t command, bool continuousCom = false); + +/** + * This Method gets the full scale for the measurement range + * e.g.: +- 4 gauss. See p.25 datasheet. + * @return The ReturnValue does not contain the sign of the value + */ +mgmLis3::Sensitivies getSensitivity(uint8_t ctrlReg2); + +/** + * The 16 bit value needs to be multiplied with a sensitivity factor + * which depends on the sensitivity configuration + * + * @param sens Configured sensitivity of the LIS3 device + * @return Multiplication factor to get the sensor value from raw data. + */ +float getSensitivityFactor(mgmLis3::Sensitivies sens); + /* Actually 15, we just round up a bit */ static constexpr size_t MAX_BUFFER_SIZE = 16; @@ -154,6 +184,6 @@ class MgmPrimaryDataset : public StaticLocalDataSet<4> { lp_var_t temperature = lp_var_t(sid.objectId, TEMPERATURE_CELCIUS, this); }; -} // namespace MGMLIS3MDL +} // namespace mgmLis3 #endif /* MISSION_DEVICES_DEVICEDEFINITIONS_MGMLIS3HANDLERDEFS_H_ */ diff --git a/src/fsfw_hal/devicehandlers/devicedefinitions/MgmRM3100HandlerDefs.h b/src/fsfw_hal/devicehandlers/devicedefinitions/mgmRm3100Helpers.h similarity index 98% rename from src/fsfw_hal/devicehandlers/devicedefinitions/MgmRM3100HandlerDefs.h rename to src/fsfw_hal/devicehandlers/devicedefinitions/mgmRm3100Helpers.h index a2aa8ab00..680bd13dd 100644 --- a/src/fsfw_hal/devicehandlers/devicedefinitions/MgmRM3100HandlerDefs.h +++ b/src/fsfw_hal/devicehandlers/devicedefinitions/mgmRm3100Helpers.h @@ -8,7 +8,7 @@ #include -namespace RM3100 { +namespace mgmRm3100 { /* Actually 10, we round up a little bit */ static constexpr size_t MAX_BUFFER_SIZE = 12; @@ -115,6 +115,6 @@ class Rm3100PrimaryDataset : public StaticLocalDataSet<3> { lp_vec_t fieldStrengths = lp_vec_t(sid.objectId, FIELD_STRENGTHS, this); }; -} // namespace RM3100 +} // namespace mgmRm3100 #endif /* MISSION_DEVICES_DEVICEDEFINITIONS_MGMHANDLERRM3100DEFINITIONS_H_ */ diff --git a/src/fsfw_hal/host/HostFilesystem.cpp b/src/fsfw_hal/host/HostFilesystem.cpp index fe593f278..20984f77c 100644 --- a/src/fsfw_hal/host/HostFilesystem.cpp +++ b/src/fsfw_hal/host/HostFilesystem.cpp @@ -15,7 +15,8 @@ ReturnValue_t HostFilesystem::writeToFile(FileOpParams params, const uint8_t *da return returnvalue::FAILED; } path path(params.path()); - if (not exists(path)) { + std::error_code e; + if (not exists(path, e)) { return HasFileSystemIF::FILE_DOES_NOT_EXIST; } // This is equivalent to "r+" mode, which is what we need here. Only using ::out would truncate @@ -35,7 +36,8 @@ ReturnValue_t HostFilesystem::readFromFile(FileOpParams params, uint8_t **buffer return returnvalue::FAILED; } path path(params.path()); - if (not exists(path)) { + std::error_code e; + if (not exists(path, e)) { return HasFileSystemIF::FILE_DOES_NOT_EXIST; } ifstream file(path); @@ -59,7 +61,8 @@ ReturnValue_t HostFilesystem::createFile(FilesystemParams params, const uint8_t return returnvalue::FAILED; } path path(params.path); - if (exists(path)) { + std::error_code e; + if (exists(path, e)) { return HasFileSystemIF::FILE_ALREADY_EXISTS; } ofstream file(path); @@ -74,7 +77,8 @@ ReturnValue_t HostFilesystem::removeFile(const char *path_, FileSystemArgsIF *ar return returnvalue::FAILED; } path path(path_); - if (not exists(path)) { + std::error_code e; + if (not exists(path, e)) { return HasFileSystemIF::FILE_DOES_NOT_EXIST; } if (remove(path, errorCode)) { @@ -89,7 +93,8 @@ ReturnValue_t HostFilesystem::createDirectory(FilesystemParams params, bool crea } path dirPath(params.path); - if (exists(dirPath)) { + std::error_code e; + if (exists(dirPath, e)) { return HasFileSystemIF::DIRECTORY_ALREADY_EXISTS; } @@ -110,7 +115,8 @@ ReturnValue_t HostFilesystem::removeDirectory(FilesystemParams params, bool dele return returnvalue::FAILED; } path dirPath(params.path); - if (not exists(dirPath)) { + std::error_code e; + if (not exists(dirPath, e)) { return HasFileSystemIF::DIRECTORY_DOES_NOT_EXIST; } if (is_regular_file(dirPath)) { @@ -149,14 +155,32 @@ ReturnValue_t HostFilesystem::rename(const char *oldPath_, const char *newPath_, bool HostFilesystem::fileExists(FilesystemParams params) { path path(params.path); - return filesystem::exists(path); + std::error_code e; + return filesystem::exists(path, e); } ReturnValue_t HostFilesystem::truncateFile(FilesystemParams params) { path path(params.path); - if (not filesystem::exists(path)) { + std::error_code e; + if (not filesystem::exists(path, e)) { return FILE_DOES_NOT_EXIST; } - ofstream of(path); + // Specify truncation flug explicitely. + ofstream of(path, std::ios::out | std::ios::trunc); + return returnvalue::OK; +} + +bool HostFilesystem::isDirectory(const char *path) { return filesystem::is_directory(path); } + +ReturnValue_t HostFilesystem::getBaseFilename(FilesystemParams params, char *nameBuf, size_t maxLen, + size_t &baseNameLen) { + std::string path(params.path); + std::string baseName = path.substr(path.find_last_of("/\\") + 1); + if (baseName.size() + 1 > maxLen) { + return returnvalue::FAILED; + } + std::memcpy(nameBuf, baseName.c_str(), baseName.size()); + nameBuf[baseName.size()] = '\0'; + baseNameLen = baseName.size(); return returnvalue::OK; } diff --git a/src/fsfw_hal/host/HostFilesystem.h b/src/fsfw_hal/host/HostFilesystem.h index 7b865e2de..da217aecd 100644 --- a/src/fsfw_hal/host/HostFilesystem.h +++ b/src/fsfw_hal/host/HostFilesystem.h @@ -9,6 +9,9 @@ class HostFilesystem : public HasFileSystemIF { public: HostFilesystem(); + ReturnValue_t getBaseFilename(FilesystemParams params, char *nameBuf, size_t maxLen, + size_t &baseNameLen) override; + bool isDirectory(const char *path) override; bool fileExists(FilesystemParams params) override; ReturnValue_t truncateFile(FilesystemParams params) override; ReturnValue_t writeToFile(FileOpParams params, const uint8_t *data) override; diff --git a/src/fsfw_hal/linux/CommandExecutor.cpp b/src/fsfw_hal/linux/CommandExecutor.cpp index 27cf8aca8..e8f64432b 100644 --- a/src/fsfw_hal/linux/CommandExecutor.cpp +++ b/src/fsfw_hal/linux/CommandExecutor.cpp @@ -17,7 +17,7 @@ ReturnValue_t CommandExecutor::load(std::string command, bool blocking, bool pri return COMMAND_PENDING; } - currentCmd = command; + currentCmd = std::move(command); this->blocking = blocking; this->printOutput = printOutput; if (state == States::IDLE) { diff --git a/src/fsfw_hal/linux/UnixFileGuard.cpp b/src/fsfw_hal/linux/UnixFileGuard.cpp index 412938158..3178f39d2 100644 --- a/src/fsfw_hal/linux/UnixFileGuard.cpp +++ b/src/fsfw_hal/linux/UnixFileGuard.cpp @@ -6,14 +6,11 @@ #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) { - return; - } - *fileDescriptor = open(device.c_str(), flags); - if (*fileDescriptor < 0) { + : fdRef(fileDescriptor) { + fileDescriptor = open(device.c_str(), flags); + if (fileDescriptor < 0) { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << diagnosticPrefix << ": Opening device failed with error code " << errno << ": " @@ -27,10 +24,6 @@ UnixFileGuard::UnixFileGuard(std::string device, int* fileDescriptor, int flags, } } -UnixFileGuard::~UnixFileGuard() { - if (fileDescriptor != nullptr) { - close(*fileDescriptor); - } -} +UnixFileGuard::~UnixFileGuard() { close(fdRef); } ReturnValue_t UnixFileGuard::getOpenResult() const { return openStatus; } diff --git a/src/fsfw_hal/linux/UnixFileGuard.h b/src/fsfw_hal/linux/UnixFileGuard.h index 3e4ddca85..884e551cc 100644 --- a/src/fsfw_hal/linux/UnixFileGuard.h +++ b/src/fsfw_hal/linux/UnixFileGuard.h @@ -15,7 +15,15 @@ class UnixFileGuard { static constexpr ReturnValue_t OPEN_FILE_FAILED = 1; - UnixFileGuard(std::string device, int* fileDescriptor, int flags, + /** + * Open a device and assign the given file descriptor variable + * @param device [in] Device name. + * @param fileDescriptor [in/out] Will be assigned by file guard and re-used to + * close the guard. + * @param flags + * @param diagnosticPrefix + */ + UnixFileGuard(const std::string& device, int& fileDescriptor, int flags, std::string diagnosticPrefix = ""); virtual ~UnixFileGuard(); @@ -23,7 +31,7 @@ class UnixFileGuard { ReturnValue_t getOpenResult() const; private: - int* fileDescriptor = nullptr; + int& fdRef; ReturnValue_t openStatus = returnvalue::OK; }; diff --git a/src/fsfw_hal/linux/gpio/Gpio.h b/src/fsfw_hal/linux/gpio/Gpio.h new file mode 100644 index 000000000..40cc1df57 --- /dev/null +++ b/src/fsfw_hal/linux/gpio/Gpio.h @@ -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_ */ diff --git a/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp b/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp index cecc1f3fb..701de8f02 100644 --- a/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp +++ b/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.cpp @@ -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(gpiod_line_get_value(regularGpio->lineHandle)); + if (gpioState == gpio::Levels::FAILED) { + return GPIO_GET_VALUE_FAILED; + } } else { auto gpioCallback = dynamic_cast(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; diff --git a/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h b/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h index bb8e890d9..a625770c6 100644 --- a/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h +++ b/src/fsfw_hal/linux/gpio/LinuxLibgpioIF.h @@ -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. diff --git a/src/fsfw_hal/linux/i2c/I2cComIF.cpp b/src/fsfw_hal/linux/i2c/I2cComIF.cpp index e3e500402..1a85d4d34 100644 --- a/src/fsfw_hal/linux/i2c/I2cComIF.cpp +++ b/src/fsfw_hal/linux/i2c/I2cComIF.cpp @@ -66,8 +66,7 @@ ReturnValue_t I2cComIF::initializeInterface(CookieIF* cookie) { ReturnValue_t I2cComIF::sendMessage(CookieIF* cookie, const uint8_t* sendData, size_t sendLen) { ReturnValue_t result; - int fd; - std::string deviceFile; + int fd = 0; if (sendData == nullptr) { #if FSFW_CPP_OSTREAM_ENABLED == 1 @@ -98,25 +97,29 @@ ReturnValue_t I2cComIF::sendMessage(CookieIF* cookie, const uint8_t* sendData, s return returnvalue::FAILED; } - deviceFile = i2cCookie->getDeviceFile(); - UnixFileGuard fileHelper(deviceFile, &fd, O_RDWR, "I2cComIF::sendMessage"); + const auto& deviceFile = i2cCookie->getDeviceFile(); + UnixFileGuard fileHelper(deviceFile, fd, O_RDWR, "I2cComIF::sendMessage"); if (fileHelper.getOpenResult() != returnvalue::OK) { return fileHelper.getOpenResult(); } - result = openDevice(deviceFile, i2cAddress, &fd); + result = openI2cSlave(deviceFile, i2cAddress, fd); if (result != returnvalue::OK) { return result; } if (write(fd, sendData, sendLen) != static_cast(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 from " + << deviceFile << " 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); @@ -128,8 +131,7 @@ ReturnValue_t I2cComIF::getSendSuccess(CookieIF* cookie) { return returnvalue::O ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLen) { ReturnValue_t result; - int fd; - std::string deviceFile; + int fd = 0; if (requestLen == 0) { return returnvalue::OK; @@ -154,12 +156,12 @@ ReturnValue_t I2cComIF::requestReceiveMessage(CookieIF* cookie, size_t requestLe } i2cDeviceMapIter->second.replyLen = 0; - deviceFile = i2cCookie->getDeviceFile(); - UnixFileGuard fileHelper(deviceFile, &fd, O_RDWR, "I2cComIF::requestReceiveMessage"); + auto& deviceFile = i2cCookie->getDeviceFile(); + UnixFileGuard fileHelper(deviceFile, fd, O_RDWR, "I2cComIF::requestReceiveMessage"); if (fileHelper.getOpenResult() != returnvalue::OK) { return fileHelper.getOpenResult(); } - result = openDevice(deviceFile, i2cAddress, &fd); + result = openI2cSlave(deviceFile, i2cAddress, fd); if (result != returnvalue::OK) { return result; } @@ -217,9 +219,9 @@ ReturnValue_t I2cComIF::readReceivedMessage(CookieIF* cookie, uint8_t** buffer, return returnvalue::OK; } -ReturnValue_t I2cComIF::openDevice(std::string deviceFile, address_t i2cAddress, - int* fileDescriptor) { - if (ioctl(*fileDescriptor, I2C_SLAVE, i2cAddress) < 0) { +ReturnValue_t I2cComIF::openI2cSlave(const std::string& deviceFile, address_t i2cAddress, + int& fileDescriptor) { + if (ioctl(fileDescriptor, I2C_SLAVE, i2cAddress) < 0) { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "I2cComIF: Specifying target device failed with error code " << errno << "." diff --git a/src/fsfw_hal/linux/i2c/I2cComIF.h b/src/fsfw_hal/linux/i2c/I2cComIF.h index 8c44cee01..983ce734b 100644 --- a/src/fsfw_hal/linux/i2c/I2cComIF.h +++ b/src/fsfw_hal/linux/i2c/I2cComIF.h @@ -49,7 +49,8 @@ class I2cComIF : public DeviceCommunicationIF, public SystemObject { * @param fileDescriptor Pointer to device descriptor. * @return returnvalue::OK if successful, otherwise returnvalue::FAILED. */ - ReturnValue_t openDevice(std::string deviceFile, address_t i2cAddress, int *fileDescriptor); + ReturnValue_t openI2cSlave(const std::string &deviceFile, address_t i2cAddress, + int &fileDescriptor); }; #endif /* LINUX_I2C_I2COMIF_H_ */ diff --git a/src/fsfw_hal/linux/i2c/I2cCookie.cpp b/src/fsfw_hal/linux/i2c/I2cCookie.cpp index 0186be604..f41527a30 100644 --- a/src/fsfw_hal/linux/i2c/I2cCookie.cpp +++ b/src/fsfw_hal/linux/i2c/I2cCookie.cpp @@ -1,12 +1,12 @@ #include "fsfw_hal/linux/i2c/I2cCookie.h" I2cCookie::I2cCookie(address_t i2cAddress_, size_t maxReplyLen_, std::string deviceFile_) - : i2cAddress(i2cAddress_), maxReplyLen(maxReplyLen_), deviceFile(deviceFile_) {} + : i2cAddress(i2cAddress_), maxReplyLen(maxReplyLen_), deviceFile(std::move(deviceFile_)) {} address_t I2cCookie::getAddress() const { return i2cAddress; } size_t I2cCookie::getMaxReplyLen() const { return maxReplyLen; } -std::string I2cCookie::getDeviceFile() const { return deviceFile; } +const std::string& I2cCookie::getDeviceFile() const { return deviceFile; } I2cCookie::~I2cCookie() {} diff --git a/src/fsfw_hal/linux/i2c/I2cCookie.h b/src/fsfw_hal/linux/i2c/I2cCookie.h index 84a1873c3..e54bcd55c 100644 --- a/src/fsfw_hal/linux/i2c/I2cCookie.h +++ b/src/fsfw_hal/linux/i2c/I2cCookie.h @@ -25,7 +25,9 @@ class I2cCookie : public CookieIF { address_t getAddress() const; size_t getMaxReplyLen() const; - std::string getDeviceFile() const; + const std::string& getDeviceFile() const; + + uint8_t errorCounter = 0; private: address_t i2cAddress = 0; diff --git a/src/fsfw_hal/linux/serial/SerialComIF.cpp b/src/fsfw_hal/linux/serial/SerialComIF.cpp index 177d74e45..f272e787e 100644 --- a/src/fsfw_hal/linux/serial/SerialComIF.cpp +++ b/src/fsfw_hal/linux/serial/SerialComIF.cpp @@ -88,11 +88,11 @@ int SerialComIF::configureUartPort(SerialCookie* uartCookie) { return fd; } - uart::setParity(options, uartCookie->getParity()); + serial::setParity(options, uartCookie->getParity()); setStopBitOptions(&options, uartCookie); setDatasizeOptions(&options, uartCookie); setFixedOptions(&options); - uart::setMode(options, uartCookie->getUartMode()); + serial::setMode(options, uartCookie->getUartMode()); if (uartCookie->getInputShouldBeFlushed()) { tcflush(fd, TCIFLUSH); } @@ -101,7 +101,7 @@ int SerialComIF::configureUartPort(SerialCookie* uartCookie) { options.c_cc[VTIME] = 0; options.c_cc[VMIN] = 0; - uart::setBaudrate(options, uartCookie->getBaudrate()); + serial::setBaudrate(options, uartCookie->getBaudrate()); /* Save option settings */ if (tcsetattr(fd, TCSANOW, &options) != 0) { diff --git a/src/fsfw_hal/linux/serial/helper.cpp b/src/fsfw_hal/linux/serial/helper.cpp index ba975f2f9..c58689c00 100644 --- a/src/fsfw_hal/linux/serial/helper.cpp +++ b/src/fsfw_hal/linux/serial/helper.cpp @@ -3,7 +3,7 @@ #include "fsfw/serviceinterface.h" -void uart::setMode(struct termios& options, UartModes mode) { +void serial::setMode(struct termios& options, UartModes mode) { if (mode == UartModes::NON_CANONICAL) { /* Disable canonical mode */ options.c_lflag &= ~ICANON; @@ -12,7 +12,7 @@ void uart::setMode(struct termios& options, UartModes mode) { } } -void uart::setBaudrate(struct termios& options, UartBaudRate baud) { +void serial::setBaudrate(struct termios& options, UartBaudRate baud) { switch (baud) { case UartBaudRate::RATE_50: cfsetspeed(&options, B50); @@ -114,7 +114,7 @@ void uart::setBaudrate(struct termios& options, UartBaudRate baud) { } } -void uart::setBitsPerWord(struct termios& options, BitsPerWord bits) { +void serial::setBitsPerWord(struct termios& options, BitsPerWord bits) { options.c_cflag &= ~CSIZE; // Clear all the size bits if (bits == BitsPerWord::BITS_5) { options.c_cflag |= CS5; @@ -127,11 +127,11 @@ void uart::setBitsPerWord(struct termios& options, BitsPerWord bits) { } } -void uart::enableRead(struct termios& options) { options.c_cflag |= CREAD; } +void serial::enableRead(struct termios& options) { options.c_cflag |= CREAD; } -void uart::ignoreCtrlLines(struct termios& options) { options.c_cflag |= CLOCAL; } +void serial::ignoreCtrlLines(struct termios& options) { options.c_cflag |= CLOCAL; } -void uart::setParity(struct termios& options, Parity parity) { +void serial::setParity(struct termios& options, Parity parity) { /* Clear parity bit */ options.c_cflag &= ~PARENB; switch (parity) { @@ -148,11 +148,11 @@ void uart::setParity(struct termios& options, Parity parity) { } } -int uart::readCountersAndErrors(int serialPort, serial_icounter_struct& icounter) { +int serial::readCountersAndErrors(int serialPort, serial_icounter_struct& icounter) { return ioctl(serialPort, TIOCGICOUNT, &icounter); } -void uart::setStopbits(struct termios& options, StopBits bits) { +void serial::setStopbits(struct termios& options, StopBits bits) { if (bits == StopBits::TWO_STOP_BITS) { // Use two stop bits options.c_cflag |= CSTOPB; @@ -161,3 +161,7 @@ void uart::setStopbits(struct termios& options, StopBits bits) { options.c_cflag &= ~CSTOPB; } } + +void serial::flushRxBuf(int fd) { tcflush(fd, TCIFLUSH); } + +void serial::flushTxRxBuf(int fd) { tcflush(fd, TCIOFLUSH); } diff --git a/src/fsfw_hal/linux/serial/helper.h b/src/fsfw_hal/linux/serial/helper.h index 7f067d001..623612ad3 100644 --- a/src/fsfw_hal/linux/serial/helper.h +++ b/src/fsfw_hal/linux/serial/helper.h @@ -45,7 +45,7 @@ enum class UartBaudRate { RATE_4000000 }; -namespace uart { +namespace serial { void setMode(struct termios& options, UartModes mode); /** @@ -64,8 +64,11 @@ void setParity(struct termios& options, Parity parity); void ignoreCtrlLines(struct termios& options); +void flushRxBuf(int fd); +void flushTxRxBuf(int fd); + int readCountersAndErrors(int serialPort, serial_icounter_struct& icounter); -} // namespace uart +} // namespace serial #endif /* FSFW_HAL_LINUX_UART_HELPER_H_ */ diff --git a/src/fsfw_hal/linux/spi/ManualCsLockGuard.h b/src/fsfw_hal/linux/spi/ManualCsLockGuard.h new file mode 100644 index 000000000..8456f9f13 --- /dev/null +++ b/src/fsfw_hal/linux/spi/ManualCsLockGuard.h @@ -0,0 +1,45 @@ +#pragma once + +#include + +#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; +}; diff --git a/src/fsfw_hal/linux/spi/SpiComIF.cpp b/src/fsfw_hal/linux/spi/SpiComIF.cpp index cc52b689d..f227c6852 100644 --- a/src/fsfw_hal/linux/spi/SpiComIF.cpp +++ b/src/fsfw_hal/linux/spi/SpiComIF.cpp @@ -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,35 +171,44 @@ 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; + return spi::OPENING_FILE_FAILED; } spi::SpiModes spiMode = spi::SpiModes::MODE_0; uint32_t spiSpeed = 0; spiCookie->getSpiParameters(spiMode, spiSpeed, nullptr); setSpiSpeedAndMode(fileDescriptor, spiMode, spiSpeed); - spiCookie->assignWriteBuffer(sendData); - spiCookie->setTransferSize(sendLen); bool fullDuplex = spiCookie->isFullDuplex(); gpioId_t gpioId = spiCookie->getChipSelectPin(); + bool csLockManual = spiCookie->getCsLockManual(); + spiCookie->setTransferSize(0); - /* 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; + if (result == MutexIF::MUTEX_TIMEOUT) { + sif::error << "SpiComIF::sendMessage: Lock timeout" << std::endl; + } else { + 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 @@ -219,17 +217,24 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const sif::printWarning("SpiComIF::sendMessage: Pulling low CS pin failed"); #endif #endif + csMutex->unlockMutex(); return result; } + } else { + updateLinePolarity(fileDescriptor); } + spiCookie->assignWriteBuffer(sendData); + spiCookie->setTransferSize(sendLen); + /* Execute transfer */ if (fullDuplex) { /* Initiate a full duplex SPI transfer. */ retval = ioctl(fileDescriptor, SPI_IOC_MESSAGE(1), spiCookie->getTransferStructHandle()); if (retval < 0) { + spiCookie->setTransferSize(0); utility::handleIoctlError("SpiComIF::sendMessage: ioctl error."); - result = FULL_DUPLEX_TRANSFER_FAILED; + result = spi::FULL_DUPLEX_TRANSFER_FAILED; } #if FSFW_HAL_SPI_WIRETAPPING == 1 performSpiWiretapping(spiCookie); @@ -237,6 +242,7 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const } else { /* We write with a blocking half-duplex transfer here */ if (write(fileDescriptor, sendData, sendLen) != static_cast(sendLen)) { + spiCookie->setTransferSize(0); #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "SpiComIF::sendMessage: Half-Duplex write operation failed!" << std::endl; @@ -244,13 +250,13 @@ ReturnValue_t SpiComIF::performRegularSendOperation(SpiCookie* spiCookie, const sif::printWarning("SpiComIF::sendMessage: Half-Duplex write operation failed!\n"); #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FSFW_VERBOSE_LEVEL >= 1 */ - result = HALF_DUPLEX_TRANSFER_FAILED; + result = spi::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::sendMessage: Failed to unlock mutex" << std::endl; @@ -278,11 +284,10 @@ 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; + return spi::OPENING_FILE_FAILED; } uint8_t* rxBuf = nullptr; @@ -292,16 +297,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(readSize)) { @@ -312,12 +327,12 @@ ReturnValue_t SpiComIF::performHalfDuplexReception(SpiCookie* spiCookie) { sif::printWarning("SpiComIF::sendMessage: Half-Duplex read operation failed!\n"); #endif /* FSFW_CPP_OSTREAM_ENABLED == 1 */ #endif /* FSFW_VERBOSE_LEVEL >= 1 */ - result = HALF_DUPLEX_TRANSFER_FAILED; + result = spi::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 +361,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 +396,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(&mode)); @@ -401,11 +408,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(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"); } diff --git a/src/fsfw_hal/linux/spi/SpiComIF.h b/src/fsfw_hal/linux/spi/SpiComIF.h index 11defdceb..3b72a59d8 100644 --- a/src/fsfw_hal/linux/spi/SpiComIF.h +++ b/src/fsfw_hal/linux/spi/SpiComIF.h @@ -22,16 +22,7 @@ class SpiCookie; */ class SpiComIF : public DeviceCommunicationIF, public SystemObject { public: - static constexpr uint8_t spiRetvalId = CLASS_ID::HAL_SPI; - static constexpr ReturnValue_t OPENING_FILE_FAILED = returnvalue::makeCode(spiRetvalId, 0); - /* Full duplex (ioctl) transfer failure */ - static constexpr ReturnValue_t FULL_DUPLEX_TRANSFER_FAILED = - returnvalue::makeCode(spiRetvalId, 1); - /* Half duplex (read/write) transfer failure */ - 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 +34,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 +48,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 +74,13 @@ class SpiComIF : public DeviceCommunicationIF, public SystemObject { std::vector 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; spi_ioc_transfer clockUpdateTransfer = {}; using SpiDeviceMap = std::unordered_map; diff --git a/src/fsfw_hal/linux/spi/SpiCookie.cpp b/src/fsfw_hal/linux/spi/SpiCookie.cpp index c94fcdf1b..e61703e6e 100644 --- a/src/fsfw_hal/linux/spi/SpiCookie.cpp +++ b/src/fsfw_hal/linux/spi/SpiCookie.cpp @@ -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; +} diff --git a/src/fsfw_hal/linux/spi/SpiCookie.h b/src/fsfw_hal/linux/spi/SpiCookie.h index 5f4bf2d53..2104e2eb9 100644 --- a/src/fsfw_hal/linux/spi/SpiCookie.h +++ b/src/fsfw_hal/linux/spi/SpiCookie.h @@ -2,6 +2,8 @@ #define LINUX_SPI_SPICOOKIE_H_ #include +#include +#include #include #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_ */ diff --git a/src/fsfw_hal/linux/uio/UioMapper.cpp b/src/fsfw_hal/linux/uio/UioMapper.cpp index 33e4fd97a..c6da54885 100644 --- a/src/fsfw_hal/linux/uio/UioMapper.cpp +++ b/src/fsfw_hal/linux/uio/UioMapper.cpp @@ -36,7 +36,7 @@ UioMapper::~UioMapper() {} ReturnValue_t UioMapper::getMappedAdress(uint32_t** address, Permissions permissions) { ReturnValue_t result = returnvalue::OK; - int fd = open(uioFile.c_str(), O_RDWR); + int fd = open(uioFile.c_str(), O_RDWR | O_SYNC); if (fd < 1) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "UioMapper::getMappedAdress: Invalid UIO device file " << uioFile << std::endl; diff --git a/src/fsfw_hal/stm32h7/spi/SpiComIF.cpp b/src/fsfw_hal/stm32h7/spi/SpiComIF.cpp index 724917bd2..4d688bd59 100644 --- a/src/fsfw_hal/stm32h7/spi/SpiComIF.cpp +++ b/src/fsfw_hal/stm32h7/spi/SpiComIF.cpp @@ -357,13 +357,13 @@ ReturnValue_t SpiComIF::halErrorHandler(HAL_StatusTypeDef status, spi::TransferM sif::printWarning("SpiComIF::handle%sSendOperation: HAL error %d occured\n", modeString, status); switch (status) { case (HAL_BUSY): { - return spi::HAL_BUSY_RETVAL; + return spi::BUSY; } case (HAL_ERROR): { - return spi::HAL_ERROR_RETVAL; + return spi::GENERIC_ERROR; } case (HAL_TIMEOUT): { - return spi::HAL_TIMEOUT_RETVAL; + return spi::TIMEOUT; } default: { return returnvalue::FAILED; diff --git a/src/fsfw_tests/integration/assemblies/TestAssembly.cpp b/src/fsfw_tests/integration/assemblies/TestAssembly.cpp index 668120c6f..761d0d3cf 100644 --- a/src/fsfw_tests/integration/assemblies/TestAssembly.cpp +++ b/src/fsfw_tests/integration/assemblies/TestAssembly.cpp @@ -2,19 +2,17 @@ #include -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(deviceHandler0Id); - handler1 = ObjectManager::instance()->get(deviceHandler1Id); + auto* handler0 = ObjectManager::instance()->get(deviceHandler0.getObjectId()); + auto* handler1 = ObjectManager::instance()->get(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; } diff --git a/src/fsfw_tests/integration/assemblies/TestAssembly.h b/src/fsfw_tests/integration/assemblies/TestAssembly.h index 91ffbf607..86b4fb070 100644 --- a/src/fsfw_tests/integration/assemblies/TestAssembly.h +++ b/src/fsfw_tests/integration/assemblies/TestAssembly.h @@ -7,8 +7,8 @@ class TestAssembly : public AssemblyBase { public: - TestAssembly(object_id_t objectId, object_id_t parentId, object_id_t testDevice0, - object_id_t testDevice1); + TestAssembly(object_id_t objectId, object_id_t parentId, ModeTreeChildIF& testDevice0, + ModeTreeChildIF& testDevice1); virtual ~TestAssembly(); ReturnValue_t initialize() override; @@ -41,10 +41,8 @@ class TestAssembly : public AssemblyBase { private: FixedArrayList commandTable; - object_id_t deviceHandler0Id = 0; - object_id_t deviceHandler1Id = 0; - TestDevice* handler0 = nullptr; - TestDevice* handler1 = nullptr; + ModeTreeChildIF& deviceHandler0; + ModeTreeChildIF& deviceHandler1; bool isDeviceAvailable(object_id_t object); }; diff --git a/src/fsfw_tests/integration/controller/TestController.cpp b/src/fsfw_tests/integration/controller/TestController.cpp index 2ee4d5fe0..c489f336e 100644 --- a/src/fsfw_tests/integration/controller/TestController.cpp +++ b/src/fsfw_tests/integration/controller/TestController.cpp @@ -4,8 +4,8 @@ #include #include -TestController::TestController(object_id_t objectId, object_id_t parentId, size_t commandQueueDepth) - : ExtendedControllerBase(objectId, parentId, commandQueueDepth) {} +TestController::TestController(object_id_t objectId, size_t commandQueueDepth) + : ExtendedControllerBase(objectId, commandQueueDepth) {} TestController::~TestController() {} diff --git a/src/fsfw_tests/integration/controller/TestController.h b/src/fsfw_tests/integration/controller/TestController.h index 9898371f5..9577bedf1 100644 --- a/src/fsfw_tests/integration/controller/TestController.h +++ b/src/fsfw_tests/integration/controller/TestController.h @@ -7,7 +7,7 @@ class TestController : public ExtendedControllerBase { public: - TestController(object_id_t objectId, object_id_t parentId, size_t commandQueueDepth = 10); + TestController(object_id_t objectId, size_t commandQueueDepth = 10); virtual ~TestController(); protected: diff --git a/src/fsfw_tests/integration/devices/TestDeviceHandler.cpp b/src/fsfw_tests/integration/devices/TestDeviceHandler.cpp index fdf02a707..b6a6f4652 100644 --- a/src/fsfw_tests/integration/devices/TestDeviceHandler.cpp +++ b/src/fsfw_tests/integration/devices/TestDeviceHandler.cpp @@ -65,7 +65,7 @@ ReturnValue_t TestDevice::buildNormalDeviceCommand(DeviceCommandId_t* id) { } ReturnValue_t TestDevice::buildTransitionDeviceCommand(DeviceCommandId_t* id) { - if (mode == _MODE_TO_ON) { + if (getMode() == _MODE_TO_ON) { if (fullInfoPrintout) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "TestDevice" << deviceIdx @@ -80,7 +80,7 @@ ReturnValue_t TestDevice::buildTransitionDeviceCommand(DeviceCommandId_t* id) { #endif } } - if (mode == _MODE_TO_NORMAL) { + if (getMode() == _MODE_TO_NORMAL) { if (fullInfoPrintout) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "TestDevice" << deviceIdx @@ -97,7 +97,7 @@ ReturnValue_t TestDevice::buildTransitionDeviceCommand(DeviceCommandId_t* id) { setMode(MODE_NORMAL); } - if (mode == _MODE_SHUT_DOWN) { + if (getMode() == _MODE_SHUT_DOWN) { if (fullInfoPrintout) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "TestDevice" << deviceIdx @@ -118,7 +118,7 @@ ReturnValue_t TestDevice::buildTransitionDeviceCommand(DeviceCommandId_t* id) { } void TestDevice::doTransition(Mode_t modeFrom, Submode_t submodeFrom) { - if (mode == _MODE_TO_NORMAL) { + if (getMode() == _MODE_TO_NORMAL) { if (fullInfoPrintout) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::info << "TestDevice" << deviceIdx diff --git a/unittests/CMakeLists.txt b/unittests/CMakeLists.txt index ad26e3923..950b96b89 100644 --- a/unittests/CMakeLists.txt +++ b/unittests/CMakeLists.txt @@ -13,6 +13,7 @@ add_subdirectory(util) add_subdirectory(container) add_subdirectory(osal) add_subdirectory(pus) +add_subdirectory(subsystem) add_subdirectory(serialize) add_subdirectory(datapoollocal) add_subdirectory(storagemanager) diff --git a/unittests/CatchFactory.cpp b/unittests/CatchFactory.cpp index 0d855cb3f..589e6887b 100644 --- a/unittests/CatchFactory.cpp +++ b/unittests/CatchFactory.cpp @@ -30,9 +30,9 @@ */ void Factory::produceFrameworkObjects(void* args) { setStaticFrameworkObjectIds(); - new EventManager(objects::EVENT_MANAGER); + new EventManager(objects::EVENT_MANAGER, 120); new HealthTable(objects::HEALTH_TABLE); - new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER); + new InternalErrorReporter(objects::INTERNAL_ERROR_REPORTER, 20, false, 1.0); { PoolManager::LocalPoolConfig poolCfg = {{100, 16}, {50, 32}, {25, 64}, {15, 128}, {5, 1024}}; diff --git a/unittests/action/TestActionHelper.cpp b/unittests/action/TestActionHelper.cpp index d99700d7a..de021bb83 100644 --- a/unittests/action/TestActionHelper.cpp +++ b/unittests/action/TestActionHelper.cpp @@ -27,12 +27,7 @@ TEST_CASE("Action Helper", "[action]") { CHECK(not testDhMock.executeActionCalled); REQUIRE(actionHelper.handleActionMessage(&actionMessage) == returnvalue::OK); CHECK(testDhMock.executeActionCalled); - // No message is sent if everything is alright. CHECK(not testMqMock.wasMessageSent()); - store_address_t invalidAddress; - ActionMessage::setCommand(&actionMessage, testActionId, invalidAddress); - actionHelper.handleActionMessage(&actionMessage); - CHECK(testMqMock.wasMessageSent()); const uint8_t* ptr = nullptr; size_t size = 0; REQUIRE(ipcStore->getData(paramAddress, &ptr, &size) == @@ -44,6 +39,10 @@ TEST_CASE("Action Helper", "[action]") { for (uint8_t i = 0; i < 3; i++) { REQUIRE(ptr[i] == (i + 1)); } + // Action message without application data is also valid + store_address_t invalidAddress; + ActionMessage::setCommand(&actionMessage, testActionId, invalidAddress); + actionHelper.handleActionMessage(&actionMessage); testDhMock.clearBuffer(); } @@ -95,17 +94,5 @@ TEST_CASE("Action Helper", "[action]") { REQUIRE(ActionMessage::getActionId(&testMessage) == testActionId); } - SECTION("Missing IPC Data") { - ActionMessage::setCommand(&actionMessage, testActionId, store_address_t::invalid()); - CHECK(not testDhMock.executeActionCalled); - REQUIRE(actionHelper.handleActionMessage(&actionMessage) == returnvalue::OK); - CommandMessage testMessage; - REQUIRE(testMqMock.getNextSentMessage(testMessage) == returnvalue::OK); - REQUIRE(testMessage.getCommand() == static_cast(ActionMessage::STEP_FAILED)); - REQUIRE(ActionMessage::getReturnCode(&testMessage) == - static_cast(StorageManagerIF::ILLEGAL_STORAGE_ID)); - REQUIRE(ActionMessage::getStep(&testMessage) == 0); - } - SECTION("Data Reply") {} } diff --git a/unittests/cfdp/handler/CMakeLists.txt b/unittests/cfdp/handler/CMakeLists.txt index 0993a3981..f70e5dfb6 100644 --- a/unittests/cfdp/handler/CMakeLists.txt +++ b/unittests/cfdp/handler/CMakeLists.txt @@ -1,2 +1,3 @@ -target_sources(${FSFW_TEST_TGT} PRIVATE testDistributor.cpp - testFaultHandler.cpp) +target_sources( + ${FSFW_TEST_TGT} PRIVATE testDistributor.cpp testDestHandler.cpp + testSourceHandler.cpp testFaultHandler.cpp) diff --git a/unittests/cfdp/handler/testDestHandler.cpp b/unittests/cfdp/handler/testDestHandler.cpp new file mode 100644 index 000000000..0224a20bc --- /dev/null +++ b/unittests/cfdp/handler/testDestHandler.cpp @@ -0,0 +1,244 @@ +#include + +#include +#include +#include + +#include "fsfw/cfdp.h" +#include "fsfw/cfdp/pdu/EofPduCreator.h" +#include "fsfw/cfdp/pdu/FileDataCreator.h" +#include "fsfw/cfdp/pdu/MetadataPduCreator.h" +#include "mocks/AcceptsTmMock.h" +#include "mocks/EventReportingProxyMock.h" +#include "mocks/FilesystemMock.h" +#include "mocks/MessageQueueMock.h" +#include "mocks/StorageManagerMock.h" +#include "mocks/cfdp/FaultHandlerMock.h" +#include "mocks/cfdp/RemoteConfigTableMock.h" +#include "mocks/cfdp/UserMock.h" + +TEST_CASE("CFDP Dest Handler", "[cfdp]") { + using namespace cfdp; + using namespace returnvalue; + MessageQueueId_t destQueueId = 2; + AcceptsTmMock tmReceiver(destQueueId); + MessageQueueMock mqMock(destQueueId); + EntityId localId = EntityId(UnsignedByteField(2)); + EntityId remoteId = EntityId(UnsignedByteField(3)); + FaultHandlerMock fhMock; + LocalEntityCfg localEntityCfg(localId, IndicationCfg(), fhMock); + FilesystemMock fsMock; + UserMock userMock(fsMock); + RemoteConfigTableMock remoteCfgTableMock; + PacketInfoList<64> packetInfoList; + LostSegmentsList<128> lostSegmentsList; + DestHandlerParams dp(localEntityCfg, userMock, remoteCfgTableMock, packetInfoList, + lostSegmentsList); + EventReportingProxyMock eventReporterMock; + LocalPool::LocalPoolConfig storeCfg = {{10, 32}, {10, 64}, {10, 128}, {10, 1024}}; + StorageManagerMock tcStore(2, storeCfg); + StorageManagerMock tmStore(3, storeCfg); + FsfwParams fp(tmReceiver, &mqMock, &eventReporterMock); + RemoteEntityCfg cfg(remoteId); + remoteCfgTableMock.addRemoteConfig(cfg); + fp.tcStore = &tcStore; + fp.tmStore = &tmStore; + uint8_t* buf = nullptr; + size_t serLen = 0; + store_address_t storeId; + PduConfig conf; + auto destHandler = DestHandler(dp, fp); + CHECK(destHandler.initialize() == OK); + + auto metadataPreparation = [&](FileSize cfdpFileSize, ChecksumType checksumType) { + std::string srcNameString = "hello.txt"; + std::string destNameString = "hello-cpy.txt"; + StringLv srcName(srcNameString); + StringLv destName(destNameString); + MetadataInfo info(false, checksumType, cfdpFileSize, srcName, destName); + TransactionSeqNum seqNum(UnsignedByteField(1)); + conf.sourceId = remoteId; + conf.destId = localId; + conf.mode = TransmissionMode::UNACKNOWLEDGED; + conf.seqNum = seqNum; + MetadataPduCreator metadataCreator(conf, info); + REQUIRE(tcStore.getFreeElement(&storeId, metadataCreator.getSerializedSize(), &buf) == OK); + REQUIRE(metadataCreator.serialize(buf, serLen, metadataCreator.getSerializedSize()) == OK); + PacketInfo packetInfo(metadataCreator.getPduType(), storeId, + metadataCreator.getDirectiveCode()); + packetInfoList.push_back(packetInfo); + }; + + auto metadataCheck = [&](const cfdp::DestHandler::FsmResult& res, const char* sourceName, + const char* destName, size_t fileLen) { + REQUIRE(res.result == OK); + REQUIRE(res.callStatus == CallStatus::CALL_AGAIN); + REQUIRE(res.errors == 0); + // Assert that the packet was deleted after handling + REQUIRE(not tcStore.hasDataAtId(storeId)); + REQUIRE(packetInfoList.empty()); + REQUIRE(userMock.metadataRecvd.size() == 1); + auto& idMetadataPair = userMock.metadataRecvd.back(); + REQUIRE(idMetadataPair.first == destHandler.getTransactionId()); + REQUIRE(idMetadataPair.second.sourceId.getValue() == 3); + REQUIRE(idMetadataPair.second.fileSize == fileLen); + REQUIRE(strcmp(idMetadataPair.second.destFileName, destName) == 0); + REQUIRE(strcmp(idMetadataPair.second.sourceFileName, sourceName) == 0); + userMock.metadataRecvd.pop(); + REQUIRE(fsMock.fileMap.find(destName) != fsMock.fileMap.end()); + REQUIRE(res.result == OK); + REQUIRE(res.state == CfdpStates::BUSY_CLASS_1_NACKED); + REQUIRE(res.step == DestHandler::TransactionStep::RECEIVING_FILE_DATA_PDUS); + }; + + auto eofPreparation = [&](FileSize cfdpFileSize, uint32_t crc) { + EofInfo eofInfo(cfdp::ConditionCode::NO_ERROR, crc, std::move(cfdpFileSize)); + EofPduCreator eofCreator(conf, eofInfo); + REQUIRE(tcStore.getFreeElement(&storeId, eofCreator.getSerializedSize(), &buf) == OK); + REQUIRE(eofCreator.serialize(buf, serLen, eofCreator.getSerializedSize()) == OK); + PacketInfo packetInfo(eofCreator.getPduType(), storeId, eofCreator.getDirectiveCode()); + packetInfoList.push_back(packetInfo); + }; + + auto eofCheck = [&](const cfdp::DestHandler::FsmResult& res, const TransactionId& id) { + REQUIRE(res.result == OK); + REQUIRE(res.state == CfdpStates::IDLE); + REQUIRE(res.errors == 0); + REQUIRE(res.step == DestHandler::TransactionStep::IDLE); + // Assert that the packet was deleted after handling + REQUIRE(not tcStore.hasDataAtId(storeId)); + REQUIRE(packetInfoList.empty()); + REQUIRE(userMock.eofsRevd.size() == 1); + auto& eofId = userMock.eofsRevd.back(); + CHECK(eofId == id); + REQUIRE(userMock.finishedRecvd.size() == 1); + auto& idParamPair = userMock.finishedRecvd.back(); + CHECK(idParamPair.first == id); + CHECK(idParamPair.second.condCode == ConditionCode::NO_ERROR); + }; + + auto fileDataPduCheck = [&](const cfdp::DestHandler::FsmResult& res, + const std::vector& idsToCheck) { + REQUIRE(res.result == OK); + REQUIRE(res.state == CfdpStates::BUSY_CLASS_1_NACKED); + REQUIRE(res.step == DestHandler::TransactionStep::RECEIVING_FILE_DATA_PDUS); + for (const auto id : idsToCheck) { + REQUIRE(not tcStore.hasDataAtId(id)); + } + REQUIRE(packetInfoList.empty()); + }; + + SECTION("State") { + CHECK(destHandler.getCfdpState() == CfdpStates::IDLE); + CHECK(destHandler.getTransactionStep() == DestHandler::TransactionStep::IDLE); + } + + SECTION("Idle State Machine Iteration") { + auto res = destHandler.performStateMachine(); + CHECK(res.result == OK); + CHECK(res.callStatus == CallStatus::CALL_AFTER_DELAY); + CHECK(res.errors == 0); + CHECK(destHandler.getCfdpState() == CfdpStates::IDLE); + CHECK(destHandler.getTransactionStep() == DestHandler::TransactionStep::IDLE); + } + + SECTION("Empty File Transfer") { + const DestHandler::FsmResult& res = destHandler.performStateMachine(); + CHECK(res.result == OK); + FileSize cfdpFileSize(0); + metadataPreparation(cfdpFileSize, ChecksumType::NULL_CHECKSUM); + destHandler.performStateMachine(); + metadataCheck(res, "hello.txt", "hello-cpy.txt", 0); + destHandler.performStateMachine(); + REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY); + auto transactionId = destHandler.getTransactionId(); + eofPreparation(cfdpFileSize, 0); + // After EOF, operation is done because no closure was requested + destHandler.performStateMachine(); + eofCheck(res, transactionId); + } + + SECTION("Small File Transfer") { + const DestHandler::FsmResult& res = destHandler.performStateMachine(); + CHECK(res.result == OK); + std::string fileData = "hello test data"; + etl::crc32 crcCalc; + crcCalc.add(fileData.begin(), fileData.end()); + uint32_t crc32 = crcCalc.value(); + FileSize cfdpFileSize(fileData.size()); + metadataPreparation(cfdpFileSize, ChecksumType::CRC_32); + destHandler.performStateMachine(); + metadataCheck(res, "hello.txt", "hello-cpy.txt", fileData.size()); + destHandler.performStateMachine(); + REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY); + auto transactionId = destHandler.getTransactionId(); + FileSize offset(0); + FileDataInfo fdPduInfo(offset, reinterpret_cast(fileData.data()), + fileData.size()); + FileDataCreator fdPduCreator(conf, fdPduInfo); + REQUIRE(tcStore.getFreeElement(&storeId, fdPduCreator.getSerializedSize(), &buf) == OK); + REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK); + PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt); + packetInfoList.push_back(packetInfo); + destHandler.performStateMachine(); + fileDataPduCheck(res, {storeId}); + eofPreparation(cfdpFileSize, crc32); + // After EOF, operation is done because no closure was requested + destHandler.performStateMachine(); + eofCheck(res, transactionId); + } + + SECTION("Segmented File Transfer") { + const DestHandler::FsmResult& res = destHandler.performStateMachine(); + CHECK(res.result == OK); + std::random_device dev; + std::mt19937 rng(dev()); + std::uniform_int_distribution distU8(0, 255); + std::array largerFileData{}; + for (auto& val : largerFileData) { + val = distU8(rng); + } + etl::crc32 crcCalc; + crcCalc.add(largerFileData.begin(), largerFileData.end()); + uint32_t crc32 = crcCalc.value(); + FileSize cfdpFileSize(largerFileData.size()); + metadataPreparation(cfdpFileSize, ChecksumType::CRC_32); + destHandler.performStateMachine(); + metadataCheck(res, "hello.txt", "hello-cpy.txt", largerFileData.size()); + destHandler.performStateMachine(); + REQUIRE(res.callStatus == CallStatus::CALL_AFTER_DELAY); + auto transactionId = destHandler.getTransactionId(); + + std::vector idsToCheck; + { + FileSize offset(0); + FileDataInfo fdPduInfo(offset, reinterpret_cast(largerFileData.data()), + largerFileData.size() / 2); + FileDataCreator fdPduCreator(conf, fdPduInfo); + REQUIRE(tcStore.getFreeElement(&storeId, fdPduCreator.getSerializedSize(), &buf) == OK); + REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK); + PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt); + idsToCheck.push_back(storeId); + packetInfoList.push_back(packetInfo); + } + + { + FileSize offset(512); + FileDataInfo fdPduInfo(offset, reinterpret_cast(largerFileData.data() + 512), + largerFileData.size() / 2); + FileDataCreator fdPduCreator(conf, fdPduInfo); + REQUIRE(tcStore.getFreeElement(&storeId, fdPduCreator.getSerializedSize(), &buf) == OK); + REQUIRE(fdPduCreator.serialize(buf, serLen, fdPduCreator.getSerializedSize()) == OK); + PacketInfo packetInfo(fdPduCreator.getPduType(), storeId, std::nullopt); + idsToCheck.push_back(storeId); + packetInfoList.push_back(packetInfo); + } + + destHandler.performStateMachine(); + fileDataPduCheck(res, idsToCheck); + eofPreparation(cfdpFileSize, crc32); + // After EOF, operation is done because no closure was requested + destHandler.performStateMachine(); + eofCheck(res, transactionId); + } +} \ No newline at end of file diff --git a/unittests/cfdp/handler/testSourceHandler.cpp b/unittests/cfdp/handler/testSourceHandler.cpp new file mode 100644 index 000000000..570ecb085 --- /dev/null +++ b/unittests/cfdp/handler/testSourceHandler.cpp @@ -0,0 +1,3 @@ +#include + +TEST_CASE("CFDP Source Handler", "[cfdp]") {} \ No newline at end of file diff --git a/unittests/cfdp/pdu/testCfdpHeader.cpp b/unittests/cfdp/pdu/testCfdpHeader.cpp index 5f81bec9f..1fc7dfd47 100644 --- a/unittests/cfdp/pdu/testCfdpHeader.cpp +++ b/unittests/cfdp/pdu/testCfdpHeader.cpp @@ -97,7 +97,7 @@ TEST_CASE("CFDP Header", "[cfdp]") { REQUIRE(creator.serialize(&serTarget, &serSize, serBuf.size(), SerializeIF::Endianness::BIG) == returnvalue::OK); CHECK(serBuf[0] == 0x3f); - CHECK(serBuf[3] == 0x99); + CHECK(serBuf[3] == 0x88); REQUIRE(creator.getCrcFlag() == true); REQUIRE(creator.getDirection() == cfdp::Direction::TOWARDS_SENDER); REQUIRE(creator.getLargeFileFlag() == true); @@ -127,7 +127,7 @@ TEST_CASE("CFDP Header", "[cfdp]") { REQUIRE(creator.getTransmissionMode() == cfdp::TransmissionMode::UNACKNOWLEDGED); REQUIRE(creator.getSegmentationControl() == true); // Last three bits are 2 now (length of seq number) and bit 1 to bit 3 is 4 (len entity IDs) - REQUIRE(serBuf[3] == 0b11001010); + REQUIRE(serBuf[3] == 0b10111001); uint32_t entityId = 0; size_t deSerSize = 0; SerializeAdapter::deSerialize(&entityId, serBuf.data() + 4, &deSerSize, @@ -175,7 +175,7 @@ TEST_CASE("CFDP Header", "[cfdp]") { REQUIRE(serBuf[1] == 0); REQUIRE(serBuf[2] == 0); // Entity and Transaction Sequence number are 1 byte large - REQUIRE(serBuf[3] == 0b00010001); + REQUIRE(serBuf[3] == 0b00000000); // Source ID REQUIRE(serBuf[4] == 0); // Transaction Seq Number @@ -220,7 +220,7 @@ TEST_CASE("CFDP Header", "[cfdp]") { REQUIRE(serBuf[1] == 0); REQUIRE(serBuf[2] == 0); // Entity and Transaction Sequence number are 1 byte large - REQUIRE(serBuf[3] == 0b00010001); + REQUIRE(serBuf[3] == 0b00000000); REQUIRE(serSize == 7); // Deser call not strictly necessary auto reader = PduHeaderReader(serBuf.data(), serBuf.size()); @@ -270,7 +270,7 @@ TEST_CASE("CFDP Header", "[cfdp]") { REQUIRE(reader.parseData() == returnvalue::OK); // Everything except version bit flipped to one now REQUIRE(serBuf[0] == 0x3f); - REQUIRE(serBuf[3] == 0b11001010); + REQUIRE(serBuf[3] == 0b10111001); REQUIRE(reader.getWholePduSize() == 14); REQUIRE(reader.getCrcFlag() == true); diff --git a/unittests/cfdp/pdu/testFileData.cpp b/unittests/cfdp/pdu/testFileData.cpp index 258ef9c13..391393780 100644 --- a/unittests/cfdp/pdu/testFileData.cpp +++ b/unittests/cfdp/pdu/testFileData.cpp @@ -68,7 +68,7 @@ TEST_CASE("File Data PDU", "[cfdp][pdu]") { // Bits 1 to 3 length of enitity IDs is 2 // Bit 4: Segment metadata flag is set // Bit 5 to seven: length of transaction seq num is 2 - REQUIRE(fileDataBuffer[3] == 0b10101010); + REQUIRE(fileDataBuffer[3] == 0b10011001); REQUIRE((fileDataBuffer[10] >> 6) & 0b11 == cfdp::RecordContinuationState::CONTAINS_START_AND_END); // Segment metadata length diff --git a/unittests/cfdp/pdu/testFileDirective.cpp b/unittests/cfdp/pdu/testFileDirective.cpp index e1158a1a7..17e0d6996 100644 --- a/unittests/cfdp/pdu/testFileDirective.cpp +++ b/unittests/cfdp/pdu/testFileDirective.cpp @@ -30,7 +30,7 @@ TEST_CASE("CFDP File Directive", "[cfdp][pdu]") { REQUIRE(serBuf[1] == 0); REQUIRE(serBuf[2] == 5); // Entity and Transaction Sequence number are 1 byte large - REQUIRE(serBuf[3] == 0b00010001); + REQUIRE(serBuf[3] == 0b00000000); // Source ID REQUIRE(serBuf[4] == 0); // Transaction Seq Number @@ -82,4 +82,4 @@ TEST_CASE("CFDP File Directive", "[cfdp][pdu]") { // Invalid file directive REQUIRE(fdDeser.parseData() == cfdp::INVALID_DIRECTIVE_FIELD); } -} \ No newline at end of file +} diff --git a/unittests/cfdp/testCfdp.cpp b/unittests/cfdp/testCfdp.cpp index eacc83dee..467b5b2d4 100644 --- a/unittests/cfdp/testCfdp.cpp +++ b/unittests/cfdp/testCfdp.cpp @@ -33,8 +33,8 @@ TEST_CASE("CFDP Base", "[cfdp]") { // PDU data field length is 5 (4 + Directive code octet) REQUIRE(serBuf[1] == 0); REQUIRE(serBuf[2] == 5); - // Entity and Transaction Sequence number are 1 byte large - REQUIRE(serBuf[3] == 0b00010001); + // Entity and Transaction Sequence number are 1 byte large, value minus one is stored + REQUIRE(serBuf[3] == 0b00000000); // Source ID REQUIRE(serBuf[4] == 0); // Transaction Seq Number diff --git a/unittests/datapoollocal/testDataSet.cpp b/unittests/datapoollocal/testDataSet.cpp index def92ac34..8bc0abb7f 100644 --- a/unittests/datapoollocal/testDataSet.cpp +++ b/unittests/datapoollocal/testDataSet.cpp @@ -269,7 +269,7 @@ TEST_CASE("DataSetTest", "[DataSetTest]") { { // PoolReadGuard rg(&sharedSet); - // CHECK(rg.getReadResult() == result::OK); + // CHECK(rg.getReadResult() == returnvalue::OK); localSet.localPoolVarUint8.value = 5; localSet.localPoolUint16Vec.value[0] = 1; localSet.localPoolUint16Vec.value[1] = 2; diff --git a/unittests/datapoollocal/testLocalPoolManager.cpp b/unittests/datapoollocal/testLocalPoolManager.cpp index 91cd011df..e463a123f 100644 --- a/unittests/datapoollocal/testLocalPoolManager.cpp +++ b/unittests/datapoollocal/testLocalPoolManager.cpp @@ -9,6 +9,7 @@ #include #include +#include #include #include "CatchDefinitions.h" @@ -309,9 +310,7 @@ TEST_CASE("Local Pool Manager Tests", "[LocManTest]") { HousekeepingMessage::setCollectionIntervalModificationCommand(&hkCmd, lpool::testSid, 0.4, false); CHECK(poolOwner.poolManager.handleHousekeepingMessage(&hkCmd) == returnvalue::OK); - /* For non-diagnostics and a specified minimum frequency of 0.2 seconds, the - resulting collection interval should be 1.0 second */ - CHECK(poolOwner.dataset.getCollectionInterval() == 1.0); + CHECK_THAT(poolOwner.dataset.getCollectionInterval(), Catch::Matchers::WithinAbs(0.4, 0.01)); REQUIRE(poolOwnerMock.wasMessageSent()); REQUIRE(poolOwnerMock.numberOfSentMessages() == 1); CHECK(poolOwnerMock.clearLastSentMessage() == returnvalue::OK); @@ -348,14 +347,6 @@ TEST_CASE("Local Pool Manager Tests", "[LocManTest]") { REQUIRE(poolOwnerMock.numberOfSentMessages() == 1); CHECK(poolOwnerMock.clearLastSentMessage() == returnvalue::OK); - HousekeepingMessage::setCollectionIntervalModificationCommand(&hkCmd, lpool::testSid, 0.4, - false); - CHECK(poolOwner.poolManager.handleHousekeepingMessage(&hkCmd) == - static_cast(LocalDataPoolManager::WRONG_HK_PACKET_TYPE)); - REQUIRE(poolOwnerMock.wasMessageSent()); - REQUIRE(poolOwnerMock.numberOfSentMessages() == 1); - CHECK(poolOwnerMock.clearLastSentMessage() == returnvalue::OK); - HousekeepingMessage::setStructureReportingCommand(&hkCmd, lpool::testSid, false); CHECK(poolOwner.poolManager.handleHousekeepingMessage(&hkCmd) == static_cast(LocalDataPoolManager::WRONG_HK_PACKET_TYPE)); diff --git a/unittests/hal/testCommandExecutor.cpp b/unittests/hal/testCommandExecutor.cpp index 89011922b..f66da7a9a 100644 --- a/unittests/hal/testCommandExecutor.cpp +++ b/unittests/hal/testCommandExecutor.cpp @@ -78,7 +78,7 @@ TEST_CASE("Command Executor", "[hal][linux]") { REQUIRE(result != CommandExecutor::COMMAND_ERROR); // This ensures that the tests do not block indefinitely usleep(500); - REQUIRE(limitIdx < 500); + REQUIRE(limitIdx < 50000); } limitIdx = 0; CHECK(bytesHaveBeenRead == true); diff --git a/unittests/mocks/DeviceHandlerMock.cpp b/unittests/mocks/DeviceHandlerMock.cpp index ef0a23d8a..3ad80048f 100644 --- a/unittests/mocks/DeviceHandlerMock.cpp +++ b/unittests/mocks/DeviceHandlerMock.cpp @@ -5,7 +5,7 @@ DeviceHandlerMock::DeviceHandlerMock(object_id_t objectId, object_id_t deviceCommunication, CookieIF *comCookie, FailureIsolationBase *fdirInstance) : DeviceHandlerBase(objectId, deviceCommunication, comCookie, fdirInstance) { - mode = MODE_ON; + setMode(MODE_ON); } DeviceHandlerMock::~DeviceHandlerMock() = default; diff --git a/unittests/mocks/FilesystemMock.cpp b/unittests/mocks/FilesystemMock.cpp index bf0c3bf67..248502279 100644 --- a/unittests/mocks/FilesystemMock.cpp +++ b/unittests/mocks/FilesystemMock.cpp @@ -138,3 +138,10 @@ ReturnValue_t FilesystemMock::truncateFile(FilesystemParams params) { truncateCalledOnFile = params.path; return returnvalue::OK; } + +ReturnValue_t FilesystemMock::getBaseFilename(FilesystemParams params, char *nameBuf, size_t maxLen, + size_t &baseNameLen) { + return returnvalue::OK; +} + +bool FilesystemMock::isDirectory(const char *path) { return false; } diff --git a/unittests/mocks/FilesystemMock.h b/unittests/mocks/FilesystemMock.h index 74221d708..2ddbefc36 100644 --- a/unittests/mocks/FilesystemMock.h +++ b/unittests/mocks/FilesystemMock.h @@ -56,6 +56,10 @@ class FilesystemMock : public HasFileSystemIF { std::string truncateCalledOnFile; ReturnValue_t feedFile(const std::string &filename, std::ifstream &file); + ReturnValue_t getBaseFilename(FilesystemParams params, char *nameBuf, size_t maxLen, + size_t &baseNameLen) override; + + bool isDirectory(const char *path) override; bool fileExists(FilesystemParams params) override; ReturnValue_t truncateFile(FilesystemParams params) override; diff --git a/unittests/subsystem/CMakeLists.txt b/unittests/subsystem/CMakeLists.txt new file mode 100644 index 000000000..724ebc056 --- /dev/null +++ b/unittests/subsystem/CMakeLists.txt @@ -0,0 +1 @@ +target_sources(${FSFW_TEST_TGT} PRIVATE testModeDef.cpp) diff --git a/unittests/subsystem/testModeDef.cpp b/unittests/subsystem/testModeDef.cpp new file mode 100644 index 000000000..758b33016 --- /dev/null +++ b/unittests/subsystem/testModeDef.cpp @@ -0,0 +1,49 @@ + +#include +#include + +#include "fsfw/subsystem/modes/ModeDefinitions.h" + +TEST_CASE("Mode Definitions", "[mode]") { + ModeListEntry entry; + + SECTION("Basic") { + entry.setMode(HasModesIF::MODE_OFF); + entry.setSubmode(2); + CHECK(entry.getMode() == HasModesIF::MODE_OFF); + CHECK(entry.getSubmode() == 2); + uint8_t mask; + CHECK(entry.submodesAllowed(&mask) == false); + } + + SECTION("Allowed submode mask") { + entry.allowAllSubmodes(); + uint8_t mask; + CHECK(entry.submodesAllowed(&mask) == true); + CHECK(mask == 0xff); + } + + SECTION("Serialization") { + std::array buf{}; + entry.setObject(0x1f2f3f4f); + entry.setMode(HasModesIF::MODE_ON); + entry.setSubmode(2); + entry.enableInheritSubmode(); + entry.enableSubmodeAllowed(0x1f); + uint8_t* serPtr = buf.data(); + size_t serLen = 0; + REQUIRE(entry.serialize(&serPtr, &serLen, buf.size(), SerializeIF::Endianness::NETWORK) == + returnvalue::OK); + CHECK(buf[0] == 0x1f); + CHECK(buf[1] == 0x2f); + CHECK(buf[2] == 0x3f); + CHECK(buf[3] == 0x4f); + CHECK(buf[4] == 0); + CHECK(buf[5] == 0); + CHECK(buf[6] == 0); + CHECK(buf[7] == HasModesIF::MODE_ON); + CHECK(buf[8] == 2); + CHECK(buf[9] == (mode::SpecialSubmodeFlags::ALLOWED_MASK | mode::SpecialSubmodeFlags::INHERIT)); + CHECK(buf[10] == 0x1f); + } +} diff --git a/unittests/timemanager/TestCountdown.cpp b/unittests/timemanager/TestCountdown.cpp index 67f4ddb22..61d372e7a 100644 --- a/unittests/timemanager/TestCountdown.cpp +++ b/unittests/timemanager/TestCountdown.cpp @@ -1,15 +1,18 @@ #include #include +#include +#include #include "CatchDefinitions.h" +static constexpr bool TEST_LONGER_CD = false; TEST_CASE("Countdown Tests", "[TestCountdown]") { INFO("Countdown Tests"); Countdown count(20); - REQUIRE(count.timeout == 20); + REQUIRE(count.getTimeoutMs() == 20); REQUIRE(count.setTimeout(100) == static_cast(returnvalue::OK)); - REQUIRE(count.timeout == 100); + REQUIRE(count.getTimeoutMs() == 100); REQUIRE(count.setTimeout(150) == static_cast(returnvalue::OK)); REQUIRE(count.isBusy()); REQUIRE(not count.hasTimedOut()); @@ -25,4 +28,19 @@ TEST_CASE("Countdown Tests", "[TestCountdown]") { count.resetTimer(); REQUIRE(not count.hasTimedOut()); REQUIRE(count.isBusy()); + count.setTimeout(100); + REQUIRE(not count.hasTimedOut()); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + REQUIRE(not count.hasTimedOut()); + std::this_thread::sleep_for(std::chrono::milliseconds(50)); + REQUIRE(count.hasTimedOut()); + + // Takes longer, disabled by default + if (TEST_LONGER_CD) { + count.setTimeout(2500); + std::this_thread::sleep_for(std::chrono::milliseconds(1000)); + REQUIRE(not count.hasTimedOut()); + std::this_thread::sleep_for(std::chrono::milliseconds(1500)); + REQUIRE(count.hasTimedOut()); + } } diff --git a/unittests/util/testUnsignedByteField.cpp b/unittests/util/testUnsignedByteField.cpp index df1ff4836..58a87a7dd 100644 --- a/unittests/util/testUnsignedByteField.cpp +++ b/unittests/util/testUnsignedByteField.cpp @@ -4,7 +4,7 @@ #include "fsfw/util/UnsignedByteField.h" -TEST_CASE("Unsigned Byte Field", "[unsigned-byte-field]") { +TEST_CASE("Unsigned Byte Field", "[util]") { auto testByteField = UnsignedByteField(10); auto u32ByteField = U32ByteField(10); auto u16ByteField = U16ByteField(5);