#ifndef BSP_Q7S_CORE_CORECONTROLLER_H_ #define BSP_Q7S_CORE_CORECONTROLLER_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include "OBSWConfig.h" #include "bsp_q7s/fs/SdCardManager.h" #include "events/subsystemIdRanges.h" #include "fsfw/controller/ExtendedControllerBase.h" #include "mission/sysDefs.h" class Timer; class SdCardManager; struct RebootWatchdogFile { static constexpr uint8_t DEFAULT_MAX_BOOT_CNT = 10; bool enabled = true; size_t maxCount = DEFAULT_MAX_BOOT_CNT; uint32_t img00Cnt = 0; uint32_t img01Cnt = 0; uint32_t img10Cnt = 0; uint32_t img11Cnt = 0; bool img00Lock = false; bool img01Lock = false; bool img10Lock = false; bool img11Lock = false; uint32_t* relevantBootCnt = &img00Cnt; bool bootFlag = false; xsc::Chip lastChip = xsc::Chip::CHIP_0; xsc::Copy lastCopy = xsc::Copy::COPY_0; xsc::Chip mechanismNextChip = xsc::Chip::NO_CHIP; xsc::Copy mechanismNextCopy = xsc::Copy::NO_COPY; }; class RebootWatchdogPacket : public SerialLinkedListAdapter { public: RebootWatchdogPacket(RebootWatchdogFile& rf) { enabled = rf.enabled; maxCount = rf.maxCount; img00Count = rf.img00Cnt; img01Count = rf.img01Cnt; img10Count = rf.img10Cnt; img11Count = rf.img11Cnt; img00Lock = rf.img00Lock; img01Lock = rf.img01Lock; img10Lock = rf.img10Lock; img11Lock = rf.img11Lock; lastChip = static_cast(rf.lastChip); lastCopy = static_cast(rf.lastCopy); nextChip = static_cast(rf.mechanismNextChip); nextCopy = static_cast(rf.mechanismNextCopy); setLinks(); } private: void setLinks() { setStart(&enabled); enabled.setNext(&maxCount); maxCount.setNext(&img00Count); img00Count.setNext(&img01Count); img01Count.setNext(&img10Count); img10Count.setNext(&img11Count); img11Count.setNext(&img00Lock); img00Lock.setNext(&img01Lock); img01Lock.setNext(&img10Lock); img10Lock.setNext(&img11Lock); img11Lock.setNext(&lastChip); lastChip.setNext(&lastCopy); lastCopy.setNext(&nextChip); nextChip.setNext(&nextCopy); setLast(&nextCopy); } SerializeElement enabled = false; SerializeElement maxCount = 0; SerializeElement img00Count = 0; SerializeElement img01Count = 0; SerializeElement img10Count = 0; SerializeElement img11Count = 0; SerializeElement img00Lock = false; SerializeElement img01Lock = false; SerializeElement img10Lock = false; SerializeElement img11Lock = false; SerializeElement lastChip = 0; SerializeElement lastCopy = 0; SerializeElement nextChip = 0; SerializeElement nextCopy = 0; }; struct RebootCountersFile { // 16 bit values so all boot counters fit into one event. uint16_t img00Cnt = 0; uint16_t img01Cnt = 0; uint16_t img10Cnt = 0; uint16_t img11Cnt = 0; }; class RebootCountersPacket : public SerialLinkedListAdapter { RebootCountersPacket(RebootCountersFile& rf) { img00Count = rf.img00Cnt; img01Count = rf.img01Cnt; img10Count = rf.img10Cnt; img11Count = rf.img11Cnt; setLinks(); } private: void setLinks() { setStart(&img00Count); img00Count.setNext(&img01Count); img01Count.setNext(&img10Count); img10Count.setNext(&img11Count); setLast(&img11Count); } SerializeElement img00Count = 0; SerializeElement img01Count = 0; SerializeElement img10Count = 0; SerializeElement img11Count = 0; }; class CoreController : public ExtendedControllerBase, public ReceivesParameterMessagesIF { public: enum ParamId : uint8_t { PREF_SD = 0, NUM_IDS }; static xsc::Chip CURRENT_CHIP; static xsc::Copy CURRENT_COPY; static constexpr char CHIP_PROT_SCRIPT[] = "get-chip-prot-status.sh"; static constexpr char CHIP_STATE_FILE[] = "/tmp/chip_prot_status.txt"; static constexpr char CURR_COPY_FILE[] = "/tmp/curr_copy.txt"; const std::string VERSION_FILE = "/" + std::string(core::CONF_FOLDER) + "/" + std::string(core::VERSION_FILE_NAME); const std::string LEGACY_REBOOT_WATCHDOG_FILE = "/" + std::string(core::CONF_FOLDER) + "/" + std::string(core::LEGACY_REBOOT_WATCHDOG_FILE_NAME); const std::string REBOOT_WATCHDOG_FILE = "/" + std::string(core::CONF_FOLDER) + "/" + std::string(core::REBOOT_WATCHDOG_FILE_NAME); const std::string LEAP_SECONDS_FILE = "/" + std::string(core::CONF_FOLDER) + "/" + std::string(core::LEAP_SECONDS_FILE_NAME); const std::string BACKUP_TIME_FILE = "/" + std::string(core::CONF_FOLDER) + "/" + std::string(core::TIME_FILE_NAME); const std::string REBOOT_COUNTERS_FILE = "/" + std::string(core::CONF_FOLDER) + "/" + std::string(core::REBOOT_COUNTER_FILE_NAME); static constexpr char CHIP_0_COPY_0_MOUNT_DIR[] = "/tmp/mntupdate-xdi-qspi0-nom-rootfs"; static constexpr char CHIP_0_COPY_1_MOUNT_DIR[] = "/tmp/mntupdate-xdi-qspi0-gold-rootfs"; static constexpr char CHIP_1_COPY_0_MOUNT_DIR[] = "/tmp/mntupdate-xdi-qspi1-nom-rootfs"; static constexpr char CHIP_1_COPY_1_MOUNT_DIR[] = "/tmp/mntupdate-xdi-qspi1-gold-rootfs"; static constexpr char LIST_DIR_DUMP_WORK_FILE[] = "/tmp/dir_listing.tmp"; static constexpr dur_millis_t INIT_SD_CARD_CHECK_TIMEOUT = 5000; static constexpr dur_millis_t DEFAULT_SD_CARD_CHECK_TIMEOUT = 60000; CoreController(object_id_t objectId, bool enableHkSet); virtual ~CoreController(); ReturnValue_t initialize() override; ReturnValue_t initializeAfterTaskCreation() override; ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy, const uint8_t* data, size_t size) override; ReturnValue_t handleCommandMessage(CommandMessage* message) override; void performControlOperation() override; /** * Generate a file containing the chip lock/unlock states inside /tmp/chip_prot_status.txt * @return */ static ReturnValue_t generateChipStateFile(); static ReturnValue_t incrementAllocationFailureCount(); static void getCurrentBootCopy(xsc::Chip& chip, xsc::Copy& copy); static const char* getXscMountDir(xsc::Chip chip, xsc::Copy copy); ReturnValue_t updateProtInfo(bool regenerateChipStateFile = true); /** * Checks whether the target chip and copy are write protected and protect set them to a target * state where applicable. * @param targetChip * @param targetCopy * @param protect Target state * @param protOperationPerformed [out] Can be used to determine whether any operation * was performed * @param updateProtFile Specify whether the protection info file is updated * @return */ ReturnValue_t setBootCopyProtectionAndUpdateFile(xsc::Chip targetChip, xsc::Copy targetCopy, bool protect); bool sdInitFinished() const; private: static constexpr uint32_t BOOT_OFFSET_SECONDS = 15; static constexpr MutexIF::TimeoutType TIMEOUT_TYPE = MutexIF::TimeoutType::WAITING; static constexpr uint32_t MUTEX_TIMEOUT = 20; bool enableHkSet = false; GpsHyperion::FixMode gpsFix = GpsHyperion::FixMode::UNKNOWN; // States for SD state machine, which is used in non-blocking mode enum class SdStates { NONE, START, UPDATE_SD_INFO_START, SKIP_TWO_CYCLES_IF_SD_LOCKED, MOUNT_SELF, // Determine operations for other SD card, depending on redundancy configuration DETERMINE_OTHER, SET_STATE_OTHER, // Mount or unmount other MOUNT_UNMOUNT_OTHER, // Skip period because the shell command used to generate the info file sometimes is // missing the last performed operation if executed too early SKIP_CYCLE_BEFORE_INFO_UPDATE, UPDATE_SD_INFO_END, // SD initialization done IDLE }; enum class SwUpdateSources { SD_0, SD_1, TMP_DIR }; static constexpr bool BLOCKING_SD_INIT = false; uint32_t* mappedSysRomAddr = nullptr; SdCardManager* sdcMan = nullptr; MessageQueueIF* eventQueue = nullptr; uint8_t prefSdRaw = sd::SdCard::SLOT_0; SdStates sdFsmState = SdStates::START; SdStates fsmStateAfterDelay = SdStates::IDLE; enum SdCfgMode { PASSIVE, COLD_REDUNDANT, HOT_REDUNDANT }; struct SdFsmParams { SdCfgMode cfgMode = SdCfgMode::COLD_REDUNDANT; sd::SdCard active = sd::SdCard::NONE; sd::SdCard other = sd::SdCard::NONE; std::string activeChar = "0"; std::string otherChar = "1"; sd::SdState activeState = sd::SdState::OFF; sd::SdState otherState = sd::SdState::OFF; std::pair mountSwitch = {true, true}; // This flag denotes that the SD card usage is locked. This is relevant if SD cards go off // to leave appliation using the SD cards some time to detect the SD card is not usable anymore. // This is relevant if the active SD card is being switched. The SD card will also be locked // when going from hot-redundant mode to cold-redundant mode. bool lockSdCardUsage = false; bool commandPending = true; bool initFinished = false; SdCardManager::SdStatePair currentState; uint16_t cycleCount = 0; uint16_t skippedCyclesCount = 0; } sdInfo; struct SdCommanding { bool cmdPending = false; MessageQueueId_t commander = MessageQueueIF::NO_QUEUE; DeviceCommandId_t actionId; } sdCommandingInfo; struct DirListingDumpContext { bool active; bool firstDump; size_t dumpedBytes; size_t totalFileSize; size_t listingDataOffset; size_t maxDumpLen; uint32_t segmentIdx; MessageQueueId_t commander = MessageQueueIF::NO_QUEUE; DeviceCommandId_t actionId; }; std::array dirListingBuf{}; DirListingDumpContext dumpContext{}; RebootWatchdogFile rebootWatchdogFile = {}; RebootCountersFile rebootCountersFile = {}; CommandExecutor cmdExecutor; SimpleRingBuffer cmdReplyBuf; DynamicFIFO cmdRepliesSizes; bool shellCmdIsExecuting = false; MessageQueueId_t successRecipient = MessageQueueIF::NO_QUEUE; std::string currMntPrefix; bool timeFileInitDone = false; bool leapSecondsInitDone = false; bool performOneShotSdCardOpsSwitch = false; uint8_t shortSdCardCdCounter = 0; #if OBSW_THREAD_TRACING == 1 uint32_t opCounter; #endif Countdown sdCardCheckCd = Countdown(INIT_SD_CARD_CHECK_TIMEOUT); /** * First index: Chip. * Second index: Copy. */ bool protArray[2][2]{}; PeriodicOperationDivider opDivider5; PeriodicOperationDivider opDivider10; PoolEntry tempPoolEntry = PoolEntry(0.0); PoolEntry psVoltageEntry = PoolEntry(0.0); PoolEntry plVoltageEntry = PoolEntry(0.0); core::HkSet hkSet; ParameterHelper paramHelper; #if OBSW_SD_CARD_MUST_BE_ON == 1 bool remountAttemptFlag = true; #endif MessageQueueId_t getCommandQueue() const override; ReturnValue_t getParameter(uint8_t domainId, uint8_t uniqueIdentifier, ParameterWrapper* parameterWrapper, const ParameterWrapper* newValues, uint16_t startAtIndex) override; ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, LocalDataPoolManager& poolManager) override; LocalPoolDataSetBase* getDataSetHandle(sid_t sid) override; ReturnValue_t checkModeCommand(Mode_t mode, Submode_t submode, uint32_t* msToReachTheMode); void performMountedSdCardOperations(); ReturnValue_t initVersionFile(); void initLeapSeconds(); ReturnValue_t initLeapSecondsFromFile(); ReturnValue_t initClockFromTimeFile(); ReturnValue_t actionUpdateLeapSeconds(const uint8_t* data); ReturnValue_t writeLeapSecondsToFile(const uint16_t leapSeconds); ReturnValue_t performSdCardCheck(); ReturnValue_t backupTimeFileHandler(); ReturnValue_t initBootCopyFile(); ReturnValue_t initSdCardBlocking(); bool startSdStateMachine(sd::SdCard targetActiveSd, SdCfgMode mode, MessageQueueId_t commander, DeviceCommandId_t actionId); void initPrint(); ReturnValue_t sdStateMachine(); void updateInternalSdInfo(); ReturnValue_t sdCardSetup(sd::SdCard sdCard, sd::SdState targetState, std::string sdChar, bool printOutput = true); ReturnValue_t executeSwUpdate(SwUpdateSources sourceDir, const uint8_t* data, size_t size); ReturnValue_t sdColdRedundantBlockingInit(); void currentStateSetter(sd::SdCard sdCard, sd::SdState newState); void executeNextExternalSdCommand(); void checkExternalSdCommandStatus(); void performRebootWatchdogHandling(bool recreateFile); void performRebootCountersHandling(bool recreateFile); ReturnValue_t actionListDirectoryIntoFile(ActionId_t actionId, MessageQueueId_t commandedBy, const uint8_t* data, size_t size); ReturnValue_t actionListDirectoryDumpDirectly(ActionId_t actionId, MessageQueueId_t commandedBy, const uint8_t* data, size_t size); ReturnValue_t performGracefulShutdown(xsc::Chip targetChip, xsc::Copy targetCopy); ReturnValue_t actionListDirectoryCommonCommandCreator(const uint8_t* data, size_t size, std::ostringstream& oss); ReturnValue_t actionXscReboot(const uint8_t* data, size_t size); ReturnValue_t actionReboot(const uint8_t* data, size_t size); ReturnValue_t gracefulShutdownTasks(xsc::Chip chip, xsc::Copy copy, bool& protOpPerformed); ReturnValue_t handleProtInfoUpdateLine(std::string nextLine); ReturnValue_t handleSwitchingSdCardsOffNonBlocking(); bool handleBootCopyProt(xsc::Chip targetChip, xsc::Copy targetCopy, bool protect); void rebootWatchdogAlgorithm(RebootWatchdogFile& rf, bool& needsReboot, xsc::Chip& tgtChip, xsc::Copy& tgtCopy); void resetRebootWatchdogCounters(xsc::Chip tgtChip, xsc::Copy tgtCopy); void setRebootMechanismLock(bool lock, xsc::Chip tgtChip, xsc::Copy tgtCopy); bool parseRebootWatchdogFile(std::string path, RebootWatchdogFile& file); bool parseRebootCountersFile(std::string path, RebootCountersFile& file); void rewriteRebootWatchdogFile(RebootWatchdogFile file); void rewriteRebootCountersFile(RebootCountersFile file); void announceBootCounts(); void announceVersionInfo(); void announceCurrentImageInfo(); void announceSdInfo(SdCardManager::SdStatePair sdStates); void readHkData(); void dirListingDumpHandler(); bool isNumber(const std::string& s); }; #endif /* BSP_Q7S_CORE_CORECONTROLLER_H_ */