diff --git a/bsp_q7s/core/ObjectFactory.cpp b/bsp_q7s/core/ObjectFactory.cpp index 8b2c4366..c3019aad 100644 --- a/bsp_q7s/core/ObjectFactory.cpp +++ b/bsp_q7s/core/ObjectFactory.cpp @@ -44,8 +44,8 @@ #include "linux/csp/CspComIF.h" #include "linux/csp/CspCookie.h" #include "linux/devices/SolarArrayDeploymentHandler.h" -#include "linux/devices/SusHandler.h" -#include "linux/devices/devicedefinitions/SusDefinitions.h" +#include "mission/devices/SusHandler.h" +#include "mission/devices/devicedefinitions/SusDefinitions.h" #include "mission/core/GenericFactory.h" #include "mission/devices/ACUHandler.h" #include "mission/devices/BpxBatteryHandler.h" @@ -351,61 +351,57 @@ void ObjectFactory::createSunSensorComponents(LinuxLibgpioIF* gpioComIF, SpiComI SpiCookie* spiCookieSus1 = new SpiCookie(addresses::SUS_1, gpio::NO_GPIO, std::string(q7s::SPI_DEFAULT_DEV), - SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, SUS::MAX1227_SPI_FREQ); + SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, spi::SUS_MAX1227_SPI_FREQ); SpiCookie* spiCookieSus2 = new SpiCookie(addresses::SUS_2, gpio::NO_GPIO, std::string(q7s::SPI_DEFAULT_DEV), - SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, SUS::MAX1227_SPI_FREQ); + SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, spi::SUS_MAX1227_SPI_FREQ); SpiCookie* spiCookieSus3 = new SpiCookie(addresses::SUS_3, gpio::NO_GPIO, std::string(q7s::SPI_DEFAULT_DEV), - SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, SUS::MAX1227_SPI_FREQ); + SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, spi::SUS_MAX1227_SPI_FREQ); SpiCookie* spiCookieSus4 = new SpiCookie(addresses::SUS_4, gpio::NO_GPIO, std::string(q7s::SPI_DEFAULT_DEV), - SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, SUS::MAX1227_SPI_FREQ); + SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, spi::SUS_MAX1227_SPI_FREQ); SpiCookie* spiCookieSus5 = new SpiCookie(addresses::SUS_5, gpio::NO_GPIO, std::string(q7s::SPI_DEFAULT_DEV), - SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, SUS::MAX1227_SPI_FREQ); + SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, spi::SUS_MAX1227_SPI_FREQ); SpiCookie* spiCookieSus6 = new SpiCookie(addresses::SUS_6, gpio::NO_GPIO, std::string(q7s::SPI_DEFAULT_DEV), - SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, SUS::MAX1227_SPI_FREQ); + SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, spi::SUS_MAX1227_SPI_FREQ); SpiCookie* spiCookieSus7 = new SpiCookie(addresses::SUS_7, gpio::NO_GPIO, std::string(q7s::SPI_DEFAULT_DEV), - SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, SUS::MAX1227_SPI_FREQ); + SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, spi::SUS_MAX1227_SPI_FREQ); SpiCookie* spiCookieSus8 = new SpiCookie(addresses::SUS_8, gpio::NO_GPIO, std::string(q7s::SPI_DEFAULT_DEV), - SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, SUS::MAX1227_SPI_FREQ); + SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, spi::SUS_MAX1227_SPI_FREQ); SpiCookie* spiCookieSus9 = new SpiCookie(addresses::SUS_9, gpio::NO_GPIO, std::string(q7s::SPI_DEFAULT_DEV), - SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, SUS::MAX1227_SPI_FREQ); + SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, spi::SUS_MAX1227_SPI_FREQ); SpiCookie* spiCookieSus10 = new SpiCookie(addresses::SUS_10, gpio::NO_GPIO, std::string(q7s::SPI_DEFAULT_DEV), - SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, SUS::MAX1227_SPI_FREQ); + SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, spi::SUS_MAX1227_SPI_FREQ); SpiCookie* spiCookieSus11 = new SpiCookie(addresses::SUS_11, gpio::NO_GPIO, std::string(q7s::SPI_DEFAULT_DEV), - SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, SUS::MAX1227_SPI_FREQ); + SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, spi::SUS_MAX1227_SPI_FREQ); SpiCookie* spiCookieSus12 = new SpiCookie(addresses::SUS_12, gpio::NO_GPIO, std::string(q7s::SPI_DEFAULT_DEV), - SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, SUS::MAX1227_SPI_FREQ); + SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, spi::SUS_MAX1227_SPI_FREQ); SpiCookie* spiCookieSus13 = new SpiCookie(addresses::SUS_13, gpio::NO_GPIO, std::string(q7s::SPI_DEFAULT_DEV), - SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, SUS::MAX1227_SPI_FREQ); + SUS::MAX_CMD_SIZE, spi::DEFAULT_MAX_1227_MODE, spi::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); + new SusHandler(objects::SUS_1, 0, objects::SPI_COM_IF, spiCookieSus1); + new SusHandler(objects::SUS_2, 1, objects::SPI_COM_IF, spiCookieSus2); + new SusHandler(objects::SUS_3, 2, objects::SPI_COM_IF, spiCookieSus3); + new SusHandler(objects::SUS_4, 3, objects::SPI_COM_IF, spiCookieSus4); + new SusHandler(objects::SUS_5, 4, objects::SPI_COM_IF, spiCookieSus5); + new SusHandler(objects::SUS_6, 5, objects::SPI_COM_IF, spiCookieSus6); + new SusHandler(objects::SUS_7, 6, objects::SPI_COM_IF, spiCookieSus7); + new SusHandler(objects::SUS_8, 7, objects::SPI_COM_IF, spiCookieSus8); + new SusHandler(objects::SUS_9, 8, objects::SPI_COM_IF, spiCookieSus9); + new SusHandler(objects::SUS_10, 9, objects::SPI_COM_IF, spiCookieSus10); + new SusHandler(objects::SUS_11, 10, objects::SPI_COM_IF, spiCookieSus11); + new SusHandler(objects::SUS_12, 11, objects::SPI_COM_IF, spiCookieSus12); + new SusHandler(objects::SUS_13, 12, objects::SPI_COM_IF, spiCookieSus13); } void ObjectFactory::createAcsBoardComponents(LinuxLibgpioIF* gpioComIF, UartComIF* uartComIF) { diff --git a/common/config/devConf.h b/common/config/devConf.h index 78681ec7..deea6aa2 100644 --- a/common/config/devConf.h +++ b/common/config/devConf.h @@ -23,7 +23,13 @@ static constexpr uint32_t DEFAULT_L3G_SPEED = 976'000; static constexpr uint32_t L3G_TRANSITION_DELAY = 5000; static constexpr spi::SpiModes DEFAULT_L3G_MODE = spi::SpiModes::MODE_3; -static constexpr uint32_t DEFAULT_MAX_1227_SPEED = 3'900'000; +/** + * 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 SUS_MAX1227_SPI_FREQ = 976'000; + +static constexpr uint32_t DEFAULT_MAX_1227_SPEED = 976'000; static constexpr spi::SpiModes DEFAULT_MAX_1227_MODE = spi::SpiModes::MODE_3; static constexpr uint32_t DEFAULT_ADIS16507_SPEED = 976'000; diff --git a/linux/devices/CMakeLists.txt b/linux/devices/CMakeLists.txt index 8d3272a1..e50b7626 100644 --- a/linux/devices/CMakeLists.txt +++ b/linux/devices/CMakeLists.txt @@ -1,4 +1,3 @@ target_sources(${OBSW_NAME} PRIVATE SolarArrayDeploymentHandler.cpp - SusHandler.cpp ) diff --git a/linux/devices/SusHandler.cpp b/linux/devices/SusHandler.cpp deleted file mode 100644 index 44755f41..00000000 --- a/linux/devices/SusHandler.cpp +++ /dev/null @@ -1,214 +0,0 @@ -#include "SusHandler.h" - -#include -#include - -#include "OBSWConfig.h" - -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 && OBSW_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/linux/fsfwconfig/pollingsequence/pollingSequenceFactory.cpp b/linux/fsfwconfig/pollingsequence/pollingSequenceFactory.cpp index 9ddff5d3..38717c37 100644 --- a/linux/fsfwconfig/pollingsequence/pollingSequenceFactory.cpp +++ b/linux/fsfwconfig/pollingsequence/pollingSequenceFactory.cpp @@ -1,13 +1,13 @@ #include "pollingSequenceFactory.h" +#include "OBSWConfig.h" +#include "objects/systemObjectList.h" #include #include #include #include -#include "OBSWConfig.h" -#include "linux/devices/SusHandler.h" -#include "objects/systemObjectList.h" + ReturnValue_t pst::pstGpio(FixedTimeslotTaskIF *thisSequence) { // Length of a communication cycle diff --git a/mission/devices/CMakeLists.txt b/mission/devices/CMakeLists.txt index 680cc64c..dc4b6308 100644 --- a/mission/devices/CMakeLists.txt +++ b/mission/devices/CMakeLists.txt @@ -17,4 +17,5 @@ target_sources(${LIB_EIVE_MISSION} PRIVATE GyroADIS1650XHandler.cpp RwHandler.cpp max1227.cpp + SusHandler.cpp ) diff --git a/mission/devices/SusHandler.cpp b/mission/devices/SusHandler.cpp new file mode 100644 index 00000000..9c55409e --- /dev/null +++ b/mission/devices/SusHandler.cpp @@ -0,0 +1,232 @@ +#include "SusHandler.h" + +#include +#include + +#include "OBSWConfig.h" + +SusHandler::SusHandler(object_id_t objectId, uint8_t susIdx, object_id_t comIF, CookieIF *comCookie) + : DeviceHandlerBase(objectId, comIF, comCookie), divider(5), dataset(this), susIdx(susIdx) {} + +SusHandler::~SusHandler() {} + +ReturnValue_t SusHandler::initialize() { + ReturnValue_t result = RETURN_OK; + result = DeviceHandlerBase::initialize(); + if (result != RETURN_OK) { + return result; + } + return RETURN_OK; +} + +void SusHandler::doStartUp() { + if (comState == ComStates::IDLE) { + comState = ComStates::WRITE_SETUP; + commandExecuted = false; + } + if (comState == ComStates::WRITE_SETUP) { + if (commandExecuted) { + if (goToNormalModeImmediately) { + setMode(MODE_NORMAL); + } else { + setMode(_MODE_TO_ON); + } + commandExecuted = false; + if (clkMode == ClkModes::INT_CLOCKED) { + comState = ComStates::START_INT_CLOCKED_CONVERSIONS; + } else { + comState = ComStates::EXT_CLOCKED_CONVERSIONS; + } + } + } +} + +void SusHandler::doShutDown() { setMode(_MODE_POWER_DOWN); } + +ReturnValue_t SusHandler::buildNormalDeviceCommand(DeviceCommandId_t *id) { + switch (comState) { + case (ComStates::IDLE): { + break; + } + case (ComStates::WRITE_SETUP): { + *id = SUS::WRITE_SETUP; + return buildCommandFromCommand(*id, nullptr, 0); + } + case (ComStates::EXT_CLOCKED_CONVERSIONS): { + *id = SUS::READ_EXT_TIMED_CONVERSIONS; + return buildCommandFromCommand(*id, nullptr, 0); + } + case (ComStates::START_INT_CLOCKED_CONVERSIONS): { + *id = SUS::START_INT_TIMED_CONVERSIONS; + comState = ComStates::READ_INT_CLOCKED_CONVERSIONS; + return buildCommandFromCommand(*id, nullptr, 0); + } + case (ComStates::READ_INT_CLOCKED_CONVERSIONS): { + *id = SUS::READ_INT_TIMED_CONVERSIONS; + comState = ComStates::START_INT_CLOCKED_CONVERSIONS; + return buildCommandFromCommand(*id, nullptr, 0); + } + case (ComStates::EXT_CLOCKED_TEMP): { + *id = SUS::READ_EXT_TIMED_TEMPS; + return buildCommandFromCommand(*id, nullptr, 0); + } + } + return NOTHING_TO_SEND; +} + +ReturnValue_t SusHandler::buildTransitionDeviceCommand(DeviceCommandId_t *id) { + if (comState == ComStates::WRITE_SETUP) { + *id = SUS::WRITE_SETUP; + return buildCommandFromCommand(*id, nullptr, 0); + } + return HasReturnvaluesIF::RETURN_OK; +} + +ReturnValue_t SusHandler::buildCommandFromCommand(DeviceCommandId_t deviceCommand, + const uint8_t *commandData, + size_t commandDataLen) { + using namespace max1227; + switch (deviceCommand) { + case (SUS::WRITE_SETUP): { + if (clkMode == ClkModes::INT_CLOCKED) { + cmdBuffer[0] = SUS::SETUP_INT_CLOKED; + } else { + cmdBuffer[0] = SUS::SETUP_EXT_CLOCKED; + } + + rawPacket = cmdBuffer; + rawPacketLen = 1; + break; + } + case (SUS::START_INT_TIMED_CONVERSIONS): { + std::memset(cmdBuffer, 0, sizeof(cmdBuffer)); + cmdBuffer[0] = max1227::buildResetByte(true); + cmdBuffer[1] = SUS::CONVERSION; + rawPacket = cmdBuffer; + rawPacketLen = 2; + break; + } + case (SUS::READ_INT_TIMED_CONVERSIONS): { + std::memset(cmdBuffer, 0, sizeof(cmdBuffer)); + rawPacket = cmdBuffer; + rawPacketLen = SUS::SIZE_READ_INT_CONVERSIONS; + break; + } + case (SUS::READ_EXT_TIMED_CONVERSIONS): { + std::memset(cmdBuffer, 0, sizeof(cmdBuffer)); + rawPacket = cmdBuffer; + for (uint8_t idx = 0; idx < 6; idx++) { + cmdBuffer[idx * 2] = buildConvByte(ScanModes::N_ONCE, idx, false); + cmdBuffer[idx * 2 + 1] = 0; + } + cmdBuffer[12] = 0x00; + rawPacketLen = SUS::SIZE_READ_EXT_CONVERSIONS; + break; + } + case (SUS::READ_EXT_TIMED_TEMPS): { + cmdBuffer[0] = buildConvByte(ScanModes::N_ONCE, 0, true); + std::memset(cmdBuffer + 1, 0, 24); + rawPacket = cmdBuffer; + rawPacketLen = 25; + break; + } + default: + return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; + } + return HasReturnvaluesIF::RETURN_OK; +} + +void SusHandler::fillCommandAndReplyMap() { + insertInCommandAndReplyMap(SUS::WRITE_SETUP, 1); + insertInCommandAndReplyMap(SUS::START_INT_TIMED_CONVERSIONS, 1); + insertInCommandAndReplyMap(SUS::READ_INT_TIMED_CONVERSIONS, 1, &dataset, + SUS::SIZE_READ_INT_CONVERSIONS); + insertInCommandAndReplyMap(SUS::READ_EXT_TIMED_CONVERSIONS, 1, &dataset, + SUS::SIZE_READ_EXT_CONVERSIONS); + insertInCommandAndReplyMap(SUS::READ_EXT_TIMED_TEMPS, 1); +} + +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::WRITE_SETUP: { + if (mode == _MODE_START_UP) { + commandExecuted = true; + } + return HasReturnvaluesIF::RETURN_OK; + } + case SUS::START_INT_TIMED_CONVERSIONS: { + return HasReturnvaluesIF::RETURN_OK; + } + case SUS::READ_INT_TIMED_CONVERSIONS: { + PoolReadGuard readSet(&dataset); + + dataset.temperatureCelcius = max1227::getTemperature(((packet[0] & 0x0f) << 8) | packet[1]); + for (uint8_t idx = 0; idx < 6; idx++) { + dataset.channels[idx] = packet[idx * 2 + 2] << 8 | packet[idx * 2 + 3]; + } + printDataset(); + break; + } + case (SUS::READ_EXT_TIMED_CONVERSIONS): { + PoolReadGuard readSet(&dataset); + for (uint8_t idx = 0; idx < 6; idx++) { + dataset.channels[idx] = packet[idx * 2 + 1] << 8 | packet[idx * 2 + 2]; + } + // Read temperature in next read cycle + if (clkMode == ClkModes::EXT_CLOCKED_WITH_TEMP) { + comState = ComStates::EXT_CLOCKED_TEMP; + } + printDataset(); + break; + } + case (SUS::READ_EXT_TIMED_TEMPS): { + PoolReadGuard readSet(&dataset); + dataset.temperatureCelcius = max1227::getTemperature(((packet[23] & 0x0f) << 8) | packet[24]); + comState = ComStates::EXT_CLOCKED_CONVERSIONS; + break; + } + default: { + sif::debug << "SusHandler::interpretDeviceReply: Unknown reply id" << std::endl; + return DeviceHandlerIF::UNKNOWN_DEVICE_REPLY; + } + } + return HasReturnvaluesIF::RETURN_OK; +} + +uint32_t SusHandler::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) { return 2000; } + +ReturnValue_t SusHandler::initializeLocalDataPool(localpool::DataPool &localDataPoolMap, + LocalDataPoolManager &poolManager) { + localDataPoolMap.emplace(SUS::TEMPERATURE_C, &tempC); + localDataPoolMap.emplace(SUS::CHANNEL_VEC, &channelVec); + return HasReturnvaluesIF::RETURN_OK; +} + +void SusHandler::setToGoToNormalMode(bool enable) { this->goToNormalModeImmediately = enable; } + +void SusHandler::printDataset() { + if (periodicPrintout) { + if (divider.checkAndIncrement()) { + sif::info << "SUS ADC " << static_cast(susIdx) << " hex [" << std::setfill('0') << std::hex; + for (uint8_t idx = 0; idx < 6; idx++) { + sif::info << std::setw(3) << dataset.channels[idx]; + if (idx < 6 - 1) { + sif::info << ","; + } + } + sif::info << "] | T[C] " << std::dec << dataset.temperatureCelcius.value << std::endl; + } + } +} + +void SusHandler::enablePeriodicPrintout(bool enable, uint8_t divider) { + this->periodicPrintout = enable; + this->divider.setDivider(divider); +} diff --git a/linux/devices/SusHandler.h b/mission/devices/SusHandler.h similarity index 58% rename from linux/devices/SusHandler.h rename to mission/devices/SusHandler.h index 0eab5fd0..18587c71 100644 --- a/linux/devices/SusHandler.h +++ b/mission/devices/SusHandler.h @@ -2,16 +2,18 @@ #define MISSION_DEVICES_SUSHANDLER_H_ #include -#include #include "devicedefinitions/SusDefinitions.h" +#include "fsfw/globalfunctions/PeriodicOperationDivider.h" +#include "mission/devices/max1227.h" /** - * @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 + * @brief This is the device handler class for the SUS sensor based on the MAX1227 ADC. * - * @details Datasheet of MAX1227: https://datasheets.maximintegrated.com/en/ds/MAX1227-MAX1231.pdf + * @details + * Datasheet of MAX1227: https://datasheets.maximintegrated.com/en/ds/MAX1227-MAX1231.pdf + * 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 * * @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 @@ -21,15 +23,17 @@ */ class SusHandler : public DeviceHandlerBase { public: + enum ClkModes { INT_CLOCKED, EXT_CLOCKED, EXT_CLOCKED_WITH_TEMP }; + static const uint8_t FIRST_WRITE = 7; - SusHandler(object_id_t objectId, object_id_t comIF, CookieIF* comCookie, - LinuxLibgpioIF* gpioComIF, gpioId_t chipSelectId); + SusHandler(object_id_t objectId, uint8_t susIdx, object_id_t comIF, CookieIF* comCookie); virtual ~SusHandler(); - virtual ReturnValue_t performOperation(uint8_t counter) override; + void enablePeriodicPrintout(bool enable, uint8_t divider); virtual ReturnValue_t initialize() override; + void setToGoToNormalMode(bool enable); protected: void doStartUp() override; @@ -42,7 +46,6 @@ class SusHandler : public DeviceHandlerBase { 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; @@ -53,19 +56,34 @@ class SusHandler : public DeviceHandlerBase { 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 }; + enum class ComStates { + IDLE, + WRITE_SETUP, + EXT_CLOCKED_CONVERSIONS, + EXT_CLOCKED_TEMP, + START_INT_CLOCKED_CONVERSIONS, + READ_INT_CLOCKED_CONVERSIONS + }; - LinuxLibgpioIF* gpioComIF = nullptr; - - gpioId_t chipSelectId = gpio::NO_GPIO; + bool periodicPrintout = false; + PeriodicOperationDivider divider; + bool goToNormalModeImmediately = false; + bool commandExecuted = false; SUS::SusDataset dataset; + // Read temperature in each alternating communication step when using + // externally clocked mode + ClkModes clkMode = ClkModes::INT_CLOCKED; + PoolEntry tempC = PoolEntry({0.0}); + PoolEntry channelVec = PoolEntry({0, 0, 0, 0, 0, 0}); + uint8_t susIdx = 0; uint8_t cmdBuffer[SUS::MAX_CMD_SIZE]; - CommunicationStep communicationStep = CommunicationStep::IDLE; + ComStates comState = ComStates::IDLE; MutexIF::TimeoutType timeoutType = MutexIF::TimeoutType::WAITING; uint32_t timeoutMs = 20; + void printDataset(); MutexIF* spiMutex = nullptr; }; diff --git a/linux/devices/devicedefinitions/SusDefinitions.h b/mission/devices/devicedefinitions/SusDefinitions.h similarity index 64% rename from linux/devices/devicedefinitions/SusDefinitions.h rename to mission/devices/devicedefinitions/SusDefinitions.h index 2a45ebc5..973ae051 100644 --- a/linux/devices/devicedefinitions/SusDefinitions.h +++ b/mission/devices/devicedefinitions/SusDefinitions.h @@ -8,25 +8,23 @@ 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; +static const DeviceCommandId_t WRITE_SETUP = 1; /** * This command initiates the ADC conversion for all channels including the internal * temperature sensor. */ -static const DeviceCommandId_t START_CONVERSIONS = 0x2; +static const DeviceCommandId_t START_INT_TIMED_CONVERSIONS = 2; /** * This command reads the internal fifo which holds the temperature and the channel * conversions. */ -static const DeviceCommandId_t READ_CONVERSIONS = 0x3; +static constexpr DeviceCommandId_t READ_INT_TIMED_CONVERSIONS = 3; + +static constexpr DeviceCommandId_t READ_EXT_TIMED_CONVERSIONS = 4; + +static constexpr DeviceCommandId_t READ_EXT_TIMED_TEMPS = 5; /** * @brief This is the configuration byte which will be written to the setup register after @@ -39,7 +37,8 @@ static const DeviceCommandId_t READ_CONVERSIONS = 0x3; * written to the setup register * */ -static const uint8_t SETUP = 0b01101000; +static constexpr uint8_t SETUP_INT_CLOKED = 0b01101000; +static constexpr uint8_t SETUP_EXT_CLOCKED = 0b01111000; /** * @brief This values will always be written to the ADC conversion register to specify the @@ -51,24 +50,18 @@ static const uint8_t SETUP = 0b01101000; */ static const uint8_t CONVERSION = 0b10101001; -static const uint8_t SUS_DATA_SET_ID = READ_CONVERSIONS; +static const uint8_t SUS_DATA_SET_ID = READ_INT_TIMED_CONVERSIONS; /** Size of data replies. Temperature and 6 channel convesions (AIN0 - AIN5) */ -static const uint8_t SIZE_READ_CONVERSIONS = 14; +static const uint8_t SIZE_READ_INT_CONVERSIONS = 14; +// 6 * conv byte, 6 * 0 and one trailing zero +static constexpr uint8_t SIZE_READ_EXT_CONVERSIONS = 13; -static const uint8_t MAX_CMD_SIZE = SIZE_READ_CONVERSIONS; +static const uint8_t MAX_CMD_SIZE = 32; static const uint8_t POOL_ENTRIES = 7; -enum Max1227PoolIds : lp_id_t { - TEMPERATURE_C, - AIN0, - AIN1, - AIN2, - AIN3, - AIN4, - AIN5, -}; +enum Max1227PoolIds : lp_id_t { TEMPERATURE_C, CHANNEL_VEC }; class SusDataset : public StaticLocalDataSet { public: @@ -77,12 +70,7 @@ class SusDataset : public StaticLocalDataSet { 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); + lp_vec_t channels = lp_vec_t(sid.objectId, CHANNEL_VEC, this); }; } // namespace SUS