#ifndef MISSION_DEVICES_SOLARARRAYDEPLOYMENT_H_ #define MISSION_DEVICES_SOLARARRAYDEPLOYMENT_H_ #include #include #include "devices/powerSwitcherList.h" #include "eive/definitions.h" #include "events/subsystemIdRanges.h" #include "fsfw/action/HasActionsIF.h" #include "fsfw/devicehandlers/CookieIF.h" #include "fsfw/devicehandlers/DeviceHandlerIF.h" #include "fsfw/objectmanager/SystemObject.h" #include "fsfw/power/PowerSwitchIF.h" #include "fsfw/returnvalues/returnvalue.h" #include "fsfw/serialize/SerialLinkedListAdapter.h" #include "fsfw/tasks/ExecutableObjectIF.h" #include "fsfw/timemanager/Countdown.h" #include "fsfw_hal/common/gpio/GpioIF.h" #include "mission/memory/SdCardMountedIF.h" #include "mission/trace.h" #include "returnvalues/classIds.h" enum DeploymentChannels : uint8_t { SA_1 = 1, SA_2 = 2 }; class ManualDeploymentCommand : public SerialLinkedListAdapter { public: ManualDeploymentCommand() { setLinks(); } void setLinks() { setStart(&burnTimeSecs); burnTimeSecs.setNext(&switchIntervalMs); switchIntervalMs.setNext(&initChannel); initChannel.setNext(&dryRun); } uint32_t getBurnTimeSecs() const { return burnTimeSecs.entry; } uint32_t getSwitchIntervalMs() const { return switchIntervalMs.entry; }; uint8_t getInitChannel() const { return initChannel.entry; }; bool isDryRun() const { return dryRun.entry; } private: SerializeElement burnTimeSecs; SerializeElement switchIntervalMs; SerializeElement initChannel; SerializeElement dryRun; }; /** * @brief This class is used to control the solar array deployment. * * @author J. Meier */ class SolarArrayDeploymentHandler : public ExecutableObjectIF, public SystemObject, public HasActionsIF { public: //! Manual deployment of the solar arrays. Burn time, channel switch interval, initial //! burn channel and dry run flag are supplied as parameters. There are following cases to //! consider. //! //! - Channel switch interval greater or equal to burn time: Only burn one channel. The init //! burn channel parameter can be used to select which channel is burned. //! - Channel switch interval half of burn time: Burn each channel for half of the burn time. //! //! The dry run flag can be used to avoid actually toggling IO pins and only test the //! application logic. static constexpr DeviceCommandId_t DEPLOY_SOLAR_ARRAYS_MANUALLY = 0x05; static constexpr DeviceCommandId_t SWITCH_OFF_DEPLOYMENT = 0x06; static constexpr uint32_t FIRST_BURN_START_TIME = config::SA_DEPL_INIT_BUFFER_SECS; static constexpr uint32_t FIRST_BURN_END_TIME = FIRST_BURN_START_TIME + config::SA_DEPL_BURN_TIME_SECS; static constexpr uint32_t WAIT_START_TIME = FIRST_BURN_END_TIME; static constexpr uint32_t WAIT_END_TIME = WAIT_START_TIME + config::SA_DEPL_WAIT_TIME_SECS; static constexpr uint32_t SECOND_BURN_START_TIME = WAIT_END_TIME; static constexpr uint32_t SECOND_BURN_END_TIME = SECOND_BURN_START_TIME + config::SA_DEPL_WAIT_TIME_SECS; static constexpr char SD_0_DEPL_FILE[] = "/mnt/sd0/conf/deployment"; static constexpr char SD_1_DEPL_FILE[] = "/mnt/sd1/conf/deployment"; static constexpr char SD_0_DEPLY_INFO[] = "/mnt/sd0/conf/deployment_info.txt"; static constexpr char SD_1_DEPLY_INFO[] = "/mnt/sd1/conf/deployment_info.txt"; static constexpr char PHASE_INIT_STR[] = "init"; static constexpr char PHASE_FIRST_BURN_STR[] = "first_burn"; static constexpr char PHASE_WAIT_STR[] = "wait"; static constexpr char PHASE_SECOND_BURN_STR[] = "second_burn"; static constexpr char PHASE_DONE[] = "done"; /** * @brief constructor * * @param setObjectId The object id of the SolarArrayDeploymentHandler. * @param gpioDriverId The id of the gpio com if. * @param gpioCookie GpioCookie holding information about the gpios used to switch the * transistors. * @param mainLineSwitcherObjectId The object id of the object responsible for switching * the 8V power source. This is normally the PCDU. * @param mainLineSwitch The id of the main line switch. This is defined in * powerSwitcherList.h. * @param deplSA1 gpioId of the GPIO controlling the deployment 1 transistor. * @param deplSA2 gpioId of the GPIO controlling the deployment 2 transistor. * @param burnTimeMs Time duration the power will be applied to the burn wires. */ SolarArrayDeploymentHandler(object_id_t setObjectId, GpioIF& gpio, PowerSwitchIF& mainLineSwitcher, power::Switches mainLineSwitch, gpioId_t deplSA1, gpioId_t deplSA2, SdCardMountedIF& sdcMountedIF); virtual ~SolarArrayDeploymentHandler(); virtual ReturnValue_t performOperation(uint8_t operationCode = 0) override; virtual MessageQueueId_t getCommandQueue() const override; virtual ReturnValue_t executeAction(ActionId_t actionId, MessageQueueId_t commandedBy, const uint8_t* data, size_t size) override; virtual ReturnValue_t initialize() override; private: enum AutonomousDeplState { INIT, FIRST_BURN, WAIT, SECOND_BURN, DONE }; enum StateMachine { IDLE, MAIN_POWER_ON, MAIN_POWER_OFF, WAIT_MAIN_POWER_ON, WAIT_MAIN_POWER_OFF, SWITCH_DEPL_GPIOS, BURNING }; struct FsmInfo { // Not required anymore // DeploymentChannels channel; bool dryRun; bool alternationDummy = false; uint8_t initChannel = 0; uint32_t burnCountdownMs = config::SA_DEPL_MAX_BURN_TIME; }; static const uint8_t INTERFACE_ID = CLASS_ID::SA_DEPL_HANDLER; static const ReturnValue_t COMMAND_NOT_SUPPORTED = MAKE_RETURN_CODE(0xA0); static const ReturnValue_t DEPLOYMENT_ALREADY_EXECUTING = MAKE_RETURN_CODE(0xA1); static const ReturnValue_t MAIN_SWITCH_TIMEOUT_FAILURE = MAKE_RETURN_CODE(0xA2); static const ReturnValue_t SWITCHING_DEPL_SA1_FAILED = MAKE_RETURN_CODE(0xA3); static const ReturnValue_t SWITCHING_DEPL_SA2_FAILED = MAKE_RETURN_CODE(0xA4); static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SA_DEPL_HANDLER; //! [EXPORT] : [COMMENT] P1: Burn duration in milliseconds, P2: Dry run flag static constexpr Event BURN_PHASE_START = event::makeEvent(SUBSYSTEM_ID, 0, severity::INFO); //! [EXPORT] : [COMMENT] P1: Burn duration in milliseconds, P2: Dry run flag static constexpr Event BURN_PHASE_DONE = event::makeEvent(SUBSYSTEM_ID, 1, severity::INFO); static constexpr Event MAIN_SWITCH_ON_TIMEOUT = event::makeEvent(SUBSYSTEM_ID, 2, severity::LOW); static constexpr Event MAIN_SWITCH_OFF_TIMEOUT = event::makeEvent(SUBSYSTEM_ID, 3, severity::LOW); static constexpr Event DEPL_SA1_GPIO_SWTICH_ON_FAILED = event::makeEvent(SUBSYSTEM_ID, 4, severity::HIGH); static constexpr Event DEPL_SA2_GPIO_SWTICH_ON_FAILED = event::makeEvent(SUBSYSTEM_ID, 5, severity::HIGH); static constexpr Event DEPL_SA1_GPIO_SWTICH_OFF_FAILED = event::makeEvent(SUBSYSTEM_ID, 6, severity::HIGH); static constexpr Event DEPL_SA2_GPIO_SWTICH_OFF_FAILED = event::makeEvent(SUBSYSTEM_ID, 7, severity::HIGH); static constexpr Event AUTONOMOUS_DEPLOYMENT_COMPLETED = event::makeEvent(SUBSYSTEM_ID, 8, severity::INFO); FsmInfo fsmInfo; StateMachine stateMachine = IDLE; bool actionActive = false; bool firstAutonomousCycle = true; ActionId_t activeCmd = HasActionsIF::INVALID_ACTION_ID; std::optional initUptime; #if OBSW_THREAD_TRACING == 1 uint32_t opCounter = 0; #endif PeriodicOperationDivider opDivider = PeriodicOperationDivider(5); uint8_t retryCounter = 3; bool startFsmOn(uint32_t burnCountdownSecs, uint32_t channelAlternationIntervalMs, uint8_t initChannel, bool dryRun); void startFsmOff(); void finishFsm(ReturnValue_t resultForActionHelper); ReturnValue_t performAutonomousDepl(sd::SdCard sdCard, bool dryRun); bool dryRunStringInFile(const char* filename); bool autonomousDeplForFile(sd::SdCard sdCard, const char* filename, bool dryRun); /** * This countdown is used to check if the PCDU sets the 8V line on in the intended time. */ Countdown mainSwitchCountdown; /** * This countdown is used to wait for the burn wire being successful cut. */ Countdown burnCountdown; // Only initial value, new approach is to burn each channel half of the total burn time. Countdown channelAlternationCd = Countdown(config::LEGACY_SA_DEPL_CHANNEL_ALTERNATION_INTERVAL_SECS * 1000); /** * The message queue id of the component commanding an action will be stored in this variable. * This is necessary to send later the action finish replies. */ MessageQueueId_t rememberCommanderId = 0; /** Size of command queue */ size_t cmdQueueSize = 20; GpioIF& gpioInterface; gpioId_t deplSA1; gpioId_t deplSA2; /** * After initialization this pointer will hold the reference to the main line switcher object. */ PowerSwitchIF& mainLineSwitcher; /** Switch number of the 8V power switch */ uint8_t mainLineSwitch; SdCardMountedIF& sdcMan; ActionHelper actionHelper; /** Queue to receive messages from other objects. */ MessageQueueIF* commandQueue = nullptr; void readCommandQueue(); /** * @brief This function performs actions dependent on the current state. */ void handleStateMachine(); /** * @brief This function polls the 8V switch state and changes the state machine when the * switch has been enabled. */ bool checkMainPowerOn(); bool checkMainPowerOff(); bool checkMainPower(bool onOff); void allOff(); ReturnValue_t deploymentTransistorsOff(); ReturnValue_t saGpioAlternation(); ReturnValue_t sa1On(); ReturnValue_t sa1Off(); ReturnValue_t sa2On(); ReturnValue_t sa2Off(); }; #endif /* MISSION_DEVICES_SOLARARRAYDEPLOYMENT_H_ */