diff --git a/CHANGELOG.md b/CHANGELOG.md index 7fc8f0c5..26df0fbf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -22,11 +22,13 @@ will consitute of a breaking change warranting a new major release: the `MEKF` on its own once. This way, there will not be an event spam and operators will have to look into the reason of wrong outputs. To restore the reset ability, an action command has been added. +- Contingency handling for non-working I2C bus bug. Reboot the system if the I2C is not working. ## Fixed - Fixed transition for dual power lane assemblies: When going from dual side submode to single side submode, perform logical commanding first, similarly to when going to OFF mode. +- GPS time is only set to valid if at least one satellite is in view. ## Changed @@ -36,7 +38,8 @@ will consitute of a breaking change warranting a new major release: consit of just one digit. - EIVE system fallback and COM system fallback: Perform general subsystem handling first, then event reception, and finally any new transition handling. - +- Safe mode controller failure event now only triggers once per minute. + # [v1.38.0] 2023-03-17 eive-tmtc: v2.19.2 diff --git a/bsp_q7s/core/CoreController.cpp b/bsp_q7s/core/CoreController.cpp index 085d27de..61e7ee67 100644 --- a/bsp_q7s/core/CoreController.cpp +++ b/bsp_q7s/core/CoreController.cpp @@ -31,14 +31,15 @@ xsc::Chip CoreController::CURRENT_CHIP = xsc::Chip::NO_CHIP; xsc::Copy CoreController::CURRENT_COPY = xsc::Copy::NO_COPY; -CoreController::CoreController(object_id_t objectId) +CoreController::CoreController(object_id_t objectId, const std::atomic_uint16_t& i2cErrors) : ExtendedControllerBase(objectId, 5), cmdExecutor(4096), cmdReplyBuf(4096, true), cmdRepliesSizes(128), opDivider5(5), opDivider10(10), - hkSet(this) { + hkSet(this), + i2cErrors(i2cErrors) { cmdExecutor.setRingBuffer(&cmdReplyBuf, &cmdRepliesSizes); try { sdcMan = SdCardManager::instance(); @@ -107,6 +108,12 @@ void CoreController::performControlOperation() { sdStateMachine(); performMountedSdCardOperations(); readHkData(); + if(i2cErrors >= 5) { + bool protOpPerformed = false; + triggerEvent(I2C_UNAVAILABLE_REBOOT); + gracefulShutdownTasks(CURRENT_CHIP, CURRENT_COPY, protOpPerformed); + std::system("xsc_boot_copy -r"); + } if (shellCmdIsExecuting) { bool replyReceived = false; // TODO: We could read the data in the ring buffer and send it as an action data reply. diff --git a/bsp_q7s/core/CoreController.h b/bsp_q7s/core/CoreController.h index fa07ec59..cd504e3c 100644 --- a/bsp_q7s/core/CoreController.h +++ b/bsp_q7s/core/CoreController.h @@ -15,6 +15,7 @@ #include "fsfw/controller/ExtendedControllerBase.h" #include "mission/devices/devicedefinitions/GPSDefinitions.h" #include "mission/trace.h" +#include class Timer; class SdCardManager; @@ -131,8 +132,9 @@ class CoreController : public ExtendedControllerBase { //! P1: First 16 bits boot count of image 0 0, last 16 bits boot count of image 0 1. //! P2: First 16 bits boot count of image 1 0, last 16 bits boot count of image 1 1. static constexpr Event INDIVIDUAL_BOOT_COUNTS = event::makeEvent(SUBSYSTEM_ID, 8, severity::INFO); + static constexpr Event I2C_UNAVAILABLE_REBOOT = event::makeEvent(SUBSYSTEM_ID, 10, severity::MEDIUM); - CoreController(object_id_t objectId); + CoreController(object_id_t objectId, const std::atomic_uint16_t& i2cErrors); virtual ~CoreController(); ReturnValue_t initialize() override; @@ -262,6 +264,7 @@ class CoreController : public ExtendedControllerBase { PoolEntry plVoltageEntry = PoolEntry(0.0); core::HkSet hkSet; + const std::atomic_uint16_t& i2cErrors; #if OBSW_SD_CARD_MUST_BE_ON == 1 bool remountAttemptFlag = true; diff --git a/bsp_q7s/core/ObjectFactory.cpp b/bsp_q7s/core/ObjectFactory.cpp index abd37678..84101e63 100644 --- a/bsp_q7s/core/ObjectFactory.cpp +++ b/bsp_q7s/core/ObjectFactory.cpp @@ -123,6 +123,7 @@ using gpio::Levels; ResetArgs RESET_ARGS_GNSS; std::atomic_bool LINK_STATE = CcsdsIpCoreHandler::LINK_DOWN; +std::atomic_uint16_t I2C_FATAL_ERRORS = 0; void Factory::setStaticFrameworkObjectIds() { PusServiceBase::PUS_DISTRIBUTOR = objects::PUS_PACKET_DISTRIBUTOR; @@ -953,7 +954,7 @@ void ObjectFactory::createImtqComponents(PowerSwitchIF* pwrSwitcher) { auto* imtqAssy = new ImtqAssembly(objects::IMTQ_ASSY); imtqAssy->connectModeTreeParent(satsystem::acs::ACS_SUBSYSTEM); - new ImtqPollingTask(objects::IMTQ_POLLING); + new ImtqPollingTask(objects::IMTQ_POLLING, I2C_FATAL_ERRORS); I2cCookie* imtqI2cCookie = new I2cCookie(addresses::IMTQ, imtq::MAX_REPLY_SIZE, q7s::I2C_PL_EIVE); auto imtqHandler = new ImtqHandler(objects::IMTQ_HANDLER, objects::IMTQ_POLLING, imtqI2cCookie, power::Switches::PDU1_CH3_MGT_5V); diff --git a/bsp_q7s/core/ObjectFactory.h b/bsp_q7s/core/ObjectFactory.h index c0da31d4..66ece5cd 100644 --- a/bsp_q7s/core/ObjectFactory.h +++ b/bsp_q7s/core/ObjectFactory.h @@ -12,6 +12,7 @@ #include #include +#include class LinuxLibgpioIF; class SerialComIF; @@ -22,6 +23,8 @@ class HealthTableIF; class AcsBoardAssembly; class GpioIF; +extern std::atomic_uint16_t I2C_FATAL_ERRORS; + namespace ObjectFactory { struct CcsdsComponentArgs { diff --git a/bsp_q7s/fmObjectFactory.cpp b/bsp_q7s/fmObjectFactory.cpp index bb63a1d0..9862c73f 100644 --- a/bsp_q7s/fmObjectFactory.cpp +++ b/bsp_q7s/fmObjectFactory.cpp @@ -38,7 +38,7 @@ void ObjectFactory::produce(void* args) { q7s::gpioCallbacks::initSpiCsDecoder(gpioComIF); gpioCallbacks::disableAllDecoder(gpioComIF); - new CoreController(objects::CORE_CONTROLLER); + new CoreController(objects::CORE_CONTROLLER, I2C_FATAL_ERRORS); createPcduComponents(gpioComIF, &pwrSwitcher); auto* stackHandler = new Stack5VHandler(*pwrSwitcher); diff --git a/linux/devices/GpsHyperionLinuxController.cpp b/linux/devices/GpsHyperionLinuxController.cpp index 18461c14..8b26da5c 100644 --- a/linux/devices/GpsHyperionLinuxController.cpp +++ b/linux/devices/GpsHyperionLinuxController.cpp @@ -302,7 +302,10 @@ ReturnValue_t GpsHyperionLinuxController::handleGpsReadData() { // TIME is set for every message, no need for a counter bool timeValid = false; if (TIME_SET == (TIME_SET & gps.set)) { - timeValid = true; + // To prevent totally incorrect times from being declared valid. + if(gpsSet.satInView.isValid() and gpsSet.satInView.value >= 1) { + timeValid = true; + } timeval time = {}; #if LIBGPS_VERSION_MINOR <= 17 gpsSet.unixSeconds.value = std::floor(gps.fix.time); diff --git a/linux/devices/ImtqPollingTask.cpp b/linux/devices/ImtqPollingTask.cpp index fbd5f847..a0e59412 100644 --- a/linux/devices/ImtqPollingTask.cpp +++ b/linux/devices/ImtqPollingTask.cpp @@ -10,7 +10,9 @@ #include "fsfw/FSFW.h" -ImtqPollingTask::ImtqPollingTask(object_id_t imtqPollingTask) : SystemObject(imtqPollingTask) { +ImtqPollingTask::ImtqPollingTask(object_id_t imtqPollingTask, + std::atomic_uint16_t& i2cFatalErrors): SystemObject(imtqPollingTask), + i2cFatalErrors(i2cFatalErrors) { semaphore = SemaphoreFactory::instance()->createBinarySemaphore(); semaphore->acquire(); ipcLock = MutexFactory::instance()->createMutex(); @@ -427,12 +429,20 @@ ReturnValue_t ImtqPollingTask::performI2cFullRequest(uint8_t* reply, size_t repl if (ioctl(fd, I2C_SLAVE, i2cAddr) < 0) { sif::warning << "Opening IMTQ slave device failed with code " << errno << ": " << strerror(errno) << std::endl; + if(errno == EBUSY) { + i2cFatalErrors++; + } } int written = write(fd, cmdBuf.data(), cmdLen); if (written < 0) { sif::error << "IMTQ: Failed to send with error code " << errno << ". Error description: " << strerror(errno) << std::endl; + // This is a weird issue which sometimes occurs on debug builds. All I2C buses are busy + // for all writes, + if(errno == EBUSY) { + i2cFatalErrors++; + } return returnvalue::FAILED; } else if (static_cast(written) != cmdLen) { sif::error << "IMTQ: Could not write all bytes" << std::endl; diff --git a/linux/devices/ImtqPollingTask.h b/linux/devices/ImtqPollingTask.h index cb2d3882..efe6a01b 100644 --- a/linux/devices/ImtqPollingTask.h +++ b/linux/devices/ImtqPollingTask.h @@ -8,12 +8,13 @@ #include "fsfw/objectmanager/SystemObject.h" #include "fsfw/tasks/ExecutableObjectIF.h" #include "mission/devices/devicedefinitions/imtqHelpers.h" +#include class ImtqPollingTask : public SystemObject, public ExecutableObjectIF, public DeviceCommunicationIF { public: - ImtqPollingTask(object_id_t imtqPollingTask); + ImtqPollingTask(object_id_t imtqPollingTask, std::atomic_uint16_t& i2cFatalErrors); ReturnValue_t performOperation(uint8_t operationCode) override; ReturnValue_t initialize() override; @@ -28,6 +29,7 @@ class ImtqPollingTask : public SystemObject, ReturnValue_t comStatus = returnvalue::OK; MutexIF* ipcLock; MutexIF* bufLock; + std::atomic_uint16_t& i2cFatalErrors; I2cCookie* i2cCookie = nullptr; const char* i2cDev = nullptr; address_t i2cAddr = 0; diff --git a/mission/controller/AcsController.cpp b/mission/controller/AcsController.cpp index c87f460c..b275960b 100644 --- a/mission/controller/AcsController.cpp +++ b/mission/controller/AcsController.cpp @@ -186,7 +186,7 @@ void AcsController::performSafe() { safeCtrlFailureFlag = true; } safeCtrlFailureCounter++; - if (safeCtrlFailureCounter > 50) { + if (safeCtrlFailureCounter > 150) { safeCtrlFailureFlag = false; safeCtrlFailureCounter = 0; }