#include "PusTmFunnel.h" #include "eive/definitions.h" #include "eive/objects.h" #include "fsfw/ipc/CommandMessage.h" #include "fsfw/ipc/QueueFactory.h" #include "fsfw/objectmanager.h" #include "fsfw/tmstorage/TmStoreMessage.h" #include "fsfw/tmtcpacket/pus/tm/PusTmZcWriter.h" PusTmFunnel::PusTmFunnel(TmFunnelBase::FunnelCfg cfg, TimeReaderIF &timeReader, SdCardMountedIF &sdcMan) : TmFunnelBase(cfg), timeReader(timeReader), miscStore(objects::MISC_TM_STORE, "tm", "misc", RolloverInterval::HOURLY, 2, currentTv, tmStore, sdcMan), okStore(objects::OK_TM_STORE, "tm", "ok", RolloverInterval::MINUTELY, 30, currentTv, tmStore, sdcMan), notOkStore(objects::NOT_OK_TM_STORE, "tm", "nok", RolloverInterval::MINUTELY, 30, currentTv, tmStore, sdcMan), hkStore(objects::HK_TM_STORE, "tm", "hk", RolloverInterval::MINUTELY, 15, currentTv, tmStore, sdcMan), sdcMan(sdcMan) { Clock::getClock_timeval(¤tTv); Clock::getUptime(&lastTvUpdate); hkStore.addApid(config::EIVE_PUS_APID); hkStore.addService(3); miscStore.addApid(config::EIVE_PUS_APID); miscStore.addService(17); miscStore.addService(2); miscStore.addService(200); okStore.addApid(config::EIVE_PUS_APID); okStore.addServiceSubservice(5, 1); okStore.addApid(config::EIVE_PUS_APID); okStore.addService(8); okStore.addServiceSubservice(1, 1); okStore.addServiceSubservice(1, 3); okStore.addServiceSubservice(1, 5); okStore.addServiceSubservice(1, 7); notOkStore.addApid(config::EIVE_PUS_APID); notOkStore.addServiceSubservice(5, 2); notOkStore.addServiceSubservice(5, 3); notOkStore.addServiceSubservice(5, 4); notOkStore.addServiceSubservice(1, 2); notOkStore.addServiceSubservice(1, 4); notOkStore.addServiceSubservice(1, 6); notOkStore.addServiceSubservice(1, 8); } PusTmFunnel::~PusTmFunnel() = default; ReturnValue_t PusTmFunnel::performOperation(uint8_t) { CommandMessage cmdMessage; ReturnValue_t status = tcQueue->receiveMessage(&cmdMessage); if (status == returnvalue::OK) { ReturnValue_t result = handleTcRequest(cmdMessage); if (result != returnvalue::OK) { sif::error << "PusTmFunnel::performOperation: Error handling TC request" << std::endl; } } TmTcMessage currentMessage; unsigned int count = 0; ReturnValue_t status = tmQueue->receiveMessage(¤tMessage); while (status == returnvalue::OK) { status = handleTmPacket(tmMessage); if (status != returnvalue::OK) { sif::warning << "TmFunnel packet handling failed" << std::endl; break; } count++; if(count == 500) { sif::error << "PusTmFunnel: Possible message storm detected" << std::endl; break; } status = tmQueue->receiveMessage(¤tMessage); } if (status == MessageQueueIF::EMPTY) { return returnvalue::OK; } return status; } ReturnValue_t PusTmFunnel::handleTmPacket(TmTcMessage &message) { uint8_t *packetData = nullptr; size_t size = 0; store_address_t origStoreId = message.getStorageId(); ReturnValue_t result = tmStore.modifyData(origStoreId, &packetData, &size); if (result != returnvalue::OK) { return result; } PusTmZeroCopyWriter packet(timeReader, packetData, size); result = packet.parseDataWithoutCrcCheck(); if (result != returnvalue::OK) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::warning << "PusTmFunnel::handlePacket: Error parsing received PUS packet" << std::endl; #endif return result; } packet.setSequenceCount(sourceSequenceCount++); sourceSequenceCount = sourceSequenceCount % ccsds::LIMIT_SEQUENCE_COUNT; packet.updateErrorControl(); timeval currentUptime{}; Clock::getUptime(¤tUptime); if (currentUptime.tv_sec - lastTvUpdate.tv_sec > static_cast(TV_UPDATE_INTERVAL_SECS)) { Clock::getClock_timeval(¤tTv); lastTvUpdate = currentUptime; } bool sdcUsable = sdcMan.isSdCardUsable(std::nullopt); initStoresIfPossible(sdcUsable); if (sdcUsable) { miscStore.passPacket(packet); okStore.passPacket(packet); notOkStore.passPacket(packet); hkStore.passPacket(packet); } return sendPacketToDestinations(origStoreId, message, packetData, size); } const char *PusTmFunnel::getName() const { return "PUS TM Funnel"; } void PusTmFunnel::initStoresIfPossible(bool sdCardUsable) { if (not storesInitialized and sdCardUsable) { miscStore.updateBaseDir(); okStore.updateBaseDir(); hkStore.updateBaseDir(); notOkStore.updateBaseDir(); storesInitialized = true; } } ReturnValue_t PusTmFunnel::initialize() { initStoresIfPossible(sdcMan.isSdCardUsable(std::nullopt)); return returnvalue::OK; } ReturnValue_t PusTmFunnel::handleTcRequest(CommandMessage &cmdMessage) { if (cmdMessage.getMessageType() == messagetypes::TM_STORE) { Command_t cmd = cmdMessage.getCommand(); object_id_t objectId = TmStoreMessage::getObjectId(&cmdMessage); TmStore *tmStore = nullptr; switch (objectId) { case (objects::HK_TM_STORE): { tmStore = &hkStore; break; } case (objects::OK_TM_STORE): { tmStore = &okStore; break; } case (objects::NOT_OK_TM_STORE): { tmStore = ¬OkStore; break; } case (objects::MISC_TM_STORE): { tmStore = &miscStore; break; } default: { } } if (tmStore == nullptr) { return returnvalue::FAILED; } if (cmd == TmStoreMessage::DELETE_STORE_CONTENT_TIME) { store_address_t storeId = TmStoreMessage::getStoreId(&cmdMessage); auto accessor = ipcStore.getData(storeId); uint32_t deleteUpToUnixSeconds = 0; size_t size = accessor.second.size(); SerializeAdapter::deSerialize(&deleteUpToUnixSeconds, accessor.second.data(), &size, SerializeIF::Endianness::NETWORK); tmStore->deleteUpTo(deleteUpToUnixSeconds); } else if (cmd == TmStoreMessage::DOWNLINK_STORE_CONTENT_TIME) { store_address_t storeId = TmStoreMessage::getStoreId(&cmdMessage); auto accessor = ipcStore.getData(storeId); uint32_t dumpFromUnixSeconds; uint32_t dumpUntilUnixSeconds; size_t size = accessor.second.size(); SerializeAdapter::deSerialize(&dumpFromUnixSeconds, accessor.second.data(), &size, SerializeIF::Endianness::NETWORK); SerializeAdapter::deSerialize(&dumpUntilUnixSeconds, accessor.second.data(), &size, SerializeIF::Endianness::NETWORK); // TODO: TM store missing, and maybe there is a better way to do this? tmStore->dumpFromUpTo(dumpFromUnixSeconds, dumpUntilUnixSeconds, *this); } } return returnvalue::OK; }