diff --git a/README.md b/README.md index 38df4443..ec32a2bb 100644 --- a/README.md +++ b/README.md @@ -266,7 +266,7 @@ To transfer files from the local machine to the Q7S, use port forwarding ssh -L 1535:192.168.133.10:22 eive@2001:7c0:2018:1099:babe:0:e1fe:f1a5 ``` -Then you can copy an `example` file like this +An `example` file can be copied like this ```sh scp -P 1535 example root@localhost:/tmp @@ -277,7 +277,7 @@ Copying a file from Q7S to flatsat PC scp -P 22 root@192.168.133.10:/tmp/kernel-config /tmp ```` -From a windows machine files can be copied with putty tools +From a windows machine files can be copied with putty tools (note: use IPv4 address) ```` pscp -scp -P 22 eive@192.168.199.227:/example-file ```` @@ -579,4 +579,23 @@ to install the required GPIO libraries before cloning the system root folder. When using Eclipse, there are two special build variables in the project properties → C/C++ Build → Build Variables called `Q7S_SYSROOT` or `RPI_SYSROOT`. You can set the sysroot path in those variables to get any additional includes like `gpiod.h` in the -Eclipse indexer. \ No newline at end of file +Eclipse indexer. + +## Xilinx UARTLIE +Get info about ttyUL* devices +```` +cat /proc/tty/driver +```` + +## I2C +Getting information about I2C device +```` +ls /sys/class/i2c-dev/i2c-0/device/device/driver +```` +This shows the memory mapping of /dev/i2c-0 + +## Useful Q7S Linux Commands +Rebooting currently running image: +```` +xsc_boot_copy -r +```` \ No newline at end of file diff --git a/bsp_q7s/InitMission.cpp b/bsp_q7s/InitMission.cpp index 3fe0ba0c..797c5e71 100644 --- a/bsp_q7s/InitMission.cpp +++ b/bsp_q7s/InitMission.cpp @@ -135,6 +135,8 @@ void initmission::initTasks() { initmission::printAddObjectError("PUS_17", objects::PUS_SERVICE_17_TEST); } +#if TE0720 == 0 + //TODO: Add handling of missed deadlines /* Polling Sequence Table Default */ #if Q7S_ADD_SPI_TEST == 0 @@ -147,14 +149,22 @@ void initmission::initTasks() { } #endif -#if TE0720 == 0 FixedTimeslotTaskIF* gomSpacePstTask = factory-> createFixedTimeslotTask("GS_PST_TASK", 50, - PeriodicTaskIF::MINIMUM_STACK_SIZE*8, 3.0, missedDeadlineFunc); + PeriodicTaskIF::MINIMUM_STACK_SIZE*8, 1.0, missedDeadlineFunc); result = pst::gomspacePstInit(gomSpacePstTask); if(result != HasReturnvaluesIF::RETURN_OK) { sif::error << "InitMission::initTasks: GomSpace PST initialization failed!" << std::endl; } + +#else + FixedTimeslotTaskIF * pollingSequenceTaskTE0720 = factory->createFixedTimeslotTask( + "PST_TASK_TE0720", 30, PeriodicTaskIF::MINIMUM_STACK_SIZE * 8, 3.0, + missedDeadlineFunc); + result = pst::pollingSequenceTE0720(pollingSequenceTaskTE0720); + if (result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "InitMission::initTasks: Creating TE0720 PST failed!" << std::endl; + } #endif #if OBSW_ADD_TEST_CODE == 1 @@ -184,12 +194,11 @@ void initmission::initTasks() { udpBridgeTask->startTask(); udpPollingTask->startTask(); -#if TE0720 == 0 +#if TE0720 == 0 && Q7S_ADD_SPI_TEST == 0 gomSpacePstTask->startTask(); -#endif - -#if Q7S_ADD_SPI_TEST == 0 pollingSequenceTableTaskDefault->startTask(); +#elif TE0720 == 1 && Q7S_ADD_SPI_TEST == 0 + pollingSequenceTaskTE0720->startTask(); #endif pusVerification->startTask(); diff --git a/bsp_q7s/ObjectFactory.cpp b/bsp_q7s/ObjectFactory.cpp index 5519b84b..297f8167 100644 --- a/bsp_q7s/ObjectFactory.cpp +++ b/bsp_q7s/ObjectFactory.cpp @@ -20,14 +20,20 @@ #include #include #include -#include #include #include #include #include +#include +#include +#include #include #include +#include +#include +#include +#include #include #include @@ -99,19 +105,17 @@ void ObjectFactory::produce(){ new UartComIF(objects::UART_COM_IF); #if Q7S_ADD_SPI_TEST == 0 new SpiComIF(objects::SPI_COM_IF, gpioComIF); -#endif +#endif /* Q7S_ADD_SPI_TEST == 0 */ /* Temperature sensors */ Tmp1075Handler* tmp1075Handler_1 = new Tmp1075Handler( objects::TMP1075_HANDLER_1, objects::I2C_COM_IF, i2cCookieTmp1075tcs1); - tmp1075Handler_1->setStartUpImmediately(); + (void) tmp1075Handler_1; Tmp1075Handler* tmp1075Handler_2 = new Tmp1075Handler( objects::TMP1075_HANDLER_2, objects::I2C_COM_IF, i2cCookieTmp1075tcs2); - tmp1075Handler_2->setStartUpImmediately(); - - GpioCookie* heaterGpiosCookie = new GpioCookie; + (void) tmp1075Handler_2; #if TE0720 == 0 CspCookie* p60DockCspCookie = new CspCookie(P60Dock::MAX_REPLY_LENGTH, @@ -147,16 +151,127 @@ void ObjectFactory::produce(){ (void) pdu2handler; (void) acuhandler; + /* Adding gpios for chip select decoding to the gpioComIf */ + gpioCallbacks::initSpiCsDecoder(gpioComIF); + + GpioCookie* gpioCookieRadSensor = new GpioCookie; + GpiodRegular* chipSelectRadSensor = new GpiodRegular(std::string("gpiochip5"), 19, + std::string("Chip Select Radiation Sensor"), gpio::OUT, 1); + gpioCookieRadSensor->addGpio(gpioIds::CS_RAD_SENSOR, chipSelectRadSensor); + gpioComIF->addGpios(gpioCookieRadSensor); + + SpiCookie* spiCookieRadSensor = new SpiCookie(addresses::RAD_SENSOR, gpioIds::CS_RAD_SENSOR, + std::string("/dev/spidev2.0"), RAD_SENSOR::READ_SIZE, spi::DEFAULT_MAX_1227_MODE, + spi::DEFAULT_MAX_1227_SPEED); + new RadiationSensorHandler(objects::RAD_SENSOR, objects::SPI_COM_IF, spiCookieRadSensor); + GpioCookie* gpioCookieSus = new GpioCookie(); + + GpioCallback* susgpio = new GpioCallback(std::string("Chip select SUS 1"), gpio::OUT, 1, + &gpioCallbacks::spiCsDecoderCallback, gpioComIF); + gpioCookieSus->addGpio(gpioIds::CS_SUS_1, susgpio); + susgpio = new GpioCallback(std::string("Chip select SUS 2"), gpio::OUT, 1, + &gpioCallbacks::spiCsDecoderCallback, gpioComIF); + gpioCookieSus->addGpio(gpioIds::CS_SUS_2, susgpio); + susgpio = new GpioCallback(std::string("Chip select SUS 3"), gpio::OUT, 1, + &gpioCallbacks::spiCsDecoderCallback, gpioComIF); + gpioCookieSus->addGpio(gpioIds::CS_SUS_3, susgpio); + susgpio = new GpioCallback(std::string("Chip select SUS 4"), gpio::OUT, 1, + &gpioCallbacks::spiCsDecoderCallback, gpioComIF); + gpioCookieSus->addGpio(gpioIds::CS_SUS_4, susgpio); + susgpio = new GpioCallback(std::string("Chip select SUS 5"), gpio::OUT, 1, + &gpioCallbacks::spiCsDecoderCallback, gpioComIF); + gpioCookieSus->addGpio(gpioIds::CS_SUS_5, susgpio); + susgpio = new GpioCallback(std::string("Chip select SUS 6"), gpio::OUT, 1, + &gpioCallbacks::spiCsDecoderCallback, gpioComIF); + gpioCookieSus->addGpio(gpioIds::CS_SUS_6, susgpio); + susgpio = new GpioCallback(std::string("Chip select SUS 7"), gpio::OUT, 1, + &gpioCallbacks::spiCsDecoderCallback, gpioComIF); + gpioCookieSus->addGpio(gpioIds::CS_SUS_7, susgpio); + susgpio = new GpioCallback(std::string("Chip select SUS 8"), gpio::OUT, 1, + &gpioCallbacks::spiCsDecoderCallback, gpioComIF); + gpioCookieSus->addGpio(gpioIds::CS_SUS_8, susgpio); + susgpio = new GpioCallback(std::string("Chip select SUS 9"), gpio::OUT, 1, + &gpioCallbacks::spiCsDecoderCallback, gpioComIF); + gpioCookieSus->addGpio(gpioIds::CS_SUS_9, susgpio); + susgpio = new GpioCallback(std::string("Chip select SUS 10"), gpio::OUT, 1, + &gpioCallbacks::spiCsDecoderCallback, gpioComIF); + gpioCookieSus->addGpio(gpioIds::CS_SUS_10, susgpio); + susgpio = new GpioCallback(std::string("Chip select SUS 11"), gpio::OUT, 1, + &gpioCallbacks::spiCsDecoderCallback, gpioComIF); + gpioCookieSus->addGpio(gpioIds::CS_SUS_11, susgpio); + susgpio = new GpioCallback(std::string("Chip select SUS 12"), gpio::OUT, 1, + &gpioCallbacks::spiCsDecoderCallback, gpioComIF); + gpioCookieSus->addGpio(gpioIds::CS_SUS_12, susgpio); + susgpio = new GpioCallback(std::string("Chip select SUS 13"), gpio::OUT, 1, + &gpioCallbacks::spiCsDecoderCallback, gpioComIF); + gpioCookieSus->addGpio(gpioIds::CS_SUS_13, susgpio); + + gpioComIF->addGpios(gpioCookieSus); + + SpiCookie* spiCookieSus1 = new SpiCookie(addresses::SUS_1, gpio::NO_GPIO, + std::string("/dev/spidev2.0"), SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, + SUS::MAX1227_SPI_FREQ); + SpiCookie* spiCookieSus2 = new SpiCookie(addresses::SUS_2, gpio::NO_GPIO, + std::string("/dev/spidev2.0"), SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, + SUS::MAX1227_SPI_FREQ); + SpiCookie* spiCookieSus3 = new SpiCookie(addresses::SUS_3, gpio::NO_GPIO, + std::string("/dev/spidev2.0"), SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, + SUS::MAX1227_SPI_FREQ); + SpiCookie* spiCookieSus4 = new SpiCookie(addresses::SUS_4, gpio::NO_GPIO, + std::string("/dev/spidev2.0"), SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, + SUS::MAX1227_SPI_FREQ); + SpiCookie* spiCookieSus5 = new SpiCookie(addresses::SUS_5, gpio::NO_GPIO, + std::string("/dev/spidev2.0"), SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, + SUS::MAX1227_SPI_FREQ); + SpiCookie* spiCookieSus6 = new SpiCookie(addresses::SUS_6, gpio::NO_GPIO, + std::string("/dev/spidev2.0"), SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, + SUS::MAX1227_SPI_FREQ); + SpiCookie* spiCookieSus7 = new SpiCookie(addresses::SUS_7, gpio::NO_GPIO, + std::string("/dev/spidev2.0"), SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, + SUS::MAX1227_SPI_FREQ); + SpiCookie* spiCookieSus8 = new SpiCookie(addresses::SUS_8, gpio::NO_GPIO, + std::string("/dev/spidev2.0"), SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, + SUS::MAX1227_SPI_FREQ); + SpiCookie* spiCookieSus9 = new SpiCookie(addresses::SUS_9, gpio::NO_GPIO, + std::string("/dev/spidev2.0"), SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, + SUS::MAX1227_SPI_FREQ); + SpiCookie* spiCookieSus10 = new SpiCookie(addresses::SUS_10, gpio::NO_GPIO, + std::string("/dev/spidev2.0"), SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, + SUS::MAX1227_SPI_FREQ); + SpiCookie* spiCookieSus11 = new SpiCookie(addresses::SUS_11, gpio::NO_GPIO, + std::string("/dev/spidev2.0"), SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, + SUS::MAX1227_SPI_FREQ); + SpiCookie* spiCookieSus12 = new SpiCookie(addresses::SUS_12, gpio::NO_GPIO, + std::string("/dev/spidev2.0"), SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, + SUS::MAX1227_SPI_FREQ); + SpiCookie* spiCookieSus13 = new SpiCookie(addresses::SUS_13, gpio::NO_GPIO, + std::string("/dev/spidev2.0"), SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, + SUS::MAX1227_SPI_FREQ); + + new SusHandler(objects::SUS_1, objects::SPI_COM_IF, spiCookieSus1, gpioComIF, gpioIds::CS_SUS_1); + new SusHandler(objects::SUS_2, objects::SPI_COM_IF, spiCookieSus2, gpioComIF, gpioIds::CS_SUS_2); + new SusHandler(objects::SUS_3, objects::SPI_COM_IF, spiCookieSus3, gpioComIF, gpioIds::CS_SUS_3); + new SusHandler(objects::SUS_4, objects::SPI_COM_IF, spiCookieSus4, gpioComIF, gpioIds::CS_SUS_4); + new SusHandler(objects::SUS_5, objects::SPI_COM_IF, spiCookieSus5, gpioComIF, gpioIds::CS_SUS_5); + new SusHandler(objects::SUS_6, objects::SPI_COM_IF, spiCookieSus6, gpioComIF, gpioIds::CS_SUS_6); + new SusHandler(objects::SUS_7, objects::SPI_COM_IF, spiCookieSus7, gpioComIF, gpioIds::CS_SUS_7); + new SusHandler(objects::SUS_8, objects::SPI_COM_IF, spiCookieSus8, gpioComIF, gpioIds::CS_SUS_8); + new SusHandler(objects::SUS_9, objects::SPI_COM_IF, spiCookieSus9, gpioComIF, gpioIds::CS_SUS_9); + new SusHandler(objects::SUS_10, objects::SPI_COM_IF, spiCookieSus10, gpioComIF, gpioIds::CS_SUS_10); + new SusHandler(objects::SUS_11, objects::SPI_COM_IF, spiCookieSus11, gpioComIF, gpioIds::CS_SUS_11); + new SusHandler(objects::SUS_12, objects::SPI_COM_IF, spiCookieSus12, gpioComIF, gpioIds::CS_SUS_12); + new SusHandler(objects::SUS_13, objects::SPI_COM_IF, spiCookieSus13, gpioComIF, gpioIds::CS_SUS_13); + #if OBSW_ADD_ACS_BOARD == 1 GpioCookie* gpioCookieAcsBoard = new GpioCookie(); GpiodRegular* gpio = nullptr; - gpio = new GpiodRegular(std::string("gpiochip5"), 1, std::string("CS_GYRO_1_ADIS"), + gpio = new GpiodRegular(std::string("gpiochip5"), 1, std::string("CS_GYRO_0_ADIS"), gpio::OUT, gpio::HIGH); gpioCookieAcsBoard->addGpio(gpioIds::GYRO_0_ADIS_CS, gpio); - gpio = new GpiodRegular(std::string("gpiochip5"), 7, std::string("CS_GYRO_2_L3G"), + gpio = new GpiodRegular(std::string("gpiochip5"), 7, std::string("CS_GYRO_1_L3G"), gpio::OUT, gpio::HIGH); gpioCookieAcsBoard->addGpio(gpioIds::GYRO_1_L3G_CS, gpio); - gpio = new GpiodRegular(std::string("gpiochip5"), 3, std::string("CS_GYRO_3_L3G"), + gpio = new GpiodRegular(std::string("gpiochip5"), 3, std::string("CS_GYRO_2_L3G"), gpio::OUT, gpio::HIGH); gpioCookieAcsBoard->addGpio(gpioIds::GYRO_2_L3G_CS, gpio); @@ -164,7 +279,7 @@ void ObjectFactory::produce(){ gpio::OUT, gpio::HIGH); gpioCookieAcsBoard->addGpio(gpioIds::MGM_0_LIS3_CS, gpio); - gpio = new GpiodRegular(std::string("gpiochip5"), 17, std::string("CS_MGM_1_RM3100_A"), + gpio = new GpiodRegular(std::string("gpiochip5"), 16, std::string("CS_MGM_1_RM3100_A"), gpio::OUT, gpio::HIGH); gpioCookieAcsBoard->addGpio(gpioIds::MGM_1_RM3100_CS, gpio); @@ -197,13 +312,31 @@ void ObjectFactory::produce(){ objects::SPI_COM_IF, spiCookie); mgmRm3100Handler->setStartUpImmediately(); + spiCookie = new SpiCookie(addresses::MGM_3_RM3100, gpioIds::MGM_3_RM3100_CS, spiDev, + RM3100::MAX_BUFFER_SIZE, spi::DEFAULT_RM3100_MODE, spi::DEFAULT_RM3100_SPEED); + mgmRm3100Handler = new MGMHandlerRM3100(objects::MGM_3_RM3100_HANDLER, + objects::SPI_COM_IF, spiCookie); + mgmRm3100Handler->setStartUpImmediately(); + + //TODO: Adis Gyro (Gyro 0 Side A) + + /* Gyro 1 Side A */ spiCookie = new SpiCookie(addresses::GYRO_1_L3G, gpioIds::GYRO_1_L3G_CS, spiDev, L3GD20H::MAX_BUFFER_SIZE, spi::DEFAULT_L3G_MODE, spi::DEFAULT_L3G_SPEED); auto gyroL3gHandler = new GyroHandlerL3GD20H(objects::GYRO_1_L3G_HANDLER, objects::SPI_COM_IF, spiCookie); gyroL3gHandler->setStartUpImmediately(); + + /* Gyro 2 Side B */ + spiCookie = new SpiCookie(addresses::GYRO_2_L3G, gpioIds::GYRO_2_L3G_CS, spiDev, + L3GD20H::MAX_BUFFER_SIZE, spi::DEFAULT_L3G_MODE, spi::DEFAULT_L3G_SPEED); + gyroL3gHandler = new GyroHandlerL3GD20H(objects::GYRO_2_L3G_HANDLER, objects::SPI_COM_IF, + spiCookie); + gyroL3gHandler->setStartUpImmediately(); #endif + GpioCookie* heaterGpiosCookie = new GpioCookie; + /* Pin H2-11 on stack connector */ GpiodRegular* gpioConfigHeater0 = new GpiodRegular(std::string("gpiochip7"), 6, std::string("Heater0"), gpio::OUT, 0); @@ -406,17 +539,25 @@ void ObjectFactory::produce(){ #endif /* Q7S_ADD_RTD_DEVICES == 1 */ + I2cCookie* imtqI2cCookie = new I2cCookie(addresses::IMTQ, IMTQ::MAX_REPLY_SIZE, + std::string("/dev/i2c-0")); + IMTQHandler* imtqHandler = new IMTQHandler(objects::IMTQ_HANDLER, objects::I2C_COM_IF, imtqI2cCookie); +// imtqHandler->setStartUpImmediately(); + (void) imtqHandler; + + UartCookie* plocUartCookie = new UartCookie(std::string("/dev/ttyUL3"), 115200, + PLOC::MAX_REPLY_SIZE); + PlocHandler* plocHandler = new PlocHandler(objects::PLOC_HANDLER, objects::UART_COM_IF, + plocUartCookie); +// plocHandler->setStartUpImmediately(); + (void) plocHandler; + #endif /* TE0720 == 0 */ new UdpTmTcBridge(objects::UDP_BRIDGE, objects::CCSDS_PACKET_DISTRIBUTOR, objects::TM_STORE, objects::TC_STORE); new UdpTcPollingTask(objects::UDP_POLLING_TASK, objects::UDP_BRIDGE); - I2cCookie* imtqI2cCookie = new I2cCookie(addresses::IMTQ, IMTQ::MAX_REPLY_SIZE, - std::string("/dev/i2c-0")); - IMTQHandler* imtqHandler = new IMTQHandler(objects::IMTQ_HANDLER, objects::I2C_COM_IF, imtqI2cCookie); - imtqHandler->setStartUpImmediately(); - #if TE0720 == 1 && TEST_LIBGPIOD == 1 /* Configure MIO0 as input */ GpiodRegular gpioConfigMio0(std::string("gpiochip0"), 0, @@ -424,13 +565,55 @@ void ObjectFactory::produce(){ GpioCookie* gpioCookie = new GpioCookie; gpioCookie->addGpio(gpioIds::TEST_ID_0, gpioConfigMio0); new LibgpiodTest(objects::LIBGPIOD_TEST, objects::GPIO_IF, gpioCookie); -#elif TE0720 == 1 +#endif + +#if TE0720 == 1 && TEST_SUS_HANDLER == 1 + GpioCookie* gpioCookieSus = new GpioCookie; + GpiodRegular* chipSelectSus = new GpiodRegular(std::string("gpiochip1"), 9, + std::string("Chip Select Sus Sensor"), gpio::OUT, 1); + gpioCookieSus->addGpio(gpioIds::CS_SUS_1, chipSelectSus); + gpioComIF->addGpios(gpioCookieSus); + + SpiCookie* spiCookieSus = new SpiCookie(addresses::SUS_1, std::string("/dev/spidev1.0"), + SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, spi::DEFAULT_MAX_1227_SPEED); + + SusHandler* sus1 = new SusHandler(objects::SUS_1, objects::SPI_COM_IF, spiCookieSus, gpioComIF, + gpioIds::CS_SUS_1); + sus1->setStartUpImmediately(); +#endif + +#if TE0720 == 1 && TEST_RADIATION_SENSOR_HANDLER == 1 + GpioCookie* gpioCookieRadSensor = new GpioCookie; + GpiodRegular* chipSelectRadSensor = new GpiodRegular(std::string("gpiochip1"), 0, + std::string("Chip select radiation sensor"), gpio::OUT, 1); + gpioCookieRadSensor->addGpio(gpioIds::CS_RAD_SENSOR, chipSelectRadSensor); + gpioComIF->addGpios(gpioCookieRadSensor); + + SpiCookie* spiCookieRadSensor = new SpiCookie(addresses::RAD_SENSOR, gpioIds::CS_RAD_SENSOR, + std::string("/dev/spidev1.0"), SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, + spi::DEFAULT_MAX_1227_SPEED); + + RadiationSensorHandler* radSensor = new RadiationSensorHandler(objects::RAD_SENSOR, + objects::SPI_COM_IF, spiCookieRadSensor); + radSensor->setStartUpImmediately(); +#endif + +#if TE0720 == 1 && TEST_PLOC_HANDLER == 1 + UartCookie* plocUartCookie = new UartCookie(std::string("/dev/ttyPS1"), 115200, + PLOC::MAX_REPLY_SIZE); + /* Testing PlocHandler on TE0720-03-1CFA */ + PlocHandler* plocHandler = new PlocHandler(objects::PLOC_HANDLER, objects::UART_COM_IF, + plocUartCookie); + plocHandler->setStartUpImmediately(); +#endif + +#if TE0720 == 1 && TE0720_HEATER_TEST == 1 /* Configuration for MIO0 on TE0720-03-1CFA */ - GpiodRegular gpioConfigForDummyHeater(std::string("gpiochip0"), 0, - std::string("Heater0"), gpio::OUT, 0); - heaterGpiosCookie->addGpio(gpioIds::HEATER_0, gpioConfigForDummyHeater); - new HeaterHandler(objects::HEATER_HANDLER, objects::GPIO_IF, heaterGpiosCookie, - objects::PCDU_HANDLER, pcduSwitches::TCS_BOARD_8V_HEATER_IN); + GpiodRegular* heaterGpio = new GpiodRegular(std::string("gpiochip0"), 0, std::string("MIO0"), gpio::IN, 0); + GpioCookie* gpioCookie = new GpioCookie; + gpioCookie->addGpio(gpioIds::HEATER_0, heaterGpio); + new HeaterHandler(objects::HEATER_HANDLER, objects::GPIO_IF, gpioCookie, objects::PCDU_HANDLER, + pcduSwitches::TCS_BOARD_8V_HEATER_IN); #endif #if Q7S_ADD_SPI_TEST == 1 diff --git a/bsp_q7s/devices/HeaterHandler.cpp b/bsp_q7s/devices/HeaterHandler.cpp index 21a4a3f4..6c5af7be 100644 --- a/bsp_q7s/devices/HeaterHandler.cpp +++ b/bsp_q7s/devices/HeaterHandler.cpp @@ -58,8 +58,9 @@ ReturnValue_t HeaterHandler::initialize() { if(mainLineSwitcherObjectId != objects::NO_OBJECT) { mainLineSwitcher = objectManager->get(mainLineSwitcherObjectId); if (mainLineSwitcher == nullptr) { - sif::error << "HeaterHandler::initialize: Main line switcher failed to fetch object" - << "from object ID." << std::endl; + sif::error + << "HeaterHandler::initialize: Failed to get main line switcher. Make sure " + << "main line switcher object is initialized." << std::endl; return ObjectManagerIF::CHILD_INIT_FAILED; } } diff --git a/bsp_q7s/gpio/gpioCallbacks.cpp b/bsp_q7s/gpio/gpioCallbacks.cpp index 086e6469..2f59cb0e 100644 --- a/bsp_q7s/gpio/gpioCallbacks.cpp +++ b/bsp_q7s/gpio/gpioCallbacks.cpp @@ -10,31 +10,32 @@ namespace gpioCallbacks { GpioIF* gpioComInterface; -void initTcsBoardDecoder(GpioIF* gpioComIF) { +void initSpiCsDecoder(GpioIF* gpioComIF) { ReturnValue_t result; if (gpioComIF == nullptr) { - sif::debug << "initTcsBoardDecoder: Invalid gpioComIF" << std::endl; + sif::debug << "initSpiCsDecoder: Invalid gpioComIF" << std::endl; return; } gpioComInterface = gpioComIF; GpioCookie* spiMuxGpios = new GpioCookie; - /** - * Initial values of the spi mux gpios can all be set to an arbitrary value expect for spi mux - * bit 1. Setting spi mux bit 1 to high will pull all decoder outputs to high voltage level. - */ + + /** Setting mux bit 1 to low will disable IC21 on the interface board */ GpiodRegular* spiMuxBit1 = new GpiodRegular(std::string("gpiochip7"), 13, - std::string("SPI Mux Bit 1"), gpio::OUT, 1); + std::string("SPI Mux Bit 1"), gpio::OUT, 0); spiMuxGpios->addGpio(gpioIds::SPI_MUX_BIT_1, spiMuxBit1); + /** Setting mux bit 2 to low disables IC1 on the TCS board */ GpiodRegular* spiMuxBit2 = new GpiodRegular(std::string("gpiochip7"), 14, std::string("SPI Mux Bit 2"), gpio::OUT, 0); spiMuxGpios->addGpio(gpioIds::SPI_MUX_BIT_2, spiMuxBit2); + /** Setting mux bit 3 to low disables IC2 on the TCS board and IC22 on the interface board */ GpiodRegular* spiMuxBit3 = new GpiodRegular(std::string("gpiochip7"), 15, std::string("SPI Mux Bit 3"), gpio::OUT, 0); spiMuxGpios->addGpio(gpioIds::SPI_MUX_BIT_3, spiMuxBit3); + /** The following gpios can take arbitrary initial values */ GpiodRegular* spiMuxBit4 = new GpiodRegular(std::string("gpiochip7"), 16, std::string("SPI Mux Bit 4"), gpio::OUT, 0); spiMuxGpios->addGpio(gpioIds::SPI_MUX_BIT_4, spiMuxBit4); @@ -47,175 +48,261 @@ void initTcsBoardDecoder(GpioIF* gpioComIF) { result = gpioComInterface->addGpios(spiMuxGpios); if (result != HasReturnvaluesIF::RETURN_OK) { - sif::error << "initTcsBoardDecoder: Failed to add mux bit gpios to gpioComIF" + sif::error << "initSpiCsDecoder: Failed to add mux bit gpios to gpioComIF" << std::endl; return; } } -void tcsBoardDecoderCallback(gpioId_t gpioId, gpio::GpioOperation gpioOp, int value, +void spiCsDecoderCallback(gpioId_t gpioId, gpio::GpioOperation gpioOp, int value, void* args) { if (gpioComInterface == nullptr) { - sif::debug << "tcsBoardDecoderCallback: No gpioComIF specified. Call initTcsBoardDecoder " + sif::debug << "spiCsDecoderCallback: No gpioComIF specified. Call initSpiCsDecoder " << "to specify gpioComIF" << std::endl; return; } - /* Read is not supported by the callback function */ + /* Reading is not supported by the callback function */ if (gpioOp == gpio::GpioOperation::READ) { return; } if (value == 1) { - /* This will pull all 16 decoder outputs to high */ - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_1); + disableAllDecoder(); } else if (value == 0) { switch (gpioId) { case(gpioIds::RTD_IC3): { - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_2); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_3); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_4); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_5); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_6); + enableDecoderTcsIc1(); + selectY7(); break; } case(gpioIds::RTD_IC4): { - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_2); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_3); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_4); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_5); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_6); + enableDecoderTcsIc1(); + selectY6(); break; } case(gpioIds::RTD_IC5): { - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_2); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_3); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_4); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_5); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_6); + enableDecoderTcsIc1(); + selectY5(); break; } case(gpioIds::RTD_IC6): { - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_2); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_3); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_4); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_5); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_6); + enableDecoderTcsIc1(); + selectY4(); break; } case(gpioIds::RTD_IC7): { - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_2); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_3); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_4); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_5); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_6); + enableDecoderTcsIc1(); + selectY3(); break; } case(gpioIds::RTD_IC8): { - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_2); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_3); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_4); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_5); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_6); + enableDecoderTcsIc1(); + selectY2(); break; } case(gpioIds::RTD_IC9): { - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_2); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_3); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_4); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_5); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_6); + enableDecoderTcsIc1(); + selectY1(); break; } case(gpioIds::RTD_IC10): { - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_2); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_3); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_4); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_5); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_6); + enableDecoderTcsIc1(); + selectY0(); break; } case(gpioIds::RTD_IC11): { - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_3); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_4); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_5); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_6); + enableDecoderTcsIc2(); + selectY7(); break; } case(gpioIds::RTD_IC12): { - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_3); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_4); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_5); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_6); + enableDecoderTcsIc2(); + selectY6(); break; } case(gpioIds::RTD_IC13): { - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_3); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_4); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_5); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_6); + enableDecoderTcsIc2(); + selectY5(); break; } case(gpioIds::RTD_IC14): { - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_3); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_4); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_5); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_6); + enableDecoderTcsIc2(); + selectY4(); break; } case(gpioIds::RTD_IC15): { - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_3); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_4); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_5); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_6); + enableDecoderTcsIc2(); + selectY3(); break; } case(gpioIds::RTD_IC16): { - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_3); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_4); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_5); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_6); + enableDecoderTcsIc2(); + selectY2(); break; } case(gpioIds::RTD_IC17): { - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_3); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_4); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_5); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_6); + enableDecoderTcsIc2(); + selectY1(); break; } case(gpioIds::RTD_IC18): { - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1); - gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_3); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_4); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_5); - gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_6); + enableDecoderTcsIc2(); + selectY0(); + break; + } + case(gpioIds::CS_SUS_1): { + enableDecoderInterfaceBoardIc1(); + selectY0(); + break; + } + case(gpioIds::CS_SUS_2): { + enableDecoderInterfaceBoardIc1(); + selectY1(); + break; + } + case(gpioIds::CS_SUS_3): { + enableDecoderInterfaceBoardIc2(); + selectY0(); + break; + } + case(gpioIds::CS_SUS_4): { + enableDecoderInterfaceBoardIc2(); + selectY1(); + break; + } + case(gpioIds::CS_SUS_5): { + enableDecoderInterfaceBoardIc2(); + selectY2(); + break; + } + case(gpioIds::CS_SUS_6): { + enableDecoderInterfaceBoardIc1(); + selectY2(); + break; + } + case(gpioIds::CS_SUS_7): { + enableDecoderInterfaceBoardIc1(); + selectY3(); + break; + } + case(gpioIds::CS_SUS_8): { + enableDecoderInterfaceBoardIc2(); + selectY3(); + break; + } + case(gpioIds::CS_SUS_9): { + enableDecoderInterfaceBoardIc1(); + selectY4(); + break; + } + case(gpioIds::CS_SUS_10): { + enableDecoderInterfaceBoardIc1(); + selectY5(); + break; + } + case(gpioIds::CS_SUS_11): { + enableDecoderInterfaceBoardIc2(); + selectY4(); + break; + } + case(gpioIds::CS_SUS_12): { + enableDecoderInterfaceBoardIc2(); + selectY5(); + break; + } + case(gpioIds::CS_SUS_13): { + enableDecoderInterfaceBoardIc1(); + selectY6(); break; } default: - sif::debug << "tcsBoardDecoderCallback: Invalid gpioid " << gpioId << std::endl; + sif::debug << "spiCsDecoderCallback: Invalid gpio id " << gpioId << std::endl; } } else { - sif::debug << "tcsBoardDecoderCallback: Invalid value. Must be 0 or 1" << std::endl; + sif::debug << "spiCsDecoderCallback: Invalid value. Must be 0 or 1" << std::endl; } } +void enableDecoderTcsIc1() { + gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1); + gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_2); + gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_3); +} + +void enableDecoderTcsIc2() { + gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1); + gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_2); + gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_3); +} + +void enableDecoderInterfaceBoardIc1() { + gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_1); + gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_2); + gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_3); +} + +void enableDecoderInterfaceBoardIc2() { + gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_1); + gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_2); + gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_3); +} + +void selectY0() { + gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_4); + gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_5); + gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_6); +} + +void selectY1() { + gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_4); + gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_5); + gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_6); +} + +void selectY2() { + gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_4); + gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_5); + gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_6); +} + +void selectY3() { + gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_4); + gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_5); + gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_6); +} + +void selectY4() { + gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_4); + gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_5); + gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_6); +} + +void selectY5() { + gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_4); + gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_5); + gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_6); +} + +void selectY6() { + gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_4); + gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_5); + gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_6); +} + +void selectY7() { + gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_4); + gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_5); + gpioComInterface->pullHigh(gpioIds::SPI_MUX_BIT_6); +} + +void disableAllDecoder() { + gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_1); + gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_2); + gpioComInterface->pullLow(gpioIds::SPI_MUX_BIT_3); +} + } diff --git a/bsp_q7s/gpio/gpioCallbacks.h b/bsp_q7s/gpio/gpioCallbacks.h index 845127fb..4a0c73cb 100644 --- a/bsp_q7s/gpio/gpioCallbacks.h +++ b/bsp_q7s/gpio/gpioCallbacks.h @@ -9,15 +9,54 @@ namespace gpioCallbacks { /** * @brief This function initializes the GPIOs used to control the SN74LVC138APWR decoders on - * the TCS Board. + * the TCS Board and the interface board. */ - void initTcsBoardDecoder(GpioIF* gpioComIF); + void initSpiCsDecoder(GpioIF* gpioComIF); /** - * @brief This function implements the decoding to multiply gpios by using the two decoder - * chips SN74LVC138APWR on the TCS board. + * @brief This function implements the decoding to multiply gpios by using the decoder + * chips SN74LVC138APWR on the TCS board and the interface board. */ - void tcsBoardDecoderCallback(gpioId_t gpioId, gpio::GpioOperation gpioOp, int value, void* args); + void spiCsDecoderCallback(gpioId_t gpioId, gpio::GpioOperation gpioOp, int value, void* args); + + /** + * @brief This function sets mux bits 1-3 to a state which will only enable the decoder + * on the TCS board which is named to IC1 in the schematic. + */ + void enableDecoderTcsIc1(); + + /** + * @brief This function sets mux bits 1-3 to a state which will only enable the decoder + * on the TCS board which is named to IC2 in the schematic. + */ + void enableDecoderTcsIc2(); + + /** + * @brief This function sets mux bits 1-3 to a state which will only enable the decoder + * on the inteface board board which is named to IC21 in the schematic. + */ + void enableDecoderInterfaceBoardIc1(); + + /** + * @brief This function sets mux bits 1-3 to a state which will only enable the decoder + * on the inteface board board which is named to IC22 in the schematic. + */ + void enableDecoderInterfaceBoardIc2(); + + /** + * @brief This function disables all decoder. + */ + void disableAllDecoder(); + + /** The following functions enable the appropriate channel of the currently enabled decoder */ + void selectY0(); + void selectY1(); + void selectY2(); + void selectY3(); + void selectY4(); + void selectY5(); + void selectY6(); + void selectY7(); } #endif /* LINUX_GPIO_GPIOCALLBACKS_H_ */ diff --git a/bsp_q7s/main.cpp b/bsp_q7s/main.cpp index b087e315..06f454c2 100644 --- a/bsp_q7s/main.cpp +++ b/bsp_q7s/main.cpp @@ -1,6 +1,7 @@ #include "InitMission.h" #include #include +#include "OBSWConfig.h" #include @@ -13,7 +14,11 @@ int main(void) { std::cout << "-- EIVE OBSW --" << std::endl; +#if TE0720 == 0 std::cout << "-- Compiled for Linux (Xiphos Q7S) --" << std::endl; +#else + std::cout << "-- Compiled for Linux (TE0720) --" << std::endl; +#endif std::cout << "-- Software version " << SW_NAME << " v" << SW_VERSION << "." << SW_SUBVERSION << "." << SW_SUBSUBVERSION << " -- " << std::endl; std::cout << "-- " << __DATE__ << " " << __TIME__ << " --" << std::endl; diff --git a/etl b/etl new file mode 160000 index 00000000..ae06e641 --- /dev/null +++ b/etl @@ -0,0 +1 @@ +Subproject commit ae06e6417702b770c49289c9e7162cb3f4a5a217 diff --git a/fsfw b/fsfw index d7d24bd9..ac027e3f 160000 --- a/fsfw +++ b/fsfw @@ -1 +1 @@ -Subproject commit d7d24bd9aac7522eb096ea9138eb61559fde9012 +Subproject commit ac027e3ff22b609fe63096275a135babc8f76253 diff --git a/fsfwconfig/OBSWConfig.h b/fsfwconfig/OBSWConfig.h index f3f7cda3..9426d01b 100644 --- a/fsfwconfig/OBSWConfig.h +++ b/fsfwconfig/OBSWConfig.h @@ -16,19 +16,25 @@ /* These defines should be disabled for mission code but are useful for debugging. */ -#define OBSW_VERBOSE_LEVEL 1 -#define OBSW_PRINT_MISSED_DEADLINES 1 -#define OBSW_ADD_TEST_CODE 1 -#define TEST_LIBGPIOD 0 +#define OBSW_VERBOSE_LEVEL 1 +#define OBSW_PRINT_MISSED_DEADLINES 1 +#define OBSW_ADD_TEST_CODE 1 +#define TEST_LIBGPIOD 0 +#define TEST_RADIATION_SENSOR_HANDLER 1 +#define TEST_SUS_HANDLER 1 +#define TEST_PLOC_HANDLER 0 #define TE0720 0 +#define TE0720_HEATER_TEST 0 #define P60DOCK_DEBUG 0 #define PDU1_DEBUG 0 #define PDU2_DEBUG 0 #define ACU_DEBUG 0 #define SYRLINKS_DEBUG 0 -#define IMQT_DEBUG 1 +#define IMQT_DEBUG 0 +#define DEBUG_RAD_SENSOR 1 +#define DEBUG_SUS 1 #include "OBSWVersion.h" diff --git a/fsfwconfig/devices/addresses.h b/fsfwconfig/devices/addresses.h index 4974834d..3de3a105 100644 --- a/fsfwconfig/devices/addresses.h +++ b/fsfwconfig/devices/addresses.h @@ -19,6 +19,22 @@ namespace addresses { GYRO_1_L3G = objects::GYRO_1_L3G_HANDLER, GYRO_2_L3G = objects::GYRO_2_L3G_HANDLER, + RAD_SENSOR = objects::RAD_SENSOR, + + SUS_1 = objects::SUS_1, + SUS_2 = objects::SUS_2, + SUS_3 = objects::SUS_3, + SUS_4 = objects::SUS_4, + SUS_5 = objects::SUS_5, + SUS_6 = objects::SUS_6, + SUS_7 = objects::SUS_7, + SUS_8 = objects::SUS_8, + SUS_9 = objects::SUS_9, + SUS_10 = objects::SUS_10, + SUS_11 = objects::SUS_11, + SUS_12 = objects::SUS_12, + SUS_13 = objects::SUS_13, + /* Dummy and Test Addresses */ DUMMY_ECHO = 129, DUMMY_GPS0 = 130, diff --git a/fsfwconfig/devices/gpioIds.h b/fsfwconfig/devices/gpioIds.h index ac999152..3221c613 100644 --- a/fsfwconfig/devices/gpioIds.h +++ b/fsfwconfig/devices/gpioIds.h @@ -44,12 +44,28 @@ namespace gpioIds { RTD_IC17, RTD_IC18, + CS_SUS_1, + CS_SUS_2, + CS_SUS_3, + CS_SUS_4, + CS_SUS_5, + CS_SUS_6, + CS_SUS_7, + CS_SUS_8, + CS_SUS_9, + CS_SUS_10, + CS_SUS_11, + CS_SUS_12, + CS_SUS_13, + SPI_MUX_BIT_1, SPI_MUX_BIT_2, SPI_MUX_BIT_3, SPI_MUX_BIT_4, SPI_MUX_BIT_5, - SPI_MUX_BIT_6 + SPI_MUX_BIT_6, + + CS_RAD_SENSOR }; } diff --git a/fsfwconfig/devices/spi.h b/fsfwconfig/devices/spi.h index 55271a40..eb17786b 100644 --- a/fsfwconfig/devices/spi.h +++ b/fsfwconfig/devices/spi.h @@ -20,6 +20,9 @@ static constexpr spi::SpiModes DEFAULT_RM3100_MODE = spi::SpiModes::MODE_3; static constexpr uint32_t DEFAULT_L3G_SPEED = 3'900'000; static constexpr spi::SpiModes DEFAULT_L3G_MODE = spi::SpiModes::MODE_3; +static constexpr uint32_t DEFAULT_MAX_1227_SPEED = 3'900'000; +static constexpr spi::SpiModes DEFAULT_MAX_1227_MODE = spi::SpiModes::MODE_3; + } diff --git a/fsfwconfig/events/subsystemIdRanges.h b/fsfwconfig/events/subsystemIdRanges.h index b2e9aaac..b33ee807 100644 --- a/fsfwconfig/events/subsystemIdRanges.h +++ b/fsfwconfig/events/subsystemIdRanges.h @@ -21,7 +21,8 @@ enum: uint8_t { MGM_RM3100, PCDU_HANDLER, HEATER_HANDLER, - SA_DEPL_HANDLER + SA_DEPL_HANDLER, + PLOC_HANDLER }; } diff --git a/fsfwconfig/objects/systemObjectList.h b/fsfwconfig/objects/systemObjectList.h index 110b5c17..746e83cf 100644 --- a/fsfwconfig/objects/systemObjectList.h +++ b/fsfwconfig/objects/systemObjectList.h @@ -52,6 +52,22 @@ namespace objects { GYRO_2_L3G_HANDLER = 0x44000013, IMTQ_HANDLER = 0x44000014, + PLOC_HANDLER = 0x44000015, + + + SUS_1 = 0x44000016, + SUS_2 = 0x44000017, + SUS_3 = 0x44000018, + SUS_4 = 0x44000019, + SUS_5 = 0x4400001A, + SUS_6 = 0x4400001B, + SUS_7 = 0x4400001C, + SUS_8 = 0x4400001D, + SUS_9 = 0x4400001E, + SUS_10 = 0x4400001F, + SUS_11 = 0x44000021, + SUS_12 = 0x44000022, + SUS_13 = 0x44000023, /* Custom device handler */ PCDU_HANDLER = 0x44001000, @@ -81,6 +97,8 @@ namespace objects { RTD_IC17 = 0x5400003F, RTD_IC18 = 0x5400004F, + RAD_SENSOR = 0x54000050, + /* 0x54 ('T') for test handlers */ TEST_TASK = 0x54694269, LIBGPIOD_TEST = 0x54123456, diff --git a/fsfwconfig/pollingsequence/pollingSequenceFactory.cpp b/fsfwconfig/pollingsequence/pollingSequenceFactory.cpp index 02e6b625..1199ae2c 100644 --- a/fsfwconfig/pollingsequence/pollingSequenceFactory.cpp +++ b/fsfwconfig/pollingsequence/pollingSequenceFactory.cpp @@ -5,13 +5,14 @@ #include #include #include +#include +#include ReturnValue_t pst::pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence) { /* Length of a communication cycle */ uint32_t length = thisSequence->getPeriodMs(); - thisSequence->addSlot(objects::TMP1075_HANDLER_1, length * 0, DeviceHandlerIF::PERFORM_OPERATION); thisSequence->addSlot(objects::TMP1075_HANDLER_2, length * 0, @@ -40,6 +41,7 @@ ReturnValue_t pst::pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence) #endif /* Q7S_ADD_RTD_DEVICES */ thisSequence->addSlot(objects::IMTQ_HANDLER, length * 0, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::PLOC_HANDLER, length * 0, DeviceHandlerIF::PERFORM_OPERATION); thisSequence->addSlot(objects::TMP1075_HANDLER_1, length * 0.2, DeviceHandlerIF::SEND_WRITE); thisSequence->addSlot(objects::TMP1075_HANDLER_2, length * 0.2, DeviceHandlerIF::SEND_WRITE); @@ -64,6 +66,7 @@ ReturnValue_t pst::pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence) #endif /* Q7S_ADD_RTD_DEVICES */ thisSequence->addSlot(objects::IMTQ_HANDLER, length * 0.2, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::PLOC_HANDLER, length * 0.2, DeviceHandlerIF::SEND_WRITE); thisSequence->addSlot(objects::TMP1075_HANDLER_1, length * 0.4, DeviceHandlerIF::GET_WRITE); thisSequence->addSlot(objects::TMP1075_HANDLER_2, length * 0.4, DeviceHandlerIF::GET_WRITE); @@ -85,9 +88,11 @@ ReturnValue_t pst::pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence) thisSequence->addSlot(objects::RTD_IC16, length * 0.4, DeviceHandlerIF::GET_WRITE); thisSequence->addSlot(objects::RTD_IC17, length * 0.4, DeviceHandlerIF::GET_WRITE); thisSequence->addSlot(objects::RTD_IC18, length * 0.4, DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::IMTQ_HANDLER, length * 0.4, DeviceHandlerIF::GET_WRITE); #endif /* Q7S_ADD_RTD_DEVICES */ + thisSequence->addSlot(objects::IMTQ_HANDLER, length * 0.4, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::PLOC_HANDLER, length * 0.4, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::TMP1075_HANDLER_1, length * 0.6, DeviceHandlerIF::SEND_READ); thisSequence->addSlot(objects::TMP1075_HANDLER_2, length * 0.6, DeviceHandlerIF::SEND_READ); @@ -111,6 +116,7 @@ ReturnValue_t pst::pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence) #endif /* Q7S_ADD_RTD_DEVICES */ thisSequence->addSlot(objects::IMTQ_HANDLER, length * 0.6, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::PLOC_HANDLER, length * 0.6, DeviceHandlerIF::SEND_READ); thisSequence->addSlot(objects::TMP1075_HANDLER_1, length * 0.8, DeviceHandlerIF::GET_READ); thisSequence->addSlot(objects::TMP1075_HANDLER_2, length * 0.8, DeviceHandlerIF::GET_READ); @@ -135,6 +141,276 @@ ReturnValue_t pst::pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence) #endif /* Q7S_ADD_RTD_DEVICES */ thisSequence->addSlot(objects::IMTQ_HANDLER, length * 0.8, DeviceHandlerIF::GET_READ); + thisSequence->addSlot(objects::PLOC_HANDLER, length * 0.8, DeviceHandlerIF::GET_READ); + + + /* 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); + + if (length != 3000) { + sif::warning << "pollingSequenceInitDefault: Frequency changed. Make sure timing critical " + << "SUS sensors still produce correct values" << std::endl; + } + + /** + * The sun sensor will be shutdown as soon as the chip select is pulled high. Thus all + * requests to a sun sensor must be performed consecutively. Another reason for calling multiple + * device handler cycles is that the ADC conversions take some time. Thus first the ADC + * conversions are initiated and in a next step the results can be read from the internal FIFO. + * One sun sensor communication sequence also blocks the SPI bus. So other devices can not be + * inserted between the device handler cycles of one SUS. + */ + + /* Write setup */ + thisSequence->addSlot(objects::SUS_1, length * 0.9, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_1, length * 0.9, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_1, length * 0.9, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_1, length * 0.9, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_1, length * 0.9, DeviceHandlerIF::GET_READ); + /* Write setup */ + thisSequence->addSlot(objects::SUS_1, length * 0.901, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_1, length * 0.901, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_1, length * 0.901, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_1, length * 0.901, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_1, length * 0.901, DeviceHandlerIF::GET_READ); + /* Write setup */ + thisSequence->addSlot(objects::SUS_1, length * 0.902, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_1, length * 0.902, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_1, length * 0.902, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_1, length * 0.902, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_1, length * 0.902, DeviceHandlerIF::GET_READ); + + /* Write setup */ + thisSequence->addSlot(objects::SUS_2, length * 0.903, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_2, length * 0.903, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_2, length * 0.903, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_2, length * 0.903, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_2, length * 0.903, DeviceHandlerIF::GET_READ); + /* Write setup */ + thisSequence->addSlot(objects::SUS_2, length * 0.904, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_2, length * 0.904, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_2, length * 0.904, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_2, length * 0.904, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_2, length * 0.904, DeviceHandlerIF::GET_READ); + /* Write setup */ + thisSequence->addSlot(objects::SUS_2, length * 0.905, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_2, length * 0.905, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_2, length * 0.905, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_2, length * 0.905, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_2, length * 0.905, DeviceHandlerIF::GET_READ); + + /* Write setup */ + thisSequence->addSlot(objects::SUS_3, length * 0.906, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_3, length * 0.906, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_3, length * 0.906, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_3, length * 0.906, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_3, length * 0.906, DeviceHandlerIF::GET_READ); + /* Write setup */ + thisSequence->addSlot(objects::SUS_3, length * 0.907, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_3, length * 0.907, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_3, length * 0.907, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_3, length * 0.907, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_3, length * 0.907, DeviceHandlerIF::GET_READ); + /* Write setup */ + thisSequence->addSlot(objects::SUS_3, length * 0.908, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_3, length * 0.908, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_3, length * 0.908, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_3, length * 0.908, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_3, length * 0.908, DeviceHandlerIF::GET_READ); + + /* Write setup */ + thisSequence->addSlot(objects::SUS_4, length * 0.909, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_4, length * 0.909, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_4, length * 0.909, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_4, length * 0.909, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_4, length * 0.909, DeviceHandlerIF::GET_READ); + /* Write setup */ + thisSequence->addSlot(objects::SUS_4, length * 0.91, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_4, length * 0.91, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_4, length * 0.91, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_4, length * 0.91, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_4, length * 0.91, DeviceHandlerIF::GET_READ); + /* Write setup */ + thisSequence->addSlot(objects::SUS_4, length * 0.911, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_4, length * 0.911, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_4, length * 0.911, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_4, length * 0.911, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_4, length * 0.911, DeviceHandlerIF::GET_READ); + + /* Write setup */ + thisSequence->addSlot(objects::SUS_5, length * 0.912, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_5, length * 0.912, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_5, length * 0.912, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_5, length * 0.912, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_5, length * 0.912, DeviceHandlerIF::GET_READ); + /* Write setup */ + thisSequence->addSlot(objects::SUS_5, length * 0.913, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_5, length * 0.913, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_5, length * 0.913, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_5, length * 0.913, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_5, length * 0.913, DeviceHandlerIF::GET_READ); + /* Write setup */ + thisSequence->addSlot(objects::SUS_5, length * 0.914, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_5, length * 0.914, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_5, length * 0.914, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_5, length * 0.914, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_5, length * 0.914, DeviceHandlerIF::GET_READ); + + /* Write setup */ + thisSequence->addSlot(objects::SUS_6, length * 0.915, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_6, length * 0.915, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_6, length * 0.915, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_6, length * 0.915, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_6, length * 0.915, DeviceHandlerIF::GET_READ); + /* Start ADC conversions */ + thisSequence->addSlot(objects::SUS_6, length * 0.916, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_6, length * 0.916, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::SUS_6, length * 0.916, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_6, length * 0.916, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_6, length * 0.916, DeviceHandlerIF::GET_READ); + /* Read ADC conversions from inernal FIFO */ + thisSequence->addSlot(objects::SUS_6, length * 0.917, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_6, length * 0.917, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::SUS_6, length * 0.917, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_6, length * 0.917, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_6, length * 0.917, DeviceHandlerIF::GET_READ); + + /* Write setup */ + thisSequence->addSlot(objects::SUS_7, length * 0.918, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_7, length * 0.918, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_7, length * 0.918, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_7, length * 0.918, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_7, length * 0.918, DeviceHandlerIF::GET_READ); + /* Start ADC conversions */ + thisSequence->addSlot(objects::SUS_7, length * 0.919, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_7, length * 0.919, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::SUS_7, length * 0.919, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_7, length * 0.919, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_7, length * 0.919, DeviceHandlerIF::GET_READ); + /* Read ADC conversions from inernal FIFO */ + thisSequence->addSlot(objects::SUS_7, length * 0.92, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_7, length * 0.92, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::SUS_7, length * 0.92, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_7, length * 0.92, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_7, length * 0.92, DeviceHandlerIF::GET_READ); + + /* Write setup */ + thisSequence->addSlot(objects::SUS_8, length * 0.921, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_8, length * 0.921, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_8, length * 0.921, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_8, length * 0.921, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_8, length * 0.921, DeviceHandlerIF::GET_READ); + /* Start ADC conversions */ + thisSequence->addSlot(objects::SUS_8, length * 0.922, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_8, length * 0.922, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::SUS_8, length * 0.922, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_8, length * 0.922, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_8, length * 0.922, DeviceHandlerIF::GET_READ); + /* Read ADC conversions from inernal FIFO */ + thisSequence->addSlot(objects::SUS_8, length * 0.923, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_8, length * 0.923, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::SUS_8, length * 0.923, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_8, length * 0.923, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_8, length * 0.923, DeviceHandlerIF::GET_READ); + + /* Write setup */ + thisSequence->addSlot(objects::SUS_9, length * 0.924, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_9, length * 0.924, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_9, length * 0.924, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_9, length * 0.924, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_9, length * 0.924, DeviceHandlerIF::GET_READ); + /* Start ADC conversions */ + thisSequence->addSlot(objects::SUS_9, length * 0.925, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_9, length * 0.925, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::SUS_9, length * 0.925, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_9, length * 0.925, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_9, length * 0.925, DeviceHandlerIF::GET_READ); + /* Read ADC conversions */ + thisSequence->addSlot(objects::SUS_9, length * 0.926, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_9, length * 0.926, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::SUS_9, length * 0.926, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_9, length * 0.926, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_9, length * 0.926, DeviceHandlerIF::GET_READ); + + /* Write setup */ + thisSequence->addSlot(objects::SUS_10, length * 0.927, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_10, length * 0.927, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_10, length * 0.927, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_10, length * 0.927, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_10, length * 0.927, DeviceHandlerIF::GET_READ); + /* Start ADC conversions */ + thisSequence->addSlot(objects::SUS_10, length * 0.928, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_10, length * 0.928, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::SUS_10, length * 0.928, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_10, length * 0.928, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_10, length * 0.928, DeviceHandlerIF::GET_READ); + /* Read ADC conversions */ + thisSequence->addSlot(objects::SUS_10, length * 0.929, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_10, length * 0.929, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::SUS_10, length * 0.929, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_10, length * 0.929, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_10, length * 0.929, DeviceHandlerIF::GET_READ); + + /* Write setup */ + thisSequence->addSlot(objects::SUS_11, length * 0.93, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_11, length * 0.93, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_11, length * 0.93, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_11, length * 0.93, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_11, length * 0.93, DeviceHandlerIF::GET_READ); + /* Start ADC conversions */ + thisSequence->addSlot(objects::SUS_11, length * 0.931, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_11, length * 0.931, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::SUS_11, length * 0.931, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_11, length * 0.931, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_11, length * 0.931, DeviceHandlerIF::GET_READ); + /* Read ADC conversions */ + thisSequence->addSlot(objects::SUS_11, length * 0.932, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_11, length * 0.932, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::SUS_11, length * 0.932, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_11, length * 0.932, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_11, length * 0.932, DeviceHandlerIF::GET_READ); + + /* Write setup */ + thisSequence->addSlot(objects::SUS_12, length * 0.933, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_12, length * 0.933, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_12, length * 0.933, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_12, length * 0.933, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_12, length * 0.933, DeviceHandlerIF::GET_READ); + /* Start ADC conversions */ + thisSequence->addSlot(objects::SUS_12, length * 0.934, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_12, length * 0.934, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::SUS_12, length * 0.934, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_12, length * 0.934, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_12, length * 0.934, DeviceHandlerIF::GET_READ); + /* Read ADC conversions */ + thisSequence->addSlot(objects::SUS_12, length * 0.935, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_12, length * 0.935, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::SUS_12, length * 0.935, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_12, length * 0.935, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_12, length * 0.935, DeviceHandlerIF::GET_READ); + + /* Write setup */ + thisSequence->addSlot(objects::SUS_13, length * 0.936, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_13, length * 0.936, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_13, length * 0.936, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_13, length * 0.936, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_13, length * 0.936, DeviceHandlerIF::GET_READ); + /* Start ADC conversions */ + thisSequence->addSlot(objects::SUS_13, length * 0.937, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_13, length * 0.937, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::SUS_13, length * 0.937, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_13, length * 0.937, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_13, length * 0.937, DeviceHandlerIF::GET_READ); + /* Read ADC conversions */ + thisSequence->addSlot(objects::SUS_13, length * 0.938, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_13, length * 0.938, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::SUS_13, length * 0.938, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_13, length * 0.938, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_13, length * 0.938, DeviceHandlerIF::GET_READ); if (thisSequence->checkSequence() == HasReturnvaluesIF::RETURN_OK) { return HasReturnvaluesIF::RETURN_OK; @@ -196,27 +472,27 @@ ReturnValue_t pst::gomspacePstInit(FixedTimeslotTaskIF *thisSequence){ length * 0.8, DeviceHandlerIF::GET_READ); #if OBSW_ADD_ACS_BOARD == 1 -// thisSequence->addSlot(objects::MGM_0_LIS3_HANDLER, length * 0, -// DeviceHandlerIF::PERFORM_OPERATION); -// thisSequence->addSlot(objects::MGM_0_LIS3_HANDLER, length * 0.2, -// DeviceHandlerIF::SEND_WRITE); -// thisSequence->addSlot(objects::MGM_0_LIS3_HANDLER, length * 0.4, -// DeviceHandlerIF::GET_WRITE); -// thisSequence->addSlot(objects::MGM_0_LIS3_HANDLER, length * 0.6, -// DeviceHandlerIF::SEND_READ); -// thisSequence->addSlot(objects::MGM_0_LIS3_HANDLER, length * 0.8, -// DeviceHandlerIF::GET_READ); -// -// thisSequence->addSlot(objects::MGM_1_RM3100_HANDLER, length * 0, -// DeviceHandlerIF::PERFORM_OPERATION); -// thisSequence->addSlot(objects::MGM_1_RM3100_HANDLER, length * 0.2, -// DeviceHandlerIF::SEND_WRITE); -// thisSequence->addSlot(objects::MGM_1_RM3100_HANDLER, length * 0.4, -// DeviceHandlerIF::GET_WRITE); -// thisSequence->addSlot(objects::MGM_1_RM3100_HANDLER, length * 0.6, -// DeviceHandlerIF::SEND_READ); -// thisSequence->addSlot(objects::MGM_1_RM3100_HANDLER, length * 0.8, -// DeviceHandlerIF::GET_READ); + thisSequence->addSlot(objects::MGM_0_LIS3_HANDLER, length * 0, + DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::MGM_0_LIS3_HANDLER, length * 0.2, + DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::MGM_0_LIS3_HANDLER, length * 0.4, + DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::MGM_0_LIS3_HANDLER, length * 0.6, + DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::MGM_0_LIS3_HANDLER, length * 0.8, + DeviceHandlerIF::GET_READ); + + thisSequence->addSlot(objects::MGM_1_RM3100_HANDLER, length * 0, + DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::MGM_1_RM3100_HANDLER, length * 0.2, + DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::MGM_1_RM3100_HANDLER, length * 0.4, + DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::MGM_1_RM3100_HANDLER, length * 0.6, + DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::MGM_1_RM3100_HANDLER, length * 0.8, + DeviceHandlerIF::GET_READ); thisSequence->addSlot(objects::MGM_2_LIS3_HANDLER, length * 0, DeviceHandlerIF::PERFORM_OPERATION); @@ -229,16 +505,42 @@ ReturnValue_t pst::gomspacePstInit(FixedTimeslotTaskIF *thisSequence){ thisSequence->addSlot(objects::MGM_2_LIS3_HANDLER, length * 0.8, DeviceHandlerIF::GET_READ); -// thisSequence->addSlot(objects::GYRO_1_L3G_HANDLER, length * 0, -// DeviceHandlerIF::PERFORM_OPERATION); -// thisSequence->addSlot(objects::GYRO_1_L3G_HANDLER, length * 0.2, -// DeviceHandlerIF::SEND_WRITE); -// thisSequence->addSlot(objects::GYRO_1_L3G_HANDLER, length * 0.4, -// DeviceHandlerIF::GET_WRITE); -// thisSequence->addSlot(objects::GYRO_1_L3G_HANDLER, length * 0.6, -// DeviceHandlerIF::SEND_READ); -// thisSequence->addSlot(objects::GYRO_1_L3G_HANDLER, length * 0.8, -// DeviceHandlerIF::GET_READ); + + thisSequence->addSlot(objects::GYRO_1_L3G_HANDLER, length * 0, + DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::GYRO_1_L3G_HANDLER, length * 0.2, + DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::GYRO_1_L3G_HANDLER, length * 0.4, + DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::GYRO_1_L3G_HANDLER, length * 0.6, + DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::GYRO_1_L3G_HANDLER, length * 0.8, + DeviceHandlerIF::GET_READ); + + + thisSequence->addSlot(objects::GYRO_2_L3G_HANDLER, length * 0, + DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::GYRO_2_L3G_HANDLER, length * 0.2, + DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::GYRO_2_L3G_HANDLER, length * 0.4, + DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::GYRO_2_L3G_HANDLER, length * 0.6, + DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::GYRO_2_L3G_HANDLER, length * 0.8, + DeviceHandlerIF::GET_READ); + + + thisSequence->addSlot(objects::MGM_3_RM3100_HANDLER, length * 0, + DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::MGM_3_RM3100_HANDLER, length * 0.2, + DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::MGM_3_RM3100_HANDLER, length * 0.4, + DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::MGM_3_RM3100_HANDLER, length * 0.6, + DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::MGM_3_RM3100_HANDLER, length * 0.8, + DeviceHandlerIF::GET_READ); + #endif if (thisSequence->checkSequence() != HasReturnvaluesIF::RETURN_OK) { @@ -248,44 +550,52 @@ ReturnValue_t pst::gomspacePstInit(FixedTimeslotTaskIF *thisSequence){ return HasReturnvaluesIF::RETURN_OK; } -ReturnValue_t pst::pollingSequenceAcsTest(FixedTimeslotTaskIF *thisSequence) { +ReturnValue_t pst::pollingSequenceTE0720(FixedTimeslotTaskIF *thisSequence) { uint32_t length = thisSequence->getPeriodMs(); - thisSequence->addSlot(objects::MGM_0_LIS3_HANDLER, length * 0, - DeviceHandlerIF::PERFORM_OPERATION); - thisSequence->addSlot(objects::MGM_0_LIS3_HANDLER, length * 0.2, - DeviceHandlerIF::SEND_WRITE); - thisSequence->addSlot(objects::MGM_0_LIS3_HANDLER, length * 0.4, - DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::MGM_0_LIS3_HANDLER, length * 0.6, - DeviceHandlerIF::SEND_READ); - thisSequence->addSlot(objects::MGM_0_LIS3_HANDLER, length * 0.8, - DeviceHandlerIF::GET_READ); +#if TEST_PLOC_HANDLER == 1 + thisSequence->addSlot(objects::PLOC_HANDLER, length * 0, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::PLOC_HANDLER, length * 0.2, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::PLOC_HANDLER, length * 0.4, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::PLOC_HANDLER, length * 0.6, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::PLOC_HANDLER, length * 0.8, DeviceHandlerIF::GET_READ); +#endif - thisSequence->addSlot(objects::MGM_1_RM3100_HANDLER, length * 0, - DeviceHandlerIF::PERFORM_OPERATION); - thisSequence->addSlot(objects::MGM_1_RM3100_HANDLER, length * 0.2, - DeviceHandlerIF::SEND_WRITE); - thisSequence->addSlot(objects::MGM_1_RM3100_HANDLER, length * 0.4, - DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::MGM_1_RM3100_HANDLER, length * 0.6, - DeviceHandlerIF::SEND_READ); - thisSequence->addSlot(objects::MGM_1_RM3100_HANDLER, length * 0.8, - DeviceHandlerIF::GET_READ); +#if TEST_RADIATION_SENSOR_HANDLER == 1 + 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 TEST_SUS_HANDLER == 1 + /* Write setup */ + thisSequence->addSlot(objects::SUS_1, length * 0.901, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_1, length * 0.902, SusHandler::FIRST_WRITE); + thisSequence->addSlot(objects::SUS_1, length * 0.903, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_1, length * 0.904, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_1, length * 0.905, DeviceHandlerIF::GET_READ); + + /* Start conversion*/ + thisSequence->addSlot(objects::SUS_1, length * 0.906, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_1, length * 0.907, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::SUS_1, length * 0.908, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_1, length * 0.909, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_1, length * 0.91, DeviceHandlerIF::GET_READ); + + /* Read conversions */ + thisSequence->addSlot(objects::SUS_1, length * 0.911, DeviceHandlerIF::PERFORM_OPERATION); + thisSequence->addSlot(objects::SUS_1, length * 0.912, DeviceHandlerIF::SEND_WRITE); + thisSequence->addSlot(objects::SUS_1, length * 0.913, DeviceHandlerIF::GET_WRITE); + thisSequence->addSlot(objects::SUS_1, length * 0.914, DeviceHandlerIF::SEND_READ); + thisSequence->addSlot(objects::SUS_1, length * 0.915, DeviceHandlerIF::GET_READ); +#endif - thisSequence->addSlot(objects::GYRO_1_L3G_HANDLER, length * 0, - DeviceHandlerIF::PERFORM_OPERATION); - thisSequence->addSlot(objects::GYRO_1_L3G_HANDLER, length * 0.2, - DeviceHandlerIF::SEND_WRITE); - thisSequence->addSlot(objects::GYRO_1_L3G_HANDLER, length * 0.4, - DeviceHandlerIF::GET_WRITE); - thisSequence->addSlot(objects::GYRO_1_L3G_HANDLER, length * 0.6, - DeviceHandlerIF::SEND_READ); - thisSequence->addSlot(objects::GYRO_1_L3G_HANDLER, length * 0.8, - DeviceHandlerIF::GET_READ); if (thisSequence->checkSequence() != HasReturnvaluesIF::RETURN_OK) { - sif::error << "Initialization of ACS Board PST failed" << std::endl; + sif::error << "Initialization of TE0720 PST failed" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } return HasReturnvaluesIF::RETURN_OK; } + diff --git a/fsfwconfig/pollingsequence/pollingSequenceFactory.h b/fsfwconfig/pollingsequence/pollingSequenceFactory.h index 09dd7242..73cdc0bb 100644 --- a/fsfwconfig/pollingsequence/pollingSequenceFactory.h +++ b/fsfwconfig/pollingsequence/pollingSequenceFactory.h @@ -35,6 +35,11 @@ ReturnValue_t pollingSequenceInitDefault(FixedTimeslotTaskIF *thisSequence); ReturnValue_t gomspacePstInit(FixedTimeslotTaskIF *thisSequence); ReturnValue_t pollingSequenceAcsTest(FixedTimeslotTaskIF* thisSequence); + +/** + * @brief This polling sequence will be created when the software is compiled for the TE0720. + */ +ReturnValue_t pollingSequenceTE0720(FixedTimeslotTaskIF* thisSequence); } diff --git a/fsfwconfig/returnvalues/classIds.h b/fsfwconfig/returnvalues/classIds.h index 93349596..50bb3cea 100644 --- a/fsfwconfig/returnvalues/classIds.h +++ b/fsfwconfig/returnvalues/classIds.h @@ -20,6 +20,8 @@ enum { SA_DEPL_HANDLER, SYRLINKS_HANDLER, IMTQ_HANDLER, + PLOC_HANDLER, + SUS_HANDLER }; } diff --git a/linux/uart/UartComIF.cpp b/linux/uart/UartComIF.cpp index 79470a45..8d9a15c3 100644 --- a/linux/uart/UartComIF.cpp +++ b/linux/uart/UartComIF.cpp @@ -363,6 +363,9 @@ ReturnValue_t UartComIF::readReceivedMessage(CookieIF *cookie, *buffer = uartDeviceMapIter->second.replyBuffer.data(); *size = uartDeviceMapIter->second.replyLen; + /* Length is reset to 0 to prevent reading the same data twice */ + uartDeviceMapIter->second.replyLen = 0; + return RETURN_OK; } diff --git a/mission/devices/CMakeLists.txt b/mission/devices/CMakeLists.txt index 6e8518b0..9965fedc 100644 --- a/mission/devices/CMakeLists.txt +++ b/mission/devices/CMakeLists.txt @@ -13,6 +13,9 @@ target_sources(${TARGET_NAME} PUBLIC SyrlinksHkHandler.cpp Max31865PT1000Handler.cpp IMTQHandler.cpp + PlocHandler.cpp + RadiationSensorHandler.cpp + SusHandler.cpp ) diff --git a/mission/devices/IMTQHandler.cpp b/mission/devices/IMTQHandler.cpp index 0c1b1d1e..3111c39d 100644 --- a/mission/devices/IMTQHandler.cpp +++ b/mission/devices/IMTQHandler.cpp @@ -6,7 +6,8 @@ #include IMTQHandler::IMTQHandler(object_id_t objectId, object_id_t comIF, CookieIF * comCookie) : - DeviceHandlerBase(objectId, comIF, comCookie), engHkDataset(this) { + DeviceHandlerBase(objectId, comIF, comCookie), engHkDataset(this), calMtmMeasurementSet( + this), rawMtmMeasurementSet(this) { if (comCookie == NULL) { sif::error << "IMTQHandler: Invalid com cookie" << std::endl; } @@ -20,6 +21,7 @@ void IMTQHandler::doStartUp(){ if(mode == _MODE_START_UP){ //TODO: Set to MODE_ON again setMode(MODE_NORMAL); + communicationStep = CommunicationStep::SELF_TEST; } } @@ -29,7 +31,34 @@ void IMTQHandler::doShutDown(){ ReturnValue_t IMTQHandler::buildNormalDeviceCommand( DeviceCommandId_t * id) { - *id = IMTQ::GET_ENG_HK_DATA; + switch (communicationStep) { + case CommunicationStep::SELF_TEST: +// *id = IMTQ::SELF_TEST; +//TODO: Implementing self test command. On-hold because of issue with humidity in clean +// room + communicationStep = CommunicationStep::GET_ENG_HK_DATA; + break; + case CommunicationStep::GET_ENG_HK_DATA: + *id = IMTQ::GET_ENG_HK_DATA; + communicationStep = CommunicationStep::START_MTM_MEASUREMENT; + break; + case CommunicationStep::START_MTM_MEASUREMENT: + *id = IMTQ::START_MTM_MEASUREMENT; + communicationStep = CommunicationStep::GET_CAL_MTM_MEASUREMENT; + break; + case CommunicationStep::GET_CAL_MTM_MEASUREMENT: + *id = IMTQ::GET_CAL_MTM_MEASUREMENT; + communicationStep = CommunicationStep::GET_RAW_MTM_MEASUREMENT; + break; + case CommunicationStep::GET_RAW_MTM_MEASUREMENT: + *id = IMTQ::GET_RAW_MTM_MEASUREMENT; + communicationStep = CommunicationStep::GET_ENG_HK_DATA; + break; + default: + sif::debug << "IMTQHandler::buildNormalDeviceCommand: Invalid communication step" + << std::endl; + break; + } return buildCommandFromCommand(*id, NULL, 0); } @@ -42,25 +71,49 @@ ReturnValue_t IMTQHandler::buildCommandFromCommand( DeviceCommandId_t deviceCommand, const uint8_t * commandData, size_t commandDataLen) { switch(deviceCommand) { + case(IMTQ::START_ACTUATION_DIPOLE): { + /* IMTQ expects low byte first */ + commandBuffer[0] = IMTQ::CC::START_ACTUATION_DIPOLE; + commandBuffer[1] = *(commandData + 1); + commandBuffer[2] = *(commandData); + commandBuffer[3] = *(commandData + 3); + commandBuffer[4] = *(commandData + 2); + commandBuffer[5] = *(commandData + 5); + commandBuffer[6] = *(commandData + 4); + commandBuffer[7] = *(commandData + 7); + commandBuffer[8] = *(commandData + 6); + rawPacket = commandBuffer; + rawPacketLen = 9; + return RETURN_OK; + } case(IMTQ::GET_ENG_HK_DATA): { commandBuffer[0] = IMTQ::CC::GET_ENG_HK_DATA; rawPacket = commandBuffer; rawPacketLen = 1; return RETURN_OK; } - case(IMTQ::START_ACTUATION_DIPOLE): { - /* IMTQ expects low byte first */ - commandBuffer[0] = IMTQ::CC::START_ACTUATION_DIPOLE; - commandBuffer[1] = *(commandData + 1); - commandBuffer[2] = *(commandData); - commandBuffer[3] = *(commandData + 3); - commandBuffer[4] = *(commandData + 2); - commandBuffer[5] = *(commandData + 5); - commandBuffer[6] = *(commandData + 4); - commandBuffer[7] = *(commandData + 7); - commandBuffer[8] = *(commandData + 6); + case(IMTQ::GET_COMMANDED_DIPOLE): { + commandBuffer[0] = IMTQ::CC::GET_COMMANDED_DIPOLE; rawPacket = commandBuffer; - rawPacketLen = 9; + rawPacketLen = 1; + return RETURN_OK; + } + case(IMTQ::START_MTM_MEASUREMENT): { + commandBuffer[0] = IMTQ::CC::START_MTM_MEASUREMENT; + rawPacket = commandBuffer; + rawPacketLen = 1; + return RETURN_OK; + } + case(IMTQ::GET_CAL_MTM_MEASUREMENT): { + commandBuffer[0] = IMTQ::CC::GET_CAL_MTM_MEASUREMENT; + rawPacket = commandBuffer; + rawPacketLen = 1; + return RETURN_OK; + } + case(IMTQ::GET_RAW_MTM_MEASUREMENT): { + commandBuffer[0] = IMTQ::CC::GET_RAW_MTM_MEASUREMENT; + rawPacket = commandBuffer; + rawPacketLen = 1; return RETURN_OK; } default: @@ -70,8 +123,18 @@ ReturnValue_t IMTQHandler::buildCommandFromCommand( } void IMTQHandler::fillCommandAndReplyMap() { + this->insertInCommandAndReplyMap(IMTQ::START_ACTUATION_DIPOLE, 1, nullptr, + IMTQ::SIZE_STATUS_REPLY); this->insertInCommandAndReplyMap(IMTQ::GET_ENG_HK_DATA, 1, &engHkDataset, - IMTQ::SIZE_ENG_HK_DATA_REPLY, false, true, IMTQ::SIZE_ENG_HK_DATA_REPLY); + IMTQ::SIZE_ENG_HK_DATA_REPLY); + this->insertInCommandAndReplyMap(IMTQ::GET_COMMANDED_DIPOLE, 1, nullptr, + IMTQ::SIZE_GET_COMMANDED_DIPOLE_REPLY); + this->insertInCommandAndReplyMap(IMTQ::START_MTM_MEASUREMENT, 1, nullptr, + IMTQ::SIZE_STATUS_REPLY); + this->insertInCommandAndReplyMap(IMTQ::GET_CAL_MTM_MEASUREMENT, 1, &calMtmMeasurementSet, + IMTQ::SIZE_GET_CAL_MTM_MEASUREMENT); + this->insertInCommandAndReplyMap(IMTQ::GET_RAW_MTM_MEASUREMENT, 1, &rawMtmMeasurementSet, + IMTQ::SIZE_GET_RAW_MTM_MEASUREMENT); } ReturnValue_t IMTQHandler::scanForReply(const uint8_t *start, @@ -80,10 +143,30 @@ ReturnValue_t IMTQHandler::scanForReply(const uint8_t *start, ReturnValue_t result = RETURN_OK; switch(*start) { + case(IMTQ::CC::START_ACTUATION_DIPOLE): + *foundLen = IMTQ::SIZE_STATUS_REPLY; + *foundId = IMTQ::START_ACTUATION_DIPOLE; + break; + case(IMTQ::CC::START_MTM_MEASUREMENT): + *foundLen = IMTQ::SIZE_STATUS_REPLY; + *foundId = IMTQ::START_MTM_MEASUREMENT; + break; case(IMTQ::CC::GET_ENG_HK_DATA): *foundLen = IMTQ::SIZE_ENG_HK_DATA_REPLY; *foundId = IMTQ::GET_ENG_HK_DATA; break; + case(IMTQ::CC::GET_COMMANDED_DIPOLE): + *foundLen = IMTQ::SIZE_GET_COMMANDED_DIPOLE_REPLY; + *foundId = IMTQ::GET_COMMANDED_DIPOLE; + break; + case(IMTQ::CC::GET_CAL_MTM_MEASUREMENT): + *foundLen = IMTQ::SIZE_GET_CAL_MTM_MEASUREMENT; + *foundId = IMTQ::GET_CAL_MTM_MEASUREMENT; + break; + case(IMTQ::CC::GET_RAW_MTM_MEASUREMENT): + *foundLen = IMTQ::SIZE_GET_RAW_MTM_MEASUREMENT; + *foundId = IMTQ::GET_RAW_MTM_MEASUREMENT; + break; default: sif::debug << "IMTQHandler::scanForReply: Reply contains invalid command code" << std::endl; result = IGNORE_REPLY_DATA; @@ -105,9 +188,22 @@ ReturnValue_t IMTQHandler::interpretDeviceReply(DeviceCommandId_t id, } switch (id) { + case (IMTQ::START_ACTUATION_DIPOLE): + case (IMTQ::START_MTM_MEASUREMENT): + /* Replies only the status byte which is already handled with parseStatusByte */ + break; case (IMTQ::GET_ENG_HK_DATA): fillEngHkDataset(packet); break; + case (IMTQ::GET_COMMANDED_DIPOLE): + handleGetCommandedDipoleReply(packet); + break; + case (IMTQ::GET_CAL_MTM_MEASUREMENT): + fillCalibratedMtmDataset(packet); + break; + case (IMTQ::GET_RAW_MTM_MEASUREMENT): + fillRawMtmDataset(packet); + break; default: { sif::debug << "IMTQHandler::interpretDeviceReply: Unknown device reply id" << std::endl; return DeviceHandlerIF::UNKNOWN_DEVICE_REPLY; @@ -117,22 +213,68 @@ ReturnValue_t IMTQHandler::interpretDeviceReply(DeviceCommandId_t id, return RETURN_OK; } +void IMTQHandler::setNormalDatapoolEntriesInvalid(){ + +} + +uint32_t IMTQHandler::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo){ + return 500; +} + +ReturnValue_t IMTQHandler::initializeLocalDataPool(localpool::DataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) { + + /** Entries of engineering housekeeping dataset */ + localDataPoolMap.emplace(IMTQ::DIGITAL_VOLTAGE_MV, new PoolEntry( { 0 })); + localDataPoolMap.emplace(IMTQ::ANALOG_VOLTAGE_MV, new PoolEntry( { 0 })); + localDataPoolMap.emplace(IMTQ::DIGITAL_CURRENT, new PoolEntry( { 0 })); + localDataPoolMap.emplace(IMTQ::ANALOG_CURRENT, new PoolEntry( { 0 })); + localDataPoolMap.emplace(IMTQ::COIL_X_CURRENT, new PoolEntry( { 0 })); + localDataPoolMap.emplace(IMTQ::COIL_Y_CURRENT, new PoolEntry( { 0 })); + localDataPoolMap.emplace(IMTQ::COIL_Z_CURRENT, new PoolEntry( { 0 })); + localDataPoolMap.emplace(IMTQ::COIL_X_TEMPERATURE, new PoolEntry( { 0 })); + localDataPoolMap.emplace(IMTQ::COIL_Y_TEMPERATURE, new PoolEntry( { 0 })); + localDataPoolMap.emplace(IMTQ::COIL_Z_TEMPERATURE, new PoolEntry( { 0 })); + localDataPoolMap.emplace(IMTQ::MCU_TEMPERATURE, new PoolEntry( { 0 })); + + /** Entries of calibrated MTM measurement dataset */ + localDataPoolMap.emplace(IMTQ::MTM_CAL_X, new PoolEntry( { 0 })); + localDataPoolMap.emplace(IMTQ::MTM_CAL_Y, new PoolEntry( { 0 })); + localDataPoolMap.emplace(IMTQ::MTM_CAL_Z, new PoolEntry( { 0 })); + localDataPoolMap.emplace(IMTQ::ACTUATION_CAL_STATUS, new PoolEntry( { 0 })); + + /** Entries of raw MTM measurement dataset */ + localDataPoolMap.emplace(IMTQ::MTM_RAW_X, new PoolEntry( { 0 })); + localDataPoolMap.emplace(IMTQ::MTM_RAW_Y, new PoolEntry( { 0 })); + localDataPoolMap.emplace(IMTQ::MTM_RAW_Z, new PoolEntry( { 0 })); + localDataPoolMap.emplace(IMTQ::ACTUATION_RAW_STATUS, new PoolEntry( { 0 })); + + return HasReturnvaluesIF::RETURN_OK; +} + ReturnValue_t IMTQHandler::parseStatusByte(const uint8_t* packet) { uint8_t cmdErrorField = *(packet + 1) & 0xF; switch (cmdErrorField) { case 0: return RETURN_OK; case 1: + sif::error << "IMTQHandler::parseStatusByte: Command rejected without reason" << std::endl; return REJECTED_WITHOUT_REASON; case 2: + sif::error << "IMTQHandler::parseStatusByte: Command has invalid command code" << std::endl; return INVALID_COMMAND_CODE; case 3: + sif::error << "IMTQHandler::parseStatusByte: Command has missing parameter" << std::endl; return PARAMETER_MISSING; case 4: + sif::error << "IMTQHandler::parseStatusByte: Command has invalid parameter" << std::endl; return PARAMETER_INVALID; case 5: + sif::error << "IMTQHandler::parseStatusByte: CC unavailable" << std::endl; return CC_UNAVAILABLE; case 7: + sif::error << "IMTQHandler::parseStatusByte: IMQT replied internal processing error" + << std::endl; return INTERNAL_PROCESSING_ERROR; default: sif::error << "IMTQHandler::parseStatusByte: CMD Error field contains unknown error code " @@ -143,36 +285,36 @@ ReturnValue_t IMTQHandler::parseStatusByte(const uint8_t* packet) { void IMTQHandler::fillEngHkDataset(const uint8_t* packet) { uint8_t offset = 2; - engHkDataset.digitalVoltageMv = *(packet + offset + 1) | *(packet + offset); + engHkDataset.digitalVoltageMv = *(packet + offset + 1) << 8 | *(packet + offset); offset += 2; - engHkDataset.analogVoltageMv = *(packet + offset + 1) | *(packet + offset); + engHkDataset.analogVoltageMv = *(packet + offset + 1) << 8 | *(packet + offset); offset += 2; - engHkDataset.digitalCurrentA = (*(packet + offset + 1) | *(packet + offset)) * 0.0001; + engHkDataset.digitalCurrentmA = (*(packet + offset + 1) << 8 | *(packet + offset)) * 0.1; offset += 2; - engHkDataset.analogCurrentA = (*(packet + offset + 1) | *(packet + offset)) * 0.0001; + engHkDataset.analogCurrentmA = (*(packet + offset + 1) << 8 | *(packet + offset)) * 0.1; offset += 2; - engHkDataset.coilXcurrentA = (*(packet + offset + 1) | *(packet + offset)) * 0.0001; + engHkDataset.coilXCurrentmA = (*(packet + offset + 1) << 8 | *(packet + offset)) * 0.1; offset += 2; - engHkDataset.coilYcurrentA = (*(packet + offset + 1) | *(packet + offset)) * 0.0001; + engHkDataset.coilYCurrentmA = (*(packet + offset + 1) << 8 | *(packet + offset)) * 0.1; offset += 2; - engHkDataset.coilZcurrentA = (*(packet + offset + 1) | *(packet + offset)) * 0.0001; + engHkDataset.coilZCurrentmA = (*(packet + offset + 1) << 8 | *(packet + offset)) * 0.1; offset += 2; - engHkDataset.coilXTemperature = (*(packet + offset + 1) | *(packet + offset)); + engHkDataset.coilXTemperature = (*(packet + offset + 1) << 8 | *(packet + offset)); offset += 2; - engHkDataset.coilYTemperature = (*(packet + offset + 1) | *(packet + offset)); + engHkDataset.coilYTemperature = (*(packet + offset + 1) << 8 | *(packet + offset)); offset += 2; - engHkDataset.coilZTemperature = (*(packet + offset + 1) | *(packet + offset)); + engHkDataset.coilZTemperature = (*(packet + offset + 1) << 8 | *(packet + offset)); offset += 2; - engHkDataset.mcuTemperature = (*(packet + offset + 1) | *(packet + offset)); + engHkDataset.mcuTemperature = (*(packet + offset + 1) << 8 | *(packet + offset)); #if OBSW_VERBOSE_LEVEL >= 1 && IMQT_DEBUG == 1 sif::info << "IMTQ digital voltage: " << engHkDataset.digitalVoltageMv << " mV" << std::endl; sif::info << "IMTQ analog voltage: " << engHkDataset.analogVoltageMv << " mV" << std::endl; - sif::info << "IMTQ digital current: " << engHkDataset.digitalCurrentA << " A" << std::endl; - sif::info << "IMTQ analog current: " << engHkDataset.analogCurrentA << " A" << std::endl; - sif::info << "IMTQ coil X current: " << engHkDataset.coilXcurrentA << " A" << std::endl; - sif::info << "IMTQ coil Y current: " << engHkDataset.coilYcurrentA << " A" << std::endl; - sif::info << "IMTQ coil Z current: " << engHkDataset.coilZcurrentA << " A" << std::endl; + sif::info << "IMTQ digital current: " << engHkDataset.digitalCurrentmA << " mA" << std::endl; + sif::info << "IMTQ analog current: " << engHkDataset.analogCurrentmA << " mA" << std::endl; + sif::info << "IMTQ coil X current: " << engHkDataset.coilXCurrentmA << " mA" << std::endl; + sif::info << "IMTQ coil Y current: " << engHkDataset.coilYCurrentmA << " mA" << std::endl; + sif::info << "IMTQ coil Z current: " << engHkDataset.coilZCurrentmA << " mA" << std::endl; sif::info << "IMTQ coil X temperature: " << engHkDataset.coilXTemperature << " °C" << std::endl; sif::info << "IMTQ coil Y temperature: " << engHkDataset.coilYTemperature << " °C" @@ -184,33 +326,93 @@ void IMTQHandler::fillEngHkDataset(const uint8_t* packet) { #endif } -void IMTQHandler::setNormalDatapoolEntriesInvalid(){ - -} - -uint32_t IMTQHandler::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo){ - return 500; -} - -ReturnValue_t IMTQHandler::initializeLocalDataPool(localpool::DataPool& localDataPoolMap, - LocalDataPoolManager& poolManager) { - - localDataPoolMap.emplace(IMTQ::DIGITAL_VOLTAGE_MV, new PoolEntry( { 0 })); - localDataPoolMap.emplace(IMTQ::ANALOG_VOLTAGE_MV, new PoolEntry( { 0 })); - localDataPoolMap.emplace(IMTQ::DIGITAL_CURRENT_A, new PoolEntry( { 0 })); - localDataPoolMap.emplace(IMTQ::ANALOG_CURRENT_A, new PoolEntry( { 0 })); - localDataPoolMap.emplace(IMTQ::COIL_X_CURRENT_A, new PoolEntry( { 0 })); - localDataPoolMap.emplace(IMTQ::COIL_Y_CURRENT_A, new PoolEntry( { 0 })); - localDataPoolMap.emplace(IMTQ::COIL_Z_CURRENT_A, new PoolEntry( { 0 })); - localDataPoolMap.emplace(IMTQ::COIL_X_TEMPERATURE, new PoolEntry( { 0 })); - localDataPoolMap.emplace(IMTQ::COIL_Y_TEMPERATURE, new PoolEntry( { 0 })); - localDataPoolMap.emplace(IMTQ::COIL_Z_TEMPERATURE, new PoolEntry( { 0 })); - localDataPoolMap.emplace(IMTQ::MCU_TEMPERATURE, new PoolEntry( { 0 })); - - return HasReturnvaluesIF::RETURN_OK; -} - void IMTQHandler::setModeNormal() { mode = MODE_NORMAL; } +void IMTQHandler::handleDeviceTM(const uint8_t* data, size_t dataSize, DeviceCommandId_t replyId) { + + if (wiretappingMode == RAW) { + /* Data already sent in doGetRead() */ + return; + } + + DeviceReplyMap::iterator iter = deviceReplyMap.find(replyId); + if (iter == deviceReplyMap.end()) { + sif::debug << "IMTQHandler::handleDeviceTM: Unknown reply id" << std::endl; + return; + } + MessageQueueId_t queueId = iter->second.command->second.sendReplyTo; + + if (queueId == NO_COMMANDER) { + return; + } + + ReturnValue_t result = actionHelper.reportData(queueId, replyId, data, dataSize); + if (result != RETURN_OK) { + sif::debug << "IMTQHandler::handleDeviceTM: Failed to report data" << std::endl; + return; + } +} + +void IMTQHandler::handleGetCommandedDipoleReply(const uint8_t* packet) { + uint8_t tmData[6]; + /* Switching endianess of received dipole values */ + tmData[0] = *(packet + 3); + tmData[1] = *(packet + 2); + tmData[2] = *(packet + 5); + tmData[3] = *(packet + 4); + tmData[4] = *(packet + 7); + tmData[5] = *(packet + 6); + handleDeviceTM(tmData, sizeof(tmData), IMTQ::GET_COMMANDED_DIPOLE); +} + +void IMTQHandler::fillCalibratedMtmDataset(const uint8_t* packet) { + int8_t offset = 2; + calMtmMeasurementSet.mtmXnT = *(packet + offset + 3) << 24 | *(packet + offset + 2) << 16 + | *(packet + offset + 1) << 8 | *(packet + offset); + offset += 4; + calMtmMeasurementSet.mtmYnT = *(packet + offset + 3) << 24 | *(packet + offset + 2) << 16 + | *(packet + offset + 1) << 8 | *(packet + offset); + offset += 4; + calMtmMeasurementSet.mtmZnT = *(packet + offset + 3) << 24 | *(packet + offset + 2) << 16 + | *(packet + offset + 1) << 8 | *(packet + offset); + offset += 4; + calMtmMeasurementSet.coilActuationStatus = (*(packet + offset + 3) << 24) + | (*(packet + offset + 2) << 16) | (*(packet + offset + 1) << 8) | (*(packet + offset)); +#if OBSW_VERBOSE_LEVEL >= 1 && IMQT_DEBUG == 1 + sif::info << "IMTQ calibrated MTM measurement X: " << calMtmMeasurementSet.mtmXnT << " nT" + << std::endl; + sif::info << "IMTQ calibrated MTM measurement Y: " << calMtmMeasurementSet.mtmYnT << " nT" + << std::endl; + sif::info << "IMTQ calibrated MTM measurement Z: " << calMtmMeasurementSet.mtmZnT << " nT" + << std::endl; + sif::info << "IMTQ coil actuation status during MTM measurement: " + << (unsigned int) calMtmMeasurementSet.coilActuationStatus.value << std::endl; +#endif +} + +void IMTQHandler::fillRawMtmDataset(const uint8_t* packet) { + int8_t offset = 2; + rawMtmMeasurementSet.mtmXnT = (*(packet + offset + 3) << 24 | *(packet + offset + 2) << 16 + | *(packet + offset + 1) << 8 | *(packet + offset)) * 7.5; + offset += 4; + rawMtmMeasurementSet.mtmYnT = (*(packet + offset + 3) << 24 | *(packet + offset + 2) << 16 + | *(packet + offset + 1) << 8 | *(packet + offset)) * 7.5; + offset += 4; + rawMtmMeasurementSet.mtmZnT = (*(packet + offset + 3) << 24 | *(packet + offset + 2) << 16 + | *(packet + offset + 1) << 8 | *(packet + offset)) * 7.5; + offset += 4; + rawMtmMeasurementSet.coilActuationStatus = (*(packet + offset + 3) << 24) + | (*(packet + offset + 2) << 16) | (*(packet + offset + 1) << 8) | (*(packet + offset)); +#if OBSW_VERBOSE_LEVEL >= 1 && IMQT_DEBUG == 1 + sif::info << "IMTQ raw MTM measurement X: " << rawMtmMeasurementSet.mtmXnT << " nT" + << std::endl; + sif::info << "IMTQ raw MTM measurement Y: " << rawMtmMeasurementSet.mtmYnT << " nT" + << std::endl; + sif::info << "IMTQ raw MTM measurement Z: " << rawMtmMeasurementSet.mtmZnT << " nT" + << std::endl; + sif::info << "IMTQ coil actuation status during MTM measurement: " + << (unsigned int) rawMtmMeasurementSet.coilActuationStatus.value << std::endl; +#endif +} diff --git a/mission/devices/IMTQHandler.h b/mission/devices/IMTQHandler.h index 2e2a7612..e162c1c6 100644 --- a/mission/devices/IMTQHandler.h +++ b/mission/devices/IMTQHandler.h @@ -52,9 +52,21 @@ private: IMTQ::EngHkDataset engHkDataset; + IMTQ::CalibratedMtmMeasurementSet calMtmMeasurementSet; + IMTQ::RawMtmMeasurementSet rawMtmMeasurementSet; uint8_t commandBuffer[IMTQ::MAX_COMMAND_SIZE]; + enum class CommunicationStep { + SELF_TEST, + GET_ENG_HK_DATA, + START_MTM_MEASUREMENT, + GET_CAL_MTM_MEASUREMENT, + GET_RAW_MTM_MEASUREMENT + }; + + CommunicationStep communicationStep = CommunicationStep::GET_ENG_HK_DATA; + /** * @brief Each reply contains a status byte giving information about a request. This function * parses this byte and returns the associated failure message. @@ -72,6 +84,36 @@ private: * */ void fillEngHkDataset(const uint8_t* packet); + + /** + * @brief This function sends a command reply to the requesting queue. + * + * @param data Pointer to the data to send. + * @param dataSize Size of the data to send. + * @param relplyId Reply id which will be inserted at the beginning of the action message. + */ + void handleDeviceTM(const uint8_t* data, size_t dataSize, DeviceCommandId_t replyId); + + /** + * @brief This function handles the reply containing the commanded dipole. + * + * @param packet Pointer to the reply data. + */ + void handleGetCommandedDipoleReply(const uint8_t* packet); + + /** + * @brief This function parses the reply containing the calibrated MTM measurement and writes + * the values to the appropriate dataset. + * @param packet Pointer to the reply data. + */ + void fillCalibratedMtmDataset(const uint8_t* packet); + + /** + * @brief This function copies the raw MTM measurements to the MTM raw dataset. + * @param packet Pointer to the reply data requested with the GET_RAW_MTM_MEASUREMENTS + * command. + */ + void fillRawMtmDataset(const uint8_t* packet); }; #endif /* MISSION_DEVICES_IMTQHANDLER_H_ */ diff --git a/mission/devices/PlocHandler.cpp b/mission/devices/PlocHandler.cpp new file mode 100644 index 00000000..b0660ba0 --- /dev/null +++ b/mission/devices/PlocHandler.cpp @@ -0,0 +1,498 @@ +#include "PlocHandler.h" + +#include +#include +#include +#include + +PlocHandler::PlocHandler(object_id_t objectId, object_id_t comIF, CookieIF * comCookie) : + DeviceHandlerBase(objectId, comIF, comCookie) { + if (comCookie == NULL) { + sif::error << "PlocHandler: Invalid com cookie" << std::endl; + } +} + +PlocHandler::~PlocHandler() { +} + + +void PlocHandler::doStartUp(){ + if(mode == _MODE_START_UP){ + setMode(MODE_ON); + } +} + +void PlocHandler::doShutDown(){ + +} + +ReturnValue_t PlocHandler::buildNormalDeviceCommand( + DeviceCommandId_t * id) { + return RETURN_OK; +} + +ReturnValue_t PlocHandler::buildTransitionDeviceCommand( + DeviceCommandId_t * id){ + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t PlocHandler::buildCommandFromCommand( + DeviceCommandId_t deviceCommand, const uint8_t * commandData, + size_t commandDataLen) { + switch(deviceCommand) { + case(PLOC::TC_MEM_WRITE): { + return prepareTcMemWriteCommand(commandData, commandDataLen); + } + case(PLOC::TC_MEM_READ): { + return prepareTcMemReadCommand(commandData, commandDataLen); + } + default: + sif::debug << "PlocHandler::buildCommandFromCommand: Command not implemented" << std::endl; + return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; + } + return HasReturnvaluesIF::RETURN_FAILED; +} + +void PlocHandler::fillCommandAndReplyMap() { + this->insertInCommandMap(PLOC::TC_MEM_WRITE); + this->insertInCommandMap(PLOC::TC_MEM_READ); + this->insertInReplyMap(PLOC::ACK_REPORT, 1, nullptr, PLOC::SIZE_ACK_REPORT); + this->insertInReplyMap(PLOC::EXE_REPORT, 3, nullptr, PLOC::SIZE_EXE_REPORT); + this->insertInReplyMap(PLOC::TM_MEMORY_READ_REPORT, 2, nullptr, PLOC::SIZE_TM_MEM_READ_REPORT); +} + +ReturnValue_t PlocHandler::scanForReply(const uint8_t *start, + size_t remainingSize, DeviceCommandId_t *foundId, size_t *foundLen) { + + ReturnValue_t result = RETURN_OK; + + uint16_t apid = (*(start) << 8 | *(start + 1)) & APID_MASK; + + switch(apid) { + case(PLOC::APID_ACK_SUCCESS): + *foundLen = PLOC::SIZE_ACK_REPORT; + *foundId = PLOC::ACK_REPORT; + break; + case(PLOC::APID_ACK_FAILURE): + *foundLen = PLOC::SIZE_ACK_REPORT; + *foundId = PLOC::ACK_REPORT; + break; + case(PLOC::APID_TM_MEMORY_READ_REPORT): + *foundLen = PLOC::SIZE_TM_MEM_READ_REPORT; + *foundId = PLOC::TM_MEMORY_READ_REPORT; + break; + case(PLOC::APID_EXE_SUCCESS): + *foundLen = PLOC::SIZE_EXE_REPORT; + *foundId = PLOC::EXE_REPORT; + break; + case(PLOC::APID_EXE_FAILURE): + *foundLen = PLOC::SIZE_EXE_REPORT; + *foundId = PLOC::EXE_REPORT; + break; + default: { + sif::debug << "PlocHandler::scanForReply: Reply has invalid apid" << std::endl; + *foundLen = remainingSize; + return INVALID_APID; + } + } + + /** + * This should normally never fail. However, this function is also responsible for incrementing + * the packet sequence count why it is called here. + */ + result = checkPacketSequenceCount(start); + + return result; +} + +ReturnValue_t PlocHandler::interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) { + + ReturnValue_t result = RETURN_OK; + + switch (id) { + case PLOC::ACK_REPORT: { + result = handleAckReport(packet); + break; + } + case (PLOC::TM_MEMORY_READ_REPORT): { + result = handleMemoryReadReport(packet); + break; + } + case (PLOC::EXE_REPORT): { + result = handleExecutionReport(packet); + break; + } + default: { + sif::debug << "PlocHandler::interpretDeviceReply: Unknown device reply id" << std::endl; + return DeviceHandlerIF::UNKNOWN_DEVICE_REPLY; + } + } + + return result; +} + +void PlocHandler::setNormalDatapoolEntriesInvalid(){ + +} + +uint32_t PlocHandler::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo){ + return 500; +} + +ReturnValue_t PlocHandler::initializeLocalDataPool(localpool::DataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) { + + return HasReturnvaluesIF::RETURN_OK; +} + +void PlocHandler::setModeNormal() { + mode = MODE_NORMAL; +} + +ReturnValue_t PlocHandler::prepareTcMemWriteCommand(const uint8_t * commandData, + size_t commandDataLen) { + const uint32_t memoryAddress = *(commandData) << 24 | *(commandData + 1) << 16 + | *(commandData + 2) << 8 | *(commandData + 3); + const uint32_t memoryData = *(commandData + 4) << 24 | *(commandData + 5) << 16 + | *(commandData + 6) << 8 | *(commandData + 7); + packetSequenceCount = (packetSequenceCount + 1) & PACKET_SEQUENCE_COUNT_MASK; + PLOC::TcMemWrite tcMemWrite(memoryAddress, memoryData, packetSequenceCount); + if (tcMemWrite.getFullSize() > PLOC::MAX_COMMAND_SIZE) { + sif::debug << "PlocHandler::prepareTcMemWriteCommand: Command too big" << std::endl; + return RETURN_FAILED; + } + memcpy(commandBuffer, tcMemWrite.getWholeData(), tcMemWrite.getFullSize()); + rawPacket = commandBuffer; + rawPacketLen = tcMemWrite.getFullSize(); + nextReplyId = PLOC::ACK_REPORT; + return RETURN_OK; +} + +ReturnValue_t PlocHandler::prepareTcMemReadCommand(const uint8_t * commandData, + size_t commandDataLen) { + const uint32_t memoryAddress = *(commandData) << 24 | *(commandData + 1) << 16 + | *(commandData + 2) << 8 | *(commandData + 3); + packetSequenceCount = (packetSequenceCount + 1) & PACKET_SEQUENCE_COUNT_MASK; + PLOC::TcMemRead tcMemRead(memoryAddress, packetSequenceCount); + if (tcMemRead.getFullSize() > PLOC::MAX_COMMAND_SIZE) { + sif::debug << "PlocHandler::prepareTcMemReadCommand: Command too big" << std::endl; + return RETURN_FAILED; + } + memcpy(commandBuffer, tcMemRead.getWholeData(), tcMemRead.getFullSize()); + rawPacket = commandBuffer; + rawPacketLen = tcMemRead.getFullSize(); + nextReplyId = PLOC::ACK_REPORT; + + return RETURN_OK; +} + +ReturnValue_t PlocHandler::verifyPacket(const uint8_t* start, size_t foundLen) { + + uint16_t receivedCrc = *(start + foundLen - 2) << 8 | *(start + foundLen - 1); + + uint16_t recalculatedCrc = CRC::crc16ccitt(start, foundLen - 2); + + if (receivedCrc != recalculatedCrc) { + return CRC_FAILURE; + } + + return RETURN_OK; +} + +ReturnValue_t PlocHandler::handleAckReport(const uint8_t* data) { + + ReturnValue_t result = RETURN_OK; + + result = verifyPacket(data, PLOC::SIZE_ACK_REPORT); + if(result == CRC_FAILURE) { + sif::error << "PlocHandler::handleAckReport: CRC failure" << std::endl; + nextReplyId = PLOC::NONE; + replyRawReplyIfnotWiretapped(data, PLOC::SIZE_ACK_REPORT); + triggerEvent(CRC_FAILURE_EVENT); + sendFailureReport(PLOC::ACK_REPORT, CRC_FAILURE); + disableAllReplies(); + return IGNORE_REPLY_DATA; + } + + uint16_t apid = (*(data) << 8 | *(data + 1)) & APID_MASK; + + switch(apid) { + case PLOC::APID_ACK_FAILURE: { + //TODO: Interpretation of status field in acknowledgment report + sif::debug << "PlocHandler::handleAckReport: Received Ack failure report" << std::endl; + DeviceCommandId_t commandId = getPendingCommand(); + if (commandId != DeviceHandlerIF::NO_COMMAND_ID) { + triggerEvent(ACK_FAILURE, commandId); + } + sendFailureReport(PLOC::ACK_REPORT, RECEIVED_ACK_FAILURE); + disableAllReplies(); + nextReplyId = PLOC::NONE; + result = IGNORE_REPLY_DATA; + break; + } + case PLOC::APID_ACK_SUCCESS: { + setNextReplyId(); + break; + } + default: { + sif::debug << "PlocHandler::handleAckReport: Invalid APID in Ack report" << std::endl; + result = RETURN_FAILED; + break; + } + } + + return result; +} + +ReturnValue_t PlocHandler::handleExecutionReport(const uint8_t* data) { + + ReturnValue_t result = RETURN_OK; + + result = verifyPacket(data, PLOC::SIZE_EXE_REPORT); + if(result == CRC_FAILURE) { + sif::error << "PlocHandler::handleExecutionReport: CRC failure" << std::endl; + nextReplyId = PLOC::NONE; + return result; + } + + uint16_t apid = (*(data) << 8 | *(data + 1)) & APID_MASK; + + switch (apid) { + case (PLOC::APID_EXE_SUCCESS): { + break; + } + case (PLOC::APID_EXE_FAILURE): { + //TODO: Interpretation of status field in execution report + sif::error << "PlocHandler::handleExecutionReport: Received execution failure report" + << std::endl; + DeviceCommandId_t commandId = getPendingCommand(); + if (commandId != DeviceHandlerIF::NO_COMMAND_ID) { + triggerEvent(EXE_FAILURE, commandId); + } + else { + sif::debug << "PlocHandler::handleExecutionReport: Unknown command id" << std::endl; + } + sendFailureReport(PLOC::EXE_REPORT, RECEIVED_EXE_FAILURE); + disableExeReportReply(); + result = IGNORE_REPLY_DATA; + break; + } + default: { + sif::error << "PlocHandler::handleExecutionReport: Unknown APID" << std::endl; + result = RETURN_FAILED; + break; + } + } + + nextReplyId = PLOC::NONE; + + return result; +} + +ReturnValue_t PlocHandler::handleMemoryReadReport(const uint8_t* data) { + + ReturnValue_t result = RETURN_OK; + + result = verifyPacket(data, PLOC::SIZE_TM_MEM_READ_REPORT); + + if(result == CRC_FAILURE) { + sif::error << "PlocHandler::handleMemoryReadReport: Memory read report has invalid crc" + << std::endl; + } + /** Send data to commanding queue */ + handleDeviceTM(data + PLOC::DATA_FIELD_OFFSET, PLOC::SIZE_MEM_READ_REPORT_DATA, + PLOC::TM_MEMORY_READ_REPORT); + + nextReplyId = PLOC::EXE_REPORT; + + return result; +} + +ReturnValue_t PlocHandler::enableReplyInReplyMap(DeviceCommandMap::iterator command, + uint8_t expectedReplies, bool useAlternateId, + DeviceCommandId_t alternateReplyID) { + + ReturnValue_t result = RETURN_OK; + + uint8_t enabledReplies = 0; + + switch (command->first) { + case PLOC::TC_MEM_WRITE: + enabledReplies = 2; + break; + case PLOC::TC_MEM_READ: { + enabledReplies = 3; + result = DeviceHandlerBase::enableReplyInReplyMap(command, enabledReplies, true, + PLOC::TM_MEMORY_READ_REPORT); + if (result != RETURN_OK) { + sif::debug << "PlocHandler::enableReplyInReplyMap: Reply with id " + << PLOC::TM_MEMORY_READ_REPORT << " not in replyMap" << std::endl; + } + break; + } + default: + sif::debug << "PlocHandler::enableReplyInReplyMap: Unknown command id" << std::endl; + break; + } + + /** + * Every command causes at least one acknowledgment and one execution report. Therefore both + * replies will be enabled here. + */ + result = DeviceHandlerBase::enableReplyInReplyMap(command, + enabledReplies, true, PLOC::ACK_REPORT); + if (result != RETURN_OK) { + sif::debug << "PlocHandler::enableReplyInReplyMap: Reply with id " << PLOC::ACK_REPORT + << " not in replyMap" << std::endl; + } + + result = DeviceHandlerBase::enableReplyInReplyMap(command, + enabledReplies, true, PLOC::EXE_REPORT); + if (result != RETURN_OK) { + sif::debug << "PlocHandler::enableReplyInReplyMap: Reply with id " << PLOC::EXE_REPORT + << " not in replyMap" << std::endl; + } + + return RETURN_OK; +} + +void PlocHandler::setNextReplyId() { + switch(getPendingCommand()) { + case PLOC::TC_MEM_READ: + nextReplyId = PLOC::TM_MEMORY_READ_REPORT; + break; + default: + /* If no telemetry is expected the next reply is always the execution report */ + nextReplyId = PLOC::EXE_REPORT; + break; + } +} +size_t PlocHandler::getNextReplyLength(DeviceCommandId_t commandId){ + + size_t replyLen = 0; + + if (nextReplyId == PLOC::NONE) { + return replyLen; + } + + DeviceReplyIter iter = deviceReplyMap.find(nextReplyId); + if (iter != deviceReplyMap.end()) { + if (iter->second.delayCycles == 0) { + /* Reply inactive */ + return replyLen; + } + replyLen = iter->second.replyLen; + } + else { + sif::debug << "PlocHandler::getNextReplyLength: No entry for reply with reply id " + << std::hex << nextReplyId << " in deviceReplyMap" << std::endl; + } + + return replyLen; +} + +void PlocHandler::handleDeviceTM(const uint8_t* data, size_t dataSize, DeviceCommandId_t replyId) { + + ReturnValue_t result = RETURN_OK; + + if (wiretappingMode == RAW) { + /* Data already sent in doGetRead() */ + return; + } + + DeviceReplyMap::iterator iter = deviceReplyMap.find(replyId); + if (iter == deviceReplyMap.end()) { + sif::debug << "PlocHandler::handleDeviceTM: Unknown reply id" << std::endl; + return; + } + MessageQueueId_t queueId = iter->second.command->second.sendReplyTo; + + if (queueId == NO_COMMANDER) { + return; + } + + result = actionHelper.reportData(queueId, replyId, data, dataSize); + if (result != RETURN_OK) { + sif::debug << "PlocHandler::handleDeviceTM: Failed to report data" << std::endl; + } +} + +void PlocHandler::disableAllReplies() { + + DeviceReplyMap::iterator iter; + + /* Disable ack reply */ + iter = deviceReplyMap.find(PLOC::ACK_REPORT); + DeviceReplyInfo *info = &(iter->second); + info->delayCycles = 0; + info->command = deviceCommandMap.end(); + + DeviceCommandId_t commandId = getPendingCommand(); + + /* If the command expects a telemetry packet the appropriate tm reply will be disabled here */ + switch (commandId) { + case PLOC::TC_MEM_WRITE: + break; + case PLOC::TC_MEM_READ: { + iter = deviceReplyMap.find(PLOC::TM_MEMORY_READ_REPORT); + info = &(iter->second); + info->delayCycles = 0; + info->command = deviceCommandMap.end(); + break; + } + default: { + sif::debug << "PlocHandler::disableAllReplies: Unknown command id" << commandId + << std::endl; + break; + } + } + + /* We must always disable the execution report reply here */ + disableExeReportReply(); +} + +void PlocHandler::sendFailureReport(DeviceCommandId_t replyId, ReturnValue_t status) { + + DeviceReplyIter iter = deviceReplyMap.find(replyId); + + if (iter == deviceReplyMap.end()) { + sif::debug << "PlocHandler::sendFailureReport: Reply not in reply map" << std::endl; + return; + } + + DeviceCommandInfo* info = &(iter->second.command->second); + + if (info == nullptr) { + sif::debug << "PlocHandler::sendFailureReport: Reply has no active command" << std::endl; + return; + } + + if (info->sendReplyTo != NO_COMMANDER) { + actionHelper.finish(false, info->sendReplyTo, iter->first, status); + } + info->isExecuting = false; +} + +void PlocHandler::disableExeReportReply() { + DeviceReplyIter iter = deviceReplyMap.find(PLOC::EXE_REPORT); + DeviceReplyInfo *info = &(iter->second); + info->delayCycles = 0; + info->command = deviceCommandMap.end(); + /* Expected replies is set to one here. The value will set to 0 in replyToReply() */ + info->command->second.expectedReplies = 0; +} + +ReturnValue_t PlocHandler::checkPacketSequenceCount(const uint8_t* data) { + uint16_t receivedSequenceCount = (*(data + 2) << 8 | *(data + 3)) & PACKET_SEQUENCE_COUNT_MASK; + uint16_t expectedPacketSequenceCount = ((packetSequenceCount + 1) & PACKET_SEQUENCE_COUNT_MASK); + if (receivedSequenceCount != expectedPacketSequenceCount) { + sif::debug + << "PlocHandler::checkPacketSequenceCount: Packet sequence count mismatch. " + << std::endl; + sif::debug << "Received sequence count: " << receivedSequenceCount << ". OBSW sequence " + << "count: " << expectedPacketSequenceCount << std::endl; + } + packetSequenceCount = receivedSequenceCount; + return RETURN_OK; +} diff --git a/mission/devices/PlocHandler.h b/mission/devices/PlocHandler.h new file mode 100644 index 00000000..06965d0f --- /dev/null +++ b/mission/devices/PlocHandler.h @@ -0,0 +1,201 @@ +#ifndef MISSION_DEVICES_PLOCHANDLER_H_ +#define MISSION_DEVICES_PLOCHANDLER_H_ + +#include +#include +#include + +/** + * @brief This is the device handler for the PLOC. + * + * @details The PLOC uses the space packet protocol for communication. To each command the PLOC + * answers with at least one acknowledgment and one execution report. + * + * @author J. Meier + */ +class PlocHandler: public DeviceHandlerBase { +public: + + PlocHandler(object_id_t objectId, object_id_t comIF, CookieIF * comCookie); + virtual ~PlocHandler(); + + /** + * @brief Sets mode to MODE_NORMAL. Can be used for debugging. + */ + void setModeNormal(); + +protected: + void doStartUp() override; + void doShutDown() 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; + void setNormalDatapoolEntriesInvalid() override; + uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) override; + ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) override; + ReturnValue_t enableReplyInReplyMap(DeviceCommandMap::iterator command, + uint8_t expectedReplies = 1, bool useAlternateId = false, + DeviceCommandId_t alternateReplyID = 0) override; + size_t getNextReplyLength(DeviceCommandId_t deviceCommand) override; + +private: + + static const uint8_t INTERFACE_ID = CLASS_ID::PLOC_HANDLER; + + static const ReturnValue_t CRC_FAILURE = MAKE_RETURN_CODE(0xA0); //!> Space Packet received from PLOC has invalid CRC + static const ReturnValue_t RECEIVED_ACK_FAILURE = MAKE_RETURN_CODE(0xA1); //!> Received ACK failure reply from PLOC + static const ReturnValue_t RECEIVED_EXE_FAILURE = MAKE_RETURN_CODE(0xA2); //!> Received execution failure reply from PLOC + static const ReturnValue_t INVALID_APID = MAKE_RETURN_CODE(0xA3); //!> Received space packet with invalid APID from PLOC + + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PLOC_HANDLER; + + static const Event MEMORY_READ_RPT_CRC_FAILURE = MAKE_EVENT(1, severity::LOW); //!> PLOC crc failure in telemetry packet + static const Event ACK_FAILURE = MAKE_EVENT(2, severity::LOW); //!> PLOC receive acknowledgment failure report + static const Event EXE_FAILURE = MAKE_EVENT(3, severity::LOW); //!> PLOC receive execution failure report + static const Event CRC_FAILURE_EVENT = MAKE_EVENT(4, severity::LOW); //!> PLOC reply has invalid crc + + static const uint16_t APID_MASK = 0x7FF; + static const uint16_t PACKET_SEQUENCE_COUNT_MASK = 0x3FFF; + + uint8_t commandBuffer[PLOC::MAX_COMMAND_SIZE]; + + /** + * @brief This object is incremented each time a packet is sent or received. By checking the + * packet sequence count of a received packet, no packets can be lost without noticing + * it. Only the least significant 14 bits represent the packet sequence count in a + * space packet. Thus the maximum value amounts to 16383 (0x3FFF). + * @note Normally this should never happen because the PLOC replies are always sent in a + * fixed order. However, the PLOC software checks this value and will return an ACK + * failure report in case the sequence count is not incremented with each transferred + * space packet. + */ + uint16_t packetSequenceCount = 0x3FFF; + + /** + * This variable is used to store the id of the next reply to receive. This is necessary + * because the PLOC sends as reply to each command at least one acknowledgment and execution + * report. + */ + DeviceCommandId_t nextReplyId = PLOC::NONE; + + /** + * @brief This function fills the commandBuffer to initiate the write memory command. + * + * @param commandData Pointer to action command data. + * @param commanDataLen Size of command data in bytes. + * + * @return RETURN_OK if successful, else RETURN_FAILURE. + */ + ReturnValue_t prepareTcMemWriteCommand(const uint8_t * commandData, size_t commandDataLen); + + /** + * @brief This function fills the commandBuffer to initiate the write reads command. + * + * @param commandData Pointer to action command data. + * @param commanDataLen Size of command data in bytes. + * + * @return RETURN_OK if successful, else RETURN_FAILURE. + */ + ReturnValue_t prepareTcMemReadCommand(const uint8_t * commandData, size_t commandDataLen); + + /** + * @brief This function checks the crc of the received PLOC reply. + * + * @param start Pointer to the first byte of the reply. + * @param foundLen Pointer to the length of the whole packet. + * + * @return RETURN_OK if CRC is ok, otherwise CRC_FAILURE. + */ + ReturnValue_t verifyPacket(const uint8_t* start, size_t foundLen); + + /** + * @brief This function handles the acknowledgment report. + * + * @param data Pointer to the data holding the acknowledgment report. + * + * @return RETURN_OK if successful, otherwise an error code. + */ + ReturnValue_t handleAckReport(const uint8_t* data); + + /** + * @brief This function handles the data of a execution report. + * + * @param data Pointer to the received data packet. + * + * @return RETURN_OK if successful, otherwise an error code. + */ + ReturnValue_t handleExecutionReport(const uint8_t* data); + + /** + * @brief This function handles the memory read report. + * + * @param data Pointer to the data buffer holding the memory read report. + * + * @return RETURN_OK if successful, otherwise an error code. + */ + ReturnValue_t handleMemoryReadReport(const uint8_t* data); + + /** + * @brief Depending on the current active command, this function sets the reply id of the + * next reply after a successful acknowledgment report has been received. This is + * required by the function getNextReplyLength() to identify the length of the next + * reply to read. + */ + void setNextReplyId(); + + /** + * @brief This function handles action message replies in case the telemetry has been + * requested by another object. + * + * @param data Pointer to the telemetry data. + * @param dataSize Size of telemetry in bytes. + * @param replyId Id of the reply. This will be added to the ActionMessage. + */ + void handleDeviceTM(const uint8_t* data, size_t dataSize, DeviceCommandId_t replyId); + + /** + * @brief In case an acknowledgment failure reply has been received this function disables + * all previously enabled commands and resets the exepected replies variable of an + * active command. + */ + void disableAllReplies(); + + /** + * @brief This function sends a failure report if the active action was commanded by an other + * object. + * + * @param replyId The id of the reply which signals a failure. + * @param status A status byte which gives information about the failure type. + */ + void sendFailureReport(DeviceCommandId_t replyId, ReturnValue_t status); + + /** + * @brief This function disables the execution report reply. Within this function also the + * the variable expectedReplies of an active command will be set to 0. + */ + void disableExeReportReply(); + + /** + * @brief This function checks and increments the packet sequence count of a received space + * packet. + * + * @param data Pointer to a space packet. + * + * @return RETURN_OK if successful + * + * @details There should be never a case in which a wrong packet sequence count is received + * because the communication scheme between PLOC and OBC always follows a strict + * procedure. Thus this function mainly serves for debugging purposes to detected an + * invalid handling of the packet sequence count. + */ + ReturnValue_t checkPacketSequenceCount(const uint8_t* data); +}; + +#endif /* MISSION_DEVICES_PLOCHANDLER_H_ */ diff --git a/mission/devices/RadiationSensorHandler.cpp b/mission/devices/RadiationSensorHandler.cpp new file mode 100644 index 00000000..bd16ddaf --- /dev/null +++ b/mission/devices/RadiationSensorHandler.cpp @@ -0,0 +1,158 @@ +#include +#include +#include + +RadiationSensorHandler::RadiationSensorHandler(object_id_t objectId, object_id_t comIF, + CookieIF * comCookie) : + DeviceHandlerBase(objectId, comIF, comCookie), dataset( + this) { + if (comCookie == NULL) { + sif::error << "RadiationSensorHandler: Invalid com cookie" << std::endl; + } +} + +RadiationSensorHandler::~RadiationSensorHandler() { +} + + +void RadiationSensorHandler::doStartUp(){ + if (internalState == InternalState::CONFIGURED) { +#if OBSW_SWITCH_TO_NORMAL_MODE_AFTER_STARTUP == 1 + setMode(MODE_NORMAL); +#else + setMode(_MODE_TO_ON); +#endif + } +} + +void RadiationSensorHandler::doShutDown(){ + setMode(_MODE_POWER_DOWN); +} + +ReturnValue_t RadiationSensorHandler::buildNormalDeviceCommand( + DeviceCommandId_t * id) { + + switch (communicationStep) { + case CommunicationStep::START_CONVERSION: { + *id = RAD_SENSOR::START_CONVERSION; + communicationStep = CommunicationStep::READ_CONVERSIONS; + break; + } + case CommunicationStep::READ_CONVERSIONS: { + *id = RAD_SENSOR::READ_CONVERSIONS; + communicationStep = CommunicationStep::START_CONVERSION; + break; + } + default: { + sif::debug << "RadiationSensorHandler::buildNormalDeviceCommand: Unknwon communication " + << "step" << std::endl; + return HasReturnvaluesIF::RETURN_OK; + } + } + return buildCommandFromCommand(*id, nullptr, 0); +} + +ReturnValue_t RadiationSensorHandler::buildTransitionDeviceCommand( + DeviceCommandId_t * id){ + if (internalState == InternalState::SETUP) { + *id = RAD_SENSOR::WRITE_SETUP; + } + else { + return HasReturnvaluesIF::RETURN_OK; + } + return buildCommandFromCommand(*id, nullptr, 0); +} + +ReturnValue_t RadiationSensorHandler::buildCommandFromCommand( + DeviceCommandId_t deviceCommand, const uint8_t * commandData, + size_t commandDataLen) { + switch(deviceCommand) { + case(RAD_SENSOR::WRITE_SETUP): { + cmdBuffer[0] = RAD_SENSOR::SETUP_DEFINITION; + rawPacket = cmdBuffer; + rawPacketLen = 1; + internalState = InternalState::CONFIGURED; + return RETURN_OK; + } + case(RAD_SENSOR::START_CONVERSION): { + /* First the fifo will be reset here */ + cmdBuffer[0] = RAD_SENSOR::RESET_DEFINITION; + cmdBuffer[1] = RAD_SENSOR::CONVERSION_DEFINITION; + rawPacket = cmdBuffer; + rawPacketLen = 2; + return RETURN_OK; + } + case(RAD_SENSOR::READ_CONVERSIONS): { + cmdBuffer[0] = RAD_SENSOR::DUMMY_BYTE; + cmdBuffer[1] = RAD_SENSOR::DUMMY_BYTE; + cmdBuffer[2] = RAD_SENSOR::DUMMY_BYTE; + cmdBuffer[3] = RAD_SENSOR::DUMMY_BYTE; + cmdBuffer[4] = RAD_SENSOR::DUMMY_BYTE; + cmdBuffer[5] = RAD_SENSOR::DUMMY_BYTE; + rawPacket = cmdBuffer; + rawPacketLen = RAD_SENSOR::READ_SIZE; + return RETURN_OK; + } + default: + return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; + } + return HasReturnvaluesIF::RETURN_FAILED; +} + +void RadiationSensorHandler::fillCommandAndReplyMap() { + this->insertInCommandMap(RAD_SENSOR::WRITE_SETUP); + this->insertInCommandMap(RAD_SENSOR::START_CONVERSION); + this->insertInCommandAndReplyMap(RAD_SENSOR::READ_CONVERSIONS, 1, &dataset, + RAD_SENSOR::READ_SIZE); +} + +ReturnValue_t RadiationSensorHandler::scanForReply(const uint8_t *start, + size_t remainingSize, DeviceCommandId_t *foundId, size_t *foundLen) { + *foundId = this->getPendingCommand(); + *foundLen = remainingSize; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t RadiationSensorHandler::interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) { + switch (id) { + case RAD_SENSOR::READ_CONVERSIONS: { + PoolReadGuard readSet(&dataset); + dataset.temperatureCelcius = (*(packet) << 8 | *(packet + 1)) * 0.125; + dataset.channel0 = (*(packet + 2) << 8 | *(packet + 3)); + dataset.channel1 = (*(packet + 4) << 8 | *(packet + 5)); +#if OBSW_VERBOSE_LEVEL >= 1 && DEBUG_RAD_SENSOR + sif::info << "Radiation sensor temperature: " << dataset.temperatureCelcius << " °C" + << std::endl; + sif::info << "Radiation sensor temperature ADC value channel 0: " << dataset.channel0 + << std::endl; + sif::info << "Radiation sensor temperature ADC value channel 1: " << dataset.channel1 + << std::endl; +#endif + break; + } + default: { + sif::debug << "RadiationSensorHandler::interpretDeviceReply: Unknown reply id" << std::endl; + return DeviceHandlerIF::UNKNOWN_DEVICE_REPLY; + } + + } + return HasReturnvaluesIF::RETURN_OK; +} + +void RadiationSensorHandler::setNormalDatapoolEntriesInvalid(){ + +} + +uint32_t RadiationSensorHandler::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo){ + return 5000; +} + +ReturnValue_t RadiationSensorHandler::initializeLocalDataPool(localpool::DataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) { + localDataPoolMap.emplace(RAD_SENSOR::TEMPERATURE_C, new PoolEntry( { 0.0 })); + localDataPoolMap.emplace(RAD_SENSOR::CHANNEL_0, new PoolEntry( { 0 })); + localDataPoolMap.emplace(RAD_SENSOR::CHANNEL_1, new PoolEntry( { 0 })); + return HasReturnvaluesIF::RETURN_OK; +} + diff --git a/mission/devices/RadiationSensorHandler.h b/mission/devices/RadiationSensorHandler.h new file mode 100644 index 00000000..5612a1e0 --- /dev/null +++ b/mission/devices/RadiationSensorHandler.h @@ -0,0 +1,60 @@ +#ifndef MISSION_DEVICES_RADIATIONSENSORHANDLER_H_ +#define MISSION_DEVICES_RADIATIONSENSORHANDLER_H_ + +#include +#include + +/** + * @brief This is the device handler class for radiation sensor on the OBC IF Board. The sensor + * is based on the MAX1227 ADC converter. + * + * @details Datasheet of MAX1227: https://datasheets.maximintegrated.com/en/ds/MAX1227-MAX1231.pdf + * + * @author J. Meier + */ +class RadiationSensorHandler: public DeviceHandlerBase { +public: + + RadiationSensorHandler(object_id_t objectId, object_id_t comIF, + CookieIF * comCookie); + virtual ~RadiationSensorHandler(); + +protected: + void doStartUp() override; + void doShutDown() 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; + void setNormalDatapoolEntriesInvalid() override; + uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) override; + ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) override; + +private: + + enum class CommunicationStep { + START_CONVERSION, + READ_CONVERSIONS + }; + + enum class InternalState { + SETUP, + CONFIGURED + }; + + RAD_SENSOR::RadSensorDataset dataset; + + static const uint8_t MAX_CMD_LEN = RAD_SENSOR::READ_SIZE; + + uint8_t cmdBuffer[MAX_CMD_LEN]; + InternalState internalState = InternalState::SETUP; + CommunicationStep communicationStep = CommunicationStep::START_CONVERSION; +}; + +#endif /* MISSION_DEVICES_RADIATIONSENSORHANDLER_H_ */ diff --git a/mission/devices/SusHandler.cpp b/mission/devices/SusHandler.cpp new file mode 100644 index 00000000..59560707 --- /dev/null +++ b/mission/devices/SusHandler.cpp @@ -0,0 +1,229 @@ +#include +#include +#include +#include + +SusHandler::SusHandler(object_id_t objectId, object_id_t comIF, CookieIF * comCookie, + LinuxLibgpioIF* gpioComIF, gpioId_t chipSelectId) : + DeviceHandlerBase(objectId, comIF, comCookie), gpioComIF(gpioComIF), chipSelectId( + chipSelectId), dataset(this) { + if (comCookie == NULL) { + sif::error << "SusHandler: Invalid com cookie" << std::endl; + } + if (gpioComIF == NULL) { + sif::error << "SusHandler: Invalid GpioComIF" << std::endl; + } +} + +SusHandler::~SusHandler() { +} + +ReturnValue_t SusHandler::performOperation(uint8_t counter) { + + if (counter != FIRST_WRITE) { + DeviceHandlerBase::performOperation(counter); + return RETURN_OK; + } + + if (mode != MODE_NORMAL) { + DeviceHandlerBase::performOperation(DeviceHandlerIF::SEND_WRITE); + return RETURN_OK; + } + + /* If device is in normale mode the communication sequence is initiated here */ + if (communicationStep == CommunicationStep::IDLE) { + communicationStep = CommunicationStep::WRITE_SETUP; + } + + DeviceHandlerBase::performOperation(DeviceHandlerIF::SEND_WRITE); + + return RETURN_OK; +} + +ReturnValue_t SusHandler::initialize() { + ReturnValue_t result = RETURN_OK; + result = DeviceHandlerBase::initialize(); + if (result != RETURN_OK) { + return result; + } + auto spiComIF = dynamic_cast(communicationInterface); + if (spiComIF == nullptr) { + sif::debug << "SusHandler::initialize: Invalid communication interface" << std::endl; + return ObjectManagerIF::CHILD_INIT_FAILED; + } + spiMutex = spiComIF->getMutex(); + if (spiMutex == nullptr) { + sif::debug << "SusHandler::initialize: Failed to get spi mutex" << std::endl; + return ObjectManagerIF::CHILD_INIT_FAILED; + } + return RETURN_OK; +} + +void SusHandler::doStartUp(){ +#if OBSW_SWITCH_TO_NORMAL_MODE_AFTER_STARTUP == 1 + setMode(MODE_NORMAL); +#else + setMode(_MODE_TO_ON); +#endif +} + +void SusHandler::doShutDown(){ + setMode(_MODE_POWER_DOWN); +} + +ReturnValue_t SusHandler::buildNormalDeviceCommand( + DeviceCommandId_t * id) { + + if (communicationStep == CommunicationStep::IDLE) { + return NOTHING_TO_SEND; + } + + if (communicationStep == CommunicationStep::WRITE_SETUP) { + *id = SUS::WRITE_SETUP; + communicationStep = CommunicationStep::START_CONVERSIONS; + } + else if (communicationStep == CommunicationStep::START_CONVERSIONS) { + *id = SUS::START_CONVERSIONS; + communicationStep = CommunicationStep::READ_CONVERSIONS; + } + else if (communicationStep == CommunicationStep::READ_CONVERSIONS) { + *id = SUS::READ_CONVERSIONS; + communicationStep = CommunicationStep::IDLE; + } + return buildCommandFromCommand(*id, nullptr, 0); +} + +ReturnValue_t SusHandler::buildTransitionDeviceCommand( + DeviceCommandId_t * id){ + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t SusHandler::buildCommandFromCommand( + DeviceCommandId_t deviceCommand, const uint8_t * commandData, + size_t commandDataLen) { + switch(deviceCommand) { + case(SUS::WRITE_SETUP): { + /** + * The sun sensor ADC is shutdown when CS is pulled high, so each time requesting a + * measurement the setup has to be rewritten. There must also be a little delay between + * the transmission of the setup byte and the first conversion. Thus the conversion + * will be performed in an extra step. + * Because the chip select is driven manually by the SusHandler the SPI bus must be + * protected with a mutex here. + */ + ReturnValue_t result = spiMutex->lockMutex(timeoutType, timeoutMs); + if(result == MutexIF::MUTEX_TIMEOUT) { + sif::error << "SusHandler::buildCommandFromCommand: Mutex timeout" << std::endl; + return ERROR_LOCK_MUTEX; + } + else if(result != HasReturnvaluesIF::RETURN_OK) { + sif::error << "SusHandler::buildCommandFromCommand: Failed to lock spi mutex" + << std::endl; + return ERROR_LOCK_MUTEX; + } + + gpioComIF->pullLow(chipSelectId); + cmdBuffer[0] = SUS::SETUP; + rawPacket = cmdBuffer; + rawPacketLen = 1; + return RETURN_OK; + } + case(SUS::START_CONVERSIONS): { + std::memset(cmdBuffer, 0, sizeof(cmdBuffer)); + cmdBuffer[0] = SUS::CONVERSION; + rawPacket = cmdBuffer; + rawPacketLen = 2; + return RETURN_OK; + } + case(SUS::READ_CONVERSIONS): { + std::memset(cmdBuffer, 0, sizeof(cmdBuffer)); + rawPacket = cmdBuffer; + rawPacketLen = SUS::SIZE_READ_CONVERSIONS; + return RETURN_OK; + } + default: + return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; + } + return HasReturnvaluesIF::RETURN_FAILED; +} + +void SusHandler::fillCommandAndReplyMap() { + this->insertInCommandMap(SUS::WRITE_SETUP); + this->insertInCommandMap(SUS::START_CONVERSIONS); + this->insertInCommandAndReplyMap(SUS::READ_CONVERSIONS, 1, &dataset, SUS::SIZE_READ_CONVERSIONS); +} + +ReturnValue_t SusHandler::scanForReply(const uint8_t *start, + size_t remainingSize, DeviceCommandId_t *foundId, size_t *foundLen) { + *foundId = this->getPendingCommand(); + *foundLen = remainingSize; + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t SusHandler::interpretDeviceReply(DeviceCommandId_t id, + const uint8_t *packet) { + switch (id) { + case SUS::READ_CONVERSIONS: { + PoolReadGuard readSet(&dataset); + dataset.temperatureCelcius = (*(packet) << 8 | *(packet + 1)) * 0.125; + dataset.ain0 = (*(packet + 2) << 8 | *(packet + 3)); + dataset.ain1 = (*(packet + 4) << 8 | *(packet + 5)); + dataset.ain2 = (*(packet + 6) << 8 | *(packet + 7)); + dataset.ain3 = (*(packet + 8) << 8 | *(packet + 9)); + dataset.ain4 = (*(packet + 10) << 8 | *(packet + 11)); + dataset.ain5 = (*(packet + 12) << 8 | *(packet + 13)); +#if OBSW_VERBOSE_LEVEL >= 1 && DEBUG_SUS + sif::info << "SUS object id 0x" << std::hex << this->getObjectId() << ", Temperature: " + << dataset.temperatureCelcius << " °C" << std::endl; + sif::info << "SUS object id 0x" << std::hex << this->getObjectId() << ", AIN0: " + << std::dec << dataset.ain0 << std::endl; + sif::info << "SUS object id 0x" << std::hex << this->getObjectId() << ", AIN1: " + << std::dec << dataset.ain1 << std::endl; + sif::info << "SUS object id 0x" << std::hex << this->getObjectId() << ", AIN2: " + << std::dec << dataset.ain2 << std::endl; + sif::info << "SUS object id 0x" << std::hex << this->getObjectId() << ", AIN3: " + << std::dec << dataset.ain3 << std::endl; + sif::info << "SUS object id 0x" << std::hex << this->getObjectId() << ", AIN4: " + << std::dec << dataset.ain4 << std::endl; + sif::info << "SUS object id 0x" << std::hex << this->getObjectId() << ", AIN5: " + << std::dec << dataset.ain5 << std::endl; +#endif + /** SUS can now be shutdown and thus the SPI bus released again */ + gpioComIF->pullHigh(chipSelectId); + ReturnValue_t result = spiMutex->unlockMutex(); + if (result != RETURN_OK) { + sif::error << "SusHandler::interpretDeviceReply: Failed to unlock spi mutex" + << std::endl; + return ERROR_UNLOCK_MUTEX; + } + break; + } + default: { + sif::debug << "SusHandler::interpretDeviceReply: Unknown reply id" << std::endl; + return DeviceHandlerIF::UNKNOWN_DEVICE_REPLY; + } + + } + return HasReturnvaluesIF::RETURN_OK; +} + +void SusHandler::setNormalDatapoolEntriesInvalid(){ + +} + +uint32_t SusHandler::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo){ + return 1000; +} + +ReturnValue_t SusHandler::initializeLocalDataPool(localpool::DataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) { + localDataPoolMap.emplace(SUS::TEMPERATURE_C, new PoolEntry( { 0.0 })); + localDataPoolMap.emplace(SUS::AIN0, new PoolEntry( { 0 })); + localDataPoolMap.emplace(SUS::AIN1, new PoolEntry( { 0 })); + localDataPoolMap.emplace(SUS::AIN2, new PoolEntry( { 0 })); + localDataPoolMap.emplace(SUS::AIN3, new PoolEntry( { 0 })); + localDataPoolMap.emplace(SUS::AIN4, new PoolEntry( { 0 })); + localDataPoolMap.emplace(SUS::AIN5, new PoolEntry( { 0 })); + return HasReturnvaluesIF::RETURN_OK; +} + diff --git a/mission/devices/SusHandler.h b/mission/devices/SusHandler.h new file mode 100644 index 00000000..c73cee97 --- /dev/null +++ b/mission/devices/SusHandler.h @@ -0,0 +1,81 @@ +#ifndef MISSION_DEVICES_SUSHANDLER_H_ +#define MISSION_DEVICES_SUSHANDLER_H_ + +#include +#include +#include +#include + +/** + * @brief This is the device handler class for the SUS sensor. The sensor is + * based on the MAX1227 ADC. Details about the SUS electronic can be found at + * https://egit.irs.uni-stuttgart.de/eive/eive_dokumente/src/branch/master/400_Raumsegment/443_SunSensorDocumentation/release + * + * @details Datasheet of MAX1227: https://datasheets.maximintegrated.com/en/ds/MAX1227-MAX1231.pdf + * + * @note When adding a SusHandler to the polling sequence table make sure to add a slot with + * the executionStep FIRST_WRITE. Otherwise the communication sequence will never be + * started. + * + * @author J. Meier + */ +class SusHandler: public DeviceHandlerBase { +public: + + static const uint8_t FIRST_WRITE = 7; + + SusHandler(object_id_t objectId, object_id_t comIF, + CookieIF * comCookie, LinuxLibgpioIF* gpioComIF, gpioId_t chipSelectId); + virtual ~SusHandler(); + + virtual ReturnValue_t performOperation(uint8_t counter) override; + + virtual ReturnValue_t initialize() override; + +protected: + void doStartUp() override; + void doShutDown() 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; + void setNormalDatapoolEntriesInvalid() override; + uint32_t getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) override; + ReturnValue_t initializeLocalDataPool(localpool::DataPool& localDataPoolMap, + LocalDataPoolManager& poolManager) override; + +private: + + static const uint8_t INTERFACE_ID = CLASS_ID::SUS_HANDLER; + + static const ReturnValue_t ERROR_UNLOCK_MUTEX = MAKE_RETURN_CODE(0xA0); + static const ReturnValue_t ERROR_LOCK_MUTEX = MAKE_RETURN_CODE(0xA1); + + enum class CommunicationStep { + IDLE, + WRITE_SETUP, + START_CONVERSIONS, + READ_CONVERSIONS + }; + + LinuxLibgpioIF* gpioComIF = nullptr; + + gpioId_t chipSelectId = gpio::NO_GPIO; + + SUS::SusDataset dataset; + + uint8_t cmdBuffer[SUS::MAX_CMD_SIZE]; + CommunicationStep communicationStep = CommunicationStep::IDLE; + + MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING; + uint32_t timeoutMs = 20; + + MutexIF* spiMutex = nullptr; +}; + +#endif /* MISSION_DEVICES_SUSHANDLER_H_ */ diff --git a/mission/devices/devicedefinitions/IMTQHandlerDefinitions.h b/mission/devices/devicedefinitions/IMTQHandlerDefinitions.h index 23ff8b9a..1cfdf933 100644 --- a/mission/devices/devicedefinitions/IMTQHandlerDefinitions.h +++ b/mission/devices/devicedefinitions/IMTQHandlerDefinitions.h @@ -6,46 +6,74 @@ namespace IMTQ { static const DeviceCommandId_t NONE = 0x0; static const DeviceCommandId_t GET_ENG_HK_DATA = 0x1; static const DeviceCommandId_t START_ACTUATION_DIPOLE = 0x2; + static const DeviceCommandId_t GET_COMMANDED_DIPOLE = 0x3; + /** Generates new measurement of the magnetic field */ + static const DeviceCommandId_t START_MTM_MEASUREMENT = 0x4; + /** Requests the calibrated magnetometer measurement */ + static const DeviceCommandId_t GET_CAL_MTM_MEASUREMENT = 0x5; + /** Requests the raw values measured by the built-in MTM XEN1210 */ + static const DeviceCommandId_t GET_RAW_MTM_MEASUREMENT = 0x6; + static const DeviceCommandId_t SELF_TEST = 0x7; static const uint8_t GET_TEMP_REPLY_SIZE = 2; static const uint8_t CFGR_CMD_SIZE = 3; static const uint8_t POINTER_REG_SIZE = 1; static const uint32_t ENG_HK_DATA_SET_ID = GET_ENG_HK_DATA; + static const uint32_t CAL_MTM_SET = GET_CAL_MTM_MEASUREMENT; + static const uint8_t SIZE_ENG_HK_COMMAND = 1; + static const uint8_t SIZE_STATUS_REPLY = 2; static const uint8_t SIZE_ENG_HK_DATA_REPLY = 24; + static const uint8_t SIZE_GET_COMMANDED_DIPOLE_REPLY = 8; + static const uint8_t SIZE_GET_CAL_MTM_MEASUREMENT = 15; + static const uint8_t SIZE_GET_RAW_MTM_MEASUREMENT = 15; static const uint8_t MAX_REPLY_SIZE = SIZE_ENG_HK_DATA_REPLY; static const uint8_t MAX_COMMAND_SIZE = 9; - static const uint8_t POOL_ENTRIES = 11; + /** Define entries in IMTQ specific dataset */ + static const uint8_t ENG_HK_SET_POOL_ENTRIES = 11; + static const uint8_t CAL_MTM_POOL_ENTRIES = 4; /** * Command code definitions. Each command or reply of an IMTQ request will begin with one of * the following command codes. */ namespace CC { + static const uint8_t START_MTM_MEASUREMENT = 0x4; static const uint8_t START_ACTUATION_DIPOLE = 0x6; static const uint8_t SOFTWARE_RESET = 0xAA; static const uint8_t GET_ENG_HK_DATA = 0x4A; + static const uint8_t GET_COMMANDED_DIPOLE = 0x46; + static const uint8_t GET_RAW_MTM_MEASUREMENT = 0x42; + static const uint8_t GET_CAL_MTM_MEASUREMENT = 0x43; }; enum IMTQPoolIds: lp_id_t { DIGITAL_VOLTAGE_MV, ANALOG_VOLTAGE_MV, - DIGITAL_CURRENT_A, - ANALOG_CURRENT_A, - COIL_X_CURRENT_A, - COIL_Y_CURRENT_A, - COIL_Z_CURRENT_A, + DIGITAL_CURRENT, + ANALOG_CURRENT, + COIL_X_CURRENT, + COIL_Y_CURRENT, + COIL_Z_CURRENT, COIL_X_TEMPERATURE, COIL_Y_TEMPERATURE, COIL_Z_TEMPERATURE, - MCU_TEMPERATURE + MCU_TEMPERATURE, + MTM_CAL_X, + MTM_CAL_Y, + MTM_CAL_Z, + ACTUATION_CAL_STATUS, + MTM_RAW_X, + MTM_RAW_Y, + MTM_RAW_Z, + ACTUATION_RAW_STATUS }; class EngHkDataset: - public StaticLocalDataSet { + public StaticLocalDataSet { public: EngHkDataset(HasLocalDataPoolIF* owner): @@ -60,16 +88,16 @@ public: DIGITAL_VOLTAGE_MV, this); lp_var_t analogVoltageMv = lp_var_t(sid.objectId, ANALOG_VOLTAGE_MV, this); - lp_var_t digitalCurrentA = lp_var_t(sid.objectId, - DIGITAL_CURRENT_A, this); - lp_var_t analogCurrentA = lp_var_t(sid.objectId, - ANALOG_CURRENT_A, this); - lp_var_t coilXcurrentA = lp_var_t(sid.objectId, - COIL_X_CURRENT_A, this); - lp_var_t coilYcurrentA = lp_var_t(sid.objectId, - COIL_Y_CURRENT_A, this); - lp_var_t coilZcurrentA = lp_var_t(sid.objectId, - COIL_Z_CURRENT_A, this); + lp_var_t digitalCurrentmA = lp_var_t(sid.objectId, + DIGITAL_CURRENT, this); + lp_var_t analogCurrentmA = lp_var_t(sid.objectId, + ANALOG_CURRENT, this); + lp_var_t coilXCurrentmA = lp_var_t(sid.objectId, + COIL_X_CURRENT, this); + lp_var_t coilYCurrentmA = lp_var_t(sid.objectId, + COIL_Y_CURRENT, this); + lp_var_t coilZCurrentmA = lp_var_t(sid.objectId, + COIL_Z_CURRENT, this); /** All temperatures in [°C] */ lp_var_t coilXTemperature = lp_var_t(sid.objectId, COIL_X_TEMPERATURE, this); @@ -81,6 +109,60 @@ public: MCU_TEMPERATURE, this); }; +/** + * @brief This dataset holds the raw MTM measurements. + */ +class CalibratedMtmMeasurementSet: + public StaticLocalDataSet { +public: + + CalibratedMtmMeasurementSet(HasLocalDataPoolIF* owner): + StaticLocalDataSet(owner, CAL_MTM_SET) { + } + + CalibratedMtmMeasurementSet(object_id_t objectId): + StaticLocalDataSet(sid_t(objectId, CAL_MTM_SET)) { + } + + /** The unit of all measurements is nT */ + lp_var_t mtmXnT = lp_var_t(sid.objectId, + MTM_CAL_X, this); + lp_var_t mtmYnT = lp_var_t(sid.objectId, + MTM_CAL_Y, this); + lp_var_t mtmZnT = lp_var_t(sid.objectId, + MTM_CAL_Z, this); + /** 1 if coils were actuating during measurement otherwise 0 */ + lp_var_t coilActuationStatus = lp_var_t(sid.objectId, + ACTUATION_CAL_STATUS, this); +}; + +/** + * @brief This dataset holds the last calibrated MTM measurement. + */ +class RawMtmMeasurementSet: + public StaticLocalDataSet { +public: + + RawMtmMeasurementSet(HasLocalDataPoolIF* owner): + StaticLocalDataSet(owner, CAL_MTM_SET) { + } + + RawMtmMeasurementSet(object_id_t objectId): + StaticLocalDataSet(sid_t(objectId, CAL_MTM_SET)) { + } + + /** The unit of all measurements is nT */ + lp_var_t mtmXnT = lp_var_t(sid.objectId, + MTM_RAW_X, this); + lp_var_t mtmYnT = lp_var_t(sid.objectId, + MTM_RAW_Y, this); + lp_var_t mtmZnT = lp_var_t(sid.objectId, + MTM_RAW_Z, this); + /** 1 if coils were actuating during measurement otherwise 0 */ + lp_var_t coilActuationStatus = lp_var_t(sid.objectId, + ACTUATION_RAW_STATUS, this); +}; + /** * @brief This class can be used to ease the generation of an action message commanding the * IMTQHandler to configure the magnettorquer with the desired dipoles. diff --git a/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h b/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h index 2856c170..08f80dd9 100644 --- a/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h +++ b/mission/devices/devicedefinitions/MGMHandlerRM3100Definitions.h @@ -12,7 +12,7 @@ namespace RM3100 { /* Actually 10, we round up a little bit */ static constexpr size_t MAX_BUFFER_SIZE = 12; -static constexpr uint8_t READ_MASK = 0b1000'0000; +static constexpr uint8_t READ_MASK = 0x80; /*----------------------------------------------------------------------------*/ /* CMM Register */ @@ -45,7 +45,7 @@ static constexpr uint8_t TMRC_75HZ_VALUE = 0x95; static constexpr uint8_t TMRC_DEFAULT_37HZ_VALUE = 0x96; static constexpr uint8_t TMRC_REGISTER = 0x0B; -static constexpr uint8_t TMRC_DEFAULT_VALUE = TMRC_75HZ_VALUE; +static constexpr uint8_t TMRC_DEFAULT_VALUE = TMRC_DEFAULT_37HZ_VALUE; static constexpr uint8_t MEASUREMENT_REG_START = 0x24; static constexpr uint8_t BIST_REGISTER = 0x33; diff --git a/mission/devices/devicedefinitions/PlocDefinitions.h b/mission/devices/devicedefinitions/PlocDefinitions.h new file mode 100644 index 00000000..f5add451 --- /dev/null +++ b/mission/devices/devicedefinitions/PlocDefinitions.h @@ -0,0 +1,172 @@ +#ifndef MISSION_DEVICES_DEVICEDEFINITIONS_PLOCDEFINITIONS_H_ +#define MISSION_DEVICES_DEVICEDEFINITIONS_PLOCDEFINITIONS_H_ + +#include +#include +#include + +namespace PLOC { + + static const DeviceCommandId_t NONE = 0x0; + static const DeviceCommandId_t TC_MEM_WRITE = 0x1; + static const DeviceCommandId_t TC_MEM_READ = 0x2; + static const DeviceCommandId_t ACK_REPORT = 0x3; + static const DeviceCommandId_t EXE_REPORT = 0x5; + static const DeviceCommandId_t TM_MEMORY_READ_REPORT = 0x6; + + static const uint16_t SIZE_ACK_REPORT = 14; + static const uint16_t SIZE_EXE_REPORT = 14; + static const uint16_t SIZE_TM_MEM_READ_REPORT = 18; + + /** + * SpacePacket apids of PLOC telecommands and telemetry. + */ + static const uint16_t APID_TC_MEM_WRITE = 0x714; + static const uint16_t APID_TC_MEM_READ = 0x715; + static const uint16_t APID_TM_MEMORY_READ_REPORT = 0x404; + static const uint16_t APID_ACK_SUCCESS = 0x400; + static const uint16_t APID_ACK_FAILURE = 0x401; + static const uint16_t APID_EXE_SUCCESS = 0x402; + static const uint16_t APID_EXE_FAILURE = 0x403; + + /** Offset from first byte in Space packet to first byte of data field */ + static const uint8_t DATA_FIELD_OFFSET = 6; + + /** + * The size of payload data which will be forwarded to the requesting object. e.g. PUS Service + * 8. + */ + static const uint8_t SIZE_MEM_READ_REPORT_DATA = 10; + + /** + * PLOC space packet length for fixed size packets. This is the size of the whole packet data + * field. For the length field in the space packet this size will be substracted by one. + */ + static const uint16_t LENGTH_TC_MEM_WRITE = 12; + static const uint16_t LENGTH_TC_MEM_READ = 8; + + static const size_t MAX_REPLY_SIZE = SIZE_TM_MEM_READ_REPORT; + static const size_t MAX_COMMAND_SIZE = 18; + + /** + * @brief This class helps to build the memory read command for the PLOC. + * + * @details The last two bytes of the packet data field contain a CRC calculated over the whole + * space packet. This is the CRC-16-CCITT as specified in + * ECSS-E-ST-70-41C – Telemetry and telecommand packet utilization. + */ + class TcMemRead : public SpacePacket { + public: + + /** + * @brief Constructor + * + * @param memAddr The memory address to read from. + */ + TcMemRead(const uint32_t memAddr, uint16_t sequenceCount) : + SpacePacket(LENGTH_TC_MEM_READ - 1, true, APID_TC_MEM_READ, sequenceCount) { + fillPacketDataField(&memAddr); + } + + private: + + /** + * @brief This function builds the packet data field for the mem read command. + * + * @param memAddrPtr Pointer to the memory address to read from. + */ + void fillPacketDataField(const uint32_t* memAddrPtr) { + /* Add memAddr to packet data field */ + size_t serializedSize = 0; + uint8_t* memoryAddressPos = this->localData.fields.buffer; + SerializeAdapter::serialize(memAddrPtr, &memoryAddressPos, &serializedSize, + sizeof(*memAddrPtr), SerializeIF::Endianness::LITTLE); + + /* Add memLen to packet data field */ + this->localData.fields.buffer[OFFSET_MEM_LEN_FIELD] = 1; + this->localData.fields.buffer[OFFSET_MEM_LEN_FIELD + 1] = 0; + + /* Calculate crc */ + uint16_t crc = CRC::crc16ccitt(this->localData.byteStream, + sizeof(CCSDSPrimaryHeader) + LENGTH_TC_MEM_READ - CRC_SIZE); + + /* Add crc to packet data field of space packet */ + serializedSize = 0; + uint8_t* crcPos = this->localData.fields.buffer + CRC_OFFSET; + SerializeAdapter::serialize(&crc, &crcPos, &serializedSize, + sizeof(crc), SerializeIF::Endianness::BIG); + } + + static const uint8_t OFFSET_MEM_LEN_FIELD = 4; + static const uint8_t CRC_OFFSET = 6; + + }; + + /** + * @brief This class helps to generate the space packet to write to a memory address within + * the PLOC. + * @details The last two bytes of the packet data field contain a CRC calculated over the whole + * space packet. This is the CRC-16-CCITT as specified in + * ECSS-E-ST-70-41C – Telemetry and telecommand packet utilization. + */ + class TcMemWrite : public SpacePacket { + public: + /** + * @brief Constructor + * + * @param memAddr The PLOC memory address where to write to. + * @param memoryData The data to write to the specified memory address. + * @param sequenceCount The subsequence count. Must be incremented with each new packet. + */ + TcMemWrite(const uint32_t memAddr, const uint32_t memoryData, uint16_t sequenceCount) : + SpacePacket(LENGTH_TC_MEM_WRITE - 1, true, APID_TC_MEM_WRITE, sequenceCount) { + fillPacketDataField(&memAddr, &memoryData); + } + + private: + + /** + * @brief This function builds the packet data field for the mem write command. + * + * @param memAddrPtr Pointer to the PLOC memory address where to write to. + * @param memoryDataPtr Pointer to the memoryData to write + */ + void fillPacketDataField(const uint32_t* memAddrPtr, const uint32_t* memoryDataPtr) { + + /* Add memAddr to packet data field */ + size_t serializedSize = 0; + uint8_t* memoryAddressPos = this->localData.fields.buffer; + SerializeAdapter::serialize(memAddrPtr, &memoryAddressPos, &serializedSize, + sizeof(*memAddrPtr), SerializeIF::Endianness::BIG); + + /* Add memLen to packet data field */ + this->localData.fields.buffer[OFFSET_MEM_LEN_FIELD] = 1; + this->localData.fields.buffer[OFFSET_MEM_LEN_FIELD + 1] = 0; + + /* Add memData to packet data field */ + serializedSize = 0; + uint8_t* memoryDataPos = this->localData.fields.buffer + OFFSET_MEM_DATA_FIELD; + SerializeAdapter::serialize(memoryDataPtr, &memoryDataPos, &serializedSize, + sizeof(*memoryDataPtr), SerializeIF::Endianness::BIG); + + /* Calculate crc */ + uint16_t crc = CRC::crc16ccitt(this->localData.byteStream, + sizeof(CCSDSPrimaryHeader) + LENGTH_TC_MEM_WRITE - CRC_SIZE); + + serializedSize = 0; + uint8_t* crcPos = this->localData.fields.buffer + CRC_OFFSET; + /* Add crc to packet data field of space packet */ + SerializeAdapter::serialize(&crc, &crcPos, &serializedSize, + sizeof(crc), SerializeIF::Endianness::BIG); + } + + /** Offsets from base address of packet data field */ + static const uint8_t OFFSET_MEM_LEN_FIELD = 4; + static const uint8_t OFFSET_MEM_DATA_FIELD = 6; + static const uint8_t CRC_OFFSET = 10; + }; + +} + + +#endif /* MISSION_DEVICES_DEVICEDEFINITIONS_PLOCDEFINITIONS_H_ */ diff --git a/mission/devices/devicedefinitions/RadSensorDefinitions.h b/mission/devices/devicedefinitions/RadSensorDefinitions.h new file mode 100644 index 00000000..7d434d04 --- /dev/null +++ b/mission/devices/devicedefinitions/RadSensorDefinitions.h @@ -0,0 +1,76 @@ +#ifndef MISSION_DEVICES_DEVICEDEFINITIONS_RADSENSOR_H_ +#define MISSION_DEVICES_DEVICEDEFINITIONS_RADSENSOR_H_ + +namespace RAD_SENSOR { + + static const DeviceCommandId_t NONE = 0x0; // Set when no command is pending + + /** + * This command initiates the ADC conversion for all channels including the internal + * temperature sensor. + */ + static const DeviceCommandId_t WRITE_SETUP = 0x1; + static const DeviceCommandId_t START_CONVERSION = 0x2; + static const DeviceCommandId_t READ_CONVERSIONS = 0x3; + + /** + * @brief This is the configuration byte which will be written to the setup register after + * power on. + * + * @note Bit1 (DIFFSEL1) - Bit0 (DIFFSEL0): 0b00, no data follows the setup byte + * Bit3 (REFSEL1) - Bit2 (REFSEL0): 0b10, internal reference, no wake-up delay + * Bit5 (CLKSEL1) - Bit4 (CLKSEL0): 0b10, MAX1227 uses internal oscillator for timing + * Bit7 - Bit6: 0b01, tells MAX1227 that this is the setup register + * + */ + static const uint8_t SETUP_DEFINITION = 0b01101000; + + /** + * @brief This value will always be written to the ADC conversion register to specify the + * conversions to perform. + * @details Bit0: 1 - Enables temperature conversion + * Bit2 (SCAN1) and Bit1 (SCAN0): 0b00 (channel conversion from 0 to N) + * Bit6 - Bit3 defines N: 0b0001 (N = 1) + * Bit7: Always 1. Tells the ADC that this is the conversion register. + */ + static const uint8_t CONVERSION_DEFINITION = 0b10001001; + + /** + * @brief Writing this value resets the fifo of the MAX1227. + */ + static const uint8_t RESET_DEFINITION = 0b00011000; + + static const uint8_t DUMMY_BYTE = 0xFF; + + static const uint8_t RAD_SENSOR_DATA_SET_ID = READ_CONVERSIONS; + + /** + * One temperature value, conversion of channel 0 and conversion of channel 1 + */ + static const uint8_t READ_SIZE = 6; + + enum Max1227PoolIds: lp_id_t { + TEMPERATURE_C, + CHANNEL_0, + CHANNEL_1, + }; + +class RadSensorDataset: public StaticLocalDataSet { +public: + + RadSensorDataset(HasLocalDataPoolIF* owner) : + StaticLocalDataSet(owner, RAD_SENSOR_DATA_SET_ID) { + } + + RadSensorDataset(object_id_t objectId) : + StaticLocalDataSet(sid_t(objectId, RAD_SENSOR_DATA_SET_ID)) { + } + + lp_var_t temperatureCelcius = lp_var_t(sid.objectId, TEMPERATURE_C, this); + lp_var_t channel0 = lp_var_t(sid.objectId, CHANNEL_0, this); + lp_var_t channel1 = lp_var_t(sid.objectId, CHANNEL_1, this); +}; +} + + +#endif /* MISSION_DEVICES_DEVICEDEFINITIONS_RADSENSOR_H_ */ diff --git a/mission/devices/devicedefinitions/SusDefinitions.h b/mission/devices/devicedefinitions/SusDefinitions.h new file mode 100644 index 00000000..18f33e0d --- /dev/null +++ b/mission/devices/devicedefinitions/SusDefinitions.h @@ -0,0 +1,90 @@ +#ifndef MISSION_DEVICES_DEVICEDEFINITIONS_SUS_H_ +#define MISSION_DEVICES_DEVICEDEFINITIONS_SUS_H_ + +namespace SUS { + + /** + * Some MAX1227 could not be reached with frequencies around 4 MHz. Maybe this is caused by + * the decoder and buffer circuits. Thus frequency is here defined to 1 MHz. + */ + static const uint32_t MAX1227_SPI_FREQ = 1000000; + + static const DeviceCommandId_t NONE = 0x0; // Set when no command is pending + + static const DeviceCommandId_t WRITE_SETUP = 0x1; + /** + * This command initiates the ADC conversion for all channels including the internal + * temperature sensor. + */ + static const DeviceCommandId_t START_CONVERSIONS = 0x2; + /** + * This command reads the internal fifo which holds the temperature and the channel + * conversions. + */ + static const DeviceCommandId_t READ_CONVERSIONS = 0x3; + + /** + * @brief This is the configuration byte which will be written to the setup register after + * power on. + * + * @note Bit1 (DIFFSEL1) - Bit0 (DIFFSEL0): 0b00, No byte is following the setup byte + * Bit3 (REFSEL1) - Bit2 (REFSEL0): 0b10, Internal reference, no wake-up delay + * Bit5 (CLKSEL1) - Bit4 (CLKSEL0): 0b10, Internally clocked + * Bit7 - Bit6: 0b01, Tells MAX1227 that this byte should be + * written to the setup register + * + */ + static const uint8_t SETUP = 0b01101000; + + /** + * @brief This values will always be written to the ADC conversion register to specify the + * conversions to perform. + * @details Bit0: 1 - Enables temperature conversion + * Bit2 (SCAN1) and Bit1 (SCAN0): 0b00, Scans channels 0 through N + * Bit6 - Bit3 defines N: 0b0101 (N = 5) + * Bit7: Always 1. Tells the ADC that this is the conversion register. + */ + static const uint8_t CONVERSION = 0b10101001; + + static const uint8_t SUS_DATA_SET_ID = READ_CONVERSIONS; + + /** Size of data replies. Temperature and 6 channel convesions (AIN0 - AIN5) */ + static const uint8_t SIZE_READ_CONVERSIONS = 14; + + static const uint8_t MAX_CMD_SIZE = SIZE_READ_CONVERSIONS; + + static const uint8_t POOL_ENTRIES = 7; + + enum Max1227PoolIds: lp_id_t { + TEMPERATURE_C, + AIN0, + AIN1, + AIN2, + AIN3, + AIN4, + AIN5, + }; + +class SusDataset: public StaticLocalDataSet { +public: + + SusDataset(HasLocalDataPoolIF* owner) : + StaticLocalDataSet(owner, SUS_DATA_SET_ID) { + } + + SusDataset(object_id_t objectId) : + StaticLocalDataSet(sid_t(objectId, SUS_DATA_SET_ID)) { + } + + lp_var_t temperatureCelcius = lp_var_t(sid.objectId, TEMPERATURE_C, this); + lp_var_t ain0 = lp_var_t(sid.objectId, AIN0, this); + lp_var_t ain1 = lp_var_t(sid.objectId, AIN1, this); + lp_var_t ain2 = lp_var_t(sid.objectId, AIN2, this); + lp_var_t ain3 = lp_var_t(sid.objectId, AIN3, this); + lp_var_t ain4 = lp_var_t(sid.objectId, AIN4, this); + lp_var_t ain5 = lp_var_t(sid.objectId, AIN5, this); +}; +} + + +#endif /* MISSION_DEVICES_DEVICEDEFINITIONS_SUS_H_ */ diff --git a/thirdparty/etl b/thirdparty/etl index ae06e641..c308dc42 160000 --- a/thirdparty/etl +++ b/thirdparty/etl @@ -1 +1 @@ -Subproject commit ae06e6417702b770c49289c9e7162cb3f4a5a217 +Subproject commit c308dc427b7a34e54f33860fb2e244564b2740b4 diff --git a/tmtc b/tmtc index 7cc06ef0..a82e6b2e 160000 --- a/tmtc +++ b/tmtc @@ -1 +1 @@ -Subproject commit 7cc06ef0e0882d286bab8156ca756e0211e5ebae +Subproject commit a82e6b2e64e271eecc23fdbe3c403c417bb65e39