Merge pull request 'Seq Count Persistent + MSG type counter' (#711) from sequence-counter-persistent-msg-type-count-support into main
All checks were successful
EIVE/eive-obsw/pipeline/head This commit looks good

Reviewed-on: #711
Reviewed-by: Marius Eggert <eggertm@irs.uni-stuttgart.de>
This commit is contained in:
Robin Müller 2023-06-28 13:37:14 +02:00
commit 0cdb850f69
13 changed files with 138 additions and 16 deletions

View File

@ -24,7 +24,6 @@ will consitute of a breaking change warranting a new major release:
## Changed
- Internal error reporter set is now enabled by default and generated every 120 seconds.
- Persistent TM store dumps are now performed in chronological order.
- Increase Syrlinks RX HK rate to 5.0 seconds during a pass.
- Various robustness improvements for the heater handler. The heater handler will now only
@ -34,6 +33,12 @@ will consitute of a breaking change warranting a new major release:
twice in a 0.5 second slot so something like a consecutive heater ON or OFF command can still
be handled relatively quickly.
## Added
- Sequence counters for PUS and CFDP packets are now stored persistently across graceful reboots.
- The PUS packet message type counter will now be incremented properly for each PUS service.
- Internal error reporter set is now enabled by default and generated every 120 seconds.
# [v5.0.0] 2023-06-26
v3.3.1 and all following version will now be moved to v5.0.0 with the additional changes listed

View File

@ -1224,6 +1224,10 @@ ReturnValue_t CoreController::actionReboot(const uint8_t *data, size_t size) {
ReturnValue_t CoreController::gracefulShutdownTasks(xsc::Chip chip, xsc::Copy copy,
bool &protOpPerformed) {
// Store both sequence counters persistently.
core::SAVE_CFDP_SEQUENCE_COUNT = true;
core::SAVE_PUS_SEQUENCE_COUNT = true;
sdcMan->setBlocking(true);
sdcMan->markUnusable();
// Wait two seconds to ensure no one uses the SD cards

View File

@ -11,6 +11,8 @@ static constexpr char SD_1_MOUNT_POINT[] = "/mnt/sd1";
static constexpr char OBSW_UPDATE_ARCHIVE_FILE_NAME[] = "eive-sw-update.tar.xz";
static constexpr char STRIPPED_OBSW_BINARY_FILE_NAME[] = "eive-obsw-stripped";
static constexpr char OBSW_VERSION_FILE_NAME[] = "obsw_version.txt";
static constexpr char PUS_SEQUENCE_COUNT_FILE[] = "pus-sequence-count.txt";
static constexpr char CFDP_SEQUENCE_COUNT_FILE[] = "cfdp-sequence-count.txt";
static constexpr char OBSW_PATH[] = "/usr/bin/eive-obsw";
static constexpr char OBSW_VERSION_FILE_PATH[] = "/usr/share/eive-obsw/obsw_version.txt";

2
fsfw

@ -1 +1 @@
Subproject commit 6aff3250c29f5243eb4a6111ba0a5c0cc1a3033c
Subproject commit 8da89eba80f73cb05e5c38fc012456f1d9569af5

View File

@ -91,6 +91,8 @@ EiveFaultHandler EIVE_FAULT_HANDLER;
} // namespace cfdp
std::atomic_bool tcs::TCS_BOARD_SHORTLY_UNAVAILABLE = false;
std::atomic_bool core::SAVE_PUS_SEQUENCE_COUNT = false;
std::atomic_bool core::SAVE_CFDP_SEQUENCE_COUNT = false;
void ObjectFactory::produceGenericObjects(HealthTableIF** healthTable_, PusTmFunnel** pusFunnel,
CfdpTmFunnel** cfdpFunnel, SdCardMountedIF& sdcMan,
@ -155,9 +157,11 @@ void ObjectFactory::produceGenericObjects(HealthTableIF** healthTable_, PusTmFun
new PusDistributor(config::EIVE_PUS_APID, objects::PUS_PACKET_DISTRIBUTOR, ccsdsDistrib);
PusTmFunnel::FunnelCfg pusFunnelCfg(objects::PUS_TM_FUNNEL, "PusTmFunnel", **tmStore, **ipcStore,
config::MAX_PUS_FUNNEL_QUEUE_DEPTH);
config::MAX_PUS_FUNNEL_QUEUE_DEPTH, sdcMan,
config::PUS_SEQUENCE_COUNT_FILE,
core::SAVE_PUS_SEQUENCE_COUNT);
// The PUS funnel routes all live TM to the live destinations and to the TM stores.
*pusFunnel = new PusTmFunnel(pusFunnelCfg, *ramToFileStore, *timeStamper, sdcMan);
*pusFunnel = new PusTmFunnel(pusFunnelCfg, *ramToFileStore, *timeStamper);
// MISC store and PUS funnel to MISC store routing
{
@ -216,7 +220,9 @@ void ObjectFactory::produceGenericObjects(HealthTableIF** healthTable_, PusTmFun
stores.cfdpStore->getReportReceptionQueue(0));
}
PusTmFunnel::FunnelCfg cfdpFunnelCfg(objects::CFDP_TM_FUNNEL, "CfdpTmFunnel", **tmStore,
**ipcStore, config::MAX_CFDP_FUNNEL_QUEUE_DEPTH);
**ipcStore, config::MAX_CFDP_FUNNEL_QUEUE_DEPTH, sdcMan,
config::CFDP_SEQUENCE_COUNT_FILE,
core::SAVE_CFDP_SEQUENCE_COUNT);
*cfdpFunnel = new CfdpTmFunnel(cfdpFunnelCfg, stores.cfdpStore->getReportReceptionQueue(0),
*ramToFileStore, config::EIVE_CFDP_APID);

View File

@ -34,6 +34,9 @@ enum Copy : int { COPY_0, COPY_1, NO_COPY, SELF_COPY, ALL_COPY };
namespace core {
extern std::atomic_bool SAVE_PUS_SEQUENCE_COUNT;
extern std::atomic_bool SAVE_CFDP_SEQUENCE_COUNT;
// TODO: Support for status? Or maybe some command to quickly get information whether a unit
// is running.
enum SystemctlCmd : uint8_t { START = 0, STOP = 1, RESTART = 2, NUM_CMDS = 3 };

View File

@ -15,8 +15,16 @@ const char* CfdpTmFunnel::getName() const { return "CFDP TM Funnel"; }
ReturnValue_t CfdpTmFunnel::performOperation(uint8_t) {
TmTcMessage currentMessage;
ReturnValue_t status;
unsigned int count = 0;
ReturnValue_t status = tmQueue->receiveMessage(&currentMessage);
if (saveSequenceCount) {
status = saveSequenceCountToFile();
if (status != returnvalue::OK) {
sif::error << "CfdpTmFunnel: Storing sequence count to file has failed" << std::endl;
}
saveSequenceCount = false;
}
status = tmQueue->receiveMessage(&currentMessage);
while (status == returnvalue::OK) {
status = handlePacket(currentMessage);
if (status != returnvalue::OK) {

View File

@ -3,6 +3,7 @@
#include <mission/tmtc/TmFunnelBase.h>
#include <atomic>
#include <vector>
#include "fsfw/objectmanager/SystemObject.h"
@ -23,7 +24,6 @@ class CfdpTmFunnel : public TmFunnelBase {
MessageQueueId_t fileStoreDest;
StorageManagerIF& ramToFileStore;
uint16_t sourceSequenceCount = 0;
uint16_t cfdpInCcsdsApid;
};
#endif // FSFW_EXAMPLE_COMMON_CFDPTMFUNNEL_H

View File

@ -1,5 +1,7 @@
#include "PusTmFunnel.h"
#include <limits>
#include "eive/definitions.h"
#include "eive/objects.h"
#include "fsfw/ipc/CommandMessage.h"
@ -11,8 +13,8 @@
#include "tmtc/pusIds.h"
PusTmFunnel::PusTmFunnel(TmFunnelBase::FunnelCfg cfg, StorageManagerIF &ramToFileStore,
TimeReaderIF &timeReader, SdCardMountedIF &sdcMan)
: TmFunnelBase(cfg), ramToFileStore(ramToFileStore), timeReader(timeReader), sdcMan(sdcMan) {}
TimeReaderIF &timeReader)
: TmFunnelBase(cfg), ramToFileStore(ramToFileStore), timeReader(timeReader) {}
PusTmFunnel::~PusTmFunnel() = default;
@ -21,6 +23,13 @@ ReturnValue_t PusTmFunnel::performOperation(uint8_t) {
ReturnValue_t result;
TmTcMessage currentMessage;
unsigned int count = 0;
if (saveSequenceCount) {
result = saveSequenceCountToFile();
if (result != returnvalue::OK) {
sif::error << "PusTmFunnel: Storing sequence count to file has failed" << std::endl;
}
saveSequenceCount = false;
}
result = tmQueue->receiveMessage(&currentMessage);
while (result == returnvalue::OK) {
result = handleTmPacket(currentMessage);
@ -59,7 +68,33 @@ ReturnValue_t PusTmFunnel::handleTmPacket(TmTcMessage &message) {
return result;
}
packet.setSequenceCount(sourceSequenceCount++);
// NOTE: This only works because the limit value bit width is below 16 bits!
sourceSequenceCount = sourceSequenceCount % ccsds::LIMIT_SEQUENCE_COUNT;
// Message type counter handling.
uint8_t service = packet.getService();
bool insertionFailed = false;
auto mapIter = msgCounterMap.find(service);
if (mapIter == msgCounterMap.end()) {
auto iterPair = msgCounterMap.emplace(service, 0);
if (iterPair.second) {
mapIter = iterPair.first;
} else {
// Should really never never happen but you never know..
insertionFailed = true;
}
}
if (not insertionFailed) {
packet.setMessageCount(mapIter->second);
// Sane overflow handling.
if (mapIter->second == std::numeric_limits<uint16_t>::max()) {
mapIter->second = 0;
} else {
mapIter->second++;
}
}
// Re-calculate CRC after changing the fields. This operation HAS to come last!
packet.updateErrorControl();
// Send to persistent TM store if the packet matches some filter.

View File

@ -9,6 +9,8 @@
#include <mission/tmtc/PusTmRouteByFilterHelper.h>
#include <mission/tmtc/TmFunnelBase.h>
#include <atomic>
#include <map>
#include <vector>
#include "PersistentTmStore.h"
@ -25,7 +27,7 @@
class PusTmFunnel : public TmFunnelBase {
public:
PusTmFunnel(TmFunnelBase::FunnelCfg cfg, StorageManagerIF &ramToFileStore,
TimeReaderIF &timeReader, SdCardMountedIF &sdcMan);
TimeReaderIF &timeReader);
[[nodiscard]] const char *getName() const override;
~PusTmFunnel() override;
@ -36,11 +38,10 @@ class PusTmFunnel : public TmFunnelBase {
// Update TV stamp every 5 minutes
static constexpr dur_millis_t TV_UPDATE_INTERVAL_SECS = 60 * 5;
uint16_t sourceSequenceCount = 0;
std::map<uint8_t, uint16_t> msgCounterMap;
StorageManagerIF &ramToFileStore;
TimeReaderIF &timeReader;
bool storesInitialized = false;
SdCardMountedIF &sdcMan;
PusTmRouteByFilterHelper persistentTmMap;
ReturnValue_t handleTmPacket(TmTcMessage &message);

View File

@ -2,6 +2,10 @@
#include <fsfw/tmtcservices/TmTcMessage.h>
#include <atomic>
#include <filesystem>
#include <fstream>
#include "fsfw/ipc/QueueFactory.h"
TmFunnelBase::TmFunnelBase(FunnelCfg cfg)
@ -10,7 +14,10 @@ TmFunnelBase::TmFunnelBase(FunnelCfg cfg)
tmStore(cfg.tmStore),
ipcStore(cfg.ipcStore),
tmQueue(QueueFactory::instance()->createMessageQueue(cfg.tmMsgDepth)),
liveDemux(*tmQueue) {}
liveDemux(*tmQueue),
sdcMan(cfg.sdcMan),
sequenceCounterFilename(cfg.sequenceCounterFilename),
saveSequenceCount(cfg.saveSequenceCount) {}
ReturnValue_t TmFunnelBase::demultiplexLivePackets(store_address_t origStoreId,
const uint8_t *tmData, size_t tmSize) {
@ -27,3 +34,38 @@ void TmFunnelBase::addLiveDestination(const char *name,
const AcceptsTelemetryIF &downlinkDestination, uint8_t vcid) {
liveDemux.addDestination(name, downlinkDestination, vcid);
}
ReturnValue_t TmFunnelBase::initialize() {
using namespace std::filesystem;
// The filesystem should always be available at the start.. Let's assume it always is, otherwise
// we just live with a regular 0 initialization. It simplifies a lot.
std::error_code e;
path filePath =
path(path(sdcMan.getCurrentMountPrefix()) / path("conf") / path(sequenceCounterFilename));
if (exists(filePath, e)) {
std::ifstream ifile(filePath);
if (ifile.bad()) {
sif::error << "TmFunnelBase::initialize: Faulty file open for sequence counter initialization"
<< std::endl;
return returnvalue::OK;
}
if (not(ifile >> sourceSequenceCount)) {
// Initialize to 0 in any case if reading a number failed.
sourceSequenceCount = 0;
}
}
return returnvalue::OK;
}
ReturnValue_t TmFunnelBase::saveSequenceCountToFile() {
using namespace std::filesystem;
std::error_code e;
path filePath =
path(path(sdcMan.getCurrentMountPrefix()) / path("conf") / path(sequenceCounterFilename));
std::ofstream ofile(filePath);
if (ofile.bad()) {
return returnvalue::FAILED;
}
ofile << sourceSequenceCount << "\n";
return returnvalue::OK;
}

View File

@ -6,25 +6,34 @@
#include <fsfw/tmstorage/TmStoreFrontendSimpleIF.h>
#include <fsfw/tmtcservices/AcceptsTelemetryIF.h>
#include <fsfw/tmtcservices/TmTcMessage.h>
#include <mission/memory/SdCardMountedIF.h>
#include <mission/tmtc/PusLiveDemux.h>
#include <atomic>
#include <vector>
class TmFunnelBase : public AcceptsTelemetryIF, public SystemObject {
public:
struct FunnelCfg {
FunnelCfg(object_id_t objId, const char* name, StorageManagerIF& tmStore,
StorageManagerIF& ipcStore, uint32_t tmMsgDepth)
StorageManagerIF& ipcStore, uint32_t tmMsgDepth, SdCardMountedIF& sdcMan,
const char* sequenceCounterFilename, std::atomic_bool& saveSequenceCount)
: objectId(objId),
name(name),
tmStore(tmStore),
ipcStore(ipcStore),
tmMsgDepth(tmMsgDepth) {}
tmMsgDepth(tmMsgDepth),
sdcMan(sdcMan),
sequenceCounterFilename(sequenceCounterFilename),
saveSequenceCount(saveSequenceCount) {}
object_id_t objectId;
const char* name;
StorageManagerIF& tmStore;
StorageManagerIF& ipcStore;
uint32_t tmMsgDepth;
SdCardMountedIF& sdcMan;
const char* sequenceCounterFilename;
std::atomic_bool& saveSequenceCount;
};
explicit TmFunnelBase(FunnelCfg cfg);
[[nodiscard]] MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel) const override;
@ -32,6 +41,9 @@ class TmFunnelBase : public AcceptsTelemetryIF, public SystemObject {
uint8_t vcid = 0);
ReturnValue_t demultiplexLivePackets(store_address_t origStoreId, const uint8_t* tmData,
size_t tmSize);
ReturnValue_t initialize() override;
ReturnValue_t saveSequenceCountToFile();
~TmFunnelBase() override;
@ -41,6 +53,10 @@ class TmFunnelBase : public AcceptsTelemetryIF, public SystemObject {
StorageManagerIF& ipcStore;
MessageQueueIF* tmQueue = nullptr;
PusLiveDemux liveDemux;
SdCardMountedIF& sdcMan;
const char* sequenceCounterFilename;
std::atomic_bool& saveSequenceCount;
uint16_t sourceSequenceCount = 0;
};
#endif /* MISSION_TMTC_TMFUNNELBASE_H_ */

2
tmtc

@ -1 +1 @@
Subproject commit ec0ebc365308198046addc94909b1bca8678aa5a
Subproject commit 8caa408cbdf7eebdd441cff580063283ab81ffe1