#include "PlocSupvHelper.h" #include #include #include "OBSWConfig.h" #ifdef XIPHOS_Q7S #include "bsp_q7s/memory/FilesystemHelper.h" #include "bsp_q7s/memory/SdCardManager.h" #endif #include "fsfw/globalfunctions/CRC.h" #include "fsfw/tasks/TaskFactory.h" #include "fsfw/timemanager/Countdown.h" #include "mission/utility/Filenaming.h" #include "mission/utility/ProgressPrinter.h" #include "mission/utility/Timestamp.h" PlocSupvHelper::PlocSupvHelper(object_id_t objectId) : SystemObject(objectId) {} PlocSupvHelper::~PlocSupvHelper() {} ReturnValue_t PlocSupvHelper::initialize() { #ifdef XIPHOS_Q7S sdcMan = SdCardManager::instance(); if (sdcMan == nullptr) { sif::warning << "PlocSupvHelper::initialize: Invalid SD Card Manager" << std::endl; return RETURN_FAILED; } #endif return RETURN_OK; } ReturnValue_t PlocSupvHelper::performOperation(uint8_t operationCode) { ReturnValue_t result = RETURN_OK; semaphore.acquire(); while (true) { switch (internalState) { case InternalState::IDLE: { semaphore.acquire(); break; } case InternalState::UPDATE: { result = performUpdate(); if (result == RETURN_OK) { triggerEvent(SUPV_UPDATE_SUCCESSFUL, result); } else if (result == PROCESS_TERMINATED) { // Event already triggered } else { triggerEvent(SUPV_UPDATE_FAILED, result); } internalState = InternalState::IDLE; break; } case InternalState::CONTINUE_UPDATE: { result = continueUpdate(); if (result == RETURN_OK) { triggerEvent(SUPV_CONTINUE_UPDATE_SUCCESSFUL, result); } else if (result == PROCESS_TERMINATED) { // Event already triggered } else { triggerEvent(SUPV_CONTINUE_UPDATE_FAILED, result); } internalState = InternalState::IDLE; break; } case InternalState::REQUEST_EVENT_BUFFER: { result = performEventBufferRequest(); if (result == RETURN_OK) { triggerEvent(SUPV_EVENT_BUFFER_REQUEST_SUCCESSFUL, result); } else if (result == PROCESS_TERMINATED) { // Event already triggered break; } else { triggerEvent(SUPV_EVENT_BUFFER_REQUEST_FAILED, result); } internalState = InternalState::IDLE; break; } default: sif::debug << "PlocSupvHelper::performOperation: Invalid state" << std::endl; break; } } } ReturnValue_t PlocSupvHelper::setComIF(UartComIF* uartComIF_) { if (uartComIF_ == nullptr) { sif::warning << "PlocSupvHelper::initialize: Provided invalid uart com if" << std::endl; return RETURN_FAILED; } uartComIF = uartComIF_; return RETURN_OK; } void PlocSupvHelper::setComCookie(CookieIF* comCookie_) { comCookie = comCookie_; } ReturnValue_t PlocSupvHelper::startUpdate(std::string file, uint8_t memoryId, uint32_t startAddress) { ReturnValue_t result = RETURN_OK; #ifdef XIPHOS_Q7S result = FilesystemHelper::checkPath(file); if (result != RETURN_OK) { sif::warning << "PlocSupvHelper::startUpdate: File " << file << " does not exist" << std::endl; return result; } result = FilesystemHelper::fileExists(file); if (result != RETURN_OK) { sif::warning << "PlocSupvHelper::startUpdate: The file " << file << " does not exist" << std::endl; return result; } #endif #ifdef TE0720_1CFA if (not std::filesystem::exists(file)) { sif::warning << "PlocSupvHelper::startUpdate: The file " << file << " does not exist" << std::endl; return RETURN_FAILED; } #endif update.file = file; update.length = getFileSize(update.file); update.memoryId = memoryId; update.startAddress = startAddress; update.remainingSize = update.length; update.bytesWritten = 0; update.packetNum = 1; update.sequenceCount = 1; internalState = InternalState::UPDATE; uartComIF->flushUartTxAndRxBuf(comCookie); semaphore.release(); return result; } void PlocSupvHelper::initiateUpdateContinuation() { internalState = InternalState::CONTINUE_UPDATE; semaphore.release(); } ReturnValue_t PlocSupvHelper::startEventbBufferRequest(std::string path) { #ifdef XIPHOS_Q7S ReturnValue_t result = FilesystemHelper::checkPath(path); if (result != RETURN_OK) { return result; } #endif if (not std::filesystem::exists(path)) { return PATH_NOT_EXISTS; } eventBufferReq.path = path; internalState = InternalState::REQUEST_EVENT_BUFFER; uartComIF->flushUartTxAndRxBuf(comCookie); semaphore.release(); return RETURN_OK; } void PlocSupvHelper::stopProcess() { terminate = true; } ReturnValue_t PlocSupvHelper::performUpdate() { ReturnValue_t result = RETURN_OK; result = calcImageCrc(); if (result != RETURN_OK) { return result; } result = selectMemory(); if (result != RETURN_OK) { return result; } result = prepareUpdate(); if (result != RETURN_OK) { return result; } result = eraseMemory(); if (result != RETURN_OK) { return result; } result = writeUpdatePackets(); if (result != RETURN_OK) { return result; } result = handleCheckMemoryCommand(); if (result != RETURN_OK) { return result; } return result; } ReturnValue_t PlocSupvHelper::continueUpdate() { ReturnValue_t result = prepareUpdate(); if (result != RETURN_OK) { return result; } result = writeUpdatePackets(); if (result != RETURN_OK) { return result; } result = handleCheckMemoryCommand(); if (result != RETURN_OK) { return result; } return result; } ReturnValue_t PlocSupvHelper::writeUpdatePackets() { ReturnValue_t result = RETURN_OK; #if OBSW_DEBUG_PLOC_SUPERVISOR == 1 ProgressPrinter progressPrinter("Supervisor update", update.length, ProgressPrinter::HALF_PERCENT); #endif /* OBSW_DEBUG_PLOC_SUPERVISOR == 1 */ uint8_t tempData[supv::WriteMemory::CHUNK_MAX]; std::ifstream file(update.file, std::ifstream::binary); uint16_t dataLength = 0; supv::SequenceFlags seqFlags; while (update.remainingSize > 0) { if (terminate) { terminate = false; triggerEvent(TERMINATED_UPDATE_PROCEDURE); return PROCESS_TERMINATED; } if (update.remainingSize > supv::WriteMemory::CHUNK_MAX) { dataLength = supv::WriteMemory::CHUNK_MAX; } else { dataLength = static_cast(update.remainingSize); } if (file.is_open()) { file.seekg(update.bytesWritten, file.beg); file.read(reinterpret_cast(tempData), dataLength); if (!file) { sif::warning << "PlocSupvHelper::performUpdate: Read only " << file.gcount() << " of " << dataLength << " bytes" << std::endl; sif::info << "PlocSupvHelper::performUpdate: Failed when trying to read byte " << update.bytesWritten << std::endl; } } else { return FILE_CLOSED_ACCIDENTALLY; } if (update.bytesWritten == 0) { seqFlags = supv::SequenceFlags::FIRST_PKT; } else if (update.remainingSize == 0) { seqFlags = supv::SequenceFlags::LAST_PKT; } else { seqFlags = supv::SequenceFlags::CONTINUED_PKT; } supv::WriteMemory packet(seqFlags, update.sequenceCount++, update.memoryId, update.startAddress + update.bytesWritten, dataLength, tempData); result = handlePacketTransmission(packet); if (result != RETURN_OK) { update.sequenceCount--; triggerEvent(WRITE_MEMORY_FAILED, update.packetNum); return result; } update.remainingSize -= dataLength; update.packetNum += 1; update.bytesWritten += dataLength; #if OBSW_DEBUG_PLOC_SUPERVISOR == 1 progressPrinter.print(update.bytesWritten); #endif /* OBSW_DEBUG_PLOC_SUPERVISOR == 1 */ } return result; } ReturnValue_t PlocSupvHelper::performEventBufferRequest() { using namespace supv; ReturnValue_t result = RETURN_OK; RequestLoggingData packet(RequestLoggingData::Sa::REQUEST_EVENT_BUFFERS); result = sendCommand(packet); if (result != RETURN_OK) { return result; } result = handleAck(); if (result != RETURN_OK) { return result; } result = handleEventBufferReception(); if (result != RETURN_OK) { return result; } result = handleExe(); if (result != RETURN_OK) { return result; } return result; } ReturnValue_t PlocSupvHelper::selectMemory() { ReturnValue_t result = RETURN_OK; supv::MPSoCBootSelect packet(update.memoryId); result = handlePacketTransmission(packet); if (result != RETURN_OK) { return result; } return RETURN_OK; } ReturnValue_t PlocSupvHelper::prepareUpdate() { ReturnValue_t result = RETURN_OK; supv::ApidOnlyPacket packet(supv::APID_PREPARE_UPDATE); result = handlePacketTransmission(packet, PREPARE_UPDATE_EXECUTION_REPORT); if (result != RETURN_OK) { return result; } return RETURN_OK; } ReturnValue_t PlocSupvHelper::eraseMemory() { ReturnValue_t result = RETURN_OK; supv::EraseMemory eraseMemory(update.memoryId, update.startAddress, update.length); result = handlePacketTransmission(eraseMemory, supv::recv_timeout::ERASE_MEMORY); if (result != RETURN_OK) { return result; } return RETURN_OK; } ReturnValue_t PlocSupvHelper::handlePacketTransmission(SpacePacket& packet, uint32_t timeoutExecutionReport) { ReturnValue_t result = RETURN_OK; result = sendCommand(packet); if (result != RETURN_OK) { return result; } result = handleAck(); if (result != RETURN_OK) { return result; } result = handleExe(timeoutExecutionReport); if (result != RETURN_OK) { return result; } return RETURN_OK; } ReturnValue_t PlocSupvHelper::sendCommand(SpacePacket& packet) { ReturnValue_t result = RETURN_OK; rememberApid = packet.getAPID(); result = uartComIF->sendMessage(comCookie, packet.getWholeData(), packet.getFullSize()); if (result != RETURN_OK) { sif::warning << "PlocSupvHelper::sendCommand: Failed to send command" << std::endl; triggerEvent(SUPV_SENDING_COMMAND_FAILED, result, static_cast(internalState)); return result; } return result; } ReturnValue_t PlocSupvHelper::handleAck() { ReturnValue_t result = RETURN_OK; supv::AcknowledgmentReport ackReport; result = handleTmReception(&ackReport, supv::SIZE_ACK_REPORT); if (result != RETURN_OK) { triggerEvent(ACK_RECEPTION_FAILURE, result, static_cast(rememberApid)); sif::warning << "PlocSupvHelper::handleAck: Error in reception of acknowledgment report" << std::endl; return result; } result = ackReport.checkApid(); if (result != RETURN_OK) { if (result == SupvReturnValuesIF::RECEIVED_ACK_FAILURE) { triggerEvent(SUPV_ACK_FAILURE_REPORT, static_cast(ackReport.getRefApid())); } else if (result == SupvReturnValuesIF::INVALID_APID) { triggerEvent(SUPV_ACK_INVALID_APID, static_cast(rememberApid)); } return result; } return RETURN_OK; } ReturnValue_t PlocSupvHelper::handleExe(uint32_t timeout) { ReturnValue_t result = RETURN_OK; supv::ExecutionReport exeReport; result = handleTmReception(&exeReport, supv::SIZE_EXE_REPORT, timeout); if (result != RETURN_OK) { triggerEvent(EXE_RECEPTION_FAILURE, result, static_cast(rememberApid)); sif::warning << "PlocSupvHelper::handleExe: Error in reception of execution report" << std::endl; return result; } result = exeReport.checkApid(); if (result != RETURN_OK) { if (result == SupvReturnValuesIF::RECEIVED_EXE_FAILURE) { triggerEvent(SUPV_EXE_FAILURE_REPORT, static_cast(exeReport.getRefApid())); } else if (result == SupvReturnValuesIF::INVALID_APID) { triggerEvent(SUPV_EXE_INVALID_APID, static_cast(rememberApid)); } return result; } return RETURN_OK; } ReturnValue_t PlocSupvHelper::handleTmReception(supv::TmPacket* tmPacket, size_t remainingBytes, uint32_t timeout) { ReturnValue_t result = RETURN_OK; size_t readBytes = 0; size_t currentBytes = 0; Countdown countdown(timeout); while (!countdown.hasTimedOut()) { result = receive(tmPacket->getWholeData() + readBytes, ¤tBytes, remainingBytes); if (result != RETURN_OK) { return result; } readBytes += currentBytes; remainingBytes = remainingBytes - currentBytes; if (remainingBytes == 0) { break; } } if (remainingBytes != 0) { sif::warning << "PlocSupvHelper::handleTmReception: Failed to read " << std::dec << remainingBytes << " bytes" << std::endl; return RETURN_FAILED; } result = tmPacket->checkCrc(); if (result != RETURN_OK) { sif::warning << "PlocSupvHelper::handleTmReception: CRC check failed" << std::endl; return result; } return result; } ReturnValue_t PlocSupvHelper::receive(uint8_t* data, size_t* readBytes, size_t requestBytes) { ReturnValue_t result = RETURN_OK; uint8_t* buffer = nullptr; result = uartComIF->requestReceiveMessage(comCookie, requestBytes); if (result != RETURN_OK) { sif::warning << "PlocSupvHelper::receive: Failed to request reply" << std::endl; triggerEvent(SUPV_HELPER_REQUESTING_REPLY_FAILED, result, static_cast(static_cast(internalState))); return RETURN_FAILED; } result = uartComIF->readReceivedMessage(comCookie, &buffer, readBytes); if (result != RETURN_OK) { sif::warning << "PlocSupvHelper::receive: Failed to read received message" << std::endl; triggerEvent(SUPV_HELPER_READING_REPLY_FAILED, result, static_cast(internalState)); return RETURN_FAILED; } if (*readBytes > 0) { std::memcpy(data, buffer, *readBytes); } else { TaskFactory::delayTask(40); } return result; } ReturnValue_t PlocSupvHelper::calcImageCrc() { ReturnValue_t result = RETURN_OK; #ifdef XIPHOS_Q7S result = FilesystemHelper::checkPath(update.file); #endif if (result != RETURN_OK) { sif::warning << "PlocSupvHelper::calcImageCrc: File " << update.file << " does not exist" << std::endl; return result; } std::ifstream file(update.file, std::ifstream::binary); uint16_t remainder = CRC16_INIT; uint8_t input; #if OBSW_DEBUG_PLOC_SUPERVISOR == 1 ProgressPrinter progress("Supervisor update crc calculation", update.length, ProgressPrinter::ONE_PERCENT); #endif /* OBSW_DEBUG_PLOC_SUPERVISOR == 1 */ uint32_t byteCount = 0; for (byteCount = 0; byteCount < update.length; byteCount++) { file.seekg(byteCount, file.beg); file.read(reinterpret_cast(&input), 1); remainder = CRC::crc16ccitt(&input, sizeof(input), remainder); #if OBSW_DEBUG_PLOC_SUPERVISOR == 1 progress.print(byteCount); #endif /* OBSW_DEBUG_PLOC_SUPERVISOR == 1 */ } #if OBSW_DEBUG_PLOC_SUPERVISOR == 1 progress.print(byteCount); #endif /* OBSW_DEBUG_PLOC_SUPERVISOR == 1 */ file.close(); update.crc = remainder; return result; } ReturnValue_t PlocSupvHelper::handleCheckMemoryCommand() { ReturnValue_t result = RETURN_OK; // Verification of update write procedure supv::CheckMemory packet(update.memoryId, update.startAddress, update.length); result = sendCommand(packet); if (result != RETURN_OK) { return result; } result = handleAck(); if (result != RETURN_OK) { return result; } supv::UpdateStatusReport updateStatusReport; result = handleTmReception(&updateStatusReport, static_cast(updateStatusReport.getNominalSize()), supv::recv_timeout::UPDATE_STATUS_REPORT); if (result != RETURN_OK) { sif::warning << "PlocSupvHelper::handleCheckMemoryCommand: Failed to receive update status report" << std::endl; return result; } result = handleExe(CRC_EXECUTION_TIMEOUT); if (result != RETURN_OK) { return result; } result = updateStatusReport.parseDataField(); if (result != RETURN_OK) { return result; } result = updateStatusReport.verifycrc(update.crc); if (result != RETURN_OK) { sif::warning << "PlocSupvHelper::handleCheckMemoryCommand: CRC failure. Expected CRC 0x" << std::hex << update.crc << " but received CRC 0x" << updateStatusReport.getCrc() << std::endl; return result; } return result; } uint32_t PlocSupvHelper::getFileSize(std::string filename) { std::ifstream file(filename, std::ifstream::binary); file.seekg(0, file.end); uint32_t size = file.tellg(); file.close(); return size; } ReturnValue_t PlocSupvHelper::handleEventBufferReception() { ReturnValue_t result = RETURN_OK; std::string filename = Filenaming::generateAbsoluteFilename( eventBufferReq.path, eventBufferReq.filename, timestamping); std::ofstream file(filename, std::ios_base::app | std::ios_base::out); uint32_t packetsRead = 0; size_t requestLen = 0; supv::TmPacket tmPacket; for (packetsRead = 0; packetsRead < NUM_EVENT_BUFFER_PACKETS; packetsRead++) { if (terminate) { triggerEvent(SUPV_EVENT_BUFFER_REQUEST_TERMINATED, packetsRead - 1); file.close(); return PROCESS_TERMINATED; } if (packetsRead == NUM_EVENT_BUFFER_PACKETS - 1) { requestLen = SIZE_EVENT_BUFFER_LAST_PACKET; } else { requestLen = SIZE_EVENT_BUFFER_FULL_PACKET; } result = handleTmReception(&tmPacket, requestLen); if (result != RETURN_OK) { sif::debug << "PlocSupvHelper::handleEventBufferReception: Failed while trying to read packet" << " " << packetsRead + 1 << std::endl; file.close(); return result; } uint16_t apid = tmPacket.getAPID(); if (apid != supv::APID_MRAM_DUMP_TM) { sif::warning << "PlocSupvHelper::handleEventBufferReception: Did not expect space packet " << "with APID 0x" << std::hex << apid << std::endl; file.close(); return EVENT_BUFFER_REPLY_INVALID_APID; } file.write(reinterpret_cast(tmPacket.getPacketData()), tmPacket.getPayloadDataLength()); } return result; }