#include "LiveTmTask.h" #include #include #include #include #include "mission/sysDefs.h" std::atomic_bool signals::CFDP_CHANNEL_THROTTLE_SIGNAL = false; LiveTmTask::LiveTmTask(object_id_t objectId, PusTmFunnel& pusFunnel, CfdpTmFunnel& cfdpFunnel, VirtualChannel& channel, const std::atomic_bool& ptmeLocked, uint32_t regularTmQueueDepth, uint32_t cfdpQueueDepth) : SystemObject(objectId), modeHelper(this), pusFunnel(pusFunnel), cfdpFunnel(cfdpFunnel), channel(channel), ptmeLocked(ptmeLocked) { requestQueue = QueueFactory::instance()->createMessageQueue(); cfdpTmQueue = QueueFactory::instance()->createMessageQueue(cfdpQueueDepth); regularTmQueue = QueueFactory::instance()->createMessageQueue(regularTmQueueDepth); } ReturnValue_t LiveTmTask::performOperation(uint8_t opCode) { readCommandQueue(); bool handledTm; ReturnValue_t result; while (true) { // TODO: Must read CFDP TM queue and regular TM queue and forward them. Handle regular queue // first. handledTm = false; if (!channel.isBusy()) { result = handleRegularTmQueue(); if (result == MessageQueueIF::EMPTY) { result = handleCfdpTmQueue(); } if (result == returnvalue::OK) { handledTm = true; } } if (channel.isBusy()) { // Throttle CFDP packet creator. It is by far the most relevant data creator, so throttling // it is the easiest way to handle back pressure for now in a sensible way. It is cleared // by the data creator. signals::CFDP_CHANNEL_THROTTLE_SIGNAL = true; } if (!handledTm) { if (tmFunnelCd.hasTimedOut()) { pusFunnel.performOperation(0); cfdpFunnel.performOperation(0); tmFunnelCd.resetTimer(); } // Read command queue during idle times. readCommandQueue(); // 40 ms IDLE delay. Might tweak this in the future. TaskFactory::delayTask(40); } else { packetCounter++; } } } MessageQueueId_t LiveTmTask::getCommandQueue() const { return requestQueue->getId(); } void LiveTmTask::getMode(Mode_t* mode, Submode_t* submode) { if (mode != nullptr) { *mode = this->mode; } if (submode != nullptr) { *submode = SUBMODE_NONE; } } ReturnValue_t LiveTmTask::checkModeCommand(Mode_t mode, Submode_t submode, uint32_t* msToReachTheMode) { if (mode == MODE_ON or mode == MODE_OFF) { return returnvalue::OK; } return returnvalue::FAILED; } void LiveTmTask::startTransition(Mode_t mode, Submode_t submode) { this->mode = mode; modeHelper.modeChanged(mode, submode); announceMode(false); } void LiveTmTask::announceMode(bool recursive) { triggerEvent(MODE_INFO, mode, SUBMODE_NONE); } object_id_t LiveTmTask::getObjectId() const { return SystemObject::getObjectId(); } const HasHealthIF* LiveTmTask::getOptHealthIF() const { return nullptr; } const HasModesIF& LiveTmTask::getModeIF() const { return *this; } ReturnValue_t LiveTmTask::connectModeTreeParent(HasModeTreeChildrenIF& parent) { return modetree::connectModeTreeParent(parent, *this, nullptr, modeHelper); } void LiveTmTask::readCommandQueue(void) { CommandMessage commandMessage; ReturnValue_t result = returnvalue::FAILED; result = requestQueue->receiveMessage(&commandMessage); if (result == returnvalue::OK) { result = modeHelper.handleModeCommand(&commandMessage); if (result == returnvalue::OK) { return; } CommandMessage reply; reply.setReplyRejected(CommandMessage::UNKNOWN_COMMAND, commandMessage.getCommand()); requestQueue->reply(&reply); return; } } ReturnValue_t LiveTmTask::handleRegularTmQueue() { return handleGenericTmQueue(*regularTmQueue); } ReturnValue_t LiveTmTask::handleCfdpTmQueue() { return handleGenericTmQueue(*cfdpTmQueue); } ReturnValue_t LiveTmTask::handleGenericTmQueue(MessageQueueIF& queue) { TmTcMessage message; ReturnValue_t result = queue.receiveMessage(&message); if (result == MessageQueueIF::EMPTY) { return result; } store_address_t storeId = message.getStorageId(); const uint8_t* data = nullptr; size_t size = 0; result = tmStore->getData(storeId, &data, &size); if (result != returnvalue::OK) { sif::warning << "VirtualChannel::performOperation: Failed to read data from TM store" << std::endl; tmStore->deleteData(storeId); return result; } if (!ptmeLocked) { result = channel.write(data, size); } // Try delete in any case, ignore failures (which should not happen), it is more important to // propagate write errors. tmStore->deleteData(storeId); return result; } ModeTreeChildIF& LiveTmTask::getModeTreeChildIF() { return *this; } ReturnValue_t LiveTmTask::initialize() { modeHelper.initialize(); tmStore = ObjectManager::instance()->get(objects::TM_STORE); if (tmStore == nullptr) { return ObjectManagerIF::CHILD_INIT_FAILED; } return returnvalue::OK; } MessageQueueId_t LiveTmTask::getNormalLiveQueueId() const { return regularTmQueue->getId(); } MessageQueueId_t LiveTmTask::getCfdpLiveQueueId() const { return cfdpTmQueue->getId(); }