bugfix for virt channel: clear invalid state #827
4
.gitignore
vendored
4
.gitignore
vendored
@ -22,3 +22,7 @@ __pycache__
|
|||||||
!/.idea/cmake.xml
|
!/.idea/cmake.xml
|
||||||
|
|
||||||
generators/*.db
|
generators/*.db
|
||||||
|
|
||||||
|
# Clangd LSP
|
||||||
|
/compile_commands.json
|
||||||
|
/.cache
|
||||||
|
11
CHANGELOG.md
11
CHANGELOG.md
@ -22,6 +22,17 @@ will consitute of a breaking change warranting a new major release:
|
|||||||
not sufficient for cases where 3 writers write concurrently.
|
not sufficient for cases where 3 writers write concurrently.
|
||||||
- Fixed state issue for PTME writer object where the writer was not reset properly after a timeout
|
- Fixed state issue for PTME writer object where the writer was not reset properly after a timeout
|
||||||
of a partial transfer. This was a major bug blocking the whole VC if it occured.
|
of a partial transfer. This was a major bug blocking the whole VC if it occured.
|
||||||
|
- STR config path was previously hardcoded to `/mnt/sd0/startracker/flight-config.json`.
|
||||||
|
A new abstraction was introduces which now uses the active SD card to build the correct
|
||||||
|
config path when initializing the star tracker.
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- Added new PUS 15 subservice `DELETE_BY_TIME_RANGE` which allows to also specify a deletion
|
||||||
|
start time when deleting packets from the persistent TM store.
|
||||||
|
- Introduced a new `RELOAD_JSON_CFG_FILE` command for the STR to reload the JSON configuration
|
||||||
|
data based on the current output of the config file path getter function. A reboot of the
|
||||||
|
device is still necessary to load the configuration to the STR.
|
||||||
|
|
||||||
# [v7.3.0] 2023-11-07
|
# [v7.3.0] 2023-11-07
|
||||||
|
|
||||||
|
@ -25,3 +25,4 @@ add_subdirectory(memory)
|
|||||||
add_subdirectory(callbacks)
|
add_subdirectory(callbacks)
|
||||||
add_subdirectory(xadc)
|
add_subdirectory(xadc)
|
||||||
add_subdirectory(fs)
|
add_subdirectory(fs)
|
||||||
|
add_subdirectory(acs)
|
||||||
|
1
bsp_q7s/acs/CMakeLists.txt
Normal file
1
bsp_q7s/acs/CMakeLists.txt
Normal file
@ -0,0 +1 @@
|
|||||||
|
# target_sources(${OBSW_NAME} PUBLIC <Source File List>)
|
23
bsp_q7s/acs/StrConfigPathGetter.h
Normal file
23
bsp_q7s/acs/StrConfigPathGetter.h
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include "bsp_q7s/fs/SdCardManager.h"
|
||||||
|
#include "mission/acs/str/strHelpers.h"
|
||||||
|
|
||||||
|
class StrConfigPathGetter : public startracker::SdCardConfigPathGetter {
|
||||||
|
public:
|
||||||
|
StrConfigPathGetter(SdCardManager& sdcMan) : sdcMan(sdcMan) {}
|
||||||
|
|
||||||
|
std::optional<std::string> getCfgPath() override {
|
||||||
|
if (!sdcMan.isSdCardUsable(std::nullopt)) {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
if (sdcMan.getActiveSdCard() == sd::SdCard::SLOT_1) {
|
||||||
|
return std::string("/mnt/sd1/startracker/flight-config.json");
|
||||||
|
} else {
|
||||||
|
return std::string("/mnt/sd0/startracker/flight-config.json");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
SdCardManager& sdcMan;
|
||||||
|
};
|
@ -152,7 +152,7 @@ void ObjectFactory::produce(void* args) {
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if OBSW_ADD_STAR_TRACKER == 1
|
#if OBSW_ADD_STAR_TRACKER == 1
|
||||||
createStrComponents(pwrSwitcher);
|
createStrComponents(pwrSwitcher, *SdCardManager::instance());
|
||||||
#endif /* OBSW_ADD_STAR_TRACKER == 1 */
|
#endif /* OBSW_ADD_STAR_TRACKER == 1 */
|
||||||
|
|
||||||
#if OBSW_ADD_PL_PCDU == 1
|
#if OBSW_ADD_PL_PCDU == 1
|
||||||
|
@ -109,7 +109,7 @@ void ObjectFactory::produce(void* args) {
|
|||||||
createPayloadComponents(gpioComIF, *pwrSwitcher);
|
createPayloadComponents(gpioComIF, *pwrSwitcher);
|
||||||
|
|
||||||
#if OBSW_ADD_STAR_TRACKER == 1
|
#if OBSW_ADD_STAR_TRACKER == 1
|
||||||
createStrComponents(pwrSwitcher);
|
createStrComponents(pwrSwitcher, *SdCardManager::instance());
|
||||||
#endif /* OBSW_ADD_STAR_TRACKER == 1 */
|
#endif /* OBSW_ADD_STAR_TRACKER == 1 */
|
||||||
|
|
||||||
#if OBSW_ADD_CCSDS_IP_CORES == 1
|
#if OBSW_ADD_CCSDS_IP_CORES == 1
|
||||||
|
@ -37,6 +37,7 @@
|
|||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
#include "OBSWConfig.h"
|
#include "OBSWConfig.h"
|
||||||
|
#include "bsp_q7s/acs/StrConfigPathGetter.h"
|
||||||
#include "bsp_q7s/boardtest/Q7STestTask.h"
|
#include "bsp_q7s/boardtest/Q7STestTask.h"
|
||||||
#include "bsp_q7s/callbacks/gnssCallback.h"
|
#include "bsp_q7s/callbacks/gnssCallback.h"
|
||||||
#include "bsp_q7s/callbacks/pcduSwitchCb.h"
|
#include "bsp_q7s/callbacks/pcduSwitchCb.h"
|
||||||
@ -935,7 +936,7 @@ void ObjectFactory::createTestComponents(LinuxLibgpioIF* gpioComIF) {
|
|||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
void ObjectFactory::createStrComponents(PowerSwitchIF* pwrSwitcher) {
|
void ObjectFactory::createStrComponents(PowerSwitchIF* pwrSwitcher, SdCardManager& sdcMan) {
|
||||||
auto* strAssy = new StrAssembly(objects::STR_ASSY);
|
auto* strAssy = new StrAssembly(objects::STR_ASSY);
|
||||||
strAssy->connectModeTreeParent(satsystem::acs::ACS_SUBSYSTEM);
|
strAssy->connectModeTreeParent(satsystem::acs::ACS_SUBSYSTEM);
|
||||||
auto* starTrackerCookie =
|
auto* starTrackerCookie =
|
||||||
@ -949,9 +950,10 @@ void ObjectFactory::createStrComponents(PowerSwitchIF* pwrSwitcher) {
|
|||||||
sif::error << "No valid Star Tracker parameter JSON file" << std::endl;
|
sif::error << "No valid Star Tracker parameter JSON file" << std::endl;
|
||||||
}
|
}
|
||||||
auto strFdir = new StrFdir(objects::STAR_TRACKER);
|
auto strFdir = new StrFdir(objects::STAR_TRACKER);
|
||||||
|
auto cfgGetter = new StrConfigPathGetter(sdcMan);
|
||||||
auto starTracker =
|
auto starTracker =
|
||||||
new StarTrackerHandler(objects::STAR_TRACKER, objects::STR_COM_IF, starTrackerCookie,
|
new StarTrackerHandler(objects::STAR_TRACKER, objects::STR_COM_IF, starTrackerCookie,
|
||||||
paramJsonFile, strComIF, power::PDU1_CH2_STAR_TRACKER_5V);
|
strComIF, power::PDU1_CH2_STAR_TRACKER_5V, *cfgGetter);
|
||||||
starTracker->setPowerSwitcher(pwrSwitcher);
|
starTracker->setPowerSwitcher(pwrSwitcher);
|
||||||
starTracker->connectModeTreeParent(*strAssy);
|
starTracker->connectModeTreeParent(*strAssy);
|
||||||
starTracker->setCustomFdir(strFdir);
|
starTracker->setCustomFdir(strFdir);
|
||||||
|
@ -15,6 +15,8 @@
|
|||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
|
#include "bsp_q7s/fs/SdCardManager.h"
|
||||||
|
|
||||||
class LinuxLibgpioIF;
|
class LinuxLibgpioIF;
|
||||||
class SerialComIF;
|
class SerialComIF;
|
||||||
class SpiComIF;
|
class SpiComIF;
|
||||||
@ -75,7 +77,7 @@ void createHeaterComponents(GpioIF* gpioIF, PowerSwitchIF* pwrSwitcher, HealthTa
|
|||||||
HeaterHandler*& heaterHandler);
|
HeaterHandler*& heaterHandler);
|
||||||
void createImtqComponents(PowerSwitchIF* pwrSwitcher, bool enableHkSets, const char* i2cDev);
|
void createImtqComponents(PowerSwitchIF* pwrSwitcher, bool enableHkSets, const char* i2cDev);
|
||||||
void createBpxBatteryComponent(bool enableHkSets, const char* i2cDev);
|
void createBpxBatteryComponent(bool enableHkSets, const char* i2cDev);
|
||||||
void createStrComponents(PowerSwitchIF* pwrSwitcher);
|
void createStrComponents(PowerSwitchIF* pwrSwitcher, SdCardManager& sdcMan);
|
||||||
void createSolarArrayDeploymentComponents(PowerSwitchIF& pwrSwitcher, GpioIF& gpioIF);
|
void createSolarArrayDeploymentComponents(PowerSwitchIF& pwrSwitcher, GpioIF& gpioIF);
|
||||||
void createSyrlinksComponents(PowerSwitchIF* pwrSwitcher);
|
void createSyrlinksComponents(PowerSwitchIF* pwrSwitcher);
|
||||||
void createPayloadComponents(LinuxLibgpioIF* gpioComIF, PowerSwitchIF& pwrSwitcher);
|
void createPayloadComponents(LinuxLibgpioIF* gpioComIF, PowerSwitchIF& pwrSwitcher);
|
||||||
|
2
fsfw
2
fsfw
@ -1 +1 @@
|
|||||||
Subproject commit cc3e64e70d90f6a2b5c59215b2569c1771e890f0
|
Subproject commit 41d67bff639192afa2e18a23db6801c75b4fea88
|
@ -65,7 +65,7 @@ void ArcsecJsonParamBase::addSetParamHeader(uint8_t* buffer, uint8_t setId) {
|
|||||||
*(buffer + 1) = setId;
|
*(buffer + 1) = setId;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t ArcsecJsonParamBase::init(const std::string filename) {
|
ReturnValue_t ArcsecJsonParamBase::init(const std::string& filename) {
|
||||||
ReturnValue_t result = returnvalue::OK;
|
ReturnValue_t result = returnvalue::OK;
|
||||||
if (not std::filesystem::exists(filename)) {
|
if (not std::filesystem::exists(filename)) {
|
||||||
sif::warning << "ArcsecJsonParamBase::init: JSON file " << filename << " does not exist"
|
sif::warning << "ArcsecJsonParamBase::init: JSON file " << filename << " does not exist"
|
||||||
|
@ -46,7 +46,7 @@ class ArcsecJsonParamBase {
|
|||||||
* @param return JSON_FILE_NOT_EXISTS if specified file does not exist, otherwise
|
* @param return JSON_FILE_NOT_EXISTS if specified file does not exist, otherwise
|
||||||
* returnvalue::OK
|
* returnvalue::OK
|
||||||
*/
|
*/
|
||||||
ReturnValue_t init(const std::string filename);
|
ReturnValue_t init(const std::string& filename);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Fills a buffer with a parameter set
|
* @brief Fills a buffer with a parameter set
|
||||||
|
@ -5,6 +5,8 @@
|
|||||||
#include <mission/acs/str/strHelpers.h>
|
#include <mission/acs/str/strHelpers.h>
|
||||||
#include <mission/acs/str/strJsonCommands.h>
|
#include <mission/acs/str/strJsonCommands.h>
|
||||||
|
|
||||||
|
#include "fsfw/ipc/MessageQueueIF.h"
|
||||||
|
|
||||||
extern "C" {
|
extern "C" {
|
||||||
#include <sagitta/client/actionreq.h>
|
#include <sagitta/client/actionreq.h>
|
||||||
#include <sagitta/client/client_tm_structs.h>
|
#include <sagitta/client/client_tm_structs.h>
|
||||||
@ -24,8 +26,8 @@ extern "C" {
|
|||||||
std::atomic_bool JCFG_DONE(false);
|
std::atomic_bool JCFG_DONE(false);
|
||||||
|
|
||||||
StarTrackerHandler::StarTrackerHandler(object_id_t objectId, object_id_t comIF, CookieIF* comCookie,
|
StarTrackerHandler::StarTrackerHandler(object_id_t objectId, object_id_t comIF, CookieIF* comCookie,
|
||||||
const char* jsonFileStr, StrComHandler* strHelper,
|
StrComHandler* strHelper, power::Switch_t powerSwitch,
|
||||||
power::Switch_t powerSwitch)
|
startracker::SdCardConfigPathGetter& cfgPathGetter)
|
||||||
: DeviceHandlerBase(objectId, comIF, comCookie),
|
: DeviceHandlerBase(objectId, comIF, comCookie),
|
||||||
temperatureSet(this),
|
temperatureSet(this),
|
||||||
versionSet(this),
|
versionSet(this),
|
||||||
@ -57,8 +59,8 @@ StarTrackerHandler::StarTrackerHandler(object_id_t objectId, object_id_t comIF,
|
|||||||
centroidsSet(this),
|
centroidsSet(this),
|
||||||
contrastSet(this),
|
contrastSet(this),
|
||||||
strHelper(strHelper),
|
strHelper(strHelper),
|
||||||
paramJsonFile(jsonFileStr),
|
powerSwitch(powerSwitch),
|
||||||
powerSwitch(powerSwitch) {
|
cfgPathGetter(cfgPathGetter) {
|
||||||
if (comCookie == nullptr) {
|
if (comCookie == nullptr) {
|
||||||
sif::error << "StarTrackerHandler: Invalid com cookie" << std::endl;
|
sif::error << "StarTrackerHandler: Invalid com cookie" << std::endl;
|
||||||
}
|
}
|
||||||
@ -82,17 +84,12 @@ void StarTrackerHandler::doStartUp() {
|
|||||||
// the device handler's submode to the star tracker's mode
|
// the device handler's submode to the star tracker's mode
|
||||||
return;
|
return;
|
||||||
case StartupState::DONE:
|
case StartupState::DONE:
|
||||||
if (jcfgCountdown.isBusy()) {
|
if (!JCFG_DONE) {
|
||||||
startupState = StartupState::WAIT_JCFG;
|
startupState = StartupState::WAIT_JCFG;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
startupState = StartupState::IDLE;
|
|
||||||
break;
|
break;
|
||||||
case StartupState::WAIT_JCFG: {
|
case StartupState::WAIT_JCFG: {
|
||||||
if (jcfgCountdown.hasTimedOut()) {
|
|
||||||
startupState = StartupState::IDLE;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
default:
|
default:
|
||||||
@ -139,8 +136,7 @@ ReturnValue_t StarTrackerHandler::initialize() {
|
|||||||
|
|
||||||
// Spin up a thread to do the JSON initialization, takes 200-250 ms which would
|
// Spin up a thread to do the JSON initialization, takes 200-250 ms which would
|
||||||
// delay whole satellite boot process.
|
// delay whole satellite boot process.
|
||||||
jcfgCountdown.resetTimer();
|
reloadJsonCfgFile();
|
||||||
jsonCfgTask = std::thread{setUpJsonCfgs, std::ref(jcfgs), paramJsonFile.c_str()};
|
|
||||||
|
|
||||||
EventManagerIF* manager = ObjectManager::instance()->get<EventManagerIF>(objects::EVENT_MANAGER);
|
EventManagerIF* manager = ObjectManager::instance()->get<EventManagerIF>(objects::EVENT_MANAGER);
|
||||||
if (manager == nullptr) {
|
if (manager == nullptr) {
|
||||||
@ -169,6 +165,20 @@ ReturnValue_t StarTrackerHandler::initialize() {
|
|||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool StarTrackerHandler::reloadJsonCfgFile() {
|
||||||
|
jcfgCountdown.resetTimer();
|
||||||
|
auto strCfgPath = cfgPathGetter.getCfgPath();
|
||||||
|
if (strCfgPath.has_value()) {
|
||||||
|
jcfgPending = true;
|
||||||
|
JCFG_DONE = false;
|
||||||
|
jsonCfgTask = std::thread{setUpJsonCfgs, std::ref(jcfgs), strCfgPath.value()};
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// Simplified FDIR: Just continue as usual..
|
||||||
|
JCFG_DONE = true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
ReturnValue_t StarTrackerHandler::executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
|
ReturnValue_t StarTrackerHandler::executeAction(ActionId_t actionId, MessageQueueId_t commandedBy,
|
||||||
const uint8_t* data, size_t size) {
|
const uint8_t* data, size_t size) {
|
||||||
ReturnValue_t result = returnvalue::OK;
|
ReturnValue_t result = returnvalue::OK;
|
||||||
@ -335,6 +345,24 @@ void StarTrackerHandler::performOperationHook() {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (jcfgPending) {
|
||||||
|
if (JCFG_DONE) {
|
||||||
|
if(startupState == StartupState::WAIT_JCFG) {
|
||||||
|
startupState = StartupState::DONE;
|
||||||
|
}
|
||||||
|
jsonCfgTask.join();
|
||||||
|
jcfgPending = false;
|
||||||
|
auto iter = deviceCommandMap.find(startracker::RELOAD_JSON_CFG_FILE);
|
||||||
|
if (iter != deviceCommandMap.end() and iter->second.sendReplyTo != MessageQueueIF::NO_QUEUE) {
|
||||||
|
actionHelper.finish(true, iter->second.sendReplyTo, startracker::RELOAD_JSON_CFG_FILE);
|
||||||
|
}
|
||||||
|
} else if (jcfgCountdown.hasTimedOut()) {
|
||||||
|
auto iter = deviceCommandMap.find(startracker::RELOAD_JSON_CFG_FILE);
|
||||||
|
if (iter != deviceCommandMap.end() and iter->second.sendReplyTo != MessageQueueIF::NO_QUEUE) {
|
||||||
|
actionHelper.finish(false, iter->second.sendReplyTo, startracker::RELOAD_JSON_CFG_FILE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Submode_t StarTrackerHandler::getInitialSubmode() { return startracker::SUBMODE_BOOTLOADER; }
|
Submode_t StarTrackerHandler::getInitialSubmode() { return startracker::SUBMODE_BOOTLOADER; }
|
||||||
@ -499,6 +527,16 @@ ReturnValue_t StarTrackerHandler::buildCommandFromCommand(DeviceCommandId_t devi
|
|||||||
preparePingRequest();
|
preparePingRequest();
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
case (startracker::RELOAD_JSON_CFG_FILE): {
|
||||||
|
if (jcfgPending) {
|
||||||
|
return HasActionsIF::IS_BUSY;
|
||||||
|
}
|
||||||
|
// It should be noted that this just reloads the JSON config structure in memory from the
|
||||||
|
// JSON file. The configuration still needs to be sent to the STR. The easiest way to achieve
|
||||||
|
// this is to simply reboot the device after a reload.
|
||||||
|
reloadJsonCfgFile();
|
||||||
|
return returnvalue::OK;
|
||||||
|
}
|
||||||
case (startracker::SET_TIME_FROM_SYS_TIME): {
|
case (startracker::SET_TIME_FROM_SYS_TIME): {
|
||||||
SetTimeActionRequest setTimeRequest{};
|
SetTimeActionRequest setTimeRequest{};
|
||||||
timeval tv;
|
timeval tv;
|
||||||
@ -513,6 +551,7 @@ ReturnValue_t StarTrackerHandler::buildCommandFromCommand(DeviceCommandId_t devi
|
|||||||
rawPacket = commandBuffer;
|
rawPacket = commandBuffer;
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
case (startracker::REQ_TIME): {
|
case (startracker::REQ_TIME): {
|
||||||
prepareTimeRequest();
|
prepareTimeRequest();
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
@ -726,6 +765,7 @@ void StarTrackerHandler::fillCommandAndReplyMap() {
|
|||||||
startracker::MAX_FRAME_SIZE * 2 + 2);
|
startracker::MAX_FRAME_SIZE * 2 + 2);
|
||||||
this->insertInCommandMap(startracker::UPLOAD_IMAGE);
|
this->insertInCommandMap(startracker::UPLOAD_IMAGE);
|
||||||
this->insertInCommandMap(startracker::DOWNLOAD_IMAGE);
|
this->insertInCommandMap(startracker::DOWNLOAD_IMAGE);
|
||||||
|
this->insertInCommandMap(startracker::RELOAD_JSON_CFG_FILE);
|
||||||
this->insertInCommandAndReplyMap(startracker::REQ_POWER, 3, &powerSet,
|
this->insertInCommandAndReplyMap(startracker::REQ_POWER, 3, &powerSet,
|
||||||
startracker::MAX_FRAME_SIZE * 2 + 2);
|
startracker::MAX_FRAME_SIZE * 2 + 2);
|
||||||
this->insertInCommandAndReplyMap(startracker::REQ_INTERFACE, 3, &interfaceSet,
|
this->insertInCommandAndReplyMap(startracker::REQ_INTERFACE, 3, &interfaceSet,
|
||||||
@ -928,7 +968,7 @@ void StarTrackerHandler::bootFirmware(Mode_t toMode) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void StarTrackerHandler::setUpJsonCfgs(JsonConfigs& cfgs, const char* paramJsonFile) {
|
void StarTrackerHandler::setUpJsonCfgs(JsonConfigs& cfgs, std::string paramJsonFile) {
|
||||||
cfgs.tracking.init(paramJsonFile);
|
cfgs.tracking.init(paramJsonFile);
|
||||||
cfgs.logLevel.init(paramJsonFile);
|
cfgs.logLevel.init(paramJsonFile);
|
||||||
cfgs.logSubscription.init(paramJsonFile);
|
cfgs.logSubscription.init(paramJsonFile);
|
||||||
@ -2811,3 +2851,5 @@ ReturnValue_t StarTrackerHandler::checkCommand(ActionId_t actionId) {
|
|||||||
}
|
}
|
||||||
return returnvalue::OK;
|
return returnvalue::OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ReturnValue_t StarTrackerHandler::acceptExternalDeviceCommands() { return returnvalue::OK; }
|
||||||
|
@ -27,7 +27,9 @@ extern "C" {
|
|||||||
* @details Datasheet: https://eive-cloud.irs.uni-stuttgart.de/index.php/apps/files/?dir=/EIVE_IRS/
|
* @details Datasheet: https://eive-cloud.irs.uni-stuttgart.de/index.php/apps/files/?dir=/EIVE_IRS/
|
||||||
* Arbeitsdaten/08_Used%20Components/ArcSec_KULeuven_Startracker/
|
* Arbeitsdaten/08_Used%20Components/ArcSec_KULeuven_Startracker/
|
||||||
* Sagitta%201.0%20Datapack&fileid=659181
|
* Sagitta%201.0%20Datapack&fileid=659181
|
||||||
* @author J. Meier
|
* @note The STR code is a chaotic inconsistent mess and should be re-written with a simpler base
|
||||||
|
* class. DO NOT USE THIS AS REFERENCE. Stay away from it.
|
||||||
|
* @author J. Meier, R. Mueller
|
||||||
*/
|
*/
|
||||||
class StarTrackerHandler : public DeviceHandlerBase {
|
class StarTrackerHandler : public DeviceHandlerBase {
|
||||||
public:
|
public:
|
||||||
@ -42,8 +44,8 @@ class StarTrackerHandler : public DeviceHandlerBase {
|
|||||||
* to high to enable the device.
|
* to high to enable the device.
|
||||||
*/
|
*/
|
||||||
StarTrackerHandler(object_id_t objectId, object_id_t comIF, CookieIF* comCookie,
|
StarTrackerHandler(object_id_t objectId, object_id_t comIF, CookieIF* comCookie,
|
||||||
const char* jsonFileStr, StrComHandler* strHelper,
|
StrComHandler* strHelper, power::Switch_t powerSwitch,
|
||||||
power::Switch_t powerSwitch);
|
startracker::SdCardConfigPathGetter& cfgPathGetter);
|
||||||
virtual ~StarTrackerHandler();
|
virtual ~StarTrackerHandler();
|
||||||
|
|
||||||
ReturnValue_t initialize() override;
|
ReturnValue_t initialize() override;
|
||||||
@ -240,11 +242,12 @@ class StarTrackerHandler : public DeviceHandlerBase {
|
|||||||
Subscription subscription;
|
Subscription subscription;
|
||||||
AutoThreshold autoThreshold;
|
AutoThreshold autoThreshold;
|
||||||
};
|
};
|
||||||
|
bool jcfgPending = false;
|
||||||
JsonConfigs jcfgs;
|
JsonConfigs jcfgs;
|
||||||
Countdown jcfgCountdown = Countdown(250);
|
Countdown jcfgCountdown = Countdown(1000);
|
||||||
bool commandExecuted = false;
|
bool commandExecuted = false;
|
||||||
std::thread jsonCfgTask;
|
std::thread jsonCfgTask;
|
||||||
static void setUpJsonCfgs(JsonConfigs& cfgs, const char* paramJsonFile);
|
static void setUpJsonCfgs(JsonConfigs& cfgs, std::string paramJsonFile);
|
||||||
|
|
||||||
std::string paramJsonFile;
|
std::string paramJsonFile;
|
||||||
|
|
||||||
@ -311,6 +314,8 @@ class StarTrackerHandler : public DeviceHandlerBase {
|
|||||||
std::set<DeviceCommandId_t> additionalRequestedTm{};
|
std::set<DeviceCommandId_t> additionalRequestedTm{};
|
||||||
std::set<DeviceCommandId_t>::iterator currentSecondaryTmIter;
|
std::set<DeviceCommandId_t>::iterator currentSecondaryTmIter;
|
||||||
|
|
||||||
|
startracker::SdCardConfigPathGetter& cfgPathGetter;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Handles internal state
|
* @brief Handles internal state
|
||||||
*/
|
*/
|
||||||
@ -542,6 +547,8 @@ class StarTrackerHandler : public DeviceHandlerBase {
|
|||||||
void doNormalTransition(Mode_t modeFrom, Submode_t subModeFrom);
|
void doNormalTransition(Mode_t modeFrom, Submode_t subModeFrom);
|
||||||
void bootFirmware(Mode_t toMode);
|
void bootFirmware(Mode_t toMode);
|
||||||
void bootBootloader();
|
void bootBootloader();
|
||||||
|
bool reloadJsonCfgFile();
|
||||||
|
ReturnValue_t acceptExternalDeviceCommands() override;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* MISSION_DEVICES_STARTRACKERHANDLER_H_ */
|
#endif /* MISSION_DEVICES_STARTRACKERHANDLER_H_ */
|
||||||
|
@ -14,6 +14,12 @@ namespace startracker {
|
|||||||
static const Submode_t SUBMODE_BOOTLOADER = 1;
|
static const Submode_t SUBMODE_BOOTLOADER = 1;
|
||||||
static const Submode_t SUBMODE_FIRMWARE = 2;
|
static const Submode_t SUBMODE_FIRMWARE = 2;
|
||||||
|
|
||||||
|
class SdCardConfigPathGetter {
|
||||||
|
public:
|
||||||
|
virtual ~SdCardConfigPathGetter() = default;
|
||||||
|
virtual std::optional<std::string> getCfgPath() = 0;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Returns the frame type field of a decoded frame.
|
* @brief Returns the frame type field of a decoded frame.
|
||||||
*/
|
*/
|
||||||
@ -381,6 +387,7 @@ static constexpr DeviceCommandId_t REQ_CENTROIDS = 94;
|
|||||||
static constexpr DeviceCommandId_t ADD_SECONDARY_TM_TO_NORMAL_MODE = 95;
|
static constexpr DeviceCommandId_t ADD_SECONDARY_TM_TO_NORMAL_MODE = 95;
|
||||||
static constexpr DeviceCommandId_t RESET_SECONDARY_TM_SET = 96;
|
static constexpr DeviceCommandId_t RESET_SECONDARY_TM_SET = 96;
|
||||||
static constexpr DeviceCommandId_t READ_SECONDARY_TM_SET = 97;
|
static constexpr DeviceCommandId_t READ_SECONDARY_TM_SET = 97;
|
||||||
|
static constexpr DeviceCommandId_t RELOAD_JSON_CFG_FILE = 100;
|
||||||
static const DeviceCommandId_t NONE = 0xFFFFFFFF;
|
static const DeviceCommandId_t NONE = 0xFFFFFFFF;
|
||||||
|
|
||||||
static const uint32_t VERSION_SET_ID = REQ_VERSION;
|
static const uint32_t VERSION_SET_ID = REQ_VERSION;
|
||||||
|
@ -137,16 +137,47 @@ ReturnValue_t PersistentTmStore::handleCommandQueue(StorageManagerIF& ipcStore,
|
|||||||
if (cmdMessage.getMessageType() == messagetypes::TM_STORE) {
|
if (cmdMessage.getMessageType() == messagetypes::TM_STORE) {
|
||||||
Command_t cmd = cmdMessage.getCommand();
|
Command_t cmd = cmdMessage.getCommand();
|
||||||
if (cmd == TmStoreMessage::DELETE_STORE_CONTENT_TIME) {
|
if (cmd == TmStoreMessage::DELETE_STORE_CONTENT_TIME) {
|
||||||
|
result = handleDeletionCmd(ipcStore, cmdMessage);
|
||||||
|
execCmd = cmd;
|
||||||
|
} else if (cmd == TmStoreMessage::DOWNLINK_STORE_CONTENT_TIME) {
|
||||||
|
result = handleDumpCmd(ipcStore, cmdMessage);
|
||||||
|
execCmd = cmd;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t PersistentTmStore::handleDeletionCmd(StorageManagerIF& ipcStore,
|
||||||
|
CommandMessage& cmdMessage) {
|
||||||
Clock::getClock_timeval(¤tTv);
|
Clock::getClock_timeval(¤tTv);
|
||||||
store_address_t storeId = TmStoreMessage::getStoreId(&cmdMessage);
|
store_address_t storeId = TmStoreMessage::getStoreId(&cmdMessage);
|
||||||
auto accessor = ipcStore.getData(storeId);
|
auto accessor = ipcStore.getData(storeId);
|
||||||
uint32_t deleteUpToUnixSeconds = 0;
|
|
||||||
size_t size = accessor.second.size();
|
size_t size = accessor.second.size();
|
||||||
SerializeAdapter::deSerialize(&deleteUpToUnixSeconds, accessor.second.data(), &size,
|
if (size < 4) {
|
||||||
|
return returnvalue::FAILED;
|
||||||
|
}
|
||||||
|
const uint8_t* data = accessor.second.data();
|
||||||
|
uint32_t deleteUpToUnixSeconds = 0;
|
||||||
|
if (size == 4) {
|
||||||
|
SerializeAdapter::deSerialize(&deleteUpToUnixSeconds, &data, &size,
|
||||||
SerializeIF::Endianness::NETWORK);
|
SerializeIF::Endianness::NETWORK);
|
||||||
execCmd = cmd;
|
|
||||||
deleteUpTo(deleteUpToUnixSeconds);
|
deleteUpTo(deleteUpToUnixSeconds);
|
||||||
} else if (cmd == TmStoreMessage::DOWNLINK_STORE_CONTENT_TIME) {
|
} else if (size == 8) {
|
||||||
|
uint32_t deleteFromUnixSeconds = 0;
|
||||||
|
SerializeAdapter::deSerialize(&deleteFromUnixSeconds, &data, &size,
|
||||||
|
SerializeIF::Endianness::NETWORK);
|
||||||
|
SerializeAdapter::deSerialize(&deleteUpToUnixSeconds, &data, &size,
|
||||||
|
SerializeIF::Endianness::NETWORK);
|
||||||
|
deleteFromUpTo(deleteFromUnixSeconds, deleteUpToUnixSeconds);
|
||||||
|
} else {
|
||||||
|
sif::warning << "PersistentTmStore: Unknown deletion time specification" << std::endl;
|
||||||
|
return returnvalue::FAILED;
|
||||||
|
}
|
||||||
|
return returnvalue::OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t PersistentTmStore::handleDumpCmd(StorageManagerIF& ipcStore,
|
||||||
|
CommandMessage& cmdMessage) {
|
||||||
Clock::getClock_timeval(¤tTv);
|
Clock::getClock_timeval(¤tTv);
|
||||||
store_address_t storeId = TmStoreMessage::getStoreId(&cmdMessage);
|
store_address_t storeId = TmStoreMessage::getStoreId(&cmdMessage);
|
||||||
auto accessor = ipcStore.getData(storeId);
|
auto accessor = ipcStore.getData(storeId);
|
||||||
@ -160,15 +191,12 @@ ReturnValue_t PersistentTmStore::handleCommandQueue(StorageManagerIF& ipcStore,
|
|||||||
SerializeIF::Endianness::NETWORK);
|
SerializeIF::Endianness::NETWORK);
|
||||||
SerializeAdapter::deSerialize(&dumpUntilUnixSeconds, accessor.second.data() + 4, &size,
|
SerializeAdapter::deSerialize(&dumpUntilUnixSeconds, accessor.second.data() + 4, &size,
|
||||||
SerializeIF::Endianness::NETWORK);
|
SerializeIF::Endianness::NETWORK);
|
||||||
result = startDumpFromUpTo(dumpFromUnixSeconds, dumpUntilUnixSeconds);
|
ReturnValue_t result = startDumpFromUpTo(dumpFromUnixSeconds, dumpUntilUnixSeconds);
|
||||||
if (result == BUSY_DUMPING) {
|
if (result == BUSY_DUMPING) {
|
||||||
triggerEvent(persTmStore::BUSY_DUMPING_EVENT);
|
triggerEvent(persTmStore::BUSY_DUMPING_EVENT);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
execCmd = cmd;
|
return returnvalue::OK;
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t PersistentTmStore::startDumpFrom(uint32_t fromUnixSeconds) {
|
ReturnValue_t PersistentTmStore::startDumpFrom(uint32_t fromUnixSeconds) {
|
||||||
@ -257,7 +285,9 @@ bool PersistentTmStore::updateBaseDir() {
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PersistentTmStore::deleteUpTo(uint32_t unixSeconds) {
|
void PersistentTmStore::deleteUpTo(uint32_t unixSeconds) { deleteFromUpTo(0, unixSeconds); }
|
||||||
|
|
||||||
|
void PersistentTmStore::deleteFromUpTo(uint32_t startUnixTime, uint32_t endUnixTime) {
|
||||||
using namespace std::filesystem;
|
using namespace std::filesystem;
|
||||||
for (auto const& file : directory_iterator(basePath)) {
|
for (auto const& file : directory_iterator(basePath)) {
|
||||||
if (file.is_directory() or (activeFile.has_value() and (activeFile.value() == file.path()))) {
|
if (file.is_directory() or (activeFile.has_value() and (activeFile.value() == file.path()))) {
|
||||||
@ -270,7 +300,8 @@ void PersistentTmStore::deleteUpTo(uint32_t unixSeconds) {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
time_t fileEpoch = timegm(&fileTime);
|
time_t fileEpoch = timegm(&fileTime);
|
||||||
if (fileEpoch + rolloverDiffSeconds < unixSeconds) {
|
if (fileEpoch + rolloverDiffSeconds < endUnixTime and
|
||||||
|
static_cast<uint32_t>(fileEpoch) >= startUnixTime) {
|
||||||
std::error_code e;
|
std::error_code e;
|
||||||
std::filesystem::remove(file.path(), e);
|
std::filesystem::remove(file.path(), e);
|
||||||
}
|
}
|
||||||
|
@ -14,6 +14,7 @@
|
|||||||
|
|
||||||
#include "eive/eventSubsystemIds.h"
|
#include "eive/eventSubsystemIds.h"
|
||||||
#include "eive/resultClassIds.h"
|
#include "eive/resultClassIds.h"
|
||||||
|
#include "fsfw/ipc/CommandMessage.h"
|
||||||
|
|
||||||
enum class RolloverInterval { MINUTELY, HOURLY, DAILY };
|
enum class RolloverInterval { MINUTELY, HOURLY, DAILY };
|
||||||
|
|
||||||
@ -60,6 +61,7 @@ class PersistentTmStore : public TmStoreFrontendSimpleIF, public SystemObject {
|
|||||||
ReturnValue_t handleCommandQueue(StorageManagerIF& ipcStore, Command_t& execCmd);
|
ReturnValue_t handleCommandQueue(StorageManagerIF& ipcStore, Command_t& execCmd);
|
||||||
|
|
||||||
void deleteUpTo(uint32_t unixSeconds);
|
void deleteUpTo(uint32_t unixSeconds);
|
||||||
|
void deleteFromUpTo(uint32_t startUnixTime, uint32_t endUnixTime);
|
||||||
ReturnValue_t startDumpFrom(uint32_t fromUnixSeconds);
|
ReturnValue_t startDumpFrom(uint32_t fromUnixSeconds);
|
||||||
ReturnValue_t startDumpFromUpTo(uint32_t fromUnixSeconds, uint32_t upToUnixSeconds);
|
ReturnValue_t startDumpFromUpTo(uint32_t fromUnixSeconds, uint32_t upToUnixSeconds);
|
||||||
/**
|
/**
|
||||||
@ -145,6 +147,8 @@ class PersistentTmStore : public TmStoreFrontendSimpleIF, public SystemObject {
|
|||||||
std::optional<uint8_t> extractSuffix(const std::string& pathStr);
|
std::optional<uint8_t> extractSuffix(const std::string& pathStr);
|
||||||
bool updateBaseDir();
|
bool updateBaseDir();
|
||||||
ReturnValue_t assignAndOrCreateMostRecentFile();
|
ReturnValue_t assignAndOrCreateMostRecentFile();
|
||||||
|
ReturnValue_t handleDeletionCmd(StorageManagerIF& ipcStore, CommandMessage& cmdMessage);
|
||||||
|
ReturnValue_t handleDumpCmd(StorageManagerIF& ipcStore, CommandMessage& cmdMessage);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* MISSION_TMTC_TMSTOREBACKEND_H_ */
|
#endif /* MISSION_TMTC_TMSTOREBACKEND_H_ */
|
||||||
|
@ -16,8 +16,9 @@ Service15TmStorage::Service15TmStorage(object_id_t objectId, uint16_t apid,
|
|||||||
|
|
||||||
ReturnValue_t Service15TmStorage::isValidSubservice(uint8_t subservice) {
|
ReturnValue_t Service15TmStorage::isValidSubservice(uint8_t subservice) {
|
||||||
switch (subservice) {
|
switch (subservice) {
|
||||||
case (Subservices::DELETE_UP_TO):
|
case (Subservice::DELETE_UP_TO):
|
||||||
case (Subservices::START_BY_TIME_RANGE_RETRIEVAL): {
|
case (Subservice::DELETE_BY_TIME_RANGE):
|
||||||
|
case (Subservice::START_BY_TIME_RANGE_RETRIEVAL): {
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
default: {
|
default: {
|
||||||
@ -45,7 +46,8 @@ ReturnValue_t Service15TmStorage::getMessageQueueAndObject(uint8_t subservice,
|
|||||||
ReturnValue_t Service15TmStorage::prepareCommand(CommandMessage *message, uint8_t subservice,
|
ReturnValue_t Service15TmStorage::prepareCommand(CommandMessage *message, uint8_t subservice,
|
||||||
const uint8_t *tcData, size_t tcDataLen,
|
const uint8_t *tcData, size_t tcDataLen,
|
||||||
uint32_t *state, object_id_t objectId) {
|
uint32_t *state, object_id_t objectId) {
|
||||||
if (subservice == Subservices::START_BY_TIME_RANGE_RETRIEVAL) {
|
switch (subservice) {
|
||||||
|
case (Subservice::START_BY_TIME_RANGE_RETRIEVAL): {
|
||||||
// TODO: Hardcoded to UNIX timestamps.. Should allow arbitrary timestamp and let receiver
|
// TODO: Hardcoded to UNIX timestamps.. Should allow arbitrary timestamp and let receiver
|
||||||
// to time reading and reply handling
|
// to time reading and reply handling
|
||||||
if (tcDataLen != 12) {
|
if (tcDataLen != 12) {
|
||||||
@ -59,7 +61,8 @@ ReturnValue_t Service15TmStorage::prepareCommand(CommandMessage *message, uint8_
|
|||||||
// Store timestamps
|
// Store timestamps
|
||||||
TmStoreMessage::setDownlinkContentTimeMessage(message, storeId);
|
TmStoreMessage::setDownlinkContentTimeMessage(message, storeId);
|
||||||
return CommandingServiceBase::EXECUTION_COMPLETE;
|
return CommandingServiceBase::EXECUTION_COMPLETE;
|
||||||
} else if (subservice == Subservices::DELETE_UP_TO) {
|
}
|
||||||
|
case (Subservice::DELETE_UP_TO): {
|
||||||
// TODO: Hardcoded to UNIX timestamps.. Should allow arbitrary timestamp and let receiver
|
// TODO: Hardcoded to UNIX timestamps.. Should allow arbitrary timestamp and let receiver
|
||||||
// to time reading and reply handling
|
// to time reading and reply handling
|
||||||
if (tcDataLen != 8) {
|
if (tcDataLen != 8) {
|
||||||
@ -74,6 +77,25 @@ ReturnValue_t Service15TmStorage::prepareCommand(CommandMessage *message, uint8_
|
|||||||
TmStoreMessage::setDeleteContentTimeMessage(message, storeId);
|
TmStoreMessage::setDeleteContentTimeMessage(message, storeId);
|
||||||
return CommandingServiceBase::EXECUTION_COMPLETE;
|
return CommandingServiceBase::EXECUTION_COMPLETE;
|
||||||
}
|
}
|
||||||
|
case (Subservice::DELETE_BY_TIME_RANGE): {
|
||||||
|
// TODO: Hardcoded two UNIX timestamps.. Should allow arbitrary timestamp and let receiver
|
||||||
|
// to time reading and reply handling
|
||||||
|
if (tcDataLen != 12) {
|
||||||
|
return INVALID_TC;
|
||||||
|
}
|
||||||
|
store_address_t storeId;
|
||||||
|
ReturnValue_t result = ipcStore->addData(&storeId, tcData + 4, tcDataLen - 4);
|
||||||
|
if (result != OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
// Store timestamps
|
||||||
|
TmStoreMessage::setDeleteContentTimeMessage(message, storeId);
|
||||||
|
return CommandingServiceBase::EXECUTION_COMPLETE;
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
return CommandingServiceBase::INVALID_SUBSERVICE;
|
||||||
|
}
|
||||||
|
}
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -5,7 +5,11 @@
|
|||||||
|
|
||||||
class Service15TmStorage : public CommandingServiceBase {
|
class Service15TmStorage : public CommandingServiceBase {
|
||||||
public:
|
public:
|
||||||
enum Subservices : uint8_t { START_BY_TIME_RANGE_RETRIEVAL = 9, DELETE_UP_TO = 11 };
|
enum Subservice : uint8_t {
|
||||||
|
START_BY_TIME_RANGE_RETRIEVAL = 9,
|
||||||
|
DELETE_UP_TO = 11,
|
||||||
|
DELETE_BY_TIME_RANGE = 128
|
||||||
|
};
|
||||||
explicit Service15TmStorage(object_id_t objectId, uint16_t apid, uint8_t numParallelCommands,
|
explicit Service15TmStorage(object_id_t objectId, uint16_t apid, uint8_t numParallelCommands,
|
||||||
uint16_t commandTimeoutSecs = 60, size_t queueDepth = 10);
|
uint16_t commandTimeoutSecs = 60, size_t queueDepth = 10);
|
||||||
|
|
||||||
|
2
tmtc
2
tmtc
@ -1 +1 @@
|
|||||||
Subproject commit 99c6c8bbd0d791d8b17720de481c6142091a54a4
|
Subproject commit 0a417a89e9e7f0447d35c70950685df59bf5c062
|
Loading…
Reference in New Issue
Block a user