Merge pull request 'Solar Array Deployment Update' (#305) from mueller/solar-array-depl-autonomous into develop
All checks were successful
EIVE/eive-obsw/pipeline/head This commit looks good

Reviewed-on: #305
This commit is contained in:
Robin Müller 2022-10-17 10:26:08 +02:00
commit 81696b334c
18 changed files with 721 additions and 307 deletions

View File

@ -20,7 +20,6 @@
// Set to 1 if telecommands are received via the PDEC IP Core // Set to 1 if telecommands are received via the PDEC IP Core
#define OBSW_TC_FROM_PDEC 0 #define OBSW_TC_FROM_PDEC 0
#define OBSW_ENABLE_TIMERS 1
#define OBSW_ADD_GOMSPACE_PCDU @OBSW_ADD_GOMSPACE_PCDU@ #define OBSW_ADD_GOMSPACE_PCDU @OBSW_ADD_GOMSPACE_PCDU@
#define OBSW_ADD_MGT @OBSW_ADD_MGT@ #define OBSW_ADD_MGT @OBSW_ADD_MGT@
#define OBSW_ADD_BPX_BATTERY_HANDLER @OBSW_ADD_BPX_BATTERY_HANDLER@ #define OBSW_ADD_BPX_BATTERY_HANDLER @OBSW_ADD_BPX_BATTERY_HANDLER@
@ -41,7 +40,11 @@
#define OBSW_ADD_PL_PCDU @OBSW_ADD_PL_PCDU@ #define OBSW_ADD_PL_PCDU @OBSW_ADD_PL_PCDU@
#define OBSW_ADD_SYRLINKS @OBSW_ADD_SYRLINKS@ #define OBSW_ADD_SYRLINKS @OBSW_ADD_SYRLINKS@
#define OBSW_ENABLE_SYRLINKS_TRANSMIT_TIMEOUT 0 #define OBSW_ENABLE_SYRLINKS_TRANSMIT_TIMEOUT 0
#define OBSW_MPSOC_JTAG_BOOT 0
// Configuration parameter which causes the core controller to try to keep at least one SD card
// working
#define OBSW_SD_CARD_MUST_BE_ON 1
#define OBSW_ENABLE_TIMERS 1
// This is a really tricky switch.. It initializes the PCDU switches to their default states // This is a really tricky switch.. It initializes the PCDU switches to their default states
// at powerup. I think it would be better // at powerup. I think it would be better
@ -59,6 +62,7 @@
#define OBSW_SWITCH_TO_NORMAL_MODE_AFTER_STARTUP 1 #define OBSW_SWITCH_TO_NORMAL_MODE_AFTER_STARTUP 1
#define OBSW_PRINT_MISSED_DEADLINES 1 #define OBSW_PRINT_MISSED_DEADLINES 1
#define OBSW_MPSOC_JTAG_BOOT 0
#define OBSW_STAR_TRACKER_GROUND_CONFIG 1 #define OBSW_STAR_TRACKER_GROUND_CONFIG 1
#define OBSW_SYRLINKS_SIMULATED 1 #define OBSW_SYRLINKS_SIMULATED 1
#define OBSW_ADD_TEST_CODE 0 #define OBSW_ADD_TEST_CODE 0

View File

@ -4,7 +4,6 @@
#include <fsfw/filesystem/HasFileSystemIF.h> #include <fsfw/filesystem/HasFileSystemIF.h>
#include <fsfw/ipc/QueueFactory.h> #include <fsfw/ipc/QueueFactory.h>
#include "OBSWConfig.h"
#include "OBSWVersion.h" #include "OBSWVersion.h"
#include "fsfw/serviceinterface/ServiceInterface.h" #include "fsfw/serviceinterface/ServiceInterface.h"
#include "fsfw/timemanager/Stopwatch.h" #include "fsfw/timemanager/Stopwatch.h"
@ -1243,16 +1242,16 @@ void CoreController::performMountedSdCardOperations() {
} }
timeFileHandler(); timeFileHandler();
}; };
bool clearOneShotFlag = false; bool someSdCardActive = false;
if (sdInfo.active == sd::SdCard::SLOT_0 and sdcMan->isSdCardUsable(sd::SdCard::SLOT_0)) { if (sdInfo.active == sd::SdCard::SLOT_0 and sdcMan->isSdCardUsable(sd::SdCard::SLOT_0)) {
mountedSdCardOp(sd::SdCard::SLOT_0, config::SD_0_MOUNT_POINT); mountedSdCardOp(sd::SdCard::SLOT_0, config::SD_0_MOUNT_POINT);
clearOneShotFlag = true; someSdCardActive = true;
} }
if (sdInfo.active == sd::SdCard::SLOT_1 and sdcMan->isSdCardUsable(sd::SdCard::SLOT_1)) { if (sdInfo.active == sd::SdCard::SLOT_1 and sdcMan->isSdCardUsable(sd::SdCard::SLOT_1)) {
mountedSdCardOp(sd::SdCard::SLOT_1, config::SD_1_MOUNT_POINT); mountedSdCardOp(sd::SdCard::SLOT_1, config::SD_1_MOUNT_POINT);
clearOneShotFlag = true; someSdCardActive = true;
} }
if (clearOneShotFlag) { if (someSdCardActive) {
performOneShotSdCardOpsSwitch = true; performOneShotSdCardOpsSwitch = true;
} }
} }
@ -1295,7 +1294,19 @@ ReturnValue_t CoreController::performSdCardCheck() {
if (active.second == sd::SdState::MOUNTED) { if (active.second == sd::SdState::MOUNTED) {
sdCardCheck(sd::SdCard::SLOT_1); sdCardCheck(sd::SdCard::SLOT_1);
} }
#if OBSW_SD_CARD_MUST_BE_ON == 1
// This is FDIR. The core controller will attempt once to get some SD card working
bool someSdCardActive = false;
if ((sdInfo.active == sd::SdCard::SLOT_0 and sdcMan->isSdCardUsable(sd::SdCard::SLOT_0)) or
(sdInfo.active == sd::SdCard::SLOT_1 and sdcMan->isSdCardUsable(sd::SdCard::SLOT_1))) {
someSdCardActive = true;
}
if (not someSdCardActive and remountAttemptFlag) {
triggerEvent(NO_SD_CARD_ACTIVE);
initSdCardBlocking();
remountAttemptFlag = false;
}
#endif
return returnvalue::OK; return returnvalue::OK;
} }

View File

@ -7,6 +7,7 @@
#include <cstddef> #include <cstddef>
#include "CoreDefinitions.h" #include "CoreDefinitions.h"
#include "OBSWConfig.h"
#include "bsp_q7s/fs/SdCardManager.h" #include "bsp_q7s/fs/SdCardManager.h"
#include "events/subsystemIdRanges.h" #include "events/subsystemIdRanges.h"
#include "fsfw/controller/ExtendedControllerBase.h" #include "fsfw/controller/ExtendedControllerBase.h"
@ -102,6 +103,9 @@ class CoreController : public ExtendedControllerBase {
event::makeEvent(SUBSYSTEM_ID, 2, severity::MEDIUM); event::makeEvent(SUBSYSTEM_ID, 2, severity::MEDIUM);
//! Trying to find a way how to determine that the reboot came from ProASIC3 or PCDU.. //! 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); 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);
CoreController(object_id_t objectId); CoreController(object_id_t objectId);
virtual ~CoreController(); virtual ~CoreController();
@ -219,6 +223,10 @@ class CoreController : public ExtendedControllerBase {
core::HkSet hkSet; core::HkSet hkSet;
#if OBSW_SD_CARD_MUST_BE_ON == 1
bool remountAttemptFlag = true;
#endif
ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap,
LocalDataPoolManager& poolManager) override; LocalDataPoolManager& poolManager) override;
Countdown sdCardCheckCd = Countdown(120000); Countdown sdCardCheckCd = Countdown(120000);

View File

@ -67,16 +67,30 @@ void initmission::initTasks() {
void (*missedDeadlineFunc)(void) = nullptr; void (*missedDeadlineFunc)(void) = nullptr;
#endif #endif
PeriodicTaskIF* coreController = factory->createPeriodicTask( PeriodicTaskIF* sysCtrlTask = factory->createPeriodicTask(
"CORE_CTRL", 60, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.4, missedDeadlineFunc); "CORE_CTRL", 60, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.4, missedDeadlineFunc);
result = coreController->addComponent(objects::CORE_CONTROLLER); result = sysCtrlTask->addComponent(objects::CORE_CONTROLLER);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
initmission::printAddObjectError("CORE_CTRL", objects::CORE_CONTROLLER); initmission::printAddObjectError("CORE_CTRL", objects::CORE_CONTROLLER);
} }
// Could add this to the core controller but the core controller does so many thing that I would
// prefer to have the solar array deployment in a seprate task.
PeriodicTaskIF* solarArrayDeplTask = factory->createPeriodicTask(
"SOLAR_ARRAY_DEPL", 65, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.4, missedDeadlineFunc);
result = solarArrayDeplTask->addComponent(objects::SOLAR_ARRAY_DEPL_HANDLER);
if (result != returnvalue::OK) {
initmission::printAddObjectError("SOLAR_ARRAY_DEPL", objects::SOLAR_ARRAY_DEPL_HANDLER);
}
/* TMTC Distribution */ /* TMTC Distribution */
PeriodicTaskIF* tmTcDistributor = factory->createPeriodicTask( PeriodicTaskIF* tmTcDistributor = factory->createPeriodicTask(
"DIST", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.2, missedDeadlineFunc); "DIST", 45, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.2, missedDeadlineFunc);
#if OBSW_ADD_TCPIP_BRIDGE == 1
result = tmTcDistributor->addComponent(objects::TMTC_BRIDGE);
if (result != returnvalue::OK) {
initmission::printAddObjectError("TMTC_BRIDGE", objects::TMTC_BRIDGE);
}
#endif
result = tmTcDistributor->addComponent(objects::CCSDS_PACKET_DISTRIBUTOR); result = tmTcDistributor->addComponent(objects::CCSDS_PACKET_DISTRIBUTOR);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
initmission::printAddObjectError("CCSDS_DISTRIB", objects::CCSDS_PACKET_DISTRIBUTOR); initmission::printAddObjectError("CCSDS_DISTRIB", objects::CCSDS_PACKET_DISTRIBUTOR);
@ -95,13 +109,6 @@ void initmission::initTasks() {
} }
#if OBSW_ADD_TCPIP_BRIDGE == 1 #if OBSW_ADD_TCPIP_BRIDGE == 1
// TMTC bridge
PeriodicTaskIF* tmtcBridgeTask = factory->createPeriodicTask(
"TCPIP_TMTC_BRIDGE", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.2, missedDeadlineFunc);
result = tmtcBridgeTask->addComponent(objects::TMTC_BRIDGE);
if (result != returnvalue::OK) {
initmission::printAddObjectError("TMTC_BRIDGE", objects::TMTC_BRIDGE);
}
PeriodicTaskIF* tmtcPollingTask = factory->createPeriodicTask( PeriodicTaskIF* tmtcPollingTask = factory->createPeriodicTask(
"TMTC_POLLING", 80, PeriodicTaskIF::MINIMUM_STACK_SIZE, 2.0, missedDeadlineFunc); "TMTC_POLLING", 80, PeriodicTaskIF::MINIMUM_STACK_SIZE, 2.0, missedDeadlineFunc);
result = tmtcPollingTask->addComponent(objects::TMTC_POLLING_TASK); result = tmtcPollingTask->addComponent(objects::TMTC_POLLING_TASK);
@ -138,39 +145,39 @@ void initmission::initTasks() {
} }
#endif #endif
PeriodicTaskIF* acsTask = factory->createPeriodicTask( PeriodicTaskIF* acsCtrlTask = factory->createPeriodicTask(
"ACS_TASK", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE * 2, 0.4, missedDeadlineFunc); "ACS_TASK", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE * 2, 0.4, missedDeadlineFunc);
#if OBSW_ADD_GPS_CTRL == 1 #if OBSW_ADD_GPS_CTRL == 1
result = acsTask->addComponent(objects::GPS_CONTROLLER); result = acsCtrlTask->addComponent(objects::GPS_CONTROLLER);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
initmission::printAddObjectError("GPS_CTRL", objects::GPS_CONTROLLER); initmission::printAddObjectError("GPS_CTRL", objects::GPS_CONTROLLER);
} }
#endif /* OBSW_ADD_GPS_CTRL */ #endif /* OBSW_ADD_GPS_CTRL */
#if OBSW_ADD_ACS_CTRL == 1 #if OBSW_ADD_ACS_CTRL == 1
acsTask->addComponent(objects::ACS_CONTROLLER); acsCtrlTask->addComponent(objects::ACS_CONTROLLER);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
initmission::printAddObjectError("ACS_CTRL", objects::ACS_CONTROLLER); initmission::printAddObjectError("ACS_CTRL", objects::ACS_CONTROLLER);
} }
#endif #endif
PeriodicTaskIF* sysTask = factory->createPeriodicTask( PeriodicTaskIF* acsSysTask = factory->createPeriodicTask(
"SYS_TASK", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE * 2, 0.4, missedDeadlineFunc); "SYS_TASK", 40, PeriodicTaskIF::MINIMUM_STACK_SIZE * 2, 0.4, missedDeadlineFunc);
static_cast<void>(sysTask); static_cast<void>(acsSysTask);
#if OBSW_ADD_ACS_BOARD == 1 #if OBSW_ADD_ACS_BOARD == 1
result = sysTask->addComponent(objects::ACS_BOARD_ASS); result = acsSysTask->addComponent(objects::ACS_BOARD_ASS);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
initmission::printAddObjectError("ACS_BOARD_ASS", objects::ACS_BOARD_ASS); initmission::printAddObjectError("ACS_BOARD_ASS", objects::ACS_BOARD_ASS);
} }
#endif /* OBSW_ADD_ACS_HANDLERS */ #endif /* OBSW_ADD_ACS_HANDLERS */
#if OBSW_ADD_RW == 1 #if OBSW_ADD_RW == 1
result = sysTask->addComponent(objects::RW_ASS); result = acsSysTask->addComponent(objects::RW_ASS);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
initmission::printAddObjectError("RW_ASS", objects::RW_ASS); initmission::printAddObjectError("RW_ASS", objects::RW_ASS);
} }
#endif #endif
#if OBSW_ADD_SUS_BOARD_ASS == 1 #if OBSW_ADD_SUS_BOARD_ASS == 1
result = sysTask->addComponent(objects::SUS_BOARD_ASS); result = acsSysTask->addComponent(objects::SUS_BOARD_ASS);
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
initmission::printAddObjectError("SUS_BOARD_ASS", objects::SUS_BOARD_ASS); initmission::printAddObjectError("SUS_BOARD_ASS", objects::SUS_BOARD_ASS);
} }
@ -211,13 +218,27 @@ void initmission::initTasks() {
tcsTask->addComponent(rtd, DeviceHandlerIF::SEND_READ); tcsTask->addComponent(rtd, DeviceHandlerIF::SEND_READ);
tcsTask->addComponent(rtd, DeviceHandlerIF::GET_READ); tcsTask->addComponent(rtd, DeviceHandlerIF::GET_READ);
} }
tcsTask->addComponent(objects::TCS_BOARD_ASS);
#endif /* OBSW_ADD_RTD_DEVICES */
#if OBSW_ADD_TCS_CTRL == 1
tcsTask->addComponent(objects::THERMAL_CONTROLLER);
#endif #endif
PeriodicTaskIF* tcsSystemTask = factory->createPeriodicTask(
"TCS_TASK", 45, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.5, missedDeadlineFunc);
#if OBSW_ADD_RTD_DEVICES == 1
result = tcsSystemTask->addComponent(objects::TCS_BOARD_ASS);
if (result != returnvalue::OK) {
initmission::printAddObjectError("TCS_BOARD_ASS", objects::TCS_BOARD_ASS);
}
#endif /* OBSW_ADD_RTD_DEVICES */
#if OBSW_ADD_TCS_CTRL == 1
result = tcsSystemTask->addComponent(objects::THERMAL_CONTROLLER);
if (result != returnvalue::OK) {
initmission::printAddObjectError("THERMAL_CONTROLLER", objects::THERMAL_CONTROLLER);
}
#endif
result = tcsSystemTask->addComponent(objects::HEATER_HANDLER);
if (result != returnvalue::OK) {
initmission::printAddObjectError("HEATER_HANDLER", objects::HEATER_HANDLER);
}
#if OBSW_ADD_STAR_TRACKER == 1 #if OBSW_ADD_STAR_TRACKER == 1
PeriodicTaskIF* strHelperTask = factory->createPeriodicTask( PeriodicTaskIF* strHelperTask = factory->createPeriodicTask(
"STR_HELPER", 20, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.2, missedDeadlineFunc); "STR_HELPER", 20, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.2, missedDeadlineFunc);
@ -283,7 +304,6 @@ void initmission::initTasks() {
tmTcDistributor->startTask(); tmTcDistributor->startTask();
#if OBSW_ADD_TCPIP_BRIDGE == 1 #if OBSW_ADD_TCPIP_BRIDGE == 1
tmtcBridgeTask->startTask();
tmtcPollingTask->startTask(); tmtcPollingTask->startTask();
#endif #endif
@ -292,7 +312,8 @@ void initmission::initTasks() {
pdecHandlerTask->startTask(); pdecHandlerTask->startTask();
#endif /* OBSW_USE_CCSDS_IP_CORE == 1 */ #endif /* OBSW_USE_CCSDS_IP_CORE == 1 */
coreController->startTask(); sysCtrlTask->startTask();
solarArrayDeplTask->startTask();
taskStarter(pstTasks, "PST task vector"); taskStarter(pstTasks, "PST task vector");
taskStarter(pusTasks, "PUS task vector"); taskStarter(pusTasks, "PUS task vector");
@ -313,12 +334,13 @@ void initmission::initTasks() {
strHelperTask->startTask(); strHelperTask->startTask();
#endif /* OBSW_ADD_STAR_TRACKER == 1 */ #endif /* OBSW_ADD_STAR_TRACKER == 1 */
acsTask->startTask(); acsCtrlTask->startTask();
sysTask->startTask(); acsSysTask->startTask();
#if OBSW_ADD_RTD_DEVICES == 1 #if OBSW_ADD_RTD_DEVICES == 1
tcsPollingTask->startTask(); tcsPollingTask->startTask();
tcsTask->startTask(); tcsTask->startTask();
#endif /* OBSW_ADD_RTD_DEVICES == 1 */ #endif /* OBSW_ADD_RTD_DEVICES == 1 */
tcsSystemTask->startTask();
#if OBSW_ADD_PLOC_SUPERVISOR == 1 #if OBSW_ADD_PLOC_SUPERVISOR == 1
supvHelperTask->startTask(); supvHelperTask->startTask();
#endif /* OBSW_ADD_PLOC_SUPERVISOR == 1 */ #endif /* OBSW_ADD_PLOC_SUPERVISOR == 1 */
@ -378,18 +400,6 @@ void initmission::createPstTasks(TaskFactory& factory,
taskVec.push_back(uartPst); taskVec.push_back(uartPst);
} }
FixedTimeslotTaskIF* gpioPst = factory.createFixedTimeslotTask(
"GPIO_PST", 70, PeriodicTaskIF::MINIMUM_STACK_SIZE * 2, 0.2, missedDeadlineFunc);
result = pst::pstGpio(gpioPst);
if (result != returnvalue::OK) {
if (result == FixedTimeslotTaskIF::SLOT_LIST_EMPTY) {
sif::warning << "InitMission::initTasks: GPIO PST is empty" << std::endl;
} else {
sif::error << "InitMission::initTasks: Creating GPIO PST failed!" << std::endl;
}
} else {
taskVec.push_back(gpioPst);
}
#if OBSW_ADD_I2C_TEST_CODE == 0 #if OBSW_ADD_I2C_TEST_CODE == 0
FixedTimeslotTaskIF* i2cPst = factory.createFixedTimeslotTask( FixedTimeslotTaskIF* i2cPst = factory.createFixedTimeslotTask(
"I2C_PST", 65, PeriodicTaskIF::MINIMUM_STACK_SIZE * 4, 0.2, missedDeadlineFunc); "I2C_PST", 65, PeriodicTaskIF::MINIMUM_STACK_SIZE * 4, 0.2, missedDeadlineFunc);

View File

@ -539,7 +539,8 @@ void ObjectFactory::createHeaterComponents(GpioIF* gpioIF, PowerSwitchIF* pwrSwi
pcdu::Switches::PDU2_CH3_TCS_BOARD_HEATER_IN_8V); pcdu::Switches::PDU2_CH3_TCS_BOARD_HEATER_IN_8V);
} }
void ObjectFactory::createSolarArrayDeploymentComponents() { void ObjectFactory::createSolarArrayDeploymentComponents(PowerSwitchIF& pwrSwitcher,
GpioIF& gpioIF) {
using namespace gpio; using namespace gpio;
GpioCookie* solarArrayDeplCookie = new GpioCookie; GpioCookie* solarArrayDeplCookie = new GpioCookie;
GpiodRegularByLineName* gpio = nullptr; GpiodRegularByLineName* gpio = nullptr;
@ -552,12 +553,14 @@ void ObjectFactory::createSolarArrayDeploymentComponents() {
gpio = new GpiodRegularByLineName(q7s::gpioNames::SA_DPL_PIN_1, consumer.str(), Direction::OUT, gpio = new GpiodRegularByLineName(q7s::gpioNames::SA_DPL_PIN_1, consumer.str(), Direction::OUT,
Levels::LOW); Levels::LOW);
solarArrayDeplCookie->addGpio(gpioIds::DEPLSA2, gpio); solarArrayDeplCookie->addGpio(gpioIds::DEPLSA2, gpio);
ReturnValue_t result = gpioIF.addGpios(solarArrayDeplCookie);
if (result != returnvalue::OK) {
sif::error << "Adding Solar Array Deployment GPIO cookie failed" << std::endl;
}
// TODO: Find out burn time. For now set to 1000 ms. new SolarArrayDeploymentHandler(objects::SOLAR_ARRAY_DEPL_HANDLER, gpioIF, pwrSwitcher,
new SolarArrayDeploymentHandler(objects::SOLAR_ARRAY_DEPL_HANDLER, objects::GPIO_IF,
solarArrayDeplCookie, objects::PCDU_HANDLER,
pcdu::Switches::PDU2_CH5_DEPLOYMENT_MECHANISM_8V, pcdu::Switches::PDU2_CH5_DEPLOYMENT_MECHANISM_8V,
gpioIds::DEPLSA1, gpioIds::DEPLSA2, 1000); gpioIds::DEPLSA1, gpioIds::DEPLSA2, *SdCardManager::instance());
} }
void ObjectFactory::createSyrlinksComponents(PowerSwitchIF* pwrSwitcher) { void ObjectFactory::createSyrlinksComponents(PowerSwitchIF* pwrSwitcher) {

View File

@ -33,7 +33,7 @@ void createHeaterComponents(GpioIF* gpioIF, PowerSwitchIF* pwrSwitcher, HealthTa
void createImtqComponents(PowerSwitchIF* pwrSwitcher); void createImtqComponents(PowerSwitchIF* pwrSwitcher);
void createBpxBatteryComponent(); void createBpxBatteryComponent();
void createStrComponents(PowerSwitchIF* pwrSwitcher); void createStrComponents(PowerSwitchIF* pwrSwitcher);
void createSolarArrayDeploymentComponents(); void createSolarArrayDeploymentComponents(PowerSwitchIF& pwrSwitcher, GpioIF& gpioIF);
void createSyrlinksComponents(PowerSwitchIF* pwrSwitcher); void createSyrlinksComponents(PowerSwitchIF* pwrSwitcher);
void createPayloadComponents(LinuxLibgpioIF* gpioComIF); void createPayloadComponents(LinuxLibgpioIF* gpioComIF);
void createReactionWheelComponents(LinuxLibgpioIF* gpioComIF, PowerSwitchIF* pwrSwitcher); void createReactionWheelComponents(LinuxLibgpioIF* gpioComIF, PowerSwitchIF* pwrSwitcher);

View File

@ -35,7 +35,7 @@ void ObjectFactory::produce(void* args) {
createAcsBoardComponents(gpioComIF, uartComIF, pwrSwitcher); createAcsBoardComponents(gpioComIF, uartComIF, pwrSwitcher);
#endif #endif
createHeaterComponents(gpioComIF, pwrSwitcher, healthTable); createHeaterComponents(gpioComIF, pwrSwitcher, healthTable);
createSolarArrayDeploymentComponents(); createSolarArrayDeploymentComponents(*pwrSwitcher, *gpioComIF);
createPlPcduComponents(gpioComIF, spiMainComIF, pwrSwitcher); createPlPcduComponents(gpioComIF, spiMainComIF, pwrSwitcher);
#if OBSW_ADD_SYRLINKS == 1 #if OBSW_ADD_SYRLINKS == 1
createSyrlinksComponents(pwrSwitcher); createSyrlinksComponents(pwrSwitcher);

View File

@ -34,6 +34,15 @@ static constexpr uint8_t LIVE_TM = 0;
static constexpr uint32_t MAX_PATH_SIZE = 100; static constexpr uint32_t MAX_PATH_SIZE = 100;
static constexpr uint32_t MAX_FILENAME_SIZE = 50; static constexpr uint32_t MAX_FILENAME_SIZE = 50;
static constexpr uint32_t SA_DEPL_INIT_BUFFER_SECS = 120;
// Burn time for autonomous deployment
static constexpr uint32_t SA_DEPL_BURN_TIME_SECS = 180;
static constexpr uint32_t SA_DEPL_WAIT_TIME_SECS = 45 * 60;
// HW constraints (current limit) mean that the GPIO channels need to be switched on in alternation
static constexpr uint32_t SA_DEPL_CHANNEL_ALTERNATION_INTERVAL_SECS = 5;
// Maximum allowed burn time allowed by the software.
static constexpr uint32_t SA_DEPL_MAX_BURN_TIME = 180;
} // namespace config } // namespace config
#endif /* COMMON_CONFIG_DEFINITIONS_H_ */ #endif /* COMMON_CONFIG_DEFINITIONS_H_ */

View File

@ -92,11 +92,15 @@ Event ID (dec); Event ID (hex); Name; Severity; Description; File Path
11405;0x2c8d;SWITCH_ALREADY_OFF;LOW;;mission/devices/HeaterHandler.h 11405;0x2c8d;SWITCH_ALREADY_OFF;LOW;;mission/devices/HeaterHandler.h
11406;0x2c8e;MAIN_SWITCH_TIMEOUT;MEDIUM;;mission/devices/HeaterHandler.h 11406;0x2c8e;MAIN_SWITCH_TIMEOUT;MEDIUM;;mission/devices/HeaterHandler.h
11407;0x2c8f;FAULTY_HEATER_WAS_ON;LOW;;mission/devices/HeaterHandler.h 11407;0x2c8f;FAULTY_HEATER_WAS_ON;LOW;;mission/devices/HeaterHandler.h
11500;0x2cec;MAIN_SWITCH_ON_TIMEOUT;LOW;;mission/devices/SolarArrayDeploymentHandler.h 11500;0x2cec;BURN_PHASE_START;INFO;P1: Burn duration in milliseconds, P2: Dry run flag;mission/devices/SolarArrayDeploymentHandler.h
11501;0x2ced;MAIN_SWITCH_OFF_TIMEOUT;LOW;;mission/devices/SolarArrayDeploymentHandler.h 11501;0x2ced;BURN_PHASE_DONE;INFO;P1: Burn duration in milliseconds, P2: Dry run flag;mission/devices/SolarArrayDeploymentHandler.h
11502;0x2cee;DEPLOYMENT_FAILED;HIGH;;mission/devices/SolarArrayDeploymentHandler.h 11502;0x2cee;MAIN_SWITCH_ON_TIMEOUT;LOW;;mission/devices/SolarArrayDeploymentHandler.h
11503;0x2cef;DEPL_SA1_GPIO_SWTICH_ON_FAILED;HIGH;;mission/devices/SolarArrayDeploymentHandler.h 11503;0x2cef;MAIN_SWITCH_OFF_TIMEOUT;LOW;;mission/devices/SolarArrayDeploymentHandler.h
11504;0x2cf0;DEPL_SA2_GPIO_SWTICH_ON_FAILED;HIGH;;mission/devices/SolarArrayDeploymentHandler.h 11504;0x2cf0;DEPL_SA1_GPIO_SWTICH_ON_FAILED;HIGH;;mission/devices/SolarArrayDeploymentHandler.h
11505;0x2cf1;DEPL_SA2_GPIO_SWTICH_ON_FAILED;HIGH;;mission/devices/SolarArrayDeploymentHandler.h
11506;0x2cf2;DEPL_SA1_GPIO_SWTICH_OFF_FAILED;HIGH;;mission/devices/SolarArrayDeploymentHandler.h
11507;0x2cf3;DEPL_SA2_GPIO_SWTICH_OFF_FAILED;HIGH;;mission/devices/SolarArrayDeploymentHandler.h
11508;0x2cf4;AUTONOMOUS_DEPLOYMENT_COMPLETED;INFO;;mission/devices/SolarArrayDeploymentHandler.h
11601;0x2d51;MEMORY_READ_RPT_CRC_FAILURE;LOW;PLOC crc failure in telemetry packet;linux/devices/ploc/PlocMPSoCHandler.h 11601;0x2d51;MEMORY_READ_RPT_CRC_FAILURE;LOW;PLOC crc failure in telemetry packet;linux/devices/ploc/PlocMPSoCHandler.h
11602;0x2d52;ACK_FAILURE;LOW;PLOC receive acknowledgment failure report P1: Command Id which leads the acknowledgment failure report P2: The status field inserted by the MPSoC into the data field;linux/devices/ploc/PlocMPSoCHandler.h 11602;0x2d52;ACK_FAILURE;LOW;PLOC receive acknowledgment failure report P1: Command Id which leads the acknowledgment failure report P2: The status field inserted by the MPSoC into the data field;linux/devices/ploc/PlocMPSoCHandler.h
11603;0x2d53;EXE_FAILURE;LOW;PLOC receive execution failure report P1: Command Id which leads the execution failure report P2: The status field inserted by the MPSoC into the data field;linux/devices/ploc/PlocMPSoCHandler.h 11603;0x2d53;EXE_FAILURE;LOW;PLOC receive execution failure report P1: Command Id which leads the execution failure report P2: The status field inserted by the MPSoC into the data field;linux/devices/ploc/PlocMPSoCHandler.h

1 Event ID (dec) Event ID (hex) Name Severity Description File Path
92 11405 0x2c8d SWITCH_ALREADY_OFF LOW mission/devices/HeaterHandler.h
93 11406 0x2c8e MAIN_SWITCH_TIMEOUT MEDIUM mission/devices/HeaterHandler.h
94 11407 0x2c8f FAULTY_HEATER_WAS_ON LOW mission/devices/HeaterHandler.h
95 11500 0x2cec MAIN_SWITCH_ON_TIMEOUT BURN_PHASE_START LOW INFO P1: Burn duration in milliseconds, P2: Dry run flag mission/devices/SolarArrayDeploymentHandler.h
96 11501 0x2ced MAIN_SWITCH_OFF_TIMEOUT BURN_PHASE_DONE LOW INFO P1: Burn duration in milliseconds, P2: Dry run flag mission/devices/SolarArrayDeploymentHandler.h
97 11502 0x2cee DEPLOYMENT_FAILED MAIN_SWITCH_ON_TIMEOUT HIGH LOW mission/devices/SolarArrayDeploymentHandler.h
98 11503 0x2cef DEPL_SA1_GPIO_SWTICH_ON_FAILED MAIN_SWITCH_OFF_TIMEOUT HIGH LOW mission/devices/SolarArrayDeploymentHandler.h
99 11504 0x2cf0 DEPL_SA2_GPIO_SWTICH_ON_FAILED DEPL_SA1_GPIO_SWTICH_ON_FAILED HIGH mission/devices/SolarArrayDeploymentHandler.h
100 11505 0x2cf1 DEPL_SA2_GPIO_SWTICH_ON_FAILED HIGH mission/devices/SolarArrayDeploymentHandler.h
101 11506 0x2cf2 DEPL_SA1_GPIO_SWTICH_OFF_FAILED HIGH mission/devices/SolarArrayDeploymentHandler.h
102 11507 0x2cf3 DEPL_SA2_GPIO_SWTICH_OFF_FAILED HIGH mission/devices/SolarArrayDeploymentHandler.h
103 11508 0x2cf4 AUTONOMOUS_DEPLOYMENT_COMPLETED INFO mission/devices/SolarArrayDeploymentHandler.h
104 11601 0x2d51 MEMORY_READ_RPT_CRC_FAILURE LOW PLOC crc failure in telemetry packet linux/devices/ploc/PlocMPSoCHandler.h
105 11602 0x2d52 ACK_FAILURE LOW PLOC receive acknowledgment failure report P1: Command Id which leads the acknowledgment failure report P2: The status field inserted by the MPSoC into the data field linux/devices/ploc/PlocMPSoCHandler.h
106 11603 0x2d53 EXE_FAILURE LOW PLOC receive execution failure report P1: Command Id which leads the execution failure report P2: The status field inserted by the MPSoC into the data field linux/devices/ploc/PlocMPSoCHandler.h

View File

@ -1,7 +1,7 @@
/** /**
* @brief Auto-generated event translation file. Contains 225 translations. * @brief Auto-generated event translation file. Contains 229 translations.
* @details * @details
* Generated on: 2022-10-10 11:15:49 * Generated on: 2022-10-14 14:54:47
*/ */
#include "translateEvents.h" #include "translateEvents.h"
@ -98,11 +98,15 @@ const char *SWITCH_ALREADY_ON_STRING = "SWITCH_ALREADY_ON";
const char *SWITCH_ALREADY_OFF_STRING = "SWITCH_ALREADY_OFF"; const char *SWITCH_ALREADY_OFF_STRING = "SWITCH_ALREADY_OFF";
const char *MAIN_SWITCH_TIMEOUT_STRING = "MAIN_SWITCH_TIMEOUT"; const char *MAIN_SWITCH_TIMEOUT_STRING = "MAIN_SWITCH_TIMEOUT";
const char *FAULTY_HEATER_WAS_ON_STRING = "FAULTY_HEATER_WAS_ON"; const char *FAULTY_HEATER_WAS_ON_STRING = "FAULTY_HEATER_WAS_ON";
const char *BURN_PHASE_START_STRING = "BURN_PHASE_START";
const char *BURN_PHASE_DONE_STRING = "BURN_PHASE_DONE";
const char *MAIN_SWITCH_ON_TIMEOUT_STRING = "MAIN_SWITCH_ON_TIMEOUT"; const char *MAIN_SWITCH_ON_TIMEOUT_STRING = "MAIN_SWITCH_ON_TIMEOUT";
const char *MAIN_SWITCH_OFF_TIMEOUT_STRING = "MAIN_SWITCH_OFF_TIMEOUT"; const char *MAIN_SWITCH_OFF_TIMEOUT_STRING = "MAIN_SWITCH_OFF_TIMEOUT";
const char *DEPLOYMENT_FAILED_STRING = "DEPLOYMENT_FAILED";
const char *DEPL_SA1_GPIO_SWTICH_ON_FAILED_STRING = "DEPL_SA1_GPIO_SWTICH_ON_FAILED"; const char *DEPL_SA1_GPIO_SWTICH_ON_FAILED_STRING = "DEPL_SA1_GPIO_SWTICH_ON_FAILED";
const char *DEPL_SA2_GPIO_SWTICH_ON_FAILED_STRING = "DEPL_SA2_GPIO_SWTICH_ON_FAILED"; const char *DEPL_SA2_GPIO_SWTICH_ON_FAILED_STRING = "DEPL_SA2_GPIO_SWTICH_ON_FAILED";
const char *DEPL_SA1_GPIO_SWTICH_OFF_FAILED_STRING = "DEPL_SA1_GPIO_SWTICH_OFF_FAILED";
const char *DEPL_SA2_GPIO_SWTICH_OFF_FAILED_STRING = "DEPL_SA2_GPIO_SWTICH_OFF_FAILED";
const char *AUTONOMOUS_DEPLOYMENT_COMPLETED_STRING = "AUTONOMOUS_DEPLOYMENT_COMPLETED";
const char *MEMORY_READ_RPT_CRC_FAILURE_STRING = "MEMORY_READ_RPT_CRC_FAILURE"; const char *MEMORY_READ_RPT_CRC_FAILURE_STRING = "MEMORY_READ_RPT_CRC_FAILURE";
const char *ACK_FAILURE_STRING = "ACK_FAILURE"; const char *ACK_FAILURE_STRING = "ACK_FAILURE";
const char *EXE_FAILURE_STRING = "EXE_FAILURE"; const char *EXE_FAILURE_STRING = "EXE_FAILURE";
@ -416,15 +420,23 @@ const char *translateEvents(Event event) {
case (11407): case (11407):
return FAULTY_HEATER_WAS_ON_STRING; return FAULTY_HEATER_WAS_ON_STRING;
case (11500): case (11500):
return MAIN_SWITCH_ON_TIMEOUT_STRING; return BURN_PHASE_START_STRING;
case (11501): case (11501):
return MAIN_SWITCH_OFF_TIMEOUT_STRING; return BURN_PHASE_DONE_STRING;
case (11502): case (11502):
return DEPLOYMENT_FAILED_STRING; return MAIN_SWITCH_ON_TIMEOUT_STRING;
case (11503): case (11503):
return DEPL_SA1_GPIO_SWTICH_ON_FAILED_STRING; return MAIN_SWITCH_OFF_TIMEOUT_STRING;
case (11504): case (11504):
return DEPL_SA1_GPIO_SWTICH_ON_FAILED_STRING;
case (11505):
return DEPL_SA2_GPIO_SWTICH_ON_FAILED_STRING; return DEPL_SA2_GPIO_SWTICH_ON_FAILED_STRING;
case (11506):
return DEPL_SA1_GPIO_SWTICH_OFF_FAILED_STRING;
case (11507):
return DEPL_SA2_GPIO_SWTICH_OFF_FAILED_STRING;
case (11508):
return AUTONOMOUS_DEPLOYMENT_COMPLETED_STRING;
case (11601): case (11601):
return MEMORY_READ_RPT_CRC_FAILURE_STRING; return MEMORY_READ_RPT_CRC_FAILURE_STRING;
case (11602): case (11602):

View File

@ -2,7 +2,7 @@
* @brief Auto-generated object translation file. * @brief Auto-generated object translation file.
* @details * @details
* Contains 138 translations. * Contains 138 translations.
* Generated on: 2022-10-10 11:15:49 * Generated on: 2022-10-14 14:54:47
*/ */
#include "translateObjects.h" #include "translateObjects.h"

View File

@ -1,7 +1,7 @@
/** /**
* @brief Auto-generated event translation file. Contains 225 translations. * @brief Auto-generated event translation file. Contains 229 translations.
* @details * @details
* Generated on: 2022-10-10 11:15:49 * Generated on: 2022-10-14 14:54:47
*/ */
#include "translateEvents.h" #include "translateEvents.h"
@ -98,11 +98,15 @@ const char *SWITCH_ALREADY_ON_STRING = "SWITCH_ALREADY_ON";
const char *SWITCH_ALREADY_OFF_STRING = "SWITCH_ALREADY_OFF"; const char *SWITCH_ALREADY_OFF_STRING = "SWITCH_ALREADY_OFF";
const char *MAIN_SWITCH_TIMEOUT_STRING = "MAIN_SWITCH_TIMEOUT"; const char *MAIN_SWITCH_TIMEOUT_STRING = "MAIN_SWITCH_TIMEOUT";
const char *FAULTY_HEATER_WAS_ON_STRING = "FAULTY_HEATER_WAS_ON"; const char *FAULTY_HEATER_WAS_ON_STRING = "FAULTY_HEATER_WAS_ON";
const char *BURN_PHASE_START_STRING = "BURN_PHASE_START";
const char *BURN_PHASE_DONE_STRING = "BURN_PHASE_DONE";
const char *MAIN_SWITCH_ON_TIMEOUT_STRING = "MAIN_SWITCH_ON_TIMEOUT"; const char *MAIN_SWITCH_ON_TIMEOUT_STRING = "MAIN_SWITCH_ON_TIMEOUT";
const char *MAIN_SWITCH_OFF_TIMEOUT_STRING = "MAIN_SWITCH_OFF_TIMEOUT"; const char *MAIN_SWITCH_OFF_TIMEOUT_STRING = "MAIN_SWITCH_OFF_TIMEOUT";
const char *DEPLOYMENT_FAILED_STRING = "DEPLOYMENT_FAILED";
const char *DEPL_SA1_GPIO_SWTICH_ON_FAILED_STRING = "DEPL_SA1_GPIO_SWTICH_ON_FAILED"; const char *DEPL_SA1_GPIO_SWTICH_ON_FAILED_STRING = "DEPL_SA1_GPIO_SWTICH_ON_FAILED";
const char *DEPL_SA2_GPIO_SWTICH_ON_FAILED_STRING = "DEPL_SA2_GPIO_SWTICH_ON_FAILED"; const char *DEPL_SA2_GPIO_SWTICH_ON_FAILED_STRING = "DEPL_SA2_GPIO_SWTICH_ON_FAILED";
const char *DEPL_SA1_GPIO_SWTICH_OFF_FAILED_STRING = "DEPL_SA1_GPIO_SWTICH_OFF_FAILED";
const char *DEPL_SA2_GPIO_SWTICH_OFF_FAILED_STRING = "DEPL_SA2_GPIO_SWTICH_OFF_FAILED";
const char *AUTONOMOUS_DEPLOYMENT_COMPLETED_STRING = "AUTONOMOUS_DEPLOYMENT_COMPLETED";
const char *MEMORY_READ_RPT_CRC_FAILURE_STRING = "MEMORY_READ_RPT_CRC_FAILURE"; const char *MEMORY_READ_RPT_CRC_FAILURE_STRING = "MEMORY_READ_RPT_CRC_FAILURE";
const char *ACK_FAILURE_STRING = "ACK_FAILURE"; const char *ACK_FAILURE_STRING = "ACK_FAILURE";
const char *EXE_FAILURE_STRING = "EXE_FAILURE"; const char *EXE_FAILURE_STRING = "EXE_FAILURE";
@ -416,15 +420,23 @@ const char *translateEvents(Event event) {
case (11407): case (11407):
return FAULTY_HEATER_WAS_ON_STRING; return FAULTY_HEATER_WAS_ON_STRING;
case (11500): case (11500):
return MAIN_SWITCH_ON_TIMEOUT_STRING; return BURN_PHASE_START_STRING;
case (11501): case (11501):
return MAIN_SWITCH_OFF_TIMEOUT_STRING; return BURN_PHASE_DONE_STRING;
case (11502): case (11502):
return DEPLOYMENT_FAILED_STRING; return MAIN_SWITCH_ON_TIMEOUT_STRING;
case (11503): case (11503):
return DEPL_SA1_GPIO_SWTICH_ON_FAILED_STRING; return MAIN_SWITCH_OFF_TIMEOUT_STRING;
case (11504): case (11504):
return DEPL_SA1_GPIO_SWTICH_ON_FAILED_STRING;
case (11505):
return DEPL_SA2_GPIO_SWTICH_ON_FAILED_STRING; return DEPL_SA2_GPIO_SWTICH_ON_FAILED_STRING;
case (11506):
return DEPL_SA1_GPIO_SWTICH_OFF_FAILED_STRING;
case (11507):
return DEPL_SA2_GPIO_SWTICH_OFF_FAILED_STRING;
case (11508):
return AUTONOMOUS_DEPLOYMENT_COMPLETED_STRING;
case (11601): case (11601):
return MEMORY_READ_RPT_CRC_FAILURE_STRING; return MEMORY_READ_RPT_CRC_FAILURE_STRING;
case (11602): case (11602):

View File

@ -2,7 +2,7 @@
* @brief Auto-generated object translation file. * @brief Auto-generated object translation file.
* @details * @details
* Contains 138 translations. * Contains 138 translations.
* Generated on: 2022-10-10 11:15:49 * Generated on: 2022-10-14 14:54:47
*/ */
#include "translateObjects.h" #include "translateObjects.h"

View File

@ -15,22 +15,6 @@
#define RPI_TEST_GPS_HANDLER 0 #define RPI_TEST_GPS_HANDLER 0
#endif #endif
ReturnValue_t pst::pstGpio(FixedTimeslotTaskIF *thisSequence) {
// Length of a communication cycle
uint32_t length = thisSequence->getPeriodMs();
thisSequence->addSlot(objects::HEATER_HANDLER, length * 0, DeviceHandlerIF::PERFORM_OPERATION);
thisSequence->addSlot(objects::SOLAR_ARRAY_DEPL_HANDLER, length * 0,
DeviceHandlerIF::PERFORM_OPERATION);
if (thisSequence->checkSequence() == returnvalue::OK) {
return returnvalue::OK;
}
sif::error << "PollingSequence::initialize has errors!" << std::endl;
return returnvalue::FAILED;
}
ReturnValue_t pst::pstSpiRw(FixedTimeslotTaskIF *thisSequence) { ReturnValue_t pst::pstSpiRw(FixedTimeslotTaskIF *thisSequence) {
uint32_t length = thisSequence->getPeriodMs(); uint32_t length = thisSequence->getPeriodMs();
static_cast<void>(length); static_cast<void>(length);

View File

@ -31,9 +31,6 @@ class FixedTimeslotTaskIF;
*/ */
namespace pst { namespace pst {
/* 0.4 second period init*/
ReturnValue_t pstGpio(FixedTimeslotTaskIF* thisSequence);
/** /**
* @brief This function creates the PST for all gomspace devices. * @brief This function creates the PST for all gomspace devices.
* @details * @details

View File

@ -1,171 +1,470 @@
#include "SolarArrayDeploymentHandler.h" #include "SolarArrayDeploymentHandler.h"
#include <devices/gpioIds.h> #include <fsfw/tasks/TaskFactory.h>
#include <fsfw/ipc/QueueFactory.h>
#include <fsfw/objectmanager/ObjectManager.h>
#include <fsfw_hal/common/gpio/GpioCookie.h>
SolarArrayDeploymentHandler::SolarArrayDeploymentHandler( #include <filesystem>
object_id_t setObjectId_, object_id_t gpioDriverId_, CookieIF* gpioCookie_, #include <fstream>
object_id_t mainLineSwitcherObjectId_, pcdu::Switches mainLineSwitch_, gpioId_t deplSA1, #include <iostream>
gpioId_t deplSA2, uint32_t burnTimeMs)
#include "devices/gpioIds.h"
#include "fsfw/ipc/QueueFactory.h"
#include "fsfw/objectmanager/ObjectManager.h"
#include "fsfw_hal/common/gpio/GpioCookie.h"
static constexpr bool DEBUG_MODE = true;
SolarArrayDeploymentHandler::SolarArrayDeploymentHandler(object_id_t setObjectId_,
GpioIF& gpioInterface,
PowerSwitchIF& mainLineSwitcher_,
pcdu::Switches mainLineSwitch_,
gpioId_t deplSA1, gpioId_t deplSA2,
SdCardMountedIF& sdcMountedIF)
: SystemObject(setObjectId_), : SystemObject(setObjectId_),
gpioDriverId(gpioDriverId_), gpioInterface(gpioInterface),
gpioCookie(gpioCookie_),
mainLineSwitcherObjectId(mainLineSwitcherObjectId_),
mainLineSwitch(mainLineSwitch_),
deplSA1(deplSA1), deplSA1(deplSA1),
deplSA2(deplSA2), deplSA2(deplSA2),
burnTimeMs(burnTimeMs), mainLineSwitcher(mainLineSwitcher_),
mainLineSwitch(mainLineSwitch_),
sdcMan(sdcMountedIF),
actionHelper(this, nullptr) { actionHelper(this, nullptr) {
auto mqArgs = MqArgs(setObjectId_, static_cast<void*>(this)); auto mqArgs = MqArgs(setObjectId_, static_cast<void*>(this));
commandQueue = QueueFactory::instance()->createMessageQueue( commandQueue = QueueFactory::instance()->createMessageQueue(
cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs); cmdQueueSize, MessageQueueMessage::MAX_MESSAGE_SIZE, &mqArgs);
} }
SolarArrayDeploymentHandler::~SolarArrayDeploymentHandler() {} SolarArrayDeploymentHandler::~SolarArrayDeploymentHandler() = default;
ReturnValue_t SolarArrayDeploymentHandler::performOperation(uint8_t operationCode) { ReturnValue_t SolarArrayDeploymentHandler::performOperation(uint8_t operationCode) {
if (operationCode == DeviceHandlerIF::PERFORM_OPERATION) { using namespace std::filesystem;
handleStateMachine(); if (opDivider.checkAndIncrement()) {
return returnvalue::OK; auto activeSdc = sdcMan.getActiveSdCard();
} if (activeSdc and activeSdc.value() == sd::SdCard::SLOT_0 and
return returnvalue::OK; sdcMan.isSdCardUsable(activeSdc.value())) {
} if (exists(SD_0_DEPL_FILE)) {
// perform autonomous deployment handling
ReturnValue_t SolarArrayDeploymentHandler::initialize() { performAutonomousDepl(sd::SdCard::SLOT_0, dryRunStringInFile(SD_0_DEPL_FILE));
ReturnValue_t result = SystemObject::initialize(); }
if (result != returnvalue::OK) { } else if (activeSdc and activeSdc.value() == sd::SdCard::SLOT_1 and
return ObjectManagerIF::CHILD_INIT_FAILED; sdcMan.isSdCardUsable(activeSdc.value())) {
} if (exists(SD_1_DEPL_FILE)) {
// perform autonomous deployment handling
gpioInterface = ObjectManager::instance()->get<GpioIF>(gpioDriverId); performAutonomousDepl(sd::SdCard::SLOT_1, dryRunStringInFile(SD_1_DEPL_FILE));
if (gpioInterface == nullptr) { }
sif::error << "SolarArrayDeploymentHandler::initialize: Invalid Gpio interface." << std::endl; } else {
return ObjectManagerIF::CHILD_INIT_FAILED; // TODO: This is FDIR domain. If both SD cards are not available for whatever reason,
} // there is not much we can do except somehow use the scratch buffer which is
// not non-volatile. Implementation effort is considerable as well.
result = gpioInterface->addGpios(dynamic_cast<GpioCookie*>(gpioCookie));
if (result != returnvalue::OK) {
sif::error << "SolarArrayDeploymentHandler::initialize: Failed to initialize Gpio interface"
<< std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
}
if (mainLineSwitcherObjectId != objects::NO_OBJECT) {
mainLineSwitcher = ObjectManager::instance()->get<PowerSwitchIF>(mainLineSwitcherObjectId);
if (mainLineSwitcher == nullptr) {
sif::error
<< "SolarArrayDeploymentHandler::initialize: Main line switcher failed to fetch object"
<< "from object ID." << std::endl;
return ObjectManagerIF::CHILD_INIT_FAILED;
} }
} }
readCommandQueue();
result = actionHelper.initialize(commandQueue); handleStateMachine();
if (result != returnvalue::OK) {
return ObjectManagerIF::CHILD_INIT_FAILED;
}
return returnvalue::OK; return returnvalue::OK;
} }
void SolarArrayDeploymentHandler::handleStateMachine() { void SolarArrayDeploymentHandler::handleStateMachine() {
switch (stateMachine) { if (stateMachine == MAIN_POWER_ON) {
case WAIT_ON_DELOYMENT_COMMAND: mainLineSwitcher.sendSwitchCommand(mainLineSwitch, PowerSwitchIF::SWITCH_ON);
readCommandQueue(); mainSwitchCountdown.setTimeout(mainLineSwitcher.getSwitchDelayMs());
break; stateMachine = WAIT_MAIN_POWER_ON;
case SWITCH_8V_ON: sif::info << "S/A Deployment: Deployment power line on" << std::endl;
mainLineSwitcher->sendSwitchCommand(mainLineSwitch, PowerSwitchIF::SWITCH_ON); }
mainSwitchCountdown.setTimeout(mainLineSwitcher->getSwitchDelayMs()); if (stateMachine == MAIN_POWER_OFF) {
stateMachine = WAIT_ON_8V_SWITCH; // These should never fail
break; allOff();
case WAIT_ON_8V_SWITCH: stateMachine = WAIT_MAIN_POWER_OFF;
performWaitOn8VActions(); sif::info << "S/A Deployment: Deployment power line off" << std::endl;
break; }
case SWITCH_DEPL_GPIOS: if (stateMachine == WAIT_MAIN_POWER_ON) {
switchDeploymentTransistors(); if (checkMainPowerOn()) {
break; if (DEBUG_MODE) {
case WAIT_ON_DEPLOYMENT_FINISH: sif::debug << "SA DEPL FSM: WAIT_MAIN_POWER_ON done -> SWITCH_DEPL_GPIOS" << std::endl;
handleDeploymentFinish();
break;
case WAIT_FOR_MAIN_SWITCH_OFF:
if (mainLineSwitcher->getSwitchState(mainLineSwitch) == PowerSwitchIF::SWITCH_OFF) {
stateMachine = WAIT_ON_DELOYMENT_COMMAND;
} else if (mainSwitchCountdown.hasTimedOut()) {
triggerEvent(MAIN_SWITCH_OFF_TIMEOUT);
sif::error << "SolarArrayDeploymentHandler::handleStateMachine: Failed to switch main"
<< " switch off" << std::endl;
stateMachine = WAIT_ON_DELOYMENT_COMMAND;
} }
break; stateMachine = SWITCH_DEPL_GPIOS;
default: }
sif::debug << "SolarArrayDeploymentHandler::handleStateMachine: Invalid state" << std::endl; }
break; if (stateMachine == WAIT_MAIN_POWER_OFF) {
if (checkMainPowerOff()) {
if (DEBUG_MODE) {
sif::debug << "SA DEPL FSM: WAIT_MAIN_POWER_OFF done -> FSM DONE" << std::endl;
}
sif::info << "S/A Deployment: FSM done" << std::endl;
finishFsm(returnvalue::OK);
}
}
if (stateMachine == SWITCH_DEPL_GPIOS) {
burnCountdown.setTimeout(fsmInfo.burnCountdownMs);
// This should never fail
channelAlternationCd.resetTimer();
if (not fsmInfo.dryRun) {
sa2Off();
sa1On();
fsmInfo.alternationDummy = true;
}
sif::info << "S/A Deployment: Burning" << std::endl;
triggerEvent(BURN_PHASE_START, fsmInfo.burnCountdownMs, fsmInfo.dryRun);
stateMachine = BURNING;
}
if (stateMachine == BURNING) {
saGpioAlternation();
if (burnCountdown.hasTimedOut()) {
if (DEBUG_MODE) {
sif::debug << "SA DEPL FSM: BURNING done -> WAIT_MAIN_POWER_OFF" << std::endl;
}
allOff();
triggerEvent(BURN_PHASE_DONE, fsmInfo.burnCountdownMs, fsmInfo.dryRun);
stateMachine = WAIT_MAIN_POWER_OFF;
}
} }
} }
void SolarArrayDeploymentHandler::performWaitOn8VActions() { ReturnValue_t SolarArrayDeploymentHandler::performAutonomousDepl(sd::SdCard sdCard, bool dryRun) {
if (mainLineSwitcher->getSwitchState(mainLineSwitch) == PowerSwitchIF::SWITCH_ON) { using namespace std::filesystem;
stateMachine = SWITCH_DEPL_GPIOS; using namespace std;
auto initFile = [](const char* filename) {
ofstream of(filename);
of << "phase: init\n";
of << "secs_since_start: 0\n";
};
if (sdCard == sd::SdCard::SLOT_0) {
if (not exists(SD_0_DEPLY_INFO)) {
initFile(SD_0_DEPLY_INFO);
}
if (not autonomousDeplForFile(sd::SdCard::SLOT_0, SD_0_DEPLY_INFO, dryRun)) {
initFile(SD_0_DEPLY_INFO);
}
} else if (sdCard == sd::SdCard::SLOT_1) {
if (not exists(SD_1_DEPLY_INFO)) {
initFile(SD_1_DEPLY_INFO);
}
if (not autonomousDeplForFile(sd::SdCard::SLOT_1, SD_1_DEPLY_INFO, dryRun)) {
initFile(SD_1_DEPLY_INFO);
}
}
return returnvalue::OK;
}
bool SolarArrayDeploymentHandler::autonomousDeplForFile(sd::SdCard sdCard, const char* filename,
bool dryRun) {
using namespace std;
ifstream file(filename);
string line;
string word;
unsigned int lineNum = 0;
AutonomousDeplState deplState;
bool stateSwitch = false;
uint32_t secsSinceBoot = 0;
while (std::getline(file, line)) {
std::istringstream iss(line);
if (lineNum == 0) {
iss >> word;
if (word.find("phase:") == string::npos) {
return false;
}
iss >> word;
if (word.find(PHASE_INIT_STR) != string::npos) {
deplState = AutonomousDeplState::INIT;
} else if (word.find(PHASE_FIRST_BURN_STR) != string::npos) {
deplState = AutonomousDeplState::FIRST_BURN;
} else if (word.find(PHASE_WAIT_STR) != string::npos) {
deplState = AutonomousDeplState::WAIT;
} else if (word.find(PHASE_SECOND_BURN_STR) != string::npos) {
deplState = AutonomousDeplState::SECOND_BURN;
} else if (word.find(PHASE_DONE) != string::npos) {
deplState = AutonomousDeplState::DONE;
} else {
return false;
}
} else if (lineNum == 1) {
iss >> word;
if (iss.bad()) {
return false;
}
if (word.find("secs_since_start:") == string::npos) {
return false;
}
iss >> secsSinceBoot;
if (iss.bad()) {
return false;
}
if (not initUptime) {
initUptime = secsSinceBoot;
}
auto switchCheck = [&](AutonomousDeplState expected) {
if (deplState != expected) {
deplState = expected;
stateSwitch = true;
}
};
if ((secsSinceBoot > FIRST_BURN_START_TIME) and (secsSinceBoot < FIRST_BURN_END_TIME)) {
switchCheck(AutonomousDeplState::FIRST_BURN);
} else if ((secsSinceBoot > WAIT_START_TIME) and (secsSinceBoot < WAIT_END_TIME)) {
switchCheck(AutonomousDeplState::WAIT);
} else if ((secsSinceBoot > SECOND_BURN_START_TIME) and
(secsSinceBoot < SECOND_BURN_END_TIME)) {
switchCheck(AutonomousDeplState::SECOND_BURN);
} else if (secsSinceBoot > SECOND_BURN_END_TIME) {
switchCheck(AutonomousDeplState::DONE);
}
}
lineNum++;
}
if (initUptime) {
secsSinceBoot = initUptime.value();
}
// Uptime has increased by X seconds so we need to update the uptime count inside the file
secsSinceBoot += Clock::getUptime().tv_sec;
if (stateSwitch or firstAutonomousCycle) {
if (deplState == AutonomousDeplState::FIRST_BURN or
deplState == AutonomousDeplState::SECOND_BURN) {
startFsmOn(config::SA_DEPL_BURN_TIME_SECS, dryRun);
} else if (deplState == AutonomousDeplState::WAIT or deplState == AutonomousDeplState::DONE or
deplState == AutonomousDeplState::INIT) {
startFsmOff();
}
}
if (deplState == AutonomousDeplState::DONE) {
remove(filename);
if (sdCard == sd::SdCard::SLOT_0) {
remove(SD_0_DEPL_FILE);
} else {
remove(SD_1_DEPL_FILE);
}
triggerEvent(AUTONOMOUS_DEPLOYMENT_COMPLETED);
} else { } else {
if (mainSwitchCountdown.hasTimedOut()) { std::ofstream of(filename);
of << "phase: ";
if (deplState == AutonomousDeplState::INIT) {
of << PHASE_INIT_STR << "\n";
} else if (deplState == AutonomousDeplState::FIRST_BURN) {
of << PHASE_FIRST_BURN_STR << "\n";
} else if (deplState == AutonomousDeplState::WAIT) {
of << PHASE_WAIT_STR << "\n";
} else if (deplState == AutonomousDeplState::SECOND_BURN) {
of << PHASE_SECOND_BURN_STR << "\n";
}
of << "secs_since_start: " << std::to_string(secsSinceBoot) << "\n";
}
if (firstAutonomousCycle) {
firstAutonomousCycle = false;
}
return true;
}
bool SolarArrayDeploymentHandler::checkMainPowerOn() { return checkMainPower(true); }
bool SolarArrayDeploymentHandler::checkMainPowerOff() { return checkMainPower(false); }
bool SolarArrayDeploymentHandler::checkMainPower(bool onOff) {
if ((onOff and mainLineSwitcher.getSwitchState(mainLineSwitch) == PowerSwitchIF::SWITCH_ON) or
(not onOff and
mainLineSwitcher.getSwitchState(mainLineSwitch) == PowerSwitchIF::SWITCH_OFF)) {
return true;
}
if (mainSwitchCountdown.hasTimedOut()) {
if (onOff) {
triggerEvent(MAIN_SWITCH_ON_TIMEOUT); triggerEvent(MAIN_SWITCH_ON_TIMEOUT);
actionHelper.finish(false, rememberCommanderId, DEPLOY_SOLAR_ARRAYS, } else {
MAIN_SWITCH_TIMEOUT_FAILURE); triggerEvent(MAIN_SWITCH_OFF_TIMEOUT);
stateMachine = WAIT_ON_DELOYMENT_COMMAND;
} }
if (retryCounter < 3) {
if (onOff) {
stateMachine = MAIN_POWER_ON;
} else {
stateMachine = MAIN_POWER_OFF;
}
retryCounter++;
} else {
finishFsm(MAIN_SWITCH_TIMEOUT_FAILURE);
}
}
return false;
}
bool SolarArrayDeploymentHandler::startFsmOn(uint32_t burnCountdownSecs, bool dryRun) {
if (stateMachine != StateMachine::IDLE) {
return false;
}
if (burnCountdownSecs > config::SA_DEPL_MAX_BURN_TIME) {
burnCountdownSecs = config::SA_DEPL_MAX_BURN_TIME;
}
fsmInfo.dryRun = dryRun;
fsmInfo.burnCountdownMs = burnCountdownSecs * 1000;
stateMachine = StateMachine::MAIN_POWER_ON;
retryCounter = 0;
return true;
}
void SolarArrayDeploymentHandler::startFsmOff() {
if (stateMachine != StateMachine::IDLE) {
// off commands override the state machine. Cancel any active action commands.
finishFsm(returnvalue::FAILED);
}
retryCounter = 0;
stateMachine = StateMachine::MAIN_POWER_OFF;
}
void SolarArrayDeploymentHandler::finishFsm(ReturnValue_t resultForActionHelper) {
retryCounter = 0;
stateMachine = StateMachine::IDLE;
fsmInfo.dryRun = false;
fsmInfo.alternationDummy = false;
if (actionActive) {
bool success = false;
if (resultForActionHelper == returnvalue::OK or
resultForActionHelper == HasActionsIF::EXECUTION_FINISHED) {
success = true;
}
actionHelper.finish(success, rememberCommanderId, activeCmd, resultForActionHelper);
} }
} }
void SolarArrayDeploymentHandler::switchDeploymentTransistors() { void SolarArrayDeploymentHandler::allOff() {
deploymentTransistorsOff();
mainLineSwitcher.sendSwitchCommand(mainLineSwitch, PowerSwitchIF::SWITCH_OFF);
mainSwitchCountdown.setTimeout(mainLineSwitcher.getSwitchDelayMs());
}
bool SolarArrayDeploymentHandler::dryRunStringInFile(const char* filename) {
std::ifstream ifile(filename);
if (ifile.bad()) {
return false;
}
std::string line;
while (getline(ifile, line)) {
if (line.find("dryrun") != std::string::npos) {
return true;
}
}
return false;
}
ReturnValue_t SolarArrayDeploymentHandler::executeAction(ActionId_t actionId,
MessageQueueId_t commandedBy,
const uint8_t* data, size_t size) {
ReturnValue_t result = returnvalue::OK; ReturnValue_t result = returnvalue::OK;
result = gpioInterface->pullHigh(deplSA1); if (actionId == DEPLOY_SOLAR_ARRAYS_MANUALLY) {
ManualDeploymentCommand cmd;
if (size < cmd.getSerializedSize()) {
return HasActionsIF::INVALID_PARAMETERS;
}
result = cmd.deSerialize(&data, &size, SerializeIF::Endianness::NETWORK);
if (result != returnvalue::OK) {
return result;
}
uint32_t burnCountdown = cmd.getBurnTime();
if (not startFsmOn(burnCountdown, cmd.isDryRun())) {
return HasActionsIF::IS_BUSY;
}
actionActive = true;
rememberCommanderId = commandedBy;
return result;
} else if (actionId == SWITCH_OFF_DEPLOYMENT) {
startFsmOff();
actionActive = true;
rememberCommanderId = commandedBy;
return result;
} else {
return HasActionsIF::INVALID_ACTION_ID;
}
return result;
}
ReturnValue_t SolarArrayDeploymentHandler::saGpioAlternation() {
ReturnValue_t status = returnvalue::OK;
ReturnValue_t result;
if (channelAlternationCd.hasTimedOut() and not fsmInfo.dryRun) {
if (fsmInfo.alternationDummy) {
result = sa1Off();
if (result != returnvalue::OK) {
status = result;
}
TaskFactory::delayTask(1);
result = sa2On();
if (result != returnvalue::OK) {
status = result;
}
} else {
result = sa2Off();
if (result != returnvalue::OK) {
status = result;
}
TaskFactory::delayTask(1);
result = sa1On();
if (result != returnvalue::OK) {
status = result;
}
}
fsmInfo.alternationDummy = not fsmInfo.alternationDummy;
channelAlternationCd.resetTimer();
}
return status;
}
ReturnValue_t SolarArrayDeploymentHandler::deploymentTransistorsOff() {
ReturnValue_t status = returnvalue::OK;
ReturnValue_t result = sa1Off();
if (result != returnvalue::OK) { if (result != returnvalue::OK) {
sif::debug << "SolarArrayDeploymentHandler::handleStateMachine: Failed to pull solar" status = result;
" array deployment switch 1 high " }
<< std::endl; result = sa2Off();
/* If gpio switch high failed, state machine is reset to wait for a command reinitiating if (result != returnvalue::OK) {
* the deployment sequence. */ status = result;
stateMachine = WAIT_ON_DELOYMENT_COMMAND; }
return status;
}
ReturnValue_t SolarArrayDeploymentHandler::sa1On() {
ReturnValue_t result = gpioInterface.pullHigh(deplSA1);
if (result != returnvalue::OK) {
sif::warning << "SolarArrayDeploymentHandler::handleStateMachine: Failed to pull solar"
" array deployment switch 1 high"
<< std::endl;
// If gpio switch high failed, state machine is reset to wait for a command re-initiating
// the deployment sequence.
triggerEvent(DEPL_SA1_GPIO_SWTICH_ON_FAILED); triggerEvent(DEPL_SA1_GPIO_SWTICH_ON_FAILED);
actionHelper.finish(false, rememberCommanderId, DEPLOY_SOLAR_ARRAYS, SWITCHING_DEPL_SA2_FAILED);
mainLineSwitcher->sendSwitchCommand(mainLineSwitch, PowerSwitchIF::SWITCH_OFF);
} }
result = gpioInterface->pullHigh(deplSA2); return result;
if (result != returnvalue::OK) {
sif::debug << "SolarArrayDeploymentHandler::handleStateMachine: Failed to pull solar"
" array deployment switch 2 high "
<< std::endl;
stateMachine = WAIT_ON_DELOYMENT_COMMAND;
triggerEvent(DEPL_SA2_GPIO_SWTICH_ON_FAILED);
actionHelper.finish(false, rememberCommanderId, DEPLOY_SOLAR_ARRAYS, SWITCHING_DEPL_SA2_FAILED);
mainLineSwitcher->sendSwitchCommand(mainLineSwitch, PowerSwitchIF::SWITCH_OFF);
}
deploymentCountdown.setTimeout(burnTimeMs);
stateMachine = WAIT_ON_DEPLOYMENT_FINISH;
} }
void SolarArrayDeploymentHandler::handleDeploymentFinish() { ReturnValue_t SolarArrayDeploymentHandler::sa1Off() {
ReturnValue_t result = returnvalue::OK; ReturnValue_t result = gpioInterface.pullLow(deplSA1);
if (deploymentCountdown.hasTimedOut()) { if (result != returnvalue::OK) {
actionHelper.finish(true, rememberCommanderId, DEPLOY_SOLAR_ARRAYS, returnvalue::OK); sif::warning << "SolarArrayDeploymentHandler::handleStateMachine: Failed to pull solar"
result = gpioInterface->pullLow(deplSA1); " array deployment switch 1 low"
if (result != returnvalue::OK) {
sif::debug << "SolarArrayDeploymentHandler::handleStateMachine: Failed to pull solar"
" array deployment switch 1 low "
<< std::endl; << std::endl;
} // If gpio switch high failed, state machine is reset to wait for a command re-initiating
result = gpioInterface->pullLow(deplSA2); // the deployment sequence.
if (result != returnvalue::OK) { triggerEvent(DEPL_SA1_GPIO_SWTICH_OFF_FAILED);
sif::debug << "SolarArrayDeploymentHandler::handleStateMachine: Failed to pull solar"
" array deployment switch 2 low "
<< std::endl;
}
mainLineSwitcher->sendSwitchCommand(mainLineSwitch, PowerSwitchIF::SWITCH_OFF);
mainSwitchCountdown.setTimeout(mainLineSwitcher->getSwitchDelayMs());
stateMachine = WAIT_FOR_MAIN_SWITCH_OFF;
} }
return result;
}
ReturnValue_t SolarArrayDeploymentHandler::sa2On() {
ReturnValue_t result = gpioInterface.pullHigh(deplSA2);
if (result != returnvalue::OK) {
sif::warning << "SolarArrayDeploymentHandler::handleStateMachine: Failed to pull solar"
" array deployment switch 2 high"
<< std::endl;
// If gpio switch high failed, state machine is reset to wait for a command re-initiating
// the deployment sequence.
triggerEvent(DEPL_SA2_GPIO_SWTICH_ON_FAILED);
}
return result;
}
ReturnValue_t SolarArrayDeploymentHandler::sa2Off() {
ReturnValue_t result = gpioInterface.pullLow(deplSA2);
if (result != returnvalue::OK) {
sif::warning << "SolarArrayDeploymentHandler::handleStateMachine: Failed to pull solar"
" array deployment switch 2 low"
<< std::endl;
// If gpio switch high failed, state machine is reset to wait for a command re-initiating
// the deployment sequence.
triggerEvent(DEPL_SA2_GPIO_SWTICH_OFF_FAILED);
}
return result;
} }
void SolarArrayDeploymentHandler::readCommandQueue() { void SolarArrayDeploymentHandler::readCommandQueue() {
@ -181,27 +480,14 @@ void SolarArrayDeploymentHandler::readCommandQueue() {
} }
} }
ReturnValue_t SolarArrayDeploymentHandler::executeAction(ActionId_t actionId,
MessageQueueId_t commandedBy,
const uint8_t* data, size_t size) {
ReturnValue_t result;
if (stateMachine != WAIT_ON_DELOYMENT_COMMAND) {
sif::error << "SolarArrayDeploymentHandler::executeAction: Received command while not in"
<< "waiting-on-command-state" << std::endl;
return DEPLOYMENT_ALREADY_EXECUTING;
}
if (actionId != DEPLOY_SOLAR_ARRAYS) {
sif::error << "SolarArrayDeploymentHandler::executeAction: Received invalid command"
<< std::endl;
result = COMMAND_NOT_SUPPORTED;
} else {
stateMachine = SWITCH_8V_ON;
rememberCommanderId = commandedBy;
result = returnvalue::OK;
}
return result;
}
MessageQueueId_t SolarArrayDeploymentHandler::getCommandQueue() const { MessageQueueId_t SolarArrayDeploymentHandler::getCommandQueue() const {
return commandQueue->getId(); return commandQueue->getId();
} }
ReturnValue_t SolarArrayDeploymentHandler::initialize() {
ReturnValue_t result = actionHelper.initialize(commandQueue);
if (result != returnvalue::OK) {
return ObjectManagerIF::CHILD_INIT_FAILED;
}
return SystemObject::initialize();
}

View File

@ -1,22 +1,46 @@
#ifndef MISSION_DEVICES_SOLARARRAYDEPLOYMENT_H_ #ifndef MISSION_DEVICES_SOLARARRAYDEPLOYMENT_H_
#define MISSION_DEVICES_SOLARARRAYDEPLOYMENT_H_ #define MISSION_DEVICES_SOLARARRAYDEPLOYMENT_H_
#include <devices/powerSwitcherList.h> #include <fsfw/globalfunctions/PeriodicOperationDivider.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/tasks/ExecutableObjectIF.h>
#include <fsfw/timemanager/Countdown.h>
#include <fsfw_hal/common/gpio/GpioIF.h>
#include <unordered_map> #include <unordered_map>
#include "devices/powerSwitcherList.h"
#include "eive/definitions.h"
#include "events/subsystemIdRanges.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 "returnvalues/classIds.h" #include "returnvalues/classIds.h"
enum DeploymentChannels : uint8_t { SA_1 = 1, SA_2 = 2 };
class ManualDeploymentCommand : public SerialLinkedListAdapter<SerializeIF> {
public:
ManualDeploymentCommand() { setLinks(); }
void setLinks() {
setStart(&burnTime);
burnTime.setNext(&dryRun);
}
uint32_t getBurnTime() const { return burnTime.entry; }
bool isDryRun() const { return dryRun.entry; }
private:
SerializeElement<uint32_t> burnTime;
SerializeElement<uint8_t> dryRun;
};
/** /**
* @brief This class is used to control the solar array deployment. * @brief This class is used to control the solar array deployment.
* *
@ -26,8 +50,29 @@ class SolarArrayDeploymentHandler : public ExecutableObjectIF,
public SystemObject, public SystemObject,
public HasActionsIF { public HasActionsIF {
public: public:
static const DeviceCommandId_t DEPLOY_SOLAR_ARRAYS = 0x5; //! Manual deployment of the solar arrays. Burn time and channels are supplied with TC parameters
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 * @brief constructor
* *
@ -43,10 +88,9 @@ class SolarArrayDeploymentHandler : public ExecutableObjectIF,
* @param deplSA2 gpioId of the GPIO controlling the deployment 2 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. * @param burnTimeMs Time duration the power will be applied to the burn wires.
*/ */
SolarArrayDeploymentHandler(object_id_t setObjectId, object_id_t gpioDriverId, SolarArrayDeploymentHandler(object_id_t setObjectId, GpioIF& gpio,
CookieIF* gpioCookie, object_id_t mainLineSwitcherObjectId, PowerSwitchIF& mainLineSwitcher, pcdu::Switches mainLineSwitch,
pcdu::Switches mainLineSwitch, gpioId_t deplSA1, gpioId_t deplSA2, gpioId_t deplSA1, gpioId_t deplSA2, SdCardMountedIF& sdcMountedIF);
uint32_t burnTimeMs);
virtual ~SolarArrayDeploymentHandler(); virtual ~SolarArrayDeploymentHandler();
@ -58,6 +102,26 @@ class SolarArrayDeploymentHandler : public ExecutableObjectIF,
virtual ReturnValue_t initialize() override; virtual ReturnValue_t initialize() override;
private: 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;
uint32_t burnCountdownMs = config::SA_DEPL_MAX_BURN_TIME;
};
static const uint8_t INTERFACE_ID = CLASS_ID::SA_DEPL_HANDLER; 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 COMMAND_NOT_SUPPORTED = MAKE_RETURN_CODE(0xA0);
static const ReturnValue_t DEPLOYMENT_ALREADY_EXECUTING = MAKE_RETURN_CODE(0xA1); static const ReturnValue_t DEPLOYMENT_ALREADY_EXECUTING = MAKE_RETURN_CODE(0xA1);
@ -66,23 +130,41 @@ class SolarArrayDeploymentHandler : public ExecutableObjectIF,
static const ReturnValue_t SWITCHING_DEPL_SA2_FAILED = MAKE_RETURN_CODE(0xA4); static const ReturnValue_t SWITCHING_DEPL_SA2_FAILED = MAKE_RETURN_CODE(0xA4);
static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SA_DEPL_HANDLER; static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::SA_DEPL_HANDLER;
static const Event MAIN_SWITCH_ON_TIMEOUT = MAKE_EVENT(0, severity::LOW);
static const Event MAIN_SWITCH_OFF_TIMEOUT = MAKE_EVENT(1, severity::LOW);
static const Event DEPLOYMENT_FAILED = MAKE_EVENT(2, severity::HIGH);
static const Event DEPL_SA1_GPIO_SWTICH_ON_FAILED = MAKE_EVENT(3, severity::HIGH);
static const Event DEPL_SA2_GPIO_SWTICH_ON_FAILED = MAKE_EVENT(4, severity::HIGH);
enum StateMachine { //! [EXPORT] : [COMMENT] P1: Burn duration in milliseconds, P2: Dry run flag
WAIT_ON_DELOYMENT_COMMAND, static constexpr Event BURN_PHASE_START = event::makeEvent(SUBSYSTEM_ID, 0, severity::INFO);
SWITCH_8V_ON, //! [EXPORT] : [COMMENT] P1: Burn duration in milliseconds, P2: Dry run flag
WAIT_ON_8V_SWITCH, static constexpr Event BURN_PHASE_DONE = event::makeEvent(SUBSYSTEM_ID, 1, severity::INFO);
SWITCH_DEPL_GPIOS, static constexpr Event MAIN_SWITCH_ON_TIMEOUT = event::makeEvent(SUBSYSTEM_ID, 2, severity::LOW);
WAIT_ON_DEPLOYMENT_FINISH, static constexpr Event MAIN_SWITCH_OFF_TIMEOUT = event::makeEvent(SUBSYSTEM_ID, 3, severity::LOW);
WAIT_FOR_MAIN_SWITCH_OFF 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);
StateMachine stateMachine = WAIT_ON_DELOYMENT_COMMAND; FsmInfo fsmInfo;
StateMachine stateMachine = IDLE;
bool actionActive = false;
bool firstAutonomousCycle = true;
ActionId_t activeCmd = HasActionsIF::INVALID_ACTION_ID;
std::optional<uint64_t> initUptime;
PeriodicOperationDivider opDivider = PeriodicOperationDivider(5);
uint8_t retryCounter = 3;
bool startFsmOn(uint32_t burnCountdownSecs, 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. * This countdown is used to check if the PCDU sets the 8V line on in the intended time.
*/ */
@ -91,7 +173,10 @@ class SolarArrayDeploymentHandler : public ExecutableObjectIF,
/** /**
* This countdown is used to wait for the burn wire being successful cut. * This countdown is used to wait for the burn wire being successful cut.
*/ */
Countdown deploymentCountdown; Countdown burnCountdown;
Countdown channelAlternationCd =
Countdown(config::SA_DEPL_CHANNEL_ALTERNATION_INTERVAL_SECS * 1000);
/** /**
* The message queue id of the component commanding an action will be stored in this variable. * The message queue id of the component commanding an action will be stored in this variable.
@ -101,36 +186,25 @@ class SolarArrayDeploymentHandler : public ExecutableObjectIF,
/** Size of command queue */ /** Size of command queue */
size_t cmdQueueSize = 20; size_t cmdQueueSize = 20;
GpioIF& gpioInterface;
/** The object ID of the GPIO driver which switches the deployment transistors */
object_id_t gpioDriverId;
CookieIF* gpioCookie;
/** Object id of the object responsible to switch the 8V power input. Typically the PCDU. */
object_id_t mainLineSwitcherObjectId;
/** Switch number of the 8V power switch */
uint8_t mainLineSwitch;
gpioId_t deplSA1; gpioId_t deplSA1;
gpioId_t deplSA2; gpioId_t deplSA2;
GpioIF* gpioInterface = nullptr;
/** Time duration switches are active to cut the burn wire */
uint32_t burnTimeMs;
/** Queue to receive messages from other objects. */
MessageQueueIF* commandQueue = nullptr;
/** /**
* After initialization this pointer will hold the reference to the main line switcher object. * After initialization this pointer will hold the reference to the main line switcher object.
*/ */
PowerSwitchIF* mainLineSwitcher = nullptr; PowerSwitchIF& mainLineSwitcher;
/** Switch number of the 8V power switch */
uint8_t mainLineSwitch;
SdCardMountedIF& sdcMan;
ActionHelper actionHelper; ActionHelper actionHelper;
/** Queue to receive messages from other objects. */
MessageQueueIF* commandQueue = nullptr;
void readCommandQueue(); void readCommandQueue();
/** /**
@ -142,18 +216,18 @@ class SolarArrayDeploymentHandler : public ExecutableObjectIF,
* @brief This function polls the 8V switch state and changes the state machine when the * @brief This function polls the 8V switch state and changes the state machine when the
* switch has been enabled. * switch has been enabled.
*/ */
void performWaitOn8VActions(); bool checkMainPowerOn();
bool checkMainPowerOff();
bool checkMainPower(bool onOff);
/** void allOff();
* @brief This functions handles the switching of the solar array deployment transistors.
*/
void switchDeploymentTransistors();
/** ReturnValue_t deploymentTransistorsOff();
* @brief This function performs actions to finish the deployment. Essentially switches ReturnValue_t saGpioAlternation();
* are turned of after the burn time has expired. ReturnValue_t sa1On();
*/ ReturnValue_t sa1Off();
void handleDeploymentFinish(); ReturnValue_t sa2On();
ReturnValue_t sa2Off();
}; };
#endif /* MISSION_DEVICES_SOLARARRAYDEPLOYMENT_H_ */ #endif /* MISSION_DEVICES_SOLARARRAYDEPLOYMENT_H_ */

2
tmtc

@ -1 +1 @@
Subproject commit 4c3f5f28256be0dbfc5b46ea87f8f484c93a9996 Subproject commit 646cf1a14e0fa61d5e91e26a46017be557bad642