#include "fsfw/ipc/QueueFactory.h" #include "PlocUpdater.h" #include #include #include PlocUpdater::PlocUpdater(object_id_t objectId) : SystemObject(objectId), commandActionHelper(this), actionHelper(this, nullptr) { commandQueue = QueueFactory::instance()->createMessageQueue(QUEUE_SIZE); } PlocUpdater::~PlocUpdater() { } ReturnValue_t PlocUpdater::initialize() { sdcMan = SdCardManager::instance(); ReturnValue_t result = SystemObject::initialize(); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } result = commandActionHelper.initialize(); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } result = actionHelper.initialize(commandQueue); if (result != HasReturnvaluesIF::RETURN_OK) { return result; } return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t PlocUpdater::performOperation(uint8_t operationCode) { readCommandQueue(); doStateMachine(); return HasReturnvaluesIF::RETURN_OK; } ReturnValue_t PlocUpdater::executeAction(ActionId_t actionId, MessageQueueId_t commandedBy, const uint8_t* data, size_t size) { ReturnValue_t result = RETURN_FAILED; if (state != State::IDLE) { return IS_BUSY; } if (size > MAX_PLOC_UPDATE_PATH) { return NAME_TOO_LONG; } switch (actionId) { case UPDATE_NVM0_A: updatePartition = Partition::A; updateMemory = Memory::NVM0; break; case UPDATE_NVM0_B: updatePartition = Partition::B; updateMemory = Memory::NVM0; break; case UPDATE_NVM1_A: updatePartition = Partition::A; updateMemory = Memory::NVM1; break; case UPDATE_NVM1_B: updatePartition = Partition::B; updateMemory = Memory::NVM1; break; default: return INVALID_ACTION_ID; } result = getImageLocation(data, size); if (result != RETURN_OK) { return result; } state = State::UPDATE_AVAILABLE; return EXECUTION_FINISHED; } MessageQueueId_t PlocUpdater::getCommandQueue() const { return commandQueue->getId(); } MessageQueueIF* PlocUpdater::getCommandQueuePtr() { return commandQueue; } void PlocUpdater::readCommandQueue() { CommandMessage message; ReturnValue_t result; for (result = commandQueue->receiveMessage(&message); result == HasReturnvaluesIF::RETURN_OK; result = commandQueue->receiveMessage(&message)) { if (result != RETURN_OK) { continue; } result = actionHelper.handleActionMessage(&message); if (result == HasReturnvaluesIF::RETURN_OK) { continue; } result = commandActionHelper.handleReply(&message); if (result == HasReturnvaluesIF::RETURN_OK) { continue; } sif::debug << "PlocUpdater::readCommandQueue: Received message with invalid format" << std::endl; } } void PlocUpdater::doStateMachine() { switch (state) { case State::IDLE: break; case State::UPDATE_AVAILABLE: commandUpdateAvailable(); break; case State::UPDATE_TRANSFER: commandUpdatePacket(); break; case State::UPDATE_VERIFY: commandUpdateVerify(); break; case State::COMMAND_EXECUTING: break; default: sif::debug << "PlocUpdater::doStateMachine: Invalid state" << std::endl; break; } } ReturnValue_t PlocUpdater::checkNameLength(size_t size) { if (size > MAX_PLOC_UPDATE_PATH) { return NAME_TOO_LONG; } return RETURN_OK; } ReturnValue_t PlocUpdater::getImageLocation(const uint8_t* data, size_t size) { ReturnValue_t result = checkNameLength(size); if (result != RETURN_OK) { return result; } // Check if file is stored on SD card and if associated SD card is mounted if (std::string(reinterpret_cast(data), SD_PREFIX_LENGTH) == std::string(SdCardManager::SD_0_MOUNT_POINT)) { if (!isSdCardMounted(sd::SLOT_0)) { sif::warning << "PlocUpdater::prepareNvm0AUpdate: SD card 0 not mounted" << std::endl; return SD_NOT_MOUNTED; } } else if (std::string(reinterpret_cast(data), SD_PREFIX_LENGTH) == std::string(SdCardManager::SD_1_MOUNT_POINT)) { if (!isSdCardMounted(sd::SLOT_0)) { sif::warning << "PlocUpdater::prepareNvm0AUpdate: SD card 1 not mounted" << std::endl; return SD_NOT_MOUNTED; } } else { //update image not stored on SD card } updateFile = std::string(reinterpret_cast(data), size); // Check if file exists if(not std::filesystem::exists(updateFile)) { return FILE_NOT_EXISTS; } return RETURN_OK; } bool PlocUpdater::isSdCardMounted(sd::SdCard sdCard) { SdCardManager::SdStatePair active; ReturnValue_t result = sdcMan->getSdCardActiveStatus(active); if (result != RETURN_OK) { sif::debug << "PlocUpdater::isSdCardMounted: Failed to get SD card active state"; return false; } if (sdCard == sd::SLOT_0) { if (active.first == sd::MOUNTED) { return true; } else { return false; } } else if (sdCard == sd::SLOT_1) { if (active.second == sd::MOUNTED) { return true; } else { return false; } } else { sif::debug << "PlocUpdater::isSdCardMounted: Unknown SD card specified" << std::endl; } return false; } void PlocUpdater::stepSuccessfulReceived(ActionId_t actionId, uint8_t step) { } void PlocUpdater::stepFailedReceived(ActionId_t actionId, uint8_t step, ReturnValue_t returnCode) { } void PlocUpdater::dataReceived(ActionId_t actionId, const uint8_t* data, uint32_t size) { } void PlocUpdater::completionSuccessfulReceived(ActionId_t actionId) { switch (pendingCommand) { case (PLOC_SPV::UPDATE_AVAILABLE): state = State::UPDATE_TRANSFER; break; case (PLOC_SPV::UPDATE_IMAGE_DATA): if (remainingPackets == 0) { packetsSent = 0; // Reset packets sent variable for next update sequence state = State::UPDATE_VERIFY; } else { state = State::UPDATE_TRANSFER; } break; case (PLOC_SPV::UPDATE_VERIFY): triggerEvent(UPDATE_FINISHED); state = State::IDLE; pendingCommand = PLOC_SPV::NONE; break; default: sif::debug << "PlocUpdater::completionSuccessfulReceived: Invalid pending command" << std::endl; state = State::IDLE; break; } } void PlocUpdater::completionFailedReceived(ActionId_t actionId, ReturnValue_t returnCode) { switch(pendingCommand) { case(PLOC_SPV::UPDATE_AVAILABLE): { triggerEvent(UPDATE_AVAILABLE_FAILED); break; } case(PLOC_SPV::UPDATE_IMAGE_DATA): { triggerEvent(UPDATE_TRANSFER_FAILED, packetsSent); break; } case(PLOC_SPV::UPDATE_VERIFY): { triggerEvent(UPDATE_VERIFY_FAILED); break; } default: sif::debug << "PlocUpdater::completionFailedReceived: Invalid pending command " << std::endl; break; } state = State::IDLE; } void PlocUpdater::commandUpdateAvailable() { ReturnValue_t result = RETURN_OK; if (not std::filesystem::exists(updateFile)) { triggerEvent(UPDATE_FILE_NOT_EXISTS, static_cast(state)); state = State::IDLE; return; } std::ifstream file(updateFile, std::ifstream::binary); file.seekg(0, file.end); imageSize = static_cast(file.tellg()); file.close(); numOfUpdatePackets = imageSize / MAX_SP_DATA ; if (imageSize % MAX_SP_DATA) { numOfUpdatePackets++; } remainingPackets = numOfUpdatePackets; packetsSent = 0; uint32_t imageCrc = makeCrc(); PLOC_SPV::UpdateInfo packet(PLOC_SPV::APID_UPDATE_AVAILABLE, static_cast(updateMemory), static_cast(updatePartition), imageSize, imageCrc, numOfUpdatePackets); result = commandActionHelper.commandAction(objects::PLOC_SUPERVISOR_HANDLER, PLOC_SPV::UPDATE_AVAILABLE, packet.getWholeData(), packet.getFullSize()); if (result != RETURN_OK) { sif::warning << "PlocUpdater::commandUpdateAvailable: Failed to send update available" << " packet to supervisor handler" << std::endl; triggerEvent(ACTION_COMMANDING_FAILED, result, PLOC_SPV::UPDATE_AVAILABLE); state = State::IDLE; pendingCommand = PLOC_SPV::NONE; return; } pendingCommand = PLOC_SPV::UPDATE_AVAILABLE; state = State::COMMAND_EXECUTING; return; } void PlocUpdater::commandUpdatePacket() { ReturnValue_t result = RETURN_OK; uint16_t payloadLength = 0; if (not std::filesystem::exists(updateFile)) { triggerEvent(UPDATE_FILE_NOT_EXISTS, static_cast(state), packetsSent); state = State::IDLE; return; } std::ifstream file(updateFile, std::ifstream::binary); file.seekg(packetsSent * MAX_SP_DATA, file.beg); if (remainingPackets == 1) { payloadLength = imageSize - static_cast(file.tellg()); } else { payloadLength = MAX_SP_DATA; } PLOC_SPV::UpdatePacket packet(payloadLength); file.read(reinterpret_cast(packet.getDataFieldPointer()), payloadLength); file.close(); // sequence count of first packet is 1 packet.setPacketSequenceCount((packetsSent + 1) & PLOC_SPV::SEQUENCE_COUNT_MASK); if (numOfUpdatePackets > 0) { adjustSequenceFlags(packet); } packet.makeCrc(); result = commandActionHelper.commandAction(objects::PLOC_SUPERVISOR_HANDLER, PLOC_SPV::UPDATE_IMAGE_DATA, packet.getWholeData(), packet.getFullSize()); if (result != RETURN_OK) { sif::warning << "PlocUpdater::commandUpdateAvailable: Failed to send update" << " packet to supervisor handler" << std::endl; triggerEvent(ACTION_COMMANDING_FAILED, result, PLOC_SPV::UPDATE_IMAGE_DATA); state = State::IDLE; pendingCommand = PLOC_SPV::NONE; return; } remainingPackets--; packetsSent++; pendingCommand = PLOC_SPV::UPDATE_IMAGE_DATA; state = State::COMMAND_EXECUTING; } void PlocUpdater::commandUpdateVerify() { ReturnValue_t result = RETURN_OK; PLOC_SPV::UpdateInfo packet(PLOC_SPV::APID_UPDATE_VERIFY, static_cast(updateMemory), static_cast(updatePartition), imageSize, imageCrc, numOfUpdatePackets); result = commandActionHelper.commandAction(objects::PLOC_SUPERVISOR_HANDLER, PLOC_SPV::UPDATE_VERIFY, packet.getWholeData(), packet.getFullSize()); if (result != RETURN_OK) { sif::warning << "PlocUpdater::commandUpdateAvailable: Failed to send update available" << " packet to supervisor handler" << std::endl; triggerEvent(ACTION_COMMANDING_FAILED, result, PLOC_SPV::UPDATE_VERIFY); state = State::IDLE; pendingCommand = PLOC_SPV::NONE; return; } state = State::COMMAND_EXECUTING; pendingCommand = PLOC_SPV::UPDATE_VERIFY; return; } ReturnValue_t PlocUpdater::makeCrc() { //TODO: Waiting on input from TAS about the CRC to use return 0; } void PlocUpdater::adjustSequenceFlags(PLOC_SPV::UpdatePacket& packet) { if (packetsSent == 0) { packet.setSequenceFlags(static_cast(PLOC_SPV::SequenceFlags::FIRST_PKT)); } else if (remainingPackets == 1) { packet.setSequenceFlags(static_cast(PLOC_SPV::SequenceFlags::LAST_PKT)); } else { packet.setSequenceFlags(static_cast(PLOC_SPV::SequenceFlags::CONTINUED_PKT)); } }