From 4f1f610ae03bd4f0fecc9e19ecafa5803ee8a231 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 7 Jul 2020 16:36:41 +0200 Subject: [PATCH 01/17] doc and improvements for DLE encoder --- globalfunctions/DleEncoder.cpp | 39 +++++++++++---------- globalfunctions/DleEncoder.h | 64 +++++++++++++++++++++++++++++----- returnvalues/FwClassIds.h | 3 +- 3 files changed, 78 insertions(+), 28 deletions(-) diff --git a/globalfunctions/DleEncoder.cpp b/globalfunctions/DleEncoder.cpp index a68f1524..ee934785 100644 --- a/globalfunctions/DleEncoder.cpp +++ b/globalfunctions/DleEncoder.cpp @@ -1,18 +1,16 @@ #include -DleEncoder::DleEncoder() { -} +DleEncoder::DleEncoder() {} -DleEncoder::~DleEncoder() { -} +DleEncoder::~DleEncoder() {} ReturnValue_t DleEncoder::decode(const uint8_t *sourceStream, - uint32_t sourceStreamLen, uint32_t *readLen, uint8_t *destStream, - uint32_t maxDestStreamlen, uint32_t *decodedLen) { - uint32_t encodedIndex = 0, decodedIndex = 0; + size_t sourceStreamLen, size_t *readLen, uint8_t *destStream, + size_t maxDestStreamlen, size_t *decodedLen) { + size_t encodedIndex = 0, decodedIndex = 0; uint8_t nextByte; if (*sourceStream != STX) { - return RETURN_FAILED; + return DECODING_ERROR; } ++encodedIndex; while ((encodedIndex < sourceStreamLen) && (decodedIndex < maxDestStreamlen) @@ -20,14 +18,18 @@ ReturnValue_t DleEncoder::decode(const uint8_t *sourceStream, && (sourceStream[encodedIndex] != STX)) { if (sourceStream[encodedIndex] == DLE) { nextByte = sourceStream[encodedIndex + 1]; - if (nextByte == 0x10) { + // The next byte is a DLE character that was escaped by another + // DLE character, so we can write it to the destination stream. + if (nextByte == DLE) { destStream[decodedIndex] = nextByte; } else { + // The next byte is a STX, DTX or 0x0D character which + // was escaped by a DLE character if ((nextByte == 0x42) || (nextByte == 0x43) || (nextByte == 0x4D)) { destStream[decodedIndex] = nextByte - 0x40; } else { - return RETURN_FAILED; + return DECODING_ERROR; } } ++encodedIndex; @@ -38,7 +40,7 @@ ReturnValue_t DleEncoder::decode(const uint8_t *sourceStream, ++decodedIndex; } if (sourceStream[encodedIndex] != ETX) { - return RETURN_FAILED; + return DECODING_ERROR; } else { *readLen = ++encodedIndex; *decodedLen = decodedIndex; @@ -47,12 +49,12 @@ ReturnValue_t DleEncoder::decode(const uint8_t *sourceStream, } ReturnValue_t DleEncoder::encode(const uint8_t* sourceStream, - uint32_t sourceLen, uint8_t* destStream, uint32_t maxDestLen, - uint32_t* encodedLen, bool addStxEtx) { + size_t sourceLen, uint8_t* destStream, size_t maxDestLen, + size_t* encodedLen, bool addStxEtx) { if (maxDestLen < 2) { - return RETURN_FAILED; + return STREAM_TOO_SHORT; } - uint32_t encodedIndex = 0, sourceIndex = 0; + size_t encodedIndex = 0, sourceIndex = 0; uint8_t nextByte; if (addStxEtx) { destStream[0] = STX; @@ -62,15 +64,16 @@ ReturnValue_t DleEncoder::encode(const uint8_t* sourceStream, nextByte = sourceStream[sourceIndex]; if ((nextByte == STX) || (nextByte == ETX) || (nextByte == 0x0D)) { if (encodedIndex + 1 >= maxDestLen) { - return RETURN_FAILED; + return STREAM_TOO_SHORT; } else { destStream[encodedIndex] = DLE; ++encodedIndex; + // Escaped byte will be actual byte + 0x40. destStream[encodedIndex] = nextByte + 0x40; } } else if (nextByte == DLE) { if (encodedIndex + 1 >= maxDestLen) { - return RETURN_FAILED; + return STREAM_TOO_SHORT; } else { destStream[encodedIndex] = DLE; ++encodedIndex; @@ -90,6 +93,6 @@ ReturnValue_t DleEncoder::encode(const uint8_t* sourceStream, *encodedLen = encodedIndex; return RETURN_OK; } else { - return RETURN_FAILED; + return STREAM_TOO_SHORT; } } diff --git a/globalfunctions/DleEncoder.h b/globalfunctions/DleEncoder.h index fc155600..0f4a4c8f 100644 --- a/globalfunctions/DleEncoder.h +++ b/globalfunctions/DleEncoder.h @@ -1,25 +1,71 @@ -#ifndef DLEENCODER_H_ -#define DLEENCODER_H_ +#ifndef FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_ +#define FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_ #include +#include +/** + * @brief This DLE Encoder (Data Link Encoder) can be used to encode and + * decode arbitrary data with ASCII control characters + * @details + * List of control codes: + * https://en.wikipedia.org/wiki/C0_and_C1_control_codes + * + * This encoder can be used to achieve a basic transport layer when using + * char based transmission systems. + * The passed source strean is converted into a encoded stream by adding + * a STX marker at the startr of the stream and an ETX marker at the end of + * the stream. Any STX, ETX and DLE occurences in the source stream are escaped + * by a DLE character. + */ class DleEncoder: public HasReturnvaluesIF { private: DleEncoder(); virtual ~DleEncoder(); public: + static constexpr uint8_t INTERFACE_ID = CLASS_ID::DLE_ENCODER; + static constexpr ReturnValue_t STREAM_TOO_SHORT = MAKE_RETURN_CODE(0x01); + static constexpr ReturnValue_t DECODING_ERROR = MAKE_RETURN_CODE(0x02); + + //! Start Of Text character. First character is encoded stream static const uint8_t STX = 0x02; + //! End Of Text character. Last character in encoded stream static const uint8_t ETX = 0x03; + //! Data Link Escape character. Used to escape STX, ETX and DLE occurences + //! in the source stream. static const uint8_t DLE = 0x10; - static ReturnValue_t decode(const uint8_t *sourceStream, - uint32_t sourceStreamLen, uint32_t *readLen, uint8_t *destStream, - uint32_t maxDestStreamlen, uint32_t *decodedLen); + /** + * Encodes the give data stream by preceding it with the STX marker + * and ending it with an ETX marker. STX, ETX and DLE characters inside + * the stream are escaped by DLE characters. + * @param sourceStream + * @param sourceLen + * @param destStream + * @param maxDestLen + * @param encodedLen + * @param addStxEtx + * Adding STX and ETX can be omitted, if they are added manually. + * @return + */ + static ReturnValue_t encode(const uint8_t *sourceStream, size_t sourceLen, + uint8_t *destStream, size_t maxDestLen, size_t *encodedLen, + bool addStxEtx = true); - static ReturnValue_t encode(const uint8_t *sourceStream, uint32_t sourceLen, - uint8_t *destStream, uint32_t maxDestLen, uint32_t *encodedLen, - bool addStxEtx = true); + /** + * Converts an encoded stream back + * @param sourceStream + * @param sourceStreamLen + * @param readLen + * @param destStream + * @param maxDestStreamlen + * @param decodedLen + * @return + */ + static ReturnValue_t decode(const uint8_t *sourceStream, + size_t sourceStreamLen, size_t *readLen, uint8_t *destStream, + size_t maxDestStreamlen, size_t *decodedLen); }; -#endif /* DLEENCODER_H_ */ +#endif /* FRAMEWORK_GLOBALFUNCTIONS_DLEENCODER_H_ */ diff --git a/returnvalues/FwClassIds.h b/returnvalues/FwClassIds.h index abee534a..7e4d8953 100644 --- a/returnvalues/FwClassIds.h +++ b/returnvalues/FwClassIds.h @@ -64,7 +64,8 @@ enum { LOCAL_POOL_OWNER_IF, //LPIF 58 POOL_VARIABLE_IF, //PVA 59 HOUSEKEEPING_MANAGER, //HKM 60 - PUS_PARSER, //PUSP 61 + DLE_ENCODER, //DLEE 61 + PUS_PARSER, //PUSP 62 FW_CLASS_ID_COUNT //is actually count + 1 ! }; From 359163886ba2d926cefe8f57b6691818a1e70b8e Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 7 Jul 2020 17:06:30 +0200 Subject: [PATCH 02/17] pus srv5 and 1 moved to framework --- framework.mk | 2 +- pus/Service1TelecommandVerification.cpp | 100 ++++++++++++++ pus/Service1TelecommandVerification.h | 94 ++++++++++++++ pus/Service5EventReporting.cpp | 92 +++++++++++++ pus/Service5EventReporting.h | 86 ++++++++++++ pus/servicepackets/Service1Packets.h | 166 ++++++++++++++++++++++++ pus/servicepackets/Service5Packets.h | 83 ++++++++++++ 7 files changed, 622 insertions(+), 1 deletion(-) create mode 100644 pus/Service1TelecommandVerification.cpp create mode 100644 pus/Service1TelecommandVerification.h create mode 100644 pus/Service5EventReporting.cpp create mode 100644 pus/Service5EventReporting.h create mode 100644 pus/servicepackets/Service1Packets.h create mode 100644 pus/servicepackets/Service5Packets.h diff --git a/framework.mk b/framework.mk index c8822981..bfbd4b1f 100644 --- a/framework.mk +++ b/framework.mk @@ -58,4 +58,4 @@ CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcpacket/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcpacket/packetmatcher/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcpacket/pus/*.cpp) CXXSRC += $(wildcard $(FRAMEWORK_PATH)/tmtcservices/*.cpp) -CXXSRC += $(wildcard $(FRAMEWORK_PATH)/test/*.cpp) \ No newline at end of file +CXXSRC += $(wildcard $(FRAMEWORK_PATH)/pus/*.cpp) \ No newline at end of file diff --git a/pus/Service1TelecommandVerification.cpp b/pus/Service1TelecommandVerification.cpp new file mode 100644 index 00000000..4ce2ce54 --- /dev/null +++ b/pus/Service1TelecommandVerification.cpp @@ -0,0 +1,100 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + + +Service1TelecommandVerification::Service1TelecommandVerification( + object_id_t objectId, uint16_t apid, uint8_t serviceId, + object_id_t targetDestination): + SystemObject(objectId), apid(apid), serviceId(serviceId), + targetDestination(targetDestination) { + tmQueue = QueueFactory::instance()->createMessageQueue(); +} + +Service1TelecommandVerification::~Service1TelecommandVerification() {} + +MessageQueueId_t Service1TelecommandVerification::getVerificationQueue(){ + return tmQueue->getId(); +} + + +ReturnValue_t Service1TelecommandVerification::performOperation( + uint8_t operationCode){ + PusVerificationMessage message; + ReturnValue_t status = tmQueue->receiveMessage(&message); + while(status == HasReturnvaluesIF::RETURN_OK) { + status = sendVerificationReport(&message); + if(status != HasReturnvaluesIF::RETURN_OK) { + return status; + } + status = tmQueue->receiveMessage(&message); + } + if (status == MessageQueueIF::EMPTY) { + return HasReturnvaluesIF::RETURN_OK; + } + else { + return status; + } +} + + +ReturnValue_t Service1TelecommandVerification::sendVerificationReport( + PusVerificationMessage* message) { + ReturnValue_t result; + if(message->getReportId() % 2 == 0) { + result = generateFailureReport(message); + } else { + result = generateSuccessReport(message); + } + if(result != HasReturnvaluesIF::RETURN_OK){ + sif::error << "Service1TelecommandVerification::initialize: " + "Sending verification packet failed !" << std::endl; + } + return result; +} + +ReturnValue_t Service1TelecommandVerification::generateFailureReport( + PusVerificationMessage *message) { + FailureReport report( + message->getReportId(), message->getTcPacketId(), + message->getTcSequenceControl(), message->getStep(), + message->getErrorCode(), message->getParameter1(), + message->getParameter2()); + TmPacketStored tmPacket(apid, serviceId, message->getReportId(), + packetSubCounter++, &report); + ReturnValue_t result = tmPacket.sendPacket(tmQueue->getDefaultDestination(), + tmQueue->getId()); + return result; +} + +ReturnValue_t Service1TelecommandVerification::generateSuccessReport( + PusVerificationMessage *message) { + SuccessReport report(message->getReportId(),message->getTcPacketId(), + message->getTcSequenceControl(),message->getStep()); + TmPacketStored tmPacket(apid, serviceId, message->getReportId(), + packetSubCounter++, &report); + ReturnValue_t result = tmPacket.sendPacket(tmQueue->getDefaultDestination(), + tmQueue->getId()); + return result; +} + + +ReturnValue_t Service1TelecommandVerification::initialize() { + // Get target object for TC verification messages + AcceptsTelemetryIF* funnel = objectManager-> + get(targetDestination); + if(funnel == nullptr){ + sif::error << "Service1TelecommandVerification::initialize: Specified" + " TM funnel invalid. Make sure it is set up and implements" + " AcceptsTelemetryIF." << std::endl; + return ObjectManagerIF::CHILD_INIT_FAILED; + } + tmQueue->setDefaultDestination(funnel->getReportReceptionQueue()); + return SystemObject::initialize(); +} diff --git a/pus/Service1TelecommandVerification.h b/pus/Service1TelecommandVerification.h new file mode 100644 index 00000000..1d4b6719 --- /dev/null +++ b/pus/Service1TelecommandVerification.h @@ -0,0 +1,94 @@ +#ifndef MISSION_PUS_SERVICE1TELECOMMANDVERIFICATION_H_ +#define MISSION_PUS_SERVICE1TELECOMMANDVERIFICATION_H_ + +#include +#include +#include +#include +#include +#include + +/** + * @brief Verify TC acceptance, start, progress and execution. + * + * Full Documentation: ECSS-E70-41A p.51 + * + * The telecommand verification service provides the capability for + * explicit verification of each distinct stage of execution of a telecommand + * packet, from on-board acceptance through to completion of execution. + * + * Minimum capabilities of this service: + * + * - TM[1,1]: Telecommand Acceptance Report - Success. + * - TM[1,2]: Telecommand Acceptance Report - Failure. + * + * Additional capabilities of this service: + * + * - TM[1,3]: Telecommand Execution Started Report - Success (Req. 4). + * - TM[1,4]: Telecommand Execution Started Report - Failure (Req. 3). + * - TM[1,5]: Telecommand Execution Progress Report - Success (Req. 6). + * - TM[1,6]: Telecommand Execution Progress Report - Failure (Req. 5). + * - TM[1,7]: Telecommand Execution Completed Report - Success (Req. 8). + * - TM[1,8]: Telecommand Execution Completed Report - Failure (Req. 7). + * + * This Service is not inherited from PUSServiceBase unlike other PUS Services + * because all services implementing PUSServiceBase use this service to + * generate verification reports. + * @ingroup pus_services + */ +class Service1TelecommandVerification: public AcceptsVerifyMessageIF, + public SystemObject, + public ExecutableObjectIF, + public HasReturnvaluesIF { +public: + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PUS_SERVICE_1; + + Service1TelecommandVerification(object_id_t objectId, + uint16_t apid, uint8_t serviceId, object_id_t targetDestination); + virtual ~Service1TelecommandVerification(); + + /** + * + * @return ID of Verification Queue + */ + virtual MessageQueueId_t getVerificationQueue(); + + /** + * Performs the service periodically as specified in init_mission(). + * Triggers the handlePacket function to send TC verification messages + * @param operationCode + * @return + */ + ReturnValue_t performOperation(uint8_t operationCode = 0) override; + + /** + * Initializes the destination for TC verification messages and initializes + * Service 1 as a system object + * @return + */ + ReturnValue_t initialize() override; +private: + uint16_t apid = 0; + uint8_t serviceId = 0; + + object_id_t targetDestination = objects::NO_OBJECT; + + ReturnValue_t sendVerificationReport(PusVerificationMessage* message); + ReturnValue_t generateFailureReport(PusVerificationMessage* message); + ReturnValue_t generateSuccessReport(PusVerificationMessage* message); + + uint16_t packetSubCounter = 0; + + MessageQueueIF* tmQueue = nullptr; + + enum class Subservice: uint8_t { + VERIFY_ACCEPTANCE_SUCCESS = 1, //!< [EXPORT] : [TM] + VERIFY_ACCEPTANCE_FAILED = 2, //!< [EXPORT] : [TM] + VERIFY_START_SUCCESS = 3, //!< [EXPORT] : [TM] + VERIFY_START_FAILED = 4, //!< [EXPORT] : [TM] + VERIFY_STEP_SUCCESS = 5, //!< [EXPORT] : [TM] + VERIFY_STEP_FAILED = 6 //!< [EXPORT] : [TM] + }; +}; + +#endif /* MISSION_PUS_SERVICE1TELECOMMANDVERIFICATION_H_ */ diff --git a/pus/Service5EventReporting.cpp b/pus/Service5EventReporting.cpp new file mode 100644 index 00000000..fe55059c --- /dev/null +++ b/pus/Service5EventReporting.cpp @@ -0,0 +1,92 @@ +#include +#include + +#include +#include +#include +#include + + +Service5EventReporting::Service5EventReporting(object_id_t objectId, + uint16_t apid, uint8_t serviceId, size_t maxNumberReportsPerCycle): + PusServiceBase(objectId, apid, serviceId), + maxNumberReportsPerCycle(maxNumberReportsPerCycle) { + eventQueue = QueueFactory::instance()->createMessageQueue(); +} + +Service5EventReporting::~Service5EventReporting(){} + +ReturnValue_t Service5EventReporting::performService() { + EventMessage message; + ReturnValue_t status = RETURN_OK; + for(uint8_t counter = 0; + counter < maxNumberReportsPerCycle; + counter++) + { + // Receive messages even if reporting is disabled for now. + status = eventQueue->receiveMessage(&message); + if(status == MessageQueueIF::EMPTY) { + return HasReturnvaluesIF::RETURN_OK; + } + + if(enableEventReport) { + status = generateEventReport(message); + if(status != HasReturnvaluesIF::RETURN_OK) { + return status; + } + } + } + sif::debug << "Service5EventReporting::generateEventReport:" + " Too many events" << std::endl; + return HasReturnvaluesIF::RETURN_OK; +} + + +ReturnValue_t Service5EventReporting::generateEventReport( + EventMessage message) +{ + EventReport report(message.getEventId(),message.getReporter(), + message.getParameter1(),message.getParameter2()); + TmPacketStored tmPacket(PusServiceBase::apid, PusServiceBase::serviceId, + message.getSeverity(), packetSubCounter++, &report); + ReturnValue_t result = tmPacket.sendPacket( + requestQueue->getDefaultDestination(),requestQueue->getId()); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::debug << "Service5EventReporting::generateEventReport:" + " Could not send TM packet" << std::endl; + } + return result; +} + +ReturnValue_t Service5EventReporting::handleRequest(uint8_t subservice) { + switch(subservice) + { + case Subservice::ENABLE: { + enableEventReport = true; + return HasReturnvaluesIF::RETURN_OK; + } + case Subservice::DISABLE: { + enableEventReport = false; + return HasReturnvaluesIF::RETURN_OK; + } + default: + return AcceptsTelecommandsIF::INVALID_SUBSERVICE; + } +} + + +// In addition to the default PUSServiceBase initialization, this service needs +// to be registered to the event manager to listen for events. +ReturnValue_t Service5EventReporting::initialize() { + EventManagerIF* manager = objectManager->get( + objects::EVENT_MANAGER); + if (manager == NULL) { + return RETURN_FAILED; + } + // register Service 5 as listener for events + ReturnValue_t result = manager->registerListener(eventQueue->getId(),true); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return PusServiceBase::initialize(); +} diff --git a/pus/Service5EventReporting.h b/pus/Service5EventReporting.h new file mode 100644 index 00000000..79b7c5e7 --- /dev/null +++ b/pus/Service5EventReporting.h @@ -0,0 +1,86 @@ +#ifndef FRAMEWORK_PUS_SERVICE5EVENTREPORTING_H_ +#define FRAMEWORK_PUS_SERVICE5EVENTREPORTING_H_ + +#include +#include + +/** + * @brief Report on-board events like information or errors + * @details + * Full Documentation: ECSS-E70-41A p.79 + * Implements the PusServiceBase template class. + * Documentation: Dissertation Baetz p.135,136 + * + * This service provides for the reporting to the service user of information of + * operational significance. + * 1. reporting of failures or anomalies detected on-board; + * 2. reporting of autonomous on-board actions; + * 3. reporting of normal progress of operations and activities, e.g. + * detection of events which are not anomalous (such as payload events), + * reaching of predefined steps in an operation. Some reports can combine + * more than one of these events. + * + * Minimum capabilities of this service: + * + * - TM[5,1]: Normal/Progress Report + * - TM[5,2]: Error/Anomaly Report - Low Severity + * - TM[5,3]: Error/Anomaly Report - Medium Severity + * - TM[5,4]: Error/Anomaly Report - High Severity + * + * Events can be translated by using translator files located in + * /config/objects/ and /config/events/. Description to events can be added by + * adding a comment behind the event definition with [//!<] as leading string + * + * Additional capabilities of this service: + * + * - TC[5,5]: Enable Event Report Generation (Req. 6) + * - TC[5,6]: Disable Event Report Generation (Req. 5) + * @author R. Mueller + * @ingroup pus_services + */ +class Service5EventReporting: public PusServiceBase { +public: + + Service5EventReporting(object_id_t objectId, uint16_t apid, + uint8_t serviceId, size_t maxNumberReportsPerCycle = 10); + virtual ~Service5EventReporting(); + + /*** + * Check for events and generate event reports if required. + * @return + */ + ReturnValue_t performService() override; + + /*** + * Turn event generation on or off. + * @return + */ + ReturnValue_t handleRequest(uint8_t subservice) override; + + /** + * The default PusServiceBase initialize has been overridden but is still + * executed. Registers this service as a listener for events at the + * EventManager. + * @return + */ + ReturnValue_t initialize() override; + + enum Subservice: uint8_t { + NORMAL_REPORT = 1, //!< [EXPORT] : [REPLY] Generate normal report + ERROR_LOW_SEVERITY = 2, //!< [EXPORT] : [REPLY] Generate error report with low severity + ERROR_MED_SEVERITY = 3, //!< [EXPORT] : [REPLY] Generate error report with medium severity + ERROR_HIGH_SEVERITY = 4, //!< [EXPORT] : [REPLY] Generate error report with high severity + ENABLE = 5, //!< [EXPORT] : [COMMAND] Enable report generation + DISABLE = 6 //!< [EXPORT] : [COMMAND] Disable report generation + }; + +private: + uint16_t packetSubCounter = 0; + MessageQueueIF* eventQueue = nullptr; + bool enableEventReport = true; + const uint8_t maxNumberReportsPerCycle; + + ReturnValue_t generateEventReport(EventMessage message); +}; + +#endif /* MISSION_PUS_SERVICE5EVENTREPORTING_H_ */ diff --git a/pus/servicepackets/Service1Packets.h b/pus/servicepackets/Service1Packets.h new file mode 100644 index 00000000..b01942c6 --- /dev/null +++ b/pus/servicepackets/Service1Packets.h @@ -0,0 +1,166 @@ +/** + * @defgroup spacepackets PUS Packet Definitions + * This group contains all implemented TM or TM packages that are sent to + * or sent by the OBC.They are exported later to display + * packet structures in Mission Information Base (MIB). + */ + +#ifndef MISSION_PUS_SERVICEPACKETS_SERVICE1PACKETS_H_ +#define MISSION_PUS_SERVICEPACKETS_SERVICE1PACKETS_H_ + +#include +#include + +/** + * @brief FailureReport class to serialize a failure report + * @brief Subservice 1, 3, 5, 7 + * @ingroup spacepackets + */ +class FailureReport: public SerializeIF { //!< [EXPORT] : [SUBSERVICE] 1, 3, 5, 7 +public: + FailureReport(uint8_t failureSubtype_, uint16_t packetId_, + uint16_t packetSequenceControl_, uint8_t stepNumber_, + ReturnValue_t errorCode_, uint32_t errorParameter1_, + uint32_t errorParameter2_) : + packetId(packetId_), packetSequenceControl(packetSequenceControl_), + stepNumber(stepNumber_), errorCode(errorCode_), + errorParameter1(errorParameter1_), errorParameter2(errorParameter2_), + failureSubtype(failureSubtype_) {} + + /** + * This function is called by the FSFW when calling the tm packet send + * function and supplying the SerializeIF* as parameter + * @param buffer Object content is serialized into the buffer + * @param size + * @param max_size + * @param bigEndian + * @return + */ + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, SerializeIF::Endianness streamEndianness + ) const override { + ReturnValue_t result = SerializeAdapter::serialize(&packetId, buffer, + size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::serialize(&packetSequenceControl, buffer, + size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if (failureSubtype == TC_VERIFY::PROGRESS_FAILURE) { + result = SerializeAdapter::serialize(&stepNumber, buffer, size, + maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + result = SerializeAdapter::serialize(&errorCode, buffer, size, + maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::serialize(&errorParameter1, buffer, size, + maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + result = SerializeAdapter::serialize(&errorParameter2, buffer, size, + maxSize, streamEndianness); + return result; + } + + + virtual size_t getSerializedSize() const { + size_t size = 0; + size += SerializeAdapter::getSerializedSize(&packetId); + size += sizeof(packetSequenceControl); + if(failureSubtype==TC_VERIFY::PROGRESS_FAILURE){ + size += SerializeAdapter::getSerializedSize(&stepNumber); + } + size += SerializeAdapter::getSerializedSize(&errorCode); + size += SerializeAdapter::getSerializedSize(&errorParameter1); + size += SerializeAdapter::getSerializedSize(&errorParameter2); + return size; + } + + /** + * Deserialization is not allowed for a report. + * @param buffer + * @param size + * @param bigEndian + * @return + */ + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) override { + return HasReturnvaluesIF::RETURN_FAILED; + } +private: + uint16_t packetId; //!< [EXPORT] : [COMMENT] Packet ID of respective Telecommand + uint16_t packetSequenceControl; //!< [EXPORT] : [COMMENT] Packet SSC of respective Telecommand + uint8_t stepNumber; //!< [EXPORT] : [OPTIONAL][SUBSERVICE] 6 + ReturnValue_t errorCode; //!< [EXPORT] : [COMMENT] Error code which can be looked up in generated error code file + uint32_t errorParameter1; + uint32_t errorParameter2; + const uint8_t failureSubtype; //!< [EXPORT] : [IGNORE] +}; + +/** + * @brief Subservices 2, 4, 6, 8 + * @ingroup spacepackets + */ +class SuccessReport: public SerializeIF { //!< [EXPORT] : [SUBSERVICE] 2, 4, 6, 8 +public: + SuccessReport(uint8_t subtype_, uint16_t packetId_, + uint16_t packetSequenceControl_,uint8_t stepNumber_) : + packetId(packetId_), packetSequenceControl(packetSequenceControl_), + stepNumber(stepNumber_), subtype(subtype_) {} + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, SerializeIF::Endianness streamEndianness + ) const override { + ReturnValue_t result = SerializeAdapter::serialize(&packetId, buffer, + size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::serialize(&packetSequenceControl, buffer, + size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if (subtype == TC_VERIFY::PROGRESS_SUCCESS) { + result = SerializeAdapter::serialize(&stepNumber, buffer, size, + maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + } + return result; + } + + virtual size_t getSerializedSize() const override { + size_t size = 0; + size += SerializeAdapter::getSerializedSize(&packetId); + size += sizeof(packetSequenceControl); + if(subtype == TC_VERIFY::PROGRESS_SUCCESS){ + size += SerializeAdapter::getSerializedSize(&stepNumber); + } + return size; + + } + + ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) override { + return HasReturnvaluesIF::RETURN_FAILED; + } +private: + uint16_t packetId; //!< [EXPORT] : [COMMENT] Packet ID of respective Telecommand + uint16_t packetSequenceControl; //!< [EXPORT] : [COMMENT] Packet SSC of respective Telecommand + uint8_t stepNumber; //!< [EXPORT] : [OPTIONAL][SUBSERVICE] 6 + const uint8_t subtype; //!< [EXPORT] : [IGNORE] +}; + +#endif /* MISSION_PUS_SERVICEPACKETS_SERVICE1PACKETS_H_ */ diff --git a/pus/servicepackets/Service5Packets.h b/pus/servicepackets/Service5Packets.h new file mode 100644 index 00000000..f8f730c3 --- /dev/null +++ b/pus/servicepackets/Service5Packets.h @@ -0,0 +1,83 @@ +/** + * \file Service5Packets.h + * + * Structure of Event Report. + * It consists of: + * 1. Report ID(RID). This is the Event ID in the FSFW + * 2. Object ID of the reporter (e.g. subsystem) + * 2. Parameter 1 + * 3. Parameter 2 + * + * Created on: 21.05.2019 + * Author: R. Mueller, J. Meier + */ + +#ifndef MISSION_PUS_SERVICEPACKETS_SERVICE5PACKETS_H_ +#define MISSION_PUS_SERVICEPACKETS_SERVICE5PACKETS_H_ + +#include +#include + + +/** + * \brief Subservice 1, 2, 3, 4 + * \ingroup spacepackets + */ +class EventReport: public SerializeIF { //!< [EXPORT] : [SUBSERVICE] 1, 2, 3, 4 +public: + + EventReport(EventId_t reportId_, object_id_t objectId_, uint32_t parameter1_, + uint32_t parameter2_): + reportId(reportId_),objectId(objectId_), parameter1(parameter1_), + parameter2(parameter2_) {} + + virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, + size_t maxSize, + SerializeIF::Endianness streamEndianness) const override + { + ReturnValue_t result = SerializeAdapter::serialize(&reportId, buffer, + size, maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::serialize(&objectId, buffer, size, + maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::serialize(¶meter1, buffer, size, + maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + result = SerializeAdapter::serialize(¶meter2, buffer, size, + maxSize, streamEndianness); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + return result; + } + + virtual size_t getSerializedSize() const override { + uint32_t size = 0; + size += SerializeAdapter::getSerializedSize(&reportId); + size += SerializeAdapter::getSerializedSize(&objectId); + size += SerializeAdapter::getSerializedSize(¶meter1); + size += SerializeAdapter::getSerializedSize(¶meter2); + return size; + + } + + virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, + SerializeIF::Endianness streamEndianness) override { + return HasReturnvaluesIF::RETURN_FAILED; + } +private: + EventId_t reportId; + object_id_t objectId; + uint32_t parameter1; + uint32_t parameter2; +}; + + +#endif /* MISSION_PUS_SERVICEPACKETS_SERVICE5PACKETS_H_ */ From 7698f3f13e4ff5886c6c56145e56111a49a6ff4f Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 7 Jul 2020 17:18:33 +0200 Subject: [PATCH 03/17] moved srv2 to framework --- pus/Service2DeviceAccess.cpp | 178 +++++++++++++++++++++++++++ pus/Service2DeviceAccess.h | 96 +++++++++++++++ pus/servicepackets/Service2Packets.h | 76 ++++++++++++ pus/servicepackets/Service5Packets.h | 25 ++-- 4 files changed, 359 insertions(+), 16 deletions(-) create mode 100644 pus/Service2DeviceAccess.cpp create mode 100644 pus/Service2DeviceAccess.h create mode 100644 pus/servicepackets/Service2Packets.h diff --git a/pus/Service2DeviceAccess.cpp b/pus/Service2DeviceAccess.cpp new file mode 100644 index 00000000..5c6ad506 --- /dev/null +++ b/pus/Service2DeviceAccess.cpp @@ -0,0 +1,178 @@ +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +Service2DeviceAccess::Service2DeviceAccess(object_id_t objectId, + uint16_t apid, uint8_t serviceId, object_id_t tcSource, + object_id_t tmDestination): + CommandingServiceBase(objectId, apid, serviceId, + NUM_OF_PARALLEL_COMMANDS, COMMAND_TIMEOUT_SECONDS, + tcSource, tmDestination) {} + +Service2DeviceAccess::~Service2DeviceAccess() {} + +ReturnValue_t Service2DeviceAccess::isValidSubservice(uint8_t subservice) { + switch(static_cast(subservice)){ + case Subservice::RAW_COMMANDING: + case Subservice::TOGGLE_WIRETAPPING: + return HasReturnvaluesIF::RETURN_OK; + default: + sif::error << "Invalid Subservice" << std::endl; + return AcceptsTelecommandsIF::INVALID_SUBSERVICE; + } +} + +ReturnValue_t Service2DeviceAccess::getMessageQueueAndObject( + uint8_t subservice, const uint8_t* tcData, size_t tcDataLen, + MessageQueueId_t* id, object_id_t* objectId) { + ReturnValue_t result = checkAndAcquireTargetID(objectId,tcData,tcDataLen); + if(result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + + result = checkInterfaceAndAcquireMessageQueue(id,objectId); + return result; + +} + +ReturnValue_t Service2DeviceAccess::checkAndAcquireTargetID( + object_id_t* objectIdToSet, const uint8_t* tcData, size_t tcDataLen) { + if(SerializeAdapter::deSerialize(objectIdToSet, &tcData, + &tcDataLen, SerializeIF::Endianness::BIG) != RETURN_OK) { + sif::error << "Service 2: Target ID not found. ID: " << + std::hex << objectIdToSet ; + return CommandingServiceBase::INVALID_TC; + } + else { + return HasReturnvaluesIF::RETURN_OK; + } +} + +ReturnValue_t Service2DeviceAccess::checkInterfaceAndAcquireMessageQueue( + MessageQueueId_t * messageQueueToSet, object_id_t *objectId) { + DeviceHandlerIF* possibleTarget = + objectManager->get(*objectId); + if(possibleTarget == nullptr) { + return CommandingServiceBase::INVALID_OBJECT; + } + *messageQueueToSet = possibleTarget->getCommandQueue(); + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t Service2DeviceAccess::prepareCommand(CommandMessage* message, + uint8_t subservice, const uint8_t* tcData, size_t tcDataLen, + uint32_t* state, object_id_t objectId) { + switch(static_cast(subservice)){ + case Subservice::RAW_COMMANDING: { + return prepareRawCommand(dynamic_cast(message), + tcData, tcDataLen); + } + break; + case Subservice::TOGGLE_WIRETAPPING: { + return prepareWiretappingCommand(dynamic_cast(message), + tcData, tcDataLen); + } + break; + default: + return HasReturnvaluesIF::RETURN_FAILED; + } +} + +ReturnValue_t Service2DeviceAccess::prepareRawCommand( + CommandMessage* messageToSet, const uint8_t *tcData,size_t tcDataLen) { + RawCommand RawCommand(tcData,tcDataLen); + // store command into the Inter Process Communication Store + store_address_t storeAddress; + ReturnValue_t result = IPCStore->addData(&storeAddress, + RawCommand.getCommand(), RawCommand.getCommandSize()); + DeviceHandlerMessage::setDeviceHandlerRawCommandMessage(messageToSet, + storeAddress); + return result; +} + +ReturnValue_t Service2DeviceAccess::prepareWiretappingCommand( + CommandMessage *messageToSet, const uint8_t *tcData, + size_t tcDataLen) { + if(tcDataLen != WiretappingToggle::WIRETAPPING_COMMAND_SIZE) { + return CommandingServiceBase::INVALID_TC; + } + WiretappingToggle command; + ReturnValue_t result = command.deSerialize(&tcData, &tcDataLen, + SerializeIF::Endianness::BIG); + DeviceHandlerMessage::setDeviceHandlerWiretappingMessage(messageToSet, + command.getWiretappingMode()); + return result; +} + +ReturnValue_t Service2DeviceAccess::handleReply(const CommandMessage* reply, + Command_t previousCommand, uint32_t* state, + CommandMessage* optionalNextCommand, object_id_t objectId, + bool* isStep) { + switch(reply->getCommand()) { + case CommandMessage::REPLY_COMMAND_OK: + return HasReturnvaluesIF::RETURN_OK; + case CommandMessage::REPLY_REJECTED: + return reply->getReplyRejectedReason(); + default: + return CommandingServiceBase::INVALID_REPLY; + } +} + +// All device handlers set service 2 as default raw receiver for wiretapping +// so we have to handle those unrequested messages. +void Service2DeviceAccess::handleUnrequestedReply(CommandMessage* reply) { + switch(reply->getCommand()) { + case DeviceHandlerMessage::REPLY_RAW_COMMAND: + sendWiretappingTm(reply, + static_cast(Subservice::WIRETAPPING_RAW_TC)); + break; + case DeviceHandlerMessage::REPLY_RAW_REPLY: + sendWiretappingTm(reply, + static_cast(Subservice::RAW_REPLY)); + break; + default: + sif::error << "Unknown message in Service2DeviceAccess::" + "handleUnrequestedReply with command ID " << + reply->getCommand() << std::endl; + break; + } + //Must be reached by all cases to clear message + reply->clear(); +} + +void Service2DeviceAccess::sendWiretappingTm(CommandMessage *reply, + uint8_t subservice) { + // Raw Wiretapping + // Get Address of Data from Message + store_address_t storeAddress = DeviceHandlerMessage::getStoreAddress(reply); + const uint8_t* data = nullptr; + size_t size = 0; + ReturnValue_t result = IPCStore->getData(storeAddress,&data,&size); + if(result != HasReturnvaluesIF::RETURN_OK){ + sif::error << "Service2DeviceAccess::sendWiretappingTm: Data Lost in " + "handleUnrequestedReply with failure ID "<< result + << std::endl; + return; + } + + // Init our dummy packet and correct endianness of object ID before + // sending it back. + WiretappingPacket TmPacket(DeviceHandlerMessage::getDeviceObjectId(reply), + data); + TmPacket.objectId = EndianConverter::convertBigEndian(TmPacket.objectId); + sendTmPacket(subservice,TmPacket.data,size,reinterpret_cast( + &TmPacket.objectId),sizeof(TmPacket.objectId)); +} + +MessageQueueId_t Service2DeviceAccess::getDeviceQueue() { + return commandQueue->getId(); +} + diff --git a/pus/Service2DeviceAccess.h b/pus/Service2DeviceAccess.h new file mode 100644 index 00000000..ecab6101 --- /dev/null +++ b/pus/Service2DeviceAccess.h @@ -0,0 +1,96 @@ +#ifndef FRAMEWORK_PUS_SERVICE2DEVICEACCESS_H_ +#define FRAMEWORK_PUS_SERVICE2DEVICEACCESS_H_ + +#include +#include +#include + +/** + * @brief Raw Commanding and Wiretapping of devices. + * @details + * Full Documentation: ECSS-E-ST-70-41C or ECSS-E-70-41A + * Dissertation Baetz p. 115, 116, 165-167. + * + * This service provides the capability to communicate with devices in their + * native protocols with raw commands through the DeviceHandlerIF. + * + * This is a gateway service. It relays device commands using the software bus. + * This service is very closely tied to the Commanding Service Base + * template class. There is constant interaction between this Service Base und + * a Subclass like this service + * There are 4 adaption points for component implementation through the + * Commanding Service Base. + * + * This service employs custom subservices exclusively. This includes a + * wiretapping subservice to monitor all traffic between target devices and + * this service. + * + * - TC[2,128]: Raw Commanding + * - TC[2,129]: Toggle Wiretapping + * - TM[2,130]: Wiretapping Packet TM + * - TM[2,131]: Wiretapping Packet TC + * @ingroup pus_services + */ +class Service2DeviceAccess : public CommandingServiceBase, + public AcceptsDeviceResponsesIF +{ +public: + Service2DeviceAccess(object_id_t objectId, uint16_t apid, + uint8_t serviceId, object_id_t tcSource, + object_id_t tmDestination); + virtual ~Service2DeviceAccess(); + + static constexpr uint8_t NUM_OF_PARALLEL_COMMANDS = 4; + static constexpr uint16_t COMMAND_TIMEOUT_SECONDS = 60; +protected: + //! CommandingServiceBase (CSB) abstract functions. See CSB documentation. + ReturnValue_t isValidSubservice(uint8_t subservice) override; + ReturnValue_t getMessageQueueAndObject(uint8_t subservice, + const uint8_t *tcData, size_t tcDataLen, MessageQueueId_t *id, + object_id_t *objectId) override; + ReturnValue_t prepareCommand(CommandMessage* message, uint8_t subservice, + const uint8_t *tcData, size_t tcDataLen, uint32_t *state, + object_id_t objectId) override; + ReturnValue_t handleReply(const CommandMessage* reply, + Command_t previousCommand, uint32_t *state, + CommandMessage* optionalNextCommand, object_id_t objectId, + bool *isStep) override; + + /** + * @brief Generates TM packets containing either the TC wiretapping + * packets or the TM wiretapping packets. + * Note that for service 2, all telemetry will be treated as an + * unrequested reply regardless of wiretapping mode. + * @param reply + */ + void handleUnrequestedReply(CommandMessage* reply) override; + + MessageQueueId_t getDeviceQueue() override; +private: + /** + * Generates TM packets for Wiretapping Service + * @param reply + * @param subservice + */ + void sendWiretappingTm(CommandMessage* reply,uint8_t subservice); + + ReturnValue_t checkAndAcquireTargetID(object_id_t* objectIdToSet, + const uint8_t* tcData, size_t tcDataLen); + ReturnValue_t checkInterfaceAndAcquireMessageQueue( + MessageQueueId_t* messageQueueToSet, object_id_t* objectId); + + ReturnValue_t prepareRawCommand(CommandMessage* messageToSet, + const uint8_t* tcData, size_t tcDataLen); + ReturnValue_t prepareWiretappingCommand(CommandMessage* messageToSet, + const uint8_t* tcData, size_t tcDataLen); + + enum class Subservice { + RAW_COMMANDING = 128, //!< [EXPORT] : [COMMAND] Command in device native protocol + TOGGLE_WIRETAPPING = 129, //!< [EXPORT] : [COMMAND] Toggle wiretapping of raw communication + RAW_REPLY = 130, //!< [EXPORT] : [REPLY] Includes wiretapping TM and normal TM raw replies from device + WIRETAPPING_RAW_TC = 131 //!< [EXPORT] : [REPLY] Wiretapping packets of commands built by device handler + }; +}; + + +#endif /* MISSION_PUS_DEVICE2DEVICECOMMANDING_H_ */ diff --git a/pus/servicepackets/Service2Packets.h b/pus/servicepackets/Service2Packets.h new file mode 100644 index 00000000..f292611e --- /dev/null +++ b/pus/servicepackets/Service2Packets.h @@ -0,0 +1,76 @@ +#ifndef FRAMEWORK_PUS_SERVICEPACKETS_SERVICE2PACKETS_H_ +#define FRAMEWORK_PUS_SERVICEPACKETS_SERVICE2PACKETS_H_ + +#include +#include +#include +#include + +/** + * @brief Subservice 128 + * @ingroup spacepackets + */ +class RawCommand { //!< [EXPORT] : [SUBSERVICE] 128 +public: + RawCommand(const uint8_t* buffer, size_t size) { + // Deserialize Adapter to get correct endianness + SerializeAdapter::deSerialize(&objectId, &buffer, &size, + SerializeIF::Endianness::BIG); + commandBuffer = buffer; + // size is decremented by AutoSerializeAdapter, + // remaining size is data size + dataSize = size; + } + object_id_t getObjectId() const { + return objectId; + } + + const uint8_t* getCommand() { + return commandBuffer; + } + + size_t getCommandSize() const { + return dataSize; + } +private: + object_id_t objectId = 0; + const uint8_t* commandBuffer = nullptr; //!< [EXPORT] : [MAXSIZE] 256 Bytes + size_t dataSize = 0; //!< [EXPORT] : [IGNORE] +}; + + +/** + * @brief Subservice 129: Command packet to set wiretapping mode + * @ingroup spacepackets + */ +class WiretappingToggle: public SerialLinkedListAdapter{ //!< [EXPORT] : [SUBSERVICE] 129 +public: + static const size_t WIRETAPPING_COMMAND_SIZE = 5; + WiretappingToggle(){ + setStart(&objectId); + objectId.setNext(&wiretappingMode); + } + + uint8_t getWiretappingMode() const { + return wiretappingMode.entry; + } +private: + SerializeElement objectId; + SerializeElement wiretappingMode; //!< [EXPORT] : [INPUT] Mode 0: OFF, Mode 1: RAW +}; + + +/** + * @brief Subservices 130 and 131: TM packets + * @ingroup spacepackets + */ +class WiretappingPacket { //!< [EXPORT] : [SUBSERVICE] 130, 131 +public: + object_id_t objectId; //!< [EXPORT] : [COMMENT] Object ID of source object + const uint8_t* data; //!< [EXPORT] : [MAXSIZE] Raw Command Max. Size + WiretappingPacket(object_id_t objectId, const uint8_t* buffer): + objectId(objectId), data(buffer) { + } +}; + +#endif /* FRAMEWORK_PUS_SERVICEPACKETS_SERVICE2PACKETS_H_ */ diff --git a/pus/servicepackets/Service5Packets.h b/pus/servicepackets/Service5Packets.h index f8f730c3..14219c93 100644 --- a/pus/servicepackets/Service5Packets.h +++ b/pus/servicepackets/Service5Packets.h @@ -1,17 +1,3 @@ -/** - * \file Service5Packets.h - * - * Structure of Event Report. - * It consists of: - * 1. Report ID(RID). This is the Event ID in the FSFW - * 2. Object ID of the reporter (e.g. subsystem) - * 2. Parameter 1 - * 3. Parameter 2 - * - * Created on: 21.05.2019 - * Author: R. Mueller, J. Meier - */ - #ifndef MISSION_PUS_SERVICEPACKETS_SERVICE5PACKETS_H_ #define MISSION_PUS_SERVICEPACKETS_SERVICE5PACKETS_H_ @@ -20,8 +6,15 @@ /** - * \brief Subservice 1, 2, 3, 4 - * \ingroup spacepackets + * @brief Subservice 1, 2, 3, 4 + * Structure of Event Report. + * It consists of: + * 1. Report ID(RID). This is the Event ID in the FSFW + * 2. Object ID of the reporter (e.g. subsystem) + * 2. Parameter 1 + * 3. Parameter 2 + * + * @ingroup spacepackets */ class EventReport: public SerializeIF { //!< [EXPORT] : [SUBSERVICE] 1, 2, 3, 4 public: From 684b56ac883b0ee0528edc55b492977518611430 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 7 Jul 2020 17:21:47 +0200 Subject: [PATCH 04/17] srv2 tweak: CSB params now configurable --- pus/Service2DeviceAccess.cpp | 5 +++-- pus/Service2DeviceAccess.h | 15 +++++++-------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/pus/Service2DeviceAccess.cpp b/pus/Service2DeviceAccess.cpp index 5c6ad506..d1f8faf3 100644 --- a/pus/Service2DeviceAccess.cpp +++ b/pus/Service2DeviceAccess.cpp @@ -12,9 +12,10 @@ Service2DeviceAccess::Service2DeviceAccess(object_id_t objectId, uint16_t apid, uint8_t serviceId, object_id_t tcSource, - object_id_t tmDestination): + object_id_t tmDestination, uint8_t numberOfParallelCommands, + uint16_t commandTimeoutSeconds): CommandingServiceBase(objectId, apid, serviceId, - NUM_OF_PARALLEL_COMMANDS, COMMAND_TIMEOUT_SECONDS, + numberOfParallelCommands, commandTimeoutSeconds, tcSource, tmDestination) {} Service2DeviceAccess::~Service2DeviceAccess() {} diff --git a/pus/Service2DeviceAccess.h b/pus/Service2DeviceAccess.h index ecab6101..20fc30b9 100644 --- a/pus/Service2DeviceAccess.h +++ b/pus/Service2DeviceAccess.h @@ -14,12 +14,12 @@ * This service provides the capability to communicate with devices in their * native protocols with raw commands through the DeviceHandlerIF. * - * This is a gateway service. It relays device commands using the software bus. - * This service is very closely tied to the Commanding Service Base - * template class. There is constant interaction between this Service Base und - * a Subclass like this service + * This is a gateway service. It relays device commands to the software bus. + * This service is very closely tied to the CommandingServiceBase + * template class. + * * There are 4 adaption points for component implementation through the - * Commanding Service Base. + * CommandingServiceBase. * * This service employs custom subservices exclusively. This includes a * wiretapping subservice to monitor all traffic between target devices and @@ -37,11 +37,10 @@ class Service2DeviceAccess : public CommandingServiceBase, public: Service2DeviceAccess(object_id_t objectId, uint16_t apid, uint8_t serviceId, object_id_t tcSource, - object_id_t tmDestination); + object_id_t tmDestination, uint8_t numberOfParallelCommands = 4, + uint16_t commandTimeoutSeconds = 60); virtual ~Service2DeviceAccess(); - static constexpr uint8_t NUM_OF_PARALLEL_COMMANDS = 4; - static constexpr uint16_t COMMAND_TIMEOUT_SECONDS = 60; protected: //! CommandingServiceBase (CSB) abstract functions. See CSB documentation. ReturnValue_t isValidSubservice(uint8_t subservice) override; From 06d389ed1e6157f1fe736c5dacf121eec247ea14 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 7 Jul 2020 17:25:52 +0200 Subject: [PATCH 05/17] increased srv2 readability --- pus/Service2DeviceAccess.cpp | 24 ++++++------------------ pus/Service2DeviceAccess.h | 2 -- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/pus/Service2DeviceAccess.cpp b/pus/Service2DeviceAccess.cpp index d1f8faf3..ee48b46d 100644 --- a/pus/Service2DeviceAccess.cpp +++ b/pus/Service2DeviceAccess.cpp @@ -34,29 +34,17 @@ ReturnValue_t Service2DeviceAccess::isValidSubservice(uint8_t subservice) { ReturnValue_t Service2DeviceAccess::getMessageQueueAndObject( uint8_t subservice, const uint8_t* tcData, size_t tcDataLen, MessageQueueId_t* id, object_id_t* objectId) { - ReturnValue_t result = checkAndAcquireTargetID(objectId,tcData,tcDataLen); - if(result != HasReturnvaluesIF::RETURN_OK) { - return result; - } + if(tcDataLen < sizeof(object_id_t)) { + return CommandingServiceBase::INVALID_TC; + } + SerializeAdapter::deSerialize(objectId, &tcData, + &tcDataLen, SerializeIF::Endianness::BIG); - result = checkInterfaceAndAcquireMessageQueue(id,objectId); + ReturnValue_t result = checkInterfaceAndAcquireMessageQueue(id,objectId); return result; } -ReturnValue_t Service2DeviceAccess::checkAndAcquireTargetID( - object_id_t* objectIdToSet, const uint8_t* tcData, size_t tcDataLen) { - if(SerializeAdapter::deSerialize(objectIdToSet, &tcData, - &tcDataLen, SerializeIF::Endianness::BIG) != RETURN_OK) { - sif::error << "Service 2: Target ID not found. ID: " << - std::hex << objectIdToSet ; - return CommandingServiceBase::INVALID_TC; - } - else { - return HasReturnvaluesIF::RETURN_OK; - } -} - ReturnValue_t Service2DeviceAccess::checkInterfaceAndAcquireMessageQueue( MessageQueueId_t * messageQueueToSet, object_id_t *objectId) { DeviceHandlerIF* possibleTarget = diff --git a/pus/Service2DeviceAccess.h b/pus/Service2DeviceAccess.h index 20fc30b9..4dab0fa0 100644 --- a/pus/Service2DeviceAccess.h +++ b/pus/Service2DeviceAccess.h @@ -73,8 +73,6 @@ private: */ void sendWiretappingTm(CommandMessage* reply,uint8_t subservice); - ReturnValue_t checkAndAcquireTargetID(object_id_t* objectIdToSet, - const uint8_t* tcData, size_t tcDataLen); ReturnValue_t checkInterfaceAndAcquireMessageQueue( MessageQueueId_t* messageQueueToSet, object_id_t* objectId); From dd48f7ccadc824b275ea3bf2af0da1c9820ad61b Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 7 Jul 2020 17:28:00 +0200 Subject: [PATCH 06/17] some form improvements --- pus/Service2DeviceAccess.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pus/Service2DeviceAccess.cpp b/pus/Service2DeviceAccess.cpp index ee48b46d..391c1116 100644 --- a/pus/Service2DeviceAccess.cpp +++ b/pus/Service2DeviceAccess.cpp @@ -144,7 +144,7 @@ void Service2DeviceAccess::sendWiretappingTm(CommandMessage *reply, store_address_t storeAddress = DeviceHandlerMessage::getStoreAddress(reply); const uint8_t* data = nullptr; size_t size = 0; - ReturnValue_t result = IPCStore->getData(storeAddress,&data,&size); + ReturnValue_t result = IPCStore->getData(storeAddress, &data, &size); if(result != HasReturnvaluesIF::RETURN_OK){ sif::error << "Service2DeviceAccess::sendWiretappingTm: Data Lost in " "handleUnrequestedReply with failure ID "<< result @@ -157,8 +157,8 @@ void Service2DeviceAccess::sendWiretappingTm(CommandMessage *reply, WiretappingPacket TmPacket(DeviceHandlerMessage::getDeviceObjectId(reply), data); TmPacket.objectId = EndianConverter::convertBigEndian(TmPacket.objectId); - sendTmPacket(subservice,TmPacket.data,size,reinterpret_cast( - &TmPacket.objectId),sizeof(TmPacket.objectId)); + sendTmPacket(subservice, TmPacket.data,size, reinterpret_cast( + &TmPacket.objectId), sizeof(TmPacket.objectId)); } MessageQueueId_t Service2DeviceAccess::getDeviceQueue() { From 399fc0e287048b1fb8e1343185d637c78a791a80 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Tue, 7 Jul 2020 17:42:37 +0200 Subject: [PATCH 07/17] fifo replacements --- container/DynamicFIFO.h | 27 +++++++++++++++++++++++++ container/FIFO.h | 23 +++++++++------------ container/FIFOBase.h | 4 ---- container/SimpleRingBuffer.cpp | 6 +++--- container/SimpleRingBuffer.h | 2 +- container/StaticFIFO.h | 30 ---------------------------- tmtcservices/CommandingServiceBase.h | 4 ++-- tmtcservices/PusParser.cpp | 2 +- tmtcservices/PusParser.h | 7 +++---- tmtcservices/TmTcBridge.h | 4 ++-- 10 files changed, 48 insertions(+), 61 deletions(-) create mode 100644 container/DynamicFIFO.h delete mode 100644 container/StaticFIFO.h diff --git a/container/DynamicFIFO.h b/container/DynamicFIFO.h new file mode 100644 index 00000000..3a5242c7 --- /dev/null +++ b/container/DynamicFIFO.h @@ -0,0 +1,27 @@ +#ifndef FRAMEWORK_CONTAINER_DYNAMICFIFO_H_ +#define FRAMEWORK_CONTAINER_DYNAMICFIFO_H_ + +#include +#include + +/** + * @brief Simple First-In-First-Out data structure. The maximum size + * can be set in the constructor. + * @details + * The maximum capacity can be determined at run-time, so this container + * performs dynamic memory allocation! + * The public interface of FIFOBase exposes the user interface for the FIFO. + * @tparam T Entry Type + * @tparam capacity Maximum capacity + */ +template +class DynamicFIFO: public FIFOBase { +public: + DynamicFIFO(size_t maxCapacity): FIFOBase(values.data(), maxCapacity), + values(maxCapacity) {}; + +private: + std::vector values; +}; + +#endif /* FRAMEWORK_CONTAINER_DYNAMICFIFO_H_ */ diff --git a/container/FIFO.h b/container/FIFO.h index 19daaf1b..ecb218fd 100644 --- a/container/FIFO.h +++ b/container/FIFO.h @@ -1,31 +1,26 @@ #ifndef FRAMEWORK_CONTAINER_FIFO_H_ #define FRAMEWORK_CONTAINER_FIFO_H_ +#include #include -#include - -namespace fsfw { +#include /** - * @brief Simple First-In-First-Out data structure. The maximum size - * can be set in the constructor. + * @brief Simple First-In-First-Out data structure with size fixed at + * compile time * @details - * The maximum capacity can be determined at run-time, so this container - * performs dynamic memory allocation! + * Performs no dynamic memory allocation. * The public interface of FIFOBase exposes the user interface for the FIFO. * @tparam T Entry Type * @tparam capacity Maximum capacity */ -template +template class FIFO: public FIFOBase { public: - FIFO(size_t maxCapacity): FIFOBase(values.data(), maxCapacity), - values(maxCapacity) {}; + FIFO(): FIFOBase(values.data(), capacity) {}; private: - std::vector values; + std::array values; }; -} - -#endif /* FRAMEWORK_CONTAINER_FIFO_H_ */ +#endif /* FRAMEWORK_CONTAINERS_STATICFIFO_H_ */ diff --git a/container/FIFOBase.h b/container/FIFOBase.h index 6ed7d924..8bdb333f 100644 --- a/container/FIFOBase.h +++ b/container/FIFOBase.h @@ -4,8 +4,6 @@ #include #include -namespace fsfw { - template class FIFOBase { public: @@ -60,6 +58,4 @@ private: #include -} - #endif /* FRAMEWORK_CONTAINER_FIFOBASE_H_ */ diff --git a/container/SimpleRingBuffer.cpp b/container/SimpleRingBuffer.cpp index 4e50109b..731c9dc9 100644 --- a/container/SimpleRingBuffer.cpp +++ b/container/SimpleRingBuffer.cpp @@ -17,7 +17,7 @@ SimpleRingBuffer::~SimpleRingBuffer() { ReturnValue_t SimpleRingBuffer::writeData(const uint8_t* data, uint32_t amount) { - if (availableWriteSpace() >= amount || overwriteOld) { + if (availableWriteSpace() >= amount or overwriteOld) { uint32_t amountTillWrap = writeTillWrap(); if (amountTillWrap >= amount) { memcpy(&buffer[write], data, amount); @@ -43,7 +43,7 @@ ReturnValue_t SimpleRingBuffer::readData(uint8_t* data, uint32_t amount, return HasReturnvaluesIF::RETURN_FAILED; } } - if (trueAmount != NULL) { + if (trueAmount != nullptr) { *trueAmount = amount; } if (amountTillWrap >= amount) { @@ -65,7 +65,7 @@ ReturnValue_t SimpleRingBuffer::deleteData(uint32_t amount, return HasReturnvaluesIF::RETURN_FAILED; } } - if (trueAmount != NULL) { + if (trueAmount != nullptr) { *trueAmount = amount; } incrementRead(amount, READ_PTR); diff --git a/container/SimpleRingBuffer.h b/container/SimpleRingBuffer.h index b5bc2c1c..30dd184c 100644 --- a/container/SimpleRingBuffer.h +++ b/container/SimpleRingBuffer.h @@ -2,7 +2,7 @@ #define FRAMEWORK_CONTAINER_SIMPLERINGBUFFER_H_ #include -#include +#include /** * @brief Circular buffer implementation, useful for buffering diff --git a/container/StaticFIFO.h b/container/StaticFIFO.h deleted file mode 100644 index f3128200..00000000 --- a/container/StaticFIFO.h +++ /dev/null @@ -1,30 +0,0 @@ -#ifndef FRAMEWORK_CONTAINER_STATICFIFO_H_ -#define FRAMEWORK_CONTAINER_STATICFIFO_H_ - -#include -#include -#include - -namespace fsfw { - -/** - * @brief Simple First-In-First-Out data structure with size fixed at - * compile time - * @details - * Performs no dynamic memory allocation. - * The public interface of FIFOBase exposes the user interface for the FIFO. - * @tparam T Entry Type - * @tparam capacity Maximum capacity - */ -template -class StaticFIFO: public FIFOBase { -public: - StaticFIFO(): FIFOBase(values.data(), capacity) {}; - -private: - std::array values; -}; - -} - -#endif /* FRAMEWORK_CONTAINERS_STATICFIFO_H_ */ diff --git a/tmtcservices/CommandingServiceBase.h b/tmtcservices/CommandingServiceBase.h index 72fe13f2..700503c6 100644 --- a/tmtcservices/CommandingServiceBase.h +++ b/tmtcservices/CommandingServiceBase.h @@ -10,7 +10,7 @@ #include #include #include -#include +#include #include class TcPacketStored; @@ -199,7 +199,7 @@ protected: uint32_t state; Command_t command; object_id_t objectId; - fsfw::StaticFIFO fifo; + FIFO fifo; }; using CommandMapIter = FixedMap* PusParser::fifo(){ +DynamicFIFO* PusParser::fifo(){ return &indexSizePairFIFO; } diff --git a/tmtcservices/PusParser.h b/tmtcservices/PusParser.h index 82aff57e..88570bb2 100644 --- a/tmtcservices/PusParser.h +++ b/tmtcservices/PusParser.h @@ -1,8 +1,7 @@ #ifndef FRAMEWORK_TMTCSERVICES_PUSPARSER_H_ #define FRAMEWORK_TMTCSERVICES_PUSPARSER_H_ -#include - +#include #include #include @@ -55,7 +54,7 @@ public: * by the parsePusPackets() function. * @return */ - fsfw::FIFO* fifo(); + DynamicFIFO* fifo(); /** * Retrieve the next index and packet size pair from the FIFO. @@ -69,7 +68,7 @@ private: //! A FIFO is used to store information about multiple PUS packets //! inside the receive buffer. The maximum number of entries is defined //! by the first constructor argument. - fsfw::FIFO indexSizePairFIFO; + DynamicFIFO indexSizePairFIFO; bool storeSplitPackets = false; diff --git a/tmtcservices/TmTcBridge.h b/tmtcservices/TmTcBridge.h index 23f7dcfa..5b933c79 100644 --- a/tmtcservices/TmTcBridge.h +++ b/tmtcservices/TmTcBridge.h @@ -1,6 +1,7 @@ #ifndef FRAMEWORK_TMTCSERVICES_TMTCBRIDGE_H_ #define FRAMEWORK_TMTCSERVICES_TMTCBRIDGE_H_ +#include #include #include #include @@ -8,7 +9,6 @@ #include #include -#include class TmTcBridge : public AcceptsTelemetryIF, public ExecutableObjectIF, @@ -143,7 +143,7 @@ protected: * This fifo can be used to store downlink data * which can not be sent at the moment. */ - fsfw::StaticFIFO tmFifo; + FIFO tmFifo; uint8_t sentPacketsPerCycle = DEFAULT_STORED_DATA_SENT_PER_CYCLE; uint8_t maxNumberOfPacketsStored = DEFAULT_DOWNLINK_PACKETS_STORED; }; From 2efcda735f84166665c2c1b42dc604048a7bbb34 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 8 Jul 2020 02:20:38 +0200 Subject: [PATCH 08/17] message arriving. big clean up in tcdistribution folder --- osal/linux/TcUnixUdpPollingTask.cpp | 73 +++++++++++----- osal/linux/TcUnixUdpPollingTask.h | 13 ++- osal/linux/TmTcUnixUdpBridge.cpp | 15 ++-- osal/linux/TmTcUnixUdpBridge.h | 2 +- tcdistribution/CCSDSDistributor.cpp | 39 +++++---- tcdistribution/CCSDSDistributor.h | 87 ++++++++++--------- tcdistribution/PUSDistributor.cpp | 4 +- tcdistribution/PUSDistributor.h | 52 +++++++----- tcdistribution/TcDistributor.cpp | 5 +- tcdistribution/TcDistributor.h | 124 ++++++++++++++-------------- tmtcservices/PusServiceBase.cpp | 11 ++- tmtcservices/TmTcBridge.h | 2 +- 12 files changed, 253 insertions(+), 174 deletions(-) diff --git a/osal/linux/TcUnixUdpPollingTask.cpp b/osal/linux/TcUnixUdpPollingTask.cpp index f237a0f2..83f7a3da 100644 --- a/osal/linux/TcUnixUdpPollingTask.cpp +++ b/osal/linux/TcUnixUdpPollingTask.cpp @@ -1,6 +1,7 @@ #include +#include -TcSocketPollingTask::TcSocketPollingTask(object_id_t objectId, +TcUnixUdpPollingTask::TcUnixUdpPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge, size_t frameSize, double timeoutSeconds): SystemObject(objectId), tmtcBridgeId(tmtcUnixUdpBridge) { @@ -23,23 +24,13 @@ TcSocketPollingTask::TcSocketPollingTask(object_id_t objectId, else { receptionTimeout = timevalOperations::toTimeval(timeoutSeconds); } - - // Set receive timeout. - int result = setsockopt(serverUdpSocket, SOL_SOCKET, SO_RCVTIMEO, - &receptionTimeout, sizeof(receptionTimeout)); - if(result == -1) { - sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting receive" - "timeout failed with " << strerror(errno) << std::endl; - return; - } } -TcSocketPollingTask::~TcSocketPollingTask() { +TcUnixUdpPollingTask::~TcUnixUdpPollingTask() { } -ReturnValue_t TcSocketPollingTask::performOperation(uint8_t opCode) { - // Poll for new data permanently. The call will block until the specified - // length of bytes has been received or a timeout occured. +ReturnValue_t TcUnixUdpPollingTask::performOperation(uint8_t opCode) { + // Poll for new UDP datagrams in permanent loop. while(1) { //! Sender Address is cached here. struct sockaddr_in senderAddress; @@ -48,21 +39,34 @@ ReturnValue_t TcSocketPollingTask::performOperation(uint8_t opCode) { receptionBuffer.data(), frameSize, receptionFlags, reinterpret_cast(&senderAddress), &senderSockLen); if(bytesReceived < 0) { - //handle error + // handle error sif::error << "TcSocketPollingTask::performOperation: recvfrom " "failed with " << strerror(errno) << std::endl; + if(errno == EAGAIN or errno == EWOULDBLOCK) { + sif::info << "timeout" << std::endl; + } continue; } sif::debug << "TcSocketPollingTask::performOperation: " << bytesReceived << " bytes received" << std::endl; - ReturnValue_t result = handleSuccessfullTcRead(); + ReturnValue_t result = handleSuccessfullTcRead(bytesReceived); + if(result != HasReturnvaluesIF::RETURN_FAILED) { + + } tmtcBridge->checkAndSetClientAddress(senderAddress); } return HasReturnvaluesIF::RETURN_OK; } -ReturnValue_t TcSocketPollingTask::initialize() { +ReturnValue_t TcUnixUdpPollingTask::initialize() { + tcStore = objectManager->get(objects::TC_STORE); + if (tcStore == nullptr) { + sif::error << "TcSerialPollingTask::initialize: TC Store uninitialized!" + << std::endl; + return ObjectManagerIF::CHILD_INIT_FAILED; + } + tmtcBridge = objectManager->get(tmtcBridgeId); if(tmtcBridge == nullptr) { sif::error << "TcSocketPollingTask::TcSocketPollingTask: Invalid" @@ -70,10 +74,41 @@ ReturnValue_t TcSocketPollingTask::initialize() { return ObjectManagerIF::CHILD_INIT_FAILED; } + targetTcDestination = tmtcBridge->getReportReceptionQueue(); + serverUdpSocket = tmtcBridge->serverSocket; + + // Set receive timeout. +// int result = setsockopt(serverUdpSocket, SOL_SOCKET, SO_RCVTIMEO, +// &receptionTimeout, sizeof(receptionTimeout)); +// if(result == -1) { +// sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting " +// "receive timeout failed with " << strerror(errno) << std::endl; +// return ObjectManagerIF::CHILD_INIT_FAILED; +// } return HasReturnvaluesIF::RETURN_OK; } -ReturnValue_t TcSocketPollingTask::handleSuccessfullTcRead() { - return HasReturnvaluesIF::RETURN_OK; +ReturnValue_t TcUnixUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) { + store_address_t storeId = 0; + ReturnValue_t result = tcStore->addData(&storeId, + receptionBuffer.data(), bytesRead); + // arrayprinter::print(receptionBuffer.data(), bytesRead); + if (result != HasReturnvaluesIF::RETURN_OK) { + sif::debug << "TcSerialPollingTask::transferPusToSoftwareBus: Data " + "storage failed" << std::endl; + sif::debug << "Packet size: " << bytesRead << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + TmTcMessage message(storeId); + result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message); + if (result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "Serial Polling: Sending message to queue failed" + << std::endl; + tcStore->deleteData(storeId); + } + return result; } + + diff --git a/osal/linux/TcUnixUdpPollingTask.h b/osal/linux/TcUnixUdpPollingTask.h index a6b0e9d4..3503d505 100644 --- a/osal/linux/TcUnixUdpPollingTask.h +++ b/osal/linux/TcUnixUdpPollingTask.h @@ -1,5 +1,6 @@ #ifndef FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ #define FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ + #include #include #include @@ -16,7 +17,7 @@ * This class caches the IP address of the sender. It is assumed there * is only one sender for now. */ -class TcSocketPollingTask: public SystemObject, +class TcUnixUdpPollingTask: public SystemObject, public ExecutableObjectIF { friend class TmTcUnixUdpBridge; public: @@ -24,17 +25,21 @@ public: //! 0.5 default milliseconds timeout for now. static constexpr timeval DEFAULT_TIMEOUT = {.tv_sec = 0, .tv_usec = 500}; - TcSocketPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge, + TcUnixUdpPollingTask(object_id_t objectId, object_id_t tmtcUnixUdpBridge, size_t frameSize = 0, double timeoutSeconds = -1); - virtual~ TcSocketPollingTask(); + virtual~ TcUnixUdpPollingTask(); virtual ReturnValue_t performOperation(uint8_t opCode) override; virtual ReturnValue_t initialize() override; +protected: + StorageManagerIF* tcStore = nullptr; + private: //! TMTC bridge is cached. object_id_t tmtcBridgeId = objects::NO_OBJECT; TmTcUnixUdpBridge* tmtcBridge = nullptr; + MessageQueueId_t targetTcDestination = MessageQueueIF::NO_QUEUE; //! Reception flags: https://linux.die.net/man/2/recvfrom. int receptionFlags = 0; @@ -47,7 +52,7 @@ private: size_t frameSize = 0; timeval receptionTimeout; - ReturnValue_t handleSuccessfullTcRead(); + ReturnValue_t handleSuccessfullTcRead(size_t bytesRead); }; diff --git a/osal/linux/TmTcUnixUdpBridge.cpp b/osal/linux/TmTcUnixUdpBridge.cpp index 710761b4..a337b8ae 100644 --- a/osal/linux/TmTcUnixUdpBridge.cpp +++ b/osal/linux/TmTcUnixUdpBridge.cpp @@ -101,7 +101,7 @@ void TmTcUnixUdpBridge::checkAndSetClientAddress(sockaddr_in newAddress) { void TmTcUnixUdpBridge::handleBindError() { // See: https://man7.org/linux/man-pages/man2/bind.2.html switch(errno) { - case(EACCES): + case(EACCES): { /* Ephermeral ports can be shown with following command: sysctl -A | grep ip_local_port_range @@ -110,7 +110,8 @@ void TmTcUnixUdpBridge::handleBindError() { "Ports 1-1024 are reserved on UNIX systems and require root " "rights while ephermeral ports should not be used as well." << std::endl; - break; + } + break; case(EADDRINUSE): case(EBADF): case(EINVAL): @@ -122,15 +123,17 @@ void TmTcUnixUdpBridge::handleBindError() { case(ENOENT): case(ENOMEM): case(ENOTDIR): - case(EROFS): + case(EROFS): { sif::error << "TmTcUnixBridge::TmTcUnixBridge: Socket creation failed" - << " with " << strerror(errno) << std::endl; + << " with " << strerror(errno) << std::endl; break; - default: + } + default: { sif::error << "TmTcUnixBridge::TmTcUnixBridge: Unknown error" - << std::endl; + << std::endl; break; } + } } diff --git a/osal/linux/TmTcUnixUdpBridge.h b/osal/linux/TmTcUnixUdpBridge.h index 15d256cd..2fb606b0 100644 --- a/osal/linux/TmTcUnixUdpBridge.h +++ b/osal/linux/TmTcUnixUdpBridge.h @@ -7,7 +7,7 @@ #include class TmTcUnixUdpBridge: public TmTcBridge { - friend class TcSocketPollingTask; + friend class TcUnixUdpPollingTask; public: // The ports chosen here should not be used by any other process. // List of used ports on Linux: /etc/services diff --git a/tcdistribution/CCSDSDistributor.cpp b/tcdistribution/CCSDSDistributor.cpp index 878b8f7d..199e2ed1 100644 --- a/tcdistribution/CCSDSDistributor.cpp +++ b/tcdistribution/CCSDSDistributor.cpp @@ -2,30 +2,37 @@ #include #include -CCSDSDistributor::CCSDSDistributor( uint16_t setDefaultApid, object_id_t setObjectId ) : - TcDistributor( setObjectId ), default_apid( setDefaultApid ), tcStore(NULL) { +CCSDSDistributor::CCSDSDistributor(uint16_t setDefaultApid, + object_id_t setObjectId): + TcDistributor(setObjectId), defaultApid( setDefaultApid ) { } -CCSDSDistributor::~CCSDSDistributor() { +CCSDSDistributor::~CCSDSDistributor() {} -} - -iterator_t CCSDSDistributor::selectDestination() { -// debug << "CCSDSDistributor::selectDestination received: " << this->currentMessage.getStorageId().pool_index << ", " << this->currentMessage.getStorageId().packet_index << std::endl; - const uint8_t* p_packet = NULL; +TcDistributor::TcMessageQueueMapIter CCSDSDistributor::selectDestination() { +// sif::debug << "CCSDSDistributor::selectDestination received: " << +// this->currentMessage.getStorageId().pool_index << ", " << +// this->currentMessage.getStorageId().packet_index << std::endl; + const uint8_t* packet = nullptr; size_t size = 0; - //TODO check returncode? - this->tcStore->getData( this->currentMessage.getStorageId(), &p_packet, &size ); - SpacePacketBase current_packet( p_packet ); -// info << "CCSDSDistributor::selectDestination has packet with APID " << std::hex << current_packet.getAPID() << std::dec << std::endl; - iterator_t position = this->queueMap.find( current_packet.getAPID() ); + ReturnValue_t result = this->tcStore->getData(currentMessage.getStorageId(), + &packet, &size ); + if(result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "CCSDSDistributor::selectDestination: Getting data from" + "store failed!" << std::endl; + } + SpacePacketBase currentPacket(packet); + +// sif:: info << "CCSDSDistributor::selectDestination has packet with APID " +// << std::hex << currentPacket.getAPID() << std::dec << std::endl; + TcMessageQueueMapIter position = this->queueMap.find(currentPacket.getAPID()); if ( position != this->queueMap.end() ) { return position; } else { - //The APID was not found. Forward packet to main SW-APID anyway to create acceptance failure report. - return this->queueMap.find( this->default_apid ); + //The APID was not found. Forward packet to main SW-APID anyway to + // create acceptance failure report. + return this->queueMap.find( this->defaultApid ); } - } MessageQueueId_t CCSDSDistributor::getRequestQueue() { diff --git a/tcdistribution/CCSDSDistributor.h b/tcdistribution/CCSDSDistributor.h index 9dce34f2..22025f76 100644 --- a/tcdistribution/CCSDSDistributor.h +++ b/tcdistribution/CCSDSDistributor.h @@ -1,58 +1,69 @@ -#ifndef CCSDSDISTRIBUTOR_H_ -#define CCSDSDISTRIBUTOR_H_ +#ifndef FRAMEWORK_TCDISTRIBUTION_CCSDSDISTRIBUTOR_H_ +#define FRAMEWORK_TCDISTRIBUTION_CCSDSDISTRIBUTOR_H_ #include #include #include #include #include + /** - * An instantiation of the CCSDSDistributorIF. - * It receives Space Packets, and selects a destination depending on the APID of the telecommands. + * @brief An instantiation of the CCSDSDistributorIF. + * @details + * It receives Space Packets, and selects a destination depending on the + * APID of the telecommands. * The Secondary Header (with Service/Subservice) is ignored. - * \ingroup tc_distribution + * @ingroup tc_distribution */ -class CCSDSDistributor : public TcDistributor, public CCSDSDistributorIF, public AcceptsTelecommandsIF { -protected: - /** - * This implementation checks if an Application with fitting APID has registered and forwards the - * packet to the according message queue. - * If the packet is not found, it returns the queue to \c default_apid, where a Acceptance Failure - * message should be generated. - * @return Iterator to map entry of found APID or iterator to default APID. - */ - iterator_t selectDestination(); - /** - * The default APID, where packets with unknown APID are sent to. - */ - uint16_t default_apid; - /** - * A reference to the TC storage must be maintained, as this class handles pure Space Packets and there - * exists no SpacePacketStored class. - */ - StorageManagerIF* tcStore; - /** - * The callback here handles the generation of acceptance success/failure messages. - */ - ReturnValue_t callbackAfterSending( ReturnValue_t queueStatus ); +class CCSDSDistributor : public TcDistributor, + public CCSDSDistributorIF, + public AcceptsTelecommandsIF { public: /** - * The constructor sets the default APID and calls the TcDistributor ctor with a certain object id. - * \c tcStore is set in the \c initialize method. - * @param set_default_apid The default APID, where packets with unknown destination are sent to. + * @brief The constructor sets the default APID and calls the + * TcDistributor ctor with a certain object id. + * @details + * @c tcStore is set in the @c initialize method. + * @param set_default_apid The default APID, where packets with unknown + * destination are sent to. */ CCSDSDistributor( uint16_t setDefaultApid, object_id_t setObjectId ); /** * The destructor is empty. */ ~CCSDSDistributor(); - MessageQueueId_t getRequestQueue(); - ReturnValue_t registerApplication( uint16_t apid, MessageQueueId_t id ); - ReturnValue_t registerApplication( AcceptsTelecommandsIF* application ); + + MessageQueueId_t getRequestQueue() override; + ReturnValue_t registerApplication( uint16_t apid, + MessageQueueId_t id) override; + ReturnValue_t registerApplication( + AcceptsTelecommandsIF* application) override; uint16_t getIdentifier(); - ReturnValue_t initialize(); + ReturnValue_t initialize() override; + +protected: + /** + * This implementation checks if an application with fitting APID has + * registered and forwards the packet to the according message queue. + * If the packet is not found, it returns the queue to @c defaultApid, + * where a Acceptance Failure message should be generated. + * @return Iterator to map entry of found APID or iterator to default APID. + */ + TcMessageQueueMapIter selectDestination(); + /** + * The default APID, where packets with unknown APID are sent to. + */ + uint16_t defaultApid; + /** + * A reference to the TC storage must be maintained, as this class handles + * pure Space Packets and there exists no SpacePacketStored class. + */ + StorageManagerIF* tcStore = nullptr; + /** + * The callback here handles the generation of acceptance + * success/failure messages. + */ + ReturnValue_t callbackAfterSending( ReturnValue_t queueStatus ); }; - - -#endif /* CCSDSDISTRIBUTOR_H_ */ +#endif /* FRAMEWORK_TCDISTRIBUTION_CCSDSDISTRIBUTOR_H_ */ diff --git a/tcdistribution/PUSDistributor.cpp b/tcdistribution/PUSDistributor.cpp index bcf6d571..f13b5f8d 100644 --- a/tcdistribution/PUSDistributor.cpp +++ b/tcdistribution/PUSDistributor.cpp @@ -12,9 +12,9 @@ PUSDistributor::PUSDistributor(uint16_t setApid, object_id_t setObjectId, PUSDistributor::~PUSDistributor() {} -iterator_t PUSDistributor::selectDestination() { +TcDistributor::TcMessageQueueMapIter PUSDistributor::selectDestination() { // debug << "PUSDistributor::handlePacket received: " << this->current_packet_id.store_index << ", " << this->current_packet_id.packet_index << std::endl; - iterator_t queueMapIt = this->queueMap.end(); + TcMessageQueueMapIter queueMapIt = this->queueMap.end(); this->currentPacket.setStoreAddress(this->currentMessage.getStorageId()); if (currentPacket.getWholeData() != NULL) { tcStatus = checker.checkPacket(¤tPacket); diff --git a/tcdistribution/PUSDistributor.h b/tcdistribution/PUSDistributor.h index 8d774662..3d6717bd 100644 --- a/tcdistribution/PUSDistributor.h +++ b/tcdistribution/PUSDistributor.h @@ -1,5 +1,5 @@ -#ifndef PUSDISTRIBUTOR_H_ -#define PUSDISTRIBUTOR_H_ +#ifndef FRAMEWORK_TCDISTRIBUTION_PUSDISTRIBUTOR_H_ +#define FRAMEWORK_TCDISTRIBUTION_PUSDISTRIBUTOR_H_ #include #include @@ -9,37 +9,42 @@ #include /** - * This class accepts PUS Telecommands and forwards them to Application services. - * In addition, the class performs a formal packet check and sends acceptance success - * or failure messages. - * \ingroup tc_distribution + * This class accepts PUS Telecommands and forwards them to Application + * services. In addition, the class performs a formal packet check and + * sends acceptance success or failure messages. + * @ingroup tc_distribution */ class PUSDistributor: public TcDistributor, public PUSDistributorIF, public AcceptsTelecommandsIF { public: /** - * The ctor passes \c set_apid to the checker class and calls the TcDistribution ctor with a certain object id. + * The ctor passes @c set_apid to the checker class and calls the + * TcDistribution ctor with a certain object id. * @param setApid The APID of this receiving Application. * @param setObjectId Object ID of the distributor itself - * @param setPacketSource Object ID of the source of TC packets. Must implement CCSDSDistributorIF. + * @param setPacketSource Object ID of the source of TC packets. + * Must implement CCSDSDistributorIF. */ - PUSDistributor(uint16_t setApid, object_id_t setObjectId, object_id_t setPacketSource); + PUSDistributor(uint16_t setApid, object_id_t setObjectId, + object_id_t setPacketSource); /** * The destructor is empty. */ virtual ~PUSDistributor(); - ReturnValue_t registerService(AcceptsTelecommandsIF* service); - MessageQueueId_t getRequestQueue(); - uint16_t getIdentifier(); - ReturnValue_t initialize(); + ReturnValue_t registerService(AcceptsTelecommandsIF* service) override; + MessageQueueId_t getRequestQueue() override; + ReturnValue_t initialize() override; + uint16_t getIdentifier() override; + protected: /** * This attribute contains the class, that performs a formal packet check. */ TcPacketCheck checker; /** - * With this class, verification messages are sent to the TC Verification service. + * With this class, verification messages are sent to the + * TC Verification service. */ VerificationReporter verifyChannel; /** @@ -47,21 +52,26 @@ protected: */ TcPacketStored currentPacket; /** - * With this variable, the current check status is stored to generate acceptance messages later. + * With this variable, the current check status is stored to generate + * acceptance messages later. */ ReturnValue_t tcStatus; const object_id_t packetSource; /** - * This method reads the packet service, checks if such a service is registered and forwards the packet to the destination. - * It also initiates the formal packet check and sending of verification messages. - * @return Iterator to map entry of found service id or iterator to \c map.end(). + * This method reads the packet service, checks if such a service is + * registered and forwards the packet to the destination. + * It also initiates the formal packet check and sending of verification + * messages. + * @return Iterator to map entry of found service id + * or iterator to @c map.end(). */ - iterator_t selectDestination(); + TcMessageQueueMapIter selectDestination(); /** - * The callback here handles the generation of acceptance success/failure messages. + * The callback here handles the generation of acceptance + * success/failure messages. */ ReturnValue_t callbackAfterSending(ReturnValue_t queueStatus); }; -#endif /* PUSDISTRIBUTOR_H_ */ +#endif /* FRAMEWORK_TCDISTRIBUTION_PUSDISTRIBUTOR_H_ */ diff --git a/tcdistribution/TcDistributor.cpp b/tcdistribution/TcDistributor.cpp index 57921459..7bebbb9c 100644 --- a/tcdistribution/TcDistributor.cpp +++ b/tcdistribution/TcDistributor.cpp @@ -15,7 +15,6 @@ TcDistributor::~TcDistributor() { ReturnValue_t TcDistributor::performOperation(uint8_t opCode) { ReturnValue_t status = RETURN_OK; -// debug << "TcDistributor: performing Operation." << std::endl; for (status = tcQueue->receiveMessage(¤tMessage); status == RETURN_OK; status = tcQueue->receiveMessage(¤tMessage)) { status = handlePacket(); @@ -29,7 +28,7 @@ ReturnValue_t TcDistributor::performOperation(uint8_t opCode) { ReturnValue_t TcDistributor::handlePacket() { - iterator_t queueMapIt = this->selectDestination(); + TcMessageQueueMapIter queueMapIt = this->selectDestination(); ReturnValue_t returnValue = RETURN_FAILED; if (queueMapIt != this->queueMap.end()) { returnValue = this->tcQueue->sendMessage(queueMapIt->second, @@ -41,7 +40,7 @@ ReturnValue_t TcDistributor::handlePacket() { void TcDistributor::print() { sif::debug << "Distributor content is: " << std::endl << "ID\t| message queue id" << std::endl; - for (iterator_t it = this->queueMap.begin(); it != this->queueMap.end(); + for (TcMessageQueueMapIter it = this->queueMap.begin(); it != this->queueMap.end(); it++) { sif::debug << it->first << "\t| 0x" << std::hex << it->second << std::dec << std::endl; diff --git a/tcdistribution/TcDistributor.h b/tcdistribution/TcDistributor.h index b80f08e6..5c958de0 100644 --- a/tcdistribution/TcDistributor.h +++ b/tcdistribution/TcDistributor.h @@ -1,5 +1,6 @@ -#ifndef TCDISTRIBUTOR_H_ -#define TCDISTRIBUTOR_H_ +#ifndef FRAMEWORK_TMTCSERVICES_TCDISTRIBUTOR_H_ +#define FRAMEWORK_TMTCSERVICES_TCDISTRIBUTOR_H_ + #include #include #include @@ -9,16 +10,12 @@ #include #include - /** - * \defgroup tc_distribution Telecommand Distribution - * All classes associated with Routing and Distribution of Telecommands belong to this group. + * @defgroup tc_distribution Telecommand Distribution + * All classes associated with Routing and Distribution of Telecommands + * belong to this group. */ -/** - * This typedef simplifies writing down the \c map iterator. - */ -typedef std::map::iterator iterator_t; /** * This is the base class to implement distributors for Space Packets. @@ -28,59 +25,15 @@ typedef std::map::iterator iterator_t; * message queue ids to some identifier. The process of unpacking the * destination information from the packet is handled by the child class * implementations. - * \ingroup tc_distribution + * @ingroup tc_distribution */ -class TcDistributor : public SystemObject, public ExecutableObjectIF, public HasReturnvaluesIF { -private: - /** - * This constant sets the maximum number of packets distributed per call. - */ - static const uint8_t DISTRIBUTER_MAX_PACKETS = 128; -protected: - /** - * This is the receiving queue for incoming Telecommands. - * The child classes must make its queue id public. - */ - MessageQueueIF* tcQueue; - /** - * The last received incoming packet information is stored in this - * member. - * As different child classes unpack the incoming packet differently - * (i.e. as a CCSDS Space Packet or as a PUS Telecommand Packet), it - * is not tried to unpack the packet information within this class. - */ - TmTcMessage currentMessage; - /** - * The map that links certain packet information to a destination. - * The packet information may be the APID of the packet or the service - * identifier. Filling of the map is under control of the different child - * classes. - */ - std::map queueMap; - /** - * This method shall unpack the routing information from the incoming - * packet and select the map entry which represents the packet's target. - * @return An iterator to the map element to forward to or queuMap.end(). - */ - virtual iterator_t selectDestination() = 0; - /** - * The handlePacket method calls the child class's selectDestination method - * and forwards the packet to its destination, if found. - * @return The message queue return value or \c RETURN_FAILED, in case no - * destination was found. - */ - ReturnValue_t handlePacket(); - /** - * This method gives the child class a chance to perform some kind of operation - * after the parent tried to forward the message. - * A typically application would be sending success/failure messages. - * The default implementation just returns \c RETURN_OK. - * @param queueStatus The status of the message queue after an attempt to send the TC. - * @return - \c RETURN_OK on success - * - \c RETURN_FAILED on failure - */ - virtual ReturnValue_t callbackAfterSending( ReturnValue_t queueStatus ); +class TcDistributor : public SystemObject, + public ExecutableObjectIF, + public HasReturnvaluesIF { public: + using TcMessageQueueMap = std::map; + using TcMessageQueueMapIter = std::map::iterator; + static const uint8_t INTERFACE_ID = CLASS_ID::PACKET_DISTRIBUTION; static const ReturnValue_t PACKET_LOST = MAKE_RETURN_CODE( 1 ); static const ReturnValue_t DESTINATION_NOT_FOUND = MAKE_RETURN_CODE( 2 ); @@ -110,6 +63,57 @@ public: * queueMap. */ void print(); + +protected: + /** + * This is the receiving queue for incoming Telecommands. + * The child classes must make its queue id public. + */ + MessageQueueIF* tcQueue; + /** + * The last received incoming packet information is stored in this + * member. + * As different child classes unpack the incoming packet differently + * (i.e. as a CCSDS Space Packet or as a PUS Telecommand Packet), it + * is not tried to unpack the packet information within this class. + */ + TmTcMessage currentMessage; + /** + * The map that links certain packet information to a destination. + * The packet information may be the APID of the packet or the service + * identifier. Filling of the map is under control of the different child + * classes. + */ + TcMessageQueueMap queueMap; + /** + * This method shall unpack the routing information from the incoming + * packet and select the map entry which represents the packet's target. + * @return An iterator to the map element to forward to or queuMap.end(). + */ + virtual TcMessageQueueMapIter selectDestination() = 0; + /** + * The handlePacket method calls the child class's selectDestination method + * and forwards the packet to its destination, if found. + * @return The message queue return value or \c RETURN_FAILED, in case no + * destination was found. + */ + ReturnValue_t handlePacket(); + /** + * This method gives the child class a chance to perform some kind of operation + * after the parent tried to forward the message. + * A typically application would be sending success/failure messages. + * The default implementation just returns \c RETURN_OK. + * @param queueStatus The status of the message queue after an attempt to send the TC. + * @return - \c RETURN_OK on success + * - \c RETURN_FAILED on failure + */ + virtual ReturnValue_t callbackAfterSending( ReturnValue_t queueStatus ); + +private: + /** + * This constant sets the maximum number of packets distributed per call. + */ + static const uint8_t DISTRIBUTER_MAX_PACKETS = 128; }; diff --git a/tmtcservices/PusServiceBase.cpp b/tmtcservices/PusServiceBase.cpp index 82e5ff5c..cb1e633f 100644 --- a/tmtcservices/PusServiceBase.cpp +++ b/tmtcservices/PusServiceBase.cpp @@ -41,9 +41,14 @@ void PusServiceBase::handleRequestQueue() { ReturnValue_t result = RETURN_FAILED; for (uint8_t count = 0; count < PUS_SERVICE_MAX_RECEPTION; count++) { ReturnValue_t status = this->requestQueue->receiveMessage(&message); - // debug << "PusServiceBase::performOperation: Receiving from MQ ID: " - // << std::hex << this->requestQueue.getId() - // << std::dec << " returned: " << status << std::endl; +// if(status != MessageQueueIF::EMPTY) { +// sif::debug << "PusServiceBase::performOperation: Receiving from " +// << "MQ ID: " << std::hex << "0x" << std::setw(8) +// << std::setfill('0') << this->requestQueue->getId() +// << std::dec << " returned: " << status << std::setfill(' ') +// << std::endl; +// } + if (status == RETURN_OK) { this->currentPacket.setStoreAddress(message.getStorageId()); //info << "Service " << (uint16_t) this->serviceId << diff --git a/tmtcservices/TmTcBridge.h b/tmtcservices/TmTcBridge.h index 5b933c79..a009c962 100644 --- a/tmtcservices/TmTcBridge.h +++ b/tmtcservices/TmTcBridge.h @@ -62,7 +62,7 @@ public: * @param virtualChannel * @return */ - MessageQueueId_t getReportReceptionQueue( + virtual MessageQueueId_t getReportReceptionQueue( uint8_t virtualChannel = 0) override; protected: //! Used to send and receive TMTC messages. From 264914e86a1b9a2854dbc8d83ed96445a1255482 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 8 Jul 2020 03:18:09 +0200 Subject: [PATCH 09/17] tmtcbridge tweaks. UDP bridge now working :-D --- osal/linux/MessageQueue.cpp | 8 ++-- osal/linux/PeriodicPosixTask.cpp | 8 ++-- osal/linux/TcUnixUdpPollingTask.cpp | 69 ++++++++++++++++------------ osal/linux/TcUnixUdpPollingTask.h | 8 ++++ osal/linux/TmTcUnixUdpBridge.cpp | 43 +++++++---------- osal/linux/TmTcUnixUdpBridge.h | 7 +-- tcdistribution/CCSDSDistributor.cpp | 4 +- tcdistribution/CCSDSDistributor.h | 8 ++-- tcdistribution/PUSDistributor.cpp | 4 +- tcdistribution/PUSDistributor.h | 2 +- tcdistribution/TcDistributor.cpp | 4 +- tcdistribution/TcDistributor.h | 4 +- tmtcservices/AcceptsTelecommandsIF.h | 10 ++-- tmtcservices/TmTcBridge.cpp | 26 +++++++---- tmtcservices/TmTcBridge.h | 34 ++++++-------- 15 files changed, 121 insertions(+), 118 deletions(-) diff --git a/osal/linux/MessageQueue.cpp b/osal/linux/MessageQueue.cpp index ce1da17c..153f43d3 100644 --- a/osal/linux/MessageQueue.cpp +++ b/osal/linux/MessageQueue.cpp @@ -155,10 +155,10 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessageIF* message) { } if(message->getMaximumMessageSize() < maxMessageSize) { - sif::error << "MessageQueue::receiveMessage: Message size " - << message->getMaximumMessageSize() << - " too small to receive data!" << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; + sif::error << "MessageQueue::receiveMessage: Message size " + << message->getMaximumMessageSize() + << " too small to receive data!" << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; } unsigned int messagePriority = 0; diff --git a/osal/linux/PeriodicPosixTask.cpp b/osal/linux/PeriodicPosixTask.cpp index b811274b..4b0c77fc 100644 --- a/osal/linux/PeriodicPosixTask.cpp +++ b/osal/linux/PeriodicPosixTask.cpp @@ -68,12 +68,12 @@ void PeriodicPosixTask::taskFunctionality(void) { char name[20] = {0}; int status = pthread_getname_np(pthread_self(),name,sizeof(name)); if(status == 0){ - sif::error << "PeriodicPosixTask " << name << ": Deadline " - "missed." << std::endl; + //sif::error << "PeriodicPosixTask " << name << ": Deadline " + // "missed." << std::endl; } else { - sif::error << "PeriodicPosixTask X: Deadline missed. " << - status << std::endl; + //sif::error << "PeriodicPosixTask X: Deadline missed. " << + // status << std::endl; } if (this->deadlineMissedFunc != nullptr) { this->deadlineMissedFunc(); diff --git a/osal/linux/TcUnixUdpPollingTask.cpp b/osal/linux/TcUnixUdpPollingTask.cpp index 83f7a3da..97fbd044 100644 --- a/osal/linux/TcUnixUdpPollingTask.cpp +++ b/osal/linux/TcUnixUdpPollingTask.cpp @@ -26,8 +26,7 @@ TcUnixUdpPollingTask::TcUnixUdpPollingTask(object_id_t objectId, } } -TcUnixUdpPollingTask::~TcUnixUdpPollingTask() { -} +TcUnixUdpPollingTask::~TcUnixUdpPollingTask() {} ReturnValue_t TcUnixUdpPollingTask::performOperation(uint8_t opCode) { // Poll for new UDP datagrams in permanent loop. @@ -59,6 +58,30 @@ ReturnValue_t TcUnixUdpPollingTask::performOperation(uint8_t opCode) { return HasReturnvaluesIF::RETURN_OK; } + +ReturnValue_t TcUnixUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) { + store_address_t storeId = 0; + ReturnValue_t result = tcStore->addData(&storeId, + receptionBuffer.data(), bytesRead); + // arrayprinter::print(receptionBuffer.data(), bytesRead); + if (result != HasReturnvaluesIF::RETURN_OK) { + sif::debug << "TcSerialPollingTask::transferPusToSoftwareBus: Data " + "storage failed" << std::endl; + sif::debug << "Packet size: " << bytesRead << std::endl; + return HasReturnvaluesIF::RETURN_FAILED; + } + + TmTcMessage message(storeId); + + result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message); + if (result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "Serial Polling: Sending message to queue failed" + << std::endl; + tcStore->deleteData(storeId); + } + return result; +} + ReturnValue_t TcUnixUdpPollingTask::initialize() { tcStore = objectManager->get(objects::TC_STORE); if (tcStore == nullptr) { @@ -74,41 +97,27 @@ ReturnValue_t TcUnixUdpPollingTask::initialize() { return ObjectManagerIF::CHILD_INIT_FAILED; } - targetTcDestination = tmtcBridge->getReportReceptionQueue(); - serverUdpSocket = tmtcBridge->serverSocket; - // Set receive timeout. -// int result = setsockopt(serverUdpSocket, SOL_SOCKET, SO_RCVTIMEO, -// &receptionTimeout, sizeof(receptionTimeout)); -// if(result == -1) { -// sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting " -// "receive timeout failed with " << strerror(errno) << std::endl; -// return ObjectManagerIF::CHILD_INIT_FAILED; -// } return HasReturnvaluesIF::RETURN_OK; } -ReturnValue_t TcUnixUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) { - store_address_t storeId = 0; - ReturnValue_t result = tcStore->addData(&storeId, - receptionBuffer.data(), bytesRead); - // arrayprinter::print(receptionBuffer.data(), bytesRead); - if (result != HasReturnvaluesIF::RETURN_OK) { - sif::debug << "TcSerialPollingTask::transferPusToSoftwareBus: Data " - "storage failed" << std::endl; - sif::debug << "Packet size: " << bytesRead << std::endl; - return HasReturnvaluesIF::RETURN_FAILED; - } +ReturnValue_t TcUnixUdpPollingTask::initializeAfterTaskCreation() { + // Initialize the destination after task creation. This ensures + // that the destination will be set in the TMTC bridge. + targetTcDestination = tmtcBridge->getRequestQueue(); + return HasReturnvaluesIF::RETURN_OK; +} - TmTcMessage message(storeId); - result = MessageQueueSenderIF::sendMessage(targetTcDestination, &message); - if (result != HasReturnvaluesIF::RETURN_OK) { - sif::error << "Serial Polling: Sending message to queue failed" - << std::endl; - tcStore->deleteData(storeId); +void TcUnixUdpPollingTask::setTimeout(double timeoutSeconds) { + timeval tval; + tval = timevalOperations::toTimeval(timeoutSeconds); + int result = setsockopt(serverUdpSocket, SOL_SOCKET, SO_RCVTIMEO, + &tval, sizeof(receptionTimeout)); + if(result == -1) { + sif::error << "TcSocketPollingTask::TcSocketPollingTask: Setting " + "receive timeout failed with " << strerror(errno) << std::endl; } - return result; } diff --git a/osal/linux/TcUnixUdpPollingTask.h b/osal/linux/TcUnixUdpPollingTask.h index 3503d505..86591e8d 100644 --- a/osal/linux/TcUnixUdpPollingTask.h +++ b/osal/linux/TcUnixUdpPollingTask.h @@ -29,8 +29,16 @@ public: size_t frameSize = 0, double timeoutSeconds = -1); virtual~ TcUnixUdpPollingTask(); + /** + * Turn on optional timeout for UDP polling. In the default mode, + * the receive function will block until a packet is received. + * @param timeoutSeconds + */ + void setTimeout(double timeoutSeconds); + virtual ReturnValue_t performOperation(uint8_t opCode) override; virtual ReturnValue_t initialize() override; + virtual ReturnValue_t initializeAfterTaskCreation() override; protected: StorageManagerIF* tcStore = nullptr; diff --git a/osal/linux/TmTcUnixUdpBridge.cpp b/osal/linux/TmTcUnixUdpBridge.cpp index a337b8ae..4dc61c50 100644 --- a/osal/linux/TmTcUnixUdpBridge.cpp +++ b/osal/linux/TmTcUnixUdpBridge.cpp @@ -1,8 +1,9 @@ #include #include -#include #include +#include + TmTcUnixUdpBridge::TmTcUnixUdpBridge(object_id_t objectId, object_id_t ccsdsPacketDistributor, uint16_t serverPort, uint16_t clientPort): @@ -14,17 +15,16 @@ TmTcUnixUdpBridge::TmTcUnixUdpBridge(object_id_t objectId, setServerPort = serverPort; } - uint16_t setClientPort = DEFAULT_UDP_CLIENT_PORT; - if(clientPort != 0xFFFF) { - setClientPort = clientPort; - } +// uint16_t setClientPort = DEFAULT_UDP_CLIENT_PORT; +// if(clientPort != 0xFFFF) { +// setClientPort = clientPort; +// } // Set up UDP socket: https://man7.org/linux/man-pages/man7/ip.7.html serverSocket = socket(AF_INET, SOCK_DGRAM, 0); if(socket < 0) { sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not open" " UDP socket!" << std::endl; - // check errno here. handleSocketError(); return; } @@ -44,7 +44,6 @@ TmTcUnixUdpBridge::TmTcUnixUdpBridge(object_id_t objectId, sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not bind " "local port " << setServerPort << " to server socket!" << std::endl; - // check errno here. handleBindError(); return; } @@ -57,14 +56,21 @@ ReturnValue_t TmTcUnixUdpBridge::sendTm(const uint8_t *data, size_t dataLen) { int flags = 0; ssize_t result = send(serverSocket, data, dataLen, flags); if(result < 0) { - //handle error + // todo: handle errors sif::error << "TmTcUnixUdpBridge::sendTm: Send operation failed " "with error " << strerror(errno) << std::endl; } - return HasReturnvaluesIF::RETURN_OK; } +void TmTcUnixUdpBridge::checkAndSetClientAddress(sockaddr_in newAddress) { + MutexHelper lock(mutex, 10); + // Set new IP address if it has changed. + if(clientAddress.sin_addr.s_addr != newAddress.sin_addr.s_addr) { + clientAddress.sin_addr.s_addr = newAddress.sin_addr.s_addr; + } +} + void TmTcUnixUdpBridge::handleSocketError() { // See: https://man7.org/linux/man-pages/man2/socket.2.html @@ -87,17 +93,6 @@ void TmTcUnixUdpBridge::handleSocketError() { } } -void TmTcUnixUdpBridge::setTimeout(float timeoutSeconds) { -} - -void TmTcUnixUdpBridge::checkAndSetClientAddress(sockaddr_in newAddress) { - MutexHelper lock(mutex, 10); - // Set new IP address if it has changed. - if(clientAddress.sin_addr.s_addr != newAddress.sin_addr.s_addr) { - clientAddress.sin_addr.s_addr = newAddress.sin_addr.s_addr; - } -} - void TmTcUnixUdpBridge::handleBindError() { // See: https://man7.org/linux/man-pages/man2/bind.2.html switch(errno) { @@ -128,16 +123,10 @@ void TmTcUnixUdpBridge::handleBindError() { << " with " << strerror(errno) << std::endl; break; } - default: { + default: sif::error << "TmTcUnixBridge::TmTcUnixBridge: Unknown error" << std::endl; break; } - } } - -ReturnValue_t TmTcUnixUdpBridge::receiveTc(uint8_t **recvBuffer, size_t *size) { - // TC reception handled by separate polling task because it is blocking. - return HasReturnvaluesIF::RETURN_OK; -} diff --git a/osal/linux/TmTcUnixUdpBridge.h b/osal/linux/TmTcUnixUdpBridge.h index 2fb606b0..538664d8 100644 --- a/osal/linux/TmTcUnixUdpBridge.h +++ b/osal/linux/TmTcUnixUdpBridge.h @@ -1,6 +1,7 @@ #ifndef FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_ #define FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_ +#include #include #include #include @@ -18,13 +19,11 @@ public: uint16_t serverPort = 0xFFFF,uint16_t clientPort = 0xFFFF); virtual~ TmTcUnixUdpBridge(); - void setTimeout(float timeoutSeconds); void checkAndSetClientAddress(sockaddr_in clientAddress); protected: - virtual ReturnValue_t receiveTc(uint8_t ** recvBuffer, - size_t * size) override; virtual ReturnValue_t sendTm(const uint8_t * data, size_t dataLen) override; + private: int serverSocket = 0; const int serverSocketOptions = 0; @@ -43,6 +42,4 @@ private: void handleBindError(); }; - - #endif /* FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_ */ diff --git a/tcdistribution/CCSDSDistributor.cpp b/tcdistribution/CCSDSDistributor.cpp index 199e2ed1..24c93730 100644 --- a/tcdistribution/CCSDSDistributor.cpp +++ b/tcdistribution/CCSDSDistributor.cpp @@ -9,7 +9,7 @@ CCSDSDistributor::CCSDSDistributor(uint16_t setDefaultApid, CCSDSDistributor::~CCSDSDistributor() {} -TcDistributor::TcMessageQueueMapIter CCSDSDistributor::selectDestination() { +TcDistributor::TcMqMapIter CCSDSDistributor::selectDestination() { // sif::debug << "CCSDSDistributor::selectDestination received: " << // this->currentMessage.getStorageId().pool_index << ", " << // this->currentMessage.getStorageId().packet_index << std::endl; @@ -25,7 +25,7 @@ TcDistributor::TcMessageQueueMapIter CCSDSDistributor::selectDestination() { // sif:: info << "CCSDSDistributor::selectDestination has packet with APID " // << std::hex << currentPacket.getAPID() << std::dec << std::endl; - TcMessageQueueMapIter position = this->queueMap.find(currentPacket.getAPID()); + TcMqMapIter position = this->queueMap.find(currentPacket.getAPID()); if ( position != this->queueMap.end() ) { return position; } else { diff --git a/tcdistribution/CCSDSDistributor.h b/tcdistribution/CCSDSDistributor.h index 22025f76..60877753 100644 --- a/tcdistribution/CCSDSDistributor.h +++ b/tcdistribution/CCSDSDistributor.h @@ -24,14 +24,14 @@ public: * TcDistributor ctor with a certain object id. * @details * @c tcStore is set in the @c initialize method. - * @param set_default_apid The default APID, where packets with unknown + * @param setDefaultApid The default APID, where packets with unknown * destination are sent to. */ - CCSDSDistributor( uint16_t setDefaultApid, object_id_t setObjectId ); + CCSDSDistributor(uint16_t setDefaultApid, object_id_t setObjectId); /** * The destructor is empty. */ - ~CCSDSDistributor(); + virtual ~CCSDSDistributor(); MessageQueueId_t getRequestQueue() override; ReturnValue_t registerApplication( uint16_t apid, @@ -49,7 +49,7 @@ protected: * where a Acceptance Failure message should be generated. * @return Iterator to map entry of found APID or iterator to default APID. */ - TcMessageQueueMapIter selectDestination(); + TcMqMapIter selectDestination() override; /** * The default APID, where packets with unknown APID are sent to. */ diff --git a/tcdistribution/PUSDistributor.cpp b/tcdistribution/PUSDistributor.cpp index f13b5f8d..d6e20acf 100644 --- a/tcdistribution/PUSDistributor.cpp +++ b/tcdistribution/PUSDistributor.cpp @@ -12,9 +12,9 @@ PUSDistributor::PUSDistributor(uint16_t setApid, object_id_t setObjectId, PUSDistributor::~PUSDistributor() {} -TcDistributor::TcMessageQueueMapIter PUSDistributor::selectDestination() { +TcDistributor::TcMqMapIter PUSDistributor::selectDestination() { // debug << "PUSDistributor::handlePacket received: " << this->current_packet_id.store_index << ", " << this->current_packet_id.packet_index << std::endl; - TcMessageQueueMapIter queueMapIt = this->queueMap.end(); + TcMqMapIter queueMapIt = this->queueMap.end(); this->currentPacket.setStoreAddress(this->currentMessage.getStorageId()); if (currentPacket.getWholeData() != NULL) { tcStatus = checker.checkPacket(¤tPacket); diff --git a/tcdistribution/PUSDistributor.h b/tcdistribution/PUSDistributor.h index 3d6717bd..4a22f936 100644 --- a/tcdistribution/PUSDistributor.h +++ b/tcdistribution/PUSDistributor.h @@ -66,7 +66,7 @@ protected: * @return Iterator to map entry of found service id * or iterator to @c map.end(). */ - TcMessageQueueMapIter selectDestination(); + TcMqMapIter selectDestination() override; /** * The callback here handles the generation of acceptance * success/failure messages. diff --git a/tcdistribution/TcDistributor.cpp b/tcdistribution/TcDistributor.cpp index 7bebbb9c..0190cc97 100644 --- a/tcdistribution/TcDistributor.cpp +++ b/tcdistribution/TcDistributor.cpp @@ -28,7 +28,7 @@ ReturnValue_t TcDistributor::performOperation(uint8_t opCode) { ReturnValue_t TcDistributor::handlePacket() { - TcMessageQueueMapIter queueMapIt = this->selectDestination(); + TcMqMapIter queueMapIt = this->selectDestination(); ReturnValue_t returnValue = RETURN_FAILED; if (queueMapIt != this->queueMap.end()) { returnValue = this->tcQueue->sendMessage(queueMapIt->second, @@ -40,7 +40,7 @@ ReturnValue_t TcDistributor::handlePacket() { void TcDistributor::print() { sif::debug << "Distributor content is: " << std::endl << "ID\t| message queue id" << std::endl; - for (TcMessageQueueMapIter it = this->queueMap.begin(); it != this->queueMap.end(); + for (TcMqMapIter it = this->queueMap.begin(); it != this->queueMap.end(); it++) { sif::debug << it->first << "\t| 0x" << std::hex << it->second << std::dec << std::endl; diff --git a/tcdistribution/TcDistributor.h b/tcdistribution/TcDistributor.h index 5c958de0..73425302 100644 --- a/tcdistribution/TcDistributor.h +++ b/tcdistribution/TcDistributor.h @@ -32,7 +32,7 @@ class TcDistributor : public SystemObject, public HasReturnvaluesIF { public: using TcMessageQueueMap = std::map; - using TcMessageQueueMapIter = std::map::iterator; + using TcMqMapIter = std::map::iterator; static const uint8_t INTERFACE_ID = CLASS_ID::PACKET_DISTRIBUTION; static const ReturnValue_t PACKET_LOST = MAKE_RETURN_CODE( 1 ); @@ -90,7 +90,7 @@ protected: * packet and select the map entry which represents the packet's target. * @return An iterator to the map element to forward to or queuMap.end(). */ - virtual TcMessageQueueMapIter selectDestination() = 0; + virtual TcMqMapIter selectDestination() = 0; /** * The handlePacket method calls the child class's selectDestination method * and forwards the packet to its destination, if found. diff --git a/tmtcservices/AcceptsTelecommandsIF.h b/tmtcservices/AcceptsTelecommandsIF.h index 0952d3a6..2878dd5d 100644 --- a/tmtcservices/AcceptsTelecommandsIF.h +++ b/tmtcservices/AcceptsTelecommandsIF.h @@ -1,5 +1,5 @@ -#ifndef ACCEPTSTELECOMMANDSIF_H_ -#define ACCEPTSTELECOMMANDSIF_H_ +#ifndef FRAMEWORK_TMTCSERVICES_ACCEPTSTELECOMMANDSIF_H_ +#define FRAMEWORK_TMTCSERVICES_ACCEPTSTELECOMMANDSIF_H_ #include @@ -26,9 +26,9 @@ public: /** * @brief Getter for the service id. * @details Any receiving service (at least any PUS service) shall have a - * service id. If the receiver can handle Telecommands, but for + * service ID. If the receiver can handle Telecommands, but for * some reason has no service id, it shall return 0. - * @return The service id or 0. + * @return The service ID or 0. */ virtual uint16_t getIdentifier() = 0; /** @@ -40,4 +40,4 @@ public: }; -#endif /* ACCEPTSTELECOMMANDSIF_H_ */ +#endif /* FRAMEWORK_TMTCSERVICES_ACCEPTSTELECOMMANDSIF_H_ */ diff --git a/tmtcservices/TmTcBridge.cpp b/tmtcservices/TmTcBridge.cpp index 092884bb..9c3e5b94 100644 --- a/tmtcservices/TmTcBridge.cpp +++ b/tmtcservices/TmTcBridge.cpp @@ -9,7 +9,7 @@ TmTcBridge::TmTcBridge(object_id_t objectId, object_id_t ccsdsPacketDistributor): SystemObject(objectId), ccsdsPacketDistributor(ccsdsPacketDistributor) { - TmTcReceptionQueue = QueueFactory::instance()-> + tmTcReceptionQueue = QueueFactory::instance()-> createMessageQueue(TMTC_RECEPTION_QUEUE_DEPTH); } @@ -55,7 +55,8 @@ ReturnValue_t TmTcBridge::initialize() { if (tcDistributor == NULL) { return RETURN_FAILED; } - TmTcReceptionQueue->setDefaultDestination(tcDistributor->getRequestQueue()); + + tmTcReceptionQueue->setDefaultDestination(tcDistributor->getRequestQueue()); return RETURN_OK; } @@ -73,10 +74,7 @@ ReturnValue_t TmTcBridge::performOperation(uint8_t operationCode) { } ReturnValue_t TmTcBridge::handleTc() { - uint8_t * recvBuffer = nullptr; - size_t recvLen = 0; - ReturnValue_t result = receiveTc(&recvBuffer, &recvLen); - return result; + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t TmTcBridge::handleTm() { @@ -97,8 +95,8 @@ ReturnValue_t TmTcBridge::handleTmQueue() { TmTcMessage message; const uint8_t* data = nullptr; size_t size = 0; - for (ReturnValue_t result = TmTcReceptionQueue->receiveMessage(&message); - result == RETURN_OK; result = TmTcReceptionQueue->receiveMessage(&message)) + for (ReturnValue_t result = tmTcReceptionQueue->receiveMessage(&message); + result == RETURN_OK; result = tmTcReceptionQueue->receiveMessage(&message)) { if(communicationLinkUp == false) { result = storeDownlinkData(&message); @@ -183,10 +181,20 @@ void TmTcBridge::registerCommDisconnect() { } MessageQueueId_t TmTcBridge::getReportReceptionQueue(uint8_t virtualChannel) { - return TmTcReceptionQueue->getId(); + return tmTcReceptionQueue->getId(); } void TmTcBridge::printData(uint8_t * data, size_t dataLen) { arrayprinter::print(data, dataLen); } + +uint16_t TmTcBridge::getIdentifier() { + // This is no PUS service, so we just return 0 + return 0; +} + +MessageQueueId_t TmTcBridge::getRequestQueue() { + // Default implementation: Relay TC messages to TC distributor directly. + return tmTcReceptionQueue->getDefaultDestination(); +} diff --git a/tmtcservices/TmTcBridge.h b/tmtcservices/TmTcBridge.h index a009c962..3fcbf84c 100644 --- a/tmtcservices/TmTcBridge.h +++ b/tmtcservices/TmTcBridge.h @@ -1,16 +1,18 @@ #ifndef FRAMEWORK_TMTCSERVICES_TMTCBRIDGE_H_ #define FRAMEWORK_TMTCSERVICES_TMTCBRIDGE_H_ -#include +#include #include #include #include #include -#include +#include +#include #include class TmTcBridge : public AcceptsTelemetryIF, + public AcceptsTelecommandsIF, public ExecutableObjectIF, public HasReturnvaluesIF, public SystemObject { @@ -57,17 +59,19 @@ public: */ virtual ReturnValue_t performOperation(uint8_t operationCode = 0) override; - /** - * Return TMTC Reception Queue - * @param virtualChannel - * @return - */ + + /** AcceptsTelemetryIF override */ virtual MessageQueueId_t getReportReceptionQueue( uint8_t virtualChannel = 0) override; + + /** AcceptsTelecommandsIF override */ + virtual uint16_t getIdentifier() override; + virtual MessageQueueId_t getRequestQueue() override; + protected: //! Used to send and receive TMTC messages. //! TmTcMessage is used to transport messages between tasks. - MessageQueueIF* TmTcReceptionQueue = nullptr; + MessageQueueIF* tmTcReceptionQueue = nullptr; StorageManagerIF* tcStore = nullptr; StorageManagerIF* tmStore = nullptr; object_id_t ccsdsPacketDistributor = 0; @@ -79,23 +83,11 @@ protected: * @brief Handle TC reception * @details * Default implementation provided, but is empty. - * Child handler should override this in most cases orsend TC to the - * TC distributor directly with the address of the reception queue by - * calling getReportRecptionQueue() + * In most cases, TC reception will be handled in a separate task anyway. * @return */ virtual ReturnValue_t handleTc(); - /** - * Implemented by child class. Perform receiving of Telecommand, - * for example by implementing specific drivers or wrappers, - * e.g. UART Communication or an ethernet stack - * @param recvBuffer [out] Received data - * @param size [out] Size of received data - * @return - */ - virtual ReturnValue_t receiveTc(uint8_t ** recvBuffer, size_t * size) = 0; - /** * Handle Telemetry. Default implementation provided. * Calls sendTm() From 94f9b1e1ef0ecdbd0f92751284f74dc02310b7c2 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 8 Jul 2020 12:41:15 +0200 Subject: [PATCH 10/17] dle encoder doc finished and hopefully correct --- globalfunctions/DleEncoder.cpp | 128 +++++++++++++++++++-------------- globalfunctions/DleEncoder.h | 21 ++++-- 2 files changed, 89 insertions(+), 60 deletions(-) diff --git a/globalfunctions/DleEncoder.cpp b/globalfunctions/DleEncoder.cpp index ee934785..d727d665 100644 --- a/globalfunctions/DleEncoder.cpp +++ b/globalfunctions/DleEncoder.cpp @@ -4,50 +4,6 @@ DleEncoder::DleEncoder() {} DleEncoder::~DleEncoder() {} -ReturnValue_t DleEncoder::decode(const uint8_t *sourceStream, - size_t sourceStreamLen, size_t *readLen, uint8_t *destStream, - size_t maxDestStreamlen, size_t *decodedLen) { - size_t encodedIndex = 0, decodedIndex = 0; - uint8_t nextByte; - if (*sourceStream != STX) { - return DECODING_ERROR; - } - ++encodedIndex; - while ((encodedIndex < sourceStreamLen) && (decodedIndex < maxDestStreamlen) - && (sourceStream[encodedIndex] != ETX) - && (sourceStream[encodedIndex] != STX)) { - if (sourceStream[encodedIndex] == DLE) { - nextByte = sourceStream[encodedIndex + 1]; - // The next byte is a DLE character that was escaped by another - // DLE character, so we can write it to the destination stream. - if (nextByte == DLE) { - destStream[decodedIndex] = nextByte; - } else { - // The next byte is a STX, DTX or 0x0D character which - // was escaped by a DLE character - if ((nextByte == 0x42) || (nextByte == 0x43) - || (nextByte == 0x4D)) { - destStream[decodedIndex] = nextByte - 0x40; - } else { - return DECODING_ERROR; - } - } - ++encodedIndex; - } else { - destStream[decodedIndex] = sourceStream[encodedIndex]; - } - ++encodedIndex; - ++decodedIndex; - } - if (sourceStream[encodedIndex] != ETX) { - return DECODING_ERROR; - } else { - *readLen = ++encodedIndex; - *decodedLen = decodedIndex; - return RETURN_OK; - } -} - ReturnValue_t DleEncoder::encode(const uint8_t* sourceStream, size_t sourceLen, uint8_t* destStream, size_t maxDestLen, size_t* encodedLen, bool addStxEtx) { @@ -60,39 +16,105 @@ ReturnValue_t DleEncoder::encode(const uint8_t* sourceStream, destStream[0] = STX; ++encodedIndex; } - while ((encodedIndex < maxDestLen) && (sourceIndex < sourceLen)) { + + while (encodedIndex < maxDestLen and sourceIndex < sourceLen) { nextByte = sourceStream[sourceIndex]; - if ((nextByte == STX) || (nextByte == ETX) || (nextByte == 0x0D)) { + // STX, ETX and CR characters in the stream need to be escaped with DLE + if (nextByte == STX or nextByte == ETX or nextByte == CARRIAGE_RETURN) { if (encodedIndex + 1 >= maxDestLen) { return STREAM_TOO_SHORT; - } else { + } + else { destStream[encodedIndex] = DLE; ++encodedIndex; - // Escaped byte will be actual byte + 0x40. + /* Escaped byte will be actual byte + 0x40. This prevents + * STX, ETX, and carriage return characters from appearing + * in the encoded data stream at all, so when polling an + * encoded stream, the transmission can be stopped at ETX. + * 0x40 was chosen at random with special requirements: + * - Prevent going from one control char to another + * - Prevent overflow for common characters */ destStream[encodedIndex] = nextByte + 0x40; } - } else if (nextByte == DLE) { + } + // DLE characters are simply escaped with DLE. + else if (nextByte == DLE) { if (encodedIndex + 1 >= maxDestLen) { return STREAM_TOO_SHORT; - } else { + } + else { destStream[encodedIndex] = DLE; ++encodedIndex; destStream[encodedIndex] = DLE; } - } else { + } + else { destStream[encodedIndex] = nextByte; } ++encodedIndex; ++sourceIndex; } - if ((sourceIndex == sourceLen) && (encodedIndex < maxDestLen)) { + + if (sourceIndex == sourceLen and encodedIndex < maxDestLen) { if (addStxEtx) { destStream[encodedIndex] = ETX; ++encodedIndex; } *encodedLen = encodedIndex; return RETURN_OK; - } else { + } + else { return STREAM_TOO_SHORT; } } + +ReturnValue_t DleEncoder::decode(const uint8_t *sourceStream, + size_t sourceStreamLen, size_t *readLen, uint8_t *destStream, + size_t maxDestStreamlen, size_t *decodedLen) { + size_t encodedIndex = 0, decodedIndex = 0; + uint8_t nextByte; + if (*sourceStream != STX) { + return DECODING_ERROR; + } + ++encodedIndex; + + while ((encodedIndex < sourceStreamLen) && (decodedIndex < maxDestStreamlen) + && (sourceStream[encodedIndex] != ETX) + && (sourceStream[encodedIndex] != STX)) { + if (sourceStream[encodedIndex] == DLE) { + nextByte = sourceStream[encodedIndex + 1]; + // The next byte is a DLE character that was escaped by another + // DLE character, so we can write it to the destination stream. + if (nextByte == DLE) { + destStream[decodedIndex] = nextByte; + } + else { + /* The next byte is a STX, DTX or 0x0D character which + * was escaped by a DLE character. The actual byte was + * also encoded by adding + 0x40 to preven having control chars, + * in the stream at all, so we convert it back. */ + if (nextByte == 0x42 or nextByte == 0x43 or nextByte == 0x4D) { + destStream[decodedIndex] = nextByte - 0x40; + } else { + return DECODING_ERROR; + } + } + ++encodedIndex; + } + else { + destStream[decodedIndex] = sourceStream[encodedIndex]; + } + ++encodedIndex; + ++decodedIndex; + } + + if (sourceStream[encodedIndex] != ETX) { + return DECODING_ERROR; + } + else { + *readLen = ++encodedIndex; + *decodedLen = decodedIndex; + return RETURN_OK; + } +} + diff --git a/globalfunctions/DleEncoder.h b/globalfunctions/DleEncoder.h index 0f4a4c8f..36cb1d3f 100644 --- a/globalfunctions/DleEncoder.h +++ b/globalfunctions/DleEncoder.h @@ -14,9 +14,15 @@ * This encoder can be used to achieve a basic transport layer when using * char based transmission systems. * The passed source strean is converted into a encoded stream by adding - * a STX marker at the startr of the stream and an ETX marker at the end of - * the stream. Any STX, ETX and DLE occurences in the source stream are escaped - * by a DLE character. + * a STX marker at the start of the stream and an ETX marker at the end of + * the stream. Any STX, ETX, DLE and CR occurences in the source stream are + * escaped by a DLE character. The encoder also replaces escaped control chars + * by another char, so STX, ETX and CR should not appear anywhere in the actual + * encoded data stream. + * + * When using a strictly char based reception of packets enoded with DLE, + * STX can be used to notify a reader that actual data will start to arrive + * while ETX can be used to notify the reader that the data has ended. */ class DleEncoder: public HasReturnvaluesIF { private: @@ -29,12 +35,13 @@ public: static constexpr ReturnValue_t DECODING_ERROR = MAKE_RETURN_CODE(0x02); //! Start Of Text character. First character is encoded stream - static const uint8_t STX = 0x02; + static constexpr uint8_t STX = 0x02; //! End Of Text character. Last character in encoded stream - static const uint8_t ETX = 0x03; + static constexpr uint8_t ETX = 0x03; //! Data Link Escape character. Used to escape STX, ETX and DLE occurences //! in the source stream. - static const uint8_t DLE = 0x10; + static constexpr uint8_t DLE = 0x10; + static constexpr uint8_t CARRIAGE_RETURN = 0x0D; /** * Encodes the give data stream by preceding it with the STX marker @@ -54,7 +61,7 @@ public: bool addStxEtx = true); /** - * Converts an encoded stream back + * Converts an encoded stream back. * @param sourceStream * @param sourceStreamLen * @param readLen From 01b10803766e61833eaa9762327a48e0fff76c29 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 8 Jul 2020 12:53:46 +0200 Subject: [PATCH 11/17] readability increase --- globalfunctions/DleEncoder.cpp | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/globalfunctions/DleEncoder.cpp b/globalfunctions/DleEncoder.cpp index d727d665..c8f78872 100644 --- a/globalfunctions/DleEncoder.cpp +++ b/globalfunctions/DleEncoder.cpp @@ -17,7 +17,8 @@ ReturnValue_t DleEncoder::encode(const uint8_t* sourceStream, ++encodedIndex; } - while (encodedIndex < maxDestLen and sourceIndex < sourceLen) { + while (encodedIndex < maxDestLen and sourceIndex < sourceLen) + { nextByte = sourceStream[sourceIndex]; // STX, ETX and CR characters in the stream need to be escaped with DLE if (nextByte == STX or nextByte == ETX or nextByte == CARRIAGE_RETURN) { @@ -80,7 +81,8 @@ ReturnValue_t DleEncoder::decode(const uint8_t *sourceStream, while ((encodedIndex < sourceStreamLen) && (decodedIndex < maxDestStreamlen) && (sourceStream[encodedIndex] != ETX) - && (sourceStream[encodedIndex] != STX)) { + && (sourceStream[encodedIndex] != STX)) + { if (sourceStream[encodedIndex] == DLE) { nextByte = sourceStream[encodedIndex + 1]; // The next byte is a DLE character that was escaped by another @@ -95,7 +97,8 @@ ReturnValue_t DleEncoder::decode(const uint8_t *sourceStream, * in the stream at all, so we convert it back. */ if (nextByte == 0x42 or nextByte == 0x43 or nextByte == 0x4D) { destStream[decodedIndex] = nextByte - 0x40; - } else { + } + else { return DECODING_ERROR; } } @@ -104,6 +107,7 @@ ReturnValue_t DleEncoder::decode(const uint8_t *sourceStream, else { destStream[decodedIndex] = sourceStream[encodedIndex]; } + ++encodedIndex; ++decodedIndex; } From b56aa94f99730cee982eebc09dd8fa88a3fbc077 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 8 Jul 2020 12:54:40 +0200 Subject: [PATCH 12/17] additional doc --- globalfunctions/DleEncoder.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/globalfunctions/DleEncoder.h b/globalfunctions/DleEncoder.h index 36cb1d3f..29851dfe 100644 --- a/globalfunctions/DleEncoder.h +++ b/globalfunctions/DleEncoder.h @@ -46,7 +46,8 @@ public: /** * Encodes the give data stream by preceding it with the STX marker * and ending it with an ETX marker. STX, ETX and DLE characters inside - * the stream are escaped by DLE characters. + * the stream are escaped by DLE characters and also replaced by adding + * 0x40 (which is reverted in the decoing process). * @param sourceStream * @param sourceLen * @param destStream From 5ec78b065c4ca0ba486b9837c0e4c0eba40d5b15 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 8 Jul 2020 13:29:57 +0200 Subject: [PATCH 13/17] error handling for invalid dest queues improved --- ipc/MessageQueueIF.h | 14 +++---- objectmanager/frameworkObjects.h | 4 ++ osal/linux/MessageQueue.cpp | 13 ++++--- tmtcservices/VerificationReporter.cpp | 56 +++++++++++++++------------ tmtcservices/VerificationReporter.h | 39 ++++++++++++++----- 5 files changed, 78 insertions(+), 48 deletions(-) diff --git a/ipc/MessageQueueIF.h b/ipc/MessageQueueIF.h index 500f71e2..c0575442 100644 --- a/ipc/MessageQueueIF.h +++ b/ipc/MessageQueueIF.h @@ -18,18 +18,14 @@ public: static const MessageQueueId_t NO_QUEUE = MessageQueueMessageIF::NO_QUEUE; //!< Ugly hack. static const uint8_t INTERFACE_ID = CLASS_ID::MESSAGE_QUEUE_IF; - /** - * No new messages on the queue - */ + //! No new messages on the queue static const ReturnValue_t EMPTY = MAKE_RETURN_CODE(1); - /** - * No space left for more messages - */ + //! No space left for more messages static const ReturnValue_t FULL = MAKE_RETURN_CODE(2); - /** - * Returned if a reply method was called without partner - */ + //! Returned if a reply method was called without partner static const ReturnValue_t NO_REPLY_PARTNER = MAKE_RETURN_CODE(3); + //! Returned if the target destination is invalid. + static constexpr ReturnValue_t DESTINVATION_INVALID = MAKE_RETURN_CODE(4); virtual ~MessageQueueIF() {} /** diff --git a/objectmanager/frameworkObjects.h b/objectmanager/frameworkObjects.h index c3deafc4..46d5feea 100644 --- a/objectmanager/frameworkObjects.h +++ b/objectmanager/frameworkObjects.h @@ -3,6 +3,9 @@ namespace objects { enum framework_objects { + // Default verification reporter. + PUS_SERVICE_1 = 0x53000000, + //Generic IDs for IPC, modes, health, events HEALTH_TABLE = 0x53010000, // MODE_STORE = 0x53010100, @@ -12,6 +15,7 @@ enum framework_objects { //IDs for PUS Packet Communication TC_STORE = 0x534f0100, TM_STORE = 0x534f0200, + NO_OBJECT = 0xFFFFFFFF }; } diff --git a/osal/linux/MessageQueue.cpp b/osal/linux/MessageQueue.cpp index 153f43d3..236e61b6 100644 --- a/osal/linux/MessageQueue.cpp +++ b/osal/linux/MessageQueue.cpp @@ -330,13 +330,16 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, //MQ_NONBLOCK flag was set in its attributes, and the //specified queue is full. return MessageQueueIF::FULL; - case EBADF: + case EBADF: { //mq_des doesn't represent a valid message queue descriptor, //or mq_des wasn't opened for writing. - sif::error << "MessageQueue::sendMessage: Configuration error " - << strerror(errno) << " in mq_send mqSendTo: " << sendTo - << " sent from " << sentFrom << std::endl; - /*NO BREAK*/ + sif::error << "MessageQueue::sendMessage: Configuration error, MQ" + << " destination invalid." << std::endl; + sif::error << strerror(errno) << " in " + <<"mq_send to: " << sendTo << " sent from " + << sentFrom << std::endl; + return DESTINVATION_INVALID; + } case EINTR: //The call was interrupted by a signal. case EINVAL: diff --git a/tmtcservices/VerificationReporter.cpp b/tmtcservices/VerificationReporter.cpp index bcb4756c..40f7e57f 100644 --- a/tmtcservices/VerificationReporter.cpp +++ b/tmtcservices/VerificationReporter.cpp @@ -1,17 +1,18 @@ -#include -#include -#include #include -object_id_t VerificationReporter::messageReceiver = 0; +#include +#include +#include +#include +#include + +object_id_t VerificationReporter::messageReceiver = objects::PUS_SERVICE_1; VerificationReporter::VerificationReporter() : - acknowledgeQueue() { + acknowledgeQueue(MessageQueueIF::NO_QUEUE) { } -VerificationReporter::~VerificationReporter() { - //Default, empty -} +VerificationReporter::~VerificationReporter() {} void VerificationReporter::sendSuccessReport(uint8_t set_report_id, TcPacketBase* current_packet, uint8_t set_step) { @@ -23,10 +24,11 @@ void VerificationReporter::sendSuccessReport(uint8_t set_report_id, current_packet->getPacketId(), current_packet->getPacketSequenceControl(), 0, set_step); ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, - &message); + &message); if (status != HasReturnvaluesIF::RETURN_OK) { sif::error << "VerificationReporter::sendSuccessReport: Error writing " - "to queue. Code: " << std::hex << (uint16_t) status << std::endl; + << "to queue. Code: " << std::hex << status << std::dec + << std::endl; } } @@ -39,10 +41,11 @@ void VerificationReporter::sendSuccessReport(uint8_t set_report_id, PusVerificationMessage message(set_report_id, ackFlags, tcPacketId, tcSequenceControl, 0, set_step); ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, - &message); + &message); if (status != HasReturnvaluesIF::RETURN_OK) { sif::error << "VerificationReporter::sendSuccessReport: Error writing " - "to queue. Code: " << std::hex << (uint16_t) status << std::endl; + << "to queue. Code: " << std::hex << status << std::dec + << std::endl; } } @@ -60,9 +63,9 @@ void VerificationReporter::sendFailureReport(uint8_t report_id, ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, &message); if (status != HasReturnvaluesIF::RETURN_OK) { - sif::error - << "VerificationReporter::sendFailureReport Error writing to queue. Code: " - << (uint16_t) status << std::endl; + sif::error << "VerificationReporter::sendFailureReport Error writing " + << "to queue. Code: " << std::hex << status << std::dec + << std::endl; } } @@ -78,20 +81,25 @@ void VerificationReporter::sendFailureReport(uint8_t report_id, ReturnValue_t status = MessageQueueSenderIF::sendMessage(acknowledgeQueue, &message); if (status != HasReturnvaluesIF::RETURN_OK) { - sif::error - << "VerificationReporter::sendFailureReport Error writing to queue. Code: " - << (uint16_t) status << std::endl; + sif::error << "VerificationReporter::sendFailureReport Error writing " + << "to queue. Code: " << std::hex << status << std::dec + << std::endl; } } void VerificationReporter::initialize() { + if(messageReceiver == objects::NO_OBJECT) { + sif::warning << "VerificationReporter::initialize: Verification message" + " receiver object ID not set yet in Factory!" << std::endl; + return; + } AcceptsVerifyMessageIF* temp = objectManager->get( messageReceiver); - if (temp != NULL) { - this->acknowledgeQueue = temp->getVerificationQueue(); - } else { - sif::error - << "VerificationReporter::VerificationReporter: Configuration error." - << std::endl; + if (temp == nullptr) { + sif::error << "VerificationReporter::initialize: Message " + << "receiver invalid. Make sure it is set up properly and " + <<"implementsAcceptsVerifyMessageIF" << std::endl; + } + this->acknowledgeQueue = temp->getVerificationQueue(); } diff --git a/tmtcservices/VerificationReporter.h b/tmtcservices/VerificationReporter.h index 370c44c8..f13998d9 100644 --- a/tmtcservices/VerificationReporter.h +++ b/tmtcservices/VerificationReporter.h @@ -1,5 +1,5 @@ -#ifndef VERIFICATIONREPORTER_H_ -#define VERIFICATIONREPORTER_H_ +#ifndef FRAMEWORK_TMTCSERVICES_VERIFICATIONREPORTER_H_ +#define FRAMEWORK_TMTCSERVICES_VERIFICATIONREPORTER_H_ #include #include @@ -8,24 +8,43 @@ namespace Factory{ void setStaticFrameworkObjectIds(); } +/** + * @brief This helper object is used to forward verification messages + * which are generated by the Flight Software Framework. + * @details + * The messages can be relayed to an arbitrary object, for example a dedicated + * Verification Reporter. The destination is set by setting the static framework + * Id VerificationReporter::messageReceiver. The default verification reporter + * will be the PUS service 1, which sends verification messages according + * to the PUS standard. + * + */ class VerificationReporter { friend void (Factory::setStaticFrameworkObjectIds)(); public: VerificationReporter(); virtual ~VerificationReporter(); - void sendSuccessReport( uint8_t set_report_id, TcPacketBase* current_packet, uint8_t set_step = 0 ); - void sendSuccessReport(uint8_t set_report_id, uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, uint8_t set_step = 0); - void sendFailureReport( uint8_t report_id, TcPacketBase* current_packet, ReturnValue_t error_code = 0, - uint8_t step = 0, uint32_t parameter1 = 0, uint32_t parameter2 = 0 ); + + void sendSuccessReport( uint8_t set_report_id, TcPacketBase* current_packet, + uint8_t set_step = 0 ); + void sendSuccessReport(uint8_t set_report_id, uint8_t ackFlags, + uint16_t tcPacketId, uint16_t tcSequenceControl, + uint8_t set_step = 0); + + void sendFailureReport( uint8_t report_id, TcPacketBase* current_packet, + ReturnValue_t error_code = 0, + uint8_t step = 0, uint32_t parameter1 = 0, + uint32_t parameter2 = 0 ); void sendFailureReport(uint8_t report_id, - uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, ReturnValue_t error_code = 0, uint8_t step = 0, + uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, + ReturnValue_t error_code = 0, uint8_t step = 0, uint32_t parameter1 = 0, uint32_t parameter2 = 0); + void initialize(); + private: static object_id_t messageReceiver; MessageQueueId_t acknowledgeQueue; - - }; -#endif /* VERIFICATIONREPORTER_H_ */ +#endif /* FRAMEWORK_TMTCSERVICES_VERIFICATIONREPORTER_H_ */ From 236ad1b85b600acecc741127faa19c72925542fc Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 8 Jul 2020 15:06:46 +0200 Subject: [PATCH 14/17] a lot of debug output added --- osal/linux/TcUnixUdpPollingTask.cpp | 1 + osal/linux/TmTcUnixUdpBridge.cpp | 54 ++++++++++++++++++++------- osal/linux/TmTcUnixUdpBridge.h | 11 ++++-- tmtcservices/PusServiceBase.cpp | 20 +++++----- tmtcservices/TmTcBridge.cpp | 32 ++++++++++------ tmtcservices/TmTcBridge.h | 17 ++++++--- tmtcservices/VerificationReporter.cpp | 8 ++-- 7 files changed, 93 insertions(+), 50 deletions(-) diff --git a/osal/linux/TcUnixUdpPollingTask.cpp b/osal/linux/TcUnixUdpPollingTask.cpp index 97fbd044..122301da 100644 --- a/osal/linux/TcUnixUdpPollingTask.cpp +++ b/osal/linux/TcUnixUdpPollingTask.cpp @@ -53,6 +53,7 @@ ReturnValue_t TcUnixUdpPollingTask::performOperation(uint8_t opCode) { if(result != HasReturnvaluesIF::RETURN_FAILED) { } + tmtcBridge->registerCommConnect(); tmtcBridge->checkAndSetClientAddress(senderAddress); } return HasReturnvaluesIF::RETURN_OK; diff --git a/osal/linux/TmTcUnixUdpBridge.cpp b/osal/linux/TmTcUnixUdpBridge.cpp index 4dc61c50..40e96561 100644 --- a/osal/linux/TmTcUnixUdpBridge.cpp +++ b/osal/linux/TmTcUnixUdpBridge.cpp @@ -3,11 +3,12 @@ #include #include +#include TmTcUnixUdpBridge::TmTcUnixUdpBridge(object_id_t objectId, - object_id_t ccsdsPacketDistributor, uint16_t serverPort, - uint16_t clientPort): - TmTcBridge(objectId, ccsdsPacketDistributor) { + object_id_t tcDestination, object_id_t tmStoreId, object_id_t tcStoreId, + uint16_t serverPort, uint16_t clientPort): + TmTcBridge(objectId, tcDestination, tmStoreId, tcStoreId) { mutex = MutexFactory::instance()->createMutex(); uint16_t setServerPort = DEFAULT_UDP_SERVER_PORT; @@ -15,13 +16,14 @@ TmTcUnixUdpBridge::TmTcUnixUdpBridge(object_id_t objectId, setServerPort = serverPort; } -// uint16_t setClientPort = DEFAULT_UDP_CLIENT_PORT; -// if(clientPort != 0xFFFF) { -// setClientPort = clientPort; -// } + uint16_t setClientPort = DEFAULT_UDP_CLIENT_PORT; + if(clientPort != 0xFFFF) { + setClientPort = clientPort; + } // Set up UDP socket: https://man7.org/linux/man-pages/man7/ip.7.html - serverSocket = socket(AF_INET, SOCK_DGRAM, 0); + //clientSocket = socket(AF_INET, SOCK_DGRAM, 0); + serverSocket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP); if(socket < 0) { sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not open" " UDP socket!" << std::endl; @@ -36,10 +38,14 @@ TmTcUnixUdpBridge::TmTcUnixUdpBridge(object_id_t objectId, setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &serverSocketOptions, sizeof(serverSocketOptions)); - serverSocketLen = sizeof(serverAddress); + clientAddress.sin_family = AF_INET; + clientAddress.sin_addr.s_addr = htonl(INADDR_ANY); + clientAddress.sin_port = htons(setClientPort); + + serverAddressLen = sizeof(serverAddress); int result = bind(serverSocket, reinterpret_cast(&serverAddress), - serverSocketLen); + serverAddressLen); if(result == -1) { sif::error << "TmTcUnixUdpBridge::TmTcUnixUdpBridge: Could not bind " "local port " << setServerPort << " to server socket!" @@ -54,20 +60,35 @@ TmTcUnixUdpBridge::~TmTcUnixUdpBridge() { ReturnValue_t TmTcUnixUdpBridge::sendTm(const uint8_t *data, size_t dataLen) { int flags = 0; - ssize_t result = send(serverSocket, data, dataLen, flags); - if(result < 0) { + sif::debug << "Client Port: "<(&clientAddress), clientAddressLen); + if(bytesSent < 0) { // todo: handle errors - sif::error << "TmTcUnixUdpBridge::sendTm: Send operation failed " - "with error " << strerror(errno) << std::endl; + sif::error << "TmTcUnixUdpBridge::sendTm: Send operation failed." + << std::endl; + sif::error << "Error: " << strerror(errno) << std::endl; + handleSendError(); } + sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were" + " sent." << std::endl; return HasReturnvaluesIF::RETURN_OK; } void TmTcUnixUdpBridge::checkAndSetClientAddress(sockaddr_in newAddress) { MutexHelper lock(mutex, 10); + + char ipAddress [15]; + sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET, + &newAddress.sin_addr.s_addr, ipAddress, 15) << std::endl; + + sif::debug << "IP Address Old: " << inet_ntop(AF_INET, + &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl; // Set new IP address if it has changed. if(clientAddress.sin_addr.s_addr != newAddress.sin_addr.s_addr) { + sif::info << "setting new address" << std::endl; clientAddress.sin_addr.s_addr = newAddress.sin_addr.s_addr; + clientAddressLen = sizeof(clientAddress); } } @@ -130,3 +151,8 @@ void TmTcUnixUdpBridge::handleBindError() { } } +void TmTcUnixUdpBridge::handleSendError() { + + +} + diff --git a/osal/linux/TmTcUnixUdpBridge.h b/osal/linux/TmTcUnixUdpBridge.h index 538664d8..dbddc6c3 100644 --- a/osal/linux/TmTcUnixUdpBridge.h +++ b/osal/linux/TmTcUnixUdpBridge.h @@ -15,8 +15,9 @@ public: static constexpr uint16_t DEFAULT_UDP_SERVER_PORT = 7301; static constexpr uint16_t DEFAULT_UDP_CLIENT_PORT = 7302; - TmTcUnixUdpBridge(object_id_t objectId, object_id_t ccsdsPacketDistributor, - uint16_t serverPort = 0xFFFF,uint16_t clientPort = 0xFFFF); + TmTcUnixUdpBridge(object_id_t objectId, object_id_t tcDestination, + object_id_t tmStoreId, object_id_t tcStoreId, + uint16_t serverPort = 0xFFFF,uint16_t clientPort = 0xFFFF); virtual~ TmTcUnixUdpBridge(); void checkAndSetClientAddress(sockaddr_in clientAddress); @@ -26,13 +27,14 @@ protected: private: int serverSocket = 0; + const int serverSocketOptions = 0; struct sockaddr_in clientAddress; - socklen_t clientSocketLen = 0; + socklen_t clientAddressLen = 0; struct sockaddr_in serverAddress; - socklen_t serverSocketLen = 0; + socklen_t serverAddressLen = 0; //! Access to the client address is mutex protected as it is set //! by another task. @@ -40,6 +42,7 @@ private: void handleSocketError(); void handleBindError(); + void handleSendError(); }; #endif /* FRAMEWORK_OSAL_LINUX_TMTCUNIXUDPBRIDGE_H_ */ diff --git a/tmtcservices/PusServiceBase.cpp b/tmtcservices/PusServiceBase.cpp index cb1e633f..4385609b 100644 --- a/tmtcservices/PusServiceBase.cpp +++ b/tmtcservices/PusServiceBase.cpp @@ -103,19 +103,17 @@ ReturnValue_t PusServiceBase::initialize() { packetDestination); PUSDistributorIF* distributor = objectManager->get( packetSource); - if ((destService != nullptr) && (distributor != nullptr)) { - this->requestQueue->setDefaultDestination( - destService->getReportReceptionQueue()); - distributor->registerService(this); - return RETURN_OK; - } - else { + if (destService == nullptr or distributor == nullptr) { sif::error << "PusServiceBase::PusServiceBase: Service " - << (uint32_t) this->serviceId << ": Configuration error." - << " Make sure packetSource and packetDestination are defined " - "correctly" << std::endl; - return RETURN_FAILED; + << this->serviceId << ": Configuration error. Make sure " + << "packetSource and packetDestination are defined correctly" + << std::endl; + return ObjectManagerIF::CHILD_INIT_FAILED; } + this->requestQueue->setDefaultDestination( + destService->getReportReceptionQueue()); + distributor->registerService(this); + return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t PusServiceBase::initializeAfterTaskCreation() { diff --git a/tmtcservices/TmTcBridge.cpp b/tmtcservices/TmTcBridge.cpp index 9c3e5b94..8c44f7de 100644 --- a/tmtcservices/TmTcBridge.cpp +++ b/tmtcservices/TmTcBridge.cpp @@ -5,9 +5,11 @@ #include #include -TmTcBridge::TmTcBridge(object_id_t objectId, - object_id_t ccsdsPacketDistributor): SystemObject(objectId), - ccsdsPacketDistributor(ccsdsPacketDistributor) +TmTcBridge::TmTcBridge(object_id_t objectId, object_id_t tcDestination, + object_id_t tmStoreId, object_id_t tcStoreId): + SystemObject(objectId),tmStoreId(tmStoreId), tcStoreId(tcStoreId), + tcDestination(tcDestination) + { tmTcReceptionQueue = QueueFactory::instance()-> createMessageQueue(TMTC_RECEPTION_QUEUE_DEPTH); @@ -42,18 +44,24 @@ ReturnValue_t TmTcBridge::setMaxNumberOfPacketsStored( } ReturnValue_t TmTcBridge::initialize() { - tcStore = objectManager->get(objects::TC_STORE); - if (tcStore == NULL) { - return RETURN_FAILED; + tcStore = objectManager->get(tcStoreId); + if (tcStore == nullptr) { + sif::error << "TmTcBridge::initialize: TC store invalid. Make sure" + "it is created and set up properly." << std::endl; + return ObjectManagerIF::CHILD_INIT_FAILED; } - tmStore = objectManager->get(objects::TM_STORE); - if (tmStore == NULL) { - return RETURN_FAILED; + tmStore = objectManager->get(tmStoreId); + if (tmStore == nullptr) { + sif::error << "TmTcBridge::initialize: TM store invalid. Make sure" + "it is created and set up properly." << std::endl; + return ObjectManagerIF::CHILD_INIT_FAILED; } AcceptsTelecommandsIF* tcDistributor = - objectManager->get(ccsdsPacketDistributor); - if (tcDistributor == NULL) { - return RETURN_FAILED; + objectManager->get(tcDestination); + if (tcDistributor == nullptr) { + sif::error << "TmTcBridge::initialize: TC Distributor invalid" + << std::endl; + return ObjectManagerIF::CHILD_INIT_FAILED; } tmTcReceptionQueue->setDefaultDestination(tcDistributor->getRequestQueue()); diff --git a/tmtcservices/TmTcBridge.h b/tmtcservices/TmTcBridge.h index 3fcbf84c..3e3d1b71 100644 --- a/tmtcservices/TmTcBridge.h +++ b/tmtcservices/TmTcBridge.h @@ -24,7 +24,8 @@ public: static constexpr uint8_t DEFAULT_STORED_DATA_SENT_PER_CYCLE = 5; static constexpr uint8_t DEFAULT_DOWNLINK_PACKETS_STORED = 10; - TmTcBridge(object_id_t objectId, object_id_t ccsdsPacketDistributor); + TmTcBridge(object_id_t objectId, object_id_t tcDestination, + object_id_t tmStoreId, object_id_t tcStoreId); virtual ~TmTcBridge(); /** @@ -69,14 +70,20 @@ public: virtual MessageQueueId_t getRequestQueue() override; protected: + //! Cached for initialize function. + object_id_t tmStoreId = objects::NO_OBJECT; + object_id_t tcStoreId = objects::NO_OBJECT; + object_id_t tcDestination = objects::NO_OBJECT; + //! Used to send and receive TMTC messages. //! TmTcMessage is used to transport messages between tasks. MessageQueueIF* tmTcReceptionQueue = nullptr; - StorageManagerIF* tcStore = nullptr; + StorageManagerIF* tmStore = nullptr; - object_id_t ccsdsPacketDistributor = 0; - //! Used to specify whether communication link is up - bool communicationLinkUp = false; + StorageManagerIF* tcStore = nullptr; + + //! Used to specify whether communication link is up by default. + bool communicationLinkUp = true; bool tmStored = false; /** diff --git a/tmtcservices/VerificationReporter.cpp b/tmtcservices/VerificationReporter.cpp index 40f7e57f..79e650f1 100644 --- a/tmtcservices/VerificationReporter.cpp +++ b/tmtcservices/VerificationReporter.cpp @@ -16,7 +16,7 @@ VerificationReporter::~VerificationReporter() {} void VerificationReporter::sendSuccessReport(uint8_t set_report_id, TcPacketBase* current_packet, uint8_t set_step) { - if (this->acknowledgeQueue == 0) { + if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { this->initialize(); } PusVerificationMessage message(set_report_id, @@ -35,7 +35,7 @@ void VerificationReporter::sendSuccessReport(uint8_t set_report_id, void VerificationReporter::sendSuccessReport(uint8_t set_report_id, uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, uint8_t set_step) { - if (this->acknowledgeQueue == 0) { + if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { this->initialize(); } PusVerificationMessage message(set_report_id, ackFlags, tcPacketId, @@ -52,7 +52,7 @@ void VerificationReporter::sendSuccessReport(uint8_t set_report_id, void VerificationReporter::sendFailureReport(uint8_t report_id, TcPacketBase* current_packet, ReturnValue_t error_code, uint8_t step, uint32_t parameter1, uint32_t parameter2) { - if (this->acknowledgeQueue == 0) { + if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { this->initialize(); } PusVerificationMessage message(report_id, @@ -73,7 +73,7 @@ void VerificationReporter::sendFailureReport(uint8_t report_id, uint8_t ackFlags, uint16_t tcPacketId, uint16_t tcSequenceControl, ReturnValue_t error_code, uint8_t step, uint32_t parameter1, uint32_t parameter2) { - if (this->acknowledgeQueue == 0) { + if (acknowledgeQueue == MessageQueueIF::NO_QUEUE) { this->initialize(); } PusVerificationMessage message(report_id, ackFlags, tcPacketId, From 8046d005a46e734aa2112cbd6f617920da2ec753 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 8 Jul 2020 18:18:54 +0200 Subject: [PATCH 15/17] CSB static framework id setting --- osal/linux/FixedTimeslotTask.cpp | 2 +- osal/linux/TcUnixUdpPollingTask.cpp | 35 +++++++++++++------ osal/linux/TcUnixUdpPollingTask.h | 2 +- osal/linux/TmTcUnixUdpBridge.cpp | 48 ++++++++++++++++---------- pus/Service2DeviceAccess.cpp | 3 +- tcdistribution/PUSDistributor.cpp | 8 ++--- tmtcservices/CommandingServiceBase.cpp | 18 +++++++--- tmtcservices/CommandingServiceBase.h | 28 ++++++++++++--- tmtcservices/PusServiceBase.cpp | 5 ++- 9 files changed, 99 insertions(+), 50 deletions(-) diff --git a/osal/linux/FixedTimeslotTask.cpp b/osal/linux/FixedTimeslotTask.cpp index e5c68f9d..9d7d08f6 100644 --- a/osal/linux/FixedTimeslotTask.cpp +++ b/osal/linux/FixedTimeslotTask.cpp @@ -45,7 +45,7 @@ ReturnValue_t FixedTimeslotTask::addSlot(object_id_t componentId, } sif::error << "Component " << std::hex << componentId << - " not found, not adding it to pst" << std::endl; + " not found, not adding it to pst" << std::dec << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } diff --git a/osal/linux/TcUnixUdpPollingTask.cpp b/osal/linux/TcUnixUdpPollingTask.cpp index 122301da..8cf7b285 100644 --- a/osal/linux/TcUnixUdpPollingTask.cpp +++ b/osal/linux/TcUnixUdpPollingTask.cpp @@ -39,15 +39,14 @@ ReturnValue_t TcUnixUdpPollingTask::performOperation(uint8_t opCode) { reinterpret_cast(&senderAddress), &senderSockLen); if(bytesReceived < 0) { // handle error - sif::error << "TcSocketPollingTask::performOperation: recvfrom " - "failed with " << strerror(errno) << std::endl; - if(errno == EAGAIN or errno == EWOULDBLOCK) { - sif::info << "timeout" << std::endl; - } + sif::error << "TcSocketPollingTask::performOperation: Reception" + "error." << std::endl; + handleReadError(); + continue; } - sif::debug << "TcSocketPollingTask::performOperation: " << bytesReceived - << " bytes received" << std::endl; +// sif::debug << "TcSocketPollingTask::performOperation: " << bytesReceived +// << " bytes received" << std::endl; ReturnValue_t result = handleSuccessfullTcRead(bytesReceived); if(result != HasReturnvaluesIF::RETURN_FAILED) { @@ -61,14 +60,14 @@ ReturnValue_t TcUnixUdpPollingTask::performOperation(uint8_t opCode) { ReturnValue_t TcUnixUdpPollingTask::handleSuccessfullTcRead(size_t bytesRead) { - store_address_t storeId = 0; + store_address_t storeId; ReturnValue_t result = tcStore->addData(&storeId, receptionBuffer.data(), bytesRead); // arrayprinter::print(receptionBuffer.data(), bytesRead); if (result != HasReturnvaluesIF::RETURN_OK) { - sif::debug << "TcSerialPollingTask::transferPusToSoftwareBus: Data " + sif::error << "TcSerialPollingTask::transferPusToSoftwareBus: Data " "storage failed" << std::endl; - sif::debug << "Packet size: " << bytesRead << std::endl; + sif::error << "Packet size: " << bytesRead << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } @@ -121,4 +120,18 @@ void TcUnixUdpPollingTask::setTimeout(double timeoutSeconds) { } } - +void TcUnixUdpPollingTask::handleReadError() { + switch(errno) { + case(EAGAIN): { + // todo: When working in timeout mode, this will occur more often + // and is not an error. + sif::error << "TcUnixUdpPollingTask::handleReadError: Timeout." + << std::endl; + break; + } + default: { + sif::error << "TcUnixUdpPollingTask::handleReadError: " + << strerror(errno) << std::endl; + } + } +} diff --git a/osal/linux/TcUnixUdpPollingTask.h b/osal/linux/TcUnixUdpPollingTask.h index 86591e8d..d8de1458 100644 --- a/osal/linux/TcUnixUdpPollingTask.h +++ b/osal/linux/TcUnixUdpPollingTask.h @@ -61,7 +61,7 @@ private: timeval receptionTimeout; ReturnValue_t handleSuccessfullTcRead(size_t bytesRead); - + void handleReadError(); }; #endif /* FRAMEWORK_OSAL_LINUX_TCSOCKETPOLLINGTASK_H_ */ diff --git a/osal/linux/TmTcUnixUdpBridge.cpp b/osal/linux/TmTcUnixUdpBridge.cpp index 40e96561..92fbbdfa 100644 --- a/osal/linux/TmTcUnixUdpBridge.cpp +++ b/osal/linux/TmTcUnixUdpBridge.cpp @@ -32,17 +32,20 @@ TmTcUnixUdpBridge::TmTcUnixUdpBridge(object_id_t objectId, } serverAddress.sin_family = AF_INET; + // Accept packets from any interface. + //serverAddress.sin_addr.s_addr = inet_addr("127.73.73.0"); serverAddress.sin_addr.s_addr = htonl(INADDR_ANY); serverAddress.sin_port = htons(setServerPort); + serverAddressLen = sizeof(serverAddress); setsockopt(serverSocket, SOL_SOCKET, SO_REUSEADDR, &serverSocketOptions, sizeof(serverSocketOptions)); clientAddress.sin_family = AF_INET; clientAddress.sin_addr.s_addr = htonl(INADDR_ANY); clientAddress.sin_port = htons(setClientPort); + clientAddressLen = sizeof(clientAddress); - serverAddressLen = sizeof(serverAddress); int result = bind(serverSocket, reinterpret_cast(&serverAddress), serverAddressLen); @@ -60,33 +63,38 @@ TmTcUnixUdpBridge::~TmTcUnixUdpBridge() { ReturnValue_t TmTcUnixUdpBridge::sendTm(const uint8_t *data, size_t dataLen) { int flags = 0; - sif::debug << "Client Port: "<(&clientAddress), clientAddressLen); if(bytesSent < 0) { - // todo: handle errors sif::error << "TmTcUnixUdpBridge::sendTm: Send operation failed." << std::endl; - sif::error << "Error: " << strerror(errno) << std::endl; handleSendError(); } - sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were" - " sent." << std::endl; +// sif::debug << "TmTcUnixUdpBridge::sendTm: " << bytesSent << " bytes were" +// " sent." << std::endl; return HasReturnvaluesIF::RETURN_OK; } void TmTcUnixUdpBridge::checkAndSetClientAddress(sockaddr_in newAddress) { MutexHelper lock(mutex, 10); - char ipAddress [15]; - sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET, - &newAddress.sin_addr.s_addr, ipAddress, 15) << std::endl; +// char ipAddress [15]; +// sif::debug << "IP Address Sender: "<< inet_ntop(AF_INET, +// &newAddress.sin_addr.s_addr, ipAddress, 15) << std::endl; +// sif::debug << "IP Address Old: " << inet_ntop(AF_INET, +// &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl; - sif::debug << "IP Address Old: " << inet_ntop(AF_INET, - &clientAddress.sin_addr.s_addr, ipAddress, 15) << std::endl; // Set new IP address if it has changed. if(clientAddress.sin_addr.s_addr != newAddress.sin_addr.s_addr) { - sif::info << "setting new address" << std::endl; clientAddress.sin_addr.s_addr = newAddress.sin_addr.s_addr; clientAddressLen = sizeof(clientAddress); } @@ -104,11 +112,11 @@ void TmTcUnixUdpBridge::handleSocketError() { case(ENOBUFS): case(ENOMEM): case(EPROTONOSUPPORT): - sif::error << "TmTcUnixBridge::TmTcUnixBridge: Socket creation failed" + sif::error << "TmTcUnixBridge::handleSocketError: Socket creation failed" << " with " << strerror(errno) << std::endl; break; default: - sif::error << "TmTcUnixBridge::TmTcUnixBridge: Unknown error" + sif::error << "TmTcUnixBridge::handleSocketError: Unknown error" << std::endl; break; } @@ -122,7 +130,7 @@ void TmTcUnixUdpBridge::handleBindError() { Ephermeral ports can be shown with following command: sysctl -A | grep ip_local_port_range */ - sif::error << "TmTcUnixBridge::TmTcUnixBridge: Port access issue." + sif::error << "TmTcUnixBridge::handleBindError: Port access issue." "Ports 1-1024 are reserved on UNIX systems and require root " "rights while ephermeral ports should not be used as well." << std::endl; @@ -140,19 +148,21 @@ void TmTcUnixUdpBridge::handleBindError() { case(ENOMEM): case(ENOTDIR): case(EROFS): { - sif::error << "TmTcUnixBridge::TmTcUnixBridge: Socket creation failed" + sif::error << "TmTcUnixBridge::handleBindError: Socket creation failed" << " with " << strerror(errno) << std::endl; break; } default: - sif::error << "TmTcUnixBridge::TmTcUnixBridge: Unknown error" + sif::error << "TmTcUnixBridge::handleBindError: Unknown error" << std::endl; break; } } void TmTcUnixUdpBridge::handleSendError() { - - + switch(errno) { + default: + sif::error << "Error: " << strerror(errno) << std::endl; + } } diff --git a/pus/Service2DeviceAccess.cpp b/pus/Service2DeviceAccess.cpp index 391c1116..4648aa9c 100644 --- a/pus/Service2DeviceAccess.cpp +++ b/pus/Service2DeviceAccess.cpp @@ -15,8 +15,7 @@ Service2DeviceAccess::Service2DeviceAccess(object_id_t objectId, object_id_t tmDestination, uint8_t numberOfParallelCommands, uint16_t commandTimeoutSeconds): CommandingServiceBase(objectId, apid, serviceId, - numberOfParallelCommands, commandTimeoutSeconds, - tcSource, tmDestination) {} + numberOfParallelCommands, commandTimeoutSeconds) {} Service2DeviceAccess::~Service2DeviceAccess() {} diff --git a/tcdistribution/PUSDistributor.cpp b/tcdistribution/PUSDistributor.cpp index d6e20acf..969380d6 100644 --- a/tcdistribution/PUSDistributor.cpp +++ b/tcdistribution/PUSDistributor.cpp @@ -13,12 +13,12 @@ PUSDistributor::PUSDistributor(uint16_t setApid, object_id_t setObjectId, PUSDistributor::~PUSDistributor() {} TcDistributor::TcMqMapIter PUSDistributor::selectDestination() { -// debug << "PUSDistributor::handlePacket received: " << this->current_packet_id.store_index << ", " << this->current_packet_id.packet_index << std::endl; TcMqMapIter queueMapIt = this->queueMap.end(); this->currentPacket.setStoreAddress(this->currentMessage.getStorageId()); if (currentPacket.getWholeData() != NULL) { tcStatus = checker.checkPacket(¤tPacket); -// info << "PUSDistributor::handlePacket: packetCheck returned with " << (int)tc_status << std::endl; +// sif::debug << "PUSDistributor::handlePacket: packetCheck returned with " +// << (int)tcStatus << std::endl; uint32_t queue_id = currentPacket.getService(); queueMapIt = this->queueMap.find(queue_id); } else { @@ -29,8 +29,8 @@ TcDistributor::TcMqMapIter PUSDistributor::selectDestination() { } if (tcStatus != RETURN_OK) { - sif::debug << "PUSDistributor::handlePacket: error with " << (int) tcStatus - << ", 0x"<< std::hex << (int) tcStatus << std::endl; + sif::debug << "PUSDistributor::handlePacket: Error with " << tcStatus + << ", 0x"<< std::hex << tcStatus << std::dec << std::endl; return this->queueMap.end(); } else { return queueMapIt; diff --git a/tmtcservices/CommandingServiceBase.cpp b/tmtcservices/CommandingServiceBase.cpp index 0c5f5eab..63a3d943 100644 --- a/tmtcservices/CommandingServiceBase.cpp +++ b/tmtcservices/CommandingServiceBase.cpp @@ -8,18 +8,28 @@ #include #include +object_id_t CommandingServiceBase::packetSource = objects::NO_OBJECT; +object_id_t CommandingServiceBase::packetDestination = objects::NO_OBJECT; + CommandingServiceBase::CommandingServiceBase(object_id_t setObjectId, uint16_t apid, uint8_t service, uint8_t numberOfParallelCommands, - uint16_t commandTimeoutSeconds, object_id_t setPacketSource, - object_id_t setPacketDestination, size_t queueDepth) : + uint16_t commandTimeoutSeconds, size_t queueDepth) : SystemObject(setObjectId), apid(apid), service(service), timeoutSeconds(commandTimeoutSeconds), - commandMap(numberOfParallelCommands), packetSource(setPacketSource), - packetDestination(setPacketDestination) { + commandMap(numberOfParallelCommands) { commandQueue = QueueFactory::instance()->createMessageQueue(queueDepth); requestQueue = QueueFactory::instance()->createMessageQueue(queueDepth); } +void CommandingServiceBase::setPacketSource(object_id_t packetSource) { + this->packetSource = packetSource; +} + +void CommandingServiceBase::setPacketDestination( + object_id_t packetDestination) { + this->packetDestination = packetDestination; +} + CommandingServiceBase::~CommandingServiceBase() { QueueFactory::instance()->deleteMessageQueue(commandQueue); diff --git a/tmtcservices/CommandingServiceBase.h b/tmtcservices/CommandingServiceBase.h index 700503c6..e9b5f047 100644 --- a/tmtcservices/CommandingServiceBase.h +++ b/tmtcservices/CommandingServiceBase.h @@ -15,6 +15,10 @@ class TcPacketStored; +namespace Factory{ +void setStaticFrameworkObjectIds(); +} + /** * @brief This class is the basis for all PUS Services, which have to * relay Telecommands to software bus. @@ -33,6 +37,7 @@ class CommandingServiceBase: public SystemObject, public AcceptsTelecommandsIF, public ExecutableObjectIF, public HasReturnvaluesIF { + friend void (Factory::setStaticFrameworkObjectIds)(); public: static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_SERVICE_BASE; static const ReturnValue_t EXECUTION_COMPLETE = MAKE_RETURN_CODE(1); @@ -57,10 +62,24 @@ public: */ CommandingServiceBase(object_id_t setObjectId, uint16_t apid, uint8_t service, uint8_t numberOfParallelCommands, - uint16_t commandTimeoutSeconds, object_id_t setPacketSource, - object_id_t setPacketDestination, size_t queueDepth = 20); + uint16_t commandTimeoutSeconds, size_t queueDepth = 20); virtual ~CommandingServiceBase(); + /** + * This setter can be used to set the packet source individually instead + * of using the default static framework ID set in the factory. + * This should be called at object initialization and not during run-time! + * @param packetSource + */ + void setPacketSource(object_id_t packetSource); + /** + * This setter can be used to set the packet destination individually + * instead of using the default static framework ID set in the factory. + * This should be called at object initialization and not during run-time! + * @param packetDestination + */ + void setPacketDestination(object_id_t packetDestination); + /*** * This is the periodically called function. * Handle request queue for external commands. @@ -229,9 +248,8 @@ protected: uint32_t failureParameter1 = 0; uint32_t failureParameter2 = 0; - object_id_t packetSource; - - object_id_t packetDestination; + static object_id_t packetSource; + static object_id_t packetDestination; /** * Pointer to the task which executes this component, diff --git a/tmtcservices/PusServiceBase.cpp b/tmtcservices/PusServiceBase.cpp index 4385609b..877eff3e 100644 --- a/tmtcservices/PusServiceBase.cpp +++ b/tmtcservices/PusServiceBase.cpp @@ -79,9 +79,8 @@ void PusServiceBase::handleRequestQueue() { } else { sif::error << "PusServiceBase::performOperation: Service " - << (uint16_t) this->serviceId - << ": Error receiving packet. Code: " << std::hex << status - << std::dec << std::endl; + << this->serviceId << ": Error receiving packet. Code: " + << std::hex << status << std::dec << std::endl; } } } From dc27cc9aff73e6c17eb36281d056bd7c217ba6b6 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 8 Jul 2020 18:37:26 +0200 Subject: [PATCH 16/17] srv8 added to framework --- pus/Service2DeviceAccess.cpp | 7 +- pus/Service2DeviceAccess.h | 3 +- pus/Service8FunctionManagement.cpp | 129 +++++++++++++++++++++++++ pus/Service8FunctionManagement.h | 64 +++++++++++++ pus/servicepackets/Service8Packets.h | 136 +++++++++++++++++++++++++++ 5 files changed, 334 insertions(+), 5 deletions(-) create mode 100644 pus/Service8FunctionManagement.cpp create mode 100644 pus/Service8FunctionManagement.h create mode 100644 pus/servicepackets/Service8Packets.h diff --git a/pus/Service2DeviceAccess.cpp b/pus/Service2DeviceAccess.cpp index 4648aa9c..1d5f21eb 100644 --- a/pus/Service2DeviceAccess.cpp +++ b/pus/Service2DeviceAccess.cpp @@ -11,14 +11,14 @@ #include Service2DeviceAccess::Service2DeviceAccess(object_id_t objectId, - uint16_t apid, uint8_t serviceId, object_id_t tcSource, - object_id_t tmDestination, uint8_t numberOfParallelCommands, + uint16_t apid, uint8_t serviceId, uint8_t numberOfParallelCommands, uint16_t commandTimeoutSeconds): CommandingServiceBase(objectId, apid, serviceId, numberOfParallelCommands, commandTimeoutSeconds) {} Service2DeviceAccess::~Service2DeviceAccess() {} + ReturnValue_t Service2DeviceAccess::isValidSubservice(uint8_t subservice) { switch(static_cast(subservice)){ case Subservice::RAW_COMMANDING: @@ -41,7 +41,6 @@ ReturnValue_t Service2DeviceAccess::getMessageQueueAndObject( ReturnValue_t result = checkInterfaceAndAcquireMessageQueue(id,objectId); return result; - } ReturnValue_t Service2DeviceAccess::checkInterfaceAndAcquireMessageQueue( @@ -55,6 +54,7 @@ ReturnValue_t Service2DeviceAccess::checkInterfaceAndAcquireMessageQueue( return HasReturnvaluesIF::RETURN_OK; } + ReturnValue_t Service2DeviceAccess::prepareCommand(CommandMessage* message, uint8_t subservice, const uint8_t* tcData, size_t tcDataLen, uint32_t* state, object_id_t objectId) { @@ -100,6 +100,7 @@ ReturnValue_t Service2DeviceAccess::prepareWiretappingCommand( return result; } + ReturnValue_t Service2DeviceAccess::handleReply(const CommandMessage* reply, Command_t previousCommand, uint32_t* state, CommandMessage* optionalNextCommand, object_id_t objectId, diff --git a/pus/Service2DeviceAccess.h b/pus/Service2DeviceAccess.h index 4dab0fa0..1a0bede0 100644 --- a/pus/Service2DeviceAccess.h +++ b/pus/Service2DeviceAccess.h @@ -36,8 +36,7 @@ class Service2DeviceAccess : public CommandingServiceBase, { public: Service2DeviceAccess(object_id_t objectId, uint16_t apid, - uint8_t serviceId, object_id_t tcSource, - object_id_t tmDestination, uint8_t numberOfParallelCommands = 4, + uint8_t serviceId, uint8_t numberOfParallelCommands = 4, uint16_t commandTimeoutSeconds = 60); virtual ~Service2DeviceAccess(); diff --git a/pus/Service8FunctionManagement.cpp b/pus/Service8FunctionManagement.cpp new file mode 100644 index 00000000..47afeae6 --- /dev/null +++ b/pus/Service8FunctionManagement.cpp @@ -0,0 +1,129 @@ +#include +#include + +#include +#include +#include +#include +#include +#include + +Service8FunctionManagement::Service8FunctionManagement(object_id_t object_id, + uint16_t apid, uint8_t serviceId, uint8_t numParallelCommands, + uint16_t commandTimeoutSeconds): + CommandingServiceBase(object_id, apid, serviceId, numParallelCommands, + commandTimeoutSeconds) {} + +Service8FunctionManagement::~Service8FunctionManagement() {} + + +ReturnValue_t Service8FunctionManagement::isValidSubservice( + uint8_t subservice) { + switch(static_cast(subservice)) { + case Subservice::DIRECT_COMMANDING: + return HasReturnvaluesIF::RETURN_OK; + default: + return AcceptsTelecommandsIF::INVALID_SUBSERVICE; + } +} + +ReturnValue_t Service8FunctionManagement::getMessageQueueAndObject( + uint8_t subservice, const uint8_t* tcData, size_t tcDataLen, + MessageQueueId_t* id, object_id_t* objectId) { + if(tcDataLen < sizeof(object_id_t)) { + return CommandingServiceBase::INVALID_TC; + } + SerializeAdapter::deSerialize(objectId, &tcData, + &tcDataLen, SerializeIF::Endianness::BIG); + + return checkInterfaceAndAcquireMessageQueue(id,objectId); +} + +ReturnValue_t Service8FunctionManagement::checkInterfaceAndAcquireMessageQueue( + MessageQueueId_t* messageQueueToSet, object_id_t* objectId) { + // check HasActionIF property of target + HasActionsIF* possibleTarget = objectManager->get(*objectId); + if(possibleTarget == nullptr){ + return CommandingServiceBase::INVALID_OBJECT; + } + *messageQueueToSet = possibleTarget->getCommandQueue(); + return HasReturnvaluesIF::RETURN_OK; +} + + +ReturnValue_t Service8FunctionManagement::prepareCommand( + CommandMessage* message, uint8_t subservice, const uint8_t* tcData, + size_t tcDataLen, uint32_t* state, object_id_t objectId) { + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + if(subservice == static_cast(Subservice::DIRECT_COMMANDING)) { + result = prepareDirectCommand(dynamic_cast(message), + tcData, tcDataLen); + } + return result; +} + +ReturnValue_t Service8FunctionManagement::prepareDirectCommand( + CommandMessage *message, const uint8_t *tcData, size_t tcDataLen) { + // Create direct command instance by extracting data from Telecommand + DirectCommand command(tcData,tcDataLen); + + // store additional parameters into the Inter Process Communication Store + store_address_t parameterAddress; + ReturnValue_t result = IPCStore->addData(¶meterAddress, + command.getParameters(),command.getParametersSize()); + + // setCommand expects a Command Message, an Action ID and a store adress + // pointing to additional parameters + ActionMessage::setCommand(message,command.getActionId(),parameterAddress); + return result; +} + + +ReturnValue_t Service8FunctionManagement::handleReply( + const CommandMessage* reply, Command_t previousCommand, + uint32_t* state, CommandMessage* optionalNextCommand, + object_id_t objectId, bool* isStep) { + Command_t replyId = reply->getCommand(); + ReturnValue_t result = HasReturnvaluesIF::RETURN_FAILED; + ActionId_t actionId = ActionMessage::getActionId(reply); + ReturnValue_t returnCode = ActionMessage::getReturnCode(reply); + + switch(replyId) { + case ActionMessage::COMPLETION_SUCCESS: { + DirectReply completionReply(objectId, actionId,returnCode); + result = CommandingServiceBase::EXECUTION_COMPLETE; + break; + } + case ActionMessage::STEP_SUCCESS: { + *isStep = true; + result = HasReturnvaluesIF::RETURN_OK; + break; + } + case ActionMessage::DATA_REPLY: { + store_address_t storeId = ActionMessage::getStoreId(reply); + size_t size = 0; + const uint8_t * buffer = nullptr; + result = IPCStore->getData(storeId, &buffer, &size); + if(result != RETURN_OK) { + sif::error << "Service 8: Could not retrieve data for data reply"; + return result; + } + DataReply dataReply(objectId,actionId,buffer,size); + sendTmPacket(static_cast( + Subservice::DIRECT_COMMANDING_DATA_REPLY), &dataReply); + result = IPCStore ->deleteData(storeId); + break; + } + case ActionMessage::STEP_FAILED: + *isStep = true; + /*No break, falls through*/ + case ActionMessage::COMPLETION_FAILED: + result = ActionMessage::getReturnCode(reply); + break; + default: + result = INVALID_REPLY; + } + return result; +} + + diff --git a/pus/Service8FunctionManagement.h b/pus/Service8FunctionManagement.h new file mode 100644 index 00000000..e06c554c --- /dev/null +++ b/pus/Service8FunctionManagement.h @@ -0,0 +1,64 @@ +#ifndef MISSION_SERVICE8FUNCTIONMANAGEMENT_H_ +#define MISSION_SERVICE8FUNCTIONMANAGEMENT_H_ + +#include + +/** + * @brief Functional commanding. + * Full Documentation: ECSS-E-ST-70-41C p.64, p. 451 + * Dissertation Baetz p. 115, 116, 165-167 + * + * This service provides the capability to perform functions of an + * application process and provides high-level commanding as opposed to the + * Raw Access provided by Service 2. Examples for these functions can include + * control and operation of payload or the AOCS subsystem. + * This service will be the primary means to control the spacecraft as it is + * considered safer than the Raw Access provided + * by Service 2 and is generally sufficient for most tasks. + * + * This is a gateway service. It relays device commands using the software bus. + * This service is very closely tied to the Commanding Service Base template + * class. There is constant interaction between this Service Base und a + * subclass like this service. + * + * Service Capability: + * - TC[8,128]: Direct Commanding + * - TM[8,130]: Direct Commanding Data Reply + * + * @ingroup pus_services + */ +class Service8FunctionManagement : public CommandingServiceBase +{ +public: + Service8FunctionManagement(object_id_t objectId, uint16_t apid, + uint8_t serviceId, uint8_t numParallelCommands = 4, + uint16_t commandTimeoutSeconds = 60); + virtual ~Service8FunctionManagement(); + +protected: + /* CSB abstract functions implementation . See CSB documentation. */ + ReturnValue_t isValidSubservice(uint8_t subservice) override; + ReturnValue_t getMessageQueueAndObject(uint8_t subservice, + const uint8_t *tcData, size_t tcDataLen, MessageQueueId_t *id, + object_id_t *objectId) override; + ReturnValue_t prepareCommand(CommandMessage* message, + uint8_t subservice, const uint8_t *tcData, size_t tcDataLen, + uint32_t *state, object_id_t objectId) override; + ReturnValue_t handleReply(const CommandMessage* reply, + Command_t previousCommand, uint32_t *state, + CommandMessage* optionalNextCommand, object_id_t objectId, + bool *isStep) override; + +private: + enum class Subservice { + DIRECT_COMMANDING = 128, //!< [EXPORT] : [COMMAND] Functional commanding + DIRECT_COMMANDING_DATA_REPLY = 130, //!< [EXPORT] : [REPLY] Data reply + }; + + ReturnValue_t checkInterfaceAndAcquireMessageQueue( + MessageQueueId_t* messageQueueToSet, object_id_t* objectId); + ReturnValue_t prepareDirectCommand(CommandMessage* message, + const uint8_t* tcData, size_t tcDataLen); +}; + +#endif /* MISSION_DEVICE2DEVICECOMMANDING_H_ */ diff --git a/pus/servicepackets/Service8Packets.h b/pus/servicepackets/Service8Packets.h new file mode 100644 index 00000000..5ef91280 --- /dev/null +++ b/pus/servicepackets/Service8Packets.h @@ -0,0 +1,136 @@ +/** + * \file Service8Packets.h + * + * \brief Structure of a Direct Command. + * Normal reply (subservice 130) consists of + * 1. Target object ID + * 2. Action ID (taget device has specified functions with action IDs) + * 3. Return Code + * 4. Optional step number for step replies + * + * Data reply (subservice 132) consists of + * 1. Target Object ID + * 2. Action ID + * 3. Data + * + * \date 01.07.2019 + * \author R. Mueller + */ + +#ifndef FRAMEWORK_PUS_SERVICEPACKETS_SERVICE8PACKETS_H_ +#define FRAMEWORK_PUS_SERVICEPACKETS_SERVICE8PACKETS_H_ + +#include +#include +#include +#include +#include +#include + + +/** + * \brief Subservice 128 + * \ingroup spacepackets + */ +class DirectCommand: public SerialLinkedListAdapter { //!< [EXPORT] : [SUBSERVICE] 128 +public: + //typedef uint16_t typeOfMaxData; + //static const typeOfMaxData MAX_DATA = 256; + DirectCommand(const uint8_t* dataBuffer_, uint32_t size_) { + size_t size = sizeof(objectId); + SerializeAdapter::deSerialize(&objectId,&dataBuffer_,&size, + SerializeIF::Endianness::BIG); + size = sizeof(actionId); + SerializeAdapter::deSerialize(&actionId,&dataBuffer_,&size, + SerializeIF::Endianness::BIG); + parameterBuffer = dataBuffer_; + parametersSize = size_ - sizeof(objectId) - sizeof(actionId); + } + ActionId_t getActionId() const { + return actionId; + } + + object_id_t getObjectId() const { + return objectId; + } + + const uint8_t* getParameters() { + return parameterBuffer; + } + + uint32_t getParametersSize() const { + return parametersSize; + } + +private: + DirectCommand(const DirectCommand &command); + object_id_t objectId; + ActionId_t actionId; + uint32_t parametersSize; //!< [EXPORT] : [IGNORE] + const uint8_t * parameterBuffer; //!< [EXPORT] : [MAXSIZE] 65535 Bytes + +}; + + +/** + * \brief Subservice 130 + * \ingroup spacepackets + */ +class DataReply: public SerialLinkedListAdapter { //!< [EXPORT] : [SUBSERVICE] 130 +public: + typedef uint16_t typeOfMaxDataSize; + static const uint16_t MAX_DATA_LENGTH = sizeof(typeOfMaxDataSize); + DataReply(object_id_t objectId_, ActionId_t actionId_, + const uint8_t * replyDataBuffer_ = NULL, uint16_t replyDataSize_ = 0): + objectId(objectId_), actionId(actionId_), replyData(replyDataBuffer_,replyDataSize_){ + setLinks(); + } + +private: + DataReply(const DataReply &reply); + void setLinks() { + setStart(&objectId); + objectId.setNext(&actionId); + actionId.setNext(&replyData); + } + SerializeElement objectId; + SerializeElement actionId; + SerializeElement> replyData; +}; + + +/** + * \brief Subservice 132 + * \ingroup spacepackets + */ +class DirectReply: public SerialLinkedListAdapter { //!< [EXPORT] : [SUBSERVICE] 132 +public: + typedef uint16_t typeOfMaxDataSize; + static const uint16_t MAX_DATA_LENGTH = sizeof(typeOfMaxDataSize); + + DirectReply(object_id_t objectId_, ActionId_t actionId_, ReturnValue_t returnCode_, + bool isStep_ = false, uint8_t step_ = 0): + isStep(isStep_), objectId(objectId_), actionId(actionId_), + returnCode(returnCode_),step(step_) { + setLinks(); + } +private: + + void setLinks() { + setStart(&objectId); + objectId.setNext(&actionId); + actionId.setNext(&returnCode); + if(isStep) { + returnCode.setNext(&step); + } + } + bool isDataReply; //!< [EXPORT] : [IGNORE] + bool isStep; //!< [EXPORT] : [IGNORE] + SerializeElement objectId; //!< [EXPORT] : [IGNORE] + SerializeElement actionId; //!< [EXPORT] : [IGNORE] + SerializeElement returnCode; //!< [EXPORT] : [IGNORE] + SerializeElement step; //!< [EXPORT] : [OPTIONAL] [IGNORE] + +}; + +#endif /* FRAMEWORK_PUS_SERVICEPACKETS_SERVICE8PACKETS_H_ */ From 64c290ffe44ce6a4352152bcb1a04ff643bfd395 Mon Sep 17 00:00:00 2001 From: "Robin.Mueller" Date: Wed, 8 Jul 2020 18:38:58 +0200 Subject: [PATCH 17/17] include guard fix --- pus/Service8FunctionManagement.cpp | 2 +- pus/Service8FunctionManagement.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/pus/Service8FunctionManagement.cpp b/pus/Service8FunctionManagement.cpp index 47afeae6..24338464 100644 --- a/pus/Service8FunctionManagement.cpp +++ b/pus/Service8FunctionManagement.cpp @@ -67,7 +67,7 @@ ReturnValue_t Service8FunctionManagement::prepareDirectCommand( // Create direct command instance by extracting data from Telecommand DirectCommand command(tcData,tcDataLen); - // store additional parameters into the Inter Process Communication Store + // store additional parameters into the IPC Store store_address_t parameterAddress; ReturnValue_t result = IPCStore->addData(¶meterAddress, command.getParameters(),command.getParametersSize()); diff --git a/pus/Service8FunctionManagement.h b/pus/Service8FunctionManagement.h index e06c554c..54c98b97 100644 --- a/pus/Service8FunctionManagement.h +++ b/pus/Service8FunctionManagement.h @@ -1,5 +1,5 @@ -#ifndef MISSION_SERVICE8FUNCTIONMANAGEMENT_H_ -#define MISSION_SERVICE8FUNCTIONMANAGEMENT_H_ +#ifndef FRAMEWORK_PUS_SERVICE8FUNCTIONMANAGEMENT_H_ +#define FRAMEWORK_PUS_SERVICE8FUNCTIONMANAGEMENT_H_ #include @@ -61,4 +61,4 @@ private: const uint8_t* tcData, size_t tcDataLen); }; -#endif /* MISSION_DEVICE2DEVICECOMMANDING_H_ */ +#endif /* FRAMEWORK_PUS_SERVICE8FUNCTIONMANAGEMENT_H_ */