diff --git a/bsp_q7s/boardconfig/busConf.h b/bsp_q7s/boardconfig/busConf.h index e8cc5bd2..fffa4a2a 100644 --- a/bsp_q7s/boardconfig/busConf.h +++ b/bsp_q7s/boardconfig/busConf.h @@ -4,6 +4,8 @@ namespace q7s { static constexpr char SPI_DEFAULT_DEV[] = "/dev/spi-main"; +static constexpr uint32_t SPI_MAIN_BUS_LOCK_TIMEOUT = 50; + static constexpr char SPI_RW_DEV[] = "/dev/spi-rw"; static constexpr char I2C_DEFAULT_DEV[] = "/dev/i2c-eive"; diff --git a/bsp_q7s/callbacks/rwSpiCallback.cpp b/bsp_q7s/callbacks/rwSpiCallback.cpp index 0d845fb8..0fd2c512 100644 --- a/bsp_q7s/callbacks/rwSpiCallback.cpp +++ b/bsp_q7s/callbacks/rwSpiCallback.cpp @@ -44,8 +44,8 @@ ReturnValue_t spiCallback(SpiComIF* comIf, SpiCookie* cookie, const uint8_t* sen GpioIF* gpioIF = comIf->getGpioInterface(); MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING; uint32_t timeoutMs = 0; - cookie->getMutexParams(timeoutType, timeoutMs); MutexIF* mutex = comIf->getCsMutex(); + cookie->getMutexParams(timeoutType, timeoutMs); if (mutex == nullptr or gpioIF == nullptr) { sif::debug << "rwSpiCallback::spiCallback: Mutex or GPIO interface invalid" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; diff --git a/bsp_q7s/core/InitMission.cpp b/bsp_q7s/core/InitMission.cpp index 8913789b..1b9cc374 100644 --- a/bsp_q7s/core/InitMission.cpp +++ b/bsp_q7s/core/InitMission.cpp @@ -1,5 +1,7 @@ #include "bsp_q7s/core/InitMission.h" +#include + #include #include @@ -13,6 +15,7 @@ #include "fsfw/tasks/FixedTimeslotTaskIF.h" #include "fsfw/tasks/PeriodicTaskIF.h" #include "fsfw/tasks/TaskFactory.h" +#include "mission/devices/devicedefinitions/Max31865Definitions.h" #include "mission/utility/InitMission.h" #include "pollingsequence/pollingSequenceFactory.h" @@ -123,7 +126,7 @@ void initmission::initTasks() { #if OBSW_ADD_ACS_HANDLERS == 1 PeriodicTaskIF* acsTask = factory->createPeriodicTask( - "ACS_CTRL", 45, PeriodicTaskIF::MINIMUM_STACK_SIZE * 2, 0.4, missedDeadlineFunc); + "ACS_TASK", 50, PeriodicTaskIF::MINIMUM_STACK_SIZE * 2, 0.4, missedDeadlineFunc); result = acsTask->addComponent(objects::GPS_CONTROLLER); if (result != HasReturnvaluesIF::RETURN_OK) { initmission::printAddObjectError("GPS_CTRL", objects::GPS_CONTROLLER); @@ -145,19 +148,49 @@ void initmission::initTasks() { initmission::printAddObjectError("RW_ASS", objects::RW_ASS); } #endif - #if OBSW_ADD_SUS_BOARD_ASS == 1 result = sysTask->addComponent(objects::SUS_BOARD_ASS); if (result != HasReturnvaluesIF::RETURN_OK) { initmission::printAddObjectError("SUS_BOARD_ASS", objects::SUS_BOARD_ASS); } #endif -#if OBSW_ADD_RTD_DEVICES == 1 - result = sysTask->addComponent(objects::TCS_BOARD_ASS); + + PeriodicTaskIF* tcsPollingTask = factory->createPeriodicTask( + "TCS_POLLING_TASK", 70, PeriodicTaskIF::MINIMUM_STACK_SIZE * 2, 0.5, missedDeadlineFunc); + result = tcsPollingTask->addComponent(objects::SPI_RTD_COM_IF); if (result != HasReturnvaluesIF::RETURN_OK) { - initmission::printAddObjectError("TCS_BOARD_ASS", objects::TCS_BOARD_ASS); + initmission::printAddObjectError("SPI_RTD_POLLING", objects::SPI_RTD_COM_IF); } -#endif /* OBSW_ADD_RTD_DEVICES == 1 */ + PeriodicTaskIF* tcsTask = factory->createPeriodicTask( + "TCS_TASK", 45, PeriodicTaskIF::MINIMUM_STACK_SIZE, 0.8, missedDeadlineFunc); + std::array rtdIds = { + objects::RTD_0_IC3_PLOC_HEATSPREADER, + objects::RTD_1_IC4_PLOC_MISSIONBOARD, + objects::RTD_2_IC5_4K_CAMERA, + objects::RTD_3_IC6_DAC_HEATSPREADER, + objects::RTD_4_IC7_STARTRACKER, + objects::RTD_5_IC8_RW1_MX_MY, + objects::RTD_6_IC9_DRO, + objects::RTD_7_IC10_SCEX, + objects::RTD_8_IC11_X8, + objects::RTD_9_IC12_HPA, + objects::RTD_10_IC13_PL_TX, + objects::RTD_11_IC14_MPA, + objects::RTD_12_IC15_ACU, + objects::RTD_13_IC16_PLPCDU_HEATSPREADER, + objects::RTD_14_IC17_TCS_BOARD, + objects::RTD_15_IC18_IMTQ, + }; +#if OBSW_ADD_RTD_DEVICES == 1 + tcsTask->addComponent(objects::TCS_BOARD_ASS); + for (const auto& rtd : rtdIds) { + tcsTask->addComponent(rtd, DeviceHandlerIF::PERFORM_OPERATION); + tcsTask->addComponent(rtd, DeviceHandlerIF::SEND_WRITE); + tcsTask->addComponent(rtd, DeviceHandlerIF::GET_WRITE); + tcsTask->addComponent(rtd, DeviceHandlerIF::SEND_READ); + tcsTask->addComponent(rtd, DeviceHandlerIF::GET_READ); + } +#endif /* OBSW_ADD_RTD_DEVICES */ // FS task, task interval does not matter because it runs in permanent loop, priority low // because it is a non-essential background task @@ -254,12 +287,10 @@ void initmission::initTasks() { strHelperTask->startTask(); #endif /* OBSW_ADD_STAR_TRACKER == 1 */ -#if OBSW_ADD_ACS_HANDLERS == 1 acsTask->startTask(); -#endif -#if OBSW_ADD_RTD_DEVICES == 1 sysTask->startTask(); -#endif + tcsPollingTask->startTask(); + tcsTask->startTask(); #if OBSW_ADD_PLOC_SUPERVISOR == 1 supvHelperTask->startTask(); #endif /* OBSW_ADD_PLOC_SUPERVISOR == 1 */ diff --git a/bsp_q7s/core/InitMission.h b/bsp_q7s/core/InitMission.h index 5c509b79..e0b1d8f2 100644 --- a/bsp_q7s/core/InitMission.h +++ b/bsp_q7s/core/InitMission.h @@ -3,7 +3,7 @@ #include -#include "fsfw/tasks/Typedef.h" +#include "fsfw/tasks/definitions.h" class PeriodicTaskIF; class TaskFactory; diff --git a/bsp_q7s/core/ObjectFactory.cpp b/bsp_q7s/core/ObjectFactory.cpp index 1715fa63..490b5251 100644 --- a/bsp_q7s/core/ObjectFactory.cpp +++ b/bsp_q7s/core/ObjectFactory.cpp @@ -214,6 +214,7 @@ void ObjectFactory::createRadSensorComponent(LinuxLibgpioIF* gpioComIF) { SpiCookie* spiCookieRadSensor = new SpiCookie(addresses::RAD_SENSOR, gpioIds::CS_RAD_SENSOR, RAD_SENSOR::READ_SIZE, spi::DEFAULT_MAX_1227_MODE, spi::DEFAULT_MAX_1227_SPEED); + spiCookieRadSensor->setMutexParams(MutexIF::TimeoutType::WAITING, spi::RAD_SENSOR_CS_TIMEOUT); auto radSensor = new RadiationSensorHandler(objects::RAD_SENSOR, objects::SPI_MAIN_COM_IF, spiCookieRadSensor, gpioComIF); static_cast(radSensor); diff --git a/bsp_q7s/fmObjectFactory.cpp b/bsp_q7s/fmObjectFactory.cpp index 638edcd5..00e7bbd9 100644 --- a/bsp_q7s/fmObjectFactory.cpp +++ b/bsp_q7s/fmObjectFactory.cpp @@ -38,7 +38,7 @@ void ObjectFactory::produce(void* args) { #if OBSW_ADD_SYRLINKS == 1 createSyrlinksComponents(pwrSwitcher); #endif /* OBSW_ADD_SYRLINKS == 1 */ - createRtdComponents(q7s::SPI_DEFAULT_DEV, gpioComIF, pwrSwitcher); + createRtdComponents(q7s::SPI_DEFAULT_DEV, gpioComIF, pwrSwitcher, spiMainComIF); createPayloadComponents(gpioComIF); #if OBSW_ADD_MGT == 1 diff --git a/common/config/devConf.h b/common/config/devConf.h index 37e10bf3..5f9e4766 100644 --- a/common/config/devConf.h +++ b/common/config/devConf.h @@ -32,6 +32,7 @@ static constexpr spi::SpiModes DEFAULT_L3G_MODE = spi::SpiModes::MODE_3; static const uint32_t SUS_MAX1227_SPI_FREQ = 976'000; static constexpr spi::SpiModes SUS_MAX_1227_MODE = spi::SpiModes::MODE_3; +static constexpr dur_millis_t RAD_SENSOR_CS_TIMEOUT = 120; static constexpr uint32_t DEFAULT_MAX_1227_SPEED = 976'000; static constexpr spi::SpiModes DEFAULT_MAX_1227_MODE = spi::SpiModes::MODE_3; @@ -43,6 +44,7 @@ static constexpr spi::SpiModes DEFAULT_ADIS16507_MODE = spi::SpiModes::MODE_3; static constexpr uint32_t RW_SPEED = 300'000; static constexpr spi::SpiModes RW_MODE = spi::SpiModes::MODE_0; +static constexpr dur_millis_t RTD_CS_TIMEOUT = 50; static constexpr uint32_t RTD_SPEED = 2'000'000; static constexpr spi::SpiModes RTD_MODE = spi::SpiModes::MODE_3; diff --git a/fsfw b/fsfw index e758f0be..f35b0ffb 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit e758f0be2e8864c761877a4dcbdf461df52072f7 +Subproject commit f35b0ffbbd6e0e9cc1a760d0aeb69931907f1d62 diff --git a/linux/ObjectFactory.cpp b/linux/ObjectFactory.cpp index 269b0f79..f84cf52f 100644 --- a/linux/ObjectFactory.cpp +++ b/linux/ObjectFactory.cpp @@ -7,6 +7,8 @@ #include #include #include +#include +#include #include #include #include @@ -189,7 +191,7 @@ void ObjectFactory::createSunSensorComponents(GpioIF* gpioComIF, SpiComIF* spiCo } void ObjectFactory::createRtdComponents(std::string spiDev, GpioIF* gpioComIF, - PowerSwitchIF* pwrSwitcher) { + PowerSwitchIF* pwrSwitcher, SpiComIF* comIF) { using namespace gpio; GpioCookie* rtdGpioCookie = new GpioCookie; @@ -245,8 +247,8 @@ void ObjectFactory::createRtdComponents(std::string spiDev, GpioIF* gpioComIF, gpioChecker(gpioComIF->addGpios(rtdGpioCookie), "RTDs"); #if OBSW_ADD_RTD_DEVICES == 1 - static constexpr uint8_t NUMBER_RTDS = 16; - std::array, NUMBER_RTDS> cookieArgs = {{ + using namespace EiveMax31855; + std::array, NUM_RTDS> cookieArgs = {{ {addresses::RTD_IC_3, gpioIds::RTD_IC_3}, {addresses::RTD_IC_4, gpioIds::RTD_IC_4}, {addresses::RTD_IC_5, gpioIds::RTD_IC_5}, @@ -264,48 +266,52 @@ void ObjectFactory::createRtdComponents(std::string spiDev, GpioIF* gpioComIF, {addresses::RTD_IC_17, gpioIds::RTD_IC_17}, {addresses::RTD_IC_18, gpioIds::RTD_IC_18}, }}; - std::array rtdIds = {objects::RTD_0_IC3_PLOC_HEATSPREADER, - objects::RTD_1_IC4_PLOC_MISSIONBOARD, - objects::RTD_2_IC5_4K_CAMERA, - objects::RTD_3_IC6_DAC_HEATSPREADER, - objects::RTD_4_IC7_STARTRACKER, - objects::RTD_5_IC8_RW1_MX_MY, - objects::RTD_6_IC9_DRO, - objects::RTD_7_IC10_SCEX, - objects::RTD_8_IC11_X8, - objects::RTD_9_IC12_HPA, - objects::RTD_10_IC13_PL_TX, - objects::RTD_11_IC14_MPA, - objects::RTD_12_IC15_ACU, - objects::RTD_13_IC16_PLPCDU_HEATSPREADER, - objects::RTD_14_IC17_TCS_BOARD, - objects::RTD_15_IC18_IMTQ}; - std::array rtdCookies = {}; - std::array rtds = {}; + // HSPD: Heatspreader + std::array, NUM_RTDS> rtdInfos = {{ + {objects::RTD_0_IC3_PLOC_HEATSPREADER, "RTD_0_PLOC_HSPD"}, + {objects::RTD_1_IC4_PLOC_MISSIONBOARD, "RTD_1_PLOC_MISSIONBRD"}, + {objects::RTD_2_IC5_4K_CAMERA, "RTD_2_4K_CAMERA"}, + {objects::RTD_3_IC6_DAC_HEATSPREADER, "RTD_3_DAC_HSPD"}, + {objects::RTD_4_IC7_STARTRACKER, "RTD_4_STARTRACKER"}, + {objects::RTD_5_IC8_RW1_MX_MY, "RTD_5_RW1_MX_MY"}, + {objects::RTD_6_IC9_DRO, "RTD_6_DRO"}, + {objects::RTD_7_IC10_SCEX, "RTD_7_SCEX"}, + {objects::RTD_8_IC11_X8, "RTD_8_X8"}, + {objects::RTD_9_IC12_HPA, "RTD_9_HPA"}, + {objects::RTD_10_IC13_PL_TX, "RTD_10_PL_TX,"}, + {objects::RTD_11_IC14_MPA, "RTD_11_MPA"}, + {objects::RTD_12_IC15_ACU, "RTD_12_ACU"}, + {objects::RTD_13_IC16_PLPCDU_HEATSPREADER, "RTD_13_PLPCDU_HSPD"}, + {objects::RTD_14_IC17_TCS_BOARD, "RTD_14_TCS_BOARD"}, + {objects::RTD_15_IC18_IMTQ, "RTD_15_IMTQ"}, + }}; + std::array rtdCookies = {}; + std::array rtds = {}; RtdFdir* rtdFdir = nullptr; - for (uint8_t idx = 0; idx < NUMBER_RTDS; idx++) { - rtdCookies[idx] = - new SpiCookie(cookieArgs[idx].first, cookieArgs[idx].second, - Max31865Definitions::MAX_REPLY_SIZE, spi::RTD_MODE, spi::RTD_SPEED); - rtds[idx] = new Max31865PT1000Handler(rtdIds[idx], objects::SPI_MAIN_COM_IF, rtdCookies[idx]); + // Create special low level reader communication interface + new Max31865RtdReader(objects::SPI_RTD_COM_IF, comIF, gpioComIF); + for (uint8_t idx = 0; idx < NUM_RTDS; idx++) { + rtdCookies[idx] = new SpiCookie(cookieArgs[idx].first, cookieArgs[idx].second, + MAX31865::MAX_REPLY_SIZE, spi::RTD_MODE, spi::RTD_SPEED); + rtdCookies[idx]->setMutexParams(MutexIF::TimeoutType::WAITING, spi::RTD_CS_TIMEOUT); + Max31865ReaderCookie* rtdLowLevelCookie = + new Max31865ReaderCookie(rtdInfos[idx].first, idx, rtdInfos[idx].second, rtdCookies[idx]); + rtds[idx] = + new Max31865EiveHandler(rtdInfos[idx].first, objects::SPI_RTD_COM_IF, rtdLowLevelCookie); + rtds[idx]->setDeviceInfo(idx, rtdInfos[idx].second); rtds[idx]->setParent(objects::TCS_BOARD_ASS); - rtdFdir = new RtdFdir(rtdIds[idx]); + rtdFdir = new RtdFdir(rtdInfos[idx].first); rtds[idx]->setCustomFdir(rtdFdir); - rtds[idx]->setDeviceIdx(idx + 3); #if OBSW_DEBUG_RTD == 1 - rtds[idx]->setDebugMode(true); + rtds[idx]->setDebugMode(true, 5); +#endif +#if OBSW_TEST_RTD == 1 + rtds[idx]->setInstantNormal(true); + rtds[idx]->setStartUpImmediately(); #endif } -#if OBSW_TEST_RTD == 1 - for (auto& rtd : rtds) { - if (rtd != nullptr) { - rtd->setStartUpImmediately(); - rtd->setInstantNormal(true); - } - } -#endif // OBSW_TEST_RTD == 1 - TcsBoardHelper helper(rtdIds); + TcsBoardHelper helper(rtdInfos); TcsBoardAssembly* tcsBoardAss = new TcsBoardAssembly(objects::TCS_BOARD_ASS, objects::NO_OBJECT, pwrSwitcher, pcdu::Switches::PDU1_CH0_TCS_BOARD_3V3, helper); diff --git a/linux/ObjectFactory.h b/linux/ObjectFactory.h index 0ba78360..a5642729 100644 --- a/linux/ObjectFactory.h +++ b/linux/ObjectFactory.h @@ -12,7 +12,8 @@ namespace ObjectFactory { void createSunSensorComponents(GpioIF* gpioComIF, SpiComIF* spiComIF, PowerSwitchIF* pwrSwitcher, std::string spiDev); -void createRtdComponents(std::string spiDev, GpioIF* gpioComIF, PowerSwitchIF* pwrSwitcher); +void createRtdComponents(std::string spiDev, GpioIF* gpioComIF, PowerSwitchIF* pwrSwitcher, + SpiComIF* comIF); void gpioChecker(ReturnValue_t result, std::string output); diff --git a/linux/devices/CMakeLists.txt b/linux/devices/CMakeLists.txt index 45f44537..d654a513 100644 --- a/linux/devices/CMakeLists.txt +++ b/linux/devices/CMakeLists.txt @@ -2,5 +2,9 @@ if(EIVE_BUILD_GPSD_GPS_HANDLER) target_sources(${OBSW_NAME} PRIVATE GPSHyperionLinuxController.cpp) endif() +target_sources(${OBSW_NAME} PRIVATE + Max31865RtdLowlevelHandler.cpp +) + add_subdirectory(ploc) add_subdirectory(startracker) diff --git a/linux/devices/Max31865RtdLowlevelHandler.cpp b/linux/devices/Max31865RtdLowlevelHandler.cpp new file mode 100644 index 00000000..9b24f268 --- /dev/null +++ b/linux/devices/Max31865RtdLowlevelHandler.cpp @@ -0,0 +1,465 @@ +#include "Max31865RtdLowlevelHandler.h" + +#include +#include +#include + +#define OBSW_RTD_AUTO_MODE 1 + +#if OBSW_RTD_AUTO_MODE == 1 +static constexpr uint8_t BASE_CFG = (MAX31865::Bias::ON << MAX31865::CfgBitPos::BIAS_SEL) | + (MAX31865::Wires::FOUR_WIRE << MAX31865::CfgBitPos::WIRE_SEL) | + (MAX31865::ConvMode::AUTO << MAX31865::CfgBitPos::CONV_MODE); +#else +static constexpr uint8_t BASE_CFG = + (MAX31865::Bias::OFF << MAX31865::CfgBitPos::BIAS_SEL) | + (MAX31865::Wires::FOUR_WIRE << MAX31865::CfgBitPos::WIRE_SEL) | + (MAX31865::ConvMode::NORM_OFF << MAX31865::CfgBitPos::CONV_MODE); +#endif + +Max31865RtdReader::Max31865RtdReader(object_id_t objectId, SpiComIF* lowLevelComIF, GpioIF* gpioIF) + : SystemObject(objectId), rtds(EiveMax31855::NUM_RTDS), comIF(lowLevelComIF), gpioIF(gpioIF) { + readerMutex = MutexFactory::instance()->createMutex(); +} + +ReturnValue_t Max31865RtdReader::performOperation(uint8_t operationCode) { + using namespace MAX31865; + ReturnValue_t result = RETURN_OK; + static_cast(result); + // Stopwatch watch; + if (periodicInitHandling()) { +#if OBSW_RTD_AUTO_MODE == 0 + // 10 ms delay for VBIAS startup + TaskFactory::delayTask(10); +#endif + } else { + // No devices usable (e.g. TCS board off) + return RETURN_OK; + } + +#if OBSW_RTD_AUTO_MODE == 0 + result = periodicReadReqHandling(); + if (result != RETURN_OK) { + return result; + } + // After requesting, 65 milliseconds delay required + TaskFactory::delayTask(65); +#endif + + return periodicReadHandling(); +} + +bool Max31865RtdReader::rtdIsActive(uint8_t idx) { + if (rtds[idx]->on and rtds[idx]->active and rtds[idx]->configured) { + return true; + } + return false; +} + +bool Max31865RtdReader::periodicInitHandling() { + using namespace MAX31865; + MutexGuard mg(readerMutex); + ReturnValue_t result = RETURN_OK; + if (mg.getLockResult() != RETURN_OK) { + sif::warning << "Max31865RtdReader::periodicInitHandling: Mutex lock failed" << std::endl; + return false; + } + + for (auto& rtd : rtds) { + if (rtd == nullptr) { + continue; + } + if ((rtd->on or rtd->active) and not rtd->configured and rtd->cd.hasTimedOut()) { + ManualCsLockWrapper mg(csLock, gpioIF, rtd->spiCookie, csTimeoutType, csTimeoutMs); + if (mg.lockResult != RETURN_OK or mg.gpioResult != RETURN_OK) { + sif::error << "Max31865RtdReader::periodicInitHandling: Manual CS lock failed" << std::endl; + break; + } + result = writeCfgReg(rtd->spiCookie, BASE_CFG); + if (result != HasReturnvaluesIF::RETURN_OK) { + handleSpiError(rtd, result, "writeCfgReg"); + } + if (rtd->writeLowThreshold) { + result = writeLowThreshold(rtd->spiCookie, rtd->lowThreshold); + if (result != HasReturnvaluesIF::RETURN_OK) { + handleSpiError(rtd, result, "writeLowThreshold"); + } + } + if (rtd->writeHighThreshold) { + result = writeHighThreshold(rtd->spiCookie, rtd->highThreshold); + if (result != HasReturnvaluesIF::RETURN_OK) { + handleSpiError(rtd, result, "writeHighThreshold"); + } + } + result = clearFaultStatus(rtd->spiCookie); + if (result != HasReturnvaluesIF::RETURN_OK) { + handleSpiError(rtd, result, "clearFaultStatus"); + } + rtd->configured = true; + rtd->db.configured = true; + if (rtd->active) { + rtd->db.active = true; + } + } + if (rtd->active and rtd->configured and not rtd->db.active) { + rtd->db.active = true; + } + } + bool someRtdUsable = false; + for (auto& rtd : rtds) { + if (rtd == nullptr) { + continue; + } + if (rtdIsActive(rtd->idx)) { +#if OBSW_RTD_AUTO_MODE == 0 + someRtdUsable = true; + result = writeBiasSel(Bias::ON, rtd->spiCookie, BASE_CFG); +#endif + } + } + return someRtdUsable; +} + +ReturnValue_t Max31865RtdReader::periodicReadReqHandling() { + using namespace MAX31865; + MutexGuard mg(readerMutex); + if (mg.getLockResult() != RETURN_OK) { + sif::warning << "Max31865RtdReader::periodicReadReqHandling: Mutex lock failed" << std::endl; + return RETURN_FAILED; + } + // Now request one shot config for all active RTDs + for (auto& rtd : rtds) { + if (rtd == nullptr) { + continue; + } + if (rtdIsActive(rtd->idx)) { + ReturnValue_t result = writeCfgReg(rtd->spiCookie, BASE_CFG | (1 << CfgBitPos::ONE_SHOT)); + if (result != RETURN_OK) { + handleSpiError(rtd, result, "writeCfgReg"); + // Release mutex ASAP + return RETURN_FAILED; + } + } + } + return RETURN_OK; +} + +ReturnValue_t Max31865RtdReader::periodicReadHandling() { + using namespace MAX31865; + auto result = RETURN_OK; + MutexGuard mg(readerMutex); + if (mg.getLockResult() != RETURN_OK) { + sif::warning << "Max31865RtdReader::periodicReadReqHandling: Mutex lock failed" << std::endl; + return RETURN_FAILED; + } + // Now read the RTD values + for (auto& rtd : rtds) { + if (rtd == nullptr) { + continue; + } + if (rtdIsActive(rtd->idx)) { + uint16_t rtdVal = 0; + bool faultBitSet = false; + result = readRtdVal(rtd->spiCookie, rtdVal, faultBitSet); + if (result != RETURN_OK) { + handleSpiError(rtd, result, "readRtdVal"); + return RETURN_FAILED; + } + if (faultBitSet) { + rtd->db.faultBitSet = faultBitSet; + } + rtd->db.adcCode = rtdVal; + } + } +#if OBSW_RTD_AUTO_MODE == 0 + for (auto& rtd : rtds) { + if (rtd == nullptr) { + continue; + } + // Even if a device was made inactive, turn off the bias here. If it was turned off, not + // necessary anymore.. + if (rtd->on) { + result = writeBiasSel(Bias::OFF, rtd->spiCookie, BASE_CFG); + } + } +#endif + return RETURN_OK; +} + +ReturnValue_t Max31865RtdReader::initializeInterface(CookieIF* cookie) { + if (cookie == nullptr) { + throw std::invalid_argument("Invalid MAX31865 Reader Cookie"); + } + auto* rtdCookie = dynamic_cast(cookie); + ReturnValue_t result = comIF->initializeInterface(rtdCookie->spiCookie); + if (result != HasReturnvaluesIF::RETURN_OK) { + return result; + } + if (rtdCookie->idx > EiveMax31855::NUM_RTDS) { + throw std::invalid_argument("Invalid RTD index"); + } + rtds[rtdCookie->idx] = rtdCookie; + MutexGuard mg(readerMutex); + if (dbLen == 0) { + dbLen = rtdCookie->db.getSerializedSize(); + } + return RETURN_OK; +} + +ReturnValue_t Max31865RtdReader::sendMessage(CookieIF* cookie, const uint8_t* sendData, + size_t sendLen) { + if (cookie == nullptr) { + return RETURN_FAILED; + } + // Empty command.. don't fail for now + if (sendLen < 1) { + return RETURN_OK; + } + MutexGuard mg(readerMutex); + if (mg.getLockResult() != RETURN_OK) { + sif::warning << "Max31865RtdReader::sendMessage: Mutex lock failed" << std::endl; + return RETURN_FAILED; + } + auto* rtdCookie = dynamic_cast(cookie); + uint8_t cmdRaw = sendData[0]; + if (cmdRaw > EiveMax31855::RtdCommands::NUM_CMDS) { + sif::warning << "Max31865RtdReader::sendMessage: Invalid command" << std::endl; + return RETURN_FAILED; + } + + auto thresholdHandler = [](Max31865ReaderCookie* rtdCookie, const uint8_t* sendData) { + rtdCookie->lowThreshold = (sendData[1] << 8) | sendData[2]; + rtdCookie->highThreshold = (sendData[3] << 8) | sendData[4]; + rtdCookie->writeLowThreshold = true; + rtdCookie->writeHighThreshold = true; + }; + + auto cmd = static_cast(sendData[0]); + switch (cmd) { + case (EiveMax31855::RtdCommands::ON): { + if (not rtdCookie->on) { + rtdCookie->cd.setTimeout(MAX31865::WARMUP_MS); + rtdCookie->cd.resetTimer(); + rtdCookie->on = true; + rtdCookie->active = false; + rtdCookie->configured = false; + if (sendLen == 5) { + thresholdHandler(rtdCookie, sendData); + } + } + break; + } + case (EiveMax31855::RtdCommands::ACTIVE): { + if (not rtdCookie->on) { + rtdCookie->cd.setTimeout(MAX31865::WARMUP_MS); + rtdCookie->cd.resetTimer(); + rtdCookie->on = true; + rtdCookie->active = true; + rtdCookie->configured = false; + } else { + rtdCookie->active = true; + } + if (sendLen == 5) { + thresholdHandler(rtdCookie, sendData); + } + break; + } + case (EiveMax31855::RtdCommands::OFF): { + rtdCookie->on = false; + rtdCookie->active = false; + rtdCookie->configured = false; + break; + } + case (EiveMax31855::RtdCommands::HIGH_TRESHOLD): { + if (sendLen == 3) { + rtdCookie->highThreshold = (sendData[1] << 8) | sendData[2]; + rtdCookie->writeHighThreshold = true; + } else { + return RETURN_FAILED; + } + break; + } + case (EiveMax31855::RtdCommands::LOW_THRESHOLD): { + if (sendLen == 3) { + rtdCookie->lowThreshold = (sendData[1] << 8) | sendData[2]; + rtdCookie->writeLowThreshold = true; + } else { + return RETURN_FAILED; + } + break; + } + case (EiveMax31855::RtdCommands::CFG): + default: { + // TODO: Only implement if needed + break; + } + } + return RETURN_OK; +} + +ReturnValue_t Max31865RtdReader::getSendSuccess(CookieIF* cookie) { return RETURN_OK; } + +ReturnValue_t Max31865RtdReader::requestReceiveMessage(CookieIF* cookie, size_t requestLen) { + return RETURN_OK; +} + +ReturnValue_t Max31865RtdReader::readReceivedMessage(CookieIF* cookie, uint8_t** buffer, + size_t* size) { + MutexGuard mg(readerMutex); + if (mg.getLockResult() != RETURN_OK) { + // TODO: Emit warning + return RETURN_FAILED; + } + auto* rtdCookie = dynamic_cast(cookie); + uint8_t* exchangePtr = rtdCookie->exchangeBuf.data(); + size_t serLen = 0; + auto result = rtdCookie->db.serialize(&exchangePtr, &serLen, rtdCookie->exchangeBuf.size(), + SerializeIF::Endianness::MACHINE); + if (result != RETURN_OK) { + // TODO: Emit warning + return RETURN_FAILED; + } + *buffer = reinterpret_cast(rtdCookie->exchangeBuf.data()); + *size = serLen; + return RETURN_OK; +} + +ReturnValue_t Max31865RtdReader::writeCfgReg(SpiCookie* cookie, uint8_t cfg) { + using namespace MAX31865; + return writeNToReg(cookie, CONFIG, 1, &cfg, nullptr); +} + +ReturnValue_t Max31865RtdReader::writeBiasSel(MAX31865::Bias bias, SpiCookie* cookie, + uint8_t baseCfg) { + using namespace MAX31865; + if (bias == MAX31865::Bias::OFF) { + baseCfg &= ~(1 << CfgBitPos::BIAS_SEL); + } else { + baseCfg |= (1 << CfgBitPos::BIAS_SEL); + } + return writeCfgReg(cookie, baseCfg); +} + +ReturnValue_t Max31865RtdReader::clearFaultStatus(SpiCookie* cookie) { + using namespace MAX31865; + // Read back the current configuration to avoid overwriting it when clearing te fault status + uint8_t currentCfg = 0; + auto result = readCfgReg(cookie, currentCfg); + if (result != RETURN_OK) { + return result; + } + // Clear bytes 5, 3 and 2 which need to be 0 + currentCfg &= ~0x2C; + currentCfg |= (1 << CfgBitPos::FAULT_STATUS_CLEAR); + return writeCfgReg(cookie, currentCfg); +} + +ReturnValue_t Max31865RtdReader::readCfgReg(SpiCookie* cookie, uint8_t& cfg) { + using namespace MAX31865; + uint8_t* replyPtr = nullptr; + auto result = readNFromReg(cookie, CONFIG, 1, &replyPtr); + if (result == RETURN_OK) { + cfg = replyPtr[0]; + } + return result; +} + +ReturnValue_t Max31865RtdReader::writeLowThreshold(SpiCookie* cookie, uint16_t val) { + using namespace MAX31865; + uint8_t cmd[2] = {static_cast((val >> 8) & 0xff), static_cast(val & 0xff)}; + return writeNToReg(cookie, LOW_THRESHOLD, 2, cmd, nullptr); +} + +ReturnValue_t Max31865RtdReader::writeHighThreshold(SpiCookie* cookie, uint16_t val) { + using namespace MAX31865; + uint8_t cmd[2] = {static_cast((val >> 8) & 0xff), static_cast(val & 0xff)}; + return writeNToReg(cookie, HIGH_THRESHOLD, 2, cmd, nullptr); +} + +ReturnValue_t Max31865RtdReader::readLowThreshold(SpiCookie* cookie, uint16_t& lowThreshold) { + using namespace MAX31865; + uint8_t* replyPtr = nullptr; + auto result = readNFromReg(cookie, LOW_THRESHOLD, 2, &replyPtr); + if (result == RETURN_OK) { + lowThreshold = (replyPtr[0] << 8) | replyPtr[1]; + } + return result; +} + +ReturnValue_t Max31865RtdReader::readHighThreshold(SpiCookie* cookie, uint16_t& highThreshold) { + using namespace MAX31865; + uint8_t* replyPtr = nullptr; + auto result = readNFromReg(cookie, HIGH_THRESHOLD, 2, &replyPtr); + if (result == RETURN_OK) { + highThreshold = (replyPtr[0] << 8) | replyPtr[1]; + } + return result; +} + +ReturnValue_t Max31865RtdReader::writeNToReg(SpiCookie* cookie, uint8_t reg, size_t n, uint8_t* cmd, + uint8_t** reply) { + using namespace MAX31865; + if (n > cmdBuf.size() - 1) { + return HasReturnvaluesIF::RETURN_FAILED; + } + cmdBuf[0] = reg | WRITE_BIT; + for (size_t idx = 0; idx < n; idx++) { + cmdBuf[idx + 1] = cmd[idx]; + } + return comIF->sendMessage(cookie, cmdBuf.data(), n + 1); +} + +ReturnValue_t Max31865RtdReader::readRtdVal(SpiCookie* cookie, uint16_t& val, bool& faultBitSet) { + using namespace MAX31865; + uint8_t* replyPtr = nullptr; + auto result = readNFromReg(cookie, RTD, 2, &replyPtr); + if (result != RETURN_OK) { + return result; + } + if (replyPtr[1] & 0b0000'0001) { + faultBitSet = true; + } + // Shift 1 to the right to remove fault bit + val = ((replyPtr[0] << 8) | replyPtr[1]) >> 1; + return result; +} + +ReturnValue_t Max31865RtdReader::readNFromReg(SpiCookie* cookie, uint8_t reg, size_t n, + uint8_t** reply) { + using namespace MAX31865; + if (n > 4) { + return HasReturnvaluesIF::RETURN_FAILED; + } + // Clear write bit in any case + reg &= ~WRITE_BIT; + cmdBuf[0] = reg; + std::memset(cmdBuf.data() + 1, 0, n); + ReturnValue_t result = comIF->sendMessage(cookie, cmdBuf.data(), n + 1); + if (result != RETURN_OK) { + return RETURN_FAILED; + } + + size_t dummyLen = 0; + uint8_t* replyPtr = nullptr; + result = comIF->readReceivedMessage(cookie, &replyPtr, &dummyLen); + if (result != RETURN_OK) { + return result; + } + if (reply != nullptr) { + *reply = replyPtr + 1; + } + return RETURN_OK; +} + +ReturnValue_t Max31865RtdReader::handleSpiError(Max31865ReaderCookie* cookie, ReturnValue_t result, + const char* ctx) { + cookie->db.spiErrorCount.value += 1; + sif::warning << "Max31865RtdReader::handleSpiError: " << ctx << " | Failed with result " << result + << std::endl; + return result; +} + +ReturnValue_t Max31865RtdReader::initialize() { + csLock = comIF->getCsMutex(); + return SystemObject::initialize(); +} diff --git a/linux/devices/Max31865RtdLowlevelHandler.h b/linux/devices/Max31865RtdLowlevelHandler.h new file mode 100644 index 00000000..d3845bd5 --- /dev/null +++ b/linux/devices/Max31865RtdLowlevelHandler.h @@ -0,0 +1,87 @@ +#ifndef LINUX_DEVICES_MAX31865RTDREADER_H_ +#define LINUX_DEVICES_MAX31865RTDREADER_H_ + +#include +#include +#include +#include + +#include "fsfw/devicehandlers/DeviceCommunicationIF.h" +#include "mission/devices/devicedefinitions/Max31865Definitions.h" + +struct Max31865ReaderCookie : public CookieIF { + Max31865ReaderCookie(){}; + Max31865ReaderCookie(object_id_t handlerId_, uint8_t idx_, const std::string& locString_, + SpiCookie* spiCookie_) + : idx(idx_), handlerId(handlerId_), locString(locString_), spiCookie(spiCookie_) {} + + uint8_t idx = 0; + object_id_t handlerId = objects::NO_OBJECT; + + std::string locString = ""; + std::array exchangeBuf{}; + Countdown cd = Countdown(MAX31865::WARMUP_MS); + + bool on = false; + bool configured = false; + bool active = false; + bool writeLowThreshold = false; + bool writeHighThreshold = false; + uint16_t lowThreshold = 0; + uint16_t highThreshold = 0; + SpiCookie* spiCookie = nullptr; + + // Exchange data buffer struct + EiveMax31855::ReadOutStruct db; +}; + +class Max31865RtdReader : public SystemObject, + public ExecutableObjectIF, + public DeviceCommunicationIF { + public: + Max31865RtdReader(object_id_t objectId, SpiComIF* lowLevelComIF, GpioIF* gpioIF); + + ReturnValue_t performOperation(uint8_t operationCode) override; + ReturnValue_t initialize() override; + + private: + std::vector rtds; + std::array cmdBuf = {}; + size_t dbLen = 0; + MutexIF* readerMutex; + + SpiComIF* comIF; + GpioIF* gpioIF; + MutexIF::TimeoutType csTimeoutType = MutexIF::TimeoutType::BLOCKING; + uint32_t csTimeoutMs = 0; + MutexIF* csLock = nullptr; + + bool periodicInitHandling(); + ReturnValue_t periodicReadReqHandling(); + ReturnValue_t periodicReadHandling(); + + bool rtdIsActive(uint8_t idx); + ReturnValue_t writeCfgReg(SpiCookie* cookie, uint8_t cfg); + ReturnValue_t writeBiasSel(MAX31865::Bias bias, SpiCookie* cookie, uint8_t baseCfg); + ReturnValue_t readCfgReg(SpiCookie* cookie, uint8_t& cfg); + ReturnValue_t readRtdVal(SpiCookie* cookie, uint16_t& val, bool& faultBitSet); + ReturnValue_t writeLowThreshold(SpiCookie* cookie, uint16_t val); + ReturnValue_t writeHighThreshold(SpiCookie* cookie, uint16_t val); + ReturnValue_t readLowThreshold(SpiCookie* cookie, uint16_t& val); + ReturnValue_t readHighThreshold(SpiCookie* cookie, uint16_t& val); + ReturnValue_t clearFaultStatus(SpiCookie* cookie); + + ReturnValue_t readNFromReg(SpiCookie* cookie, uint8_t reg, size_t n, uint8_t** reply); + ReturnValue_t writeNToReg(SpiCookie* cookie, uint8_t reg, size_t n, uint8_t* cmd, + uint8_t** reply); + + ReturnValue_t initializeInterface(CookieIF* cookie) override; + ReturnValue_t sendMessage(CookieIF* cookie, const uint8_t* sendData, size_t sendLen) override; + ReturnValue_t getSendSuccess(CookieIF* cookie) override; + ReturnValue_t requestReceiveMessage(CookieIF* cookie, size_t requestLen) override; + ReturnValue_t readReceivedMessage(CookieIF* cookie, uint8_t** buffer, size_t* size) override; + + ReturnValue_t handleSpiError(Max31865ReaderCookie* cookie, ReturnValue_t result, const char* ctx); +}; + +#endif /* LINUX_DEVICES_MAX31865RTDREADER_H_ */ diff --git a/linux/fsfwconfig/objects/systemObjectList.h b/linux/fsfwconfig/objects/systemObjectList.h index 57c63863..28c87d3c 100644 --- a/linux/fsfwconfig/objects/systemObjectList.h +++ b/linux/fsfwconfig/objects/systemObjectList.h @@ -50,6 +50,7 @@ enum sourceObjects : uint32_t { SPI_MAIN_COM_IF = 0x49020004, GPIO_IF = 0x49010005, SPI_RW_COM_IF = 0x49020005, + SPI_RTD_COM_IF = 0x49020006, /* 0x54 ('T') for test handlers */ TEST_TASK = 0x54694269, diff --git a/linux/fsfwconfig/pollingsequence/pollingSequenceFactory.cpp b/linux/fsfwconfig/pollingsequence/pollingSequenceFactory.cpp index 05de8cf3..87bd9c51 100644 --- a/linux/fsfwconfig/pollingsequence/pollingSequenceFactory.cpp +++ b/linux/fsfwconfig/pollingsequence/pollingSequenceFactory.cpp @@ -5,6 +5,8 @@ #include #include +#include "mission/devices/devicedefinitions/Max31865Definitions.h" + #ifndef RPI_TEST_ADIS16507 #define RPI_TEST_ADIS16507 0 #endif @@ -64,157 +66,34 @@ ReturnValue_t pst::pstSpi(FixedTimeslotTaskIF *thisSequence) { static_cast(length); #if OBSW_ADD_PL_PCDU == 1 thisSequence->addSlot(objects::PLPCDU_HANDLER, length * 0, DeviceHandlerIF::PERFORM_OPERATION); - thisSequence->addSlot(objects::PLPCDU_HANDLER, length * 0.2, DeviceHandlerIF::SEND_WRITE); - thisSequence->addSlot(objects::PLPCDU_HANDLER, length * 0.4, DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::PLPCDU_HANDLER, length * 0.6, DeviceHandlerIF::SEND_READ); - thisSequence->addSlot(objects::PLPCDU_HANDLER, length * 0.8, DeviceHandlerIF::GET_READ); + thisSequence->addSlot(objects::PLPCDU_HANDLER, length * 0, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::PLPCDU_HANDLER, length * 0, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::PLPCDU_HANDLER, length * 0, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::PLPCDU_HANDLER, length * 0, DeviceHandlerIF::GET_READ); #endif #if OBSW_ADD_TMP_DEVICES == 1 thisSequence->addSlot(objects::TMP1075_HANDLER_1, length * 0, DeviceHandlerIF::PERFORM_OPERATION); thisSequence->addSlot(objects::TMP1075_HANDLER_2, length * 0, DeviceHandlerIF::PERFORM_OPERATION); #endif -#if OBSW_ADD_RTD_DEVICES == 1 - thisSequence->addSlot(objects::RTD_0_IC3_PLOC_HEATSPREADER, length * 0, - DeviceHandlerIF::PERFORM_OPERATION); - thisSequence->addSlot(objects::RTD_1_IC4_PLOC_MISSIONBOARD, length * 0, - DeviceHandlerIF::PERFORM_OPERATION); - thisSequence->addSlot(objects::RTD_2_IC5_4K_CAMERA, length * 0, - DeviceHandlerIF::PERFORM_OPERATION); - thisSequence->addSlot(objects::RTD_3_IC6_DAC_HEATSPREADER, length * 0, - DeviceHandlerIF::PERFORM_OPERATION); - thisSequence->addSlot(objects::RTD_4_IC7_STARTRACKER, length * 0, - DeviceHandlerIF::PERFORM_OPERATION); - thisSequence->addSlot(objects::RTD_5_IC8_RW1_MX_MY, length * 0, - DeviceHandlerIF::PERFORM_OPERATION); - thisSequence->addSlot(objects::RTD_6_IC9_DRO, length * 0, DeviceHandlerIF::PERFORM_OPERATION); - thisSequence->addSlot(objects::RTD_7_IC10_SCEX, length * 0, DeviceHandlerIF::PERFORM_OPERATION); - thisSequence->addSlot(objects::RTD_8_IC11_X8, length * 0, DeviceHandlerIF::PERFORM_OPERATION); - thisSequence->addSlot(objects::RTD_9_IC12_HPA, length * 0, DeviceHandlerIF::PERFORM_OPERATION); - thisSequence->addSlot(objects::RTD_10_IC13_PL_TX, length * 0, DeviceHandlerIF::PERFORM_OPERATION); - thisSequence->addSlot(objects::RTD_11_IC14_MPA, length * 0, DeviceHandlerIF::PERFORM_OPERATION); - thisSequence->addSlot(objects::RTD_12_IC15_ACU, length * 0, DeviceHandlerIF::PERFORM_OPERATION); - thisSequence->addSlot(objects::RTD_13_IC16_PLPCDU_HEATSPREADER, length * 0, - DeviceHandlerIF::PERFORM_OPERATION); - thisSequence->addSlot(objects::RTD_14_IC17_TCS_BOARD, length * 0, - DeviceHandlerIF::PERFORM_OPERATION); - thisSequence->addSlot(objects::RTD_15_IC18_IMTQ, length * 0, DeviceHandlerIF::PERFORM_OPERATION); -#endif /* OBSW_ADD_RTD_DEVICES */ #if OBSW_ADD_TMP_DEVICES == 1 thisSequence->addSlot(objects::TMP1075_HANDLER_1, length * 0.2, DeviceHandlerIF::SEND_WRITE); thisSequence->addSlot(objects::TMP1075_HANDLER_2, length * 0.2, DeviceHandlerIF::SEND_WRITE); #endif -#if OBSW_ADD_RTD_DEVICES == 1 - thisSequence->addSlot(objects::RTD_0_IC3_PLOC_HEATSPREADER, length * 0.2, - DeviceHandlerIF::SEND_WRITE); - thisSequence->addSlot(objects::RTD_1_IC4_PLOC_MISSIONBOARD, length * 0.2, - DeviceHandlerIF::SEND_WRITE); - thisSequence->addSlot(objects::RTD_2_IC5_4K_CAMERA, length * 0.2, DeviceHandlerIF::SEND_WRITE); - thisSequence->addSlot(objects::RTD_3_IC6_DAC_HEATSPREADER, length * 0.2, - DeviceHandlerIF::SEND_WRITE); - thisSequence->addSlot(objects::RTD_4_IC7_STARTRACKER, length * 0.2, DeviceHandlerIF::SEND_WRITE); - thisSequence->addSlot(objects::RTD_5_IC8_RW1_MX_MY, length * 0.2, DeviceHandlerIF::SEND_WRITE); - thisSequence->addSlot(objects::RTD_6_IC9_DRO, length * 0.2, DeviceHandlerIF::SEND_WRITE); - thisSequence->addSlot(objects::RTD_7_IC10_SCEX, length * 0.2, DeviceHandlerIF::SEND_WRITE); - thisSequence->addSlot(objects::RTD_8_IC11_X8, length * 0.2, DeviceHandlerIF::SEND_WRITE); - thisSequence->addSlot(objects::RTD_9_IC12_HPA, length * 0.2, DeviceHandlerIF::SEND_WRITE); - thisSequence->addSlot(objects::RTD_10_IC13_PL_TX, length * 0.2, DeviceHandlerIF::SEND_WRITE); - thisSequence->addSlot(objects::RTD_11_IC14_MPA, length * 0.2, DeviceHandlerIF::SEND_WRITE); - thisSequence->addSlot(objects::RTD_12_IC15_ACU, length * 0.2, DeviceHandlerIF::SEND_WRITE); - thisSequence->addSlot(objects::RTD_13_IC16_PLPCDU_HEATSPREADER, length * 0.2, - DeviceHandlerIF::SEND_WRITE); - thisSequence->addSlot(objects::RTD_14_IC17_TCS_BOARD, length * 0.2, DeviceHandlerIF::SEND_WRITE); - thisSequence->addSlot(objects::RTD_15_IC18_IMTQ, length * 0.2, DeviceHandlerIF::SEND_WRITE); -#endif /* OBSW_ADD_RTD_DEVICES */ #if OBSW_ADD_TMP_DEVICES == 1 - thisSequence->addSlot(objects::TMP1075_HANDLER_1, length * 0.4, DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::TMP1075_HANDLER_2, length * 0.4, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::TMP1075_HANDLER_1, length * 0.2, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::TMP1075_HANDLER_2, length * 0.2, DeviceHandlerIF::GET_WRITE); #endif -#if OBSW_ADD_RTD_DEVICES == 1 - thisSequence->addSlot(objects::RTD_0_IC3_PLOC_HEATSPREADER, length * 0.4, - DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::RTD_1_IC4_PLOC_MISSIONBOARD, length * 0.4, - DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::RTD_2_IC5_4K_CAMERA, length * 0.4, DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::RTD_3_IC6_DAC_HEATSPREADER, length * 0.4, - DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::RTD_4_IC7_STARTRACKER, length * 0.4, DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::RTD_5_IC8_RW1_MX_MY, length * 0.4, DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::RTD_6_IC9_DRO, length * 0.4, DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::RTD_7_IC10_SCEX, length * 0.4, DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::RTD_8_IC11_X8, length * 0.4, DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::RTD_9_IC12_HPA, length * 0.4, DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::RTD_10_IC13_PL_TX, length * 0.4, DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::RTD_11_IC14_MPA, length * 0.4, DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::RTD_12_IC15_ACU, length * 0.4, DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::RTD_13_IC16_PLPCDU_HEATSPREADER, length * 0.4, - DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::RTD_14_IC17_TCS_BOARD, length * 0.4, DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::RTD_15_IC18_IMTQ, length * 0.4, DeviceHandlerIF::GET_WRITE); -#endif /* OBSW_ADD_RTD_DEVICES */ #if OBSW_ADD_TMP_DEVICES == 1 - thisSequence->addSlot(objects::TMP1075_HANDLER_1, length * 0.6, DeviceHandlerIF::SEND_READ); - thisSequence->addSlot(objects::TMP1075_HANDLER_2, length * 0.6, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::TMP1075_HANDLER_1, length * 0.2, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::TMP1075_HANDLER_2, length * 0.2, DeviceHandlerIF::SEND_READ); #endif -#if OBSW_ADD_RTD_DEVICES == 1 - thisSequence->addSlot(objects::RTD_0_IC3_PLOC_HEATSPREADER, length * 0.6, - DeviceHandlerIF::SEND_READ); - thisSequence->addSlot(objects::RTD_1_IC4_PLOC_MISSIONBOARD, length * 0.6, - DeviceHandlerIF::SEND_READ); - thisSequence->addSlot(objects::RTD_2_IC5_4K_CAMERA, length * 0.6, DeviceHandlerIF::SEND_READ); - thisSequence->addSlot(objects::RTD_3_IC6_DAC_HEATSPREADER, length * 0.6, - DeviceHandlerIF::SEND_READ); - thisSequence->addSlot(objects::RTD_4_IC7_STARTRACKER, length * 0.6, DeviceHandlerIF::SEND_READ); - thisSequence->addSlot(objects::RTD_5_IC8_RW1_MX_MY, length * 0.6, DeviceHandlerIF::SEND_READ); - thisSequence->addSlot(objects::RTD_6_IC9_DRO, length * 0.6, DeviceHandlerIF::SEND_READ); - thisSequence->addSlot(objects::RTD_7_IC10_SCEX, length * 0.6, DeviceHandlerIF::SEND_READ); - thisSequence->addSlot(objects::RTD_8_IC11_X8, length * 0.6, DeviceHandlerIF::SEND_READ); - thisSequence->addSlot(objects::RTD_9_IC12_HPA, length * 0.6, DeviceHandlerIF::SEND_READ); - thisSequence->addSlot(objects::RTD_10_IC13_PL_TX, length * 0.6, DeviceHandlerIF::SEND_READ); - thisSequence->addSlot(objects::RTD_11_IC14_MPA, length * 0.6, DeviceHandlerIF::SEND_READ); - thisSequence->addSlot(objects::RTD_12_IC15_ACU, length * 0.6, DeviceHandlerIF::SEND_READ); - thisSequence->addSlot(objects::RTD_13_IC16_PLPCDU_HEATSPREADER, length * 0.6, - DeviceHandlerIF::SEND_READ); - thisSequence->addSlot(objects::RTD_14_IC17_TCS_BOARD, length * 0.6, DeviceHandlerIF::SEND_READ); - thisSequence->addSlot(objects::RTD_15_IC18_IMTQ, length * 0.6, DeviceHandlerIF::SEND_READ); -#endif /* OBSW_ADD_RTD_DEVICES */ #if OBSW_ADD_TMP_DEVICES == 1 - thisSequence->addSlot(objects::TMP1075_HANDLER_1, length * 0.8, DeviceHandlerIF::GET_READ); - thisSequence->addSlot(objects::TMP1075_HANDLER_2, length * 0.8, DeviceHandlerIF::GET_READ); -#endif -#if OBSW_ADD_RTD_DEVICES == 1 - thisSequence->addSlot(objects::RTD_0_IC3_PLOC_HEATSPREADER, length * 0.8, - DeviceHandlerIF::GET_READ); - thisSequence->addSlot(objects::RTD_1_IC4_PLOC_MISSIONBOARD, length * 0.8, - DeviceHandlerIF::GET_READ); - thisSequence->addSlot(objects::RTD_2_IC5_4K_CAMERA, length * 0.8, DeviceHandlerIF::GET_READ); - thisSequence->addSlot(objects::RTD_3_IC6_DAC_HEATSPREADER, length * 0.8, - DeviceHandlerIF::GET_READ); - thisSequence->addSlot(objects::RTD_4_IC7_STARTRACKER, length * 0.8, DeviceHandlerIF::GET_READ); - thisSequence->addSlot(objects::RTD_5_IC8_RW1_MX_MY, length * 0.8, DeviceHandlerIF::GET_READ); - thisSequence->addSlot(objects::RTD_6_IC9_DRO, length * 0.8, DeviceHandlerIF::GET_READ); - thisSequence->addSlot(objects::RTD_7_IC10_SCEX, length * 0.8, DeviceHandlerIF::GET_READ); - thisSequence->addSlot(objects::RTD_8_IC11_X8, length * 0.8, DeviceHandlerIF::GET_READ); - thisSequence->addSlot(objects::RTD_9_IC12_HPA, length * 0.8, DeviceHandlerIF::GET_READ); - thisSequence->addSlot(objects::RTD_10_IC13_PL_TX, length * 0.8, DeviceHandlerIF::GET_READ); - thisSequence->addSlot(objects::RTD_11_IC14_MPA, length * 0.8, DeviceHandlerIF::GET_READ); - thisSequence->addSlot(objects::RTD_12_IC15_ACU, length * 0.8, DeviceHandlerIF::GET_READ); - thisSequence->addSlot(objects::RTD_13_IC16_PLPCDU_HEATSPREADER, length * 0.8, - DeviceHandlerIF::GET_READ); - thisSequence->addSlot(objects::RTD_14_IC17_TCS_BOARD, length * 0.8, DeviceHandlerIF::GET_READ); - thisSequence->addSlot(objects::RTD_15_IC18_IMTQ, length * 0.8, DeviceHandlerIF::GET_READ); -#endif /* OBSW_ADD_RTD_DEVICES */ - -#if OBSW_ADD_RAD_SENSORS == 1 - /* Radiation sensor */ - thisSequence->addSlot(objects::RAD_SENSOR, length * 0, DeviceHandlerIF::PERFORM_OPERATION); - thisSequence->addSlot(objects::RAD_SENSOR, length * 0.2, DeviceHandlerIF::SEND_WRITE); - thisSequence->addSlot(objects::RAD_SENSOR, length * 0.4, DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::RAD_SENSOR, length * 0.6, DeviceHandlerIF::SEND_READ); - thisSequence->addSlot(objects::RAD_SENSOR, length * 0.8, DeviceHandlerIF::GET_READ); + thisSequence->addSlot(objects::TMP1075_HANDLER_1, length * 0.2, DeviceHandlerIF::GET_READ); + thisSequence->addSlot(objects::TMP1075_HANDLER_2, length * 0.2, DeviceHandlerIF::GET_READ); #endif #if OBSW_ADD_SUN_SENSORS == 1 @@ -482,6 +361,15 @@ ReturnValue_t pst::pstSpi(FixedTimeslotTaskIF *thisSequence) { } #endif /* OBSW_ADD_SUN_SENSORS == 1 */ +#if OBSW_ADD_RAD_SENSORS == 1 + /* Radiation sensor */ + thisSequence->addSlot(objects::RAD_SENSOR, length * 0, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::RAD_SENSOR, length * 0.2, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::RAD_SENSOR, length * 0.4, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::RAD_SENSOR, length * 0.6, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::RAD_SENSOR, length * 0.8, DeviceHandlerIF::GET_READ); +#endif + #if OBSW_ADD_ACS_BOARD == 1 && OBSW_ADD_ACS_HANDLERS == 1 bool enableAside = true; bool enableBside = true; diff --git a/mission/devices/CMakeLists.txt b/mission/devices/CMakeLists.txt index b19efbc6..1a9b2efd 100644 --- a/mission/devices/CMakeLists.txt +++ b/mission/devices/CMakeLists.txt @@ -10,6 +10,7 @@ target_sources( ACUHandler.cpp SyrlinksHkHandler.cpp Max31865PT1000Handler.cpp + Max31865EiveHandler.cpp IMTQHandler.cpp HeaterHandler.cpp RadiationSensorHandler.cpp diff --git a/mission/devices/GyroADIS1650XHandler.cpp b/mission/devices/GyroADIS1650XHandler.cpp index b94c96bf..77862bfb 100644 --- a/mission/devices/GyroADIS1650XHandler.cpp +++ b/mission/devices/GyroADIS1650XHandler.cpp @@ -424,8 +424,8 @@ ReturnValue_t GyroADIS1650XHandler::spiSendCallback(SpiComIF *comIf, SpiCookie * GpioIF *gpioIF = comIf->getGpioInterface(); MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING; uint32_t timeoutMs = 0; - cookie->getMutexParams(timeoutType, timeoutMs); MutexIF *mutex = comIf->getCsMutex(); + cookie->getMutexParams(timeoutType, timeoutMs); if (mutex == nullptr or gpioIF == nullptr) { #if OBSW_VERBOSE_LEVEL >= 1 sif::warning << "GyroADIS16507Handler::spiSendCallback: " diff --git a/mission/devices/Max31865EiveHandler.cpp b/mission/devices/Max31865EiveHandler.cpp new file mode 100644 index 00000000..adcf9a0a --- /dev/null +++ b/mission/devices/Max31865EiveHandler.cpp @@ -0,0 +1,180 @@ +#include "Max31865EiveHandler.h" + +Max31865EiveHandler::Max31865EiveHandler(object_id_t objectId, object_id_t comIF, + CookieIF* comCookie) + : DeviceHandlerBase(objectId, comIF, comCookie, nullptr), + sensorDataset(this, EiveMax31855::RtdCommands::EXCHANGE_SET_ID), + debugDivider(5) { + structLen = exchangeStruct.getSerializedSize(); +} + +void Max31865EiveHandler::doStartUp() { + updatePeriodicReply(true, EiveMax31855::RtdCommands::EXCHANGE_SET_ID); + if (state == InternalState::NONE or state == InternalState::INACTIVE) { + if (instantNormal) { + state = InternalState::ACTIVE; + } else { + state = InternalState::ON; + } + transitionOk = false; + } + if ((state == InternalState::ON or state == InternalState::ACTIVE) and transitionOk) { + if (instantNormal) { + setMode(MODE_NORMAL); + } else { + setMode(MODE_ON); + } + } +} + +void Max31865EiveHandler::doShutDown() { + updatePeriodicReply(false, EiveMax31855::RtdCommands::EXCHANGE_SET_ID); + if (state == InternalState::NONE or state == InternalState::ACTIVE or + state == InternalState::ON) { + state = InternalState::INACTIVE; + transitionOk = false; + } else { + transitionOk = true; + } + if (state == InternalState::INACTIVE and transitionOk) { + setMode(_MODE_POWER_DOWN); + } +} + +ReturnValue_t Max31865EiveHandler::buildNormalDeviceCommand(DeviceCommandId_t* id) { + //*id = EiveMax31855::RtdCommands::EXCHANGE_SET_ID; + return NOTHING_TO_SEND; +} + +ReturnValue_t Max31865EiveHandler::buildTransitionDeviceCommand(DeviceCommandId_t* id) { + ReturnValue_t result = NOTHING_TO_SEND; + if (state == InternalState::ON) { + *id = EiveMax31855::RtdCommands::ON; + result = buildCommandFromCommand(*id, nullptr, 0); + } + if (state == InternalState::ACTIVE) { + *id = EiveMax31855::RtdCommands::ACTIVE; + result = buildCommandFromCommand(*id, nullptr, 0); + } + if (state == InternalState::INACTIVE) { + *id = EiveMax31855::RtdCommands::OFF; + result = buildCommandFromCommand(*id, nullptr, 0); + } + return result; +} + +ReturnValue_t Max31865EiveHandler::buildCommandFromCommand(DeviceCommandId_t deviceCommand, + const uint8_t* commandData, + size_t commandDataLen) { + auto cmdTyped = static_cast(deviceCommand); + switch (cmdTyped) { + case (EiveMax31855::RtdCommands::ON): + case (EiveMax31855::RtdCommands::ACTIVE): + case (EiveMax31855::RtdCommands::OFF): { + simpleCommand(cmdTyped); + break; + } + case (EiveMax31855::RtdCommands::LOW_THRESHOLD): + case (EiveMax31855::RtdCommands::HIGH_TRESHOLD): { + break; + } + case (EiveMax31855::RtdCommands::CFG): { + break; + } + default: + return NOTHING_TO_SEND; + } + return RETURN_OK; +} + +void Max31865EiveHandler::setInstantNormal(bool instantNormal) { + this->instantNormal = instantNormal; +} + +void Max31865EiveHandler::setDebugMode(bool enable, uint32_t divider) { + this->debugMode = enable; + debugDivider.setDivider(divider); +} + +void Max31865EiveHandler::simpleCommand(EiveMax31855::RtdCommands cmd) { + cmdBuf[0] = static_cast(cmd); + rawPacket = cmdBuf.data(); + rawPacketLen = 1; +} +void Max31865EiveHandler::doTransition(Mode_t modeFrom, Submode_t subModeFrom) { + if (mode == _MODE_TO_NORMAL) { + if (state != InternalState::ACTIVE) { + state = InternalState::ACTIVE; + transitionOk = false; + } else if (transitionOk) { + setMode(MODE_NORMAL); + } + } else { + DeviceHandlerBase::doTransition(modeFrom, subModeFrom); + } +} + +void Max31865EiveHandler::fillCommandAndReplyMap() { + insertInCommandMap(EiveMax31855::RtdCommands::ON); + insertInCommandMap(EiveMax31855::RtdCommands::ACTIVE); + insertInCommandMap(EiveMax31855::RtdCommands::OFF); + insertInReplyMap(EiveMax31855::RtdCommands::EXCHANGE_SET_ID, 200, &sensorDataset, 0, true); +} + +ReturnValue_t Max31865EiveHandler::scanForReply(const uint8_t* start, size_t remainingSize, + DeviceCommandId_t* foundId, size_t* foundLen) { + if (remainingSize != structLen) { + sif::error << "Invalid reply from RTD reader detected, reply size " << remainingSize + << " not equal to exchange struct size " << structLen << std::endl; + return DeviceHandlerIF::INVALID_DATA; + } + *foundId = EiveMax31855::RtdCommands::EXCHANGE_SET_ID; + *foundLen = remainingSize; + return RETURN_OK; +} + +ReturnValue_t Max31865EiveHandler::interpretDeviceReply(DeviceCommandId_t id, + const uint8_t* packet) { + size_t deserTmp = structLen; + auto result = exchangeStruct.deSerialize(&packet, &deserTmp, SerializeIF::Endianness::MACHINE); + if (result != RETURN_OK) { + return result; + } + if (mode == _MODE_TO_NORMAL and exchangeStruct.active and state == InternalState::ACTIVE) { + transitionOk = true; + } + if (mode == _MODE_START_UP and exchangeStruct.configured and state == InternalState::ON) { + transitionOk = true; + } + // Calculate resistance + float rtdValue = exchangeStruct.adcCode * EiveMax31855::RTD_RREF_PT1000 / INT16_MAX; + // calculate approximation + float approxTemp = exchangeStruct.adcCode / 32.0 - 256.0; + + if (debugMode) { + if (debugDivider.checkAndIncrement()) { + sif::info << "Max31865: " << std::setw(20) << std::left << locString << std::right + << " | R[Ohm] " << rtdValue << " Ohms | Approx T[C]: " << approxTemp << std::endl; + } + } + return RETURN_OK; +} + +uint32_t Max31865EiveHandler::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) { return 2000; } + +ReturnValue_t Max31865EiveHandler::initializeLocalDataPool(localpool::DataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) { + using namespace MAX31865; + localDataPoolMap.emplace(static_cast(PoolIds::RTD_VALUE), new PoolEntry({0})); + localDataPoolMap.emplace(static_cast(PoolIds::TEMPERATURE_C), new PoolEntry({0})); + localDataPoolMap.emplace(static_cast(PoolIds::FAULT_BYTE), new PoolEntry({0})); + poolManager.subscribeForPeriodicPacket(sensorDataset.getSid(), false, 30.0, false); + return RETURN_OK; +} + +void Max31865EiveHandler::setDeviceInfo(uint8_t idx_, std::string location_) { + idx = idx_; + locString = std::move(location_); +} + +ReturnValue_t Max31865EiveHandler::initialize() { return DeviceHandlerBase::initialize(); } diff --git a/mission/devices/Max31865EiveHandler.h b/mission/devices/Max31865EiveHandler.h new file mode 100644 index 00000000..121929e7 --- /dev/null +++ b/mission/devices/Max31865EiveHandler.h @@ -0,0 +1,47 @@ +#ifndef MISSION_DEVICES_MAX31865EIVEHANDLER_H_ +#define MISSION_DEVICES_MAX31865EIVEHANDLER_H_ + +#include +#include + +#include "devicedefinitions/Max31865Definitions.h" + +class Max31865EiveHandler : public DeviceHandlerBase { + public: + Max31865EiveHandler(object_id_t objectId, object_id_t comIF, CookieIF* comCookie); + void setInstantNormal(bool instantNormal); + void setDebugMode(bool enable, uint32_t divider); + void setDeviceInfo(uint8_t idx, std::string location); + + private: + void doStartUp() override; + void doShutDown() override; + void doTransition(Mode_t modeFrom, Submode_t subModeFrom) override; + ReturnValue_t buildNormalDeviceCommand(DeviceCommandId_t* id) override; + ReturnValue_t buildTransitionDeviceCommand(DeviceCommandId_t* id) override; + void fillCommandAndReplyMap() override; + ReturnValue_t buildCommandFromCommand(DeviceCommandId_t deviceCommand, const uint8_t* commandData, + size_t commandDataLen) override; + ReturnValue_t scanForReply(const uint8_t* start, size_t remainingSize, DeviceCommandId_t* foundId, + size_t* foundLen) override; + ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t* packet) override; + uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) override; + ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) override; + ReturnValue_t initialize() override; + + void simpleCommand(EiveMax31855::RtdCommands cmd); + std::array cmdBuf = {}; + uint8_t idx = 0; + std::string locString = "Unknown"; + EiveMax31855::ReadOutStruct exchangeStruct; + bool debugMode = false; + size_t structLen = 0; + bool instantNormal = false; + MAX31865::Max31865Set sensorDataset; + PeriodicOperationDivider debugDivider; + enum class InternalState { NONE, ON, ACTIVE, INACTIVE } state = InternalState::NONE; + bool transitionOk = false; +}; + +#endif /* MISSION_DEVICES_MAX31865EIVEHANDLER_H_ */ diff --git a/mission/devices/Max31865PT1000Handler.cpp b/mission/devices/Max31865PT1000Handler.cpp index 580c8637..354fe1c5 100644 --- a/mission/devices/Max31865PT1000Handler.cpp +++ b/mission/devices/Max31865PT1000Handler.cpp @@ -8,7 +8,7 @@ Max31865PT1000Handler::Max31865PT1000Handler(object_id_t objectId, object_id_t comIF, CookieIF *comCookie) : DeviceHandlerBase(objectId, comIF, comCookie), - sensorDataset(this), + sensorDataset(this, MAX31865::REQUEST_RTD), sensorDatasetSid(sensorDataset.getSid()) { #if OBSW_VERBOSE_LEVEL >= 1 debugDivider = new PeriodicOperationDivider(10); @@ -93,13 +93,13 @@ void Max31865PT1000Handler::doShutDown() { ReturnValue_t Max31865PT1000Handler::buildNormalDeviceCommand(DeviceCommandId_t *id) { if (internalState == InternalState::RUNNING) { - *id = Max31865Definitions::REQUEST_RTD; + *id = MAX31865::REQUEST_RTD; return buildCommandFromCommand(*id, nullptr, 0); } else if (internalState == InternalState::REQUEST_FAULT_BYTE) { - *id = Max31865Definitions::REQUEST_FAULT_BYTE; + *id = MAX31865::REQUEST_FAULT_BYTE; return buildCommandFromCommand(*id, nullptr, 0); } else if (internalState == InternalState::CLEAR_FAULT_BYTE) { - *id = Max31865Definitions::CLEAR_FAULT_BYTE; + *id = MAX31865::CLEAR_FAULT_BYTE; return buildCommandFromCommand(*id, nullptr, 0); } else { return DeviceHandlerBase::NOTHING_TO_SEND; @@ -113,32 +113,32 @@ ReturnValue_t Max31865PT1000Handler::buildTransitionDeviceCommand(DeviceCommandI case (InternalState::RUNNING): return DeviceHandlerBase::NOTHING_TO_SEND; case (InternalState::CONFIGURE): { - *id = Max31865Definitions::CONFIG_CMD; + *id = MAX31865::CONFIG_CMD; uint8_t config[1] = {DEFAULT_CONFIG}; return buildCommandFromCommand(*id, config, 1); } case (InternalState::REQUEST_CONFIG): { - *id = Max31865Definitions::REQUEST_CONFIG; + *id = MAX31865::REQUEST_CONFIG; return buildCommandFromCommand(*id, nullptr, 0); } case (InternalState::CONFIG_HIGH_THRESHOLD): { - *id = Max31865Definitions::WRITE_HIGH_THRESHOLD; + *id = MAX31865::WRITE_HIGH_THRESHOLD; return buildCommandFromCommand(*id, nullptr, 0); } case (InternalState::REQUEST_HIGH_THRESHOLD): { - *id = Max31865Definitions::REQUEST_HIGH_THRESHOLD; + *id = MAX31865::REQUEST_HIGH_THRESHOLD; return buildCommandFromCommand(*id, nullptr, 0); } case (InternalState::CONFIG_LOW_THRESHOLD): { - *id = Max31865Definitions::WRITE_LOW_THRESHOLD; + *id = MAX31865::WRITE_LOW_THRESHOLD; return buildCommandFromCommand(*id, nullptr, 0); } case (InternalState::REQUEST_LOW_THRESHOLD): { - *id = Max31865Definitions::REQUEST_LOW_THRESHOLD; + *id = MAX31865::REQUEST_LOW_THRESHOLD; return buildCommandFromCommand(*id, nullptr, 0); } case (InternalState::CLEAR_FAULT_BYTE): { - *id = Max31865Definitions::CLEAR_FAULT_BYTE; + *id = MAX31865::CLEAR_FAULT_BYTE; return buildCommandFromCommand(*id, nullptr, 0); } @@ -156,10 +156,11 @@ ReturnValue_t Max31865PT1000Handler::buildCommandFromCommand(DeviceCommandId_t d const uint8_t *commandData, size_t commandDataLen) { switch (deviceCommand) { - case (Max31865Definitions::CONFIG_CMD): { - commandBuffer[0] = static_cast(Max31865Definitions::CONFIG_CMD); + case (MAX31865::CONFIG_CMD): { + commandBuffer[0] = static_cast(MAX31865::CONFIG_CMD); if (commandDataLen == 1) { commandBuffer[1] = commandData[0]; + currentCfg = commandData[0]; DeviceHandlerBase::rawPacketLen = 2; DeviceHandlerBase::rawPacket = commandBuffer.data(); return HasReturnvaluesIF::RETURN_OK; @@ -167,54 +168,54 @@ ReturnValue_t Max31865PT1000Handler::buildCommandFromCommand(DeviceCommandId_t d return DeviceHandlerIF::NO_COMMAND_DATA; } } - case (Max31865Definitions::CLEAR_FAULT_BYTE): { - commandBuffer[0] = static_cast(Max31865Definitions::CONFIG_CMD); - commandBuffer[1] = Max31865Definitions::CLEAR_FAULT_BIT_VAL; + case (MAX31865::CLEAR_FAULT_BYTE): { + commandBuffer[0] = static_cast(MAX31865::CONFIG_CMD); + commandBuffer[1] = currentCfg | MAX31865::CLEAR_FAULT_BIT_VAL; DeviceHandlerBase::rawPacketLen = 2; DeviceHandlerBase::rawPacket = commandBuffer.data(); return HasReturnvaluesIF::RETURN_OK; } - case (Max31865Definitions::REQUEST_CONFIG): { - commandBuffer[0] = static_cast(Max31865Definitions::REQUEST_CONFIG); + case (MAX31865::REQUEST_CONFIG): { + commandBuffer[0] = static_cast(MAX31865::REQUEST_CONFIG); commandBuffer[1] = 0x00; // dummy byte DeviceHandlerBase::rawPacketLen = 2; DeviceHandlerBase::rawPacket = commandBuffer.data(); return HasReturnvaluesIF::RETURN_OK; } - case (Max31865Definitions::WRITE_HIGH_THRESHOLD): { - commandBuffer[0] = static_cast(Max31865Definitions::WRITE_HIGH_THRESHOLD); + case (MAX31865::WRITE_HIGH_THRESHOLD): { + commandBuffer[0] = static_cast(MAX31865::WRITE_HIGH_THRESHOLD); commandBuffer[1] = static_cast(HIGH_THRESHOLD >> 8); commandBuffer[2] = static_cast(HIGH_THRESHOLD & 0xFF); DeviceHandlerBase::rawPacketLen = 3; DeviceHandlerBase::rawPacket = commandBuffer.data(); return HasReturnvaluesIF::RETURN_OK; } - case (Max31865Definitions::REQUEST_HIGH_THRESHOLD): { - commandBuffer[0] = static_cast(Max31865Definitions::REQUEST_HIGH_THRESHOLD); + case (MAX31865::REQUEST_HIGH_THRESHOLD): { + commandBuffer[0] = static_cast(MAX31865::REQUEST_HIGH_THRESHOLD); commandBuffer[1] = 0x00; // dummy byte commandBuffer[2] = 0x00; // dummy byte DeviceHandlerBase::rawPacketLen = 3; DeviceHandlerBase::rawPacket = commandBuffer.data(); return HasReturnvaluesIF::RETURN_OK; } - case (Max31865Definitions::WRITE_LOW_THRESHOLD): { - commandBuffer[0] = static_cast(Max31865Definitions::WRITE_LOW_THRESHOLD); + case (MAX31865::WRITE_LOW_THRESHOLD): { + commandBuffer[0] = static_cast(MAX31865::WRITE_LOW_THRESHOLD); commandBuffer[1] = static_cast(LOW_THRESHOLD >> 8); commandBuffer[2] = static_cast(LOW_THRESHOLD & 0xFF); DeviceHandlerBase::rawPacketLen = 3; DeviceHandlerBase::rawPacket = commandBuffer.data(); return HasReturnvaluesIF::RETURN_OK; } - case (Max31865Definitions::REQUEST_LOW_THRESHOLD): { - commandBuffer[0] = static_cast(Max31865Definitions::REQUEST_LOW_THRESHOLD); + case (MAX31865::REQUEST_LOW_THRESHOLD): { + commandBuffer[0] = static_cast(MAX31865::REQUEST_LOW_THRESHOLD); commandBuffer[1] = 0x00; // dummy byte commandBuffer[2] = 0x00; // dummy byte DeviceHandlerBase::rawPacketLen = 3; DeviceHandlerBase::rawPacket = commandBuffer.data(); return HasReturnvaluesIF::RETURN_OK; } - case (Max31865Definitions::REQUEST_RTD): { - commandBuffer[0] = static_cast(Max31865Definitions::REQUEST_RTD); + case (MAX31865::REQUEST_RTD): { + commandBuffer[0] = static_cast(MAX31865::REQUEST_RTD); // two dummy bytes commandBuffer[1] = 0x00; commandBuffer[2] = 0x00; @@ -222,8 +223,8 @@ ReturnValue_t Max31865PT1000Handler::buildCommandFromCommand(DeviceCommandId_t d DeviceHandlerBase::rawPacket = commandBuffer.data(); return HasReturnvaluesIF::RETURN_OK; } - case (Max31865Definitions::REQUEST_FAULT_BYTE): { - commandBuffer[0] = static_cast(Max31865Definitions::REQUEST_FAULT_BYTE); + case (MAX31865::REQUEST_FAULT_BYTE): { + commandBuffer[0] = static_cast(MAX31865::REQUEST_FAULT_BYTE); commandBuffer[1] = 0x00; DeviceHandlerBase::rawPacketLen = 2; DeviceHandlerBase::rawPacket = commandBuffer.data(); @@ -236,15 +237,15 @@ ReturnValue_t Max31865PT1000Handler::buildCommandFromCommand(DeviceCommandId_t d } void Max31865PT1000Handler::fillCommandAndReplyMap() { - insertInCommandAndReplyMap(Max31865Definitions::CONFIG_CMD, 3); - insertInCommandAndReplyMap(Max31865Definitions::REQUEST_CONFIG, 3); - insertInCommandAndReplyMap(Max31865Definitions::WRITE_LOW_THRESHOLD, 3); - insertInCommandAndReplyMap(Max31865Definitions::REQUEST_LOW_THRESHOLD, 3); - insertInCommandAndReplyMap(Max31865Definitions::WRITE_HIGH_THRESHOLD, 3); - insertInCommandAndReplyMap(Max31865Definitions::REQUEST_HIGH_THRESHOLD, 3); - insertInCommandAndReplyMap(Max31865Definitions::REQUEST_RTD, 3, &sensorDataset); - insertInCommandAndReplyMap(Max31865Definitions::REQUEST_FAULT_BYTE, 3); - insertInCommandAndReplyMap(Max31865Definitions::CLEAR_FAULT_BYTE, 3); + insertInCommandAndReplyMap(MAX31865::CONFIG_CMD, 3); + insertInCommandAndReplyMap(MAX31865::REQUEST_CONFIG, 3); + insertInCommandAndReplyMap(MAX31865::WRITE_LOW_THRESHOLD, 3); + insertInCommandAndReplyMap(MAX31865::REQUEST_LOW_THRESHOLD, 3); + insertInCommandAndReplyMap(MAX31865::WRITE_HIGH_THRESHOLD, 3); + insertInCommandAndReplyMap(MAX31865::REQUEST_HIGH_THRESHOLD, 3); + insertInCommandAndReplyMap(MAX31865::REQUEST_RTD, 3, &sensorDataset); + insertInCommandAndReplyMap(MAX31865::REQUEST_FAULT_BYTE, 3); + insertInCommandAndReplyMap(MAX31865::CLEAR_FAULT_BYTE, 3); } ReturnValue_t Max31865PT1000Handler::scanForReply(const uint8_t *start, size_t remainingSize, @@ -253,7 +254,7 @@ ReturnValue_t Max31865PT1000Handler::scanForReply(const uint8_t *start, size_t r size_t configReplySize = 2; if (remainingSize == rtdReplySize and internalState == InternalState::RUNNING) { - *foundId = Max31865Definitions::REQUEST_RTD; + *foundId = MAX31865::REQUEST_RTD; *foundLen = rtdReplySize; return RETURN_OK; } @@ -262,24 +263,24 @@ ReturnValue_t Max31865PT1000Handler::scanForReply(const uint8_t *start, size_t r switch (internalState) { case (InternalState::CONFIG_HIGH_THRESHOLD): { *foundLen = 3; - *foundId = Max31865Definitions::WRITE_HIGH_THRESHOLD; + *foundId = MAX31865::WRITE_HIGH_THRESHOLD; commandExecuted = true; return RETURN_OK; } case (InternalState::REQUEST_HIGH_THRESHOLD): { *foundLen = 3; - *foundId = Max31865Definitions::REQUEST_HIGH_THRESHOLD; + *foundId = MAX31865::REQUEST_HIGH_THRESHOLD; return RETURN_OK; } case (InternalState::CONFIG_LOW_THRESHOLD): { *foundLen = 3; - *foundId = Max31865Definitions::WRITE_LOW_THRESHOLD; + *foundId = MAX31865::WRITE_LOW_THRESHOLD; commandExecuted = true; return RETURN_OK; } case (InternalState::REQUEST_LOW_THRESHOLD): { *foundLen = 3; - *foundId = Max31865Definitions::REQUEST_LOW_THRESHOLD; + *foundId = MAX31865::REQUEST_LOW_THRESHOLD; return RETURN_OK; } default: { @@ -293,13 +294,13 @@ ReturnValue_t Max31865PT1000Handler::scanForReply(const uint8_t *start, size_t r if (internalState == InternalState::CONFIGURE) { commandExecuted = true; *foundLen = configReplySize; - *foundId = Max31865Definitions::CONFIG_CMD; + *foundId = MAX31865::CONFIG_CMD; } else if (internalState == InternalState::REQUEST_FAULT_BYTE) { - *foundId = Max31865Definitions::REQUEST_FAULT_BYTE; + *foundId = MAX31865::REQUEST_FAULT_BYTE; *foundLen = 2; internalState = InternalState::RUNNING; } else if (internalState == InternalState::CLEAR_FAULT_BYTE) { - *foundId = Max31865Definitions::CLEAR_FAULT_BYTE; + *foundId = MAX31865::CLEAR_FAULT_BYTE; *foundLen = 2; if (mode == _MODE_START_UP) { commandExecuted = true; @@ -307,7 +308,7 @@ ReturnValue_t Max31865PT1000Handler::scanForReply(const uint8_t *start, size_t r internalState = InternalState::RUNNING; } } else { - *foundId = Max31865Definitions::REQUEST_CONFIG; + *foundId = MAX31865::REQUEST_CONFIG; *foundLen = configReplySize; } } @@ -318,7 +319,7 @@ ReturnValue_t Max31865PT1000Handler::scanForReply(const uint8_t *start, size_t r ReturnValue_t Max31865PT1000Handler::interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) { switch (id) { - case (Max31865Definitions::REQUEST_CONFIG): { + case (MAX31865::REQUEST_CONFIG): { if (packet[1] != DEFAULT_CONFIG) { if (warningSwitch) { #if FSFW_CPP_OSTREAM_ENABLED == 1 @@ -342,7 +343,7 @@ ReturnValue_t Max31865PT1000Handler::interpretDeviceReply(DeviceCommandId_t id, } break; } - case (Max31865Definitions::REQUEST_LOW_THRESHOLD): { + case (MAX31865::REQUEST_LOW_THRESHOLD): { uint16_t readLowThreshold = packet[1] << 8 | packet[2]; if (readLowThreshold != LOW_THRESHOLD) { #if FSFW_VERBOSE_LEVEL >= 1 @@ -360,8 +361,8 @@ ReturnValue_t Max31865PT1000Handler::interpretDeviceReply(DeviceCommandId_t id, commandExecuted = true; break; } - case (Max31865Definitions::REQUEST_HIGH_THRESHOLD): { - uint16_t readHighThreshold = packet[1] << 8 | packet[2]; + case (MAX31865::REQUEST_HIGH_THRESHOLD): { + uint16_t readHighThreshold = (packet[1] << 8) | packet[2]; if (readHighThreshold != HIGH_THRESHOLD) { #if FSFW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 @@ -378,13 +379,13 @@ ReturnValue_t Max31865PT1000Handler::interpretDeviceReply(DeviceCommandId_t id, commandExecuted = true; break; } - case (Max31865Definitions::REQUEST_RTD): { + case (MAX31865::REQUEST_RTD): { // first bit of LSB reply byte is the fault bit - uint8_t faultBit = packet[2] & 0b0000'0001; + bool faultBit = packet[2] & 0b0000'0001; if (resetFaultBit) { internalState = InternalState::CLEAR_FAULT_BYTE; resetFaultBit = false; - } else if (faultBit == 1) { + } else if (shouldFaultStatusBeRequested(faultBit)) { // Maybe we should attempt to restart it? internalState = InternalState::REQUEST_FAULT_BYTE; resetFaultBit = true; @@ -393,9 +394,8 @@ ReturnValue_t Max31865PT1000Handler::interpretDeviceReply(DeviceCommandId_t id, // RTD value consists of last seven bits of the LSB reply byte and // the MSB reply byte uint16_t adcCode = ((packet[1] << 8) | packet[2]) >> 1; - // do something with rtd value, will propably be stored in - // dataset. - float rtdValue = adcCode * RTD_RREF_PT1000 / INT16_MAX; + // Calculate resistance + float rtdValue = adcCode * EiveMax31855::RTD_RREF_PT1000 / INT16_MAX; // calculate approximation float approxTemp = adcCode / 32.0 - 256.0; @@ -403,9 +403,9 @@ ReturnValue_t Max31865PT1000Handler::interpretDeviceReply(DeviceCommandId_t id, #if OBSW_VERBOSE_LEVEL >= 1 if (debugDivider->checkAndIncrement()) { #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::info << "Max31865: ObjID " << std::hex << this->getObjectId() << " | RTD " - << std::dec << static_cast(deviceIdx) << ": R[Ohm] " << rtdValue - << " Ohms | Approx T[C]: " << approxTemp << std::endl; + sif::info << "Max31865: " << std::setw(24) << std::left << locString << std::right + << " | R[Ohm] " << rtdValue << " Ohms | Approx T[C]: " << approxTemp + << std::endl; #else sif::printInfo("Max31685: Measured resistance is %f Ohms\n", rtdValue); sif::printInfo("Approximated temperature is %f C\n", approxTemp); @@ -438,58 +438,57 @@ ReturnValue_t Max31865PT1000Handler::interpretDeviceReply(DeviceCommandId_t id, sensorDataset.temperatureCelcius = approxTemp; break; } - case (Max31865Definitions::REQUEST_FAULT_BYTE): { - faultByte = packet[1]; + case (MAX31865::REQUEST_FAULT_BYTE): { + currentFaultStatus = packet[1]; + bool faultStatusChanged = (currentFaultStatus != lastFaultStatus); + // Spam protection + if (faultStatusChanged or + ((currentFaultStatus == lastFaultStatus) and (sameFaultStatusCounter < 3))) { + // TODO: Think about triggering an event here #if OBSW_VERBOSE_LEVEL >= 1 #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::warning << "Max31865PT1000Handler::interpretDeviceReply: Object ID: " << std::hex - << this->getObjectId() - << ": Fault byte" - " is: 0b" - << std::bitset<8>(faultByte) << std::endl; + sif::warning << "Max31865PT1000Handler::interpretDeviceReply: Object ID: " << std::hex + << this->getObjectId() << ": Fault byte is: 0b" + << std::bitset<8>(currentFaultStatus) << std::endl; #else - sif::printWarning( - "Max31865PT1000Handler::interpretDeviceReply: Fault byte" - " is: 0b" BYTE_TO_BINARY_PATTERN "\n", - BYTE_TO_BINARY(faultByte)); + sif::printWarning( + "Max31865PT1000Handler::interpretDeviceReply: Fault byte" + " is: 0b" BYTE_TO_BINARY_PATTERN "\n", + BYTE_TO_BINARY(faultByte)); #endif #endif - ReturnValue_t result = sensorDataset.read(); + if (faultStatusChanged) { + sameFaultStatusCounter = 0; + } else { + sameFaultStatusCounter++; + } + } + if (faultStatusChanged) { + lastFaultStatus = currentFaultStatus; + } + + PoolReadGuard pg(&sensorDataset); + auto result = pg.getReadResult(); if (result != HasReturnvaluesIF::RETURN_OK) { // Configuration error #if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "Max31865PT1000Handler::interpretDeviceReply: Object ID: " << std::hex - << this->getObjectId() - << ":" - "Error reading dataset!" - << std::endl; + sif::warning << "Max31865PT1000Handler::interpretDeviceReply: Object ID: " << std::hex + << this->getObjectId() << ": Error reading dataset" << std::endl; #else - sif::printDebug( - "Max31865PT1000Handler::interpretDeviceReply: " - "Error reading dataset!\n"); + sif::printWarning("Max31865PT1000Handler::interpretDeviceReply: Error reading dataset\n"); #endif return result; } + if (faultStatusChanged) { + sensorDataset.lastErrorByte.setValid(true); + sensorDataset.lastErrorByte = lastFaultStatus; + } sensorDataset.errorByte.setValid(true); - sensorDataset.errorByte = faultByte; - if (faultByte != 0) { + sensorDataset.errorByte = currentFaultStatus; + + if (currentFaultStatus != 0) { sensorDataset.temperatureCelcius.setValid(false); } - - result = sensorDataset.commit(); - if (result != HasReturnvaluesIF::RETURN_OK) { - // Configuration error -#if FSFW_CPP_OSTREAM_ENABLED == 1 - sif::debug << "Max31865PT1000Handler::interpretDeviceReply: Object ID: " << std::hex - << this->getObjectId() << ": Error commiting dataset!" << std::endl; -#else - sif::printDebug( - "Max31865PT1000Handler::interpretDeviceReply: " - "Error commiting dataset!\n"); -#endif - return result; - } - break; } default: @@ -498,11 +497,8 @@ ReturnValue_t Max31865PT1000Handler::interpretDeviceReply(DeviceCommandId_t id, return HasReturnvaluesIF::RETURN_OK; } -void Max31865PT1000Handler::debugInterface(uint8_t positionTracker, object_id_t objectId, - uint32_t parameter) {} - uint32_t Max31865PT1000Handler::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) { - return 25000; + return 5000; } ReturnValue_t Max31865PT1000Handler::getSwitches(const uint8_t **switches, @@ -512,10 +508,12 @@ ReturnValue_t Max31865PT1000Handler::getSwitches(const uint8_t **switches, ReturnValue_t Max31865PT1000Handler::initializeLocalDataPool(localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) { - localDataPoolMap.emplace(Max31865Definitions::PoolIds::RTD_VALUE, new PoolEntry({0})); - localDataPoolMap.emplace(Max31865Definitions::PoolIds::TEMPERATURE_C, - new PoolEntry({0}, 1, true)); - localDataPoolMap.emplace(Max31865Definitions::PoolIds::FAULT_BYTE, new PoolEntry({0})); + using namespace MAX31865; + localDataPoolMap.emplace(static_cast(PoolIds::RTD_VALUE), new PoolEntry({0})); + localDataPoolMap.emplace(static_cast(PoolIds::TEMPERATURE_C), new PoolEntry({0})); + localDataPoolMap.emplace(static_cast(PoolIds::LAST_FAULT_BYTE), + new PoolEntry({0})); + localDataPoolMap.emplace(static_cast(PoolIds::FAULT_BYTE), new PoolEntry({0})); poolManager.subscribeForPeriodicPacket(sensorDataset.getSid(), false, 30.0, false); return HasReturnvaluesIF::RETURN_OK; } @@ -526,10 +524,23 @@ void Max31865PT1000Handler::setInstantNormal(bool instantNormal) { void Max31865PT1000Handler::modeChanged() { if (mode == MODE_OFF) { + lastFaultStatus = 0; + currentFaultStatus = 0; + sameFaultStatusCounter = 0; internalState = InternalState::NONE; } } -void Max31865PT1000Handler::setDeviceIdx(uint8_t idx) { deviceIdx = idx; } +void Max31865PT1000Handler::setDeviceInfo(uint8_t idx, std::string locString_) { + deviceIdx = idx; + locString = std::move(locString_); +} void Max31865PT1000Handler::setDebugMode(bool enable) { this->debugMode = enable; } + +bool Max31865PT1000Handler::shouldFaultStatusBeRequested(bool faultBit) { + if ((sameFaultStatusCounter < 3) and faultBit) { + return true; + } + return false; +} diff --git a/mission/devices/Max31865PT1000Handler.h b/mission/devices/Max31865PT1000Handler.h index 4f617b9d..6b136f13 100644 --- a/mission/devices/Max31865PT1000Handler.h +++ b/mission/devices/Max31865PT1000Handler.h @@ -48,7 +48,7 @@ class Max31865PT1000Handler : public DeviceHandlerBase { static constexpr uint8_t DEFAULT_CONFIG = 0b11000001; void setInstantNormal(bool instantNormal); - void setDeviceIdx(uint8_t idx); + void setDeviceInfo(uint8_t idx, std::string locString); /** * Expected temperature range is -100 C and 100 C. @@ -61,7 +61,6 @@ class Max31865PT1000Handler : public DeviceHandlerBase { static constexpr uint16_t HIGH_THRESHOLD = 11298; // = 100 C static constexpr uint16_t LOW_THRESHOLD = 4902; // = -100 C - static constexpr float RTD_RREF_PT1000 = 4020.0; //!< Ohm static constexpr float RTD_RESISTANCE0_PT1000 = 1000.0; //!< Ohm protected: // DeviceHandlerBase abstract function implementation @@ -77,12 +76,10 @@ class Max31865PT1000Handler : public DeviceHandlerBase { ReturnValue_t interpretDeviceReply(DeviceCommandId_t id, const uint8_t *packet) override; uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) override; ReturnValue_t getSwitches(const uint8_t **switches, uint8_t *numberOfSwitches) override; - - void debugInterface(uint8_t positionTracker = 0, object_id_t objectId = 0, - uint32_t parameter = 0) override; ReturnValue_t initializeLocalDataPool(localpool::DataPool &localDataPoolMap, LocalDataPoolManager &poolManager) override; void modeChanged() override; + bool shouldFaultStatusBeRequested(bool faultBit); private: uint8_t switchId = 0; @@ -109,11 +106,15 @@ class Max31865PT1000Handler : public DeviceHandlerBase { bool resetFaultBit = false; dur_millis_t startTime = 0; - uint8_t faultByte = 0; + uint8_t currentCfg = 0; + uint8_t currentFaultStatus = 0; + uint8_t lastFaultStatus = 0; + uint16_t sameFaultStatusCounter = 0; + std::string locString; uint8_t deviceIdx = 0; std::array commandBuffer{0}; - Max31865Definitions::Max31865Set sensorDataset; + MAX31865::Max31865Set sensorDataset; sid_t sensorDatasetSid; #if OBSW_VERBOSE_LEVEL >= 1 diff --git a/mission/devices/PayloadPcduHandler.cpp b/mission/devices/PayloadPcduHandler.cpp index dd576cae..85cf62fa 100644 --- a/mission/devices/PayloadPcduHandler.cpp +++ b/mission/devices/PayloadPcduHandler.cpp @@ -716,7 +716,6 @@ ReturnValue_t PayloadPcduHandler::transferAsTwo(SpiComIF* comIf, SpiCookie* cook GpioIF* gpioIF = comIf->getGpioInterface(); MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING; uint32_t timeoutMs = 0; - cookie->getMutexParams(timeoutType, timeoutMs); MutexIF* mutex = comIf->getCsMutex(); if (mutex == nullptr or gpioIF == nullptr) { #if OBSW_VERBOSE_LEVEL >= 1 @@ -728,6 +727,7 @@ ReturnValue_t PayloadPcduHandler::transferAsTwo(SpiComIF* comIf, SpiCookie* cook } if (gpioId != gpio::NO_GPIO) { + cookie->getMutexParams(timeoutType, timeoutMs); result = mutex->lockMutex(timeoutType, timeoutMs); if (result != RETURN_OK) { #if FSFW_CPP_OSTREAM_ENABLED == 1 diff --git a/mission/devices/devicedefinitions/Max31865Definitions.h b/mission/devices/devicedefinitions/Max31865Definitions.h index 58faaf97..d7d6455d 100644 --- a/mission/devices/devicedefinitions/Max31865Definitions.h +++ b/mission/devices/devicedefinitions/Max31865Definitions.h @@ -7,20 +7,48 @@ #include "objects/systemObjectList.h" -namespace Max31865Definitions { +namespace MAX31865 { -enum PoolIds : lp_id_t { RTD_VALUE, TEMPERATURE_C, FAULT_BYTE }; +enum class PoolIds : lp_id_t { RTD_VALUE, TEMPERATURE_C, LAST_FAULT_BYTE, FAULT_BYTE }; +enum Wires : unsigned int { TWO_WIRE = 0, THREE_WIRE = 1, FOUR_WIRE = 0 }; + +enum ConvMode : unsigned int { NORM_OFF = 0, AUTO = 1 }; + +enum Bias : unsigned int { OFF = 0, ON = 1 }; + +enum FilterSel : unsigned int { FIFTY_HERTZ = 1, SIXTY_HERTZ = 0 }; + +enum CfgBitPos { + FILTER_SEL = 0, + FAULT_STATUS_CLEAR = 1, + FDCC = 2, + WIRE_SEL = 4, + ONE_SHOT = 5, + CONV_MODE = 6, + BIAS_SEL = 7 +}; + +static constexpr uint32_t WARMUP_MS = 100; + +static constexpr uint8_t WRITE_BIT = 0b10000000; + +enum Regs : uint8_t { + CONFIG = 0x00, + RTD = 0x01, + HIGH_THRESHOLD = 0x03, + LOW_THRESHOLD = 0x05, + FAULT_BYTE = 0x07 +}; static constexpr DeviceCommandId_t CONFIG_CMD = 0x80; static constexpr DeviceCommandId_t WRITE_HIGH_THRESHOLD = 0x83; static constexpr DeviceCommandId_t WRITE_LOW_THRESHOLD = 0x85; -static constexpr DeviceCommandId_t REQUEST_CONFIG = 0x00; -static constexpr DeviceCommandId_t REQUEST_RTD = 0x01; -static constexpr DeviceCommandId_t REQUEST_HIGH_THRESHOLD = 0x03; -static constexpr DeviceCommandId_t REQUEST_LOW_THRESHOLD = 0x05; -static constexpr DeviceCommandId_t REQUEST_FAULT_BYTE = 0x07; - +static constexpr DeviceCommandId_t REQUEST_CONFIG = CONFIG; +static constexpr DeviceCommandId_t REQUEST_RTD = RTD; +static constexpr DeviceCommandId_t REQUEST_HIGH_THRESHOLD = HIGH_THRESHOLD; +static constexpr DeviceCommandId_t REQUEST_LOW_THRESHOLD = LOW_THRESHOLD; +static constexpr DeviceCommandId_t REQUEST_FAULT_BYTE = FAULT_BYTE; static constexpr DeviceCommandId_t CLEAR_FAULT_BYTE = 0x08; static constexpr uint32_t MAX31865_SET_ID = REQUEST_RTD; @@ -28,26 +56,82 @@ static constexpr uint8_t CLEAR_FAULT_BIT_VAL = 0b0000'0010; static constexpr size_t MAX_REPLY_SIZE = 5; -class Max31865Set : public StaticLocalDataSet { +class Max31865Set : public StaticLocalDataSet<4> { public: /** * Constructor used by owner and data creators like device handlers. * @param owner * @param setId */ - Max31865Set(HasLocalDataPoolIF* owner) : StaticLocalDataSet(owner, MAX31865_SET_ID) {} + Max31865Set(HasLocalDataPoolIF* owner, uint32_t setId) : StaticLocalDataSet(owner, setId) {} /** * Constructor used by data users like controllers. * @param sid */ - Max31865Set(object_id_t objectId) : StaticLocalDataSet(sid_t(objectId, MAX31865_SET_ID)) {} + Max31865Set(object_id_t objectId, uint32_t setId) : StaticLocalDataSet(sid_t(objectId, setId)) {} - lp_var_t rtdValue = lp_var_t(sid.objectId, PoolIds::RTD_VALUE, this); - lp_var_t temperatureCelcius = lp_var_t(sid.objectId, PoolIds::TEMPERATURE_C, this); - lp_var_t errorByte = lp_var_t(sid.objectId, PoolIds::FAULT_BYTE, this); + lp_var_t rtdValue = + lp_var_t(sid.objectId, static_cast(PoolIds::RTD_VALUE), this); + lp_var_t temperatureCelcius = + lp_var_t(sid.objectId, static_cast(PoolIds::TEMPERATURE_C), this); + lp_var_t lastErrorByte = + lp_var_t(sid.objectId, static_cast(PoolIds::LAST_FAULT_BYTE), this); + lp_var_t errorByte = + lp_var_t(sid.objectId, static_cast(PoolIds::FAULT_BYTE), this); }; -} // namespace Max31865Definitions +} // namespace MAX31865 + +namespace EiveMax31855 { + +static constexpr float RTD_RREF_PT1000 = 4020.0; //!< Ohm +static constexpr uint8_t NUM_RTDS = 16; + +enum RtdCommands : DeviceCommandId_t { + ON = 0, + EXCHANGE_SET_ID = MAX31865::REQUEST_RTD, + ACTIVE = 2, + LOW_THRESHOLD = 3, + HIGH_TRESHOLD = 4, + OFF = 5, + CFG = 6, + NUM_CMDS +}; + +class ReadOutStruct : public SerialLinkedListAdapter { + public: + ReadOutStruct() { setLinks(); } + ReadOutStruct(bool active, uint32_t spiErrCnt, bool faultBitSet, uint8_t faultVal, + uint16_t rtdVal) + : active(active), + adcCode(rtdVal), + faultBitSet(faultBitSet), + faultValue(faultVal), + spiErrorCount(spiErrCnt) { + setLinks(); + } + + //! RTD was set on and is configured, but is not periodically polled + SerializeElement configured = false; + //! RTD is active and polled periodically + SerializeElement active = false; + SerializeElement adcCode = 0; + SerializeElement faultBitSet = false; + SerializeElement faultValue = 0; + SerializeElement spiErrorCount = 0; + + private: + void setLinks() { + setStart(&configured); + configured.setNext(&active); + active.setNext(&adcCode); + adcCode.setNext(&faultBitSet); + faultBitSet.setNext(&faultValue); + faultValue.setNext(&spiErrorCount); + }; +}; + +}; // namespace EiveMax31855 #endif /* MISSION_DEVICES_DEVICEDEFINITIONS_MAX13865DEFINITIONS_H_ */ diff --git a/mission/system/TcsBoardAssembly.cpp b/mission/system/TcsBoardAssembly.cpp index 7655603b..f973335e 100644 --- a/mission/system/TcsBoardAssembly.cpp +++ b/mission/system/TcsBoardAssembly.cpp @@ -10,7 +10,7 @@ TcsBoardAssembly::TcsBoardAssembly(object_id_t objectId, object_id_t parentId, eventQueue = QueueFactory::instance()->createMessageQueue(24); ModeListEntry entry; for (uint8_t idx = 0; idx < NUMBER_RTDS; idx++) { - entry.setObject(helper.rtdIds[idx]); + entry.setObject(helper.rtdInfos[idx].first); entry.setMode(MODE_OFF); entry.setSubmode(SUBMODE_NONE); entry.setInheritSubmode(false); @@ -56,7 +56,7 @@ ReturnValue_t TcsBoardAssembly::checkChildrenStateOn(Mode_t wantedMode, Submode_ int devsInWrongMode = 0; try { for (uint8_t idx = 0; idx < NUMBER_RTDS; idx++) { - if (childrenMap.at(helper.rtdIds[idx]).mode != wantedMode) { + if (childrenMap.at(helper.rtdInfos[idx].first).mode != wantedMode) { devsInWrongMode++; } } @@ -92,8 +92,8 @@ ReturnValue_t TcsBoardAssembly::isModeCombinationValid(Mode_t mode, Submode_t su ReturnValue_t TcsBoardAssembly::initialize() { ReturnValue_t result = RETURN_OK; - for (const auto& obj : helper.rtdIds) { - result = registerChild(obj); + for (const auto& obj : helper.rtdInfos) { + result = registerChild(obj.first); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } @@ -125,8 +125,8 @@ ReturnValue_t TcsBoardAssembly::handleNormalOrOnModeCmd(Mode_t mode, Submode_t s object_id_t objId = 0; try { for (uint8_t idx = 0; idx < NUMBER_RTDS; idx++) { - devMode = childrenMap.at(helper.rtdIds[idx]).mode; - objId = helper.rtdIds[idx]; + devMode = childrenMap.at(helper.rtdInfos[idx].first).mode; + objId = helper.rtdInfos[idx].first; if (mode == devMode) { modeTable[idx].setMode(mode); } else if (mode == DeviceHandlerIF::MODE_NORMAL) { diff --git a/mission/system/TcsBoardAssembly.h b/mission/system/TcsBoardAssembly.h index c23fbd7c..10b451b2 100644 --- a/mission/system/TcsBoardAssembly.h +++ b/mission/system/TcsBoardAssembly.h @@ -6,9 +6,10 @@ #include struct TcsBoardHelper { - TcsBoardHelper(std::array rtdIds) : rtdIds(rtdIds) {} + TcsBoardHelper(std::array, 16> rtdInfos) + : rtdInfos(std::move(rtdInfos)) {} - std::array rtdIds = {}; + std::array, 16> rtdInfos = {}; }; class TcsBoardAssembly : public AssemblyBase, public ConfirmsFailuresIF { diff --git a/tmtc b/tmtc index 480e0f07..648e0b78 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 480e0f07e03edeb55a3d6e3d629e7601b6bf90a2 +Subproject commit 648e0b781483119e17799e34d669f554559692f0