diff --git a/osal/linux/MessageQueue.cpp b/osal/linux/MessageQueue.cpp index 86d1e0d9..a0749ded 100644 --- a/osal/linux/MessageQueue.cpp +++ b/osal/linux/MessageQueue.cpp @@ -9,8 +9,9 @@ #include -MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize): id(0), - lastPartner(0), defaultDestination(NO_QUEUE) { +MessageQueue::MessageQueue(uint32_t messageDepth, size_t maxMessageSize): + id(MessageQueueIF::NO_QUEUE),lastPartner(MessageQueueIF::NO_QUEUE), + defaultDestination(MessageQueueIF::NO_QUEUE) { //debug << "MessageQueue::MessageQueue: Creating a queue" << std::endl; mq_attr attributes; this->id = 0; @@ -56,16 +57,23 @@ ReturnValue_t MessageQueue::handleError(mq_attr* attributes, sif::error << "MessageQueue::MessageQueue: Invalid name or attributes" " for message size" << std::endl; size_t defaultMqMaxMsg = 0; + // Not POSIX conformant, but should work for all UNIX systems. + // Just an additional helpful printout :-) if(std::ifstream("/proc/sys/fs/mqueue/msg_max",std::ios::in) >> defaultMqMaxMsg and defaultMqMaxMsg < messageDepth) { // See: https://www.man7.org/linux/man-pages/man3/mq_open.3.html // This happens if the msg_max value is not large enough // It is ignored if the executable is run in privileged mode. - // Run the unlockRealtime script or grant the mode manully by using: + // Run the unlockRealtime script or grant the mode manually by using: // sudo setcap 'CAP_SYS_RESOURCE=+ep' - // Permanent solution (EventManager has mq depth of 80): - // echo msg_max | sudo tee /proc/sys/fs/mqueue/msg_max + // Persistent solution for session: + // echo | sudo tee /proc/sys/fs/mqueue/msg_max + + // Permanent solution: + // sudo nano /etc/sysctl.conf + // Append at end: fs/mqueue/msg_max = + // Apply changes with: sudo sysctl -p sif::error << "MessageQueue::MessageQueue: Default MQ size " << defaultMqMaxMsg << " is too small for requested size " << messageDepth << std::endl; @@ -75,24 +83,22 @@ ReturnValue_t MessageQueue::handleError(mq_attr* attributes, case(EEXIST): { // An error occured during open // We need to distinguish if it is caused by an already created queue - if (errno == EEXIST) { - //There's another queue with the same name - //We unlink the other queue - int status = mq_unlink(name); - if (status != 0) { - sif::error << "mq_unlink Failed with status: " << strerror(errno) - << std::endl; - } - else { - // Successful unlinking, try to open again - mqd_t tempId = mq_open(name, - O_NONBLOCK | O_RDWR | O_CREAT | O_EXCL, - S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP, attributes); - if (tempId != -1) { - //Successful mq_open - this->id = tempId; - return HasReturnvaluesIF::RETURN_OK; - } + //There's another queue with the same name + //We unlink the other queue + int status = mq_unlink(name); + if (status != 0) { + sif::error << "mq_unlink Failed with status: " << strerror(errno) + << std::endl; + } + else { + // Successful unlinking, try to open again + mqd_t tempId = mq_open(name, + O_NONBLOCK | O_RDWR | O_CREAT | O_EXCL, + S_IWUSR | S_IREAD | S_IWGRP | S_IRGRP, attributes); + if (tempId != -1) { + //Successful mq_open + this->id = tempId; + return HasReturnvaluesIF::RETURN_OK; } } break; @@ -150,12 +156,13 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message) { //Success but no message received return MessageQueueIF::EMPTY; } else { - //No message was received. Keep lastPartner anyway, I might send something later. - //But still, delete packet content. + //No message was received. Keep lastPartner anyway, I might send + //something later. But still, delete packet content. memset(message->getData(), 0, message->MAX_DATA_SIZE); switch(errno){ case EAGAIN: - //O_NONBLOCK or MQ_NONBLOCK was set and there are no messages currently on the specified queue. + //O_NONBLOCK or MQ_NONBLOCK was set and there are no messages + //currently on the specified queue. return MessageQueueIF::EMPTY; case EBADF: //mqdes doesn't represent a valid queue open for reading. @@ -165,9 +172,12 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message) { case EINVAL: /* * This value indicates one of the following: - * * The pointer to the buffer for storing the received message, msg_ptr, is NULL. - * * The number of bytes requested, msg_len is less than zero. - * * msg_len is anything other than the mq_msgsize of the specified queue, and the QNX extended option MQ_READBUF_DYNAMIC hasn't been set in the queue's mq_flags. + * - The pointer to the buffer for storing the received message, + * msg_ptr, is NULL. + * - The number of bytes requested, msg_len is less than zero. + * - msg_len is anything other than the mq_msgsize of the specified + * queue, and the QNX extended option MQ_READBUF_DYNAMIC hasn't + * been set in the queue's mq_flags. */ sif::error << "MessageQueue::receive: configuration error " << strerror(errno) << std::endl; @@ -175,8 +185,12 @@ ReturnValue_t MessageQueue::receiveMessage(MessageQueueMessage* message) { case EMSGSIZE: /* * This value indicates one of the following: - * * the QNX extended option MQ_READBUF_DYNAMIC hasn't been set, and the given msg_len is shorter than the mq_msgsize for the given queue. - * * the extended option MQ_READBUF_DYNAMIC has been set, but the given msg_len is too short for the message that would have been received. + * - the QNX extended option MQ_READBUF_DYNAMIC hasn't been set, + * and the given msg_len is shorter than the mq_msgsize for + * the given queue. + * - the extended option MQ_READBUF_DYNAMIC has been set, but the + * given msg_len is too short for the message that would have + * been received. */ sif::error << "MessageQueue::receive: configuration error " << strerror(errno) << std::endl; @@ -224,9 +238,10 @@ ReturnValue_t MessageQueue::flush(uint32_t* count) { case EINVAL: /* * This value indicates one of the following: - * * mq_attr is NULL. - * * MQ_MULT_NOTIFY had been set for this queue, and the given mq_flags includes a 0 in the MQ_MULT_NOTIFY bit. Once MQ_MULT_NOTIFY has been turned on, it may never be turned off. - * + * - mq_attr is NULL. + * - MQ_MULT_NOTIFY had been set for this queue, and the given + * mq_flags includes a 0 in the MQ_MULT_NOTIFY bit. Once + * MQ_MULT_NOTIFY has been turned on, it may never be turned off. */ default: return HasReturnvaluesIF::RETURN_FAILED; @@ -275,7 +290,8 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, //TODO: Check if we're in ISR. if (result != 0) { if(!ignoreFault){ - InternalErrorReporterIF* internalErrorReporter = objectManager->get( + InternalErrorReporterIF* internalErrorReporter = + objectManager->get( objects::INTERNAL_ERROR_REPORTER); if (internalErrorReporter != NULL) { internalErrorReporter->queueMessageNotSent(); @@ -283,10 +299,13 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, } switch(errno){ case EAGAIN: - //The O_NONBLOCK flag was set when opening the queue, or the MQ_NONBLOCK flag was set in its attributes, and the specified queue is full. + //The O_NONBLOCK flag was set when opening the queue, or the + //MQ_NONBLOCK flag was set in its attributes, and the + //specified queue is full. return MessageQueueIF::FULL; case EBADF: - //mq_des doesn't represent a valid message queue descriptor, or mq_des wasn't opened for writing. + //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; @@ -296,13 +315,13 @@ ReturnValue_t MessageQueue::sendMessageFromMessageQueue(MessageQueueId_t sendTo, case EINVAL: /* * This value indicates one of the following: - * * msg_ptr is NULL. - * * msg_len is negative. - * * msg_prio is greater than MQ_PRIO_MAX. - * * msg_prio is less than 0. - * * MQ_PRIO_RESTRICT is set in the mq_attr of mq_des, - * and msg_prio is greater than the priority of the calling process. - * */ + * - msg_ptr is NULL. + * - msg_len is negative. + * - msg_prio is greater than MQ_PRIO_MAX. + * - msg_prio is less than 0. + * - MQ_PRIO_RESTRICT is set in the mq_attr of mq_des, and + * msg_prio is greater than the priority of the calling process. + */ sif::error << "MessageQueue::sendMessage: Configuration error " << strerror(errno) << " in mq_send" << std::endl; /*NO BREAK*/ diff --git a/tmtcservices/CommandingServiceBase.cpp b/tmtcservices/CommandingServiceBase.cpp index a4fc1110..72351995 100644 --- a/tmtcservices/CommandingServiceBase.cpp +++ b/tmtcservices/CommandingServiceBase.cpp @@ -1,22 +1,21 @@ -/* - * CommandingServiceBase.cpp - * - * Created on: 28.08.2019 - * Author: gaisser - */ +#include +#include +#include #include +#include +#include +#include +#include CommandingServiceBase::CommandingServiceBase(object_id_t setObjectId, uint16_t apid, uint8_t service, uint8_t numberOfParallelCommands, - uint16_t commandTimeout_seconds, object_id_t setPacketSource, + uint16_t commandTimeoutSeconds, object_id_t setPacketSource, object_id_t setPacketDestination, size_t queueDepth) : - SystemObject(setObjectId), apid(apid), service(service), timeout_seconds( - commandTimeout_seconds), tmPacketCounter(0), IPCStore(NULL), TCStore( - NULL), commandQueue(NULL), requestQueue(NULL), commandMap( - numberOfParallelCommands), failureParameter1(0), failureParameter2( - 0), packetSource(setPacketSource), packetDestination( - setPacketDestination),executingTask(NULL) { + SystemObject(setObjectId), apid(apid), service(service), + timeoutSeconds(commandTimeoutSeconds), + commandMap(numberOfParallelCommands), packetSource(setPacketSource), + packetDestination(setPacketDestination) { commandQueue = QueueFactory::instance()->createMessageQueue(queueDepth); requestQueue = QueueFactory::instance()->createMessageQueue(queueDepth); } @@ -57,7 +56,7 @@ ReturnValue_t CommandingServiceBase::initialize() { objectManager->get(packetDestination); PUSDistributorIF* distributor = objectManager->get( packetSource); - if ((packetForwarding == NULL) && (distributor == NULL)) { + if (packetForwarding == nullptr or distributor == nullptr) { return RETURN_FAILED; } @@ -68,7 +67,7 @@ ReturnValue_t CommandingServiceBase::initialize() { IPCStore = objectManager->get(objects::IPC_STORE); TCStore = objectManager->get(objects::TC_STORE); - if ((IPCStore == NULL) || (TCStore == NULL)) { + if (IPCStore == nullptr or TCStore == nullptr) { return RETURN_FAILED; } @@ -77,100 +76,118 @@ ReturnValue_t CommandingServiceBase::initialize() { } void CommandingServiceBase::handleCommandQueue() { - MessageQueueMessage replyMessage; - CommandMessage reply(&replyMessage); - MessageQueueMessage nextCommandMessage; - CommandMessage nextCommand(&nextCommandMessage); - ReturnValue_t result, sendResult = RETURN_OK; - bool isStep = false; + MessageQueueMessage message; + CommandMessage reply(&message); + ReturnValue_t result = RETURN_FAILED; for (result = commandQueue->receiveMessage(&reply); result == RETURN_OK; result = commandQueue->receiveMessage(&reply)) { - isStep = false; - typename FixedMap::Iterator iter; - if (reply.getSender() == MessageQueueIF::NO_QUEUE) { - handleUnrequestedReply(&reply); - continue; - } - if ((iter = commandMap.find(reply.getSender())) == commandMap.end()) { - handleUnrequestedReply(&reply); - continue; - } - nextCommand.setCommand(CommandMessage::CMD_NONE); - result = handleReply(&reply, iter->command, &iter->state, &nextCommand, - iter->objectId, &isStep); - switch (result) { - case EXECUTION_COMPLETE: - case RETURN_OK: - case NO_STEP_MESSAGE: - iter->command = nextCommand.getCommand(); - if (nextCommand.getCommand() != CommandMessage::CMD_NONE) { - sendResult = commandQueue->sendMessage(reply.getSender(), - &nextCommand); - } - if (sendResult == RETURN_OK) { - if (isStep) { - if (result != NO_STEP_MESSAGE) { - verificationReporter.sendSuccessReport( - TC_VERIFY::PROGRESS_SUCCESS, - iter->tcInfo.ackFlags, iter->tcInfo.tcPacketId, - iter->tcInfo.tcSequenceControl, ++iter->step); - } - } else { - verificationReporter.sendSuccessReport( - TC_VERIFY::COMPLETION_SUCCESS, - iter->tcInfo.ackFlags, iter->tcInfo.tcPacketId, - iter->tcInfo.tcSequenceControl, 0); - checkAndExecuteFifo(&iter); - } - } else { - if (isStep) { - nextCommand.clearCommandMessage(); - verificationReporter.sendFailureReport( - TC_VERIFY::PROGRESS_FAILURE, iter->tcInfo.ackFlags, - iter->tcInfo.tcPacketId, - iter->tcInfo.tcSequenceControl, sendResult, - ++iter->step, failureParameter1, failureParameter2); - } else { - nextCommand.clearCommandMessage(); - verificationReporter.sendFailureReport( - TC_VERIFY::COMPLETION_FAILURE, - iter->tcInfo.ackFlags, iter->tcInfo.tcPacketId, - iter->tcInfo.tcSequenceControl, sendResult, 0, - failureParameter1, failureParameter2); - } - failureParameter1 = 0; - failureParameter2 = 0; - checkAndExecuteFifo(&iter); - } - break; - case INVALID_REPLY: - //might be just an unrequested reply at a bad moment - handleUnrequestedReply(&reply); - break; - default: - if (isStep) { - verificationReporter.sendFailureReport( - TC_VERIFY::PROGRESS_FAILURE, iter->tcInfo.ackFlags, - iter->tcInfo.tcPacketId, iter->tcInfo.tcSequenceControl, - result, ++iter->step, failureParameter1, - failureParameter2); - } else { - verificationReporter.sendFailureReport( - TC_VERIFY::COMPLETION_FAILURE, iter->tcInfo.ackFlags, - iter->tcInfo.tcPacketId, iter->tcInfo.tcSequenceControl, - result, 0, failureParameter1, failureParameter2); - } - failureParameter1 = 0; - failureParameter2 = 0; - checkAndExecuteFifo(&iter); - break; - } - + handleCommandMessage(reply); } } +void CommandingServiceBase::handleCommandMessage(CommandMessage& reply) { + bool isStep = false; + MessageQueueMessage message; + CommandMessage nextCommand(&message); + CommandMapIter iter; + if (reply.getSender() == MessageQueueIF::NO_QUEUE) { + handleUnrequestedReply(&reply); + return; + } + if ((iter = commandMap.find(reply.getSender())) == commandMap.end()) { + handleUnrequestedReply(&reply); + return; + } + nextCommand.setCommand(CommandMessage::CMD_NONE); + + // Implemented by child class, specifies what to do with reply. + ReturnValue_t result = handleReply(&reply, iter->command, &iter->state, + &nextCommand, iter->objectId, &isStep); + + switch (result) { + case EXECUTION_COMPLETE: + case RETURN_OK: + case NO_STEP_MESSAGE: + // handle result of reply handler implemented by developer. + handleReplyHandlerResult(result, iter, nextCommand, reply, isStep); + break; + case INVALID_REPLY: + //might be just an unrequested reply at a bad moment + handleUnrequestedReply(&reply); + break; + default: + if (isStep) { + verificationReporter.sendFailureReport( + TC_VERIFY::PROGRESS_FAILURE, iter->tcInfo.ackFlags, + iter->tcInfo.tcPacketId, iter->tcInfo.tcSequenceControl, + result, ++iter->step, failureParameter1, + failureParameter2); + } else { + verificationReporter.sendFailureReport( + TC_VERIFY::COMPLETION_FAILURE, iter->tcInfo.ackFlags, + iter->tcInfo.tcPacketId, iter->tcInfo.tcSequenceControl, + result, 0, failureParameter1, failureParameter2); + } + failureParameter1 = 0; + failureParameter2 = 0; + checkAndExecuteFifo(iter); + break; + } + +} + +void CommandingServiceBase::handleReplyHandlerResult(ReturnValue_t result, + CommandMapIter iter, CommandMessage& nextCommand, CommandMessage& reply, + bool& isStep) { + iter->command = nextCommand.getCommand(); + + // In case a new command is to be sent immediately, this is performed here. + // If no new command is sent, only analyse reply result by initializing + // sendResult as RETURN_OK + ReturnValue_t sendResult = RETURN_OK; + if (nextCommand.getCommand() != CommandMessage::CMD_NONE) { + sendResult = commandQueue->sendMessage(reply.getSender(), + &nextCommand); + } + + if (sendResult == RETURN_OK) { + if (isStep and result != NO_STEP_MESSAGE) { + verificationReporter.sendSuccessReport( + TC_VERIFY::PROGRESS_SUCCESS, + iter->tcInfo.ackFlags, iter->tcInfo.tcPacketId, + iter->tcInfo.tcSequenceControl, ++iter->step); + } + else { + verificationReporter.sendSuccessReport( + TC_VERIFY::COMPLETION_SUCCESS, + iter->tcInfo.ackFlags, iter->tcInfo.tcPacketId, + iter->tcInfo.tcSequenceControl, 0); + checkAndExecuteFifo(iter); + } + } + else { + if (isStep) { + nextCommand.clearCommandMessage(); + verificationReporter.sendFailureReport( + TC_VERIFY::PROGRESS_FAILURE, iter->tcInfo.ackFlags, + iter->tcInfo.tcPacketId, + iter->tcInfo.tcSequenceControl, sendResult, + ++iter->step, failureParameter1, failureParameter2); + } else { + nextCommand.clearCommandMessage(); + verificationReporter.sendFailureReport( + TC_VERIFY::COMPLETION_FAILURE, + iter->tcInfo.ackFlags, iter->tcInfo.tcPacketId, + iter->tcInfo.tcSequenceControl, sendResult, 0, + failureParameter1, failureParameter2); + } + failureParameter1 = 0; + failureParameter2 = 0; + checkAndExecuteFifo(iter); + } +} + void CommandingServiceBase::handleRequestQueue() { TmTcMessage message; ReturnValue_t result; @@ -183,8 +200,8 @@ void CommandingServiceBase::handleRequestQueue() { address = message.getStorageId(); packet.setStoreAddress(address); - if ((packet.getSubService() == 0) - || (isValidSubservice(packet.getSubService()) != RETURN_OK)) { + if (packet.getSubService() == 0 + or isValidSubservice(packet.getSubService()) != RETURN_OK) { rejectPacket(TC_VERIFY::START_FAILURE, &packet, INVALID_SUBSERVICE); continue; } @@ -197,8 +214,7 @@ void CommandingServiceBase::handleRequestQueue() { } //Is a command already active for the target object? - typename FixedMap::Iterator iter; + CommandMapIter iter; iter = commandMap.find(queue); if (iter != commandMap.end()) { @@ -213,7 +229,7 @@ void CommandingServiceBase::handleRequestQueue() { if (result != RETURN_OK) { rejectPacket(TC_VERIFY::START_FAILURE, &packet, BUSY); } else { - startExecution(&packet, &iter); + startExecution(&packet, iter); } } @@ -266,34 +282,32 @@ ReturnValue_t CommandingServiceBase::sendTmPacket(uint8_t subservice, } -void CommandingServiceBase::startExecution( - TcPacketStored *storedPacket, - typename FixedMap::Iterator *iter) { - ReturnValue_t result, sendResult = RETURN_OK; - MessageQueueMessage message; - CommandMessage command(&message); - (*iter)->subservice = storedPacket->getSubService(); - result = prepareCommand(&command, (*iter)->subservice, - storedPacket->getApplicationData(), - storedPacket->getApplicationDataSize(), &(*iter)->state, - (*iter)->objectId); +void CommandingServiceBase::startExecution(TcPacketStored *storedPacket, + CommandMapIter iter) { + ReturnValue_t result = RETURN_OK; + MessageQueueMessage message; + CommandMessage command(&message); + iter->subservice = storedPacket->getSubService(); + result = prepareCommand(&command, iter->subservice, + storedPacket->getApplicationData(), + storedPacket->getApplicationDataSize(), &iter->state, + iter->objectId); + ReturnValue_t sendResult = RETURN_OK; switch (result) { case RETURN_OK: if (command.getCommand() != CommandMessage::CMD_NONE) { - sendResult = commandQueue->sendMessage((*iter).value->first, + sendResult = commandQueue->sendMessage(iter.value->first, &message); } if (sendResult == RETURN_OK) { - Clock::getUptime(&(*iter)->uptimeOfStart); - (*iter)->step = 0; -// (*iter)->state = 0; - (*iter)->subservice = storedPacket->getSubService(); - (*iter)->command = command.getCommand(); - (*iter)->tcInfo.ackFlags = storedPacket->getAcknowledgeFlags(); - (*iter)->tcInfo.tcPacketId = storedPacket->getPacketId(); - (*iter)->tcInfo.tcSequenceControl = + Clock::getUptime(&iter->uptimeOfStart); + iter->step = 0; + iter->subservice = storedPacket->getSubService(); + iter->command = command.getCommand(); + iter->tcInfo.ackFlags = storedPacket->getAcknowledgeFlags(); + iter->tcInfo.tcPacketId = storedPacket->getPacketId(); + iter->tcInfo.tcSequenceControl = storedPacket->getPacketSequenceControl(); acceptPacket(TC_VERIFY::START_SUCCESS, storedPacket); } else { @@ -305,7 +319,7 @@ void CommandingServiceBase::startExecution( case EXECUTION_COMPLETE: if (command.getCommand() != CommandMessage::CMD_NONE) { //Fire-and-forget command. - sendResult = commandQueue->sendMessage((*iter).value->first, + sendResult = commandQueue->sendMessage(iter.value->first, &message); } if (sendResult == RETURN_OK) { @@ -341,12 +355,10 @@ void CommandingServiceBase::acceptPacket(uint8_t reportId, } -void CommandingServiceBase::checkAndExecuteFifo( - typename FixedMap::Iterator *iter) { +void CommandingServiceBase::checkAndExecuteFifo(CommandMapIter iter) { store_address_t address; - if ((*iter)->fifo.retrieve(&address) != RETURN_OK) { - commandMap.erase(iter); + if (iter->fifo.retrieve(&address) != RETURN_OK) { + commandMap.erase(&iter); } else { TcPacketStored newPacket(address); startExecution(&newPacket, iter); @@ -370,15 +382,14 @@ MessageQueueId_t CommandingServiceBase::getCommandQueue() { void CommandingServiceBase::checkTimeout() { uint32_t uptime; Clock::getUptime(&uptime); - typename FixedMap::Iterator iter; + CommandMapIter iter; for (iter = commandMap.begin(); iter != commandMap.end(); ++iter) { - if ((iter->uptimeOfStart + (timeout_seconds * 1000)) < uptime) { + if ((iter->uptimeOfStart + (timeoutSeconds * 1000)) < uptime) { verificationReporter.sendFailureReport( TC_VERIFY::COMPLETION_FAILURE, iter->tcInfo.ackFlags, iter->tcInfo.tcPacketId, iter->tcInfo.tcSequenceControl, TIMEOUT); - checkAndExecuteFifo(&iter); + checkAndExecuteFifo(iter); } } } diff --git a/tmtcservices/CommandingServiceBase.h b/tmtcservices/CommandingServiceBase.h index e79e806d..1dcafff8 100644 --- a/tmtcservices/CommandingServiceBase.h +++ b/tmtcservices/CommandingServiceBase.h @@ -1,35 +1,33 @@ -#ifndef COMMANDINGSERVICEBASE_H_ -#define COMMANDINGSERVICEBASE_H_ +#ifndef FRAMEWORK_TMTCSERVICES_COMMANDINGSERVICEBASE_H_ +#define FRAMEWORK_TMTCSERVICES_COMMANDINGSERVICEBASE_H_ -#include -#include -#include -#include #include -#include #include #include -#include -#include -#include +#include #include -#include -#include + #include -#include -#include -#include +#include +#include +#include +#include + +class TcPacketStored; /** - * \brief This class is the basis for all PUS Services, which have to relay Telecommands to software bus. + * @brief This class is the basis for all PUS Services, which have to + * relay Telecommands to software bus. * - * It manages Telecommand reception and the generation of Verification Reports like PUSServiceBase. - * Every class that inherits from this abstract class has to implement four adaption points: + * It manages Telecommand reception and the generation of Verification Reports + * similar to PusServiceBase. This class is used if a telecommand can't be + * handled immediately and must be relayed to the internal software bus. * - isValidSubservice * - getMessageQueueAndObject * - prepareCommand * - handleReply - * \ingroup pus_services + * @author gaisser + * @ingroup pus_services */ class CommandingServiceBase: public SystemObject, public AcceptsTelecommandsIF, @@ -59,7 +57,7 @@ public: */ CommandingServiceBase(object_id_t setObjectId, uint16_t apid, uint8_t service, uint8_t numberOfParallelCommands, - uint16_t commandTimeout_seconds, object_id_t setPacketSource, + uint16_t commandTimeoutSeconds, object_id_t setPacketSource, object_id_t setPacketDestination, size_t queueDepth = 20); virtual ~CommandingServiceBase(); @@ -113,8 +111,9 @@ protected: virtual ReturnValue_t isValidSubservice(uint8_t subservice) = 0; /** - * Once a TC Request is valid, the existence of the destination and its target interface is checked and retrieved. - * The target message queue ID can then be acquired by using the target interface. + * Once a TC Request is valid, the existence of the destination and its + * target interface is checked and retrieved. The target message queue ID + * can then be acquired by using the target interface. * @param subservice * @param tcData Application Data of TC Packet * @param tcDataLen @@ -129,15 +128,16 @@ protected: object_id_t *objectId) = 0; /** - * After the Message Queue and Object ID are determined, - * the command is prepared by using an implementation specific CommandMessage type - * which is sent to the target object. - * It contains all necessary information for the device to execute telecommands. - * @param message - * @param subservice - * @param tcData - * @param tcDataLen - * @param state + * After the Message Queue and Object ID are determined, the command is + * prepared by using an implementation specific CommandMessage type + * which is sent to the target object. It contains all necessary information + * for the device to execute telecommands. + * @param message [out] message which can be set and is sent to the object + * @param subservice Subservice of the current communication + * @param tcData Application data of command + * @param tcDataLen Application data length + * @param state [out/in] Setable state of the communication. + * communication * @param objectId Target object ID * @return */ @@ -146,25 +146,40 @@ protected: uint32_t *state, object_id_t objectId) = 0; /** - * This function is responsible for the communication between the Command Service Base - * and the respective PUS Commanding Service once the execution has started. - * The PUS Commanding Service receives replies from the target device and forwards them by calling this function. - * There are different translations of these replies to specify how the Command Service proceeds. - * @param reply[out] Command Message which contains information about the command - * @param previousCommand [out] - * @param state - * @param optionalNextCommand + * This function is implemented by child services to specify how replies + * to a command from another software component are handled + * @param reply + * This is the reply in form of a command message. + * @param previousCommand + * Command_t of related command + * @param state [out/in] + * Additional parameter which can be used to pass state information. + * State of the communication + * @param optionalNextCommand [out] + * An optional next command which can be set in this function * @param objectId Source object ID * @param isStep Flag value to mark steps of command execution - * @return - @c RETURN_OK, @c EXECUTION_COMPLETE or @c NO_STEP_MESSAGE to generate TC verification success - * - @c INVALID_REPLY can handle unrequested replies - * - Anything else triggers a TC verification failure + * @return + * - @c RETURN_OK, @c EXECUTION_COMPLETE or @c NO_STEP_MESSAGE to + * generate TC verification success + * - @c INVALID_REPLY calls handleUnrequestedReply + * - Anything else triggers a TC verification failure */ virtual ReturnValue_t handleReply(const CommandMessage *reply, Command_t previousCommand, uint32_t *state, CommandMessage *optionalNextCommand, object_id_t objectId, bool *isStep) = 0; + /** + * This function can be overidden to handle unrequested reply, + * when the reply sender ID is unknown or is not found is the command map. + * @param reply + */ + virtual void handleUnrequestedReply(CommandMessage *reply); + + virtual void doPeriodicOperation(); + + struct CommandInfo { struct tcInfo { uint8_t ackFlags; @@ -180,37 +195,42 @@ protected: FIFO fifo; }; + using CommandMapIter = FixedMap::Iterator; + const uint16_t apid; const uint8_t service; - const uint16_t timeout_seconds; + const uint16_t timeoutSeconds; - uint8_t tmPacketCounter; + uint8_t tmPacketCounter = 0; - StorageManagerIF *IPCStore; + StorageManagerIF *IPCStore = nullptr; - StorageManagerIF *TCStore; + StorageManagerIF *TCStore = nullptr; - MessageQueueIF* commandQueue; + MessageQueueIF* commandQueue = nullptr; - MessageQueueIF* requestQueue; + MessageQueueIF* requestQueue = nullptr; VerificationReporter verificationReporter; FixedMap commandMap; - uint32_t failureParameter1; //!< May be set be children to return a more precise failure condition. - uint32_t failureParameter2; //!< May be set be children to return a more precise failure condition. + /* May be set be children to return a more precise failure condition. */ + uint32_t failureParameter1 = 0; + uint32_t failureParameter2 = 0; object_id_t packetSource; object_id_t packetDestination; /** - * Pointer to the task which executes this component, is invalid before setTaskIF was called. + * Pointer to the task which executes this component, + * is invalid before setTaskIF was called. */ - PeriodicTaskIF* executingTask; + PeriodicTaskIF* executingTask = nullptr; /** * @brief Send TM data from pointer to data. @@ -246,22 +266,21 @@ protected: ReturnValue_t sendTmPacket(uint8_t subservice, SerializeIF* content, SerializeIF* header = nullptr); - virtual void handleUnrequestedReply(CommandMessage *reply); - - virtual void doPeriodicOperation(); - - void checkAndExecuteFifo( - typename FixedMap::Iterator *iter); + void checkAndExecuteFifo(CommandMapIter iter); private: + /** * This method handles internal execution of a command, - * once it has been started by @sa{startExecution()} in the Request Queue handler. - * It handles replies generated by the devices and relayed by the specific service implementation. - * This means that it determines further course of action depending on the return values specified - * in the service implementation. + * once it has been started by @sa{startExecution()} in the request + * queue handler. + * It handles replies generated by the devices and relayed by the specific + * service implementation. This means that it determines further course of + * action depending on the return values specified in the service + * implementation. * This includes the generation of TC verification messages. Note that - * the static framework object ID @c VerificationReporter::messageReceiver needs to be set. + * the static framework object ID @c VerificationReporter::messageReceiver + * needs to be set. * - TM[1,5] Step Successs * - TM[1,6] Step Failure * - TM[1,7] Completion Success @@ -282,8 +301,11 @@ private: void acceptPacket(uint8_t reportId, TcPacketStored* packet); - void startExecution(TcPacketStored *storedPacket, - typename FixedMap::Iterator *iter); + void startExecution(TcPacketStored *storedPacket, CommandMapIter iter); + + void handleCommandMessage(CommandMessage& reply); + void handleReplyHandlerResult(ReturnValue_t result, CommandMapIter iter, + CommandMessage& nextCommand,CommandMessage& reply, bool& isStep); void checkTimeout(); }; diff --git a/tmtcservices/PusServiceBase.cpp b/tmtcservices/PusServiceBase.cpp index c27defe6..f5d1e30b 100644 --- a/tmtcservices/PusServiceBase.cpp +++ b/tmtcservices/PusServiceBase.cpp @@ -9,10 +9,11 @@ object_id_t PusServiceBase::packetSource = 0; object_id_t PusServiceBase::packetDestination = 0; -PusServiceBase::PusServiceBase(object_id_t setObjectId, uint16_t setApid, uint8_t setServiceId) : - SystemObject(setObjectId), apid(setApid), serviceId(setServiceId), errorParameter1( - 0), errorParameter2(0), requestQueue(NULL) { - requestQueue = QueueFactory::instance()->createMessageQueue(PUS_SERVICE_MAX_RECEPTION); +PusServiceBase::PusServiceBase(object_id_t setObjectId, uint16_t setApid, + uint8_t setServiceId) : + SystemObject(setObjectId), apid(setApid), serviceId(setServiceId) { + requestQueue = QueueFactory::instance()-> + createMessageQueue(PUS_SERVICE_MAX_RECEPTION); } PusServiceBase::~PusServiceBase() { @@ -20,51 +21,60 @@ PusServiceBase::~PusServiceBase() { } ReturnValue_t PusServiceBase::performOperation(uint8_t opCode) { + handleRequestQueue(); + ReturnValue_t result = this->performService(); + if (result != RETURN_OK) { + sif::error << "PusService " << (uint16_t) this->serviceId + << ": performService returned with " << (int16_t) result + << std::endl; + return RETURN_FAILED; + } + return RETURN_OK; +} + +void PusServiceBase::handleRequestQueue() { TmTcMessage message; + 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; + // debug << "PusServiceBase::performOperation: Receiving from MQ ID: " + // << std::hex << this->requestQueue.getId() + // << std::dec << " returned: " << status << std::endl; if (status == RETURN_OK) { this->currentPacket.setStoreAddress(message.getStorageId()); - // info << "Service " << (uint16_t) this->serviceId << ": new packet!" << std::endl; + //info << "Service " << (uint16_t) this->serviceId << + // ": new packet!" << std::endl; - ReturnValue_t return_code = this->handleRequest(currentPacket.getSubService()); + result = this->handleRequest(currentPacket.getSubService()); - // debug << "Service " << (uint16_t)this->serviceId << ": handleRequest returned: " << (int)return_code << std::endl; - if (return_code == RETURN_OK) { + // debug << "Service " << (uint16_t)this->serviceId << + // ": handleRequest returned: " << (int)return_code << std::endl; + if (result == RETURN_OK) { this->verifyReporter.sendSuccessReport( TC_VERIFY::COMPLETION_SUCCESS, &this->currentPacket); - } else { + } + else { this->verifyReporter.sendFailureReport( TC_VERIFY::COMPLETION_FAILURE, &this->currentPacket, - return_code, 0, errorParameter1, errorParameter2); + result, 0, errorParameter1, errorParameter2); } this->currentPacket.deletePacket(); errorParameter1 = 0; errorParameter2 = 0; - } else if (status == MessageQueueIF::EMPTY) { + } + else if (status == MessageQueueIF::EMPTY) { status = RETURN_OK; - // debug << "PusService " << (uint16_t)this->serviceId << ": no new packet." << std::endl; + // debug << "PusService " << (uint16_t)this->serviceId << + // ": no new packet." << std::endl; break; - } else { - + } + else { sif::error << "PusServiceBase::performOperation: Service " << (uint16_t) this->serviceId << ": Error receiving packet. Code: " << std::hex << status << std::dec << std::endl; } } - ReturnValue_t return_code = this->performService(); - if (return_code == RETURN_OK) { - return RETURN_OK; - } else { - - sif::error << "PusService " << (uint16_t) this->serviceId - << ": performService returned with " << (int16_t) return_code - << std::endl; - return RETURN_FAILED; - } } uint16_t PusServiceBase::getIdentifier() { @@ -80,19 +90,21 @@ ReturnValue_t PusServiceBase::initialize() { if (result != RETURN_OK) { return result; } - AcceptsTelemetryIF* dest_service = objectManager->get( + AcceptsTelemetryIF* destService = objectManager->get( packetDestination); PUSDistributorIF* distributor = objectManager->get( packetSource); - if ((dest_service != NULL) && (distributor != NULL)) { + if ((destService != nullptr) && (distributor != nullptr)) { this->requestQueue->setDefaultDestination( - dest_service->getReportReceptionQueue()); + destService->getReportReceptionQueue()); distributor->registerService(this); return RETURN_OK; - } else { + } + else { sif::error << "PusServiceBase::PusServiceBase: Service " << (uint32_t) this->serviceId << ": Configuration error." - << " Make sure packetSource and packetDestination are defined correctly" << std::endl; + << " Make sure packetSource and packetDestination are defined " + "correctly" << std::endl; return RETURN_FAILED; } } diff --git a/tmtcservices/PusServiceBase.h b/tmtcservices/PusServiceBase.h index dbb1754c..39600c41 100644 --- a/tmtcservices/PusServiceBase.h +++ b/tmtcservices/PusServiceBase.h @@ -1,5 +1,5 @@ -#ifndef PUSSERVICEBASE_H_ -#define PUSSERVICEBASE_H_ +#ifndef FRAMEWORK_TMTCSERVICES_PUSSERVICEBASE_H_ +#define FRAMEWORK_TMTCSERVICES_PUSSERVICEBASE_H_ #include #include @@ -9,7 +9,6 @@ #include #include #include -#include #include namespace Factory{ @@ -17,18 +16,22 @@ void setStaticFrameworkObjectIds(); } /** - * \defgroup pus_services PUS Service Framework + * @defgroup pus_services PUS Service Framework * These group contains all implementations of PUS Services in the OBSW. * Most of the Services are directly taken from the ECSS PUS Standard. */ /** - * \brief This class is the basis for all PUS Services, which can immediately process Telecommand Packets. - * It manages Telecommand reception and the generation of Verification Reports. Every class that inherits - * from this abstract class has to implement handleRequest and performService. Services that are created with this + * @brief This class is the basis for all PUS Services, + * which can immediately process Telecommand Packets. + * @details + * It manages Telecommand reception and the generation of Verification Reports. + * Every class that inherits from this abstract class has to implement + * handleRequest and performService. Services that are created with this * Base class have to handle any kind of request immediately on reception. - * All PUS Services are System Objects, so an Object ID needs to be specified on construction. - * \ingroup pus_services + * All PUS Services are System Objects, so an Object ID needs to be specified + * on construction. + * @ingroup pus_services */ class PusServiceBase : public ExecutableObjectIF, public AcceptsTelecommandsIF, @@ -37,49 +40,61 @@ class PusServiceBase : public ExecutableObjectIF, friend void (Factory::setStaticFrameworkObjectIds)(); public: /** - * The constructor for the class. - * The passed values are set, but inter-object initialization is done in the initialize method. - * @param setObjectId The system object identifier of this Service instance. - * @param set_apid The APID the Service is instantiated for. - * @param set_service_id The Service Identifier as specified in ECSS PUS. + * @brief The passed values are set, but inter-object initialization is + * done in the initialize method. + * @param setObjectId + * The system object identifier of this Service instance. + * @param setApid + * The APID the Service is instantiated for. + * @param setServiceId + * The Service Identifier as specified in ECSS PUS. */ - PusServiceBase( object_id_t setObjectId, uint16_t setApid, uint8_t setServiceId); + PusServiceBase( object_id_t setObjectId, uint16_t setApid, + uint8_t setServiceId); /** * The destructor is empty. */ virtual ~PusServiceBase(); /** - * @brief The handleRequest method shall handle any kind of Telecommand Request immediately. + * @brief The handleRequest method shall handle any kind of Telecommand + * Request immediately. * @details - * Implemetations can take the Telecommand in currentPacket and perform any kind of operation. - * They may send additional "Start Success (1,3)" messages with the verifyReporter, but Completion - * Success or Failure Reports are generated automatically after execution of this method. + * Implemetations can take the Telecommand in currentPacket and perform + * any kind of operation. + * They may send additional "Start Success (1,3)" messages with the + * verifyReporter, but Completion Success or Failure Reports are generated + * automatically after execution of this method. * * If a Telecommand can not be executed within one call cycle, * this Base class is not the right parent. * - * The child class may add additional error information by setting #errorParameters which are - * attached to the generated verification message. + * The child class may add additional error information by setting + * #errorParameters which aren attached to the generated verification + * message. * * Subservice checking should be implemented in this method. * - * @return The returned status_code is directly taken as main error code in the Verification Report. + * @return The returned status_code is directly taken as main error code + * in the Verification Report. * On success, RETURN_OK shall be returned. */ virtual ReturnValue_t handleRequest(uint8_t subservice) = 0; /** - * In performService, implementations can handle periodic, non-TC-triggered activities. + * In performService, implementations can handle periodic, + * non-TC-triggered activities. * The performService method is always called. - * @return A success or failure code that does not trigger any kind of verification message. + * @return Currently, everything other that RETURN_OK only triggers + * diagnostic output. */ virtual ReturnValue_t performService() = 0; /** * This method implements the typical activity of a simple PUS Service. - * It checks for new requests, and, if found, calls handleRequest, sends completion verification messages and deletes + * It checks for new requests, and, if found, calls handleRequest, sends + * completion verification messages and deletes * the TC requests afterwards. * performService is always executed afterwards. - * @return \c RETURN_OK if the periodic performService was successful. - * \c RETURN_FAILED else. + * @return @c RETURN_OK if the periodic performService was successful. + * @c RETURN_FAILED else. */ ReturnValue_t performOperation(uint8_t opCode); virtual uint16_t getIdentifier(); @@ -97,19 +112,19 @@ protected: /** * One of two error parameters for additional error information. */ - uint32_t errorParameter1; + uint32_t errorParameter1 = 0; /** * One of two error parameters for additional error information. */ - uint32_t errorParameter2; + uint32_t errorParameter2 = 0; /** - * This is a complete instance of the Telecommand reception queue of the class. - * It is initialized on construction of the class. + * This is a complete instance of the telecommand reception queue + * of the class. It is initialized on construction of the class. */ - MessageQueueIF* requestQueue; + MessageQueueIF* requestQueue = nullptr; /** - * An instance of the VerificationReporter class, that simplifies sending any kind of - * Verification Message to the TC Verification Service. + * An instance of the VerificationReporter class, that simplifies + * sending any kind of verification message to the TC Verification Service. */ VerificationReporter verifyReporter; /** @@ -124,9 +139,12 @@ protected: private: /** * This constant sets the maximum number of packets accepted per call. - * Remember that one packet must be completely handled in one #handleRequest call. + * Remember that one packet must be completely handled in one + * #handleRequest call. */ static const uint8_t PUS_SERVICE_MAX_RECEPTION = 10; + + void handleRequestQueue(); }; #endif /* PUSSERVICEBASE_H_ */