eive-obsw/mission/com/TmStoreTaskBase.cpp

234 lines
8.1 KiB
C++
Raw Permalink Normal View History

2023-03-09 19:42:20 +01:00
#include "TmStoreTaskBase.h"
2023-03-10 20:32:11 +01:00
#include <fsfw/ipc/CommandMessageIF.h>
2023-03-31 01:14:59 +02:00
#include <fsfw/ipc/QueueFactory.h>
#include <fsfw/subsystem/helper.h>
#include <fsfw/tasks/TaskFactory.h>
2023-03-10 02:05:51 +01:00
#include <fsfw/timemanager/Stopwatch.h>
2023-03-10 20:32:11 +01:00
#include <fsfw/tmstorage/TmStoreMessage.h>
#include "mission/persistentTmStoreDefs.h"
2023-03-09 19:42:20 +01:00
TmStoreTaskBase::TmStoreTaskBase(object_id_t objectId, StorageManagerIF& ipcStore,
VirtualChannel& channel, SdCardMountedIF& sdcMan,
const std::atomic_bool& ptmeLocked)
2023-03-31 01:14:59 +02:00
: SystemObject(objectId),
modeHelper(this),
ipcStore(ipcStore),
2023-03-31 13:17:15 +02:00
tmReader(&timeReader),
2023-03-31 01:14:59 +02:00
channel(channel),
sdcMan(sdcMan),
ptmeLocked(ptmeLocked) {
2023-03-31 01:14:59 +02:00
requestQueue = QueueFactory::instance()->createMessageQueue(10);
}
2023-03-09 19:42:20 +01:00
2023-03-11 14:59:55 +01:00
bool TmStoreTaskBase::handleOneStore(PersistentTmStoreWithTmQueue& store,
DumpContext& dumpContext) {
2023-03-10 02:05:51 +01:00
ReturnValue_t result;
2023-03-10 20:13:36 +01:00
bool tmToStoreReceived = false;
bool tcRequestReceived = false;
2023-03-28 14:59:31 +02:00
bool dumpPerformed = false;
2023-03-27 21:23:09 +02:00
fileHasSwapped = false;
2023-03-27 21:39:37 +02:00
dumpContext.packetWasDumped = false;
dumpContext.vcBusyDuringDump = false;
2023-03-27 21:23:09 +02:00
2023-03-09 19:42:20 +01:00
// Store TM persistently
2023-03-10 02:05:51 +01:00
result = store.handleNextTm();
2023-03-10 20:13:36 +01:00
if (result == returnvalue::OK) {
tmToStoreReceived = true;
2023-03-09 19:42:20 +01:00
}
2023-03-31 13:17:15 +02:00
// Dump TMs
2023-03-31 12:11:31 +02:00
if (store.getState() == PersistentTmStore::State::DUMPING) {
2023-03-28 14:59:31 +02:00
if (handleOneDump(store, dumpContext, dumpPerformed) != returnvalue::OK) {
return result;
2023-03-10 20:32:11 +01:00
}
2023-03-10 02:05:51 +01:00
} else {
2023-03-10 20:32:11 +01:00
Command_t execCmd;
2023-03-10 02:05:51 +01:00
// Handle TC requests, for example deletion or retrieval requests.
2023-06-29 01:28:40 +02:00
// TODO: Not really clean here.. would be better if the executed command is returns as an
// enumeration.
2023-03-10 20:32:11 +01:00
result = store.handleCommandQueue(ipcStore, execCmd);
2023-06-29 01:28:40 +02:00
if (execCmd == TmStoreMessage::DOWNLINK_STORE_CONTENT_TIME) {
if (result == PersistentTmStore::DUMP_DONE) {
dumpDoneHandler(store, dumpContext);
} else if (result == returnvalue::OK) {
2023-03-10 20:32:11 +01:00
cancelDumpCd.resetTimer();
tmSinkBusyCd.resetTimer();
2023-03-11 14:59:55 +01:00
dumpContext.reset();
2023-03-10 20:32:11 +01:00
}
2023-06-29 01:28:40 +02:00
}
if (execCmd != CommandMessageIF::CMD_NONE) {
2023-03-10 20:13:36 +01:00
tcRequestReceived = true;
2023-03-10 02:05:51 +01:00
}
2023-03-09 19:42:20 +01:00
}
2023-03-28 14:59:31 +02:00
if (tcRequestReceived or tmToStoreReceived or dumpPerformed) {
2023-03-09 19:42:20 +01:00
return true;
}
return false;
}
bool TmStoreTaskBase::cyclicStoreCheck() {
if (not storesInitialized) {
2023-03-10 02:05:51 +01:00
storesInitialized = initStoresIfPossible();
if (not storesInitialized) {
TaskFactory::delayTask(400);
return false;
}
} else if (sdCardCheckCd.hasTimedOut()) {
if (not sdcMan.isSdCardUsable(std::nullopt)) {
// Might be due to imminent shutdown or SD card switch.
storesInitialized = false;
TaskFactory::delayTask(100);
return false;
}
sdCardCheckCd.resetTimer();
}
return true;
}
2023-03-27 21:39:37 +02:00
2023-03-28 10:13:39 +02:00
void TmStoreTaskBase::cancelDump(DumpContext& ctx, PersistentTmStore& store, bool isTxOn) {
ctx.reset();
2023-03-31 12:11:31 +02:00
if (store.getState() == PersistentTmStore::State::DUMPING) {
triggerEvent(ctx.eventIfCancelled, ctx.numberOfDumpedPackets, ctx.dumpedBytes);
}
2023-03-28 10:13:39 +02:00
store.cancelDump();
2023-03-28 14:59:31 +02:00
if (isTxOn) {
2023-03-28 10:13:39 +02:00
channel.cancelTransfer();
}
}
2023-03-28 14:59:31 +02:00
ReturnValue_t TmStoreTaskBase::handleOneDump(PersistentTmStoreWithTmQueue& store,
DumpContext& dumpContext, bool& dumpPerformed) {
ReturnValue_t result = returnvalue::OK;
// It is assumed that the PTME will only be locked for a short period (e.g. to change datarate).
if (not channel.isBusy() and not ptmeLocked) {
2023-03-31 13:17:15 +02:00
performDump(store, dumpContext, dumpPerformed);
2023-03-28 14:59:31 +02:00
} else {
// The PTME might be at full load, so it might sense to delay for a bit to let it do
// its work until some more bandwidth is available. Set a flag here so the upper layer can
// do ths.
dumpContext.vcBusyDuringDump = true;
dumpContext.ptmeBusyCounter++;
if (dumpContext.ptmeBusyCounter == 100) {
// If this happens, something is probably wrong.
2023-03-28 15:15:38 +02:00
sif::warning << "PTME busy for longer period. Cancelling dump" << std::endl;
2023-03-28 14:59:31 +02:00
cancelDump(dumpContext, store, channel.isTxOn());
}
}
if (cancelDumpCd.hasTimedOut() or tmSinkBusyCd.hasTimedOut()) {
cancelDump(dumpContext, store, channel.isTxOn());
}
return result;
}
2023-03-31 01:14:59 +02:00
2023-03-31 13:17:15 +02:00
ReturnValue_t TmStoreTaskBase::performDump(PersistentTmStoreWithTmQueue& store,
DumpContext& dumpContext, bool& dumpPerformed) {
size_t dumpedLen = 0;
// Dump the next packet into the PTME.
dumpContext.ptmeBusyCounter = 0;
tmSinkBusyCd.resetTimer();
ReturnValue_t result = store.getNextDumpPacket(tmReader, fileHasSwapped);
2023-06-20 20:52:01 +02:00
if (fileHasSwapped and result == PersistentTmStore::DUMP_DONE) {
2023-03-31 13:17:15 +02:00
// This can happen if a file is corrupted and the next file swap completes the dump.
2023-06-29 01:28:40 +02:00
dumpDoneHandler(store, dumpContext);
2023-03-31 13:17:15 +02:00
return returnvalue::OK;
2023-06-20 20:52:01 +02:00
} else if (result != returnvalue::OK) {
sif::error << "PersistentTmStore: Getting next dump packet failed" << std::endl;
return result;
2023-03-31 13:17:15 +02:00
}
2023-03-31 15:12:05 +02:00
dumpedLen = tmReader.getFullPacketLen();
2023-10-13 15:10:52 +02:00
size_t writtenSize = 0;
result = channel.write(tmReader.getFullData(), dumpedLen, writtenSize);
2023-10-13 09:20:51 +02:00
if (result == VirtualChannelIF::PARTIALLY_WRITTEN) {
result = channel.handleWriteCompletionSynchronously(writtenSize, 400);
2023-10-13 09:20:51 +02:00
if (result != returnvalue::OK) {
// TODO: Event? Might lead to dangerous spam though..
sif::warning << "LiveTmTask: Synchronous write of last segment failed with code 0x"
<< std::setfill('0') << std::setw(4) << std::hex << result << std::dec
<< std::endl;
2023-10-13 09:20:51 +02:00
}
} else if (result == DirectTmSinkIF::IS_BUSY) {
2023-06-20 20:52:01 +02:00
sif::warning << "PersistentTmStore: Unexpected VC channel busy" << std::endl;
} else if (result != returnvalue::OK) {
sif::warning << "PersistentTmStore: Unexpected VC channel write failure" << std::endl;
2023-03-31 13:17:15 +02:00
}
2023-06-20 20:52:01 +02:00
2023-03-31 13:17:15 +02:00
result = store.confirmDump(tmReader, fileHasSwapped);
if ((result == PersistentTmStore::DUMP_DONE or result == returnvalue::OK)) {
dumpPerformed = true;
if (dumpedLen > 0) {
dumpContext.dumpedBytes += dumpedLen;
dumpContext.numberOfDumpedPackets += 1;
dumpContext.packetWasDumped = true;
}
}
if (result == PersistentTmStore::DUMP_DONE) {
2023-06-29 01:28:40 +02:00
dumpDoneHandler(store, dumpContext);
2023-03-31 13:17:15 +02:00
}
return returnvalue::OK;
}
2023-03-31 01:14:59 +02:00
ReturnValue_t TmStoreTaskBase::initialize() {
modeHelper.initialize();
return returnvalue::OK;
}
void TmStoreTaskBase::getMode(Mode_t* mode, Submode_t* submode) {
if (mode != nullptr) {
*mode = this->mode;
}
if (submode != nullptr) {
*submode = SUBMODE_NONE;
}
}
ReturnValue_t TmStoreTaskBase::checkModeCommand(Mode_t mode, Submode_t submode,
uint32_t* msToReachTheMode) {
if (mode == MODE_ON or mode == MODE_OFF) {
return returnvalue::OK;
}
return returnvalue::FAILED;
}
MessageQueueId_t TmStoreTaskBase::getCommandQueue() const { return requestQueue->getId(); }
void TmStoreTaskBase::announceMode(bool recursive) { triggerEvent(MODE_INFO, mode, SUBMODE_NONE); }
object_id_t TmStoreTaskBase::getObjectId() const { return SystemObject::getObjectId(); }
const HasHealthIF* TmStoreTaskBase::getOptHealthIF() const { return nullptr; }
const HasModesIF& TmStoreTaskBase::getModeIF() const { return *this; }
ReturnValue_t TmStoreTaskBase::connectModeTreeParent(HasModeTreeChildrenIF& parent) {
return modetree::connectModeTreeParent(parent, *this, nullptr, modeHelper);
}
2023-06-29 01:28:40 +02:00
void TmStoreTaskBase::dumpDoneHandler(PersistentTmStore& store, DumpContext& dumpContext) {
uint32_t startTime;
uint32_t endTime;
store.getStartAndEndTimeCurrentOrLastDump(startTime, endTime);
triggerEvent(dumpContext.eventIfDone, dumpContext.numberOfDumpedPackets, dumpContext.dumpedBytes);
dumpContext.reset();
}
2023-03-31 01:14:59 +02:00
ModeTreeChildIF& TmStoreTaskBase::getModeTreeChildIF() { return *this; }
2023-03-31 12:11:31 +02:00
2023-03-31 01:14:59 +02:00
void TmStoreTaskBase::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;
}
}