PTME rework reset handling #542
@ -19,11 +19,19 @@ will consitute of a breaking change warranting a new major release:
|
|||||||
## Changed
|
## Changed
|
||||||
|
|
||||||
- SCEX filename updates. Also use T as the file ID / date separator between date and time.
|
- SCEX filename updates. Also use T as the file ID / date separator between date and time.
|
||||||
|
- COM TM store and dump handling: Introduce modes for all 4 TM VC/store tasks. The OFF mode can be
|
||||||
|
used to disable ongoing dumps or to prevent writes to the PTME VC. This allows cleaner reset
|
||||||
|
handling of the PTME. All 4 VC/store tasks were attached to the COM mode tree and are commanded
|
||||||
|
as part of the COM sequence as well to ensure consistent state with the CCSDS IP core handler.
|
||||||
|
- Added `PTME_LOCKED` boolean lock which is used to lock the PTME so it is not used by the VC tasks
|
||||||
|
anymore. This lock will be controlled by the CCSDS IP core handler and is locked when the PTME
|
||||||
|
needs to be reset. Examples for this are datarate changes.
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
|
|
||||||
- Bugfix for side lane transitions of the dual lane assemblies, which only worked when the
|
- Bugfix for side lane transitions of the dual lane assemblies, which only worked when the
|
||||||
assembly was directly commanded
|
assembly was directly commanded
|
||||||
|
- Syrlinks Handler: Bugfix so transition command is only sent once.
|
||||||
|
|
||||||
## Added
|
## Added
|
||||||
|
|
||||||
|
@ -486,7 +486,8 @@ endif()
|
|||||||
target_link_libraries(${LIB_EIVE_MISSION} PUBLIC ${LIB_FSFW_NAME}
|
target_link_libraries(${LIB_EIVE_MISSION} PUBLIC ${LIB_FSFW_NAME}
|
||||||
${LIB_OS_NAME})
|
${LIB_OS_NAME})
|
||||||
|
|
||||||
target_link_libraries(${LIB_DUMMIES} PUBLIC ${LIB_FSFW_NAME} ${LIB_JSON_NAME})
|
target_link_libraries(${LIB_DUMMIES} PUBLIC ${LIB_EIVE_MISSION}
|
||||||
|
${LIB_FSFW_NAME} ${LIB_JSON_NAME})
|
||||||
|
|
||||||
target_link_libraries(${OBSW_NAME} PRIVATE ${LIB_EIVE_MISSION} ${LIB_DUMMIES})
|
target_link_libraries(${OBSW_NAME} PRIVATE ${LIB_EIVE_MISSION} ${LIB_DUMMIES})
|
||||||
|
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
#include <dummies/AcuDummy.h>
|
#include <dummies/AcuDummy.h>
|
||||||
#include <dummies/CoreControllerDummy.h>
|
#include <dummies/CoreControllerDummy.h>
|
||||||
|
|
||||||
#include "dummies/helpers.h"
|
#include "dummies/helperFactory.h"
|
||||||
|
|
||||||
#ifdef PLATFORM_UNIX
|
#ifdef PLATFORM_UNIX
|
||||||
#include <fsfw_hal/linux/serial/SerialComIF.h>
|
#include <fsfw_hal/linux/serial/SerialComIF.h>
|
||||||
|
@ -20,15 +20,15 @@
|
|||||||
#include <mission/acs/MgmRm3100CustomHandler.h>
|
#include <mission/acs/MgmRm3100CustomHandler.h>
|
||||||
#include <mission/acs/str/StarTrackerHandler.h>
|
#include <mission/acs/str/StarTrackerHandler.h>
|
||||||
#include <mission/acs/str/strHelpers.h>
|
#include <mission/acs/str/strHelpers.h>
|
||||||
|
#include <mission/com/LiveTmTask.h>
|
||||||
|
#include <mission/com/PersistentLogTmStoreTask.h>
|
||||||
|
#include <mission/com/PersistentSingleTmStoreTask.h>
|
||||||
#include <mission/power/CspCookie.h>
|
#include <mission/power/CspCookie.h>
|
||||||
#include <mission/system/acs/ImtqAssembly.h>
|
#include <mission/system/acs/ImtqAssembly.h>
|
||||||
#include <mission/system/acs/StrAssembly.h>
|
#include <mission/system/acs/StrAssembly.h>
|
||||||
#include <mission/system/fdir/StrFdir.h>
|
#include <mission/system/fdir/StrFdir.h>
|
||||||
#include <mission/system/objects/CamSwitcher.h>
|
#include <mission/system/objects/CamSwitcher.h>
|
||||||
#include <mission/system/objects/SyrlinksAssembly.h>
|
#include <mission/system/objects/SyrlinksAssembly.h>
|
||||||
#include <mission/tmtc/LiveTmTask.h>
|
|
||||||
#include <mission/tmtc/PersistentLogTmStoreTask.h>
|
|
||||||
#include <mission/tmtc/PersistentSingleTmStoreTask.h>
|
|
||||||
|
|
||||||
#include "OBSWConfig.h"
|
#include "OBSWConfig.h"
|
||||||
#include "bsp_q7s/boardtest/Q7STestTask.h"
|
#include "bsp_q7s/boardtest/Q7STestTask.h"
|
||||||
@ -81,6 +81,7 @@ using gpio::Levels;
|
|||||||
#include <mission/acs/ImtqHandler.h>
|
#include <mission/acs/ImtqHandler.h>
|
||||||
#include <mission/acs/rwHelpers.h>
|
#include <mission/acs/rwHelpers.h>
|
||||||
#include <mission/com/SyrlinksHandler.h>
|
#include <mission/com/SyrlinksHandler.h>
|
||||||
|
#include <mission/com/VirtualChannelWithQueue.h>
|
||||||
#include <mission/payload/PayloadPcduHandler.h>
|
#include <mission/payload/PayloadPcduHandler.h>
|
||||||
#include <mission/payload/RadiationSensorHandler.h>
|
#include <mission/payload/RadiationSensorHandler.h>
|
||||||
#include <mission/payload/payloadPcduDefinitions.h>
|
#include <mission/payload/payloadPcduDefinitions.h>
|
||||||
@ -96,7 +97,6 @@ using gpio::Levels;
|
|||||||
#include <mission/tcs/Max31865Definitions.h>
|
#include <mission/tcs/Max31865Definitions.h>
|
||||||
#include <mission/tcs/Max31865PT1000Handler.h>
|
#include <mission/tcs/Max31865PT1000Handler.h>
|
||||||
#include <mission/tcs/Tmp1075Handler.h>
|
#include <mission/tcs/Tmp1075Handler.h>
|
||||||
#include <mission/tmtc/VirtualChannelWithQueue.h>
|
|
||||||
|
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
@ -125,6 +125,7 @@ using gpio::Levels;
|
|||||||
|
|
||||||
ResetArgs RESET_ARGS_GNSS;
|
ResetArgs RESET_ARGS_GNSS;
|
||||||
std::atomic_bool LINK_STATE = CcsdsIpCoreHandler::LINK_DOWN;
|
std::atomic_bool LINK_STATE = CcsdsIpCoreHandler::LINK_DOWN;
|
||||||
|
std::atomic_bool PTME_LOCKED = false;
|
||||||
std::atomic_uint16_t I2C_FATAL_ERRORS = 0;
|
std::atomic_uint16_t I2C_FATAL_ERRORS = 0;
|
||||||
|
|
||||||
void Factory::setStaticFrameworkObjectIds() {
|
void Factory::setStaticFrameworkObjectIds() {
|
||||||
@ -754,10 +755,8 @@ ReturnValue_t ObjectFactory::createCcsdsComponents(CcsdsComponentArgs& args) {
|
|||||||
gpioCookiePtmeIp->addGpio(gpioIds::VC3_PAPB_BUSY, gpio);
|
gpioCookiePtmeIp->addGpio(gpioIds::VC3_PAPB_BUSY, gpio);
|
||||||
gpio = new GpiodRegularByLineName(q7s::gpioNames::PAPB_EMPTY_SIGNAL_VC3, "PAPB VC3");
|
gpio = new GpiodRegularByLineName(q7s::gpioNames::PAPB_EMPTY_SIGNAL_VC3, "PAPB VC3");
|
||||||
gpioCookiePtmeIp->addGpio(gpioIds::VC3_PAPB_EMPTY, gpio);
|
gpioCookiePtmeIp->addGpio(gpioIds::VC3_PAPB_EMPTY, gpio);
|
||||||
// Initialise to low and then pull high to do a PTME reset, which puts the PTME in reset
|
|
||||||
// state. It will be put out of reset in the CCSDS handler initialize function.
|
|
||||||
gpio = new GpiodRegularByLineName(q7s::gpioNames::PTME_RESETN, "PTME RESETN",
|
gpio = new GpiodRegularByLineName(q7s::gpioNames::PTME_RESETN, "PTME RESETN",
|
||||||
gpio::Direction::OUT, gpio::Levels::LOW);
|
gpio::Direction::OUT, gpio::Levels::HIGH);
|
||||||
gpioCookiePtmeIp->addGpio(gpioIds::PTME_RESETN, gpio);
|
gpioCookiePtmeIp->addGpio(gpioIds::PTME_RESETN, gpio);
|
||||||
gpioChecker(args.gpioComIF.addGpios(gpioCookiePtmeIp), "PTME PAPB VCs");
|
gpioChecker(args.gpioComIF.addGpios(gpioCookiePtmeIp), "PTME PAPB VCs");
|
||||||
|
|
||||||
@ -791,34 +790,42 @@ ReturnValue_t ObjectFactory::createCcsdsComponents(CcsdsComponentArgs& args) {
|
|||||||
|
|
||||||
*args.ipCoreHandler =
|
*args.ipCoreHandler =
|
||||||
new CcsdsIpCoreHandler(objects::CCSDS_HANDLER, objects::CCSDS_PACKET_DISTRIBUTOR, *ptmeConfig,
|
new CcsdsIpCoreHandler(objects::CCSDS_HANDLER, objects::CCSDS_PACKET_DISTRIBUTOR, *ptmeConfig,
|
||||||
LINK_STATE, &args.gpioComIF, gpios);
|
LINK_STATE, &args.gpioComIF, gpios, PTME_LOCKED);
|
||||||
// This VC will receive all live TM
|
// This VC will receive all live TM
|
||||||
auto* vcWithQueue =
|
auto* vcWithQueue =
|
||||||
new VirtualChannelWithQueue(objects::PTME_VC0_LIVE_TM, ccsds::VC0, "PTME VC0 LIVE TM", *ptme,
|
new VirtualChannelWithQueue(objects::PTME_VC0_LIVE_TM, ccsds::VC0, "PTME VC0 LIVE TM", *ptme,
|
||||||
LINK_STATE, args.tmStore, 500);
|
LINK_STATE, args.tmStore, 500);
|
||||||
args.liveDestination = vcWithQueue;
|
args.liveDestination = vcWithQueue;
|
||||||
new LiveTmTask(objects::LIVE_TM_TASK, args.pusFunnel, args.cfdpFunnel, *vcWithQueue);
|
auto* liveTask = new LiveTmTask(objects::LIVE_TM_TASK, args.pusFunnel, args.cfdpFunnel,
|
||||||
|
*vcWithQueue, PTME_LOCKED);
|
||||||
|
liveTask->connectModeTreeParent(satsystem::com::SUBSYSTEM);
|
||||||
|
|
||||||
// Set up log store.
|
// Set up log store.
|
||||||
auto* vc = new VirtualChannel(objects::PTME_VC1_LOG_TM, ccsds::VC1, "PTME VC1 LOG TM", *ptme,
|
auto* vc = new VirtualChannel(objects::PTME_VC1_LOG_TM, ccsds::VC1, "PTME VC1 LOG TM", *ptme,
|
||||||
LINK_STATE);
|
LINK_STATE);
|
||||||
LogStores logStores(args.stores);
|
LogStores logStores(args.stores);
|
||||||
// Core task which handles the LOG store and takes care of dumping it as TM using a VC directly
|
// Core task which handles the LOG store and takes care of dumping it as TM using a VC directly
|
||||||
|
auto* logStore =
|
||||||
new PersistentLogTmStoreTask(objects::LOG_STORE_AND_TM_TASK, args.ipcStore, logStores, *vc,
|
new PersistentLogTmStoreTask(objects::LOG_STORE_AND_TM_TASK, args.ipcStore, logStores, *vc,
|
||||||
*SdCardManager::instance());
|
*SdCardManager::instance(), PTME_LOCKED);
|
||||||
|
logStore->connectModeTreeParent(satsystem::com::SUBSYSTEM);
|
||||||
|
|
||||||
vc = new VirtualChannel(objects::PTME_VC2_HK_TM, ccsds::VC2, "PTME VC2 HK TM", *ptme, LINK_STATE);
|
vc = new VirtualChannel(objects::PTME_VC2_HK_TM, ccsds::VC2, "PTME VC2 HK TM", *ptme, LINK_STATE);
|
||||||
// Core task which handles the HK store and takes care of dumping it as TM using a VC directly
|
// Core task which handles the HK store and takes care of dumping it as TM using a VC directly
|
||||||
new PersistentSingleTmStoreTask(objects::HK_STORE_AND_TM_TASK, args.ipcStore,
|
auto* hkStore = new PersistentSingleTmStoreTask(
|
||||||
*args.stores.hkStore, *vc, persTmStore::DUMP_HK_STORE_DONE,
|
objects::HK_STORE_AND_TM_TASK, args.ipcStore, *args.stores.hkStore, *vc,
|
||||||
persTmStore::DUMP_HK_STORE_DONE, *SdCardManager::instance());
|
persTmStore::DUMP_HK_STORE_DONE, persTmStore::DUMP_HK_STORE_DONE, *SdCardManager::instance(),
|
||||||
|
PTME_LOCKED);
|
||||||
|
hkStore->connectModeTreeParent(satsystem::com::SUBSYSTEM);
|
||||||
|
|
||||||
vc = new VirtualChannel(objects::PTME_VC3_CFDP_TM, ccsds::VC3, "PTME VC3 CFDP TM", *ptme,
|
vc = new VirtualChannel(objects::PTME_VC3_CFDP_TM, ccsds::VC3, "PTME VC3 CFDP TM", *ptme,
|
||||||
LINK_STATE);
|
LINK_STATE);
|
||||||
// Core task which handles the CFDP store and takes care of dumping it as TM using a VC directly
|
// Core task which handles the CFDP store and takes care of dumping it as TM using a VC directly
|
||||||
new PersistentSingleTmStoreTask(objects::CFDP_STORE_AND_TM_TASK, args.ipcStore,
|
auto* cfdpTask = new PersistentSingleTmStoreTask(
|
||||||
*args.stores.cfdpStore, *vc, persTmStore::DUMP_CFDP_STORE_DONE,
|
objects::CFDP_STORE_AND_TM_TASK, args.ipcStore, *args.stores.cfdpStore, *vc,
|
||||||
persTmStore::DUMP_CFDP_CANCELLED, *SdCardManager::instance());
|
persTmStore::DUMP_CFDP_STORE_DONE, persTmStore::DUMP_CFDP_CANCELLED,
|
||||||
|
*SdCardManager::instance(), PTME_LOCKED);
|
||||||
|
cfdpTask->connectModeTreeParent(satsystem::com::SUBSYSTEM);
|
||||||
|
|
||||||
ReturnValue_t result = (*args.ipCoreHandler)->connectModeTreeParent(satsystem::com::SUBSYSTEM);
|
ReturnValue_t result = (*args.ipCoreHandler)->connectModeTreeParent(satsystem::com::SUBSYSTEM);
|
||||||
if (result != returnvalue::OK) {
|
if (result != returnvalue::OK) {
|
||||||
|
@ -4,11 +4,11 @@
|
|||||||
#include <fsfw/returnvalues/returnvalue.h>
|
#include <fsfw/returnvalues/returnvalue.h>
|
||||||
#include <fsfw_hal/linux/spi/SpiComIF.h>
|
#include <fsfw_hal/linux/spi/SpiComIF.h>
|
||||||
#include <mission/com/CcsdsIpCoreHandler.h>
|
#include <mission/com/CcsdsIpCoreHandler.h>
|
||||||
|
#include <mission/com/PersistentLogTmStoreTask.h>
|
||||||
#include <mission/genericFactory.h>
|
#include <mission/genericFactory.h>
|
||||||
#include <mission/system/objects/Stack5VHandler.h>
|
#include <mission/system/objects/Stack5VHandler.h>
|
||||||
#include <mission/tcs/HeaterHandler.h>
|
#include <mission/tcs/HeaterHandler.h>
|
||||||
#include <mission/tmtc/CfdpTmFunnel.h>
|
#include <mission/tmtc/CfdpTmFunnel.h>
|
||||||
#include <mission/tmtc/PersistentLogTmStoreTask.h>
|
|
||||||
#include <mission/tmtc/PusTmFunnel.h>
|
#include <mission/tmtc/PusTmFunnel.h>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
@ -24,6 +24,7 @@ class AcsBoardAssembly;
|
|||||||
class GpioIF;
|
class GpioIF;
|
||||||
|
|
||||||
extern std::atomic_uint16_t I2C_FATAL_ERRORS;
|
extern std::atomic_uint16_t I2C_FATAL_ERRORS;
|
||||||
|
extern std::atomic_bool PTME_LOCKED;
|
||||||
|
|
||||||
namespace ObjectFactory {
|
namespace ObjectFactory {
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
#include "bsp_q7s/core/ObjectFactory.h"
|
#include "bsp_q7s/core/ObjectFactory.h"
|
||||||
#include "busConf.h"
|
#include "busConf.h"
|
||||||
#include "devConf.h"
|
#include "devConf.h"
|
||||||
#include "dummies/helpers.h"
|
#include "dummies/helperFactory.h"
|
||||||
#include "eive/objects.h"
|
#include "eive/objects.h"
|
||||||
#include "fsfw_hal/linux/gpio/LinuxLibgpioIF.h"
|
#include "fsfw_hal/linux/gpio/LinuxLibgpioIF.h"
|
||||||
#include "linux/ObjectFactory.h"
|
#include "linux/ObjectFactory.h"
|
||||||
|
@ -26,6 +26,6 @@ target_sources(
|
|||||||
CoreControllerDummy.cpp
|
CoreControllerDummy.cpp
|
||||||
PlocMpsocDummy.cpp
|
PlocMpsocDummy.cpp
|
||||||
PlocSupervisorDummy.cpp
|
PlocSupervisorDummy.cpp
|
||||||
helpers.cpp
|
helperFactory.cpp
|
||||||
MgmRm3100Dummy.cpp
|
MgmRm3100Dummy.cpp
|
||||||
Tmp1075Dummy.cpp)
|
Tmp1075Dummy.cpp)
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
#include "helpers.h"
|
#include "helperFactory.h"
|
||||||
|
|
||||||
#include <dummies/AcuDummy.h>
|
#include <dummies/AcuDummy.h>
|
||||||
#include <dummies/BpxDummy.h>
|
#include <dummies/BpxDummy.h>
|
||||||
@ -24,6 +24,7 @@
|
|||||||
#include <dummies/StarTrackerDummy.h>
|
#include <dummies/StarTrackerDummy.h>
|
||||||
#include <dummies/SusDummy.h>
|
#include <dummies/SusDummy.h>
|
||||||
#include <dummies/SyrlinksDummy.h>
|
#include <dummies/SyrlinksDummy.h>
|
||||||
|
#include <fsfw/devicehandlers/HealthDevice.h>
|
||||||
#include <fsfw_hal/common/gpio/GpioIF.h>
|
#include <fsfw_hal/common/gpio/GpioIF.h>
|
||||||
#include <mission/power/gsDefs.h>
|
#include <mission/power/gsDefs.h>
|
||||||
#include <mission/system/acs/ImtqAssembly.h>
|
#include <mission/system/acs/ImtqAssembly.h>
|
||||||
@ -98,6 +99,8 @@ void dummy::createDummies(DummyCfg cfg, PowerSwitchIF& pwrSwitcher, GpioIF* gpio
|
|||||||
new GyroAdisDummy(objects::GYRO_2_ADIS_HANDLER, objects::DUMMY_COM_IF, comCookieDummy);
|
new GyroAdisDummy(objects::GYRO_2_ADIS_HANDLER, objects::DUMMY_COM_IF, comCookieDummy);
|
||||||
assemblyDhbs[7] =
|
assemblyDhbs[7] =
|
||||||
new GyroL3GD20Dummy(objects::GYRO_3_L3G_HANDLER, objects::DUMMY_COM_IF, comCookieDummy);
|
new GyroL3GD20Dummy(objects::GYRO_3_L3G_HANDLER, objects::DUMMY_COM_IF, comCookieDummy);
|
||||||
|
new HealthDevice(objects::GPS_0_HEALTH_DEV, objects::ACS_BOARD_ASS);
|
||||||
|
new HealthDevice(objects::GPS_1_HEALTH_DEV, objects::ACS_BOARD_ASS);
|
||||||
auto* gpsCtrl = new GpsCtrlDummy(objects::GPS_CONTROLLER);
|
auto* gpsCtrl = new GpsCtrlDummy(objects::GPS_CONTROLLER);
|
||||||
ObjectFactory::createAcsBoardAssy(pwrSwitcher, assemblyDhbs, gpsCtrl, gpioIF);
|
ObjectFactory::createAcsBoardAssy(pwrSwitcher, assemblyDhbs, gpsCtrl, gpioIF);
|
||||||
}
|
}
|
@ -18,29 +18,28 @@ PapbVcInterface::~PapbVcInterface() {}
|
|||||||
|
|
||||||
ReturnValue_t PapbVcInterface::initialize() {
|
ReturnValue_t PapbVcInterface::initialize() {
|
||||||
UioMapper uioMapper(uioFile, mapNum);
|
UioMapper uioMapper(uioFile, mapNum);
|
||||||
uint32_t* baseReg;
|
ReturnValue_t result = uioMapper.getMappedAdress(const_cast<uint32_t**>(&vcBaseReg),
|
||||||
ReturnValue_t result = uioMapper.getMappedAdress(&baseReg, UioMapper::Permissions::WRITE_ONLY);
|
UioMapper::Permissions::WRITE_ONLY);
|
||||||
if (result != returnvalue::OK) {
|
if (result != returnvalue::OK) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
vcBaseReg = baseReg;
|
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t PapbVcInterface::write(const uint8_t* data, size_t size) {
|
ReturnValue_t PapbVcInterface::write(const uint8_t* data, size_t size) {
|
||||||
if (pollPapbBusySignal(0) == returnvalue::OK) {
|
if (pollInterfaceReadiness(0, true) == returnvalue::OK) {
|
||||||
startPacketTransfer();
|
startPacketTransfer();
|
||||||
} else {
|
} else {
|
||||||
return DirectTmSinkIF::IS_BUSY;
|
return DirectTmSinkIF::IS_BUSY;
|
||||||
}
|
}
|
||||||
for (size_t idx = 0; idx < size; idx++) {
|
for (size_t idx = 0; idx < size; idx++) {
|
||||||
// This delay is super-important, DO NOT REMOVE!
|
// This delay is super-important, DO NOT REMOVE!
|
||||||
// Polling the GPIO too often can mess up the scheduler.
|
// Polling the GPIO or the config register too often messes up the scheduler.
|
||||||
// TODO: Maybe this should not be done like this. It would be better if there was a custom
|
// TODO: Maybe this should not be done like this. It would be better if there was a custom
|
||||||
// FPGA module which can accept packets and then takes care of dumping that packet into
|
// FPGA module which can accept packets and then takes care of dumping that packet into
|
||||||
// the PTME. DMA would be an ideal solution for this.
|
// the PTME. DMA would be an ideal solution for this.
|
||||||
nanosleep(&BETWEEN_POLL_DELAY, &remDelay);
|
nanosleep(&BETWEEN_POLL_DELAY, &remDelay);
|
||||||
if (pollPapbBusySignal(2) == returnvalue::OK) {
|
if (pollInterfaceReadiness(2, false) == returnvalue::OK) {
|
||||||
*(vcBaseReg + DATA_REG_OFFSET) = static_cast<uint32_t>(data[idx]);
|
*(vcBaseReg + DATA_REG_OFFSET) = static_cast<uint32_t>(data[idx]);
|
||||||
} else {
|
} else {
|
||||||
abortPacketTransfer();
|
abortPacketTransfer();
|
||||||
@ -48,7 +47,7 @@ ReturnValue_t PapbVcInterface::write(const uint8_t* data, size_t size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
nanosleep(&BETWEEN_POLL_DELAY, &remDelay);
|
nanosleep(&BETWEEN_POLL_DELAY, &remDelay);
|
||||||
if (pollPapbBusySignal(2) == returnvalue::OK) {
|
if (pollInterfaceReadiness(2, false) == returnvalue::OK) {
|
||||||
completePacketTransfer();
|
completePacketTransfer();
|
||||||
} else {
|
} else {
|
||||||
abortPacketTransfer();
|
abortPacketTransfer();
|
||||||
@ -61,23 +60,23 @@ void PapbVcInterface::startPacketTransfer() { *vcBaseReg = CONFIG_START; }
|
|||||||
|
|
||||||
void PapbVcInterface::completePacketTransfer() { *vcBaseReg = CONFIG_END; }
|
void PapbVcInterface::completePacketTransfer() { *vcBaseReg = CONFIG_END; }
|
||||||
|
|
||||||
ReturnValue_t PapbVcInterface::pollPapbBusySignal(uint32_t maxPollRetries) const {
|
ReturnValue_t PapbVcInterface::pollInterfaceReadiness(uint32_t maxPollRetries,
|
||||||
gpio::Levels papbBusyState = gpio::Levels::LOW;
|
bool checkReadyState) const {
|
||||||
ReturnValue_t result;
|
|
||||||
uint32_t busyIdx = 0;
|
uint32_t busyIdx = 0;
|
||||||
nextDelay.tv_nsec = 0;
|
nextDelay.tv_nsec = FIRST_NON_NULL_DELAY_NS;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
/** Check if PAPB interface is ready to receive data */
|
// Check if PAPB interface is ready to receive data. Use the configuration register for this.
|
||||||
result = gpioComIF->readGpio(papbBusyId, papbBusyState);
|
// Bit 5, see PTME ptme_001_01-0-7-r2 Table 31.
|
||||||
if (result != returnvalue::OK) {
|
uint32_t reg = *vcBaseReg;
|
||||||
sif::warning << "PapbVcInterface::pollPapbBusySignal: Failed to read papb busy signal"
|
bool busy = (reg >> 5) & 0b1;
|
||||||
<< std::endl;
|
bool ready = (reg >> 6) & 0b1;
|
||||||
return returnvalue::FAILED;
|
if (not busy) {
|
||||||
}
|
|
||||||
if (papbBusyState == gpio::Levels::HIGH) {
|
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
if (checkReadyState and not ready) {
|
||||||
|
return PAPB_BUSY;
|
||||||
|
}
|
||||||
|
|
||||||
busyIdx++;
|
busyIdx++;
|
||||||
if (busyIdx >= maxPollRetries) {
|
if (busyIdx >= maxPollRetries) {
|
||||||
@ -87,9 +86,7 @@ ReturnValue_t PapbVcInterface::pollPapbBusySignal(uint32_t maxPollRetries) const
|
|||||||
// Ignore signal handling here for now.
|
// Ignore signal handling here for now.
|
||||||
nanosleep(&nextDelay, &remDelay);
|
nanosleep(&nextDelay, &remDelay);
|
||||||
// Adaptive delay.
|
// Adaptive delay.
|
||||||
if (nextDelay.tv_nsec == 0) {
|
if (nextDelay.tv_nsec * 2 <= MAX_DELAY_PAPB_POLLING_NS) {
|
||||||
nextDelay.tv_nsec = FIRST_NON_NULL_DELAY_NS;
|
|
||||||
} else if (nextDelay.tv_nsec * 2 <= MAX_DELAY_PAPB_POLLING_NS) {
|
|
||||||
nextDelay.tv_nsec *= 2;
|
nextDelay.tv_nsec *= 2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -116,7 +113,7 @@ void PapbVcInterface::isVcInterfaceBufferEmpty() {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PapbVcInterface::isBusy() const { return pollPapbBusySignal(0) == PAPB_BUSY; }
|
bool PapbVcInterface::isBusy() const { return pollInterfaceReadiness(0, true) == PAPB_BUSY; }
|
||||||
|
|
||||||
void PapbVcInterface::cancelTransfer() { abortPacketTransfer(); }
|
void PapbVcInterface::cancelTransfer() { abortPacketTransfer(); }
|
||||||
|
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
#include <fsfw_hal/linux/gpio/LinuxLibgpioIF.h>
|
#include <fsfw_hal/linux/gpio/LinuxLibgpioIF.h>
|
||||||
#include <linux/ipcore/VirtualChannelIF.h>
|
#include <linux/ipcore/VirtualChannelIF.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
#include "OBSWConfig.h"
|
#include "OBSWConfig.h"
|
||||||
#include "fsfw/returnvalues/returnvalue.h"
|
#include "fsfw/returnvalues/returnvalue.h"
|
||||||
|
|
||||||
@ -89,7 +91,7 @@ class PapbVcInterface : public VirtualChannelIF {
|
|||||||
std::string uioFile;
|
std::string uioFile;
|
||||||
int mapNum = 0;
|
int mapNum = 0;
|
||||||
mutable struct timespec nextDelay = {.tv_sec = 0, .tv_nsec = 0};
|
mutable struct timespec nextDelay = {.tv_sec = 0, .tv_nsec = 0};
|
||||||
const struct timespec BETWEEN_POLL_DELAY = {.tv_sec = 0, .tv_nsec = 5};
|
const struct timespec BETWEEN_POLL_DELAY = {.tv_sec = 0, .tv_nsec = 10};
|
||||||
mutable struct timespec remDelay;
|
mutable struct timespec remDelay;
|
||||||
|
|
||||||
volatile uint32_t* vcBaseReg = nullptr;
|
volatile uint32_t* vcBaseReg = nullptr;
|
||||||
@ -117,7 +119,7 @@ class PapbVcInterface : public VirtualChannelIF {
|
|||||||
*
|
*
|
||||||
* @return returnvalue::OK when ready to receive data else PAPB_BUSY.
|
* @return returnvalue::OK when ready to receive data else PAPB_BUSY.
|
||||||
*/
|
*/
|
||||||
inline ReturnValue_t pollPapbBusySignal(uint32_t maxPollRetries) const;
|
inline ReturnValue_t pollInterfaceReadiness(uint32_t maxPollRetries, bool checkReadyState) const;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief This function can be used for debugging to check whether there are packets in
|
* @brief This function can be used for debugging to check whether there are packets in
|
||||||
|
@ -1,2 +1,11 @@
|
|||||||
target_sources(${LIB_EIVE_MISSION} PRIVATE SyrlinksHandler.cpp
|
target_sources(
|
||||||
CcsdsIpCoreHandler.cpp)
|
${LIB_EIVE_MISSION}
|
||||||
|
PRIVATE SyrlinksHandler.cpp
|
||||||
|
CcsdsIpCoreHandler.cpp
|
||||||
|
LiveTmTask.cpp
|
||||||
|
PersistentLogTmStoreTask.cpp
|
||||||
|
TmStoreTaskBase.cpp
|
||||||
|
VirtualChannel.cpp
|
||||||
|
VirtualChannelWithQueue.cpp
|
||||||
|
PersistentSingleTmStoreTask.cpp
|
||||||
|
LiveTmTask.cpp)
|
||||||
|
@ -15,9 +15,11 @@
|
|||||||
|
|
||||||
CcsdsIpCoreHandler::CcsdsIpCoreHandler(object_id_t objectId, object_id_t tcDestination,
|
CcsdsIpCoreHandler::CcsdsIpCoreHandler(object_id_t objectId, object_id_t tcDestination,
|
||||||
PtmeConfig& ptmeConfig, std::atomic_bool& linkState,
|
PtmeConfig& ptmeConfig, std::atomic_bool& linkState,
|
||||||
GpioIF* gpioIF, PtmeGpios gpioIds)
|
GpioIF* gpioIF, PtmeGpios gpioIds,
|
||||||
|
std::atomic_bool& ptmeLocked)
|
||||||
: SystemObject(objectId),
|
: SystemObject(objectId),
|
||||||
linkState(linkState),
|
linkState(linkState),
|
||||||
|
ptmeLocked(ptmeLocked),
|
||||||
tcDestination(tcDestination),
|
tcDestination(tcDestination),
|
||||||
parameterHelper(this),
|
parameterHelper(this),
|
||||||
actionHelper(this, nullptr),
|
actionHelper(this, nullptr),
|
||||||
@ -29,12 +31,14 @@ CcsdsIpCoreHandler::CcsdsIpCoreHandler(object_id_t objectId, object_id_t tcDesti
|
|||||||
auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
|
auto mqArgs = MqArgs(objectId, static_cast<void*>(this));
|
||||||
eventQueue =
|
eventQueue =
|
||||||
QueueFactory::instance()->createMessageQueue(10, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
|
QueueFactory::instance()->createMessageQueue(10, EventMessage::EVENT_MESSAGE_SIZE, &mqArgs);
|
||||||
|
ptmeLocked = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
CcsdsIpCoreHandler::~CcsdsIpCoreHandler() = default;
|
CcsdsIpCoreHandler::~CcsdsIpCoreHandler() = default;
|
||||||
|
|
||||||
ReturnValue_t CcsdsIpCoreHandler::performOperation(uint8_t operationCode) {
|
ReturnValue_t CcsdsIpCoreHandler::performOperation(uint8_t operationCode) {
|
||||||
readCommandQueue();
|
readCommandQueue();
|
||||||
|
performPtmeUpdateWhenApplicable();
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -76,6 +80,8 @@ ReturnValue_t CcsdsIpCoreHandler::initialize() {
|
|||||||
} else {
|
} else {
|
||||||
enablePrioritySelectMode();
|
enablePrioritySelectMode();
|
||||||
}
|
}
|
||||||
|
resetPtme();
|
||||||
|
ptmeLocked = false;
|
||||||
|
|
||||||
#if OBSW_SYRLINKS_SIMULATED == 1
|
#if OBSW_SYRLINKS_SIMULATED == 1
|
||||||
// Update data on rising edge
|
// Update data on rising edge
|
||||||
@ -127,10 +133,15 @@ ReturnValue_t CcsdsIpCoreHandler::getParameter(uint8_t domainId, uint8_t uniqueI
|
|||||||
return HasParametersIF::INVALID_VALUE;
|
return HasParametersIF::INVALID_VALUE;
|
||||||
}
|
}
|
||||||
parameterWrapper->set(batPriorityParam);
|
parameterWrapper->set(batPriorityParam);
|
||||||
if (mode == MODE_ON) {
|
if (newVal != batPriorityParam) {
|
||||||
updateBatPriorityOnTxOff = true;
|
// This ensures that the BAT priority is updated at some point when an update of the PTME is
|
||||||
} else if (mode == MODE_OFF) {
|
// allowed
|
||||||
updateBatPriorityFromParam();
|
updateContext.updateBatPrio = true;
|
||||||
|
// If we are off, we can do the update after X cycles. Otherwise, wait until the transmitter
|
||||||
|
// goes off.
|
||||||
|
if (mode == MODE_OFF) {
|
||||||
|
initPtmeUpdateAfterXCycles();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
@ -148,36 +159,12 @@ ReturnValue_t CcsdsIpCoreHandler::executeAction(ActionId_t actionId, MessageQueu
|
|||||||
const uint8_t* data, size_t size) {
|
const uint8_t* data, size_t size) {
|
||||||
ReturnValue_t result = returnvalue::OK;
|
ReturnValue_t result = returnvalue::OK;
|
||||||
switch (actionId) {
|
switch (actionId) {
|
||||||
case SET_LOW_RATE: {
|
|
||||||
submode = static_cast<Submode_t>(com::CcsdsSubmode::DATARATE_LOW);
|
|
||||||
result = ptmeConfig.setRate(RATE_100KBPS);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case SET_HIGH_RATE: {
|
|
||||||
submode = static_cast<Submode_t>(com::CcsdsSubmode::DATARATE_HIGH);
|
|
||||||
result = ptmeConfig.setRate(RATE_500KBPS);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case ARBITRARY_RATE: {
|
case ARBITRARY_RATE: {
|
||||||
uint32_t bitrate = 0;
|
uint32_t bitrate = 0;
|
||||||
SerializeAdapter::deSerialize(&bitrate, &data, &size, SerializeIF::Endianness::BIG);
|
SerializeAdapter::deSerialize(&bitrate, &data, &size, SerializeIF::Endianness::BIG);
|
||||||
result = ptmeConfig.setRate(bitrate);
|
result = ptmeConfig.setRate(bitrate);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case EN_TRANSMITTER: {
|
|
||||||
enableTransmit();
|
|
||||||
if (mode == HasModesIF::MODE_OFF) {
|
|
||||||
mode = HasModesIF::MODE_ON;
|
|
||||||
}
|
|
||||||
return EXECUTION_FINISHED;
|
|
||||||
}
|
|
||||||
case DISABLE_TRANSMITTER: {
|
|
||||||
disableTransmit();
|
|
||||||
if (mode == HasModesIF::MODE_ON) {
|
|
||||||
mode = HasModesIF::MODE_OFF;
|
|
||||||
}
|
|
||||||
return EXECUTION_FINISHED;
|
|
||||||
}
|
|
||||||
case ENABLE_TX_CLK_MANIPULATOR: {
|
case ENABLE_TX_CLK_MANIPULATOR: {
|
||||||
result = ptmeConfig.configTxManipulator(true);
|
result = ptmeConfig.configTxManipulator(true);
|
||||||
break;
|
break;
|
||||||
@ -206,12 +193,8 @@ ReturnValue_t CcsdsIpCoreHandler::executeAction(ActionId_t actionId, MessageQueu
|
|||||||
void CcsdsIpCoreHandler::updateLinkState() { linkState = LINK_UP; }
|
void CcsdsIpCoreHandler::updateLinkState() { linkState = LINK_UP; }
|
||||||
|
|
||||||
void CcsdsIpCoreHandler::enableTransmit() {
|
void CcsdsIpCoreHandler::enableTransmit() {
|
||||||
// Reset PTME on each transmit enable.
|
|
||||||
updateBatPriorityFromParam();
|
|
||||||
#ifndef TE0720_1CFA
|
|
||||||
gpioIF->pullHigh(ptmeGpios.enableTxClock);
|
gpioIF->pullHigh(ptmeGpios.enableTxClock);
|
||||||
gpioIF->pullHigh(ptmeGpios.enableTxData);
|
gpioIF->pullHigh(ptmeGpios.enableTxData);
|
||||||
#endif
|
|
||||||
linkState = LINK_UP;
|
linkState = LINK_UP;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,34 +219,23 @@ ReturnValue_t CcsdsIpCoreHandler::checkModeCommand(Mode_t mode, Submode_t submod
|
|||||||
}
|
}
|
||||||
|
|
||||||
void CcsdsIpCoreHandler::startTransition(Mode_t mode, Submode_t submode) {
|
void CcsdsIpCoreHandler::startTransition(Mode_t mode, Submode_t submode) {
|
||||||
auto rateSet = [&](uint32_t rate) {
|
triggerEvent(CHANGING_MODE, mode, submode);
|
||||||
ReturnValue_t result = ptmeConfig.setRate(rate);
|
|
||||||
if (result == returnvalue::OK) {
|
|
||||||
this->mode = HasModesIF::MODE_ON;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
if (mode == HasModesIF::MODE_ON) {
|
if (mode == HasModesIF::MODE_ON) {
|
||||||
|
if (this->submode != submode) {
|
||||||
|
initPtmeUpdateAfterXCycles();
|
||||||
|
updateContext.enableTransmitAfterPtmeUpdate = true;
|
||||||
|
updateContext.updateClockRate = true;
|
||||||
|
this->submode = submode;
|
||||||
|
this->mode = mode;
|
||||||
|
updateContext.setModeAfterUpdate = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// No rate change, so enable transmitter right away.
|
||||||
enableTransmit();
|
enableTransmit();
|
||||||
if (submode == static_cast<Submode_t>(com::CcsdsSubmode::DATARATE_DEFAULT)) {
|
|
||||||
com::Datarate currentDatarate = com::getCurrentDatarate();
|
|
||||||
if (currentDatarate == com::Datarate::LOW_RATE_MODULATION_BPSK) {
|
|
||||||
rateSet(RATE_100KBPS);
|
|
||||||
} else if (currentDatarate == com::Datarate::HIGH_RATE_MODULATION_0QPSK) {
|
|
||||||
rateSet(RATE_500KBPS);
|
|
||||||
}
|
|
||||||
} else if (submode == static_cast<Submode_t>(com::CcsdsSubmode::DATARATE_HIGH)) {
|
|
||||||
rateSet(RATE_500KBPS);
|
|
||||||
} else if (submode == static_cast<Submode_t>(com::CcsdsSubmode::DATARATE_LOW)) {
|
|
||||||
rateSet(RATE_100KBPS);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (mode == HasModesIF::MODE_OFF) {
|
} else if (mode == HasModesIF::MODE_OFF) {
|
||||||
disableTransmit();
|
disableTransmit();
|
||||||
this->mode = HasModesIF::MODE_OFF;
|
|
||||||
}
|
}
|
||||||
this->submode = submode;
|
setMode(mode, submode);
|
||||||
modeHelper.modeChanged(mode, submode);
|
|
||||||
announceMode(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void CcsdsIpCoreHandler::announceMode(bool recursive) { triggerEvent(MODE_INFO, mode, submode); }
|
void CcsdsIpCoreHandler::announceMode(bool recursive) { triggerEvent(MODE_INFO, mode, submode); }
|
||||||
@ -274,9 +246,9 @@ void CcsdsIpCoreHandler::disableTransmit() {
|
|||||||
gpioIF->pullLow(ptmeGpios.enableTxData);
|
gpioIF->pullLow(ptmeGpios.enableTxData);
|
||||||
#endif
|
#endif
|
||||||
linkState = LINK_DOWN;
|
linkState = LINK_DOWN;
|
||||||
if (updateBatPriorityOnTxOff) {
|
// Some parameters need update and transmitter is off now.
|
||||||
updateBatPriorityFromParam();
|
if (updateContext.updateBatPrio or updateContext.updateClockRate) {
|
||||||
updateBatPriorityOnTxOff = false;
|
initPtmeUpdateAfterXCycles();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -294,21 +266,9 @@ ModeTreeChildIF& CcsdsIpCoreHandler::getModeTreeChildIF() { return *this; }
|
|||||||
|
|
||||||
object_id_t CcsdsIpCoreHandler::getObjectId() const { return SystemObject::getObjectId(); }
|
object_id_t CcsdsIpCoreHandler::getObjectId() const { return SystemObject::getObjectId(); }
|
||||||
|
|
||||||
void CcsdsIpCoreHandler::enablePrioritySelectMode() {
|
void CcsdsIpCoreHandler::enablePrioritySelectMode() { ptmeConfig.enableBatPriorityBit(true); }
|
||||||
ptmeConfig.enableBatPriorityBit(true);
|
|
||||||
// Reset the PTME
|
|
||||||
gpioIF->pullLow(ptmeGpios.ptmeResetn);
|
|
||||||
usleep(10);
|
|
||||||
gpioIF->pullHigh(ptmeGpios.ptmeResetn);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CcsdsIpCoreHandler::disablePrioritySelectMode() {
|
void CcsdsIpCoreHandler::disablePrioritySelectMode() { ptmeConfig.enableBatPriorityBit(false); }
|
||||||
ptmeConfig.enableBatPriorityBit(false);
|
|
||||||
// Reset the PTME
|
|
||||||
gpioIF->pullLow(ptmeGpios.ptmeResetn);
|
|
||||||
usleep(10);
|
|
||||||
gpioIF->pullHigh(ptmeGpios.ptmeResetn);
|
|
||||||
}
|
|
||||||
|
|
||||||
void CcsdsIpCoreHandler::updateBatPriorityFromParam() {
|
void CcsdsIpCoreHandler::updateBatPriorityFromParam() {
|
||||||
if (batPriorityParam == 0) {
|
if (batPriorityParam == 0) {
|
||||||
@ -317,3 +277,79 @@ void CcsdsIpCoreHandler::updateBatPriorityFromParam() {
|
|||||||
enablePrioritySelectMode();
|
enablePrioritySelectMode();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void CcsdsIpCoreHandler::setMode(Mode_t mode, Submode_t submode) {
|
||||||
|
this->submode = submode;
|
||||||
|
this->mode = mode;
|
||||||
|
modeHelper.modeChanged(mode, submode);
|
||||||
|
announceMode(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CcsdsIpCoreHandler::performPtmeUpdateWhenApplicable() {
|
||||||
|
if (not updateContext.performPtmeUpdateAfterXCycles) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (updateContext.ptmeUpdateCycleCount >= 2) {
|
||||||
|
if (updateContext.updateBatPrio) {
|
||||||
|
updateBatPriorityFromParam();
|
||||||
|
updateContext.updateBatPrio = false;
|
||||||
|
}
|
||||||
|
ReturnValue_t result = returnvalue::OK;
|
||||||
|
if (updateContext.updateClockRate) {
|
||||||
|
if (submode == static_cast<Submode_t>(com::CcsdsSubmode::DATARATE_DEFAULT)) {
|
||||||
|
com::Datarate currentDatarate = com::getCurrentDatarate();
|
||||||
|
if (currentDatarate == com::Datarate::LOW_RATE_MODULATION_BPSK) {
|
||||||
|
result = ptmeConfig.setRate(RATE_100KBPS);
|
||||||
|
} else if (currentDatarate == com::Datarate::HIGH_RATE_MODULATION_0QPSK) {
|
||||||
|
result = ptmeConfig.setRate(RATE_500KBPS);
|
||||||
|
}
|
||||||
|
} else if (submode == static_cast<Submode_t>(com::CcsdsSubmode::DATARATE_HIGH)) {
|
||||||
|
result = ptmeConfig.setRate(RATE_500KBPS);
|
||||||
|
} else if (submode == static_cast<Submode_t>(com::CcsdsSubmode::DATARATE_LOW)) {
|
||||||
|
result = ptmeConfig.setRate(RATE_100KBPS);
|
||||||
|
}
|
||||||
|
if (result != returnvalue::OK) {
|
||||||
|
sif::error << "CcsdsIpCoreHandler: Setting datarate failed" << std::endl;
|
||||||
|
}
|
||||||
|
updateContext.updateClockRate = false;
|
||||||
|
}
|
||||||
|
bool doResetPtme = true;
|
||||||
|
if (not updateContext.updateBatPrio and not updateContext.updateClockRate) {
|
||||||
|
doResetPtme = false;
|
||||||
|
}
|
||||||
|
finishPtmeUpdateAfterXCycles(doResetPtme);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
updateContext.ptmeUpdateCycleCount++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void CcsdsIpCoreHandler::resetPtme() {
|
||||||
|
gpioIF->pullLow(ptmeGpios.ptmeResetn);
|
||||||
|
usleep(10);
|
||||||
|
gpioIF->pullHigh(ptmeGpios.ptmeResetn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void CcsdsIpCoreHandler::initPtmeUpdateAfterXCycles() {
|
||||||
|
if (not updateContext.performPtmeUpdateAfterXCycles) {
|
||||||
|
updateContext.performPtmeUpdateAfterXCycles = true;
|
||||||
|
updateContext.ptmeUpdateCycleCount = 0;
|
||||||
|
ptmeLocked = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void CcsdsIpCoreHandler::finishPtmeUpdateAfterXCycles(bool doResetPtme) {
|
||||||
|
if (doResetPtme) {
|
||||||
|
resetPtme();
|
||||||
|
}
|
||||||
|
ptmeLocked = false;
|
||||||
|
updateContext.performPtmeUpdateAfterXCycles = false;
|
||||||
|
updateContext.ptmeUpdateCycleCount = 0;
|
||||||
|
if (updateContext.enableTransmitAfterPtmeUpdate) {
|
||||||
|
enableTransmit();
|
||||||
|
updateContext.enableTransmitAfterPtmeUpdate = false;
|
||||||
|
}
|
||||||
|
if (updateContext.setModeAfterUpdate) {
|
||||||
|
setMode(mode, submode);
|
||||||
|
updateContext.setModeAfterUpdate = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
#define CCSDSHANDLER_H_
|
#define CCSDSHANDLER_H_
|
||||||
|
|
||||||
#include <fsfw/modes/HasModesIF.h>
|
#include <fsfw/modes/HasModesIF.h>
|
||||||
#include <mission/tmtc/VirtualChannelWithQueue.h>
|
#include <mission/com/VirtualChannelWithQueue.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
@ -79,7 +79,8 @@ class CcsdsIpCoreHandler : public SystemObject,
|
|||||||
* @param enTxData GPIO ID of RS485 tx data enable
|
* @param enTxData GPIO ID of RS485 tx data enable
|
||||||
*/
|
*/
|
||||||
CcsdsIpCoreHandler(object_id_t objectId, object_id_t tcDestination, PtmeConfig& ptmeConfig,
|
CcsdsIpCoreHandler(object_id_t objectId, object_id_t tcDestination, PtmeConfig& ptmeConfig,
|
||||||
std::atomic_bool& linkState, GpioIF* gpioIF, PtmeGpios gpioIds);
|
std::atomic_bool& linkState, GpioIF* gpioIF, PtmeGpios gpioIds,
|
||||||
|
std::atomic_bool& ptmeLocked);
|
||||||
|
|
||||||
~CcsdsIpCoreHandler();
|
~CcsdsIpCoreHandler();
|
||||||
|
|
||||||
@ -137,9 +138,8 @@ class CcsdsIpCoreHandler : public SystemObject,
|
|||||||
//! [EXPORT] : [COMMENT] Received action message with unknown action id
|
//! [EXPORT] : [COMMENT] Received action message with unknown action id
|
||||||
static const ReturnValue_t COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xA0);
|
static const ReturnValue_t COMMAND_NOT_IMPLEMENTED = MAKE_RETURN_CODE(0xA0);
|
||||||
|
|
||||||
// using VirtualChannelMap = std::unordered_map<VcId_t, VirtualChannelWithQueue*>;
|
|
||||||
// VirtualChannelMap virtualChannelMap;
|
|
||||||
std::atomic_bool& linkState;
|
std::atomic_bool& linkState;
|
||||||
|
std::atomic_bool& ptmeLocked;
|
||||||
|
|
||||||
object_id_t tcDestination;
|
object_id_t tcDestination;
|
||||||
|
|
||||||
@ -158,7 +158,15 @@ class CcsdsIpCoreHandler : public SystemObject,
|
|||||||
PtmeGpios ptmeGpios;
|
PtmeGpios ptmeGpios;
|
||||||
// BAT priority bit on by default to enable priority selection mode for the PTME.
|
// BAT priority bit on by default to enable priority selection mode for the PTME.
|
||||||
uint8_t batPriorityParam = 0;
|
uint8_t batPriorityParam = 0;
|
||||||
bool updateBatPriorityOnTxOff = false;
|
|
||||||
|
struct UpdateContext {
|
||||||
|
bool updateBatPrio = false;
|
||||||
|
bool updateClockRate = false;
|
||||||
|
bool enableTransmitAfterPtmeUpdate = false;
|
||||||
|
uint8_t ptmeUpdateCycleCount = 0;
|
||||||
|
bool performPtmeUpdateAfterXCycles = false;
|
||||||
|
bool setModeAfterUpdate = false;
|
||||||
|
} updateContext{};
|
||||||
|
|
||||||
GpioIF* gpioIF = nullptr;
|
GpioIF* gpioIF = nullptr;
|
||||||
|
|
||||||
@ -180,6 +188,8 @@ class CcsdsIpCoreHandler : public SystemObject,
|
|||||||
*/
|
*/
|
||||||
void disableTransmit();
|
void disableTransmit();
|
||||||
|
|
||||||
|
void performPtmeUpdateWhenApplicable();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The following set of functions configure the mode of the PTME bandwith allocation table (BAT)
|
* The following set of functions configure the mode of the PTME bandwith allocation table (BAT)
|
||||||
* module. This consists of the following 2 steps:
|
* module. This consists of the following 2 steps:
|
||||||
@ -189,6 +199,11 @@ class CcsdsIpCoreHandler : public SystemObject,
|
|||||||
void enablePrioritySelectMode();
|
void enablePrioritySelectMode();
|
||||||
void disablePrioritySelectMode();
|
void disablePrioritySelectMode();
|
||||||
void updateBatPriorityFromParam();
|
void updateBatPriorityFromParam();
|
||||||
|
|
||||||
|
void setMode(Mode_t mode, Submode_t submode);
|
||||||
|
void resetPtme();
|
||||||
|
void initPtmeUpdateAfterXCycles();
|
||||||
|
void finishPtmeUpdateAfterXCycles(bool doResetPtme);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* CCSDSHANDLER_H_ */
|
#endif /* CCSDSHANDLER_H_ */
|
||||||
|
107
mission/com/LiveTmTask.cpp
Normal file
107
mission/com/LiveTmTask.cpp
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
#include "LiveTmTask.h"
|
||||||
|
|
||||||
|
#include <fsfw/ipc/QueueFactory.h>
|
||||||
|
#include <fsfw/subsystem/helper.h>
|
||||||
|
#include <fsfw/tasks/TaskFactory.h>
|
||||||
|
#include <fsfw/timemanager/Stopwatch.h>
|
||||||
|
|
||||||
|
LiveTmTask::LiveTmTask(object_id_t objectId, PusTmFunnel& pusFunnel, CfdpTmFunnel& cfdpFunnel,
|
||||||
|
VirtualChannelWithQueue& channel, const std::atomic_bool& ptmeLocked)
|
||||||
|
: SystemObject(objectId),
|
||||||
|
modeHelper(this),
|
||||||
|
pusFunnel(pusFunnel),
|
||||||
|
cfdpFunnel(cfdpFunnel),
|
||||||
|
channel(channel),
|
||||||
|
ptmeLocked(ptmeLocked) {
|
||||||
|
requestQueue = QueueFactory::instance()->createMessageQueue();
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t LiveTmTask::performOperation(uint8_t opCode) {
|
||||||
|
readCommandQueue();
|
||||||
|
while (true) {
|
||||||
|
bool performWriteOp = true;
|
||||||
|
if (mode == MODE_OFF or ptmeLocked) {
|
||||||
|
performWriteOp = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// The funnel tasks are scheduled here directly as well.
|
||||||
|
ReturnValue_t result = channel.handleNextTm(performWriteOp);
|
||||||
|
if (result == DirectTmSinkIF::IS_BUSY) {
|
||||||
|
sif::error << "Lost live TM, PAPB busy" << std::endl;
|
||||||
|
}
|
||||||
|
if (result == MessageQueueIF::EMPTY) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ModeTreeChildIF& LiveTmTask::getModeTreeChildIF() { return *this; }
|
||||||
|
|
||||||
|
ReturnValue_t LiveTmTask::initialize() {
|
||||||
|
modeHelper.initialize();
|
||||||
|
return returnvalue::OK;
|
||||||
|
}
|
57
mission/com/LiveTmTask.h
Normal file
57
mission/com/LiveTmTask.h
Normal file
@ -0,0 +1,57 @@
|
|||||||
|
#ifndef MISSION_TMTC_LIVETMTASK_H_
|
||||||
|
#define MISSION_TMTC_LIVETMTASK_H_
|
||||||
|
|
||||||
|
#include <fsfw/modes/HasModesIF.h>
|
||||||
|
#include <fsfw/objectmanager/SystemObject.h>
|
||||||
|
#include <fsfw/subsystem/ModeTreeChildIF.h>
|
||||||
|
#include <fsfw/subsystem/ModeTreeConnectionIF.h>
|
||||||
|
#include <fsfw/tasks/ExecutableObjectIF.h>
|
||||||
|
#include <fsfw/timemanager/Countdown.h>
|
||||||
|
#include <mission/com/VirtualChannelWithQueue.h>
|
||||||
|
#include <mission/tmtc/CfdpTmFunnel.h>
|
||||||
|
#include <mission/tmtc/PusTmFunnel.h>
|
||||||
|
|
||||||
|
class LiveTmTask : public SystemObject,
|
||||||
|
public HasModesIF,
|
||||||
|
public ExecutableObjectIF,
|
||||||
|
public ModeTreeChildIF,
|
||||||
|
public ModeTreeConnectionIF {
|
||||||
|
public:
|
||||||
|
LiveTmTask(object_id_t objectId, PusTmFunnel& pusFunnel, CfdpTmFunnel& cfdpFunnel,
|
||||||
|
VirtualChannelWithQueue& channel, const std::atomic_bool& ptmeLocked);
|
||||||
|
|
||||||
|
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||||
|
ReturnValue_t initialize() override;
|
||||||
|
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF& parent) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
MessageQueueIF* requestQueue;
|
||||||
|
ModeHelper modeHelper;
|
||||||
|
Mode_t mode = HasModesIF::MODE_OFF;
|
||||||
|
Countdown tmFunnelCd = Countdown(100);
|
||||||
|
PusTmFunnel& pusFunnel;
|
||||||
|
CfdpTmFunnel& cfdpFunnel;
|
||||||
|
VirtualChannelWithQueue& channel;
|
||||||
|
uint32_t packetCounter = 0;
|
||||||
|
const std::atomic_bool& ptmeLocked;
|
||||||
|
|
||||||
|
void readCommandQueue(void);
|
||||||
|
|
||||||
|
MessageQueueId_t getCommandQueue() const override;
|
||||||
|
|
||||||
|
void getMode(Mode_t* mode, Submode_t* submode) override;
|
||||||
|
|
||||||
|
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||||
|
uint32_t* msToReachTheMode) override;
|
||||||
|
|
||||||
|
void startTransition(Mode_t mode, Submode_t submode) override;
|
||||||
|
|
||||||
|
void announceMode(bool recursive) override;
|
||||||
|
|
||||||
|
object_id_t getObjectId() const override;
|
||||||
|
const HasHealthIF* getOptHealthIF() const override;
|
||||||
|
const HasModesIF& getModeIF() const override;
|
||||||
|
ModeTreeChildIF& getModeTreeChildIF() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* MISSION_TMTC_LIVETMTASK_H_ */
|
@ -5,8 +5,9 @@
|
|||||||
|
|
||||||
PersistentLogTmStoreTask::PersistentLogTmStoreTask(object_id_t objectId, StorageManagerIF& ipcStore,
|
PersistentLogTmStoreTask::PersistentLogTmStoreTask(object_id_t objectId, StorageManagerIF& ipcStore,
|
||||||
LogStores stores, VirtualChannel& channel,
|
LogStores stores, VirtualChannel& channel,
|
||||||
SdCardMountedIF& sdcMan)
|
SdCardMountedIF& sdcMan,
|
||||||
: TmStoreTaskBase(objectId, ipcStore, channel, sdcMan),
|
const std::atomic_bool& ptmeLocked)
|
||||||
|
: TmStoreTaskBase(objectId, ipcStore, channel, sdcMan, ptmeLocked),
|
||||||
stores(stores),
|
stores(stores),
|
||||||
okStoreContext(persTmStore::DUMP_OK_STORE_DONE, persTmStore::DUMP_OK_CANCELLED),
|
okStoreContext(persTmStore::DUMP_OK_STORE_DONE, persTmStore::DUMP_OK_CANCELLED),
|
||||||
notOkStoreContext(persTmStore::DUMP_NOK_STORE_DONE, persTmStore::DUMP_NOK_CANCELLED),
|
notOkStoreContext(persTmStore::DUMP_NOK_STORE_DONE, persTmStore::DUMP_NOK_CANCELLED),
|
||||||
@ -27,6 +28,8 @@ ReturnValue_t PersistentLogTmStoreTask::performOperation(uint8_t opCode) {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
while (true) {
|
while (true) {
|
||||||
|
readCommandQueue();
|
||||||
|
|
||||||
if (not cyclicStoreCheck()) {
|
if (not cyclicStoreCheck()) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -54,3 +57,17 @@ bool PersistentLogTmStoreTask::initStoresIfPossible() {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PersistentLogTmStoreTask::startTransition(Mode_t mode, Submode_t submode) {
|
||||||
|
if (mode == MODE_OFF) {
|
||||||
|
bool channelIsOn = channel.isTxOn();
|
||||||
|
cancelDump(okStoreContext, stores.okStore, channelIsOn);
|
||||||
|
cancelDump(notOkStoreContext, stores.notOkStore, channelIsOn);
|
||||||
|
cancelDump(miscStoreContext, stores.miscStore, channelIsOn);
|
||||||
|
this->mode = MODE_OFF;
|
||||||
|
} else if (mode == MODE_ON) {
|
||||||
|
this->mode = MODE_ON;
|
||||||
|
}
|
||||||
|
modeHelper.modeChanged(mode, submode);
|
||||||
|
announceMode(false);
|
||||||
|
}
|
@ -5,11 +5,11 @@
|
|||||||
#include <fsfw/storagemanager/StorageManagerIF.h>
|
#include <fsfw/storagemanager/StorageManagerIF.h>
|
||||||
#include <fsfw/tasks/ExecutableObjectIF.h>
|
#include <fsfw/tasks/ExecutableObjectIF.h>
|
||||||
#include <fsfw/tmtcservices/AcceptsTelemetryIF.h>
|
#include <fsfw/tmtcservices/AcceptsTelemetryIF.h>
|
||||||
|
#include <mission/com/TmStoreTaskBase.h>
|
||||||
|
#include <mission/com/VirtualChannelWithQueue.h>
|
||||||
#include <mission/genericFactory.h>
|
#include <mission/genericFactory.h>
|
||||||
#include <mission/tmtc/PersistentTmStore.h>
|
#include <mission/tmtc/PersistentTmStore.h>
|
||||||
#include <mission/tmtc/PersistentTmStoreWithTmQueue.h>
|
#include <mission/tmtc/PersistentTmStoreWithTmQueue.h>
|
||||||
#include <mission/tmtc/TmStoreTaskBase.h>
|
|
||||||
#include <mission/tmtc/VirtualChannelWithQueue.h>
|
|
||||||
|
|
||||||
struct LogStores {
|
struct LogStores {
|
||||||
LogStores(PersistentTmStores& stores)
|
LogStores(PersistentTmStores& stores)
|
||||||
@ -22,7 +22,8 @@ struct LogStores {
|
|||||||
class PersistentLogTmStoreTask : public TmStoreTaskBase, public ExecutableObjectIF {
|
class PersistentLogTmStoreTask : public TmStoreTaskBase, public ExecutableObjectIF {
|
||||||
public:
|
public:
|
||||||
PersistentLogTmStoreTask(object_id_t objectId, StorageManagerIF& ipcStore, LogStores tmStore,
|
PersistentLogTmStoreTask(object_id_t objectId, StorageManagerIF& ipcStore, LogStores tmStore,
|
||||||
VirtualChannel& channel, SdCardMountedIF& sdcMan);
|
VirtualChannel& channel, SdCardMountedIF& sdcMan,
|
||||||
|
const std::atomic_bool& ptmeLocked);
|
||||||
|
|
||||||
ReturnValue_t performOperation(uint8_t opCode) override;
|
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||||
|
|
||||||
@ -36,6 +37,7 @@ class PersistentLogTmStoreTask : public TmStoreTaskBase, public ExecutableObject
|
|||||||
bool someFileWasSwapped = false;
|
bool someFileWasSwapped = false;
|
||||||
|
|
||||||
bool initStoresIfPossible() override;
|
bool initStoresIfPossible() override;
|
||||||
|
void startTransition(Mode_t mode, Submode_t submode) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* MISSION_TMTC_PERSISTENTLOGTMSTORETASK_H_ */
|
#endif /* MISSION_TMTC_PERSISTENTLOGTMSTORETASK_H_ */
|
@ -1,17 +1,21 @@
|
|||||||
|
#include "PersistentSingleTmStoreTask.h"
|
||||||
|
|
||||||
#include <fsfw/tasks/TaskFactory.h>
|
#include <fsfw/tasks/TaskFactory.h>
|
||||||
#include <fsfw/timemanager/Stopwatch.h>
|
#include <fsfw/timemanager/Stopwatch.h>
|
||||||
#include <mission/tmtc/PersistentSingleTmStoreTask.h>
|
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
|
||||||
PersistentSingleTmStoreTask::PersistentSingleTmStoreTask(
|
PersistentSingleTmStoreTask::PersistentSingleTmStoreTask(
|
||||||
object_id_t objectId, StorageManagerIF& ipcStore, PersistentTmStoreWithTmQueue& tmStore,
|
object_id_t objectId, StorageManagerIF& ipcStore, PersistentTmStoreWithTmQueue& tmStore,
|
||||||
VirtualChannel& channel, Event eventIfDumpDone, Event eventIfCancelled, SdCardMountedIF& sdcMan)
|
VirtualChannel& channel, Event eventIfDumpDone, Event eventIfCancelled, SdCardMountedIF& sdcMan,
|
||||||
: TmStoreTaskBase(objectId, ipcStore, channel, sdcMan),
|
const std::atomic_bool& ptmeLocked)
|
||||||
|
: TmStoreTaskBase(objectId, ipcStore, channel, sdcMan, ptmeLocked),
|
||||||
storeWithQueue(tmStore),
|
storeWithQueue(tmStore),
|
||||||
dumpContext(eventIfDumpDone, eventIfCancelled) {}
|
dumpContext(eventIfDumpDone, eventIfCancelled) {}
|
||||||
|
|
||||||
ReturnValue_t PersistentSingleTmStoreTask::performOperation(uint8_t opCode) {
|
ReturnValue_t PersistentSingleTmStoreTask::performOperation(uint8_t opCode) {
|
||||||
while (true) {
|
while (true) {
|
||||||
|
readCommandQueue();
|
||||||
|
|
||||||
// Delay done by the check
|
// Delay done by the check
|
||||||
if (not cyclicStoreCheck()) {
|
if (not cyclicStoreCheck()) {
|
||||||
continue;
|
continue;
|
||||||
@ -22,6 +26,9 @@ ReturnValue_t PersistentSingleTmStoreTask::performOperation(uint8_t opCode) {
|
|||||||
} else if (dumpContext.vcBusyDuringDump) {
|
} else if (dumpContext.vcBusyDuringDump) {
|
||||||
// TODO: Might not be necessary
|
// TODO: Might not be necessary
|
||||||
TaskFactory::delayTask(10);
|
TaskFactory::delayTask(10);
|
||||||
|
} else {
|
||||||
|
// TODO: Would be best to remove this, but not delaying here can lead to evil issues.
|
||||||
|
TaskFactory::delayTask(10);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -33,3 +40,14 @@ bool PersistentSingleTmStoreTask::initStoresIfPossible() {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PersistentSingleTmStoreTask::startTransition(Mode_t mode, Submode_t submode) {
|
||||||
|
if (mode == MODE_OFF) {
|
||||||
|
cancelDump(dumpContext, storeWithQueue, channel.isTxOn());
|
||||||
|
this->mode = MODE_OFF;
|
||||||
|
} else if (mode == MODE_ON) {
|
||||||
|
this->mode = MODE_ON;
|
||||||
|
}
|
||||||
|
modeHelper.modeChanged(mode, submode);
|
||||||
|
announceMode(false);
|
||||||
|
}
|
@ -3,16 +3,16 @@
|
|||||||
|
|
||||||
#include <fsfw/objectmanager/SystemObject.h>
|
#include <fsfw/objectmanager/SystemObject.h>
|
||||||
#include <fsfw/tasks/ExecutableObjectIF.h>
|
#include <fsfw/tasks/ExecutableObjectIF.h>
|
||||||
|
#include <mission/com/TmStoreTaskBase.h>
|
||||||
|
#include <mission/com/VirtualChannel.h>
|
||||||
#include <mission/tmtc/PersistentTmStoreWithTmQueue.h>
|
#include <mission/tmtc/PersistentTmStoreWithTmQueue.h>
|
||||||
#include <mission/tmtc/TmStoreTaskBase.h>
|
|
||||||
#include <mission/tmtc/VirtualChannel.h>
|
|
||||||
|
|
||||||
class PersistentSingleTmStoreTask : public TmStoreTaskBase, public ExecutableObjectIF {
|
class PersistentSingleTmStoreTask : public TmStoreTaskBase, public ExecutableObjectIF {
|
||||||
public:
|
public:
|
||||||
PersistentSingleTmStoreTask(object_id_t objectId, StorageManagerIF& ipcStore,
|
PersistentSingleTmStoreTask(object_id_t objectId, StorageManagerIF& ipcStore,
|
||||||
PersistentTmStoreWithTmQueue& storeWithQueue, VirtualChannel& channel,
|
PersistentTmStoreWithTmQueue& storeWithQueue, VirtualChannel& channel,
|
||||||
Event eventIfDumpDone, Event eventIfCancelled,
|
Event eventIfDumpDone, Event eventIfCancelled,
|
||||||
SdCardMountedIF& sdcMan);
|
SdCardMountedIF& sdcMan, const std::atomic_bool& ptmeLocked);
|
||||||
|
|
||||||
ReturnValue_t performOperation(uint8_t opCode) override;
|
ReturnValue_t performOperation(uint8_t opCode) override;
|
||||||
|
|
||||||
@ -23,6 +23,8 @@ class PersistentSingleTmStoreTask : public TmStoreTaskBase, public ExecutableObj
|
|||||||
Countdown graceDelayDuringDumping = Countdown(100);
|
Countdown graceDelayDuringDumping = Countdown(100);
|
||||||
|
|
||||||
bool initStoresIfPossible() override;
|
bool initStoresIfPossible() override;
|
||||||
|
|
||||||
|
void startTransition(Mode_t mode, Submode_t submode) override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* MISSION_TMTC_PERSISTENTSINGLETMSTORETASK_H_ */
|
#endif /* MISSION_TMTC_PERSISTENTSINGLETMSTORETASK_H_ */
|
@ -21,6 +21,7 @@ SyrlinksHandler::~SyrlinksHandler() = default;
|
|||||||
|
|
||||||
void SyrlinksHandler::doStartUp() {
|
void SyrlinksHandler::doStartUp() {
|
||||||
if (internalState == InternalState::OFF) {
|
if (internalState == InternalState::OFF) {
|
||||||
|
transitionCommandPending = false;
|
||||||
internalState = InternalState::ENABLE_TEMPERATURE_PROTECTION;
|
internalState = InternalState::ENABLE_TEMPERATURE_PROTECTION;
|
||||||
commandExecuted = false;
|
commandExecuted = false;
|
||||||
}
|
}
|
||||||
@ -38,6 +39,7 @@ void SyrlinksHandler::doShutDown() {
|
|||||||
// In any case, always disable TX first.
|
// In any case, always disable TX first.
|
||||||
if (internalState != InternalState::SET_TX_STANDBY) {
|
if (internalState != InternalState::SET_TX_STANDBY) {
|
||||||
internalState = InternalState::SET_TX_STANDBY;
|
internalState = InternalState::SET_TX_STANDBY;
|
||||||
|
transitionCommandPending = false;
|
||||||
commandExecuted = false;
|
commandExecuted = false;
|
||||||
}
|
}
|
||||||
if (internalState == InternalState::SET_TX_STANDBY) {
|
if (internalState == InternalState::SET_TX_STANDBY) {
|
||||||
@ -122,9 +124,10 @@ ReturnValue_t SyrlinksHandler::buildTransitionDeviceCommand(DeviceCommandId_t* i
|
|||||||
*id = syrlinks::SET_TX_MODE_STANDBY;
|
*id = syrlinks::SET_TX_MODE_STANDBY;
|
||||||
return buildCommandFromCommand(*id, nullptr, 0);
|
return buildCommandFromCommand(*id, nullptr, 0);
|
||||||
}
|
}
|
||||||
default:
|
default: {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
return NOTHING_TO_SEND;
|
return NOTHING_TO_SEND;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -442,7 +445,6 @@ ReturnValue_t SyrlinksHandler::interpretDeviceReply(DeviceCommandId_t id, const
|
|||||||
return DeviceHandlerIF::UNKNOWN_DEVICE_REPLY;
|
return DeviceHandlerIF::UNKNOWN_DEVICE_REPLY;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -682,6 +684,9 @@ ReturnValue_t SyrlinksHandler::handleAckReply(const uint8_t* packet) {
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
default: {
|
||||||
|
sif::error << "Syrlinks: Unexpected ACK reply" << std::endl;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
switch (rememberCommandId) {
|
switch (rememberCommandId) {
|
||||||
case (syrlinks::SET_TX_MODE_STANDBY): {
|
case (syrlinks::SET_TX_MODE_STANDBY): {
|
||||||
@ -728,16 +733,19 @@ void SyrlinksHandler::doTransition(Mode_t modeFrom, Submode_t subModeFrom) {
|
|||||||
Mode_t tgtMode = getBaseMode(getMode());
|
Mode_t tgtMode = getBaseMode(getMode());
|
||||||
auto commandDone = [&]() {
|
auto commandDone = [&]() {
|
||||||
setMode(tgtMode);
|
setMode(tgtMode);
|
||||||
|
transitionCommandPending = false;
|
||||||
internalState = InternalState::IDLE;
|
internalState = InternalState::IDLE;
|
||||||
};
|
};
|
||||||
auto txOnHandler = [&](InternalState selMod) {
|
auto txOnHandler = [&](InternalState selMod) {
|
||||||
if (internalState == InternalState::IDLE) {
|
if (internalState == InternalState::IDLE) {
|
||||||
|
transitionCommandPending = false;
|
||||||
commandExecuted = false;
|
commandExecuted = false;
|
||||||
internalState = selMod;
|
internalState = selMod;
|
||||||
}
|
}
|
||||||
// Select modulation first (BPSK or 0QPSK).
|
// Select modulation first (BPSK or 0QPSK).
|
||||||
if (internalState == selMod) {
|
if (internalState == selMod) {
|
||||||
if (commandExecuted) {
|
if (commandExecuted) {
|
||||||
|
transitionCommandPending = false;
|
||||||
internalState = InternalState::SET_TX_MODULATION;
|
internalState = InternalState::SET_TX_MODULATION;
|
||||||
commandExecuted = false;
|
commandExecuted = false;
|
||||||
}
|
}
|
||||||
@ -753,6 +761,7 @@ void SyrlinksHandler::doTransition(Mode_t modeFrom, Submode_t subModeFrom) {
|
|||||||
};
|
};
|
||||||
auto txStandbyHandler = [&]() {
|
auto txStandbyHandler = [&]() {
|
||||||
if (internalState == InternalState::IDLE) {
|
if (internalState == InternalState::IDLE) {
|
||||||
|
transitionCommandPending = false;
|
||||||
internalState = InternalState::SET_TX_STANDBY;
|
internalState = InternalState::SET_TX_STANDBY;
|
||||||
commandExecuted = false;
|
commandExecuted = false;
|
||||||
}
|
}
|
||||||
|
@ -112,6 +112,7 @@ class SyrlinksHandler : public DeviceHandlerBase {
|
|||||||
float tempPowerAmplifier = 0;
|
float tempPowerAmplifier = 0;
|
||||||
float tempBasebandBoard = 0;
|
float tempBasebandBoard = 0;
|
||||||
bool commandExecuted = false;
|
bool commandExecuted = false;
|
||||||
|
bool transitionCommandPending = false;
|
||||||
|
|
||||||
uint8_t commandBuffer[syrlinks::MAX_COMMAND_SIZE];
|
uint8_t commandBuffer[syrlinks::MAX_COMMAND_SIZE];
|
||||||
|
|
||||||
|
228
mission/com/TmStoreTaskBase.cpp
Normal file
228
mission/com/TmStoreTaskBase.cpp
Normal file
@ -0,0 +1,228 @@
|
|||||||
|
#include "TmStoreTaskBase.h"
|
||||||
|
|
||||||
|
#include <fsfw/ipc/CommandMessageIF.h>
|
||||||
|
#include <fsfw/ipc/QueueFactory.h>
|
||||||
|
#include <fsfw/subsystem/helper.h>
|
||||||
|
#include <fsfw/tasks/TaskFactory.h>
|
||||||
|
#include <fsfw/timemanager/Stopwatch.h>
|
||||||
|
#include <fsfw/tmstorage/TmStoreMessage.h>
|
||||||
|
|
||||||
|
#include "mission/persistentTmStoreDefs.h"
|
||||||
|
|
||||||
|
TmStoreTaskBase::TmStoreTaskBase(object_id_t objectId, StorageManagerIF& ipcStore,
|
||||||
|
VirtualChannel& channel, SdCardMountedIF& sdcMan,
|
||||||
|
const std::atomic_bool& ptmeLocked)
|
||||||
|
: SystemObject(objectId),
|
||||||
|
modeHelper(this),
|
||||||
|
ipcStore(ipcStore),
|
||||||
|
tmReader(&timeReader),
|
||||||
|
channel(channel),
|
||||||
|
sdcMan(sdcMan),
|
||||||
|
ptmeLocked(ptmeLocked) {
|
||||||
|
requestQueue = QueueFactory::instance()->createMessageQueue(10);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TmStoreTaskBase::handleOneStore(PersistentTmStoreWithTmQueue& store,
|
||||||
|
DumpContext& dumpContext) {
|
||||||
|
ReturnValue_t result;
|
||||||
|
bool tmToStoreReceived = false;
|
||||||
|
bool tcRequestReceived = false;
|
||||||
|
bool dumpPerformed = false;
|
||||||
|
fileHasSwapped = false;
|
||||||
|
dumpContext.packetWasDumped = false;
|
||||||
|
dumpContext.vcBusyDuringDump = false;
|
||||||
|
|
||||||
|
// Store TM persistently
|
||||||
|
result = store.handleNextTm();
|
||||||
|
if (result == returnvalue::OK) {
|
||||||
|
tmToStoreReceived = true;
|
||||||
|
}
|
||||||
|
// Dump TMs
|
||||||
|
if (store.getState() == PersistentTmStore::State::DUMPING) {
|
||||||
|
if (handleOneDump(store, dumpContext, dumpPerformed) != returnvalue::OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Command_t execCmd;
|
||||||
|
// Handle TC requests, for example deletion or retrieval requests.
|
||||||
|
result = store.handleCommandQueue(ipcStore, execCmd);
|
||||||
|
if (result == returnvalue::OK) {
|
||||||
|
if (execCmd == TmStoreMessage::DOWNLINK_STORE_CONTENT_TIME) {
|
||||||
|
cancelDumpCd.resetTimer();
|
||||||
|
tmSinkBusyCd.resetTimer();
|
||||||
|
dumpContext.reset();
|
||||||
|
}
|
||||||
|
tcRequestReceived = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (tcRequestReceived or tmToStoreReceived or dumpPerformed) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool TmStoreTaskBase::cyclicStoreCheck() {
|
||||||
|
if (not storesInitialized) {
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TmStoreTaskBase::cancelDump(DumpContext& ctx, PersistentTmStore& store, bool isTxOn) {
|
||||||
|
ctx.reset();
|
||||||
|
if (store.getState() == PersistentTmStore::State::DUMPING) {
|
||||||
|
triggerEvent(ctx.eventIfCancelled, ctx.numberOfDumpedPackets, ctx.dumpedBytes);
|
||||||
|
}
|
||||||
|
store.cancelDump();
|
||||||
|
if (isTxOn) {
|
||||||
|
channel.cancelTransfer();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t TmStoreTaskBase::handleOneDump(PersistentTmStoreWithTmQueue& store,
|
||||||
|
DumpContext& dumpContext, bool& dumpPerformed) {
|
||||||
|
ReturnValue_t result = returnvalue::OK;
|
||||||
|
// The PTME might have been reset an transmitter state change, so there is no point in continuing
|
||||||
|
// the dump.
|
||||||
|
// TODO: Will be solved in a cleaner way, this is kind of a hack.
|
||||||
|
if (not channel.isTxOn()) {
|
||||||
|
cancelDump(dumpContext, store, false);
|
||||||
|
return returnvalue::FAILED;
|
||||||
|
}
|
||||||
|
// 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) {
|
||||||
|
performDump(store, dumpContext, dumpPerformed);
|
||||||
|
} 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.
|
||||||
|
sif::warning << "PTME busy for longer period. Cancelling dump" << std::endl;
|
||||||
|
cancelDump(dumpContext, store, channel.isTxOn());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cancelDumpCd.hasTimedOut() or tmSinkBusyCd.hasTimedOut()) {
|
||||||
|
cancelDump(dumpContext, store, channel.isTxOn());
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t TmStoreTaskBase::performDump(PersistentTmStoreWithTmQueue& store,
|
||||||
|
DumpContext& dumpContext, bool& dumpPerformed) {
|
||||||
|
size_t dumpedLen = 0;
|
||||||
|
|
||||||
|
auto dumpDoneHandler = [&]() {
|
||||||
|
uint32_t startTime;
|
||||||
|
uint32_t endTime;
|
||||||
|
store.getStartAndEndTimeCurrentOrLastDump(startTime, endTime);
|
||||||
|
triggerEvent(dumpContext.eventIfDone, dumpContext.numberOfDumpedPackets,
|
||||||
|
dumpContext.dumpedBytes);
|
||||||
|
dumpContext.reset();
|
||||||
|
};
|
||||||
|
// Dump the next packet into the PTME.
|
||||||
|
dumpContext.ptmeBusyCounter = 0;
|
||||||
|
tmSinkBusyCd.resetTimer();
|
||||||
|
ReturnValue_t result = store.getNextDumpPacket(tmReader, fileHasSwapped);
|
||||||
|
if (result != returnvalue::OK) {
|
||||||
|
sif::error << "PersistentTmStore: Getting next dump packet failed" << std::endl;
|
||||||
|
} else if (fileHasSwapped or result == PersistentTmStore::DUMP_DONE) {
|
||||||
|
// This can happen if a file is corrupted and the next file swap completes the dump.
|
||||||
|
dumpDoneHandler();
|
||||||
|
return returnvalue::OK;
|
||||||
|
}
|
||||||
|
dumpedLen = tmReader.getFullPacketLen();
|
||||||
|
// Only write to VC if mode is on, but always confirm the dump.
|
||||||
|
// If the mode is OFF, it is assumed the PTME is not usable and is not allowed to be written
|
||||||
|
// (e.g. to confirm a reset or the transmitter is off anyway).
|
||||||
|
if (mode == MODE_ON) {
|
||||||
|
result = channel.write(tmReader.getFullData(), dumpedLen);
|
||||||
|
if (result == DirectTmSinkIF::IS_BUSY) {
|
||||||
|
sif::warning << "PersistentTmStore: Unexpected VC channel busy" << std::endl;
|
||||||
|
} else if (result != returnvalue::OK) {
|
||||||
|
sif::warning << "PersistentTmStore: Unexpected VC channel write failure" << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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) {
|
||||||
|
dumpDoneHandler();
|
||||||
|
}
|
||||||
|
return returnvalue::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
|
ModeTreeChildIF& TmStoreTaskBase::getModeTreeChildIF() { return *this; }
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
@ -1,15 +1,22 @@
|
|||||||
#ifndef MISSION_TMTC_TMSTORETASKBASE_H_
|
#ifndef MISSION_TMTC_TMSTORETASKBASE_H_
|
||||||
#define MISSION_TMTC_TMSTORETASKBASE_H_
|
#define MISSION_TMTC_TMSTORETASKBASE_H_
|
||||||
|
|
||||||
|
#include <fsfw/modes/HasModesIF.h>
|
||||||
|
#include <fsfw/subsystem/ModeTreeChildIF.h>
|
||||||
|
#include <fsfw/subsystem/ModeTreeConnectionIF.h>
|
||||||
|
#include <fsfw/timemanager/CdsShortTimeStamper.h>
|
||||||
#include <fsfw/timemanager/Countdown.h>
|
#include <fsfw/timemanager/Countdown.h>
|
||||||
|
#include <mission/com/VirtualChannel.h>
|
||||||
#include <mission/tmtc/PersistentTmStoreWithTmQueue.h>
|
#include <mission/tmtc/PersistentTmStoreWithTmQueue.h>
|
||||||
#include <mission/tmtc/VirtualChannel.h>
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Generic class which composes a Virtual Channel and a persistent TM stores. This allows dumping
|
* Generic class which composes a Virtual Channel and a persistent TM stores. This allows dumping
|
||||||
* the TM store into the virtual channel directly.
|
* the TM store into the virtual channel directly.
|
||||||
*/
|
*/
|
||||||
class TmStoreTaskBase : public SystemObject {
|
class TmStoreTaskBase : public SystemObject,
|
||||||
|
public HasModesIF,
|
||||||
|
public ModeTreeChildIF,
|
||||||
|
public ModeTreeConnectionIF {
|
||||||
public:
|
public:
|
||||||
struct DumpContext {
|
struct DumpContext {
|
||||||
DumpContext(Event eventIfDone, Event eventIfCancelled)
|
DumpContext(Event eventIfDone, Event eventIfCancelled)
|
||||||
@ -33,19 +40,35 @@ class TmStoreTaskBase : public SystemObject {
|
|||||||
};
|
};
|
||||||
|
|
||||||
TmStoreTaskBase(object_id_t objectId, StorageManagerIF& ipcStore, VirtualChannel& channel,
|
TmStoreTaskBase(object_id_t objectId, StorageManagerIF& ipcStore, VirtualChannel& channel,
|
||||||
SdCardMountedIF& sdcMan);
|
SdCardMountedIF& sdcMan, const std::atomic_bool& ptmeLocked);
|
||||||
|
|
||||||
|
ReturnValue_t initialize() override;
|
||||||
|
ReturnValue_t connectModeTreeParent(HasModeTreeChildrenIF& parent) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
|
ModeHelper modeHelper;
|
||||||
|
MessageQueueIF* requestQueue;
|
||||||
StorageManagerIF& ipcStore;
|
StorageManagerIF& ipcStore;
|
||||||
|
PusTmReader tmReader;
|
||||||
|
CdsShortTimeStamper timeReader;
|
||||||
|
VirtualChannel& channel;
|
||||||
|
SdCardMountedIF& sdcMan;
|
||||||
|
const std::atomic_bool& ptmeLocked;
|
||||||
|
|
||||||
|
Mode_t mode = HasModesIF::MODE_OFF;
|
||||||
Countdown sdCardCheckCd = Countdown(800);
|
Countdown sdCardCheckCd = Countdown(800);
|
||||||
// 20 minutes are allowed as maximum dump time.
|
// 20 minutes are allowed as maximum dump time.
|
||||||
Countdown cancelDumpCd = Countdown(60 * 20 * 1000);
|
Countdown cancelDumpCd = Countdown(60 * 20 * 1000);
|
||||||
// If the TM sink is busy for 1 minute for whatever reason, cancel the dump.
|
// If the TM sink is busy for 1 minute for whatever reason, cancel the dump.
|
||||||
Countdown tmSinkBusyCd = Countdown(60 * 1000);
|
Countdown tmSinkBusyCd = Countdown(60 * 1000);
|
||||||
VirtualChannel& channel;
|
|
||||||
bool storesInitialized = false;
|
bool storesInitialized = false;
|
||||||
bool fileHasSwapped = false;
|
bool fileHasSwapped = false;
|
||||||
SdCardMountedIF& sdcMan;
|
|
||||||
|
void readCommandQueue(void);
|
||||||
|
|
||||||
|
virtual bool initStoresIfPossible() = 0;
|
||||||
|
virtual void startTransition(Mode_t mode, Submode_t submode) = 0;
|
||||||
|
|
||||||
void cancelDump(DumpContext& ctx, PersistentTmStore& store, bool isTxOn);
|
void cancelDump(DumpContext& ctx, PersistentTmStore& store, bool isTxOn);
|
||||||
/**
|
/**
|
||||||
@ -58,6 +81,8 @@ class TmStoreTaskBase : public SystemObject {
|
|||||||
|
|
||||||
ReturnValue_t handleOneDump(PersistentTmStoreWithTmQueue& store, DumpContext& dumpContext,
|
ReturnValue_t handleOneDump(PersistentTmStoreWithTmQueue& store, DumpContext& dumpContext,
|
||||||
bool& dumpPerformed);
|
bool& dumpPerformed);
|
||||||
|
ReturnValue_t performDump(PersistentTmStoreWithTmQueue& store, DumpContext& dumpContext,
|
||||||
|
bool& dumpPerformed);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Occasionally check whether SD card is okay to be used. If not, poll whether it is ready to
|
* Occasionally check whether SD card is okay to be used. If not, poll whether it is ready to
|
||||||
@ -65,7 +90,17 @@ class TmStoreTaskBase : public SystemObject {
|
|||||||
*/
|
*/
|
||||||
bool cyclicStoreCheck();
|
bool cyclicStoreCheck();
|
||||||
|
|
||||||
virtual bool initStoresIfPossible() = 0;
|
MessageQueueId_t getCommandQueue() const override;
|
||||||
|
|
||||||
|
void getMode(Mode_t* mode, Submode_t* submode) override;
|
||||||
|
|
||||||
|
ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode,
|
||||||
|
uint32_t* msToReachTheMode) override;
|
||||||
|
void announceMode(bool recursive) override;
|
||||||
|
object_id_t getObjectId() const override;
|
||||||
|
const HasHealthIF* getOptHealthIF() const override;
|
||||||
|
const HasModesIF& getModeIF() const override;
|
||||||
|
ModeTreeChildIF& getModeTreeChildIF() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* MISSION_TMTC_TMSTORETASKBASE_H_ */
|
#endif /* MISSION_TMTC_TMSTORETASKBASE_H_ */
|
@ -1,4 +1,4 @@
|
|||||||
#include <mission/tmtc/VirtualChannelWithQueue.h>
|
#include "VirtualChannelWithQueue.h"
|
||||||
|
|
||||||
#include "OBSWConfig.h"
|
#include "OBSWConfig.h"
|
||||||
#include "fsfw/ipc/QueueFactory.h"
|
#include "fsfw/ipc/QueueFactory.h"
|
||||||
@ -19,7 +19,7 @@ VirtualChannelWithQueue::VirtualChannelWithQueue(object_id_t objectId, uint8_t v
|
|||||||
|
|
||||||
const char* VirtualChannelWithQueue::getName() const { return VirtualChannel::getName(); }
|
const char* VirtualChannelWithQueue::getName() const { return VirtualChannel::getName(); }
|
||||||
|
|
||||||
ReturnValue_t VirtualChannelWithQueue::sendNextTm() {
|
ReturnValue_t VirtualChannelWithQueue::handleNextTm(bool performWriteOp) {
|
||||||
TmTcMessage message;
|
TmTcMessage message;
|
||||||
ReturnValue_t result = tmQueue->receiveMessage(&message);
|
ReturnValue_t result = tmQueue->receiveMessage(&message);
|
||||||
if (result == MessageQueueIF::EMPTY) {
|
if (result == MessageQueueIF::EMPTY) {
|
||||||
@ -36,7 +36,9 @@ ReturnValue_t VirtualChannelWithQueue::sendNextTm() {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (performWriteOp) {
|
||||||
result = write(data, size);
|
result = write(data, size);
|
||||||
|
}
|
||||||
// Try delete in any case, ignore failures (which should not happen), it is more important to
|
// Try delete in any case, ignore failures (which should not happen), it is more important to
|
||||||
// propagate write errors.
|
// propagate write errors.
|
||||||
tmStore.deleteData(storeId);
|
tmStore.deleteData(storeId);
|
@ -4,7 +4,7 @@
|
|||||||
#include <fsfw/objectmanager/SystemObject.h>
|
#include <fsfw/objectmanager/SystemObject.h>
|
||||||
#include <fsfw/tasks/ExecutableObjectIF.h>
|
#include <fsfw/tasks/ExecutableObjectIF.h>
|
||||||
#include <linux/ipcore/PtmeIF.h>
|
#include <linux/ipcore/PtmeIF.h>
|
||||||
#include <mission/tmtc/VirtualChannel.h>
|
#include <mission/com/VirtualChannel.h>
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
|
||||||
@ -34,7 +34,7 @@ class VirtualChannelWithQueue : public VirtualChannel, public AcceptsTelemetryIF
|
|||||||
|
|
||||||
MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel = 0) const override;
|
MessageQueueId_t getReportReceptionQueue(uint8_t virtualChannel = 0) const override;
|
||||||
[[nodiscard]] const char* getName() const override;
|
[[nodiscard]] const char* getName() const override;
|
||||||
ReturnValue_t sendNextTm();
|
ReturnValue_t handleNextTm(bool performWriteOp);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MessageQueueIF* tmQueue = nullptr;
|
MessageQueueIF* tmQueue = nullptr;
|
@ -3,6 +3,8 @@
|
|||||||
#include <fsfw/ipc/MutexFactory.h>
|
#include <fsfw/ipc/MutexFactory.h>
|
||||||
#include <fsfw/ipc/MutexGuard.h>
|
#include <fsfw/ipc/MutexGuard.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
com::Datarate DATARATE_CFG_RAW = com::Datarate::LOW_RATE_MODULATION_BPSK;
|
com::Datarate DATARATE_CFG_RAW = com::Datarate::LOW_RATE_MODULATION_BPSK;
|
||||||
MutexIF* DATARATE_LOCK = nullptr;
|
MutexIF* DATARATE_LOCK = nullptr;
|
||||||
|
|
||||||
|
@ -26,10 +26,12 @@ ReturnValue_t pst::pstSyrlinks(FixedTimeslotTaskIF *thisSequence) {
|
|||||||
thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0, DeviceHandlerIF::GET_WRITE);
|
thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0, DeviceHandlerIF::GET_WRITE);
|
||||||
thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.25, DeviceHandlerIF::SEND_READ);
|
thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.25, DeviceHandlerIF::SEND_READ);
|
||||||
thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.25, DeviceHandlerIF::GET_READ);
|
thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.25, DeviceHandlerIF::GET_READ);
|
||||||
|
thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.4,
|
||||||
|
DeviceHandlerIF::PERFORM_OPERATION);
|
||||||
thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.4, DeviceHandlerIF::SEND_WRITE);
|
thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.4, DeviceHandlerIF::SEND_WRITE);
|
||||||
thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.4, DeviceHandlerIF::GET_WRITE);
|
thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.4, DeviceHandlerIF::GET_WRITE);
|
||||||
thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.7, DeviceHandlerIF::SEND_READ);
|
thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.75, DeviceHandlerIF::SEND_READ);
|
||||||
thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.7, DeviceHandlerIF::GET_READ);
|
thisSequence->addSlot(objects::SYRLINKS_HANDLER, length * 0.75, DeviceHandlerIF::GET_READ);
|
||||||
|
|
||||||
static_cast<void>(length);
|
static_cast<void>(length);
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ auto COM_SEQUENCE_RX_ONLY =
|
|||||||
auto COM_TABLE_RX_ONLY_TGT = std::make_pair(
|
auto COM_TABLE_RX_ONLY_TGT = std::make_pair(
|
||||||
static_cast<uint32_t>(::com::Submode::RX_ONLY << 24) | 1, FixedArrayList<ModeListEntry, 3>());
|
static_cast<uint32_t>(::com::Submode::RX_ONLY << 24) | 1, FixedArrayList<ModeListEntry, 3>());
|
||||||
auto COM_TABLE_RX_ONLY_TRANS_0 = std::make_pair(
|
auto COM_TABLE_RX_ONLY_TRANS_0 = std::make_pair(
|
||||||
static_cast<uint32_t>(::com::Submode::RX_ONLY << 24) | 2, FixedArrayList<ModeListEntry, 3>());
|
static_cast<uint32_t>(::com::Submode::RX_ONLY << 24) | 2, FixedArrayList<ModeListEntry, 6>());
|
||||||
auto COM_TABLE_RX_ONLY_TRANS_1 = std::make_pair(
|
auto COM_TABLE_RX_ONLY_TRANS_1 = std::make_pair(
|
||||||
static_cast<uint32_t>(::com::Submode::RX_ONLY << 24) | 3, FixedArrayList<ModeListEntry, 3>());
|
static_cast<uint32_t>(::com::Submode::RX_ONLY << 24) | 3, FixedArrayList<ModeListEntry, 3>());
|
||||||
|
|
||||||
@ -36,7 +36,7 @@ auto COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_0 =
|
|||||||
FixedArrayList<ModeListEntry, 3>());
|
FixedArrayList<ModeListEntry, 3>());
|
||||||
auto COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1 =
|
auto COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1 =
|
||||||
std::make_pair(static_cast<uint32_t>(::com::Submode::RX_AND_TX_LOW_DATARATE << 24) | 3,
|
std::make_pair(static_cast<uint32_t>(::com::Submode::RX_AND_TX_LOW_DATARATE << 24) | 3,
|
||||||
FixedArrayList<ModeListEntry, 3>());
|
FixedArrayList<ModeListEntry, 6>());
|
||||||
|
|
||||||
auto COM_SEQUENCE_RX_AND_TX_HIGH_RATE =
|
auto COM_SEQUENCE_RX_AND_TX_HIGH_RATE =
|
||||||
std::make_pair(::com::Submode::RX_AND_TX_HIGH_DATARATE, FixedArrayList<ModeListEntry, 3>());
|
std::make_pair(::com::Submode::RX_AND_TX_HIGH_DATARATE, FixedArrayList<ModeListEntry, 3>());
|
||||||
@ -48,7 +48,7 @@ auto COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_0 =
|
|||||||
FixedArrayList<ModeListEntry, 3>());
|
FixedArrayList<ModeListEntry, 3>());
|
||||||
auto COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1 =
|
auto COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1 =
|
||||||
std::make_pair(static_cast<uint32_t>(::com::Submode::RX_AND_TX_HIGH_DATARATE << 24) | 3,
|
std::make_pair(static_cast<uint32_t>(::com::Submode::RX_AND_TX_HIGH_DATARATE << 24) | 3,
|
||||||
FixedArrayList<ModeListEntry, 3>());
|
FixedArrayList<ModeListEntry, 6>());
|
||||||
|
|
||||||
auto COM_SEQUENCE_RX_AND_TX_DEFAULT_RATE =
|
auto COM_SEQUENCE_RX_AND_TX_DEFAULT_RATE =
|
||||||
std::make_pair(::com::Submode::RX_AND_TX_DEFAULT_DATARATE, FixedArrayList<ModeListEntry, 3>());
|
std::make_pair(::com::Submode::RX_AND_TX_DEFAULT_DATARATE, FixedArrayList<ModeListEntry, 3>());
|
||||||
@ -60,7 +60,7 @@ auto COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_0 =
|
|||||||
FixedArrayList<ModeListEntry, 3>());
|
FixedArrayList<ModeListEntry, 3>());
|
||||||
auto COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1 =
|
auto COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1 =
|
||||||
std::make_pair(static_cast<uint32_t>(::com::Submode::RX_AND_TX_DEFAULT_DATARATE << 24) | 3,
|
std::make_pair(static_cast<uint32_t>(::com::Submode::RX_AND_TX_DEFAULT_DATARATE << 24) | 3,
|
||||||
FixedArrayList<ModeListEntry, 3>());
|
FixedArrayList<ModeListEntry, 6>());
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
@ -110,6 +110,10 @@ void buildRxOnlySequence(Subsystem& ss, ModeListEntry& eh) {
|
|||||||
|
|
||||||
// Build RX Only transition 0
|
// Build RX Only transition 0
|
||||||
iht(objects::SYRLINKS_ASSY, NML, ::com::Submode::RX_ONLY, COM_TABLE_RX_ONLY_TRANS_0.second);
|
iht(objects::SYRLINKS_ASSY, NML, ::com::Submode::RX_ONLY, COM_TABLE_RX_ONLY_TRANS_0.second);
|
||||||
|
iht(objects::LOG_STORE_AND_TM_TASK, OFF, 0, COM_TABLE_RX_ONLY_TRANS_0.second);
|
||||||
|
iht(objects::HK_STORE_AND_TM_TASK, OFF, 0, COM_TABLE_RX_ONLY_TRANS_0.second);
|
||||||
|
iht(objects::CFDP_STORE_AND_TM_TASK, OFF, 0, COM_TABLE_RX_ONLY_TRANS_0.second);
|
||||||
|
iht(objects::LIVE_TM_TASK, OFF, 0, COM_TABLE_RX_ONLY_TRANS_0.second);
|
||||||
check(ss.addTable(TableEntry(COM_TABLE_RX_ONLY_TRANS_0.first, &COM_TABLE_RX_ONLY_TRANS_0.second)),
|
check(ss.addTable(TableEntry(COM_TABLE_RX_ONLY_TRANS_0.first, &COM_TABLE_RX_ONLY_TRANS_0.second)),
|
||||||
ctxc);
|
ctxc);
|
||||||
|
|
||||||
@ -165,6 +169,10 @@ void buildTxAndRxLowRateSequence(Subsystem& ss, ModeListEntry& eh) {
|
|||||||
// Build TX and RX low transition 1
|
// Build TX and RX low transition 1
|
||||||
iht(objects::SYRLINKS_ASSY, NML, ::com::Submode::RX_AND_TX_LOW_DATARATE,
|
iht(objects::SYRLINKS_ASSY, NML, ::com::Submode::RX_AND_TX_LOW_DATARATE,
|
||||||
COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.second);
|
COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.second);
|
||||||
|
iht(objects::LOG_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.second);
|
||||||
|
iht(objects::HK_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.second);
|
||||||
|
iht(objects::CFDP_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.second);
|
||||||
|
iht(objects::LIVE_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.second);
|
||||||
check(ss.addTable(TableEntry(COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.first,
|
check(ss.addTable(TableEntry(COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.first,
|
||||||
&COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.second)),
|
&COM_TABLE_RX_AND_TX_LOW_RATE_TRANS_1.second)),
|
||||||
ctxc);
|
ctxc);
|
||||||
@ -217,6 +225,10 @@ void buildTxAndRxHighRateSequence(Subsystem& ss, ModeListEntry& eh) {
|
|||||||
// Build TX and RX high transition 1
|
// Build TX and RX high transition 1
|
||||||
iht(objects::SYRLINKS_ASSY, NML, ::com::Submode::RX_AND_TX_HIGH_DATARATE,
|
iht(objects::SYRLINKS_ASSY, NML, ::com::Submode::RX_AND_TX_HIGH_DATARATE,
|
||||||
COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.second);
|
COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.second);
|
||||||
|
iht(objects::LOG_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.second);
|
||||||
|
iht(objects::HK_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.second);
|
||||||
|
iht(objects::CFDP_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.second);
|
||||||
|
iht(objects::LIVE_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.second);
|
||||||
check(ss.addTable(TableEntry(COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.first,
|
check(ss.addTable(TableEntry(COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.first,
|
||||||
&COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.second)),
|
&COM_TABLE_RX_AND_TX_HIGH_RATE_TRANS_1.second)),
|
||||||
ctxc);
|
ctxc);
|
||||||
@ -271,6 +283,10 @@ void buildTxAndRxDefaultRateSequence(Subsystem& ss, ModeListEntry& eh) {
|
|||||||
// Build TX and RX default transition 1
|
// Build TX and RX default transition 1
|
||||||
iht(objects::SYRLINKS_ASSY, NML, ::com::Submode::RX_AND_TX_DEFAULT_DATARATE,
|
iht(objects::SYRLINKS_ASSY, NML, ::com::Submode::RX_AND_TX_DEFAULT_DATARATE,
|
||||||
COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.second);
|
COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.second);
|
||||||
|
iht(objects::LOG_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.second);
|
||||||
|
iht(objects::HK_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.second);
|
||||||
|
iht(objects::CFDP_STORE_AND_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.second);
|
||||||
|
iht(objects::LIVE_TM_TASK, ON, 0, COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.second);
|
||||||
check(ss.addTable(TableEntry(COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.first,
|
check(ss.addTable(TableEntry(COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.first,
|
||||||
&COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.second)),
|
&COM_TABLE_RX_AND_TX_DEFAULT_RATE_TRANS_1.second)),
|
||||||
ctxc);
|
ctxc);
|
||||||
|
@ -1,17 +1,11 @@
|
|||||||
target_sources(
|
target_sources(
|
||||||
${LIB_EIVE_MISSION}
|
${LIB_EIVE_MISSION}
|
||||||
PRIVATE VirtualChannelWithQueue.cpp
|
PRIVATE PersistentTmStoreWithTmQueue.cpp
|
||||||
PersistentTmStoreWithTmQueue.cpp
|
|
||||||
LiveTmTask.cpp
|
|
||||||
VirtualChannel.cpp
|
|
||||||
TmFunnelHandler.cpp
|
TmFunnelHandler.cpp
|
||||||
TmFunnelBase.cpp
|
TmFunnelBase.cpp
|
||||||
CfdpTmFunnel.cpp
|
CfdpTmFunnel.cpp
|
||||||
tmFilters.cpp
|
tmFilters.cpp
|
||||||
PusLiveDemux.cpp
|
PusLiveDemux.cpp
|
||||||
PersistentSingleTmStoreTask.cpp
|
|
||||||
PersistentLogTmStoreTask.cpp
|
|
||||||
TmStoreTaskBase.cpp
|
|
||||||
PusPacketFilter.cpp
|
PusPacketFilter.cpp
|
||||||
PusTmRouteByFilterHelper.cpp
|
PusTmRouteByFilterHelper.cpp
|
||||||
Service15TmStorage.cpp
|
Service15TmStorage.cpp
|
||||||
|
@ -1,27 +0,0 @@
|
|||||||
#include "LiveTmTask.h"
|
|
||||||
|
|
||||||
#include <fsfw/tasks/TaskFactory.h>
|
|
||||||
#include <fsfw/timemanager/Stopwatch.h>
|
|
||||||
|
|
||||||
LiveTmTask::LiveTmTask(object_id_t objectId, PusTmFunnel& pusFunnel, CfdpTmFunnel& cfdpFunnel,
|
|
||||||
VirtualChannelWithQueue& channel)
|
|
||||||
: SystemObject(objectId), pusFunnel(pusFunnel), cfdpFunnel(cfdpFunnel), channel(channel) {}
|
|
||||||
|
|
||||||
ReturnValue_t LiveTmTask::performOperation(uint8_t opCode) {
|
|
||||||
while (true) {
|
|
||||||
// The funnel tasks are scheduled here directly as well.
|
|
||||||
ReturnValue_t result = channel.sendNextTm();
|
|
||||||
if (result == DirectTmSinkIF::IS_BUSY) {
|
|
||||||
sif::error << "Lost live TM, PAPB busy" << std::endl;
|
|
||||||
}
|
|
||||||
if (result == MessageQueueIF::EMPTY) {
|
|
||||||
if (tmFunnelCd.hasTimedOut()) {
|
|
||||||
pusFunnel.performOperation(0);
|
|
||||||
cfdpFunnel.performOperation(0);
|
|
||||||
tmFunnelCd.resetTimer();
|
|
||||||
}
|
|
||||||
// 40 ms IDLE delay. Might tweak this in the future.
|
|
||||||
TaskFactory::delayTask(40);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,25 +0,0 @@
|
|||||||
#ifndef MISSION_TMTC_LIVETMTASK_H_
|
|
||||||
#define MISSION_TMTC_LIVETMTASK_H_
|
|
||||||
|
|
||||||
#include <fsfw/objectmanager/SystemObject.h>
|
|
||||||
#include <fsfw/tasks/ExecutableObjectIF.h>
|
|
||||||
#include <fsfw/timemanager/Countdown.h>
|
|
||||||
#include <mission/tmtc/CfdpTmFunnel.h>
|
|
||||||
#include <mission/tmtc/PusTmFunnel.h>
|
|
||||||
#include <mission/tmtc/VirtualChannelWithQueue.h>
|
|
||||||
|
|
||||||
class LiveTmTask : public SystemObject, public ExecutableObjectIF {
|
|
||||||
public:
|
|
||||||
LiveTmTask(object_id_t objectId, PusTmFunnel& pusFunnel, CfdpTmFunnel& cfdpFunnel,
|
|
||||||
VirtualChannelWithQueue& channel);
|
|
||||||
|
|
||||||
ReturnValue_t performOperation(uint8_t opCode) override;
|
|
||||||
|
|
||||||
private:
|
|
||||||
Countdown tmFunnelCd = Countdown(100);
|
|
||||||
PusTmFunnel& pusFunnel;
|
|
||||||
CfdpTmFunnel& cfdpFunnel;
|
|
||||||
VirtualChannelWithQueue& channel;
|
|
||||||
};
|
|
||||||
|
|
||||||
#endif /* MISSION_TMTC_LIVETMTASK_H_ */
|
|
@ -251,41 +251,37 @@ ReturnValue_t PersistentTmStore::loadNextDumpFile() {
|
|||||||
return DUMP_DONE;
|
return DUMP_DONE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t PersistentTmStore::dumpNextPacket(DirectTmSinkIF& tmSink, size_t& dumpedLen,
|
ReturnValue_t PersistentTmStore::getNextDumpPacket(PusTmReader& reader, bool& fileHasSwapped) {
|
||||||
bool& fileHasSwapped) {
|
if (state == State::IDLE or dumpParams.pendingPacketDump) {
|
||||||
if (state == State::IDLE) {
|
|
||||||
return returnvalue::FAILED;
|
return returnvalue::FAILED;
|
||||||
}
|
}
|
||||||
PusTmReader reader(&timeReader, fileBuf.data() + dumpParams.currentSize,
|
reader.setReadOnlyData(fileBuf.data() + dumpParams.currentSize,
|
||||||
fileBuf.size() - dumpParams.currentSize);
|
fileBuf.size() - dumpParams.currentSize);
|
||||||
// CRC check to fully ensure this is a valid TM
|
// CRC check to fully ensure this is a valid TM
|
||||||
ReturnValue_t result = reader.parseDataWithCrcCheck();
|
ReturnValue_t result = reader.parseDataWithCrcCheck();
|
||||||
if (result == returnvalue::OK) {
|
if (result != returnvalue::OK) {
|
||||||
result = tmSink.write(fileBuf.data() + dumpParams.currentSize, reader.getFullPacketLen());
|
|
||||||
if (result == DirectTmSinkIF::IS_BUSY) {
|
|
||||||
return result;
|
|
||||||
} else if (result != returnvalue::OK) {
|
|
||||||
// TODO: Event?
|
|
||||||
sif::error << "PersistentTmStore: Writing to TM sink failed" << std::endl;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
dumpParams.currentSize += reader.getFullPacketLen();
|
|
||||||
dumpedLen = reader.getFullPacketLen();
|
|
||||||
if (dumpParams.currentSize >= dumpParams.fileSize) {
|
|
||||||
fileHasSwapped = true;
|
|
||||||
return loadNextDumpFile();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
sif::error << "PersistentTmStore: Parsing of PUS TM failed with code " << result << std::endl;
|
sif::error << "PersistentTmStore: Parsing of PUS TM failed with code " << result << std::endl;
|
||||||
triggerEvent(persTmStore::POSSIBLE_FILE_CORRUPTION, result, dumpParams.currentFileUnixStamp);
|
triggerEvent(persTmStore::POSSIBLE_FILE_CORRUPTION, result, dumpParams.currentFileUnixStamp);
|
||||||
// Delete the file and load next. Could use better algorithm to partially
|
// Delete the file and load next. Could use better algorithm to partially
|
||||||
// restore the file dump, but for now do not trust the file.
|
// restore the file dump, but for now do not trust the file.
|
||||||
dumpedLen = 0;
|
|
||||||
std::error_code e;
|
std::error_code e;
|
||||||
std::filesystem::remove(dumpParams.dirEntry.path().c_str(), e);
|
std::filesystem::remove(dumpParams.dirEntry.path().c_str(), e);
|
||||||
fileHasSwapped = true;
|
fileHasSwapped = true;
|
||||||
return loadNextDumpFile();
|
return loadNextDumpFile();
|
||||||
}
|
}
|
||||||
|
fileHasSwapped = false;
|
||||||
|
dumpParams.pendingPacketDump = true;
|
||||||
|
return returnvalue::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t PersistentTmStore::confirmDump(const PusTmReader& reader, bool& fileHasSwapped) {
|
||||||
|
dumpParams.pendingPacketDump = false;
|
||||||
|
dumpParams.currentSize += reader.getFullPacketLen();
|
||||||
|
if (dumpParams.currentSize >= dumpParams.fileSize) {
|
||||||
|
fileHasSwapped = true;
|
||||||
|
return loadNextDumpFile();
|
||||||
|
}
|
||||||
|
fileHasSwapped = false;
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,12 +4,10 @@
|
|||||||
#include <fsfw/ipc/CommandMessageIF.h>
|
#include <fsfw/ipc/CommandMessageIF.h>
|
||||||
#include <fsfw/objectmanager/SystemObject.h>
|
#include <fsfw/objectmanager/SystemObject.h>
|
||||||
#include <fsfw/storagemanager/StorageManagerIF.h>
|
#include <fsfw/storagemanager/StorageManagerIF.h>
|
||||||
#include <fsfw/timemanager/CdsShortTimeStamper.h>
|
|
||||||
#include <fsfw/tmstorage/TmStoreFrontendSimpleIF.h>
|
#include <fsfw/tmstorage/TmStoreFrontendSimpleIF.h>
|
||||||
#include <fsfw/tmtcpacket/pus/tm/PusTmReader.h>
|
#include <fsfw/tmtcpacket/pus/tm/PusTmReader.h>
|
||||||
#include <fsfw/tmtcservices/AcceptsTelemetryIF.h>
|
#include <fsfw/tmtcservices/AcceptsTelemetryIF.h>
|
||||||
#include <mission/memory/SdCardMountedIF.h>
|
#include <mission/memory/SdCardMountedIF.h>
|
||||||
#include <mission/tmtc/DirectTmSinkIF.h>
|
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
|
|
||||||
@ -57,13 +55,25 @@ class PersistentTmStore : public TmStoreFrontendSimpleIF, public SystemObject {
|
|||||||
ReturnValue_t startDumpFromUpTo(uint32_t fromUnixSeconds, uint32_t upToUnixSeconds);
|
ReturnValue_t startDumpFromUpTo(uint32_t fromUnixSeconds, uint32_t upToUnixSeconds);
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param tmSink
|
* @param tmReader: Next packet will be loaded into the PUS TM reader. A CRC check will be
|
||||||
* @param dumpedLen
|
* performed on the packet. If that check fails, the file is considered corrupted and will
|
||||||
* @param fileHasSwapped
|
* be deleted for now.
|
||||||
* @return DUMP_DONE if dump is finished, returnvalue::OK if dump of next packet was a success,
|
* @param fileHasSwapped: If the CRC check fails, the file will be deleted and a new one has to
|
||||||
* and DirectTmSinkIF::IS_BUSY is TM sink is busy.
|
* be loaded. The dump can reach completion during that process. If a file is swapped, this
|
||||||
|
* boolean is set to true
|
||||||
|
* @return DUMP_DONE if dump is finished, returnvalue::OK if the next packet was loaded into the
|
||||||
|
* TM reader, and the returnvalue of the file swap operation if the CRC check failed and
|
||||||
|
* a new file was loaded.
|
||||||
*/
|
*/
|
||||||
ReturnValue_t dumpNextPacket(DirectTmSinkIF& tmSink, size_t& dumpedLen, bool& fileHasSwapped);
|
ReturnValue_t getNextDumpPacket(PusTmReader& tmReader, bool& fileHasSwapped);
|
||||||
|
/**
|
||||||
|
* Confirm the dump to advance the dump state machine.
|
||||||
|
* @param tmReader
|
||||||
|
* @param fileHasSwapped: If the confirmed dumps completes the current file, a new file will
|
||||||
|
* be loaded and this parameter will be set to true.
|
||||||
|
* @return If a file is swapped, the retrunvalue of the file swap operation.
|
||||||
|
*/
|
||||||
|
ReturnValue_t confirmDump(const PusTmReader& tmReader, bool& fileHasSwapped);
|
||||||
|
|
||||||
void getStartAndEndTimeCurrentOrLastDump(uint32_t& startTime, uint32_t& endTime) const;
|
void getStartAndEndTimeCurrentOrLastDump(uint32_t& startTime, uint32_t& endTime) const;
|
||||||
ReturnValue_t storePacket(PusTmReader& reader);
|
ReturnValue_t storePacket(PusTmReader& reader);
|
||||||
@ -83,8 +93,6 @@ class PersistentTmStore : public TmStoreFrontendSimpleIF, public SystemObject {
|
|||||||
|
|
||||||
MessageQueueIF* tcQueue;
|
MessageQueueIF* tcQueue;
|
||||||
State state = State::IDLE;
|
State state = State::IDLE;
|
||||||
// PacketFilter filter;
|
|
||||||
CdsShortTimeStamper timeReader;
|
|
||||||
bool baseDirUninitialized = true;
|
bool baseDirUninitialized = true;
|
||||||
const char* baseDir;
|
const char* baseDir;
|
||||||
std::string baseName;
|
std::string baseName;
|
||||||
@ -96,6 +104,7 @@ class PersistentTmStore : public TmStoreFrontendSimpleIF, public SystemObject {
|
|||||||
timeval activeFileTv{};
|
timeval activeFileTv{};
|
||||||
|
|
||||||
struct ActiveDumpParams {
|
struct ActiveDumpParams {
|
||||||
|
bool pendingPacketDump = false;
|
||||||
uint32_t fromUnixTime = 0;
|
uint32_t fromUnixTime = 0;
|
||||||
uint32_t untilUnixTime = 0;
|
uint32_t untilUnixTime = 0;
|
||||||
uint32_t currentFileUnixStamp = 0;
|
uint32_t currentFileUnixStamp = 0;
|
||||||
|
@ -1,131 +0,0 @@
|
|||||||
#include "TmStoreTaskBase.h"
|
|
||||||
|
|
||||||
#include <fsfw/ipc/CommandMessageIF.h>
|
|
||||||
#include <fsfw/tasks/TaskFactory.h>
|
|
||||||
#include <fsfw/timemanager/Stopwatch.h>
|
|
||||||
#include <fsfw/tmstorage/TmStoreMessage.h>
|
|
||||||
|
|
||||||
#include "mission/persistentTmStoreDefs.h"
|
|
||||||
|
|
||||||
TmStoreTaskBase::TmStoreTaskBase(object_id_t objectId, StorageManagerIF& ipcStore,
|
|
||||||
VirtualChannel& channel, SdCardMountedIF& sdcMan)
|
|
||||||
: SystemObject(objectId), ipcStore(ipcStore), channel(channel), sdcMan(sdcMan) {}
|
|
||||||
|
|
||||||
bool TmStoreTaskBase::handleOneStore(PersistentTmStoreWithTmQueue& store,
|
|
||||||
DumpContext& dumpContext) {
|
|
||||||
ReturnValue_t result;
|
|
||||||
bool tmToStoreReceived = false;
|
|
||||||
bool tcRequestReceived = false;
|
|
||||||
bool dumpPerformed = false;
|
|
||||||
fileHasSwapped = false;
|
|
||||||
dumpContext.packetWasDumped = false;
|
|
||||||
dumpContext.vcBusyDuringDump = false;
|
|
||||||
|
|
||||||
// Store TM persistently
|
|
||||||
result = store.handleNextTm();
|
|
||||||
if (result == returnvalue::OK) {
|
|
||||||
tmToStoreReceived = true;
|
|
||||||
}
|
|
||||||
// Dump TMs when applicable
|
|
||||||
if (store.getState() == PersistentTmStore::State::DUMPING) {
|
|
||||||
if (handleOneDump(store, dumpContext, dumpPerformed) != returnvalue::OK) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
Command_t execCmd;
|
|
||||||
// Handle TC requests, for example deletion or retrieval requests.
|
|
||||||
result = store.handleCommandQueue(ipcStore, execCmd);
|
|
||||||
if (result == returnvalue::OK) {
|
|
||||||
if (execCmd == TmStoreMessage::DOWNLINK_STORE_CONTENT_TIME) {
|
|
||||||
cancelDumpCd.resetTimer();
|
|
||||||
tmSinkBusyCd.resetTimer();
|
|
||||||
dumpContext.reset();
|
|
||||||
}
|
|
||||||
tcRequestReceived = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (tcRequestReceived or tmToStoreReceived or dumpPerformed) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool TmStoreTaskBase::cyclicStoreCheck() {
|
|
||||||
if (not storesInitialized) {
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TmStoreTaskBase::cancelDump(DumpContext& ctx, PersistentTmStore& store, bool isTxOn) {
|
|
||||||
triggerEvent(ctx.eventIfCancelled, ctx.numberOfDumpedPackets, ctx.dumpedBytes);
|
|
||||||
ctx.reset();
|
|
||||||
store.cancelDump();
|
|
||||||
if (isTxOn) {
|
|
||||||
channel.cancelTransfer();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t TmStoreTaskBase::handleOneDump(PersistentTmStoreWithTmQueue& store,
|
|
||||||
DumpContext& dumpContext, bool& dumpPerformed) {
|
|
||||||
ReturnValue_t result = returnvalue::OK;
|
|
||||||
// The PTME might have been reset an transmitter state change, so there is no point in continuing
|
|
||||||
// the dump.
|
|
||||||
if (not channel.isTxOn()) {
|
|
||||||
cancelDump(dumpContext, store, false);
|
|
||||||
return returnvalue::FAILED;
|
|
||||||
}
|
|
||||||
size_t dumpedLen = 0;
|
|
||||||
if (not channel.isBusy()) {
|
|
||||||
// Dump the next packet into the PTME.
|
|
||||||
dumpContext.ptmeBusyCounter = 0;
|
|
||||||
tmSinkBusyCd.resetTimer();
|
|
||||||
result = store.dumpNextPacket(channel, dumpedLen, fileHasSwapped);
|
|
||||||
if (result == DirectTmSinkIF::IS_BUSY) {
|
|
||||||
sif::warning << "Unexpected PAPB busy" << std::endl;
|
|
||||||
}
|
|
||||||
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) {
|
|
||||||
uint32_t startTime;
|
|
||||||
uint32_t endTime;
|
|
||||||
store.getStartAndEndTimeCurrentOrLastDump(startTime, endTime);
|
|
||||||
triggerEvent(dumpContext.eventIfDone, dumpContext.numberOfDumpedPackets,
|
|
||||||
dumpContext.dumpedBytes);
|
|
||||||
dumpContext.reset();
|
|
||||||
}
|
|
||||||
} 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.
|
|
||||||
sif::warning << "PTME busy for longer period. Cancelling dump" << std::endl;
|
|
||||||
cancelDump(dumpContext, store, channel.isTxOn());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (cancelDumpCd.hasTimedOut() or tmSinkBusyCd.hasTimedOut()) {
|
|
||||||
cancelDump(dumpContext, store, channel.isTxOn());
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
Loading…
Reference in New Issue
Block a user