diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b79662d..7cedf625 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -21,6 +21,18 @@ will consitute of a breaking change warranting a new major release: - Rewrote the PLOC Supervisor Handler, which is now based on a new device handler base class. Added ADC and Logging Counters telemetry set support. +## Fixed + +- 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 + +- 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 ## Changed diff --git a/bsp_q7s/CMakeLists.txt b/bsp_q7s/CMakeLists.txt index e3232363..0a1a9434 100644 --- a/bsp_q7s/CMakeLists.txt +++ b/bsp_q7s/CMakeLists.txt @@ -25,3 +25,4 @@ add_subdirectory(memory) add_subdirectory(callbacks) add_subdirectory(xadc) add_subdirectory(fs) +add_subdirectory(acs) diff --git a/bsp_q7s/acs/CMakeLists.txt b/bsp_q7s/acs/CMakeLists.txt new file mode 100644 index 00000000..87bf46f2 --- /dev/null +++ b/bsp_q7s/acs/CMakeLists.txt @@ -0,0 +1 @@ +# target_sources(${OBSW_NAME} PUBLIC ) diff --git a/bsp_q7s/acs/StrConfigPathGetter.h b/bsp_q7s/acs/StrConfigPathGetter.h new file mode 100644 index 00000000..58d6964c --- /dev/null +++ b/bsp_q7s/acs/StrConfigPathGetter.h @@ -0,0 +1,23 @@ +#include + +#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 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; +}; diff --git a/bsp_q7s/em/emObjectFactory.cpp b/bsp_q7s/em/emObjectFactory.cpp index 41dab3e6..65456d1e 100644 --- a/bsp_q7s/em/emObjectFactory.cpp +++ b/bsp_q7s/em/emObjectFactory.cpp @@ -152,7 +152,7 @@ void ObjectFactory::produce(void* args) { #endif #if OBSW_ADD_STAR_TRACKER == 1 - createStrComponents(pwrSwitcher); + createStrComponents(pwrSwitcher, *SdCardManager::instance()); #endif /* OBSW_ADD_STAR_TRACKER == 1 */ #if OBSW_ADD_PL_PCDU == 1 diff --git a/bsp_q7s/fmObjectFactory.cpp b/bsp_q7s/fmObjectFactory.cpp index b154ac52..05704abf 100644 --- a/bsp_q7s/fmObjectFactory.cpp +++ b/bsp_q7s/fmObjectFactory.cpp @@ -109,7 +109,7 @@ void ObjectFactory::produce(void* args) { createPayloadComponents(gpioComIF, *pwrSwitcher); #if OBSW_ADD_STAR_TRACKER == 1 - createStrComponents(pwrSwitcher); + createStrComponents(pwrSwitcher, *SdCardManager::instance()); #endif /* OBSW_ADD_STAR_TRACKER == 1 */ #if OBSW_ADD_CCSDS_IP_CORES == 1 diff --git a/bsp_q7s/objectFactory.cpp b/bsp_q7s/objectFactory.cpp index 95c15097..0880785b 100644 --- a/bsp_q7s/objectFactory.cpp +++ b/bsp_q7s/objectFactory.cpp @@ -36,6 +36,7 @@ #include #include "OBSWConfig.h" +#include "bsp_q7s/acs/StrConfigPathGetter.h" #include "bsp_q7s/boardtest/Q7STestTask.h" #include "bsp_q7s/callbacks/gnssCallback.h" #include "bsp_q7s/callbacks/pcduSwitchCb.h" @@ -935,7 +936,7 @@ void ObjectFactory::createTestComponents(LinuxLibgpioIF* gpioComIF) { #endif } -void ObjectFactory::createStrComponents(PowerSwitchIF* pwrSwitcher) { +void ObjectFactory::createStrComponents(PowerSwitchIF* pwrSwitcher, SdCardManager& sdcMan) { auto* strAssy = new StrAssembly(objects::STR_ASSY); strAssy->connectModeTreeParent(satsystem::acs::ACS_SUBSYSTEM); auto* starTrackerCookie = @@ -949,9 +950,10 @@ void ObjectFactory::createStrComponents(PowerSwitchIF* pwrSwitcher) { sif::error << "No valid Star Tracker parameter JSON file" << std::endl; } auto strFdir = new StrFdir(objects::STAR_TRACKER); + auto cfgGetter = new StrConfigPathGetter(sdcMan); auto starTracker = 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->connectModeTreeParent(*strAssy); starTracker->setCustomFdir(strFdir); diff --git a/bsp_q7s/objectFactory.h b/bsp_q7s/objectFactory.h index b3dfa83b..2e10dd71 100644 --- a/bsp_q7s/objectFactory.h +++ b/bsp_q7s/objectFactory.h @@ -15,6 +15,8 @@ #include #include +#include "bsp_q7s/fs/SdCardManager.h" + class LinuxLibgpioIF; class SerialComIF; class SpiComIF; @@ -75,7 +77,7 @@ void createHeaterComponents(GpioIF* gpioIF, PowerSwitchIF* pwrSwitcher, HealthTa HeaterHandler*& heaterHandler); void createImtqComponents(PowerSwitchIF* pwrSwitcher, 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 createSyrlinksComponents(PowerSwitchIF* pwrSwitcher); void createPayloadComponents(LinuxLibgpioIF* gpioComIF, PowerSwitchIF& pwrSwitcher); diff --git a/mission/acs/str/ArcsecJsonParamBase.cpp b/mission/acs/str/ArcsecJsonParamBase.cpp index 58c54d30..704c23af 100644 --- a/mission/acs/str/ArcsecJsonParamBase.cpp +++ b/mission/acs/str/ArcsecJsonParamBase.cpp @@ -65,7 +65,7 @@ void ArcsecJsonParamBase::addSetParamHeader(uint8_t* buffer, uint8_t 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; if (not std::filesystem::exists(filename)) { sif::warning << "ArcsecJsonParamBase::init: JSON file " << filename << " does not exist" diff --git a/mission/acs/str/ArcsecJsonParamBase.h b/mission/acs/str/ArcsecJsonParamBase.h index 4c4a7a90..b855a322 100644 --- a/mission/acs/str/ArcsecJsonParamBase.h +++ b/mission/acs/str/ArcsecJsonParamBase.h @@ -46,7 +46,7 @@ class ArcsecJsonParamBase { * @param return JSON_FILE_NOT_EXISTS if specified file does not exist, otherwise * returnvalue::OK */ - ReturnValue_t init(const std::string filename); + ReturnValue_t init(const std::string& filename); /** * @brief Fills a buffer with a parameter set diff --git a/mission/acs/str/StarTrackerHandler.cpp b/mission/acs/str/StarTrackerHandler.cpp index 541301f1..9ad70d41 100644 --- a/mission/acs/str/StarTrackerHandler.cpp +++ b/mission/acs/str/StarTrackerHandler.cpp @@ -5,6 +5,8 @@ #include #include +#include "fsfw/ipc/MessageQueueIF.h" + extern "C" { #include #include @@ -24,8 +26,8 @@ extern "C" { std::atomic_bool JCFG_DONE(false); StarTrackerHandler::StarTrackerHandler(object_id_t objectId, object_id_t comIF, CookieIF* comCookie, - const char* jsonFileStr, StrComHandler* strHelper, - power::Switch_t powerSwitch) + StrComHandler* strHelper, power::Switch_t powerSwitch, + startracker::SdCardConfigPathGetter& cfgPathGetter) : DeviceHandlerBase(objectId, comIF, comCookie), temperatureSet(this), versionSet(this), @@ -57,8 +59,8 @@ StarTrackerHandler::StarTrackerHandler(object_id_t objectId, object_id_t comIF, centroidsSet(this), contrastSet(this), strHelper(strHelper), - paramJsonFile(jsonFileStr), - powerSwitch(powerSwitch) { + powerSwitch(powerSwitch), + cfgPathGetter(cfgPathGetter) { if (comCookie == nullptr) { 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 return; case StartupState::DONE: - if (jcfgCountdown.isBusy()) { + if (!JCFG_DONE) { startupState = StartupState::WAIT_JCFG; return; } - startupState = StartupState::IDLE; break; case StartupState::WAIT_JCFG: { - if (jcfgCountdown.hasTimedOut()) { - startupState = StartupState::IDLE; - break; - } return; } default: @@ -139,8 +136,7 @@ ReturnValue_t StarTrackerHandler::initialize() { // Spin up a thread to do the JSON initialization, takes 200-250 ms which would // delay whole satellite boot process. - jcfgCountdown.resetTimer(); - jsonCfgTask = std::thread{setUpJsonCfgs, std::ref(jcfgs), paramJsonFile.c_str()}; + reloadJsonCfgFile(); EventManagerIF* manager = ObjectManager::instance()->get(objects::EVENT_MANAGER); if (manager == nullptr) { @@ -169,6 +165,20 @@ ReturnValue_t StarTrackerHandler::initialize() { 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, const uint8_t* data, size_t size) { ReturnValue_t result = returnvalue::OK; @@ -335,6 +345,24 @@ void StarTrackerHandler::performOperationHook() { 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; } @@ -499,6 +527,16 @@ ReturnValue_t StarTrackerHandler::buildCommandFromCommand(DeviceCommandId_t devi preparePingRequest(); 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): { SetTimeActionRequest setTimeRequest{}; timeval tv; @@ -513,6 +551,7 @@ ReturnValue_t StarTrackerHandler::buildCommandFromCommand(DeviceCommandId_t devi rawPacket = commandBuffer; return returnvalue::OK; } + case (startracker::REQ_TIME): { prepareTimeRequest(); return returnvalue::OK; @@ -726,6 +765,7 @@ void StarTrackerHandler::fillCommandAndReplyMap() { startracker::MAX_FRAME_SIZE * 2 + 2); this->insertInCommandMap(startracker::UPLOAD_IMAGE); this->insertInCommandMap(startracker::DOWNLOAD_IMAGE); + this->insertInCommandMap(startracker::RELOAD_JSON_CFG_FILE); this->insertInCommandAndReplyMap(startracker::REQ_POWER, 3, &powerSet, startracker::MAX_FRAME_SIZE * 2 + 2); 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.logLevel.init(paramJsonFile); cfgs.logSubscription.init(paramJsonFile); @@ -2811,3 +2851,5 @@ ReturnValue_t StarTrackerHandler::checkCommand(ActionId_t actionId) { } return returnvalue::OK; } + +ReturnValue_t StarTrackerHandler::acceptExternalDeviceCommands() { return returnvalue::OK; } diff --git a/mission/acs/str/StarTrackerHandler.h b/mission/acs/str/StarTrackerHandler.h index 3bfdc8fd..6bc1ff09 100644 --- a/mission/acs/str/StarTrackerHandler.h +++ b/mission/acs/str/StarTrackerHandler.h @@ -27,7 +27,9 @@ extern "C" { * @details Datasheet: https://eive-cloud.irs.uni-stuttgart.de/index.php/apps/files/?dir=/EIVE_IRS/ * Arbeitsdaten/08_Used%20Components/ArcSec_KULeuven_Startracker/ * 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 { public: @@ -42,8 +44,8 @@ class StarTrackerHandler : public DeviceHandlerBase { * to high to enable the device. */ StarTrackerHandler(object_id_t objectId, object_id_t comIF, CookieIF* comCookie, - const char* jsonFileStr, StrComHandler* strHelper, - power::Switch_t powerSwitch); + StrComHandler* strHelper, power::Switch_t powerSwitch, + startracker::SdCardConfigPathGetter& cfgPathGetter); virtual ~StarTrackerHandler(); ReturnValue_t initialize() override; @@ -240,11 +242,12 @@ class StarTrackerHandler : public DeviceHandlerBase { Subscription subscription; AutoThreshold autoThreshold; }; + bool jcfgPending = false; JsonConfigs jcfgs; - Countdown jcfgCountdown = Countdown(250); + Countdown jcfgCountdown = Countdown(1000); bool commandExecuted = false; std::thread jsonCfgTask; - static void setUpJsonCfgs(JsonConfigs& cfgs, const char* paramJsonFile); + static void setUpJsonCfgs(JsonConfigs& cfgs, std::string paramJsonFile); std::string paramJsonFile; @@ -311,6 +314,8 @@ class StarTrackerHandler : public DeviceHandlerBase { std::set additionalRequestedTm{}; std::set::iterator currentSecondaryTmIter; + startracker::SdCardConfigPathGetter& cfgPathGetter; + /** * @brief Handles internal state */ @@ -542,6 +547,8 @@ class StarTrackerHandler : public DeviceHandlerBase { void doNormalTransition(Mode_t modeFrom, Submode_t subModeFrom); void bootFirmware(Mode_t toMode); void bootBootloader(); + bool reloadJsonCfgFile(); + ReturnValue_t acceptExternalDeviceCommands() override; }; #endif /* MISSION_DEVICES_STARTRACKERHANDLER_H_ */ diff --git a/mission/acs/str/strHelpers.h b/mission/acs/str/strHelpers.h index 808d6060..8f83331d 100644 --- a/mission/acs/str/strHelpers.h +++ b/mission/acs/str/strHelpers.h @@ -14,6 +14,12 @@ namespace startracker { static const Submode_t SUBMODE_BOOTLOADER = 1; static const Submode_t SUBMODE_FIRMWARE = 2; +class SdCardConfigPathGetter { + public: + virtual ~SdCardConfigPathGetter() = default; + virtual std::optional getCfgPath() = 0; +}; + /** * @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 RESET_SECONDARY_TM_SET = 96; 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 uint32_t VERSION_SET_ID = REQ_VERSION;