#include #include #include #include #include #include #ifdef XIPHOS_Q7S #include "bsp_q7s/fs/FilesystemHelper.h" #endif #include "mission/utility/Timestamp.h" using namespace ploc; PlocMpsocSpecialComHelper::PlocMpsocSpecialComHelper(object_id_t objectId) : SystemObject(objectId) { spParams.buf = commandBuffer; spParams.maxSize = sizeof(commandBuffer); } PlocMpsocSpecialComHelper::~PlocMpsocSpecialComHelper() {} ReturnValue_t PlocMpsocSpecialComHelper::initialize() { #ifdef XIPHOS_Q7S sdcMan = SdCardManager::instance(); if (sdcMan == nullptr) { sif::warning << "PlocMPSoCHelper::initialize: Invalid SD Card Manager" << std::endl; return returnvalue::FAILED; } #endif return returnvalue::OK; } ReturnValue_t PlocMpsocSpecialComHelper::performOperation(uint8_t operationCode) { ReturnValue_t result = returnvalue::OK; semaphore.acquire(); while (true) { #if OBSW_THREAD_TRACING == 1 trace::threadTrace(opCounter, "PLOC MPSOC Helper"); #endif switch (internalState) { case InternalState::IDLE: { semaphore.acquire(); break; } case InternalState::FLASH_WRITE: { result = performFlashWrite(); if (result == returnvalue::OK) { triggerEvent(MPSOC_FLASH_WRITE_SUCCESSFUL, sequenceCount->get()); } else { triggerEvent(MPSOC_FLASH_WRITE_FAILED, sequenceCount->get()); } internalState = InternalState::IDLE; break; } case InternalState::FLASH_READ: { result = performFlashRead(); if (result == returnvalue::OK) { triggerEvent(MPSOC_FLASH_READ_SUCCESSFUL, sequenceCount->get()); } else { triggerEvent(MPSOC_FLASH_READ_FAILED, sequenceCount->get()); } internalState = InternalState::IDLE; break; } default: sif::debug << "PlocMPSoCHelper::performOperation: Invalid state" << std::endl; break; } } } ReturnValue_t PlocMpsocSpecialComHelper::setComIF(DeviceCommunicationIF* communicationInterface_) { uartComIF = dynamic_cast(communicationInterface_); if (uartComIF == nullptr) { sif::warning << "PlocMPSoCHelper::initialize: Invalid uart com if" << std::endl; return returnvalue::FAILED; } return returnvalue::OK; } void PlocMpsocSpecialComHelper::setComCookie(CookieIF* comCookie_) { comCookie = comCookie_; } void PlocMpsocSpecialComHelper::setSequenceCount(SourceSequenceCounter* sequenceCount_) { sequenceCount = sequenceCount_; } ReturnValue_t PlocMpsocSpecialComHelper::startFlashWrite(std::string obcFile, std::string mpsocFile) { if (internalState != InternalState::IDLE) { return returnvalue::FAILED; } ReturnValue_t result = startFlashReadOrWriteBase(std::move(obcFile), std::move(mpsocFile)); if (result != returnvalue::OK) { return result; } internalState = InternalState::FLASH_WRITE; return semaphore.release(); } ReturnValue_t PlocMpsocSpecialComHelper::startFlashRead(std::string obcFile, std::string mpsocFile, size_t readFileSize) { if (internalState != InternalState::IDLE) { return returnvalue::FAILED; } ReturnValue_t result = startFlashReadOrWriteBase(std::move(obcFile), std::move(mpsocFile)); if (result != returnvalue::OK) { return result; } flashReadAndWrite.totalReadSize = readFileSize; internalState = InternalState::FLASH_READ; return semaphore.release(); } void PlocMpsocSpecialComHelper::resetHelper() { spParams.buf = commandBuffer; terminate = false; uartComIF->flushUartRxBuffer(comCookie); } void PlocMpsocSpecialComHelper::stopProcess() { terminate = true; } ReturnValue_t PlocMpsocSpecialComHelper::performFlashWrite() { ReturnValue_t result = returnvalue::OK; std::ifstream file(flashReadAndWrite.obcFile, std::ifstream::binary); if (file.bad()) { return returnvalue::FAILED; } result = flashfopen(mpsoc::FileAccessModes::WRITE | mpsoc::FileAccessModes::OPEN_ALWAYS); if (result != returnvalue::OK) { return result; } // Set position of next character to end of file input stream file.seekg(0, file.end); // tellg returns position of character in input stream size_t remainingSize = file.tellg(); size_t dataLength = 0; size_t bytesRead = 0; while (remainingSize > 0) { if (terminate) { return returnvalue::OK; } // The minus 4 is necessary for unknown reasons. Maybe some bug in the ILH software? if (remainingSize > mpsoc::MAX_FLASH_WRITE_DATA_SIZE - 4) { dataLength = mpsoc::MAX_FLASH_WRITE_DATA_SIZE - 4; } else { dataLength = remainingSize; } if (file.bad() or not file.is_open()) { return FILE_WRITE_ERROR; } file.seekg(bytesRead, file.beg); file.read(reinterpret_cast(fileBuf.data()), dataLength); bytesRead += dataLength; remainingSize -= dataLength; mpsoc::TcFlashWrite tc(spParams, *sequenceCount); result = tc.setPayload(fileBuf.data(), dataLength); if (result != returnvalue::OK) { return result; } result = tc.finishPacket(); if (result != returnvalue::OK) { return result; } (*sequenceCount)++; result = handlePacketTransmissionNoReply(tc); if (result != returnvalue::OK) { return result; } } result = flashfclose(); if (result != returnvalue::OK) { return result; } return result; } ReturnValue_t PlocMpsocSpecialComHelper::performFlashRead() { std::error_code e; std::ofstream ofile(flashReadAndWrite.obcFile, std::ios::trunc | std::ios::binary); if (ofile.bad()) { return returnvalue::FAILED; } ReturnValue_t result = flashfopen(mpsoc::FileAccessModes::READ); if (result != returnvalue::OK) { std::filesystem::remove(flashReadAndWrite.obcFile, e); return result; } size_t readSoFar = 0; size_t nextReadSize = mpsoc::MAX_FLASH_READ_DATA_SIZE; while (readSoFar < flashReadAndWrite.totalReadSize) { if (terminate) { std::filesystem::remove(flashReadAndWrite.obcFile, e); return returnvalue::OK; } nextReadSize = mpsoc::MAX_FLASH_READ_DATA_SIZE; if (flashReadAndWrite.totalReadSize - readSoFar < mpsoc::MAX_FLASH_READ_DATA_SIZE) { nextReadSize = flashReadAndWrite.totalReadSize - readSoFar; } if (ofile.bad() or not ofile.is_open()) { std::filesystem::remove(flashReadAndWrite.obcFile, e); return FILE_READ_ERROR; } mpsoc::TcFlashRead flashReadRequest(spParams, *sequenceCount); result = flashReadRequest.setPayload(nextReadSize); if (result != returnvalue::OK) { std::filesystem::remove(flashReadAndWrite.obcFile, e); return result; } result = flashReadRequest.finishPacket(); if (result != returnvalue::OK) { std::filesystem::remove(flashReadAndWrite.obcFile, e); return result; } (*sequenceCount)++; result = handlePacketTransmissionFlashRead(flashReadRequest, ofile, nextReadSize); if (result != returnvalue::OK) { std::filesystem::remove(flashReadAndWrite.obcFile, e); return result; } readSoFar += nextReadSize; } result = flashfclose(); if (result != returnvalue::OK) { return result; } return result; } ReturnValue_t PlocMpsocSpecialComHelper::flashfopen(uint8_t mode) { spParams.buf = commandBuffer; mpsoc::FlashFopen flashFopen(spParams, *sequenceCount); ReturnValue_t result = flashFopen.setPayload(flashReadAndWrite.mpsocFile, mode); if (result != returnvalue::OK) { return result; } result = flashFopen.finishPacket(); if (result != returnvalue::OK) { return result; } (*sequenceCount)++; result = handlePacketTransmissionNoReply(flashFopen); if (result != returnvalue::OK) { return result; } return returnvalue::OK; } ReturnValue_t PlocMpsocSpecialComHelper::flashfclose() { spParams.buf = commandBuffer; mpsoc::FlashFclose flashFclose(spParams, *sequenceCount); ReturnValue_t result = flashFclose.finishPacket(); if (result != returnvalue::OK) { return result; } (*sequenceCount)++; result = handlePacketTransmissionNoReply(flashFclose); if (result != returnvalue::OK) { return result; } return result; } ReturnValue_t PlocMpsocSpecialComHelper::handlePacketTransmissionFlashRead(mpsoc::TcFlashRead& tc, std::ofstream& ofile, size_t expectedReadLen) { ReturnValue_t result = sendCommand(tc); if (result != returnvalue::OK) { return result; } result = handleAck(); if (result != returnvalue::OK) { return result; } result = handleTmReception(); if (result != returnvalue::OK) { return result; } // We have the nominal case where the flash read report appears first, or the case where we // get an EXE failure immediately. if (spReader.getApid() == mpsoc::apid::TM_FLASH_READ_REPORT) { result = handleFlashReadReply(ofile, expectedReadLen); if (result != returnvalue::OK) { return result; } return handleExe(); } else if (spReader.getApid() == mpsoc::apid::EXE_FAILURE) { handleExeFailure(); } else { triggerEvent(MPSOC_EXE_INVALID_APID, spReader.getApid(), static_cast(internalState)); sif::warning << "PLOC MPSoC: Expected execution report " << "but received space packet with apid " << std::hex << spReader.getApid() << std::endl; } return returnvalue::FAILED; } ReturnValue_t PlocMpsocSpecialComHelper::handlePacketTransmissionNoReply(ploc::SpTcBase& tc) { ReturnValue_t result = sendCommand(tc); if (result != returnvalue::OK) { return result; } result = handleAck(); if (result != returnvalue::OK) { return result; } return handleExe(); } ReturnValue_t PlocMpsocSpecialComHelper::sendCommand(ploc::SpTcBase& tc) { ReturnValue_t result = returnvalue::OK; result = uartComIF->sendMessage(comCookie, tc.getFullPacket(), tc.getFullPacketLen()); if (result != returnvalue::OK) { sif::warning << "PlocMPSoCHelper::sendCommand: Failed to send command" << std::endl; triggerEvent(MPSOC_SENDING_COMMAND_FAILED, result, static_cast(internalState)); return result; } return result; } ReturnValue_t PlocMpsocSpecialComHelper::handleAck() { ReturnValue_t result = returnvalue::OK; result = handleTmReception(); if (result != returnvalue::OK) { return result; } result = checkReceivedTm(); if (result != returnvalue::OK) { return result; } uint16_t apid = spReader.getApid(); if (apid != mpsoc::apid::ACK_SUCCESS) { handleAckApidFailure(spReader); return returnvalue::FAILED; } return returnvalue::OK; } void PlocMpsocSpecialComHelper::handleAckApidFailure(const ploc::SpTmReader& reader) { uint16_t apid = reader.getApid(); if (apid == mpsoc::apid::ACK_FAILURE) { uint16_t status = mpsoc::getStatusFromRawData(reader.getFullData()); sif::warning << "PLOC MPSoC ACK Failure: " << mpsoc::getStatusString(status) << std::endl; triggerEvent(MPSOC_ACK_FAILURE_REPORT, static_cast(internalState), status); } else { triggerEvent(MPSOC_ACK_INVALID_APID, apid, static_cast(internalState)); sif::warning << "PlocMPSoCHelper::handleAckApidFailure: Expected acknowledgement report " << "but received space packet with apid " << std::hex << apid << std::endl; } } ReturnValue_t PlocMpsocSpecialComHelper::handleExe() { ReturnValue_t result = returnvalue::OK; result = handleTmReception(); if (result != returnvalue::OK) { return result; } result = checkReceivedTm(); if (result != returnvalue::OK) { return result; } uint16_t apid = spReader.getApid(); if (apid == mpsoc::apid::EXE_FAILURE) { handleExeFailure(); return returnvalue::FAILED; } else if (apid != mpsoc::apid::EXE_SUCCESS) { triggerEvent(MPSOC_EXE_INVALID_APID, apid, static_cast(internalState)); sif::warning << "PLOC MPSoC: Expected execution report " << "but received space packet with apid " << std::hex << apid << std::endl; } return returnvalue::OK; } void PlocMpsocSpecialComHelper::handleExeFailure() { uint16_t status = mpsoc::getStatusFromRawData(spReader.getFullData()); sif::warning << "PLOC MPSoC EXE Failure: " << mpsoc::getStatusString(status) << std::endl; triggerEvent(MPSOC_EXE_FAILURE_REPORT, static_cast(internalState)); } ReturnValue_t PlocMpsocSpecialComHelper::handleTmReception() { ReturnValue_t result = returnvalue::OK; tmCountdown.resetTimer(); size_t readBytes = 0; size_t currentBytes = 0; uint32_t usleepDelay = 5; size_t fullPacketLen = 0; while (true) { if (tmCountdown.hasTimedOut()) { triggerEvent(MPSOC_READ_TIMEOUT, tmCountdown.getTimeoutMs()); return returnvalue::FAILED; } result = receive(tmBuf.data() + readBytes, 6, ¤tBytes); if (result != returnvalue::OK) { return result; } spReader.setReadOnlyData(tmBuf.data(), tmBuf.size()); fullPacketLen = spReader.getFullPacketLen(); readBytes += currentBytes; if (readBytes == 6) { break; } usleep(usleepDelay); if (usleepDelay < 200000) { usleepDelay *= 4; } } while (true) { if (tmCountdown.hasTimedOut()) { triggerEvent(MPSOC_READ_TIMEOUT, tmCountdown.getTimeoutMs()); return returnvalue::FAILED; } result = receive(tmBuf.data() + readBytes, fullPacketLen - readBytes, ¤tBytes); readBytes += currentBytes; if (fullPacketLen == readBytes) { break; } usleep(usleepDelay); if (usleepDelay < 200000) { usleepDelay *= 4; } } // arrayprinter::print(tmBuf.data(), readBytes); return result; } ReturnValue_t PlocMpsocSpecialComHelper::handleFlashReadReply(std::ofstream& ofile, size_t expectedReadLen) { ReturnValue_t result = checkReceivedTm(); if (result != returnvalue::OK) { return result; } uint16_t apid = spReader.getApid(); if (apid != mpsoc::apid::TM_FLASH_READ_REPORT) { triggerEvent(MPSOC_FLASH_READ_PACKET_ERROR, FlashReadErrorType::FLASH_READ_APID_ERROR); sif::warning << "PLOC MPSoC Flash Read: Unexpected APID" << std::endl; return result; } const uint8_t* packetData = spReader.getPacketData(); size_t deserDummy = spReader.getPacketDataLen() - mpsoc::CRC_SIZE; uint32_t receivedReadLen = 0; // I think this is buggy, weird stuff in the short name field. // std::string receivedShortName = std::string(reinterpret_cast(packetData), 12); // if (receivedShortName != flashReadAndWrite.mpsocFile.substr(0, 11)) { // sif::warning << "PLOC MPSoC Flash Read: Missmatch between request file name and " // "received file name" // << std::endl; // triggerEvent(MPSOC_FLASH_READ_PACKET_ERROR, FlashReadErrorType::FLASH_READ_FILENAME_ERROR); // return returnvalue::FAILED; // } packetData += 12; result = SerializeAdapter::deSerialize(&receivedReadLen, &packetData, &deserDummy, SerializeIF::Endianness::NETWORK); if (result != returnvalue::OK) { return result; } if (receivedReadLen != expectedReadLen) { sif::warning << "PLOC MPSoC Flash Read: Missmatch between request read length and " "received read length" << std::endl; triggerEvent(MPSOC_FLASH_READ_PACKET_ERROR, FlashReadErrorType::FLASH_READ_READLEN_ERROR); return returnvalue::FAILED; } ofile.write(reinterpret_cast(packetData), receivedReadLen); return returnvalue::OK; } ReturnValue_t PlocMpsocSpecialComHelper::fileCheck(std::string obcFile) { #ifdef XIPHOS_Q7S ReturnValue_t result = FilesystemHelper::checkPath(obcFile); if (result != returnvalue::OK) { return result; } #elif defined(TE0720_1CFA) if (not std::filesystem::exists(obcFile)) { sif::warning << "PlocMPSoCHelper::startFlashWrite: File " << obcFile << "does not exist" << std::endl; return returnvalue::FAILED; } #endif return returnvalue::OK; } ReturnValue_t PlocMpsocSpecialComHelper::startFlashReadOrWriteBase(std::string obcFile, std::string mpsocFile) { ReturnValue_t result = fileCheck(obcFile); if (result != returnvalue::OK) { return result; } flashReadAndWrite.obcFile = std::move(obcFile); flashReadAndWrite.mpsocFile = std::move(mpsocFile); resetHelper(); return returnvalue::OK; } ReturnValue_t PlocMpsocSpecialComHelper::checkReceivedTm() { ReturnValue_t result = spReader.checkSize(); if (result != returnvalue::OK) { sif::error << "PLOC MPSoC: Size check on received TM failed" << std::endl; triggerEvent(MPSOC_TM_SIZE_ERROR); return result; } spReader.checkCrc(); if (result != returnvalue::OK) { sif::warning << "PLOC MPSoC: CRC check failed" << std::endl; triggerEvent(MPSOC_TM_CRC_MISSMATCH, *sequenceCount); return result; } uint16_t recvSeqCnt = spReader.getSequenceCount(); if (recvSeqCnt != *sequenceCount) { triggerEvent(MPSOC_HELPER_SEQ_CNT_MISMATCH, *sequenceCount, recvSeqCnt); *sequenceCount = recvSeqCnt; } // This sequence count ping pong does not make any sense but it is how the MPSoC expects it. (*sequenceCount)++; return returnvalue::OK; } ReturnValue_t PlocMpsocSpecialComHelper::receive(uint8_t* data, size_t requestBytes, size_t* readBytes) { ReturnValue_t result = returnvalue::OK; uint8_t* buffer = nullptr; result = uartComIF->requestReceiveMessage(comCookie, requestBytes); if (result != returnvalue::OK) { sif::warning << "PlocMPSoCHelper::receive: Failed to request reply" << std::endl; triggerEvent(MPSOC_HELPER_REQUESTING_REPLY_FAILED, result, static_cast(static_cast(internalState))); return returnvalue::FAILED; } result = uartComIF->readReceivedMessage(comCookie, &buffer, readBytes); if (result != returnvalue::OK) { sif::warning << "PlocMPSoCHelper::receive: Failed to read received message" << std::endl; triggerEvent(MPSOC_HELPER_READING_REPLY_FAILED, result, static_cast(internalState)); return returnvalue::FAILED; } if (*readBytes > 0) { std::memcpy(data, buffer, *readBytes); } return result; }