Merge branch 'v3.0.0-dev' into acs-ptg-ctrl-fixes-2
EIVE/eive-obsw/pipeline/pr-v3.0.0-dev There was a failure building this commit Details

This commit is contained in:
Marius Eggert 2023-06-01 09:11:30 +02:00
commit ffe419e1ab
19 changed files with 206 additions and 58 deletions

View File

@ -18,7 +18,7 @@ will consitute of a breaking change warranting a new major release:
# [v2.2.0] to be released
# [v2.1.0] to be released
# [v3.0.0] to be released
## Changed
@ -43,12 +43,23 @@ will consitute of a breaking change warranting a new major release:
- Disable missed deadlines per default. Not useful in orbit, and triggers all the time on the EM
build after a number of subsequent runs, without any apparent reason (deadlines are not actually
missed, thread usage displayed is nominal)
- TM store dumpes will not be cancelled anymore if the transmitter is off. The dump can be cancelled
with an OFF command, and the PTME is perfectly capable of dumping without the transmitter being
on.
- Transmitter state is not taken into account anymore for writing into the PTME. The PTME should
be perfectly capable of generating a valid CADU, even when the transmitter is not ON for any
reason.
- OFF mode is ignores in TM store for determining whether a store will be written. The modes will
only be used to cancel a transfer.
## Added
- Add the remaining system modes.
- PLOC MPSoC flash read command working.
- BPX battery handler is added for EM by default.
- ACU dummy HK sets
- IMTQ HK sets
- IMTQ dummy now handles power switch
## Fixed
@ -68,6 +79,18 @@ will consitute of a breaking change warranting a new major release:
- PLOC MPSoC special communication is now scheduled, which allows flash read and flash write
commands to work.
- Fixed the MPSoC flash write command.
- Added missing ACS parameter.
- HK TM store: The HK store dump success event was triggered for cancelled HK dumps.
- When a PUS parsing error occured while parsing a TM store file, the dump completion procedure
was always executed.
- Some smaller logic fixes in the TM store base class
- Fixed usage of C `abs` instead of C++ `std::abs`, which results in MTQ commands not being
scaled correctly between 1Am² and 0.2Am².
- TCS Heater Handler: Always trigger mode event if a heater goes `OFF` or `ON`. This event might
soon replace the `HEATER_WENT_ON` and `HEATER_WENT_OFF` events.
- Prevent spam of TCS controller heater unavailability event if all heaters are in external control.
- TCS heater switch info set contained invalid values because of a faulty `memcpy` in the TCS
controller. There is not crash risk but the heater states were invalid.
# [v2.0.5] 2023-05-11

View File

@ -9,9 +9,9 @@
# ##############################################################################
cmake_minimum_required(VERSION 3.13)
set(OBSW_VERSION_MAJOR 2)
set(OBSW_VERSION_MAJOR 3)
set(OBSW_VERSION_MINOR 0)
set(OBSW_VERSION_REVISION 5)
set(OBSW_VERSION_REVISION 0)
# set(CMAKE_VERBOSE TRUE)
@ -98,7 +98,7 @@ set(OBSW_ADD_THERMAL_TEMP_INSERTER
${OBSW_Q7S_EM}
CACHE STRING "Add thermal sensor temperature inserter")
set(OBSW_ADD_ACS_BOARD
1
${INIT_VAL}
CACHE STRING "Add ACS board module")
set(OBSW_ADD_GPS_CTRL
${INIT_VAL}

View File

@ -62,6 +62,10 @@ void ObjectFactory::produce(void* args) {
StorageManagerIF* tmStore;
StorageManagerIF* ipcStore;
PersistentTmStores persistentStores;
bool enableHkSets = false;
#if OBSW_ENABLE_PERIODIC_HK == 1
enableHkSets = true;
#endif
auto sdcMan = new DummySdCardManager("/tmp");
ObjectFactory::produceGenericObjects(nullptr, &pusFunnel, &cfdpFunnel, *sdcMan, &ipcStore,
&tmStore, persistentStores, 120);
@ -101,7 +105,7 @@ void ObjectFactory::produce(void* args) {
#endif
dummy::DummyCfg cfg;
dummy::createDummies(cfg, *dummySwitcher, dummyGpioIF);
dummy::createDummies(cfg, *dummySwitcher, dummyGpioIF, enableHkSets);
HeaterHandler* heaterHandler = nullptr;
// new ThermalController(objects::THERMAL_CONTROLLER);

View File

@ -805,7 +805,7 @@ ReturnValue_t ObjectFactory::createCcsdsComponents(CcsdsComponentArgs& args) {
// Core task which handles the HK store and takes care of dumping it as TM using a VC directly
auto* hkStore = new PersistentSingleTmStoreTask(
objects::HK_STORE_AND_TM_TASK, args.ipcStore, *args.stores.hkStore, *vc,
persTmStore::DUMP_HK_STORE_DONE, persTmStore::DUMP_HK_STORE_DONE, *SdCardManager::instance(),
persTmStore::DUMP_HK_STORE_DONE, persTmStore::DUMP_HK_CANCELLED, *SdCardManager::instance(),
PTME_LOCKED);
hkStore->connectModeTreeParent(satsystem::com::SUBSYSTEM);

View File

@ -79,7 +79,7 @@ void ObjectFactory::produce(void* args) {
#endif
satsystem::EIVE_SYSTEM.setI2cRecoveryParams(pwrSwitcher);
dummy::createDummies(dummyCfg, *pwrSwitcher, gpioComIF);
dummy::createDummies(dummyCfg, *pwrSwitcher, gpioComIF, enableHkSets);
new CoreController(objects::CORE_CONTROLLER, enableHkSets);
@ -97,10 +97,10 @@ void ObjectFactory::produce(void* args) {
// TODO: Careful! Switching this on somehow messes with the communication with the ProASIC
// and will cause xsc_boot_copy commands to always boot to 0 0
// createRadSensorComponent(gpioComIF);
// Still initialize chip select to avoid SPI bus issues.
createRadSensorChipSelect(gpioComIF);
#if OBSW_ADD_ACS_BOARD == 1
// Still initialize chip select to avoid SPI bus issues.
createRadSensorChipSelect(gpioComIF);
createAcsBoardComponents(*spiMainComIF, gpioComIF, uartComIF, *pwrSwitcher, true,
adis1650x::Type::ADIS16507);
#else

View File

@ -2,8 +2,11 @@
#include <mission/power/gsDefs.h>
AcuDummy::AcuDummy(object_id_t objectId, object_id_t comif, CookieIF *comCookie)
: DeviceHandlerBase(objectId, comif, comCookie) {}
AcuDummy::AcuDummy(object_id_t objectId, object_id_t comif, CookieIF *comCookie, bool enableHkSets)
: DeviceHandlerBase(objectId, comif, comCookie),
coreHk(this),
auxHk(this),
enableHkSets(enableHkSets) {}
AcuDummy::~AcuDummy() {}
@ -37,7 +40,49 @@ uint32_t AcuDummy::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) { return
ReturnValue_t AcuDummy::initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
LocalDataPoolManager &poolManager) {
using namespace ACU;
localDataPoolMap.emplace(pool::ACU_CURRENT_IN_CHANNELS, new PoolEntry<int16_t>(6));
localDataPoolMap.emplace(pool::ACU_VOLTAGE_IN_CHANNELS, new PoolEntry<uint16_t>(6));
localDataPoolMap.emplace(pool::ACU_VCC, new PoolEntry<uint16_t>({0}));
localDataPoolMap.emplace(pool::ACU_VBAT, new PoolEntry<uint16_t>({0}));
localDataPoolMap.emplace(ACU::pool::ACU_TEMPERATURES,
new PoolEntry<float>({10.0, 10.0, 10.0}, true));
localDataPoolMap.emplace(pool::ACU_MPPT_MODE, new PoolEntry<uint8_t>({0}));
localDataPoolMap.emplace(pool::ACU_VBOOST_IN_CHANNELS, new PoolEntry<uint16_t>(6));
localDataPoolMap.emplace(pool::ACU_POWER_IN_CHANNELS, new PoolEntry<uint16_t>(6));
localDataPoolMap.emplace(pool::ACU_DAC_ENABLES, new PoolEntry<uint8_t>(3));
localDataPoolMap.emplace(pool::ACU_DAC_RAW_CHANNELS, new PoolEntry<uint16_t>(6));
localDataPoolMap.emplace(pool::ACU_BOOTCAUSE, new PoolEntry<uint32_t>({0}));
localDataPoolMap.emplace(pool::ACU_BOOTCNT, new PoolEntry<uint32_t>({0}));
localDataPoolMap.emplace(pool::ACU_UPTIME, new PoolEntry<uint32_t>({0}));
localDataPoolMap.emplace(pool::ACU_RESET_CAUSE, new PoolEntry<uint16_t>({0}));
localDataPoolMap.emplace(pool::ACU_MPPT_TIME, new PoolEntry<uint16_t>({0}));
localDataPoolMap.emplace(pool::ACU_MPPT_PERIOD, new PoolEntry<uint16_t>({0}));
localDataPoolMap.emplace(pool::ACU_DEVICES, new PoolEntry<uint8_t>(8));
localDataPoolMap.emplace(pool::ACU_DEVICES_STATUS, new PoolEntry<uint8_t>(8));
localDataPoolMap.emplace(pool::ACU_WDT_CNT_GND, new PoolEntry<uint32_t>({0}));
localDataPoolMap.emplace(pool::ACU_WDT_GND_LEFT, new PoolEntry<uint32_t>({0}));
poolManager.subscribeForDiagPeriodicPacket(
subdp::DiagnosticsHkPeriodicParams(coreHk.getSid(), enableHkSets, 30.0));
poolManager.subscribeForRegularPeriodicPacket(
subdp::RegularHkPeriodicParams(auxHk.getSid(), enableHkSets, 6000.0));
return returnvalue::OK;
}
LocalPoolDataSetBase *AcuDummy::getDataSetHandle(sid_t sid) {
if (sid == coreHk.getSid()) {
return &coreHk;
} else if (sid == auxHk.getSid()) {
return &auxHk;
}
return nullptr;
}

View File

@ -2,6 +2,7 @@
#define DUMMIES_ACUDUMMY_H_
#include <fsfw/devicehandlers/DeviceHandlerBase.h>
#include <mission/power/gsDefs.h>
class AcuDummy : public DeviceHandlerBase {
public:
@ -11,10 +12,14 @@ class AcuDummy : public DeviceHandlerBase {
static const uint8_t SIMPLE_COMMAND_DATA = 1;
static const uint8_t PERIODIC_REPLY_DATA = 2;
AcuDummy(object_id_t objectId, object_id_t comif, CookieIF *comCookie);
AcuDummy(object_id_t objectId, object_id_t comif, CookieIF *comCookie, bool enableHkSets);
virtual ~AcuDummy();
protected:
ACU::CoreHk coreHk;
ACU::AuxHk auxHk;
bool enableHkSets;
void doStartUp() override;
void doShutDown() override;
ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t *id) override;
@ -28,6 +33,7 @@ class AcuDummy : public DeviceHandlerBase {
uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) override;
ReturnValue_t initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
LocalDataPoolManager &poolManager) override;
LocalPoolDataSetBase *getDataSetHandle(sid_t sid) override;
};
#endif /* DUMMIES_ACUDUMMY_H_ */

View File

@ -2,8 +2,13 @@
#include <mission/acs/imtqHelpers.h>
ImtqDummy::ImtqDummy(object_id_t objectId, object_id_t comif, CookieIF *comCookie)
: DeviceHandlerBase(objectId, comif, comCookie) {}
ImtqDummy::ImtqDummy(object_id_t objectId, object_id_t comif, CookieIF *comCookie,
power::Switch_t pwrSwitcher, bool enableHkSets)
: DeviceHandlerBase(objectId, comif, comCookie),
setNoTorque(this),
setWithTorque(this),
enableHkSets(enableHkSets),
switcher(pwrSwitcher) {}
ImtqDummy::~ImtqDummy() = default;
@ -11,6 +16,15 @@ void ImtqDummy::doStartUp() { setMode(MODE_NORMAL); }
void ImtqDummy::doShutDown() { setMode(_MODE_POWER_DOWN); }
ReturnValue_t ImtqDummy::getSwitches(const uint8_t **switches, uint8_t *numberOfSwitches) {
if (switcher != power::NO_SWITCH) {
*numberOfSwitches = 1;
*switches = &switcher;
return returnvalue::OK;
}
return DeviceHandlerBase::NO_SWITCH;
}
ReturnValue_t ImtqDummy::buildNormalDeviceCommand(DeviceCommandId_t *id) { return NOTHING_TO_SEND; }
ReturnValue_t ImtqDummy::buildTransitionDeviceCommand(DeviceCommandId_t *id) {
@ -45,5 +59,37 @@ ReturnValue_t ImtqDummy::initializeLocalDataPool(localpool::DataPool &localDataP
localDataPoolMap.emplace(imtq::ACTUATION_RAW_STATUS, new PoolEntry<uint8_t>({0}));
localDataPoolMap.emplace(imtq::DIPOLES_ID, new PoolEntry<int16_t>({0, 0, 0}));
localDataPoolMap.emplace(imtq::CURRENT_TORQUE_DURATION, new PoolEntry<uint16_t>({0}));
// ENG HK No Torque
localDataPoolMap.emplace(imtq::DIGITAL_VOLTAGE_MV, new PoolEntry<uint16_t>({0}));
localDataPoolMap.emplace(imtq::ANALOG_VOLTAGE_MV, new PoolEntry<uint16_t>({0}));
localDataPoolMap.emplace(imtq::DIGITAL_CURRENT, new PoolEntry<float>({0}));
localDataPoolMap.emplace(imtq::ANALOG_CURRENT, new PoolEntry<float>({0}));
localDataPoolMap.emplace(imtq::COIL_CURRENTS, &coilCurrentsMilliampsNoTorque);
localDataPoolMap.emplace(imtq::COIL_TEMPERATURES, &coilTempsNoTorque);
localDataPoolMap.emplace(imtq::MCU_TEMPERATURE, new PoolEntry<int16_t>({0}));
// ENG HK With Torque
localDataPoolMap.emplace(imtq::DIGITAL_VOLTAGE_MV_WT, new PoolEntry<uint16_t>({0}));
localDataPoolMap.emplace(imtq::ANALOG_VOLTAGE_MV_WT, new PoolEntry<uint16_t>({0}));
localDataPoolMap.emplace(imtq::DIGITAL_CURRENT_WT, new PoolEntry<float>({0}));
localDataPoolMap.emplace(imtq::ANALOG_CURRENT_WT, new PoolEntry<float>({0}));
localDataPoolMap.emplace(imtq::COIL_CURRENTS_WT, &coilCurrentsMilliampsWithTorque);
localDataPoolMap.emplace(imtq::COIL_TEMPERATURES_WT, &coilTempsWithTorque);
localDataPoolMap.emplace(imtq::MCU_TEMPERATURE_WT, new PoolEntry<int16_t>({0}));
poolManager.subscribeForDiagPeriodicPacket(
subdp::DiagnosticsHkPeriodicParams(setNoTorque.getSid(), enableHkSets, 30.0));
poolManager.subscribeForDiagPeriodicPacket(
subdp::DiagnosticsHkPeriodicParams(setWithTorque.getSid(), enableHkSets, 30.0));
return DeviceHandlerBase::initializeLocalDataPool(localDataPoolMap, poolManager);
}
LocalPoolDataSetBase *ImtqDummy::getDataSetHandle(sid_t sid) {
if (sid == setNoTorque.getSid()) {
return &setNoTorque;
} else if (sid == setWithTorque.getSid()) {
return &setWithTorque;
}
return nullptr;
}

View File

@ -3,6 +3,8 @@
#include <fsfw/devicehandlers/DeviceHandlerBase.h>
#include "mission/acs/imtqHelpers.h"
class ImtqDummy : public DeviceHandlerBase {
public:
static const DeviceCommandId_t SIMPLE_COMMAND = 1;
@ -11,10 +13,35 @@ class ImtqDummy : public DeviceHandlerBase {
static const uint8_t SIMPLE_COMMAND_DATA = 1;
static const uint8_t PERIODIC_REPLY_DATA = 2;
ImtqDummy(object_id_t objectId, object_id_t comif, CookieIF *comCookie);
ImtqDummy(object_id_t objectId, object_id_t comif, CookieIF *comCookie,
power::Switch_t pwrSwitcher, bool enableHkSets);
~ImtqDummy() override;
protected:
ReturnValue_t getSwitches(const uint8_t **switches, uint8_t *numberOfSwitches) override;
imtq::HkDatasetNoTorque setNoTorque;
imtq::HkDatasetWithTorque setWithTorque;
bool enableHkSets;
PoolEntry<uint8_t> statusMode = PoolEntry<uint8_t>({0});
PoolEntry<uint8_t> statusError = PoolEntry<uint8_t>({0});
PoolEntry<uint8_t> statusConfig = PoolEntry<uint8_t>({0});
PoolEntry<uint32_t> statusUptime = PoolEntry<uint32_t>({0});
PoolEntry<int32_t> mgmCalEntry = PoolEntry<int32_t>(3);
PoolEntry<int16_t> dipolesPoolEntry = PoolEntry<int16_t>({0, 0, 0}, false);
PoolEntry<uint16_t> torqueDurationEntry = PoolEntry<uint16_t>({0}, false);
PoolEntry<float> coilCurrentsMilliampsNoTorque = PoolEntry<float>(3);
PoolEntry<float> coilCurrentsMilliampsWithTorque = PoolEntry<float>(3);
PoolEntry<int16_t> coilTempsNoTorque = PoolEntry<int16_t>(3);
PoolEntry<int16_t> coilTempsWithTorque = PoolEntry<int16_t>(3);
PoolEntry<float> mtmRawNoTorque = PoolEntry<float>(3);
PoolEntry<uint8_t> actStatusNoTorque = PoolEntry<uint8_t>(1);
PoolEntry<float> mtmRawWithTorque = PoolEntry<float>(3);
PoolEntry<uint8_t> actStatusWithTorque = PoolEntry<uint8_t>(1);
power::Switch_t switcher = power::NO_SWITCH;
void doStartUp() override;
void doShutDown() override;
ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t *id) override;
@ -28,6 +55,7 @@ class ImtqDummy : public DeviceHandlerBase {
uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) override;
ReturnValue_t initializeLocalDataPool(localpool::DataPool &localDataPoolMap,
LocalDataPoolManager &poolManager) override;
LocalPoolDataSetBase *getDataSetHandle(sid_t sid) override;
};
#endif /* DUMMIES_IMTQDUMMY_H_ */

View File

@ -42,7 +42,8 @@
#include "mission/system/tree/payloadModeTree.h"
#include "mission/tcs/defs.h"
void dummy::createDummies(DummyCfg cfg, PowerSwitchIF& pwrSwitcher, GpioIF* gpioIF) {
void dummy::createDummies(DummyCfg cfg, PowerSwitchIF& pwrSwitcher, GpioIF* gpioIF,
bool enableHkSets) {
new ComIFDummy(objects::DUMMY_COM_IF);
auto* comCookieDummy = new ComCookieDummy();
if (cfg.addBpxBattDummy) {
@ -74,13 +75,15 @@ void dummy::createDummies(DummyCfg cfg, PowerSwitchIF& pwrSwitcher, GpioIF* gpio
}
auto* imtqAssy = new ImtqAssembly(objects::IMTQ_ASSY);
imtqAssy->connectModeTreeParent(satsystem::acs::ACS_SUBSYSTEM);
auto* imtqDummy = new ImtqDummy(objects::IMTQ_HANDLER, objects::DUMMY_COM_IF, comCookieDummy);
auto* imtqDummy = new ImtqDummy(objects::IMTQ_HANDLER, objects::DUMMY_COM_IF, comCookieDummy,
power::Switches::PDU1_CH3_MGT_5V, enableHkSets);
imtqDummy->enableThermalModule(ThermalStateCfg());
imtqDummy->setPowerSwitcher(&pwrSwitcher);
imtqDummy->connectModeTreeParent(*imtqAssy);
if (cfg.addOnlyAcuDummy) {
new AcuDummy(objects::ACU_HANDLER, objects::DUMMY_COM_IF, comCookieDummy);
new AcuDummy(objects::ACU_HANDLER, objects::DUMMY_COM_IF, comCookieDummy, enableHkSets);
} else if (cfg.addPowerDummies) {
new AcuDummy(objects::ACU_HANDLER, objects::DUMMY_COM_IF, comCookieDummy);
new AcuDummy(objects::ACU_HANDLER, objects::DUMMY_COM_IF, comCookieDummy, enableHkSets);
new PduDummy(objects::PDU1_HANDLER, objects::DUMMY_COM_IF, comCookieDummy);
new PduDummy(objects::PDU2_HANDLER, objects::DUMMY_COM_IF, comCookieDummy);
new P60DockDummy(objects::P60DOCK_HANDLER, objects::DUMMY_COM_IF, comCookieDummy);

View File

@ -22,6 +22,6 @@ struct DummyCfg {
bool addCamSwitcherDummy = true;
};
void createDummies(DummyCfg cfg, PowerSwitchIF& pwrSwitch, GpioIF* gpioIF);
void createDummies(DummyCfg cfg, PowerSwitchIF& pwrSwitch, GpioIF* gpioIF, bool enableHkSets);
} // namespace dummy

View File

@ -94,13 +94,6 @@ void TmStoreTaskBase::cancelDump(DumpContext& ctx, PersistentTmStore& store, boo
ReturnValue_t TmStoreTaskBase::handleOneDump(PersistentTmStoreWithTmQueue& store,
DumpContext& dumpContext, bool& dumpPerformed) {
ReturnValue_t result = returnvalue::OK;
// The PTME might have been reset an transmitter state change, so there is no point in continuing
// the dump.
// TODO: Will be solved in a cleaner way, this is kind of a hack.
if (not channel.isTxOn()) {
cancelDump(dumpContext, store, false);
return returnvalue::FAILED;
}
// It is assumed that the PTME will only be locked for a short period (e.g. to change datarate).
if (not channel.isBusy() and not ptmeLocked) {
performDump(store, dumpContext, dumpPerformed);
@ -138,25 +131,22 @@ ReturnValue_t TmStoreTaskBase::performDump(PersistentTmStoreWithTmQueue& store,
dumpContext.ptmeBusyCounter = 0;
tmSinkBusyCd.resetTimer();
ReturnValue_t result = store.getNextDumpPacket(tmReader, fileHasSwapped);
if (result != returnvalue::OK) {
sif::error << "PersistentTmStore: Getting next dump packet failed" << std::endl;
} else if (fileHasSwapped or result == PersistentTmStore::DUMP_DONE) {
if (fileHasSwapped and result == PersistentTmStore::DUMP_DONE) {
// This can happen if a file is corrupted and the next file swap completes the dump.
dumpDoneHandler();
return returnvalue::OK;
} else if (result != returnvalue::OK) {
sif::error << "PersistentTmStore: Getting next dump packet failed" << std::endl;
return result;
}
dumpedLen = tmReader.getFullPacketLen();
// Only write to VC if mode is on, but always confirm the dump.
// If the mode is OFF, it is assumed the PTME is not usable and is not allowed to be written
// (e.g. to confirm a reset or the transmitter is off anyway).
if (mode == MODE_ON) {
result = channel.write(tmReader.getFullData(), dumpedLen);
if (result == DirectTmSinkIF::IS_BUSY) {
sif::warning << "PersistentTmStore: Unexpected VC channel busy" << std::endl;
} else if (result != returnvalue::OK) {
sif::warning << "PersistentTmStore: Unexpected VC channel write failure" << std::endl;
}
result = channel.write(tmReader.getFullData(), dumpedLen);
if (result == DirectTmSinkIF::IS_BUSY) {
sif::warning << "PersistentTmStore: Unexpected VC channel busy" << std::endl;
} else if (result != returnvalue::OK) {
sif::warning << "PersistentTmStore: Unexpected VC channel write failure" << std::endl;
}
result = store.confirmDump(tmReader, fileHasSwapped);
if ((result == PersistentTmStore::DUMP_DONE or result == returnvalue::OK)) {
dumpPerformed = true;

View File

@ -11,23 +11,14 @@ ReturnValue_t VirtualChannel::sendNextTm(const uint8_t* data, size_t size) {
}
ReturnValue_t VirtualChannel::write(const uint8_t* data, size_t size) {
if (txOn) {
return ptme.writeToVc(vcId, data, size);
}
return returnvalue::OK;
return ptme.writeToVc(vcId, data, size);
}
uint8_t VirtualChannel::getVcid() const { return vcId; }
const char* VirtualChannel::getName() const { return vcName.c_str(); }
bool VirtualChannel::isBusy() const {
// Data is discarded, so channel is not busy.
if (not txOn) {
return false;
}
return ptme.isBusy(vcId);
}
bool VirtualChannel::isBusy() const { return ptme.isBusy(vcId); }
void VirtualChannel::cancelTransfer() { ptme.cancelTransfer(vcId); }

View File

@ -175,7 +175,7 @@ void ThermalController::performControlOperation() {
heaterHandler.getAllSwitchStates(heaterSwitchStateArray);
{
PoolReadGuard pg(&heaterInfo);
std::memcpy(heaterInfo.heaterSwitchState.value, heaterStates.data(), 8);
std::memcpy(heaterInfo.heaterSwitchState.value, heaterSwitchStateArray.data(), 8);
{
PoolReadGuard pg2(&currentVecPdu2);
if (pg.getReadResult() == returnvalue::OK and pg2.getReadResult() == returnvalue::OK) {
@ -1631,13 +1631,18 @@ bool ThermalController::selectAndReadSensorTemp(HeaterContext& htrCtx) {
bool ThermalController::chooseHeater(heater::Switch& switchNr, heater::Switch redSwitchNr) {
bool heaterAvailable = true;
if (heaterHandler.getHealth(switchNr) != HasHealthIF::HEALTHY) {
if (heaterHandler.getHealth(redSwitchNr) == HasHealthIF::HEALTHY) {
HasHealthIF::HealthState mainHealth = heaterHandler.getHealth(switchNr);
HasHealthIF::HealthState redHealth = heaterHandler.getHealth(redSwitchNr);
if (mainHealth != HasHealthIF::HEALTHY) {
if (redHealth == HasHealthIF::HEALTHY) {
switchNr = redSwitchNr;
redSwitchNrInUse = true;
} else {
heaterAvailable = false;
triggerEvent(tcsCtrl::NO_HEALTHY_HEATER_AVAILABLE, switchNr, redSwitchNr);
// Special case: Ground might command/do something with the heaters, so prevent spam.
if (not(mainHealth == EXTERNAL_CONTROL and redHealth == EXTERNAL_CONTROL)) {
triggerEvent(tcsCtrl::NO_HEALTHY_HEATER_AVAILABLE, switchNr, redSwitchNr);
}
}
} else {
redSwitchNrInUse = false;

View File

@ -551,6 +551,9 @@ ReturnValue_t AcsParameters::getParameter(uint8_t domainId, uint8_t parameterId,
case 0xB:
parameterWrapper->setVector(nadirModeControllerParameters.quatRef);
break;
case 0xB:
parameterWrapper->setVector(nadirModeControllerParameters.refRotRate);
break;
case 0xC:
parameterWrapper->set(nadirModeControllerParameters.timeElapsedMax);
break;

View File

@ -62,7 +62,7 @@ void ActuatorCmd::cmdDipoleMtq(const double *inverseAlignment, const double maxD
// scaling along largest element if dipole exceeds maximum
uint8_t maxIdx = 0;
VectorOperations<double>::maxAbsValue(dipoleMomentActuatorDouble, 3, &maxIdx);
double maxAbsValue = abs(dipoleMomentActuatorDouble[maxIdx]);
double maxAbsValue = std::abs(dipoleMomentActuatorDouble[maxIdx]);
if (maxAbsValue > maxDipole) {
double scalingFactor = maxDipole / maxAbsValue;
VectorOperations<double>::mulScalar(dipoleMomentActuatorDouble, scalingFactor,

View File

@ -268,6 +268,8 @@ void HeaterHandler::handleSwitchOnCommand(heater::Switch heaterIdx) {
triggerEvent(GPIO_PULL_HIGH_FAILED, result);
} else {
triggerEvent(HEATER_WENT_ON, heaterIdx, 0);
EventManagerIF::triggerEvent(helper.heaters[heaterIdx].first->getObjectId(), MODE_INFO,
MODE_ON, 0);
{
MutexGuard mg(handlerLock, LOCK_TYPE, LOCK_TIMEOUT, LOCK_CTX);
heater.switchState = ON;
@ -324,6 +326,8 @@ void HeaterHandler::handleSwitchOffCommand(heater::Switch heaterIdx) {
heater.switchState = OFF;
}
triggerEvent(HEATER_WENT_OFF, heaterIdx, 0);
EventManagerIF::triggerEvent(helper.heaters[heaterIdx].first->getObjectId(), MODE_INFO,
MODE_OFF, 0);
// When all switches are off, also main line switch will be turned off
if (allSwitchesOff()) {
mainLineSwitcher->sendSwitchCommand(mainLineSwitch, PowerSwitchIF::SWITCH_OFF);

View File

@ -256,6 +256,7 @@ ReturnValue_t PersistentTmStore::getNextDumpPacket(PusTmReader& reader, bool& fi
if (state == State::IDLE or dumpParams.pendingPacketDump) {
return returnvalue::FAILED;
}
fileHasSwapped = false;
reader.setReadOnlyData(fileBuf.data() + dumpParams.currentSize,
fileBuf.size() - dumpParams.currentSize);
// CRC check to fully ensure this is a valid TM
@ -270,7 +271,6 @@ ReturnValue_t PersistentTmStore::getNextDumpPacket(PusTmReader& reader, bool& fi
fileHasSwapped = true;
return loadNextDumpFile();
}
fileHasSwapped = false;
dumpParams.pendingPacketDump = true;
return returnvalue::OK;
}

2
tmtc

@ -1 +1 @@
Subproject commit 6ec0ce20fa98877c9f88acb5fe9129254291344b
Subproject commit 6182369e4f40872c5c26e59be25d5fa79339176a