#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(object_id_t objectId, TimeReaderIF &timeReader, StorageManagerIF &tmStore, SdCardMountedIF &sdcMan, uint32_t tmMsgDepth, uint32_t tcMsgDepth) : TmFunnelBase(objectId, tmStore, tmMsgDepth, tcMsgDepth), timeReader(timeReader), miscStore(objects::MISC_TM_STORE, "tm", "misc", RolloverInterval::HOURLY, 2, currentTv, sdcMan), okStore(objects::OK_TM_STORE, "tm", "ok", RolloverInterval::MINUTELY, 30, currentTv, sdcMan), notOkStore(objects::NOT_OK_TM_STORE, "tm", "nok", RolloverInterval::MINUTELY, 30, currentTv, sdcMan), hkStore(objects::HK_TM_STORE, "tm", "hk", RolloverInterval::MINUTELY, 15, currentTv, 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); while (status == returnvalue::OK) { if (cmdMessage.getCommand() == messagetypes::TM_STORE) { object_id_t objectId = TmStoreMessage::getObjectId(&cmdMessage); switch (objectId) { case (objects::HK_TM_STORE): { break; } case (objects::OK_TM_STORE): { break; } case (objects::NOT_OK_TM_STORE): { break; } case (objects::MISC_TM_STORE): { break; } default: { } } } } TmTcMessage currentMessage; status = tmQueue->receiveMessage(¤tMessage); while (status == returnvalue::OK) { status = handlePacket(currentMessage); if (status != returnvalue::OK) { sif::warning << "TmFunnel packet handling failed" << std::endl; break; } status = tmQueue->receiveMessage(¤tMessage); } return status; } ReturnValue_t PusTmFunnel::handlePacket(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); } for (unsigned int idx = 0; idx < destinations.size(); idx++) { const auto &destVcidPair = destinations[idx]; if (destinations.size() > 1) { if (idx < destinations.size() - 1) { // Create copy of data to ensure each TM recipient has its own copy. That way, we don't need // to bother with send order and where the data is deleted. store_address_t storeId; result = tmStore.addData(&storeId, packetData, size); if (result == returnvalue::OK) { message.setStorageId(storeId); } else { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PusTmFunnel::handlePacket: Store too full to create data copy" << std::endl; #endif } } else { message.setStorageId(origStoreId); } } result = tmQueue->sendMessage(destVcidPair.first, &message); if (result != returnvalue::OK) { #if FSFW_CPP_OSTREAM_ENABLED == 1 sif::error << "PusTmFunnel::handlePacket: Error sending TM to downlink handler" << std::endl; #endif tmStore.deleteData(message.getStorageId()); } } return result; } 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; }