#include "PayloadPcduHandler.h" #include #include "devices/gpioIds.h" PayloadPcduHandler::PayloadPcduHandler(object_id_t objectId, object_id_t comIF, CookieIF* cookie, GpioIF* gpioIF, bool periodicPrintout) : DeviceHandlerBase(objectId, comIF, cookie), adcSet(this), periodicPrintout(periodicPrintout), gpioIF(gpioIF) {} void PayloadPcduHandler::doStartUp() { if ((state != States::PCDU_OFF) and (state != States::ON_TRANS_SSR)) { // Config error sif::error << "PayloadPcduHandler::doStartUp: Invalid state" << std::endl; } if (state == States::PCDU_OFF) { // Switch on relays here gpioIF->pullHigh(gpioIds::PLPCDU_ENB_VBAT0); gpioIF->pullHigh(gpioIds::PLPCDU_ENB_VBAT1); state = States::ON_TRANS_SSR; transitionOk = true; } if (state == States::ON_TRANS_SSR) { // If necessary, check whether a certain amount of time has elapsed if (transitionOk) { transitionOk = false; // We are now in ON mode startTransition(MODE_NORMAL, 0); adcState = AdcStates::BOOT_DELAY; // The ADC can now be read. If the values are not close to zero, we should not allow // transition monMode = MonitoringMode::CLOSE_TO_ZERO; } } } void PayloadPcduHandler::doTransition(Mode_t modeFrom, Submode_t subModeFrom) { if (mode == _MODE_TO_NORMAL) { stateMachineToNormal(); } } void PayloadPcduHandler::doShutDown() {} ReturnValue_t PayloadPcduHandler::buildNormalDeviceCommand(DeviceCommandId_t* id) { switch (adcState) { case (AdcStates::SEND_SETUP): { *id = plpcdu::SETUP_CMD; return buildCommandFromCommand(*id, nullptr, 0); } case (AdcStates::NORMAL): { *id = plpcdu::READ_WITH_TEMP; return buildCommandFromCommand(*id, nullptr, 0); } default: { break; } } return NOTHING_TO_SEND; } ReturnValue_t PayloadPcduHandler::buildTransitionDeviceCommand(DeviceCommandId_t* id) { if (adcState == AdcStates::SEND_SETUP) { *id = plpcdu::SETUP_CMD; return buildCommandFromCommand(*id, nullptr, 0); } return NOTHING_TO_SEND; } void PayloadPcduHandler::fillCommandAndReplyMap() { insertInCommandAndReplyMap(plpcdu::READ_CMD, 2, &adcSet); insertInCommandAndReplyMap(plpcdu::READ_TEMP, 1, &adcSet); insertInCommandAndReplyMap(plpcdu::READ_WITH_TEMP, 1, &adcSet); insertInCommandAndReplyMap(plpcdu::SETUP_CMD, 1); } ReturnValue_t PayloadPcduHandler::buildCommandFromCommand(DeviceCommandId_t deviceCommand, const uint8_t* commandData, size_t commandDataLen) { switch (deviceCommand) { case (plpcdu::SETUP_CMD): { cmdBuf[0] = plpcdu::SETUP_BYTE; rawPacket = cmdBuf.data(); rawPacketLen = 1; break; } case (plpcdu::READ_CMD): { max1227::prepareExternallyClockedRead0ToN(cmdBuf.data(), plpcdu::CHANNEL_N, rawPacketLen); rawPacket = cmdBuf.data(); break; } case (plpcdu::READ_TEMP): { max1227::prepareExternallyClockedTemperatureRead(cmdBuf.data(), rawPacketLen); rawPacket = cmdBuf.data(); break; } case (plpcdu::READ_WITH_TEMP): { size_t sz = 0; max1227::prepareExternallyClockedRead0ToN(cmdBuf.data(), plpcdu::CHANNEL_N, sz); max1227::prepareExternallyClockedTemperatureRead(cmdBuf.data() + sz, sz); rawPacketLen = sz; rawPacket = cmdBuf.data(); break; } default: { return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; } } return RETURN_OK; } ReturnValue_t PayloadPcduHandler::scanForReply(const uint8_t* start, size_t remainingSize, DeviceCommandId_t* foundId, size_t* foundLen) { // SPI is full duplex *foundId = getPendingCommand(); *foundLen = remainingSize; return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t PayloadPcduHandler::interpretDeviceReply(DeviceCommandId_t id, const uint8_t* packet) { using namespace plpcdu; switch (id) { case (SETUP_CMD): { if (mode == _MODE_TO_NORMAL) { adcCmdExecuted = true; } break; } case (READ_TEMP): { uint8_t tempStartIdx = TEMP_REPLY_SIZE - 2; adcSet.tempC.value = max1227::getTemperature(packet[tempStartIdx] << 8 | packet[tempStartIdx + 1]); break; } case (READ_CMD): { PoolReadGuard pg(&adcSet); if (pg.getReadResult() != HasReturnvaluesIF::RETURN_OK) { return pg.getReadResult(); } handleExtConvRead(packet); handlePrintout(); break; } case (READ_WITH_TEMP): { PoolReadGuard pg(&adcSet); if (pg.getReadResult() != HasReturnvaluesIF::RETURN_OK) { return pg.getReadResult(); } handleExtConvRead(packet); uint8_t tempStartIdx = ADC_REPLY_SIZE + TEMP_REPLY_SIZE - 2; adcSet.tempC.value = max1227::getTemperature(packet[tempStartIdx] << 8 | packet[tempStartIdx + 1]); handlePrintout(); break; } default: { break; } } return HasReturnvaluesIF::RETURN_OK; } uint32_t PayloadPcduHandler::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) { // 20 minutes transition delay is allowed return 20 * 60 * 60; } ReturnValue_t PayloadPcduHandler::initializeLocalDataPool(localpool::DataPool& localDataPoolMap, LocalDataPoolManager& poolManager) { localDataPoolMap.emplace(plpcdu::PlPcduPoolIds::CHANNEL_VEC, &channelValues); localDataPoolMap.emplace(plpcdu::PlPcduPoolIds::TEMP, &tempC); return HasReturnvaluesIF::RETURN_OK; } void PayloadPcduHandler::setToGoToNormalModeImmediately(bool enable) { this->goToNormalMode = enable; } void PayloadPcduHandler::handleExtConvRead(const uint8_t* bufStart) { for (uint8_t idx = 0; idx < 12; idx++) { adcSet.channels[idx] = bufStart[idx * 2 + 1] << 8 | bufStart[idx * 2 + 2]; } } void PayloadPcduHandler::handlePrintout() { if (periodicPrintout) { if (opDivider.checkAndIncrement()) { sif::info << "PL PCDU ADC hex [" << std::setfill('0') << std::hex; for (uint8_t idx = 0; idx < 12; idx++) { sif::info << std::setw(3) << adcSet.channels[idx]; if (idx < 11) { sif::info << ","; } } sif::info << "] | T[C] " << std::dec << adcSet.tempC.value << std::endl; } } } void PayloadPcduHandler::enablePeriodicPrintout(bool enable, uint8_t divider) { this->periodicPrintout = enable; opDivider.setDivider(divider); } void PayloadPcduHandler::stateMachineToNormal() { if (adcState == AdcStates::BOOT_DELAY) { if (adcCountdown.hasTimedOut()) { adcState = AdcStates::SEND_SETUP; adcCmdExecuted = false; } } if (adcState == AdcStates::SEND_SETUP) { if (adcCmdExecuted) { adcState = AdcStates::NORMAL; setMode(MODE_NORMAL, plpcdu::NORMAL_ADC_ONLY); adcCmdExecuted = false; } } if (submode == plpcdu::NORMAL_ALL_ON) { if (state == States::ON_TRANS_ADC_CLOSE_ZERO) { if (not commandExecuted) { countdown.resetTimer(); commandExecuted = true; } // ADC values are ok, 5 seconds have elapsed if (transitionOk and countdown.hasTimedOut()) { state = States::ON_TRANS_DRO; // Now start monitoring for negative voltages instead monMode = MonitoringMode::NEGATIVE; countdown.resetTimer(); commandExecuted = false; transitionOk = false; } } if (state == States::ON_TRANS_DRO) { if (not commandExecuted) { // Switch on DRO and start monitoring for negative voltagea gpioIF->pullHigh(gpioIds::PLPCDU_ENB_DRO); commandExecuted = true; } // ADC values are ok, 5 seconds have elapsed if (transitionOk and countdown.hasTimedOut()) { state = States::ON_TRANS_X8; countdown.resetTimer(); commandExecuted = false; transitionOk = false; } } if (state == States::ON_TRANS_X8) { if (not commandExecuted) { // Switch on X8 gpioIF->pullHigh(gpioIds::PLPCDU_ENB_X8); commandExecuted = true; } // ADC values are ok, 5 seconds have elapsed if (transitionOk and countdown.hasTimedOut()) { state = States::ON_TRANS_TX; countdown.resetTimer(); commandExecuted = false; transitionOk = false; } } if (state == States::ON_TRANS_TX) { if (not commandExecuted) { // Switch on TX gpioIF->pullHigh(gpioIds::PLPCDU_ENB_TX); commandExecuted = true; } // ADC values are ok, 5 seconds have elapsed if (transitionOk and countdown.hasTimedOut()) { state = States::ON_TRANS_MPA; countdown.resetTimer(); commandExecuted = false; transitionOk = false; } } if (state == States::ON_TRANS_MPA) { if (not commandExecuted) { // Switch on MPA gpioIF->pullHigh(gpioIds::PLPCDU_ENB_MPA); commandExecuted = true; } // ADC values are ok, 5 seconds have elapsed if (transitionOk and countdown.hasTimedOut()) { state = States::ON_TRANS_HPA; countdown.resetTimer(); commandExecuted = false; transitionOk = false; } } if (state == States::ON_TRANS_HPA) { if (not commandExecuted) { // Switch on HPA gpioIF->pullHigh(gpioIds::PLPCDU_ENB_HPA); commandExecuted = true; } // ADC values are ok, 5 seconds have elapsed if (transitionOk and countdown.hasTimedOut()) { state = States::PCDU_ON; setMode(MODE_NORMAL, plpcdu::NORMAL_ALL_ON); countdown.resetTimer(); commandExecuted = false; transitionOk = false; } } } }