#include "GomspaceDeviceHandler.h" #include #include #include "devicedefinitions/GomSpacePackets.h" #include "devicedefinitions/powerDefinitions.h" GomspaceDeviceHandler::GomspaceDeviceHandler(object_id_t objectId, object_id_t comIF, CookieIF* comCookie, FailureIsolationBase* customFdir, uint16_t maxConfigTableAddress, uint16_t maxHkTableAddress, uint16_t hkTableReplySize) : DeviceHandlerBase(objectId, comIF, comCookie, customFdir), maxConfigTableAddress(maxConfigTableAddress), maxHkTableAddress(maxHkTableAddress), hkTableReplySize(hkTableReplySize) { if (comCookie == nullptr) { sif::error << "GomspaceDeviceHandler::GomspaceDeviceHandler: Invalid com cookie" << std::endl; } } GomspaceDeviceHandler::~GomspaceDeviceHandler() {} void GomspaceDeviceHandler::doStartUp() {} void GomspaceDeviceHandler::doShutDown() {} ReturnValue_t GomspaceDeviceHandler::buildNormalDeviceCommand(DeviceCommandId_t* id) { return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t GomspaceDeviceHandler::buildTransitionDeviceCommand(DeviceCommandId_t* id) { return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t GomspaceDeviceHandler::handleAction(PrintSwitchVIAction* action) { return printStatus(action->getId()); } ReturnValue_t GomspaceDeviceHandler::handleAction(PrintLatchupsAction* action) { return printStatus(action->getId()); } void GomspaceDeviceHandler::fillCommandAndReplyMap() { this->insertInCommandAndReplyMap(GOMSPACE::PING, 3); this->insertInCommandMap(GOMSPACE::REBOOT); this->insertInCommandAndReplyMap(GOMSPACE::PARAM_SET, 3); this->insertInCommandAndReplyMap(GOMSPACE::PARAM_GET, 3); this->insertInCommandAndReplyMap(GOMSPACE::REQUEST_HK_TABLE, 3); this->insertInCommandMap(GOMSPACE::GNDWDT_RESET); this->insertInCommandMap(GOMSPACE::PRINT_SWITCH_V_I); this->insertInCommandMap(GOMSPACE::PRINT_LATCHUPS); } ReturnValue_t GomspaceDeviceHandler::scanForReply(const uint8_t* start, size_t remainingSize, DeviceCommandId_t* foundId, size_t* foundLen) { switch (rememberCommandId) { case (GOMSPACE::PING): *foundId = GOMSPACE::PING; *foundLen = PING_REPLY_SIZE; rememberCommandId = GOMSPACE::NONE; break; case (GOMSPACE::PARAM_GET): { *foundId = GOMSPACE::PARAM_GET; *foundLen = rememberRequestedSize + GOMSPACE::GS_HDR_LENGTH; rememberCommandId = GOMSPACE::NONE; break; } case (GOMSPACE::PARAM_SET): { *foundId = GOMSPACE::PARAM_SET; *foundLen = rememberRequestedSize; rememberCommandId = GOMSPACE::NONE; break; } case (GOMSPACE::REQUEST_HK_TABLE): { *foundId = GOMSPACE::REQUEST_HK_TABLE; *foundLen = rememberRequestedSize + GOMSPACE::GS_HDR_LENGTH; rememberCommandId = GOMSPACE::NONE; break; } default: return IGNORE_REPLY_DATA; } return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t GomspaceDeviceHandler::interpretDeviceReply(DeviceCommandId_t id, const uint8_t* packet) { switch (id) { case (GOMSPACE::PING): { SerializeElement replyTime = *packet; handleDeviceTM(&replyTime, id, true); break; } case (GOMSPACE::PARAM_GET): { // -2 to subtract address size from gomspace parameter reply packet uint16_t payloadLength = (*(packet + 2) << 8 | *(packet + 3)) - 2; if (payloadLength > sizeof(uint32_t)) { sif::error << "GomspaceDeviceHandler: PARAM_GET: Invalid payload " << "size in reply" << std::endl; return INVALID_PAYLOAD_SIZE; } uint8_t tempPayloadBuffer[payloadLength]; /* Extract information from received data */ CspGetParamReply cspGetParamReply(tempPayloadBuffer, payloadLength); size_t size = GOMSPACE::GS_HDR_LENGTH + payloadLength; ReturnValue_t result = cspGetParamReply.deSerialize(&packet, &size, SerializeIF::Endianness::BIG); if (result != HasReturnvaluesIF::RETURN_OK) { sif::error << "GomspaceDeviceHandler: Failed to deserialize get parameter" << "reply" << std::endl; return result; } uint8_t action = cspGetParamReply.getAction(); uint8_t tableId = cspGetParamReply.getTableId(); uint16_t address = cspGetParamReply.getAddress(); /* Pack relevant information into a tm packet */ ParamReply paramReply(action, tableId, address, payloadLength, tempPayloadBuffer); handleDeviceTM(¶mReply, id, true); break; } case (GOMSPACE::PARAM_SET): { /* When setting a parameter, the p60dock sends back the state of the * operation */ if (*packet != PARAM_SET_OK) { return HasReturnvaluesIF::RETURN_FAILED; } // TODO fix setParamCallback(setParamCacher.getParameter(), setParamCacher.getParameter(), setParamCacher.getParameterSize(), true); break; } case (GOMSPACE::REQUEST_HK_TABLE): { letChildHandleHkReply(id, packet); break; } default: break; } return HasReturnvaluesIF::RETURN_OK; } void GomspaceDeviceHandler::setNormalDatapoolEntriesInvalid() {} ReturnValue_t GomspaceDeviceHandler::handleAction(ParamSetAction* action) { // This breaks layering but I really don't want to accept this command.. if (action->address == PDU2::CONFIG_ADDRESS_OUT_EN_Q7S and this->getObjectId() == objects::PDU2_HANDLER) { triggerEvent(power::SWITCHING_Q7S_DENIED, 0, 0); return HasReturnvaluesIF::RETURN_FAILED; } //cache for later use setParamCacher.set(action->address, action->parameter, static_cast(action->parameterSize.value)); ReturnValue_t result = setParamCallback(action->address, action->parameter, static_cast(action->parameterSize.value), false); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } /* Get and check address */ if (action->address > maxConfigTableAddress) { sif::error << "GomspaceDeviceHandler: Invalid address for set parameter " << "action" << std::endl; return INVALID_ADDRESS; } uint16_t checksum = GOMSPACE::IGNORE_CHECKSUM; uint16_t seq = 0; uint16_t total = 0; /* CSP reply only contains the transaction state */ uint16_t querySize = 1; size_t parameterSize = 0; uint8_t parameterBytes[4]; uint8_t* uselessPointer = parameterBytes; switch (action->parameterSize.value) { case ParamSetAction::ParameterByteSize::ONE_BYTE: { if (action->parameter > 255) { return INVALID_PARAMETERS; } uint8_t oneByte = action->parameter.value; result = SerializeAdapter::serialize(&oneByte, &uselessPointer, ¶meterSize, sizeof(parameterBytes), SerializeIF::Endianness::BIG); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } parameterSize = 1; } break; case ParamSetAction::ParameterByteSize::TWO_BYTES: { if (action->parameter > 65535) { return INVALID_PARAMETERS; } uint16_t twoBytes = action->parameter.value; result = SerializeAdapter::serialize(&twoBytes, &uselessPointer, ¶meterSize, sizeof(parameterBytes), SerializeIF::Endianness::BIG); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } parameterSize = 2; } break; case ParamSetAction::ParameterByteSize::FOUR_BYTES: result = SerializeAdapter::serialize(&(action->parameter.value), &uselessPointer, ¶meterSize, sizeof(parameterBytes), SerializeIF::Endianness::BIG); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } parameterSize = 4; break; } uint16_t payloadlength = sizeof(action->address) + parameterSize; /* Generate command for CspComIF */ CspSetParamCommand setParamCmd(querySize, payloadlength, checksum, seq, total, action->address, parameterBytes, parameterSize); size_t cspPacketLen = 0; uint8_t* buffer = cspPacket; result = setParamCmd.serialize(&buffer, &cspPacketLen, sizeof(cspPacket), SerializeIF::Endianness::BIG); if (result != HasReturnvaluesIF::RETURN_OK) { sif::error << "GomspaceDeviceHandler: Failed to serialize command for " << "CspComIF" << std::endl; return result; } if (cspPacketLen > MAX_PACKET_LEN) { sif::error << "GomspaceDeviceHandler: Invalid length of set parameter " "command" << std::endl; return PACKET_TOO_LONG; } rawPacket = cspPacket; rawPacketLen = cspPacketLen; rememberRequestedSize = querySize; rememberCommandId = GOMSPACE::PARAM_SET; return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t GomspaceDeviceHandler::handleAction(ParamGetAction* action) { ReturnValue_t result; auto tableId = action->tableId.value; /* Get and check address */ uint16_t address = action->address; if (address > maxHkTableAddress && tableId == ParamGetAction::TableId::HK_TABLE_ID) { sif::error << "GomspaceDeviceHandler: Invalid address to get parameter from " << "housekeeping table" << std::endl; return INVALID_ADDRESS; } if (address > maxConfigTableAddress && tableId == ParamGetAction::TableId::CONFIG_TABLE_ID) { sif::error << "GomspaceDeviceHandler: Invalid address to get parameter from " << "configuration table" << std::endl; return INVALID_ADDRESS; } uint16_t length = sizeof(address); uint16_t checksum = GOMSPACE::IGNORE_CHECKSUM; uint16_t seq = 0; uint16_t total = 0; uint8_t parameterSize = static_cast(action->parameterSize.value); uint16_t querySize = parameterSize + GOMSPACE::GS_HDR_LENGTH; /* Generate the CSP command to send to the P60 Dock */ CspGetParamCommand getParamCmd(querySize, static_cast(tableId), length, checksum, seq, total, address); size_t cspPacketLen = 0; uint8_t* buffer = cspPacket; result = getParamCmd.serialize(&buffer, &cspPacketLen, sizeof(cspPacket), SerializeIF::Endianness::BIG); if (result != HasReturnvaluesIF::RETURN_OK) { sif::error << "GomspaceDeviceHandler: Failed to serialize command to " << "get parameter" << std::endl; } // checked by serialize above /* if (cspPacketLen > MAX_PACKET_LEN) { sif::error << "GomspaceDeviceHandler: Received invalid get parameter " "command" << std::endl; return PACKET_TOO_LONG; }*/ rawPacket = cspPacket; rawPacketLen = cspPacketLen; rememberRequestedSize = querySize; rememberCommandId = GOMSPACE::PARAM_GET; return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t GomspaceDeviceHandler::handleAction(PingAction* action) { CspPingCommand cspPingCommand(&action->pingData.value, 1); // TODO array size_t cspPacketLen = 0; uint8_t* buffer = cspPacket; ReturnValue_t result = cspPingCommand.serialize(&buffer, &cspPacketLen, sizeof(cspPacket), SerializeIF::Endianness::BIG); if (result != HasReturnvaluesIF::RETURN_OK) { sif::error << "GomspaceDeviceHandler: Failed to serialize ping command" << std::endl; return result; } /* Checked by the serialize function if (cspPacketLen > MAX_PACKET_LEN) { sif::error << "GomspaceDeviceHandler: Received invalid ping message" << std::endl; return PACKET_TOO_LONG; }*/ rawPacket = cspPacket; rawPacketLen = cspPacketLen; rememberCommandId = GOMSPACE::PING; return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t GomspaceDeviceHandler::handleAction(RebootAction* action) { uint8_t cspPort = GOMSPACE::REBOOT_PORT; uint16_t querySize = 0; *cspPacket = GOMSPACE::REBOOT_PORT; // TODO the following two lines look strange... *(cspPacket + 1) = querySize; size_t cspPacketLen = sizeof(cspPort) + sizeof(cspPacketLen); rawPacket = cspPacket; rawPacketLen = cspPacketLen; return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t GomspaceDeviceHandler::childCommandHook(DeviceCommandId_t cmd, const uint8_t* commandData, size_t commandDataLen) { return DeviceHandlerIF::COMMAND_NOT_IMPLEMENTED; } ReturnValue_t GomspaceDeviceHandler::setParamCallback(uint16_t address, uint32_t value, uint8_t valueBytes, bool afterExecution) { return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t GomspaceDeviceHandler::initializePduPool( localpool::DataPool& localDataPoolMap, LocalDataPoolManager& poolManager, std::array initOutEnb) { localDataPoolMap.emplace(P60System::pool::PDU_CURRENTS, new PoolEntry(9)); localDataPoolMap.emplace(P60System::pool::PDU_VOLTAGES, new PoolEntry(9)); localDataPoolMap.emplace(P60System::pool::PDU_VCC, new PoolEntry({0})); localDataPoolMap.emplace(P60System::pool::PDU_VBAT, new PoolEntry({0})); localDataPoolMap.emplace(P60System::pool::PDU_TEMPERATURE, new PoolEntry({0})); localDataPoolMap.emplace(P60System::pool::PDU_CONV_EN, new PoolEntry(3)); localDataPoolMap.emplace(P60System::pool::PDU_OUT_ENABLE, new PoolEntry(initOutEnb.data(), initOutEnb.size())); localDataPoolMap.emplace(P60System::pool::PDU_BOOTCAUSE, new PoolEntry({0})); localDataPoolMap.emplace(P60System::pool::PDU_BOOTCNT, new PoolEntry({0})); localDataPoolMap.emplace(P60System::pool::PDU_UPTIME, new PoolEntry({0})); localDataPoolMap.emplace(P60System::pool::PDU_RESETCAUSE, new PoolEntry({0})); localDataPoolMap.emplace(P60System::pool::PDU_BATT_MODE, new PoolEntry({0})); localDataPoolMap.emplace(P60System::pool::PDU_LATCHUPS, new PoolEntry(9)); localDataPoolMap.emplace(P60System::pool::PDU_DEVICES, new PoolEntry(8)); localDataPoolMap.emplace(P60System::pool::PDU_STATUSES, new PoolEntry(8)); localDataPoolMap.emplace(P60System::pool::PDU_WDT_CNT_GND, new PoolEntry({0})); localDataPoolMap.emplace(P60System::pool::PDU_WDT_CNT_I2C, new PoolEntry({0})); localDataPoolMap.emplace(P60System::pool::PDU_WDT_CNT_CAN, new PoolEntry({0})); localDataPoolMap.emplace(P60System::pool::PDU_WDT_CNT_CSP1, new PoolEntry({0})); localDataPoolMap.emplace(P60System::pool::PDU_WDT_CNT_CSP2, new PoolEntry({0})); localDataPoolMap.emplace(P60System::pool::PDU_WDT_GND_LEFT, new PoolEntry({0})); localDataPoolMap.emplace(P60System::pool::PDU_WDT_I2C_LEFT, new PoolEntry({0})); localDataPoolMap.emplace(P60System::pool::PDU_WDT_CAN_LEFT, new PoolEntry({0})); localDataPoolMap.emplace(P60System::pool::PDU_WDT_CSP_LEFT1, new PoolEntry({0})); localDataPoolMap.emplace(P60System::pool::PDU_WDT_CSP_LEFT2, new PoolEntry({0})); return RETURN_OK; } ReturnValue_t GomspaceDeviceHandler::handleAction(GndwdtResetAction* action) { WatchdogResetCommand watchdogResetCommand; size_t cspPacketLen = 0; uint8_t* buffer = cspPacket; ReturnValue_t result = watchdogResetCommand.serialize(&buffer, &cspPacketLen, sizeof(cspPacket), SerializeIF::Endianness::BIG); if (result != HasReturnvaluesIF::RETURN_OK) { sif::error << "GomspaceDeviceHandler: Failed to serialize watchdog reset " << "command" << std::endl; return result; } rawPacket = cspPacket; rawPacketLen = cspPacketLen; rememberRequestedSize = 0; // No bytes will be queried with the ground // watchdog command. rememberCommandId = GOMSPACE::GNDWDT_RESET; return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t GomspaceDeviceHandler::handleAction(RequestHkTableAction* action) { uint16_t querySize = hkTableReplySize; uint8_t tableId = static_cast(ParamGetAction::TableId::HK_TABLE_ID); RequestFullTableCommand requestFullTableCommand(querySize, tableId); size_t cspPacketLen = 0; uint8_t* buffer = cspPacket; ReturnValue_t result = requestFullTableCommand.serialize( &buffer, &cspPacketLen, sizeof(cspPacket), SerializeIF::Endianness::BIG); if (result != HasReturnvaluesIF::RETURN_OK) { sif::error << "GomspaceDeviceHandler::generateRequestFullHkTableCmd Failed to serialize " "full table request command " << std::endl; return result; } rawPacket = cspPacket; rawPacketLen = cspPacketLen; rememberRequestedSize = querySize; rememberCommandId = GOMSPACE::REQUEST_HK_TABLE; return RETURN_OK; } uint32_t GomspaceDeviceHandler::getTransitionDelayMs(Mode_t modeFrom, Mode_t modeTo) { return 0; } void GomspaceDeviceHandler::setModeNormal() { mode = MODE_NORMAL; } ReturnValue_t GomspaceDeviceHandler::printStatus(DeviceCommandId_t cmd) { sif::info << "No printHkTable implementation given.." << std::endl; return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t GomspaceDeviceHandler::parsePduHkTable(PDU::PduCoreHk& coreHk, PDU::PduAuxHk& auxHk, const uint8_t* packet) { uint16_t dataOffset = 0; PoolReadGuard pg0(&coreHk); PoolReadGuard pg1(&auxHk); if (pg0.getReadResult() != HasReturnvaluesIF::RETURN_OK or pg1.getReadResult() != HasReturnvaluesIF::RETURN_OK) { sif::warning << "Reading PDU1 datasets failed!" << std::endl; return HasReturnvaluesIF::RETURN_FAILED; } /* Fist 10 bytes contain the gomspace header. Each variable is preceded by the 16-bit table * address. */ dataOffset += 12; for (uint8_t idx = 0; idx < PDU::CHANNELS_LEN; idx++) { coreHk.currents[idx] = (packet[dataOffset] << 8) | packet[dataOffset + 1]; dataOffset += 4; } for (uint8_t idx = 0; idx < PDU::CHANNELS_LEN; idx++) { coreHk.voltages[idx] = (packet[dataOffset] << 8) | packet[dataOffset + 1]; dataOffset += 4; } auxHk.vcc = *(packet + dataOffset) << 8 | *(packet + dataOffset + 1); dataOffset += 4; auxHk.vbat = *(packet + dataOffset) << 8 | *(packet + dataOffset + 1); dataOffset += 4; coreHk.temperature = static_cast(*(packet + dataOffset) << 8 | *(packet + dataOffset + 1)) * 0.1; dataOffset += 4; for (uint8_t idx = 0; idx < 3; idx++) { auxHk.converterEnable[idx] = packet[dataOffset]; dataOffset += 3; } for (uint8_t idx = 0; idx < PDU::CHANNELS_LEN; idx++) { coreHk.outputEnables[idx] = packet[dataOffset]; dataOffset += 3; } auxHk.bootcause = *(packet + dataOffset) << 24 | *(packet + dataOffset + 1) << 16 | *(packet + dataOffset + 2) << 8 | *(packet + dataOffset + 3); dataOffset += 6; coreHk.bootcount = *(packet + dataOffset) << 24 | *(packet + dataOffset + 1) << 16 | *(packet + dataOffset + 2) << 8 | *(packet + dataOffset + 3); dataOffset += 6; auxHk.uptime = *(packet + dataOffset) << 24 | *(packet + dataOffset + 1) << 16 | *(packet + dataOffset + 2) << 8 | *(packet + dataOffset + 3); dataOffset += 6; auxHk.resetcause = *(packet + dataOffset + 1) << 8 | *(packet + dataOffset); dataOffset += 4; coreHk.battMode = *(packet + dataOffset); /* +10 because here begins the second gomspace csp packet */ dataOffset += 3 + 10; for (uint8_t idx = 0; idx < PDU::CHANNELS_LEN; idx++) { auxHk.latchups[idx] = *(packet + dataOffset) << 8 | *(packet + dataOffset + 1); dataOffset += 4; } for (uint8_t idx = 0; idx < PDU::DEVICES_NUM; idx++) { auxHk.deviceTypes[idx] = *(packet + dataOffset); dataOffset += 3; } for (uint8_t idx = 0; idx < PDU::DEVICES_NUM; idx++) { auxHk.devicesStatus[idx] = *(packet + dataOffset); dataOffset += 3; } auxHk.gndWdtReboots = *(packet + dataOffset) << 24 | *(packet + dataOffset + 1) << 16 | *(packet + dataOffset + 2) << 8 | *(packet + dataOffset + 3); dataOffset += 6; auxHk.i2cWdtReboots = *(packet + dataOffset) << 24 | *(packet + dataOffset + 1) << 16 | *(packet + dataOffset + 2) << 8 | *(packet + dataOffset + 3); dataOffset += 6; auxHk.canWdtReboots = *(packet + dataOffset) << 24 | *(packet + dataOffset + 1) << 16 | *(packet + dataOffset + 2) << 8 | *(packet + dataOffset + 3); dataOffset += 6; auxHk.csp1WdtReboots = *(packet + dataOffset) << 24 | *(packet + dataOffset + 1) << 16 | *(packet + dataOffset + 2) << 8 | *(packet + dataOffset + 3); dataOffset += 6; auxHk.csp2WdtReboots = *(packet + dataOffset) << 24 | *(packet + dataOffset + 1) << 16 | *(packet + dataOffset + 2) << 8 | *(packet + dataOffset + 3); dataOffset += 6; auxHk.groundWatchdogSecondsLeft = *(packet + dataOffset) << 24 | *(packet + dataOffset + 1) << 16 | *(packet + dataOffset + 2) << 8 | *(packet + dataOffset + 3); dataOffset += 6; auxHk.i2cWatchdogSecondsLeft = *(packet + dataOffset) << 24 | *(packet + dataOffset + 1) << 16 | *(packet + dataOffset + 2) << 8 | *(packet + dataOffset + 3); dataOffset += 6; auxHk.canWatchdogSecondsLeft = *(packet + dataOffset) << 24 | *(packet + dataOffset + 1) << 16 | *(packet + dataOffset + 2) << 8 | *(packet + dataOffset + 3); dataOffset += 6; auxHk.csp1WatchdogPingsLeft = *(packet + dataOffset); dataOffset += 3; auxHk.csp2WatchdogPingsLeft = *(packet + dataOffset); coreHk.setChanged(true); if (not coreHk.isValid()) { coreHk.setValidity(true, true); } if (not auxHk.isValid()) { auxHk.setValidity(true, true); } return RETURN_OK; }