diff --git a/linux/devices/devicedefinitions/PlocSupervisorDefinitions.h b/linux/devices/devicedefinitions/PlocSupervisorDefinitions.h index 9aac6b0f..52fdad64 100644 --- a/linux/devices/devicedefinitions/PlocSupervisorDefinitions.h +++ b/linux/devices/devicedefinitions/PlocSupervisorDefinitions.h @@ -1486,44 +1486,47 @@ class UpdateInfo : public SupvTcSpacePacket { */ class UpdatePacket : public SupvTcSpacePacket { public: - /** - * @brief Constructor - * - * @param payloadLength Update data length (data field length without CRC) - */ - UpdatePacket(uint16_t payloadLength) : SupvTcSpacePacket(payloadLength, APID_UPDATE_IMAGE_DATA) {} - /** - * @brief Returns the pointer to the beginning of the data field. - */ - uint8_t* getDataFieldPointer() { return this->localData.fields.buffer; } -}; + /** + * @brief Constrcutor + * + * @param updateData Pointer to buffer containing update data + */ + UpdatePacket(uint8_t memoryId, uint32_t startAddress, uint16_t length, uint8_t* updateData) + : SupvTcSpacePacket(META_DATA_LENGTH + length, apid), + memoryId(memoryId), + startAddress(startAddress), + length(length) { + initPacket(updateData); + makeCrc(); + } -/** - * @brief This dataset stores the boot status report of the supervisor. - */ -class BootStatusReport : public StaticLocalDataSet { - public: - BootStatusReport(HasLocalDataPoolIF* owner) : StaticLocalDataSet(owner, BOOT_REPORT_SET_ID) {} + static const uint16_t MAX_UPDATE_DATA = 1010; - BootStatusReport(object_id_t objectId) - : StaticLocalDataSet(sid_t(objectId, BOOT_REPORT_SET_ID)) {} + private: + static const uint16_t META_DATA_LENGTH = 8; - /** Information about boot status of MPSoC */ - lp_var_t bootSignal = lp_var_t(sid.objectId, PoolIds::BOOT_SIGNAL, this); - lp_var_t resetCounter = lp_var_t(sid.objectId, PoolIds::RESET_COUNTER, this); - /** Time the MPSoC needs for last boot */ - lp_var_t bootAfterMs = lp_var_t(sid.objectId, PoolIds::BOOT_AFTER_MS, this); - /** The currently set boot timeout */ - lp_var_t bootTimeoutMs = - lp_var_t(sid.objectId, PoolIds::BOOT_TIMEOUT_MS, this); - lp_var_t activeNvm = lp_var_t(sid.objectId, PoolIds::ACTIVE_NVM, this); - /** States of the boot partition pins */ - lp_var_t bp0State = lp_var_t(sid.objectId, PoolIds::BP0_STATE, this); - lp_var_t bp1State = lp_var_t(sid.objectId, PoolIds::BP1_STATE, this); - lp_var_t bp2State = lp_var_t(sid.objectId, PoolIds::BP2_STATE, this); - lp_var_t bootState = lp_var_t(sid.objectId, PoolIds::BOOT_STATE, this); - lp_var_t bootCycles = lp_var_t(sid.objectId, PoolIds::BOOT_CYCLES, this); + uint8_t memoryId =0; + uint8_t n = 1; + uint32_t startAddress = 0; + uint16_t length = 0; + + void initPacket(uint8_t* updateData) { + size_t serializedSize = 0; + uint8_t* data_field_ptr = this->localData.fields.buffer; + SerializeAdapter::serialize(&memoryId, &data_field_ptr, &serializedSize, + sizeof(memoryId), SerializeIF::Endianness::BIG); + serializedSize = 0; + SerializeAdapter::serialize(&n, &data_field_ptr, &serializedSize, + sizeof(n), SerializeIF::Endianness::BIG); + serializedSize = 0; + SerializeAdapter::serialize(&startAddress, &data_field_ptr, &serializedSize, + sizeof(startAddress), SerializeIF::Endianness::BIG); + serializedSize = 0; + SerializeAdapter::serialize(&length, &data_field_ptr, &serializedSize, + sizeof(length), SerializeIF::Endianness::BIG); + std::memcpy(data_field_ptr, updateData, length); + } }; /** @@ -1579,6 +1582,68 @@ class LatchupStatusReport : public StaticLocalDataSet { lp_var_t timeYear = lp_var_t(sid.objectId, PoolIds::LATCHUP_RPT_TIME_YEAR, this); }; + +/** + * @brief Class for handling tm replies of the supervisor. + */ +class TmPacket : public SpacePacket, public MPSoCReturnValuesIF { + public: + /** + * @brief Constructor creates idle packet and sets length field to maximum allowed size. + */ + TmPacket() : SpacePacket(PACKET_MAX_SIZE) {} + + ReturnValue_t checkCrc() { + uint8_t* crcPtr = this->getPacketData() + this->getPacketDataLength() - 1; + uint16_t receivedCrc = *(crcPtr) << 8 | *(crcPtr + 1); + uint16_t recalculatedCrc = + CRC::crc16ccitt(this->localData.byteStream, this->getFullSize() - CRC_SIZE); + if (recalculatedCrc != receivedCrc) { + return CRC_FAILURE; + } + return HasReturnvaluesIF::RETURN_OK; + } +}; + +/** + * @brief This class can be used to package the update available or update verify command. + */ +class EraseMemory : public SupvTcSpacePacket { + public: + + EraseMemory(uint8_t memoryId, uint32_t startAddress, uint32_t length) + : SupvTcSpacePacket(PAYLOAD_LENGTH, apid), + memoryId(memoryId), + startAddress(startAddress), + length(length) { + initPacket(); + makeCrc(); + } + + private: + static const uint16_t PAYLOAD_LENGTH = 10; // length without CRC field + + uint8_t memoryId =0; + uint8_t n = 1; + uint32_t startAddress = 0; + uint32_t length = 0; + + void initPacket() { + size_t serializedSize = 0; + uint8_t* data_field_ptr = this->localData.fields.buffer; + SerializeAdapter::serialize(&memoryId, &data_field_ptr, &serializedSize, + sizeof(memoryId), SerializeIF::Endianness::BIG); + serializedSize = 0; + SerializeAdapter::serialize(&n, &data_field_ptr, &serializedSize, + sizeof(n), SerializeIF::Endianness::BIG); + serializedSize = 0; + SerializeAdapter::serialize(&startAddress, &data_field_ptr, &serializedSize, + sizeof(startAddress), SerializeIF::Endianness::BIG); + serializedSize = 0; + SerializeAdapter::serialize(&length, &data_field_ptr, &serializedSize, + sizeof(length), SerializeIF::Endianness::BIG); + } +}; } // namespace supv #endif /* MISSION_DEVICES_DEVICEDEFINITIONS_PLOCSVPDEFINITIONS_H_ */ diff --git a/linux/devices/ploc/PlocSupvHelper.cpp b/linux/devices/ploc/PlocSupvHelper.cpp new file mode 100644 index 00000000..65abb843 --- /dev/null +++ b/linux/devices/ploc/PlocSupvHelper.cpp @@ -0,0 +1,311 @@ +#include "PlocSupvHelper.h" + +#include +#include + +#include "OBSWConfig.h" +#ifdef XIPHOS_Q7S +#include "bsp_q7s/memory/FilesystemHelper.h" +#endif + +#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::FLASH_WRITE: { + result = performUpdate(); + if (result == RETURN_OK) { + triggerEvent(MPSOC_FLASH_WRITE_SUCCESSFUL); + } else { + triggerEvent(MPSOC_FLASH_WRITE_FAILED); + } + internalState = InternalState::IDLE; + break; + } + default: + sif::debug << "PlocSupvHelper::performOperation: Invalid state" << std::endl; + break; + } + } +} + +ReturnValue_t PlocSupvHelper::setComIF(DeviceCommunicationIF* communicationInterface_) { + uartComIF = dynamic_cast(communicationInterface_); + if (uartComIF == nullptr) { + sif::warning << "PlocSupvHelper::initialize: Invalid uart com if" << std::endl; + return RETURN_FAILED; + } + return RETURN_OK; +} + +void PlocSupvHelper::setComCookie(CookieIF* comCookie_) { comCookie = comCookie_; } + +void PlocSupvHelper::setSequenceCount(SourceSequenceCounter* sequenceCount_) { + sequenceCount = sequenceCount_; +} + +ReturnValue_t PlocSupvHelper::startFlashWrite(std::string obcFile, std::string mpsocFile) { + ReturnValue_t result = RETURN_OK; +#ifdef XIPHOS_Q7S + result = FilesystemHelper::checkPath(obcFile); + if (result != RETURN_OK) { + return result; + } + result = FilesystemHelper::fileExists(mpsocFile); + if (result != RETURN_OK) { + return result; + } +#endif +#ifdef TE0720_1CFA + if (not std::filesystem::exists(obcFile)) { + sif::warning << "PlocSupvHelper::startFlashWrite: File " << obcFile << "does not exist" + << std::endl; + return RETURN_FAILED; + } +#endif + + flashWrite.obcFile = obcFile; + flashWrite.mpsocFile = mpsocFile; + internalState = InternalState::FLASH_WRITE; + result = resetHelper(); + if (result != RETURN_OK) { + return result; + } + return result; +} + +ReturnValue_t PlocSupvHelper::resetHelper() { + ReturnValue_t result = RETURN_OK; + semaphore.release(); + terminate = false; + result = uartComIF->flushUartRxBuffer(comCookie); + return result; +} + +void PlocSupvHelper::stopProcess() { terminate = true; } + +ReturnValue_t PlocSupvHelper::performUpdate() { + ReturnValue_t result = RETURN_OK; + result = eraseMemory(); + if (result != RETURN_OK) { + return result; + } + uint8_t tempData[supv::UpdatePacket::MAX_UPDATE_DATA]; + std::ifstream file(update.file, std::ifstream::binary); + // 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) { + update.startAddress = bytesRead; + if (terminate) { + return RETURN_OK; + } + if (remainingSize > supv::UpdatePacket::MAX_UPDATE_DATA) { + dataLength = supv::UpdatePacket::MAX_UPDATE_DATA; + } else { + dataLength = remainingSize; + } + if (file.is_open()) { + file.seekg(bytesRead, file.beg); + file.read(reinterpret_cast(tempData), dataLength); + bytesRead += dataLength; + remainingSize -= dataLength; + } else { + return FILE_CLOSED_ACCIDENTALLY; + } + supv::UpdatePacket tc(update.memoryId, update.startAddress, tempData); + result = handlePacketTransmission(tc); + if (result != RETURN_OK) { + return result; + } + } + return result; +} + +ReturnValue_t PlocSupvHelper::eraseMemory() { + ReturnValue_t result = RETURN_OK; + supv::EraseMemory eraseMemory(memoryId, startAddress, length); + result = handlePacketTransmission(eraseMemory); + if (result != RETURN_OK) { + return result; + } + return RETURN_OK; +} + +ReturnValue_t PlocSupvHelper::flashfclose() { + ReturnValue_t result = RETURN_OK; + (*sequenceCount)++; + supv::FlashFclose flashFclose(*sequenceCount); + result = flashFclose.createPacket(flashWrite.mpsocFile); + if (result != RETURN_OK) { + return result; + } + result = handlePacketTransmission(flashFclose); + if (result != RETURN_OK) { + return result; + } + return RETURN_OK; +} + +ReturnValue_t PlocSupvHelper::handlePacketTransmission(SpacePacket& tc) { + ReturnValue_t result = RETURN_OK; + result = sendCommand(tc); + if (result != RETURN_OK) { + return result; + } + result = handleAck(); + if (result != RETURN_OK) { + return result; + } + result = handleExe(); + if (result != RETURN_OK) { + return result; + } + return RETURN_OK; +} + +ReturnValue_t PlocSupvHelper::sendCommand(supv::TcBase& tc) { + ReturnValue_t result = RETURN_OK; + result = uartComIF->sendMessage(comCookie, tc.getWholeData(), tc.getFullSize()); + if (result != RETURN_OK) { + sif::warning << "PlocSupvHelper::sendCommand: Failed to send command" << std::endl; + triggerEvent(SENDING_COMMAND_FAILED, result, static_cast(internalState)); + return result; + } + return result; +} + +ReturnValue_t PlocSupvHelper::handleAck() { + ReturnValue_t result = RETURN_OK; + supv::TmPacket tmPacket; + result = handleTmReception(&tmPacket, supv::SIZE_ACK_REPORT); + if (result != RETURN_OK) { + return result; + } + uint16_t apid = tmPacket.getAPID(); + if (apid != supv::APID_ACK_SUCCESS) { + handleAckApidFailure(apid); + return RETURN_FAILED; + } + return RETURN_OK; +} + +void PlocSupvHelper::handleAckApidFailure(uint16_t apid) { + if (apid == supv::APID_ACK_FAILURE) { + triggerEvent(ACK_FAILURE_REPORT, static_cast(internalState)); + sif::warning << "PlocSupvHelper::handleAckApidFailure: Received acknowledgement failure " + << "report" << std::endl; + } else { + triggerEvent(ACK_INVALID_APID, apid, static_cast(internalState)); + sif::warning << "PlocSupvHelper::handleAckApidFailure: Expected acknowledgement report " + << "but received space packet with apid " << std::hex << apid << std::endl; + } +} + +ReturnValue_t PlocSupvHelper::handleExe() { + ReturnValue_t result = RETURN_OK; + supv::TmPacket tmPacket; + result = handleTmReception(&tmPacket, supv::SIZE_EXE_REPORT); + if (result != RETURN_OK) { + return result; + } + uint16_t apid = tmPacket.getAPID(); + if (apid != supv::apid::EXE_SUCCESS) { + handleExeApidFailure(apid); + return RETURN_FAILED; + } + return RETURN_OK; +} + +void PlocSupvHelper::handleExeApidFailure(uint16_t apid) { + if (apid == supv::apid::EXE_FAILURE) { + triggerEvent(EXE_FAILURE_REPORT, static_cast(internalState)); + sif::warning << "PlocSupvHelper::handleExeApidFailure: Received execution failure " + << "report" << std::endl; + } else { + triggerEvent(EXE_INVALID_APID, apid, static_cast(internalState)); + sif::warning << "PlocSupvHelper::handleExeApidFailure: Expected execution report " + << "but received space packet with apid " << std::hex << apid << std::endl; + } +} + +ReturnValue_t PlocSupvHelper::handleTmReception(supv::TmPacket* tmPacket, size_t remainingBytes) { + ReturnValue_t result = RETURN_OK; + size_t readBytes = 0; + size_t currentBytes = 0; + for (int retries = 0; retries < RETRIES; retries++) { + 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 receive reply" << std::endl; + triggerEvent(MISSING_EXE, remainingBytes, static_cast(internalState)); + return RETURN_FAILED; + } + result = tmPacket->checkCrc(); + if (result != RETURN_OK) { + sif::warning << "PlocSupvHelper::handleTmReception: CRC check failed" << std::endl; + return result; + } + (*sequenceCount)++; + uint16_t recvSeqCnt = tmPacket->getPacketSequenceCount(); + if (recvSeqCnt != *sequenceCount) { + triggerEvent(MPSOC_HELPER_SEQ_CNT_MISMATCH, *sequenceCount, recvSeqCnt); + *sequenceCount = recvSeqCnt; + } + 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(MPSOC_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(MPSOC_HELPER_READING_REPLY_FAILED, result, static_cast(internalState)); + return RETURN_FAILED; + } + if (*readBytes > 0) { + std::memcpy(data, buffer, *readBytes); + } + return result; +} diff --git a/linux/devices/ploc/PlocSupvHelper.h b/linux/devices/ploc/PlocSupvHelper.h new file mode 100644 index 00000000..fade2069 --- /dev/null +++ b/linux/devices/ploc/PlocSupvHelper.h @@ -0,0 +1,153 @@ +#ifndef BSP_Q7S_DEVICES_PLOCSUPVHELPER_H_ +#define BSP_Q7S_DEVICES_PLOCSUPVHELPER_H_ + +#include + +#include "fsfw/devicehandlers/CookieIF.h" +#include "fsfw/objectmanager/SystemObject.h" +#include "fsfw/osal/linux/BinarySemaphore.h" +#include "fsfw/returnvalues/HasReturnvaluesIF.h" +#include "fsfw/tasks/ExecutableObjectIF.h" +#include "fsfw/tmtcservices/SourceSequenceCounter.h" +#include "fsfw_hal/linux/uart/UartComIF.h" +#include "linux/devices/devicedefinitions/PlocMPSoCDefinitions.h" +#ifdef XIPHOS_Q7S +#include "bsp_q7s/memory/SdCardManager.h" +#endif + +/** + * @brief Helper class for supervisor of PLOC intended to accelerate large data transfers between + * the supervisor and the OBC. + * @author J. Meier + */ +class PlocSupvHelper : public SystemObject, public ExecutableObjectIF, public HasReturnvaluesIF { + public: + static const uint8_t SUBSYSTEM_ID = SUBSYSTEM_ID::PLOC_MPSOC_HELPER; + + //! [EXPORT] : [COMMENT] update failed + static const Event SUPV_UPDATE_FAILED = MAKE_EVENT(0, severity::LOW); + //! [EXPORT] : [COMMENT] update successful + static const Event SUPV_UPDATE_SUCCESSFUL = MAKE_EVENT(1, severity::LOW); + //! [EXPORT] : [COMMENT] Communication interface returned failure when trying to send the command + //! ot the PLOC + //! P1: Return value returned by the communication interface sendMessage function + //! P2: Internal state of MPSoC helper + static const Event SENDING_COMMAND_FAILED = MAKE_EVENT(2, severity::LOW); + //! [EXPORT] : [COMMENT] Request receive message of communication interface failed + //! P1: Return value returned by the communication interface requestReceiveMessage function + //! P2: Internal state of MPSoC helper + static const Event MPSOC_HELPER_REQUESTING_REPLY_FAILED = MAKE_EVENT(3, severity::LOW); + //! [EXPORT] : [COMMENT] Reading receive message of communication interface failed + //! P1: Return value returned by the communication interface readingReceivedMessage function + //! P2: Internal state of MPSoC helper + static const Event MPSOC_HELPER_READING_REPLY_FAILED = MAKE_EVENT(4, severity::LOW); + //! [EXPORT] : [COMMENT] Did not receive acknowledgement report + //! P1: Number of bytes missing + //! P2: Internal state of MPSoC helper + static const Event MISSING_ACK = MAKE_EVENT(5, severity::LOW); + //! [EXPORT] : [COMMENT] Did not receive execution report + //! P1: Number of bytes missing + //! P2: Internal state of MPSoC helper + static const Event MISSING_EXE = MAKE_EVENT(6, severity::LOW); + //! [EXPORT] : [COMMENT] Received acknowledgement failure report + //! P1: Internal state of MPSoC + static const Event ACK_FAILURE_REPORT = MAKE_EVENT(7, severity::LOW); + //! [EXPORT] : [COMMENT] Received execution failure report + //! P1: Internal state of MPSoC + static const Event EXE_FAILURE_REPORT = MAKE_EVENT(8, severity::LOW); + //! [EXPORT] : [COMMENT] Expected acknowledgement report but received space packet with other apid + //! P1: Apid of received space packet + //! P2: Internal state of MPSoC + static const Event ACK_INVALID_APID = MAKE_EVENT(9, severity::LOW); + //! [EXPORT] : [COMMENT] Expected execution report but received space packet with other apid + //! P1: Apid of received space packet + //! P2: Internal state of MPSoC + static const Event EXE_INVALID_APID = MAKE_EVENT(10, severity::LOW); + //! [EXPORT] : [COMMENT] Received sequence count does not match expected sequence count + //! P1: Expected sequence count + //! P2: Received sequence count + static const Event MPSOC_HELPER_SEQ_CNT_MISMATCH = MAKE_EVENT(11, severity::LOW); + + PlocSupvHelper(object_id_t objectId); + virtual ~PlocSupvHelper(); + + ReturnValue_t initialize() override; + ReturnValue_t performOperation(uint8_t operationCode = 0) override; + + ReturnValue_t setComIF(DeviceCommunicationIF* communicationInterface_); + void setComCookie(CookieIF* comCookie_); + + /** + * @brief Starts flash write sequence + * + * @param obcFile File where to read from the data + * @param mpsocFile The file of the MPSoC where should be written to + * + * @return RETURN_OK if successful, otherwise error return value + */ + ReturnValue_t startUpdate(std::string file, std::string mpsocFile); + + /** + * @brief Can be used to interrupt a running data transfer. + */ + void stopProcess(); + + /** + * @brief Sets the sequence count object responsible for the sequence count handling + */ + void setSequenceCount(SourceSequenceCounter* sequenceCount_); + + private: + static const uint8_t INTERFACE_ID = CLASS_ID::PLOC_MPSOC_HELPER; + + //! [EXPORT] : [COMMENT] File accidentally close + static const ReturnValue_t FILE_CLOSED_ACCIDENTALLY = MAKE_RETURN_CODE(0xA0); + + // Maximum number of times the communication interface retries polling data from the reply + // buffer + static const int RETRIES = 10000; + + struct Update { + uint8_t memoryId; + uint32_t startAddress; + uint32_t length; + // Absolute name of file containing update data + std::string file; + }; + + struct Update update; + + enum class InternalState { IDLE, UPDATE }; + + InternalState internalState = InternalState::IDLE; + + BinarySemaphore semaphore; +#ifdef XIPHOS_Q7S + SdCardManager* sdcMan = nullptr; +#endif + uint8_t commandBuffer[supv::MAX_COMMAND_SIZE]; + + bool terminate = false; + + /** + * Communication interface of MPSoC responsible for low level access. Must be set by the + * MPSoC Handler. + */ + UartComIF* uartComIF = nullptr; + // Communication cookie. Must be set by the MPSoC Handler + CookieIF* comCookie = nullptr; + // Sequence count, must be set by Ploc MPSoC Handler + SourceSequenceCounter* sequenceCount; + + ReturnValue_t performUpdate(); + ReturnValue_t handlePacketTransmission(SpacePacket& tc); + ReturnValue_t sendCommand(SpacePacket& tc); + ReturnValue_t receive(uint8_t* data, size_t* readBytes, size_t requestBytes); + ReturnValue_t handleAck(); + ReturnValue_t handleExe(); + void handleAckApidFailure(uint16_t apid); + void handleExeApidFailure(uint16_t apid); + ReturnValue_t handleTmReception(SpacePacket* tmPacket, size_t remainingBytes); +}; + +#endif /* BSP_Q7S_DEVICES_PLOCSUPVHELPER_H_ */