#ifndef FSFW_TMTCSERVICES_COMMANDINGSERVICEBASE_H_ #define FSFW_TMTCSERVICES_COMMANDINGSERVICEBASE_H_ #include "AcceptsTelecommandsIF.h" #include "VerificationReporter.h" #include "fsfw/FSFW.h" #include "fsfw/container/FIFO.h" #include "fsfw/container/FixedMap.h" #include "fsfw/ipc/CommandMessage.h" #include "fsfw/ipc/MessageQueueIF.h" #include "fsfw/objectmanager/SystemObject.h" #include "fsfw/serialize/SerializeIF.h" #include "fsfw/storagemanager/StorageManagerIF.h" #include "fsfw/tasks/ExecutableObjectIF.h" class TcPacketStoredBase; class TcPacketStoredPus; namespace Factory { void setStaticFrameworkObjectIds(); } /** * @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 * 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 * @author gaisser * @ingroup pus_services */ class CommandingServiceBase : public SystemObject, public AcceptsTelecommandsIF, public ExecutableObjectIF { friend void(Factory::setStaticFrameworkObjectIds)(); public: // We could make this configurable via preprocessor and the FSFWConfig file. static constexpr uint8_t COMMAND_INFO_FIFO_DEPTH = fsfwconfig::FSFW_CSB_FIFO_DEPTH; static const uint8_t INTERFACE_ID = CLASS_ID::COMMAND_SERVICE_BASE; static const ReturnValue_t EXECUTION_COMPLETE = MAKE_RETURN_CODE(1); static const ReturnValue_t NO_STEP_MESSAGE = MAKE_RETURN_CODE(2); static const ReturnValue_t OBJECT_BUSY = MAKE_RETURN_CODE(3); static const ReturnValue_t BUSY = MAKE_RETURN_CODE(4); static const ReturnValue_t INVALID_TC = MAKE_RETURN_CODE(5); static const ReturnValue_t INVALID_OBJECT = MAKE_RETURN_CODE(6); static const ReturnValue_t INVALID_REPLY = MAKE_RETURN_CODE(7); /** * Class constructor. Initializes two important MessageQueues: * commandQueue for command reception and requestQueue for device reception * @param setObjectId * @param apid * @param service * @param numberOfParallelCommands * @param commandTimeout_seconds * @param setPacketSource * @param setPacketDestination * @param queueDepth */ CommandingServiceBase(object_id_t setObjectId, uint16_t apid, uint8_t service, uint8_t numberOfParallelCommands, 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. * Handle command Queue for internal commands. * @param opCode is unused here at the moment * @return returnvalue::OK */ virtual ReturnValue_t performOperation(uint8_t opCode) override; virtual uint16_t getIdentifier() override; /** * Returns the requestQueue MessageQueueId_t * * The requestQueue is the queue for external commands (TC) * * @return requestQueue messageQueueId_t */ virtual MessageQueueId_t getRequestQueue() override; /** * Returns the commandQueue MessageQueueId_t * * Remember the CommandQueue is the queue for internal communication * @return commandQueue messageQueueId_t */ virtual MessageQueueId_t getCommandQueue(); virtual ReturnValue_t initialize() override; /** * Implementation of ExecutableObjectIF function * * Used to setup the reference of the task, that executes this component * @param task Pointer to the taskIF of this task */ virtual void setTaskIF(PeriodicTaskIF* task) override; protected: /** * Check the target subservice * @param subservice[in] * @return * -@c returnvalue::OK Subservice valid, continue message handling * -@c INVALID_SUBSERVICE if service is not known, rejects packet. */ 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. * @param subservice * @param tcData Application Data of TC Packet * @param tcDataLen * @param id MessageQueue ID is stored here * @param objectId Object ID is extracted and stored here * @return * - @c returnvalue::OK Cotinue message handling * - @c returnvalue::FAILED Reject the packet and generates a start failure * verification */ virtual ReturnValue_t getMessageQueueAndObject(uint8_t subservice, const uint8_t* tcData, size_t tcDataLen, MessageQueueId_t* id, 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 [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 * - @c returnvalue::OK to generate a verification start message * - @c EXECUTION_COMPLETE Fire-and-forget command. Generate a completion * verification message. * - @c Anything else rejects the packets and generates a start failure * verification. */ virtual ReturnValue_t prepareCommand(CommandMessage* message, uint8_t subservice, const uint8_t* tcData, size_t tcDataLen, uint32_t* state, object_id_t objectId) = 0; /** * 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 generic read-only 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 returnvalue::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. If returnvalue::FAILED or * INVALID_REPLY is returned and the command ID is * CommandMessage::REPLY_REJECTED, a failure verification message with * the reason as the error parameter and the initial command as * failure parameter 1 is generated. */ 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. * The default implementation will clear the command message and all * its contents. * @param reply * Reply which is non-const so the default implementation can clear the * message. */ virtual void handleUnrequestedReply(CommandMessage* reply); virtual void doPeriodicOperation(); struct CommandInfo : public SerializeIF { struct tcInfo { uint8_t ackFlags; uint16_t tcPacketId; uint16_t tcSequenceControl; } tcInfo; uint32_t uptimeOfStart; uint8_t step; uint8_t subservice; uint32_t state; Command_t command; object_id_t objectId; FIFO fifo; virtual ReturnValue_t serialize(uint8_t** buffer, size_t* size, size_t maxSize, Endianness streamEndianness) const override { return returnvalue::FAILED; }; virtual size_t getSerializedSize() const override { return 0; }; virtual ReturnValue_t deSerialize(const uint8_t** buffer, size_t* size, Endianness streamEndianness) override { return returnvalue::FAILED; }; }; using CommandMapIter = FixedMap::Iterator; const uint16_t apid; const uint8_t service; const uint16_t timeoutSeconds; uint8_t tmPacketCounter = 0; StorageManagerIF* IPCStore = nullptr; StorageManagerIF* TCStore = nullptr; MessageQueueIF* commandQueue = nullptr; MessageQueueIF* requestQueue = nullptr; VerificationReporter verificationReporter; FixedMap commandMap; /* May be set be children to return a more precise failure condition. */ uint32_t failureParameter1 = 0; uint32_t failureParameter2 = 0; static object_id_t defaultPacketSource; object_id_t packetSource = objects::NO_OBJECT; static object_id_t defaultPacketDestination; object_id_t packetDestination = objects::NO_OBJECT; /** * Pointer to the task which executes this component, * is invalid before setTaskIF was called. */ PeriodicTaskIF* executingTask = nullptr; /** * @brief Send TM data from pointer to data. * If a header is supplied it is added before data * @param subservice Number of subservice * @param data Pointer to the data in the Packet * @param dataLen Lenght of data in the Packet * @param headerData HeaderData will be placed before data * @param headerSize Size of HeaderData */ ReturnValue_t sendTmPacket(uint8_t subservice, const uint8_t* data, size_t dataLen, const uint8_t* headerData = nullptr, size_t headerSize = 0); /** * @brief To send TM packets of objects that still need to be serialized * and consist of an object ID with appended data. * @param subservice Number of subservice * @param objectId ObjectId is placed before data * @param data Data to append to the packet * @param dataLen Length of Data */ ReturnValue_t sendTmPacket(uint8_t subservice, object_id_t objectId, const uint8_t* data, size_t dataLen); /** * @brief To send packets which are contained inside a class implementing * SerializeIF. * @param subservice Number of subservice * @param content This is a pointer to the serialized packet * @param header Serialize IF header which will be placed before content */ ReturnValue_t sendTmPacket(uint8_t subservice, SerializeIF* content, SerializeIF* header = nullptr); 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. * This includes the generation of TC verification messages. Note that * 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 * - TM[1,8] Completion Failure */ void handleCommandQueue(); /** * @brief Handler function for request queue * @details * Sequence of request queue handling: * isValidSubservice -> getMessageQueueAndObject -> startExecution * Generates a Start Success Reports TM[1,3] in subfunction * @sa{startExecution()} or a Start Failure Report TM[1,4] by using the * TC Verification Service. */ void handleRequestQueue(); void rejectPacket(uint8_t reportId, TcPacketStoredPus* packet, ReturnValue_t errorCode); void acceptPacket(uint8_t reportId, TcPacketStoredPus* packet); void startExecution(TcPacketStoredPus* storedPacket, CommandMapIter iter); void handleCommandMessage(CommandMessage* reply); void handleReplyHandlerResult(ReturnValue_t result, CommandMapIter iter, CommandMessage* nextCommand, CommandMessage* reply, bool& isStep); void checkTimeout(); }; #endif /* FSFW_TMTCSERVICES_COMMANDINGSERVICEBASE_H_ */