Merge remote-tracking branch 'origin/develop' into continue_tcs_tests
All checks were successful
EIVE/eive-obsw/pipeline/pr-develop This commit looks good
All checks were successful
EIVE/eive-obsw/pipeline/pr-develop This commit looks good
This commit is contained in:
commit
d9e38d97ee
@ -27,6 +27,8 @@ will consitute of a breaking change warranting a new major release:
|
|||||||
temperature for the all-ones value (0x0fff).
|
temperature for the all-ones value (0x0fff).
|
||||||
- Better reply result handling for the ACS board devices.
|
- Better reply result handling for the ACS board devices.
|
||||||
- ADIS1650X initial timeout handling now performed in device handler.
|
- ADIS1650X initial timeout handling now performed in device handler.
|
||||||
|
- The RW assembly and TCS board assembly now perform proper power switch handling for their
|
||||||
|
recovery handling.
|
||||||
|
|
||||||
## Changed
|
## Changed
|
||||||
|
|
||||||
@ -35,6 +37,8 @@ will consitute of a breaking change warranting a new major release:
|
|||||||
This gives other tasks some time to register the SD cards being unusable, and therefore provides
|
This gives other tasks some time to register the SD cards being unusable, and therefore provides
|
||||||
a way for them to perform any re-initialization tasks necessary after SD card switches.
|
a way for them to perform any re-initialization tasks necessary after SD card switches.
|
||||||
- TCS controller now only has an OFF mode and an ON mode
|
- TCS controller now only has an OFF mode and an ON mode
|
||||||
|
- The TCS controller pauses operations related to the TCS board assembly (reading sensors and
|
||||||
|
the primary control loop) while a TCS board recovery is on-going.
|
||||||
- Allow specifying custom OBSW update filename. This allowed keeping a cleaner file structure
|
- Allow specifying custom OBSW update filename. This allowed keeping a cleaner file structure
|
||||||
where each update has a name including the version
|
where each update has a name including the version
|
||||||
- The files extracted during an update process are deleted after the update was performed to keep
|
- The files extracted during an update process are deleted after the update was performed to keep
|
||||||
|
@ -40,6 +40,7 @@
|
|||||||
#include "mission/system/com/comModeTree.h"
|
#include "mission/system/com/comModeTree.h"
|
||||||
#include "mission/system/tree/payloadModeTree.h"
|
#include "mission/system/tree/payloadModeTree.h"
|
||||||
#include "mission/system/tree/tcsModeTree.h"
|
#include "mission/system/tree/tcsModeTree.h"
|
||||||
|
#include "mission/tcs/defs.h"
|
||||||
|
|
||||||
void dummy::createDummies(DummyCfg cfg, PowerSwitchIF& pwrSwitcher, GpioIF* gpioIF) {
|
void dummy::createDummies(DummyCfg cfg, PowerSwitchIF& pwrSwitcher, GpioIF* gpioIF) {
|
||||||
new ComIFDummy(objects::DUMMY_COM_IF);
|
new ComIFDummy(objects::DUMMY_COM_IF);
|
||||||
@ -204,7 +205,8 @@ void dummy::createDummies(DummyCfg cfg, PowerSwitchIF& pwrSwitcher, GpioIF* gpio
|
|||||||
|
|
||||||
new TemperatureSensorInserter(objects::THERMAL_TEMP_INSERTER, rtdSensorDummies,
|
new TemperatureSensorInserter(objects::THERMAL_TEMP_INSERTER, rtdSensorDummies,
|
||||||
tmpSensorDummies);
|
tmpSensorDummies);
|
||||||
TcsBoardAssembly* tcsBoardAssy = ObjectFactory::createTcsBoardAssy(pwrSwitcher);
|
TcsBoardAssembly* tcsBoardAssy =
|
||||||
|
ObjectFactory::createTcsBoardAssy(pwrSwitcher, tcs::TCS_BOARD_SHORTLY_UNAVAILABLE);
|
||||||
for (auto& rtd : rtdSensorDummies) {
|
for (auto& rtd : rtdSensorDummies) {
|
||||||
rtd.second->connectModeTreeParent(*tcsBoardAssy);
|
rtd.second->connectModeTreeParent(*tcsBoardAssy);
|
||||||
}
|
}
|
||||||
|
2
fsfw
2
fsfw
@ -1 +1 @@
|
|||||||
Subproject commit 285d327b97514946f0714e477289f67ee8bd413f
|
Subproject commit ffa2fa477f105cc876264335d5b25fc9b174a181
|
@ -29,6 +29,7 @@
|
|||||||
#include "mission/system/acs/acsModeTree.h"
|
#include "mission/system/acs/acsModeTree.h"
|
||||||
#include "mission/system/tree/payloadModeTree.h"
|
#include "mission/system/tree/payloadModeTree.h"
|
||||||
#include "mission/system/tree/tcsModeTree.h"
|
#include "mission/system/tree/tcsModeTree.h"
|
||||||
|
#include "mission/tcs/defs.h"
|
||||||
|
|
||||||
void ObjectFactory::createSunSensorComponents(GpioIF* gpioComIF, SpiComIF* spiComIF,
|
void ObjectFactory::createSunSensorComponents(GpioIF* gpioComIF, SpiComIF* spiComIF,
|
||||||
PowerSwitchIF& pwrSwitcher, std::string spiDev,
|
PowerSwitchIF& pwrSwitcher, std::string spiDev,
|
||||||
@ -278,7 +279,8 @@ void ObjectFactory::createRtdComponents(std::string spiDev, GpioIF* gpioComIF,
|
|||||||
std::array<Max31865EiveHandler*, NUM_RTDS> rtds = {};
|
std::array<Max31865EiveHandler*, NUM_RTDS> rtds = {};
|
||||||
RtdFdir* rtdFdir = nullptr;
|
RtdFdir* rtdFdir = nullptr;
|
||||||
|
|
||||||
TcsBoardAssembly* tcsBoardAss = ObjectFactory::createTcsBoardAssy(*pwrSwitcher);
|
TcsBoardAssembly* tcsBoardAss =
|
||||||
|
ObjectFactory::createTcsBoardAssy(*pwrSwitcher, tcs::TCS_BOARD_SHORTLY_UNAVAILABLE);
|
||||||
|
|
||||||
// Create special low level reader communication interface
|
// Create special low level reader communication interface
|
||||||
new Max31865RtdPolling(objects::SPI_RTD_COM_IF, comIF, gpioComIF);
|
new Max31865RtdPolling(objects::SPI_RTD_COM_IF, comIF, gpioComIF);
|
||||||
|
@ -1 +1,3 @@
|
|||||||
|
|
||||||
|
target_sources(
|
||||||
|
${LIB_EIVE_MISSION} PRIVATE CfdpHandler.cpp)
|
||||||
|
134
mission/cfdp/CfdpHandler.cpp
Normal file
134
mission/cfdp/CfdpHandler.cpp
Normal file
@ -0,0 +1,134 @@
|
|||||||
|
#include "CfdpHandler.h"
|
||||||
|
|
||||||
|
#include "fsfw/cfdp/pdu/AckPduReader.h"
|
||||||
|
#include "fsfw/cfdp/pdu/PduHeaderReader.h"
|
||||||
|
#include "fsfw/globalfunctions/arrayprinter.h"
|
||||||
|
#include "fsfw/ipc/QueueFactory.h"
|
||||||
|
#include "fsfw/tmtcservices/TmTcMessage.h"
|
||||||
|
|
||||||
|
using namespace returnvalue;
|
||||||
|
using namespace cfdp;
|
||||||
|
|
||||||
|
CfdpHandler::CfdpHandler(const FsfwHandlerParams& fsfwParams, const CfdpHandlerCfg& cfdpCfg)
|
||||||
|
: SystemObject(fsfwParams.objectId),
|
||||||
|
msgQueue(fsfwParams.msgQueue),
|
||||||
|
destHandler(
|
||||||
|
DestHandlerParams(LocalEntityCfg(cfdpCfg.id, cfdpCfg.indicCfg, cfdpCfg.faultHandler),
|
||||||
|
cfdpCfg.userHandler, cfdpCfg.remoteCfgProvider, cfdpCfg.packetInfoList,
|
||||||
|
cfdpCfg.lostSegmentsList),
|
||||||
|
FsfwParams(fsfwParams.packetDest, nullptr, this, fsfwParams.tcStore,
|
||||||
|
fsfwParams.tmStore)) {
|
||||||
|
destHandler.setMsgQueue(msgQueue);
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] const char* CfdpHandler::getName() const { return "CFDP Handler"; }
|
||||||
|
|
||||||
|
[[nodiscard]] uint32_t CfdpHandler::getIdentifier() const {
|
||||||
|
return destHandler.getDestHandlerParams().cfg.localId.getValue();
|
||||||
|
}
|
||||||
|
|
||||||
|
[[nodiscard]] MessageQueueId_t CfdpHandler::getRequestQueue() const { return msgQueue.getId(); }
|
||||||
|
|
||||||
|
ReturnValue_t CfdpHandler::initialize() {
|
||||||
|
ReturnValue_t result = destHandler.initialize();
|
||||||
|
if (result != OK) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
tcStore = destHandler.getTcStore();
|
||||||
|
tmStore = destHandler.getTmStore();
|
||||||
|
|
||||||
|
return SystemObject::initialize();
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t CfdpHandler::performOperation(uint8_t operationCode) {
|
||||||
|
// TODO: Receive TC packets and route them to source and dest handler, depending on which is
|
||||||
|
// correct or more appropriate
|
||||||
|
ReturnValue_t status;
|
||||||
|
ReturnValue_t result = OK;
|
||||||
|
TmTcMessage tmtcMsg;
|
||||||
|
for (status = msgQueue.receiveMessage(&tmtcMsg); status == returnvalue::OK;
|
||||||
|
status = msgQueue.receiveMessage(&tmtcMsg)) {
|
||||||
|
result = handleCfdpPacket(tmtcMsg);
|
||||||
|
if (result != OK) {
|
||||||
|
status = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
auto& fsmRes = destHandler.performStateMachine();
|
||||||
|
// TODO: Error handling?
|
||||||
|
while (fsmRes.callStatus == CallStatus::CALL_AGAIN) {
|
||||||
|
destHandler.performStateMachine();
|
||||||
|
// TODO: Error handling?
|
||||||
|
}
|
||||||
|
return status;
|
||||||
|
}
|
||||||
|
|
||||||
|
ReturnValue_t CfdpHandler::handleCfdpPacket(TmTcMessage& msg) {
|
||||||
|
auto accessorPair = tcStore->getData(msg.getStorageId());
|
||||||
|
if (accessorPair.first != OK) {
|
||||||
|
return accessorPair.first;
|
||||||
|
}
|
||||||
|
PduHeaderReader reader(accessorPair.second.data(), accessorPair.second.size());
|
||||||
|
ReturnValue_t result = reader.parseData();
|
||||||
|
if (result != returnvalue::OK) {
|
||||||
|
return INVALID_PDU_FORMAT;
|
||||||
|
}
|
||||||
|
// The CFDP distributor should have taken care of ensuring the destination ID is correct
|
||||||
|
PduType type = reader.getPduType();
|
||||||
|
// Only the destination handler can process these PDUs
|
||||||
|
if (type == PduType::FILE_DATA) {
|
||||||
|
// Disable auto-deletion of packet
|
||||||
|
accessorPair.second.release();
|
||||||
|
PacketInfo info(type, msg.getStorageId());
|
||||||
|
result = destHandler.passPacket(info);
|
||||||
|
} else {
|
||||||
|
// Route depending on PDU type and directive type if applicable. It retrieves directive type
|
||||||
|
// from the raw stream for better performance (with sanity and directive code check).
|
||||||
|
// The routing is based on section 4.5 of the CFDP standard which specifies the PDU forwarding
|
||||||
|
// procedure.
|
||||||
|
|
||||||
|
// PDU header only. Invalid supplied data. A directive packet should have a valid data field
|
||||||
|
// with at least one byte being the directive code
|
||||||
|
const uint8_t* pduDataField = reader.getPduDataField();
|
||||||
|
if (pduDataField == nullptr) {
|
||||||
|
return INVALID_PDU_FORMAT;
|
||||||
|
}
|
||||||
|
if (not FileDirectiveReader::checkFileDirective(pduDataField[0])) {
|
||||||
|
return INVALID_DIRECTIVE_FIELD;
|
||||||
|
}
|
||||||
|
auto directive = static_cast<FileDirective>(pduDataField[0]);
|
||||||
|
|
||||||
|
auto passToDestHandler = [&]() {
|
||||||
|
accessorPair.second.release();
|
||||||
|
PacketInfo info(type, msg.getStorageId(), directive);
|
||||||
|
result = destHandler.passPacket(info);
|
||||||
|
};
|
||||||
|
auto passToSourceHandler = [&]() {
|
||||||
|
|
||||||
|
};
|
||||||
|
if (directive == FileDirective::METADATA or directive == FileDirective::EOF_DIRECTIVE or
|
||||||
|
directive == FileDirective::PROMPT) {
|
||||||
|
// Section b) of 4.5.3: These PDUs should always be targeted towards the file receiver a.k.a.
|
||||||
|
// the destination handler
|
||||||
|
passToDestHandler();
|
||||||
|
} else if (directive == FileDirective::FINISH or directive == FileDirective::NAK or
|
||||||
|
directive == FileDirective::KEEP_ALIVE) {
|
||||||
|
// Section c) of 4.5.3: These PDUs should always be targeted towards the file sender a.k.a.
|
||||||
|
// the source handler
|
||||||
|
passToSourceHandler();
|
||||||
|
} else if (directive == FileDirective::ACK) {
|
||||||
|
// Section a): Recipient depends of the type of PDU that is being acknowledged. We can simply
|
||||||
|
// extract the PDU type from the raw stream. If it is an EOF PDU, this packet is passed to
|
||||||
|
// the source handler, for a Finished PDU, it is passed to the destination handler.
|
||||||
|
FileDirective ackedDirective;
|
||||||
|
if (not AckPduReader::checkAckedDirectiveField(pduDataField[1], ackedDirective)) {
|
||||||
|
return INVALID_ACK_DIRECTIVE_FIELDS;
|
||||||
|
}
|
||||||
|
if (ackedDirective == FileDirective::EOF_DIRECTIVE) {
|
||||||
|
passToSourceHandler();
|
||||||
|
} else if (ackedDirective == FileDirective::FINISH) {
|
||||||
|
passToDestHandler();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
71
mission/cfdp/CfdpHandler.h
Normal file
71
mission/cfdp/CfdpHandler.h
Normal file
@ -0,0 +1,71 @@
|
|||||||
|
#ifndef FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H
|
||||||
|
#define FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include "fsfw/cfdp/handler/DestHandler.h"
|
||||||
|
#include "fsfw/objectmanager/SystemObject.h"
|
||||||
|
#include "fsfw/tasks/ExecutableObjectIF.h"
|
||||||
|
#include "fsfw/tmtcservices/AcceptsTelecommandsIF.h"
|
||||||
|
#include "fsfw/tmtcservices/TmTcMessage.h"
|
||||||
|
|
||||||
|
struct FsfwHandlerParams {
|
||||||
|
FsfwHandlerParams(object_id_t objectId, HasFileSystemIF& vfs, AcceptsTelemetryIF& packetDest,
|
||||||
|
StorageManagerIF& tcStore, StorageManagerIF& tmStore, MessageQueueIF& msgQueue)
|
||||||
|
: objectId(objectId),
|
||||||
|
vfs(vfs),
|
||||||
|
packetDest(packetDest),
|
||||||
|
tcStore(tcStore),
|
||||||
|
tmStore(tmStore),
|
||||||
|
msgQueue(msgQueue) {}
|
||||||
|
object_id_t objectId{};
|
||||||
|
HasFileSystemIF& vfs;
|
||||||
|
AcceptsTelemetryIF& packetDest;
|
||||||
|
StorageManagerIF& tcStore;
|
||||||
|
StorageManagerIF& tmStore;
|
||||||
|
MessageQueueIF& msgQueue;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CfdpHandlerCfg {
|
||||||
|
CfdpHandlerCfg(cfdp::EntityId localId, cfdp::IndicationCfg indicationCfg,
|
||||||
|
cfdp::UserBase& userHandler, cfdp::FaultHandlerBase& userFaultHandler,
|
||||||
|
cfdp::PacketInfoListBase& packetInfo, cfdp::LostSegmentsListBase& lostSegmentsList,
|
||||||
|
cfdp::RemoteConfigTableIF& remoteCfgProvider)
|
||||||
|
: id(std::move(localId)),
|
||||||
|
indicCfg(indicationCfg),
|
||||||
|
packetInfoList(packetInfo),
|
||||||
|
lostSegmentsList(lostSegmentsList),
|
||||||
|
remoteCfgProvider(remoteCfgProvider),
|
||||||
|
userHandler(userHandler),
|
||||||
|
faultHandler(userFaultHandler) {}
|
||||||
|
|
||||||
|
cfdp::EntityId id;
|
||||||
|
cfdp::IndicationCfg indicCfg;
|
||||||
|
cfdp::PacketInfoListBase& packetInfoList;
|
||||||
|
cfdp::LostSegmentsListBase& lostSegmentsList;
|
||||||
|
cfdp::RemoteConfigTableIF& remoteCfgProvider;
|
||||||
|
cfdp::UserBase& userHandler;
|
||||||
|
cfdp::FaultHandlerBase& faultHandler;
|
||||||
|
};
|
||||||
|
|
||||||
|
class CfdpHandler : public SystemObject, public ExecutableObjectIF, public AcceptsTelecommandsIF {
|
||||||
|
public:
|
||||||
|
explicit CfdpHandler(const FsfwHandlerParams& fsfwParams, const CfdpHandlerCfg& cfdpCfg);
|
||||||
|
|
||||||
|
[[nodiscard]] const char* getName() const override;
|
||||||
|
[[nodiscard]] uint32_t getIdentifier() const override;
|
||||||
|
[[nodiscard]] MessageQueueId_t getRequestQueue() const override;
|
||||||
|
|
||||||
|
ReturnValue_t initialize() override;
|
||||||
|
ReturnValue_t performOperation(uint8_t operationCode) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
MessageQueueIF& msgQueue;
|
||||||
|
cfdp::DestHandler destHandler;
|
||||||
|
StorageManagerIF* tcStore = nullptr;
|
||||||
|
StorageManagerIF* tmStore = nullptr;
|
||||||
|
|
||||||
|
ReturnValue_t handleCfdpPacket(TmTcMessage& msg);
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // FSFW_EXAMPLE_HOSTED_CFDPHANDLER_H
|
@ -21,7 +21,8 @@
|
|||||||
#define LOWER_EBAND_UPPER_LIMITS 0
|
#define LOWER_EBAND_UPPER_LIMITS 0
|
||||||
#define LOWER_PLOC_UPPER_LIMITS 0
|
#define LOWER_PLOC_UPPER_LIMITS 0
|
||||||
|
|
||||||
ThermalController::ThermalController(object_id_t objectId, HeaterHandler& heater)
|
ThermalController::ThermalController(object_id_t objectId, HeaterHandler& heater,
|
||||||
|
const std::atomic_bool& tcsBoardShortUnavailable)
|
||||||
: ExtendedControllerBase(objectId),
|
: ExtendedControllerBase(objectId),
|
||||||
heaterHandler(heater),
|
heaterHandler(heater),
|
||||||
sensorTemperatures(this),
|
sensorTemperatures(this),
|
||||||
@ -66,7 +67,8 @@ ThermalController::ThermalController(object_id_t objectId, HeaterHandler& heater
|
|||||||
susSet8(objects::SUS_8_R_LOC_XBYBZB_PT_YB),
|
susSet8(objects::SUS_8_R_LOC_XBYBZB_PT_YB),
|
||||||
susSet9(objects::SUS_9_R_LOC_XBYBZB_PT_YF),
|
susSet9(objects::SUS_9_R_LOC_XBYBZB_PT_YF),
|
||||||
susSet10(objects::SUS_10_N_LOC_XMYBZF_PT_ZF),
|
susSet10(objects::SUS_10_N_LOC_XMYBZF_PT_ZF),
|
||||||
susSet11(objects::SUS_11_R_LOC_XBYMZB_PT_ZB) {
|
susSet11(objects::SUS_11_R_LOC_XBYMZB_PT_ZB),
|
||||||
|
tcsBrdShortlyUnavailable(tcsBoardShortUnavailable) {
|
||||||
resetSensorsArray();
|
resetSensorsArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,10 +136,12 @@ void ThermalController::performControlOperation() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
if (not tcsBrdShortlyUnavailable) {
|
||||||
PoolReadGuard pg(&sensorTemperatures);
|
{
|
||||||
if (pg.getReadResult() == returnvalue::OK) {
|
PoolReadGuard pg(&sensorTemperatures);
|
||||||
copySensors();
|
if (pg.getReadResult() == returnvalue::OK) {
|
||||||
|
copySensors();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
@ -188,7 +192,7 @@ void ThermalController::performControlOperation() {
|
|||||||
} else {
|
} else {
|
||||||
transitionWhenHeatersOffCycles++;
|
transitionWhenHeatersOffCycles++;
|
||||||
}
|
}
|
||||||
} else if (mode != MODE_OFF) {
|
} else if (mode != MODE_OFF and not tcsBrdShortlyUnavailable) {
|
||||||
performThermalModuleCtrl(heaterSwitchStateArray);
|
performThermalModuleCtrl(heaterSwitchStateArray);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@
|
|||||||
#include <mission/tcs/Tmp1075Definitions.h>
|
#include <mission/tcs/Tmp1075Definitions.h>
|
||||||
#include <mission/utility/trace.h>
|
#include <mission/utility/trace.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -101,7 +102,8 @@ class ThermalController : public ExtendedControllerBase {
|
|||||||
static constexpr int16_t SANITY_LIMIT_LOWER_TEMP = -80;
|
static constexpr int16_t SANITY_LIMIT_LOWER_TEMP = -80;
|
||||||
static constexpr int16_t SANITY_LIMIT_UPPER_TEMP = 160;
|
static constexpr int16_t SANITY_LIMIT_UPPER_TEMP = 160;
|
||||||
|
|
||||||
ThermalController(object_id_t objectId, HeaterHandler& heater);
|
ThermalController(object_id_t objectId, HeaterHandler& heater,
|
||||||
|
const std::atomic_bool& tcsBoardShortUnavailable);
|
||||||
|
|
||||||
ReturnValue_t initialize() override;
|
ReturnValue_t initialize() override;
|
||||||
|
|
||||||
@ -188,6 +190,10 @@ class ThermalController : public ExtendedControllerBase {
|
|||||||
susMax1227::SusDataset susSet10;
|
susMax1227::SusDataset susSet10;
|
||||||
susMax1227::SusDataset susSet11;
|
susMax1227::SusDataset susSet11;
|
||||||
|
|
||||||
|
// If the TCS board in unavailable, for example due to a recovery, skip
|
||||||
|
// some TCS controller tasks to avoid unnecessary events.
|
||||||
|
const std::atomic_bool& tcsBrdShortlyUnavailable = false;
|
||||||
|
|
||||||
lp_var_t<float> tempQ7s = lp_var_t<float>(objects::CORE_CONTROLLER, core::PoolIds::TEMPERATURE);
|
lp_var_t<float> tempQ7s = lp_var_t<float>(objects::CORE_CONTROLLER, core::PoolIds::TEMPERATURE);
|
||||||
lp_var_t<int16_t> battTemp1 = lp_var_t<int16_t>(objects::BPX_BATT_HANDLER, bpxBat::BATT_TEMP_1);
|
lp_var_t<int16_t> battTemp1 = lp_var_t<int16_t>(objects::BPX_BATT_HANDLER, bpxBat::BATT_TEMP_1);
|
||||||
lp_var_t<int16_t> battTemp2 = lp_var_t<int16_t>(objects::BPX_BATT_HANDLER, bpxBat::BATT_TEMP_2);
|
lp_var_t<int16_t> battTemp2 = lp_var_t<int16_t>(objects::BPX_BATT_HANDLER, bpxBat::BATT_TEMP_2);
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
#include <fsfw/cfdp/CfdpDistributor.h>
|
#include <fsfw/cfdp/CfdpDistributor.h>
|
||||||
#include <fsfw/cfdp/handler/CfdpHandler.h>
|
#include <mission/cfdp/CfdpHandler.h>
|
||||||
#include <fsfw/cfdp/handler/RemoteConfigTableIF.h>
|
#include <fsfw/cfdp/handler/RemoteConfigTableIF.h>
|
||||||
#include <fsfw/controller/ControllerBase.h>
|
#include <fsfw/controller/ControllerBase.h>
|
||||||
#include <fsfw/controller/ExtendedControllerBase.h>
|
#include <fsfw/controller/ExtendedControllerBase.h>
|
||||||
@ -48,6 +48,7 @@
|
|||||||
#include "mission/system/acs/RwAssembly.h"
|
#include "mission/system/acs/RwAssembly.h"
|
||||||
#include "mission/system/acs/acsModeTree.h"
|
#include "mission/system/acs/acsModeTree.h"
|
||||||
#include "mission/system/tree/tcsModeTree.h"
|
#include "mission/system/tree/tcsModeTree.h"
|
||||||
|
#include "mission/tcs/defs.h"
|
||||||
#include "mission/tmtc/tmFilters.h"
|
#include "mission/tmtc/tmFilters.h"
|
||||||
#include "objects/systemObjectList.h"
|
#include "objects/systemObjectList.h"
|
||||||
#include "tmtc/pusIds.h"
|
#include "tmtc/pusIds.h"
|
||||||
@ -90,6 +91,8 @@ EiveFaultHandler EIVE_FAULT_HANDLER;
|
|||||||
|
|
||||||
} // namespace cfdp
|
} // namespace cfdp
|
||||||
|
|
||||||
|
std::atomic_bool tcs::TCS_BOARD_SHORTLY_UNAVAILABLE = false;
|
||||||
|
|
||||||
void ObjectFactory::produceGenericObjects(HealthTableIF** healthTable_, PusTmFunnel** pusFunnel,
|
void ObjectFactory::produceGenericObjects(HealthTableIF** healthTable_, PusTmFunnel** pusFunnel,
|
||||||
CfdpTmFunnel** cfdpFunnel, SdCardMountedIF& sdcMan,
|
CfdpTmFunnel** cfdpFunnel, SdCardMountedIF& sdcMan,
|
||||||
StorageManagerIF** ipcStore, StorageManagerIF** tmStore,
|
StorageManagerIF** ipcStore, StorageManagerIF** tmStore,
|
||||||
@ -300,7 +303,8 @@ void ObjectFactory::createGenericHeaterComponents(GpioIF& gpioIF, PowerSwitchIF&
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ObjectFactory::createThermalController(HeaterHandler& heaterHandler) {
|
void ObjectFactory::createThermalController(HeaterHandler& heaterHandler) {
|
||||||
auto* tcsCtrl = new ThermalController(objects::THERMAL_CONTROLLER, heaterHandler);
|
auto* tcsCtrl = new ThermalController(objects::THERMAL_CONTROLLER, heaterHandler,
|
||||||
|
tcs::TCS_BOARD_SHORTLY_UNAVAILABLE);
|
||||||
tcsCtrl->connectModeTreeParent(satsystem::tcs::SUBSYSTEM);
|
tcsCtrl->connectModeTreeParent(satsystem::tcs::SUBSYSTEM);
|
||||||
}
|
}
|
||||||
void ObjectFactory::createRwAssy(PowerSwitchIF& pwrSwitcher, power::Switch_t theSwitch,
|
void ObjectFactory::createRwAssy(PowerSwitchIF& pwrSwitcher, power::Switch_t theSwitch,
|
||||||
@ -366,10 +370,12 @@ void ObjectFactory::createAcsBoardAssy(PowerSwitchIF& pwrSwitcher,
|
|||||||
acsAss->connectModeTreeParent(satsystem::acs::ACS_SUBSYSTEM);
|
acsAss->connectModeTreeParent(satsystem::acs::ACS_SUBSYSTEM);
|
||||||
}
|
}
|
||||||
|
|
||||||
TcsBoardAssembly* ObjectFactory::createTcsBoardAssy(PowerSwitchIF& pwrSwitcher) {
|
TcsBoardAssembly* ObjectFactory::createTcsBoardAssy(PowerSwitchIF& pwrSwitcher,
|
||||||
|
std::atomic_bool& tcsShortlyUnavailable) {
|
||||||
TcsBoardHelper helper(RTD_INFOS);
|
TcsBoardHelper helper(RTD_INFOS);
|
||||||
auto* tcsBoardAss = new TcsBoardAssembly(objects::TCS_BOARD_ASS, &pwrSwitcher,
|
auto* tcsBoardAss =
|
||||||
power::Switches::PDU1_CH0_TCS_BOARD_3V3, helper);
|
new TcsBoardAssembly(objects::TCS_BOARD_ASS, &pwrSwitcher,
|
||||||
|
power::Switches::PDU1_CH0_TCS_BOARD_3V3, helper, tcsShortlyUnavailable);
|
||||||
tcsBoardAss->connectModeTreeParent(satsystem::tcs::SUBSYSTEM);
|
tcsBoardAss->connectModeTreeParent(satsystem::tcs::SUBSYSTEM);
|
||||||
return tcsBoardAss;
|
return tcsBoardAss;
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,8 @@ void createRwAssy(PowerSwitchIF& pwrSwitcher, power::Switch_t theSwitch,
|
|||||||
void createSusAssy(PowerSwitchIF& pwrSwitcher, std::array<DeviceHandlerBase*, 12> suses);
|
void createSusAssy(PowerSwitchIF& pwrSwitcher, std::array<DeviceHandlerBase*, 12> suses);
|
||||||
void createAcsBoardAssy(PowerSwitchIF& pwrSwitcher, std::array<DeviceHandlerBase*, 8> assemblyDhbs,
|
void createAcsBoardAssy(PowerSwitchIF& pwrSwitcher, std::array<DeviceHandlerBase*, 8> assemblyDhbs,
|
||||||
ExtendedControllerBase* gpsCtrl, GpioIF* gpioComIF);
|
ExtendedControllerBase* gpsCtrl, GpioIF* gpioComIF);
|
||||||
TcsBoardAssembly* createTcsBoardAssy(PowerSwitchIF& pwrSwitcher);
|
TcsBoardAssembly* createTcsBoardAssy(PowerSwitchIF& pwrSwitcher,
|
||||||
|
std::atomic_bool& tcsShortlyUnavailable);
|
||||||
|
|
||||||
} // namespace ObjectFactory
|
} // namespace ObjectFactory
|
||||||
|
|
||||||
|
@ -50,6 +50,7 @@ static constexpr Event FDIR_REACTION_IGNORED = event::makeEvent(SUBSYSTEM_ID, 3,
|
|||||||
enum class States { IDLE, SWITCHING_POWER, CHECKING_POWER, MODE_COMMANDING };
|
enum class States { IDLE, SWITCHING_POWER, CHECKING_POWER, MODE_COMMANDING };
|
||||||
enum class OpCodes { NONE, TO_OFF_DONE, TO_NOT_OFF_DONE, TIMEOUT_OCCURED };
|
enum class OpCodes { NONE, TO_OFF_DONE, TO_NOT_OFF_DONE, TIMEOUT_OCCURED };
|
||||||
|
|
||||||
|
enum RecoveryCustomStates { IDLE, POWER_SWITCHING_OFF, POWER_SWITCHING_ON, DONE };
|
||||||
} // namespace power
|
} // namespace power
|
||||||
|
|
||||||
namespace duallane {
|
namespace duallane {
|
||||||
|
@ -6,5 +6,6 @@ add_subdirectory(fdir)
|
|||||||
add_subdirectory(power)
|
add_subdirectory(power)
|
||||||
|
|
||||||
target_sources(
|
target_sources(
|
||||||
${LIB_EIVE_MISSION} PRIVATE systemTree.cpp DualLanePowerStateMachine.cpp
|
${LIB_EIVE_MISSION}
|
||||||
EiveSystem.cpp treeUtil.cpp)
|
PRIVATE systemTree.cpp DualLanePowerStateMachine.cpp EiveSystem.cpp
|
||||||
|
treeUtil.cpp SharedPowerAssemblyBase.cpp)
|
||||||
|
91
mission/system/SharedPowerAssemblyBase.cpp
Normal file
91
mission/system/SharedPowerAssemblyBase.cpp
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
#include "SharedPowerAssemblyBase.h"
|
||||||
|
|
||||||
|
SharedPowerAssemblyBase::SharedPowerAssemblyBase(object_id_t objectId, PowerSwitchIF* pwrSwitcher,
|
||||||
|
power::Switch_t switchId, uint16_t cmdQueueDepth)
|
||||||
|
: AssemblyBase(objectId, cmdQueueDepth), switcher(pwrSwitcher, switchId) {}
|
||||||
|
|
||||||
|
void SharedPowerAssemblyBase::performChildOperation() {
|
||||||
|
auto state = switcher.getState();
|
||||||
|
if (state != PowerSwitcher::WAIT_OFF and state != PowerSwitcher::WAIT_ON) {
|
||||||
|
AssemblyBase::performChildOperation();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
switcher.doStateMachine();
|
||||||
|
if (state == PowerSwitcher::WAIT_OFF and switcher.getState() == PowerSwitcher::SWITCH_IS_OFF) {
|
||||||
|
// Indicator that a transition to off is finished
|
||||||
|
AssemblyBase::handleModeReached();
|
||||||
|
} else if (state == PowerSwitcher::WAIT_ON and
|
||||||
|
switcher.getState() == PowerSwitcher::SWITCH_IS_ON) {
|
||||||
|
// Indicator that mode commanding can be performed now
|
||||||
|
AssemblyBase::startTransition(targetMode, targetSubmode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedPowerAssemblyBase::startTransition(Mode_t mode, Submode_t submode) {
|
||||||
|
if (mode != MODE_OFF) {
|
||||||
|
switcher.turnOn(true);
|
||||||
|
switcher.doStateMachine();
|
||||||
|
if (switcher.getState() == PowerSwitcher::SWITCH_IS_ON) {
|
||||||
|
AssemblyBase::startTransition(mode, submode);
|
||||||
|
} else {
|
||||||
|
// Need to wait with mode commanding until power switcher is done
|
||||||
|
targetMode = mode;
|
||||||
|
targetSubmode = submode;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Perform regular mode commanding first
|
||||||
|
AssemblyBase::startTransition(mode, submode);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SharedPowerAssemblyBase::handleModeReached() {
|
||||||
|
if (targetMode == MODE_OFF) {
|
||||||
|
switcher.turnOff(true);
|
||||||
|
switcher.doStateMachine();
|
||||||
|
// Need to wait with call to AssemblyBase::handleModeReached until power switcher is done
|
||||||
|
if (switcher.getState() == PowerSwitcher::SWITCH_IS_OFF) {
|
||||||
|
AssemblyBase::handleModeReached();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
AssemblyBase::handleModeReached();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SharedPowerAssemblyBase::checkAndHandleRecovery() {
|
||||||
|
using namespace power;
|
||||||
|
if (recoveryState == RECOVERY_IDLE) {
|
||||||
|
return AssemblyBase::checkAndHandleRecovery();
|
||||||
|
}
|
||||||
|
if (customRecoveryStates == IDLE) {
|
||||||
|
switcher.turnOff();
|
||||||
|
customRecoveryStates = RecoveryCustomStates::POWER_SWITCHING_OFF;
|
||||||
|
}
|
||||||
|
if (customRecoveryStates == POWER_SWITCHING_OFF) {
|
||||||
|
switcher.doStateMachine();
|
||||||
|
if (switcher.getState() == PowerSwitcher::SWITCH_IS_OFF) {
|
||||||
|
customRecoveryStates = RecoveryCustomStates::POWER_SWITCHING_ON;
|
||||||
|
switcher.turnOn();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (customRecoveryStates == POWER_SWITCHING_ON) {
|
||||||
|
switcher.doStateMachine();
|
||||||
|
if (switcher.getState() == PowerSwitcher::SWITCH_IS_ON) {
|
||||||
|
customRecoveryStates = RecoveryCustomStates::DONE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (customRecoveryStates == DONE) {
|
||||||
|
bool pendingRecovery = AssemblyBase::checkAndHandleRecovery();
|
||||||
|
if (not pendingRecovery) {
|
||||||
|
customRecoveryStates = RecoveryCustomStates::IDLE;
|
||||||
|
}
|
||||||
|
// For a recovery on one side, only do the recovery once
|
||||||
|
for (auto& child : childrenMap) {
|
||||||
|
if (healthHelper.healthTable->getHealth(child.first) == HasHealthIF::NEEDS_RECOVERY) {
|
||||||
|
sendHealthCommand(child.second.commandQueue, HEALTHY);
|
||||||
|
child.second.healthChanged = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return pendingRecovery;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
27
mission/system/SharedPowerAssemblyBase.h
Normal file
27
mission/system/SharedPowerAssemblyBase.h
Normal file
@ -0,0 +1,27 @@
|
|||||||
|
#ifndef MISSION_SYSTEM_SHAREDPOWERASSEMBLYBASE_H_
|
||||||
|
#define MISSION_SYSTEM_SHAREDPOWERASSEMBLYBASE_H_
|
||||||
|
|
||||||
|
#include <fsfw/devicehandlers/AssemblyBase.h>
|
||||||
|
#include <fsfw/power/PowerSwitcher.h>
|
||||||
|
#include <mission/power/defs.h>
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class which contains common functions for assemblies where the power line is shared
|
||||||
|
* among the devices in the assembly.
|
||||||
|
*/
|
||||||
|
class SharedPowerAssemblyBase : public AssemblyBase {
|
||||||
|
public:
|
||||||
|
SharedPowerAssemblyBase(object_id_t objectId, PowerSwitchIF* pwrSwitcher,
|
||||||
|
power::Switch_t switchId, uint16_t cmdQueueDepth = 8);
|
||||||
|
|
||||||
|
protected:
|
||||||
|
PowerSwitcher switcher;
|
||||||
|
power::RecoveryCustomStates customRecoveryStates = power::RecoveryCustomStates::IDLE;
|
||||||
|
|
||||||
|
void performChildOperation() override;
|
||||||
|
void startTransition(Mode_t mode, Submode_t submode) override;
|
||||||
|
void handleModeReached() override;
|
||||||
|
virtual bool checkAndHandleRecovery() override;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif /* MISSION_SYSTEM_SHAREDPOWERASSEMBLYBASE_H_ */
|
@ -39,12 +39,7 @@ class DualLaneAssemblyBase : public AssemblyBase, public ConfirmsFailuresIF {
|
|||||||
SideSwitchState sideSwitchState = SideSwitchState::NONE;
|
SideSwitchState sideSwitchState = SideSwitchState::NONE;
|
||||||
duallane::Submodes targetSubmodeForSideSwitch = duallane::Submodes::B_SIDE;
|
duallane::Submodes targetSubmodeForSideSwitch = duallane::Submodes::B_SIDE;
|
||||||
|
|
||||||
enum RecoveryCustomStates {
|
power::RecoveryCustomStates customRecoveryStates = power::RecoveryCustomStates::IDLE;
|
||||||
IDLE,
|
|
||||||
POWER_SWITCHING_OFF,
|
|
||||||
POWER_SWITCHING_ON,
|
|
||||||
DONE
|
|
||||||
} customRecoveryStates = RecoveryCustomStates::IDLE;
|
|
||||||
|
|
||||||
MessageQueueIF* eventQueue = nullptr;
|
MessageQueueIF* eventQueue = nullptr;
|
||||||
|
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#include "RwAssembly.h"
|
#include "RwAssembly.h"
|
||||||
|
|
||||||
RwAssembly::RwAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitcher, power::Switch_t switcher,
|
RwAssembly::RwAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitcher, power::Switch_t switchId,
|
||||||
RwHelper helper)
|
RwHelper helper)
|
||||||
: AssemblyBase(objectId), helper(helper), switcher(pwrSwitcher, switcher) {
|
: SharedPowerAssemblyBase(objectId, pwrSwitcher, switchId), helper(helper) {
|
||||||
ModeListEntry entry;
|
ModeListEntry entry;
|
||||||
for (uint8_t idx = 0; idx < NUMBER_RWS; idx++) {
|
for (uint8_t idx = 0; idx < NUMBER_RWS; idx++) {
|
||||||
entry.setObject(helper.rwIds[idx]);
|
entry.setObject(helper.rwIds[idx]);
|
||||||
@ -12,26 +12,8 @@ RwAssembly::RwAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitcher, power::
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void RwAssembly::performChildOperation() {
|
|
||||||
auto state = switcher.getState();
|
|
||||||
if (state != PowerSwitcher::WAIT_OFF and state != PowerSwitcher::WAIT_ON) {
|
|
||||||
AssemblyBase::performChildOperation();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switcher.doStateMachine();
|
|
||||||
if (state == PowerSwitcher::WAIT_OFF and switcher.getState() == PowerSwitcher::SWITCH_IS_OFF) {
|
|
||||||
// Indicator that a transition to off is finished
|
|
||||||
AssemblyBase::handleModeReached();
|
|
||||||
} else if (state == PowerSwitcher::WAIT_ON and
|
|
||||||
switcher.getState() == PowerSwitcher::SWITCH_IS_ON) {
|
|
||||||
// Indicator that mode commanding can be performed now
|
|
||||||
AssemblyBase::startTransition(targetMode, targetSubmode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t RwAssembly::commandChildren(Mode_t mode, Submode_t submode) {
|
ReturnValue_t RwAssembly::commandChildren(Mode_t mode, Submode_t submode) {
|
||||||
ReturnValue_t result = returnvalue::OK;
|
ReturnValue_t result = returnvalue::OK;
|
||||||
modeTransitionFailedSwitch = true;
|
|
||||||
// Initialize the mode table to ensure all devices are in a defined state
|
// Initialize the mode table to ensure all devices are in a defined state
|
||||||
for (uint8_t idx = 0; idx < NUMBER_RWS; idx++) {
|
for (uint8_t idx = 0; idx < NUMBER_RWS; idx++) {
|
||||||
modeTable[idx].setMode(MODE_OFF);
|
modeTable[idx].setMode(MODE_OFF);
|
||||||
@ -76,36 +58,6 @@ ReturnValue_t RwAssembly::isModeCombinationValid(Mode_t mode, Submode_t submode)
|
|||||||
return HasModesIF::INVALID_MODE;
|
return HasModesIF::INVALID_MODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RwAssembly::startTransition(Mode_t mode, Submode_t submode) {
|
|
||||||
if (mode != MODE_OFF) {
|
|
||||||
switcher.turnOn(true);
|
|
||||||
switcher.doStateMachine();
|
|
||||||
if (switcher.getState() == PowerSwitcher::SWITCH_IS_ON) {
|
|
||||||
AssemblyBase::startTransition(mode, submode);
|
|
||||||
} else {
|
|
||||||
// Need to wait with mode commanding until power switcher is done
|
|
||||||
targetMode = mode;
|
|
||||||
targetSubmode = submode;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Perform regular mode commanding first
|
|
||||||
AssemblyBase::startTransition(mode, submode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RwAssembly::handleModeReached() {
|
|
||||||
if (targetMode == MODE_OFF) {
|
|
||||||
switcher.turnOff(true);
|
|
||||||
switcher.doStateMachine();
|
|
||||||
// Need to wait with call to AssemblyBase::handleModeReached until power switcher is done
|
|
||||||
if (switcher.getState() == PowerSwitcher::SWITCH_IS_OFF) {
|
|
||||||
AssemblyBase::handleModeReached();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
AssemblyBase::handleModeReached();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t RwAssembly::handleNormalOrOnModeCmd(Mode_t mode, Submode_t submode) {
|
ReturnValue_t RwAssembly::handleNormalOrOnModeCmd(Mode_t mode, Submode_t submode) {
|
||||||
ReturnValue_t result = returnvalue::OK;
|
ReturnValue_t result = returnvalue::OK;
|
||||||
object_id_t objId = 0;
|
object_id_t objId = 0;
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
#ifndef MISSION_SYSTEM_RWASS_H_
|
#ifndef MISSION_SYSTEM_RWASS_H_
|
||||||
#define MISSION_SYSTEM_RWASS_H_
|
#define MISSION_SYSTEM_RWASS_H_
|
||||||
|
|
||||||
#include <fsfw/devicehandlers/AssemblyBase.h>
|
|
||||||
#include <fsfw/power/PowerSwitcher.h>
|
#include <fsfw/power/PowerSwitcher.h>
|
||||||
|
#include <mission/system/SharedPowerAssemblyBase.h>
|
||||||
|
|
||||||
struct RwHelper {
|
struct RwHelper {
|
||||||
RwHelper(std::array<object_id_t, 4> rwIds) : rwIds(rwIds) {}
|
RwHelper(std::array<object_id_t, 4> rwIds) : rwIds(rwIds) {}
|
||||||
@ -10,17 +10,15 @@ struct RwHelper {
|
|||||||
std::array<object_id_t, 4> rwIds = {};
|
std::array<object_id_t, 4> rwIds = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
class RwAssembly : public AssemblyBase {
|
class RwAssembly : public SharedPowerAssemblyBase {
|
||||||
public:
|
public:
|
||||||
RwAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitcher, power::Switch_t switcher,
|
RwAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitcher, power::Switch_t switchId,
|
||||||
RwHelper helper);
|
RwHelper helper);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr uint8_t NUMBER_RWS = 4;
|
static constexpr uint8_t NUMBER_RWS = 4;
|
||||||
RwHelper helper;
|
RwHelper helper;
|
||||||
PowerSwitcher switcher;
|
|
||||||
bool warningSwitch = true;
|
bool warningSwitch = true;
|
||||||
bool modeTransitionFailedSwitch = true;
|
|
||||||
FixedArrayList<ModeListEntry, NUMBER_RWS> modeTable;
|
FixedArrayList<ModeListEntry, NUMBER_RWS> modeTable;
|
||||||
|
|
||||||
ReturnValue_t initialize() override;
|
ReturnValue_t initialize() override;
|
||||||
@ -35,12 +33,9 @@ class RwAssembly : public AssemblyBase {
|
|||||||
bool isUseable(object_id_t object, Mode_t mode);
|
bool isUseable(object_id_t object, Mode_t mode);
|
||||||
|
|
||||||
// AssemblyBase implementation
|
// AssemblyBase implementation
|
||||||
void performChildOperation() override;
|
|
||||||
ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) override;
|
ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) override;
|
||||||
ReturnValue_t checkChildrenStateOn(Mode_t wantedMode, Submode_t wantedSubmode) override;
|
ReturnValue_t checkChildrenStateOn(Mode_t wantedMode, Submode_t wantedSubmode) override;
|
||||||
ReturnValue_t isModeCombinationValid(Mode_t mode, Submode_t submode) override;
|
ReturnValue_t isModeCombinationValid(Mode_t mode, Submode_t submode) override;
|
||||||
void startTransition(Mode_t mode, Submode_t submode) override;
|
|
||||||
void handleModeReached() override;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif /* MISSION_SYSTEM_RWASS_H_ */
|
#endif /* MISSION_SYSTEM_RWASS_H_ */
|
||||||
|
@ -3,4 +3,4 @@
|
|||||||
#include "eive/objects.h"
|
#include "eive/objects.h"
|
||||||
|
|
||||||
RtdFdir::RtdFdir(object_id_t sensorId)
|
RtdFdir::RtdFdir(object_id_t sensorId)
|
||||||
: DeviceHandlerFailureIsolation(sensorId, objects::TCS_BOARD_ASS) {}
|
: DeviceHandlerFailureIsolation(sensorId, objects::NO_OBJECT) {}
|
||||||
|
@ -4,9 +4,11 @@
|
|||||||
#include <fsfw/ipc/QueueFactory.h>
|
#include <fsfw/ipc/QueueFactory.h>
|
||||||
|
|
||||||
TcsBoardAssembly::TcsBoardAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitcher,
|
TcsBoardAssembly::TcsBoardAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitcher,
|
||||||
power::Switch_t theSwitch, TcsBoardHelper helper)
|
power::Switch_t theSwitch, TcsBoardHelper helper,
|
||||||
: AssemblyBase(objectId, 24), switcher(pwrSwitcher, theSwitch), helper(helper) {
|
std::atomic_bool& tcsShortlyUnavailable)
|
||||||
eventQueue = QueueFactory::instance()->createMessageQueue(24);
|
: SharedPowerAssemblyBase(objectId, pwrSwitcher, theSwitch, 16),
|
||||||
|
helper(helper),
|
||||||
|
tcsShortlyUnavailable(tcsShortlyUnavailable) {
|
||||||
ModeListEntry entry;
|
ModeListEntry entry;
|
||||||
for (uint8_t idx = 0; idx < NUMBER_RTDS; idx++) {
|
for (uint8_t idx = 0; idx < NUMBER_RTDS; idx++) {
|
||||||
entry.setObject(helper.rtdInfos[idx].first);
|
entry.setObject(helper.rtdInfos[idx].first);
|
||||||
@ -16,23 +18,6 @@ TcsBoardAssembly::TcsBoardAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitc
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TcsBoardAssembly::performChildOperation() {
|
|
||||||
auto state = switcher.getState();
|
|
||||||
if (state != PowerSwitcher::WAIT_OFF and state != PowerSwitcher::WAIT_ON) {
|
|
||||||
AssemblyBase::performChildOperation();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
switcher.doStateMachine();
|
|
||||||
if (state == PowerSwitcher::WAIT_OFF and switcher.getState() == PowerSwitcher::SWITCH_IS_OFF) {
|
|
||||||
// Indicator that a transition to off is finished
|
|
||||||
AssemblyBase::handleModeReached();
|
|
||||||
} else if (state == PowerSwitcher::WAIT_ON and
|
|
||||||
switcher.getState() == PowerSwitcher::SWITCH_IS_ON) {
|
|
||||||
// Indicator that mode commanding can be performed now
|
|
||||||
AssemblyBase::startTransition(targetMode, targetSubmode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t TcsBoardAssembly::commandChildren(Mode_t mode, Submode_t submode) {
|
ReturnValue_t TcsBoardAssembly::commandChildren(Mode_t mode, Submode_t submode) {
|
||||||
ReturnValue_t result = returnvalue::OK;
|
ReturnValue_t result = returnvalue::OK;
|
||||||
// Initialize the mode table to ensure all devices are in a defined state
|
// Initialize the mode table to ensure all devices are in a defined state
|
||||||
@ -50,6 +35,8 @@ ReturnValue_t TcsBoardAssembly::commandChildren(Mode_t mode, Submode_t submode)
|
|||||||
if (mode == DeviceHandlerIF::MODE_NORMAL or mode == MODE_ON) {
|
if (mode == DeviceHandlerIF::MODE_NORMAL or mode == MODE_ON) {
|
||||||
result = handleNormalOrOnModeCmd(mode, submode);
|
result = handleNormalOrOnModeCmd(mode, submode);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
tcsShortlyUnavailable = true;
|
||||||
}
|
}
|
||||||
HybridIterator<ModeListEntry> tableIter(modeTable.begin(), modeTable.end());
|
HybridIterator<ModeListEntry> tableIter(modeTable.begin(), modeTable.end());
|
||||||
executeTable(tableIter);
|
executeTable(tableIter);
|
||||||
@ -94,25 +81,6 @@ ReturnValue_t TcsBoardAssembly::isModeCombinationValid(Mode_t mode, Submode_t su
|
|||||||
return HasModesIF::INVALID_MODE;
|
return HasModesIF::INVALID_MODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReturnValue_t TcsBoardAssembly::initialize() { return AssemblyBase::initialize(); }
|
|
||||||
|
|
||||||
void TcsBoardAssembly::startTransition(Mode_t mode, Submode_t submode) {
|
|
||||||
if (mode != MODE_OFF) {
|
|
||||||
switcher.turnOn(true);
|
|
||||||
switcher.doStateMachine();
|
|
||||||
if (switcher.getState() == PowerSwitcher::SWITCH_IS_ON) {
|
|
||||||
AssemblyBase::startTransition(mode, submode);
|
|
||||||
} else {
|
|
||||||
// Need to wait with mode commanding until power switcher is done
|
|
||||||
targetMode = mode;
|
|
||||||
targetSubmode = submode;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
// Perform regular mode commanding first
|
|
||||||
AssemblyBase::startTransition(mode, submode);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
ReturnValue_t TcsBoardAssembly::handleNormalOrOnModeCmd(Mode_t mode, Submode_t submode) {
|
ReturnValue_t TcsBoardAssembly::handleNormalOrOnModeCmd(Mode_t mode, Submode_t submode) {
|
||||||
ReturnValue_t result = returnvalue::OK;
|
ReturnValue_t result = returnvalue::OK;
|
||||||
bool needsSecondStep = false;
|
bool needsSecondStep = false;
|
||||||
@ -169,21 +137,6 @@ bool TcsBoardAssembly::isUseable(object_id_t object, Mode_t mode) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageQueueId_t TcsBoardAssembly::getEventReceptionQueue() { return eventQueue->getId(); }
|
|
||||||
|
|
||||||
void TcsBoardAssembly::handleModeReached() {
|
|
||||||
if (targetMode == MODE_OFF) {
|
|
||||||
switcher.turnOff(true);
|
|
||||||
switcher.doStateMachine();
|
|
||||||
// Need to wait with call to AssemblyBase::handleModeReached until power switcher is done
|
|
||||||
if (switcher.getState() == PowerSwitcher::SWITCH_IS_OFF) {
|
|
||||||
AssemblyBase::handleModeReached();
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
AssemblyBase::handleModeReached();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void TcsBoardAssembly::handleChildrenLostMode(ReturnValue_t result) {
|
void TcsBoardAssembly::handleChildrenLostMode(ReturnValue_t result) {
|
||||||
triggerEvent(CHILDREN_LOST_MODE, result);
|
triggerEvent(CHILDREN_LOST_MODE, result);
|
||||||
startTransition(mode, submode);
|
startTransition(mode, submode);
|
||||||
@ -210,6 +163,12 @@ ReturnValue_t TcsBoardAssembly::checkAndHandleHealthStates(Mode_t deviceMode,
|
|||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TcsBoardAssembly::checkAndHandleRecovery() {
|
||||||
|
bool recoveryPending = SharedPowerAssemblyBase::checkAndHandleRecovery();
|
||||||
|
tcsShortlyUnavailable = recoveryPending;
|
||||||
|
return recoveryPending;
|
||||||
|
}
|
||||||
|
|
||||||
void TcsBoardAssembly::handleModeTransitionFailed(ReturnValue_t result) {
|
void TcsBoardAssembly::handleModeTransitionFailed(ReturnValue_t result) {
|
||||||
if (targetMode == MODE_OFF) {
|
if (targetMode == MODE_OFF) {
|
||||||
AssemblyBase::handleModeTransitionFailed(result);
|
AssemblyBase::handleModeTransitionFailed(result);
|
||||||
|
@ -4,6 +4,10 @@
|
|||||||
#include <fsfw/container/FixedArrayList.h>
|
#include <fsfw/container/FixedArrayList.h>
|
||||||
#include <fsfw/devicehandlers/AssemblyBase.h>
|
#include <fsfw/devicehandlers/AssemblyBase.h>
|
||||||
#include <fsfw/power/PowerSwitcher.h>
|
#include <fsfw/power/PowerSwitcher.h>
|
||||||
|
#include <mission/power/defs.h>
|
||||||
|
#include <mission/system/SharedPowerAssemblyBase.h>
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
|
||||||
#include "events/subsystemIdRanges.h"
|
#include "events/subsystemIdRanges.h"
|
||||||
#include "returnvalues/classIds.h"
|
#include "returnvalues/classIds.h"
|
||||||
@ -15,23 +19,20 @@ struct TcsBoardHelper {
|
|||||||
std::array<std::pair<object_id_t, std::string>, 16> rtdInfos = {};
|
std::array<std::pair<object_id_t, std::string>, 16> rtdInfos = {};
|
||||||
};
|
};
|
||||||
|
|
||||||
class TcsBoardAssembly : public AssemblyBase, public ConfirmsFailuresIF {
|
class TcsBoardAssembly : public SharedPowerAssemblyBase {
|
||||||
public:
|
public:
|
||||||
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::TCS_BOARD_ASS;
|
static constexpr uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::TCS_BOARD_ASS;
|
||||||
static constexpr Event CHILDREN_LOST_MODE = event::makeEvent(SUBSYSTEM_ID, 0, severity::MEDIUM);
|
static constexpr Event CHILDREN_LOST_MODE = event::makeEvent(SUBSYSTEM_ID, 0, severity::MEDIUM);
|
||||||
|
|
||||||
TcsBoardAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitcher, power::Switch_t switcher,
|
TcsBoardAssembly(object_id_t objectId, PowerSwitchIF* pwrSwitcher, power::Switch_t switcher,
|
||||||
TcsBoardHelper helper);
|
TcsBoardHelper helper, std::atomic_bool& tcsShortlyUnavailable);
|
||||||
|
|
||||||
ReturnValue_t initialize() override;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static constexpr uint8_t NUMBER_RTDS = 16;
|
static constexpr uint8_t NUMBER_RTDS = 16;
|
||||||
PowerSwitcher switcher;
|
|
||||||
bool warningSwitch = true;
|
bool warningSwitch = true;
|
||||||
TcsBoardHelper helper;
|
TcsBoardHelper helper;
|
||||||
FixedArrayList<ModeListEntry, NUMBER_RTDS> modeTable;
|
FixedArrayList<ModeListEntry, NUMBER_RTDS> modeTable;
|
||||||
MessageQueueIF* eventQueue = nullptr;
|
std::atomic_bool& tcsShortlyUnavailable;
|
||||||
|
|
||||||
ReturnValue_t handleNormalOrOnModeCmd(Mode_t mode, Submode_t submode);
|
ReturnValue_t handleNormalOrOnModeCmd(Mode_t mode, Submode_t submode);
|
||||||
/**
|
/**
|
||||||
@ -42,17 +43,12 @@ class TcsBoardAssembly : public AssemblyBase, public ConfirmsFailuresIF {
|
|||||||
*/
|
*/
|
||||||
bool isUseable(object_id_t object, Mode_t mode);
|
bool isUseable(object_id_t object, Mode_t mode);
|
||||||
|
|
||||||
// ConfirmFailureIF implementation
|
|
||||||
MessageQueueId_t getEventReceptionQueue() override;
|
|
||||||
|
|
||||||
// AssemblyBase implementation
|
// AssemblyBase implementation
|
||||||
void performChildOperation() override;
|
|
||||||
ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) override;
|
ReturnValue_t commandChildren(Mode_t mode, Submode_t submode) override;
|
||||||
ReturnValue_t checkChildrenStateOn(Mode_t wantedMode, Submode_t wantedSubmode) override;
|
ReturnValue_t checkChildrenStateOn(Mode_t wantedMode, Submode_t wantedSubmode) override;
|
||||||
ReturnValue_t isModeCombinationValid(Mode_t mode, Submode_t submode) override;
|
ReturnValue_t isModeCombinationValid(Mode_t mode, Submode_t submode) override;
|
||||||
void startTransition(Mode_t mode, Submode_t submode) override;
|
|
||||||
void handleModeReached() override;
|
|
||||||
ReturnValue_t checkAndHandleHealthStates(Mode_t deviceMode, Submode_t deviceSubmode);
|
ReturnValue_t checkAndHandleHealthStates(Mode_t deviceMode, Submode_t deviceSubmode);
|
||||||
|
bool checkAndHandleRecovery() override;
|
||||||
|
|
||||||
// These two overrides prevent a transition of the whole assembly back to off just because
|
// These two overrides prevent a transition of the whole assembly back to off just because
|
||||||
// some devices are not working
|
// some devices are not working
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#ifndef MISSION_TCS_DEFS_H_
|
#pragma once
|
||||||
#define MISSION_TCS_DEFS_H_
|
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
|
|
||||||
namespace heater {
|
namespace heater {
|
||||||
@ -17,4 +17,8 @@ enum Switch : uint8_t {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif /* MISSION_TCS_DEFS_H_ */
|
namespace tcs {
|
||||||
|
|
||||||
|
extern std::atomic_bool TCS_BOARD_SHORTLY_UNAVAILABLE;
|
||||||
|
|
||||||
|
}
|
||||||
|
@ -15,6 +15,7 @@
|
|||||||
|
|
||||||
TEST_CASE("Thermal Controller", "[ThermalController]") {
|
TEST_CASE("Thermal Controller", "[ThermalController]") {
|
||||||
const object_id_t THERMAL_CONTROLLER_ID = 0x123;
|
const object_id_t THERMAL_CONTROLLER_ID = 0x123;
|
||||||
|
std::atomic_bool tcsBrdShortlyUnavailable = false;
|
||||||
|
|
||||||
TemperatureSensorInserter::Max31865DummyMap map0;
|
TemperatureSensorInserter::Max31865DummyMap map0;
|
||||||
TemperatureSensorInserter::Tmp1075DummyMap map1;
|
TemperatureSensorInserter::Tmp1075DummyMap map1;
|
||||||
@ -29,7 +30,7 @@ TEST_CASE("Thermal Controller", "[ThermalController]") {
|
|||||||
|
|
||||||
// testEnvironment::initialize();
|
// testEnvironment::initialize();
|
||||||
|
|
||||||
ThermalController controller(THERMAL_CONTROLLER_ID, *heaterHandler);
|
ThermalController controller(THERMAL_CONTROLLER_ID, *heaterHandler, tcsBrdShortlyUnavailable);
|
||||||
ReturnValue_t result = controller.initialize();
|
ReturnValue_t result = controller.initialize();
|
||||||
REQUIRE(result == returnvalue::OK);
|
REQUIRE(result == returnvalue::OK);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user