#ifndef BSP_Q7S_CORE_CORECONTROLLER_H_ #define BSP_Q7S_CORE_CORECONTROLLER_H_ #include #include #include #include #include #include #include #include "CoreDefinitions.h" #include "OBSWConfig.h" #include "bsp_q7s/fs/SdCardManager.h" #include "events/subsystemIdRanges.h" #include "fsfw/controller/ExtendedControllerBase.h" #include "mission/trace.h" class Timer; class SdCardManager; namespace xsc { enum Chip : int { CHIP_0, CHIP_1, NO_CHIP, SELF_CHIP, ALL_CHIP }; enum Copy : int { COPY_0, COPY_1, NO_COPY, SELF_COPY, ALL_COPY }; } // namespace xsc struct RebootFile { 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 CoreController : public ExtendedControllerBase { public: 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"; static constexpr char CONF_FOLDER[] = "conf"; static constexpr char VERSION_FILE_NAME[] = "version.txt"; static constexpr char REBOOT_FILE_NAME[] = "reboot.txt"; static constexpr char TIME_FILE_NAME[] = "time_backup.txt"; const std::string VERSION_FILE = "/" + std::string(CONF_FOLDER) + "/" + std::string(VERSION_FILE_NAME); const std::string REBOOT_FILE = "/" + std::string(CONF_FOLDER) + "/" + std::string(REBOOT_FILE_NAME); const std::string BACKUP_TIME_FILE = "/" + std::string(CONF_FOLDER) + "/" + std::string(TIME_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 dur_millis_t INIT_SD_CARD_CHECK_TIMEOUT = 5000; static constexpr dur_millis_t DEFAULT_SD_CARD_CHECK_TIMEOUT = 60000; static constexpr ActionId_t LIST_DIRECTORY_INTO_FILE = 0; static constexpr ActionId_t ANNOUNCE_VERSION = 1; static constexpr ActionId_t ANNOUNCE_CURRENT_IMAGE = 2; static constexpr ActionId_t ANNOUNCE_BOOT_COUNTS = 3; static constexpr ActionId_t SWITCH_REBOOT_FILE_HANDLING = 5; static constexpr ActionId_t RESET_REBOOT_COUNTERS = 6; static constexpr ActionId_t SWITCH_IMG_LOCK = 7; static constexpr ActionId_t SET_MAX_REBOOT_CNT = 8; static constexpr ActionId_t OBSW_UPDATE_FROM_SD_0 = 10; static constexpr ActionId_t OBSW_UPDATE_FROM_SD_1 = 11; static constexpr ActionId_t OBSW_UPDATE_FROM_TMP = 12; static constexpr ActionId_t SWITCH_TO_SD_0 = 16; static constexpr ActionId_t SWITCH_TO_SD_1 = 17; static constexpr ActionId_t SWITCH_TO_BOTH_SD_CARDS = 18; //! Reboot using the xsc_boot_copy command static constexpr ActionId_t XSC_REBOOT_OBC = 32; static constexpr ActionId_t MOUNT_OTHER_COPY = 33; //! Reboot using the reboot command static constexpr ActionId_t REBOOT_OBC = 34; static constexpr ActionId_t EXECUTE_SHELL_CMD = 40; static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::CORE; static constexpr Event ALLOC_FAILURE = event::makeEvent(SUBSYSTEM_ID, 0, severity::MEDIUM); //! [EXPORT] : [COMMENT] Software reboot occurred. Can also be a systemd reboot. //! P1: Current Chip, P2: Current Copy static constexpr Event REBOOT_SW = event::makeEvent(SUBSYSTEM_ID, 1, severity::LOW); //! [EXPORT] : [COMMENT] The reboot mechanism was triggered. //! P1: First 16 bits: Last Chip, Last 16 bits: Last Copy, //! P2: Each byte is the respective reboot count for the slots static constexpr Event REBOOT_MECHANISM_TRIGGERED = event::makeEvent(SUBSYSTEM_ID, 2, severity::MEDIUM); //! Trying to find a way how to determine that the reboot came from ProASIC3 or PCDU.. static constexpr Event REBOOT_HW = event::makeEvent(SUBSYSTEM_ID, 3, severity::MEDIUM); //! [EXPORT] : [COMMENT] No SD card was active. Core controller will attempt to re-initialize //! a SD card. static constexpr Event NO_SD_CARD_ACTIVE = event::makeEvent(SUBSYSTEM_ID, 4, severity::HIGH); //! [EXPORT] : [COMMENT] //! P1: Byte 0: Major, Byte 1: Minor, Byte 2: Patch, Byte 3: Has Git Hash //! P2: First four letters of Git SHA is the last byte of P1 is set. static constexpr Event VERSION_INFO = event::makeEvent(SUBSYSTEM_ID, 5, severity::INFO); //! [EXPORT] : [COMMENT] P1: Current Chip, P2: Current Copy static constexpr Event CURRENT_IMAGE_INFO = event::makeEvent(SUBSYSTEM_ID, 6, severity::INFO); //! [EXPORT] : [COMMENT] Total reboot counter, which is the sum of the boot count of all //! individual images. static constexpr Event REBOOT_COUNTER = event::makeEvent(SUBSYSTEM_ID, 7, severity::INFO); //! [EXPORT] : [COMMENT] Get the boot count of the individual images. //! P1: First 16 bits boot count of image 0 0, last 16 bits boot count of image 0 1. //! P2: First 16 bits boot count of image 1 0, last 16 bits boot count of image 1 1. static constexpr Event INDIVIDUAL_BOOT_COUNTS = event::makeEvent(SUBSYSTEM_ID, 8, severity::INFO); static constexpr Event I2C_UNAVAILABLE_REBOOT = event::makeEvent(SUBSYSTEM_ID, 10, severity::MEDIUM); CoreController(object_id_t objectId, const std::atomic_uint16_t& i2cErrors); 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 setBootCopyProtection(xsc::Chip targetChip, xsc::Copy targetCopy, bool protect, bool& protOperationPerformed, bool updateProtFile = true); 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; GpsHyperion::FixMode gpsFix = GpsHyperion::FixMode::UNKNOWN; // States for SD state machine, which is used in non-blocking mode enum class SdStates { NONE, START, GET_INFO, SET_STATE_SELF, 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_INFO, // SD initialization done IDLE }; enum class SwUpdateSources { SD_0, SD_1, TMP_DIR }; static constexpr bool BLOCKING_SD_INIT = false; SdCardManager* sdcMan = nullptr; MessageQueueIF* eventQueue = nullptr; SdStates sdFsmState = SdStates::START; 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; sd::SdState activeState = sd::SdState::OFF; sd::SdState otherState = sd::SdState::OFF; std::string activeChar = "0"; std::string otherChar = "1"; std::pair mountSwitch = {true, true}; // Used to track whether a command was executed bool commandExecuted = true; bool initFinished = false; SdCardManager::SdStatePair currentState; uint16_t cycleCount = 0; } sdInfo; struct SdCommanding { bool cmdPending = false; MessageQueueId_t commander = MessageQueueIF::NO_QUEUE; DeviceCommandId_t actionId; } sdCommandingInfo; RebootFile rebootFile = {}; CommandExecutor cmdExecutor; SimpleRingBuffer cmdReplyBuf; DynamicFIFO cmdRepliesSizes; bool shellCmdIsExecuting = false; MessageQueueId_t successRecipient = MessageQueueIF::NO_QUEUE; std::string currMntPrefix; bool timeFileInitDone = 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); /** * Index 0: Chip 0 Copy 0 * Index 1: Chip 0 Copy 1 * Index 2: Chip 1 Copy 0 * Index 3: Chip 1 Copy 1 */ std::array protArray; PeriodicOperationDivider opDivider5; PeriodicOperationDivider opDivider10; PoolEntry tempPoolEntry = PoolEntry(0.0); PoolEntry psVoltageEntry = PoolEntry(0.0); PoolEntry plVoltageEntry = PoolEntry(0.0); core::HkSet hkSet; const std::atomic_uint16_t& i2cErrors; #if OBSW_SD_CARD_MUST_BE_ON == 1 bool remountAttemptFlag = true; #endif 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(); ReturnValue_t initClockFromTimeFile(); 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 updateSdInfoOther(); 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 performRebootFileHandling(bool recreateFile); ReturnValue_t actionListDirectoryIntoFile(ActionId_t actionId, MessageQueueId_t commandedBy, const uint8_t* data, size_t size); 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); int handleBootCopyProtAtIndex(xsc::Chip targetChip, xsc::Copy targetCopy, bool protect, bool& protOperationPerformed, bool selfChip, bool selfCopy, bool allChips, bool allCopies, uint8_t arrIdx); void determineAndExecuteReboot(RebootFile& rf, bool& needsReboot, xsc::Chip& tgtChip, xsc::Copy& tgtCopy); void resetRebootCount(xsc::Chip tgtChip, xsc::Copy tgtCopy); void setRebootMechanismLock(bool lock, xsc::Chip tgtChip, xsc::Copy tgtCopy); bool parseRebootFile(std::string path, RebootFile& file); void rewriteRebootFile(RebootFile file); void announceBootCounts(); void readHkData(); bool isNumber(const std::string& s); }; #endif /* BSP_Q7S_CORE_CORECONTROLLER_H_ */