commit 5ef0efe7d627b3113bf7b746c4cd0650042000ca Author: Martino Ferrari Date: Sat Feb 21 00:58:56 2026 +0100 Initial commit diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..75a34dd --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,59 @@ +cmake_minimum_required(VERSION 3.10) +project(marte_dev) + +if(NOT DEFINED ENV{MARTe2_DIR}) + message(FATAL_ERROR "MARTe2_DIR not set. Please source env.sh") +endif() + +set(MARTe2_DIR $ENV{MARTe2_DIR}) +set(MARTe2_Components_DIR $ENV{MARTe2_Components_DIR}) +set(TARGET $ENV{TARGET}) + +# Define Architecture macros +add_definitions(-DARCHITECTURE=x86_gcc) +add_definitions(-DENVIRONMENT=Linux) +add_definitions(-DMARTe2_TEST_ENVIRONMENT=GTest) # Optional +add_definitions(-DUSE_PTHREAD) + +# Add -pthread flag +set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pthread") + +include_directories( + ${MARTe2_DIR}/Source/Core/BareMetal/L0Types + ${MARTe2_DIR}/Source/Core/BareMetal/L1Portability + ${MARTe2_DIR}/Source/Core/BareMetal/L2Objects + ${MARTe2_DIR}/Source/Core/BareMetal/L3Streams + ${MARTe2_DIR}/Source/Core/BareMetal/L4Configuration + ${MARTe2_DIR}/Source/Core/BareMetal/L4Events + ${MARTe2_DIR}/Source/Core/BareMetal/L4Logger + ${MARTe2_DIR}/Source/Core/BareMetal/L4Messages + ${MARTe2_DIR}/Source/Core/BareMetal/L5FILES + ${MARTe2_DIR}/Source/Core/BareMetal/L5GAMs + ${MARTe2_DIR}/Source/Core/BareMetal/L6App + ${MARTe2_DIR}/Source/Core/Scheduler/L1Portability + ${MARTe2_DIR}/Source/Core/Scheduler/L3Services + ${MARTe2_DIR}/Source/Core/Scheduler/L4LoggerService + ${MARTe2_DIR}/Source/Core/FileSystem/L1Portability + ${MARTe2_DIR}/Source/Core/FileSystem/L3Streams + ${MARTe2_Components_DIR}/Source/Components/DataSources/EpicsDataSource + ${MARTe2_Components_DIR}/Source/Components/DataSources/FileDataSource + ${MARTe2_Components_DIR}/Source/Components/GAMs/IOGAM + Source + Headers +) + +file(GLOB_RECURSE SOURCES "Source/*.cpp") + +add_library(${PROJECT_NAME} SHARED ${SOURCES}) + +# Target MARTe2 library +set(MARTe2_LIB ${MARTe2_DIR}/Build/${TARGET}/Core/libMARTe2.so) +set(IOGAM_LIB ${MARTe2_Components_DIR}/Build/${TARGET}/Components/GAMs/IOGAM/libIOGAM.so) +set(LinuxTimer_LIB ${MARTe2_Components_DIR}/Build/${TARGET}/Components/DataSources/LinuxTimer/libLinuxTimer.so) + +target_link_libraries(${PROJECT_NAME} + ${MARTe2_LIB} +) + +add_subdirectory(Test/UnitTests) +add_subdirectory(Test/Integration) diff --git a/Headers/DebugBrokerWrapper.h b/Headers/DebugBrokerWrapper.h new file mode 100644 index 0000000..ed913cd --- /dev/null +++ b/Headers/DebugBrokerWrapper.h @@ -0,0 +1,167 @@ +#ifndef DEBUGBROKERWRAPPER_H +#define DEBUGBROKERWRAPPER_H + +#include "DebugService.h" +#include "BrokerI.h" +#include "MemoryMapBroker.h" +#include "ObjectRegistryDatabase.h" +#include "ReferenceT.h" +#include "ObjectBuilder.h" +#include "HighResolutionTimer.h" + +// Original broker headers +#include "MemoryMapInputBroker.h" +#include "MemoryMapOutputBroker.h" +#include "MemoryMapSynchronisedInputBroker.h" +#include "MemoryMapSynchronisedOutputBroker.h" +#include "MemoryMapInterpolatedInputBroker.h" +#include "MemoryMapMultiBufferInputBroker.h" +#include "MemoryMapMultiBufferOutputBroker.h" +#include "MemoryMapSynchronisedMultiBufferInputBroker.h" +#include "MemoryMapSynchronisedMultiBufferOutputBroker.h" + +namespace MARTe { + +/** + * @brief Base implementation for all debug brokers. + */ +class DebugBrokerHelper { +public: + static void Process(BrokerI* broker, DebugService* service, DebugSignalInfo** signalInfoPointers, uint32 numSignals) { + if (service == NULL_PTR(DebugService*)) return; + + while (service->IsPaused()) { + Sleep::MSec(10); + } + + if (signalInfoPointers != NULL_PTR(DebugSignalInfo**)) { + for (uint32 i = 0; i < numSignals; i++) { + DebugSignalInfo *s = signalInfoPointers[i]; + if (s != NULL_PTR(DebugSignalInfo*)) { + if (s->isTracing || s->isForcing) { + uint32 size = broker->GetCopyByteSize(i); + service->ProcessSignal(s, size); + } + } + } + } + } + + static void InitSignals(MemoryMapBroker* broker, DataSourceI &dataSourceIn, DebugService* &service, DebugSignalInfo** &signalInfoPointers, uint32 &numSignals, MemoryMapBrokerCopyTableEntry* copyTable, const char8* functionName, SignalDirection direction) { + numSignals = broker->GetNumberOfCopies(); + if (numSignals > 0) { + signalInfoPointers = new DebugSignalInfo*[numSignals]; + for (uint32 i=0; iFind("DebugService"); + if (serviceRef.IsValid()) { + service = dynamic_cast(serviceRef.operator->()); + } + + if (service && (copyTable != NULL_PTR(MemoryMapBrokerCopyTableEntry*))) { + StreamString dsPath; + DebugService::GetFullObjectName(dataSourceIn, dsPath); + + for (uint32 i = 0; i < numSignals; i++) { + void *addr = copyTable[i].dataSourcePointer; + TypeDescriptor type = copyTable[i].type; + + uint32 dsIdx = broker->GetDSCopySignalIndex(i); + StreamString signalName; + if (!dataSourceIn.GetSignalName(dsIdx, signalName)) signalName = "Unknown"; + + // 1. Register canonical DataSource name (Absolute) + StreamString dsFullName; + dsFullName.Printf("%s.%s", dsPath.Buffer(), signalName.Buffer()); + service->RegisterSignal(addr, type, dsFullName.Buffer()); + + // 2. Also register absolute GAM alias + if (functionName != NULL_PTR(const char8*)) { + StreamString gamFullName; + const char8* dirStr = (direction == InputSignals) ? "In" : "Out"; + Reference gamRef = ObjectRegistryDatabase::Instance()->Find(functionName); + if (gamRef.IsValid()) { + StreamString absGamPath; + DebugService::GetFullObjectName(*(gamRef.operator->()), absGamPath); + gamFullName.Printf("%s.%s.%s", absGamPath.Buffer(), dirStr, signalName.Buffer()); + } else { + gamFullName.Printf("Root.%s.%s.%s", functionName, dirStr, signalName.Buffer()); + } + signalInfoPointers[i] = service->RegisterSignal(addr, type, gamFullName.Buffer()); + } else { + signalInfoPointers[i] = service->RegisterSignal(addr, type, dsFullName.Buffer()); + } + } + } + } +}; + +#define DECLARE_DEBUG_BROKER_COMMON(BaseClass) \ + Debug##BaseClass() : BaseClass() { \ + service = NULL_PTR(DebugService*); \ + signalInfoPointers = NULL_PTR(DebugSignalInfo**); \ + numSignals = 0; \ + } \ + virtual ~Debug##BaseClass() { \ + if (signalInfoPointers) delete[] signalInfoPointers; \ + } \ + virtual bool Execute() { \ + bool ret = BaseClass::Execute(); \ + if (ret) DebugBrokerHelper::Process(this, service, signalInfoPointers, numSignals); \ + return ret; \ + } \ +private: \ + DebugService *service; \ + DebugSignalInfo **signalInfoPointers; \ + uint32 numSignals; + +#define DECLARE_DEBUG_BROKER(BaseClass) \ +class Debug##BaseClass : public BaseClass { \ +public: \ + DECLARE_DEBUG_BROKER_COMMON(BaseClass) \ + virtual bool Init(SignalDirection direction, DataSourceI &ds, const char8 *const name, void *gamMem) { \ + bool ret = BaseClass::Init(direction, ds, name, gamMem); \ + if (ret) DebugBrokerHelper::InitSignals(this, ds, service, signalInfoPointers, numSignals, this->copyTable, name, direction); \ + return ret; \ + } \ + virtual bool Init(SignalDirection direction, DataSourceI &ds, const char8 *const name, void *gamMem, const bool optim) { \ + bool ret = BaseClass::Init(direction, ds, name, gamMem, optim); \ + if (ret) DebugBrokerHelper::InitSignals(this, ds, service, signalInfoPointers, numSignals, this->copyTable, name, direction); \ + return ret; \ + } \ +}; \ +class Debug##BaseClass##Builder : public ObjectBuilder { \ +public: \ + virtual Object *Build(HeapI* const heap) const { return new (heap) Debug##BaseClass(); } \ +}; + +#define DECLARE_DEBUG_BROKER_NO_OPTIM(BaseClass) \ +class Debug##BaseClass : public BaseClass { \ +public: \ + DECLARE_DEBUG_BROKER_COMMON(BaseClass) \ + virtual bool Init(SignalDirection direction, DataSourceI &ds, const char8 *const name, void *gamMem) { \ + bool ret = BaseClass::Init(direction, ds, name, gamMem); \ + if (ret) DebugBrokerHelper::InitSignals(this, ds, service, signalInfoPointers, numSignals, this->copyTable, name, direction); \ + return ret; \ + } \ +}; \ +class Debug##BaseClass##Builder : public ObjectBuilder { \ +public: \ + virtual Object *Build(HeapI* const heap) const { return new (heap) Debug##BaseClass(); } \ +}; + +DECLARE_DEBUG_BROKER(MemoryMapInputBroker) +DECLARE_DEBUG_BROKER(MemoryMapOutputBroker) +DECLARE_DEBUG_BROKER(MemoryMapSynchronisedInputBroker) +DECLARE_DEBUG_BROKER(MemoryMapSynchronisedOutputBroker) +DECLARE_DEBUG_BROKER_NO_OPTIM(MemoryMapInterpolatedInputBroker) +DECLARE_DEBUG_BROKER(MemoryMapMultiBufferInputBroker) +DECLARE_DEBUG_BROKER(MemoryMapMultiBufferOutputBroker) +DECLARE_DEBUG_BROKER(MemoryMapSynchronisedMultiBufferInputBroker) +DECLARE_DEBUG_BROKER(MemoryMapSynchronisedMultiBufferOutputBroker) + +} + +#endif diff --git a/Headers/DebugCore.h b/Headers/DebugCore.h new file mode 100644 index 0000000..368b4d6 --- /dev/null +++ b/Headers/DebugCore.h @@ -0,0 +1,133 @@ +#ifndef DEBUGCORE_H +#define DEBUGCORE_H + +#include "CompilerTypes.h" +#include "TypeDescriptor.h" +#include "StreamString.h" +#include "MemoryOperationsHelper.h" + +namespace MARTe { + +struct DebugSignalInfo { + void* memoryAddress; + TypeDescriptor type; + StreamString name; + volatile bool isTracing; + volatile bool isForcing; + uint8 forcedValue[1024]; + uint32 internalID; + volatile uint32 decimationFactor; + volatile uint32 decimationCounter; +}; + +#pragma pack(push, 1) +struct TraceHeader { + uint32 magic; // 0xDA7A57AD + uint32 seq; // Sequence number + uint64 timestamp; // HighRes timestamp + uint32 count; // Number of samples in payload +}; +#pragma pack(pop) + +class TraceRingBuffer { +public: + TraceRingBuffer() { + bufferSize = 0; + buffer = NULL_PTR(uint8*); + readIndex = 0; + writeIndex = 0; + } + + ~TraceRingBuffer() { + if (buffer != NULL_PTR(uint8*)) { + delete[] buffer; + } + } + + bool Init(uint32 size) { + if (buffer != NULL_PTR(uint8*)) { + delete[] buffer; + } + bufferSize = size; + buffer = new uint8[bufferSize]; + readIndex = 0; + writeIndex = 0; + return (buffer != NULL_PTR(uint8*)); + } + + bool Push(uint32 signalID, void* data, uint32 size) { + uint32 packetSize = 4 + 4 + size; + uint32 read = readIndex; + uint32 write = writeIndex; + uint32 available = (read <= write) ? (bufferSize - (write - read) - 1) : (read - write - 1); + + if (available < packetSize) return false; + + // Use temporary write index to ensure atomic update + uint32 tempWrite = write; + WriteToBuffer(&tempWrite, &signalID, 4); + WriteToBuffer(&tempWrite, &size, 4); + WriteToBuffer(&tempWrite, data, size); + + // Final atomic update + writeIndex = tempWrite; + return true; + } + + bool Pop(uint32 &signalID, void* dataBuffer, uint32 &size, uint32 maxSize) { + uint32 read = readIndex; + uint32 write = writeIndex; + if (read == write) return false; + + uint32 tempRead = read; + uint32 tempId, tempSize; + ReadFromBuffer(&tempRead, &tempId, 4); + ReadFromBuffer(&tempRead, &tempSize, 4); + + if (tempSize > maxSize) { + // Error case: drop data up to writeIndex + readIndex = write; + return false; + } + + ReadFromBuffer(&tempRead, dataBuffer, tempSize); + signalID = tempId; + size = tempSize; + + readIndex = tempRead; + return true; + } + + uint32 Count() { + uint32 read = readIndex; + uint32 write = writeIndex; + if (write >= read) return write - read; + return bufferSize - (read - write); + } + +private: + void WriteToBuffer(uint32 *idx, void* src, uint32 count) { + uint8* s = (uint8*)src; + for (uint32 i=0; iStreamer(info); + if (type == LogStreamerType) return parent->LogStreamer(info); + return parent->Server(info); + } + private: + DebugService *parent; + ServiceType type; + }; + + ServiceBinder binderServer; + ServiceBinder binderStreamer; + ServiceBinder binderLogStreamer; + + SingleThreadService threadService; + SingleThreadService streamerService; + SingleThreadService logStreamerService; + + ThreadIdentifier serverThreadId; + ThreadIdentifier streamerThreadId; + ThreadIdentifier logStreamerThreadId; + + static const uint32 MAX_SIGNALS = 4096; + DebugSignalInfo signals[MAX_SIGNALS]; + uint32 numberOfSignals; + + static const uint32 MAX_ALIASES = 8192; + SignalAlias aliases[MAX_ALIASES]; + uint32 numberOfAliases; + + FastPollingMutexSem mutex; + TraceRingBuffer traceBuffer; + + static const uint32 MAX_CLIENTS = 16; + BasicTCPSocket* activeClients[MAX_CLIENTS]; + FastPollingMutexSem clientsMutex; + + BasicTCPSocket* activeLogClients[MAX_CLIENTS]; + FastPollingMutexSem logClientsMutex; + + static const uint32 LOG_QUEUE_SIZE = 1024; + LogEntry logQueue[LOG_QUEUE_SIZE]; + volatile uint32 logQueueRead; + volatile uint32 logQueueWrite; + EventSem logEvent; + + static DebugService* instance; + static ErrorManagement::ErrorProcessFunctionType originalLogCallback; +}; + +} + +#endif diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..655f3fd --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +all: build + +build: + mkdir -p Build && cd Build && . ../env.sh && cmake -DCMAKE_BUILD_TYPE=Debug .. && make + ln -sf libmarte_dev.so Build/DebugService.so + +clean: + rm -rf Build + +.PHONY: all build clean diff --git a/README.md b/README.md new file mode 100644 index 0000000..1e38c79 --- /dev/null +++ b/README.md @@ -0,0 +1,48 @@ +# MARTe2 Universal Debugging & Observability Suite + +A professional-grade, zero-code-change debugging suite for the MARTe2 real-time framework. + +## Features + +- **Runtime Registry Patching**: Instruments all MARTe2 Brokers automatically at startup. +- **Hierarchical Tree Explorer**: Recursive visualization of the `ObjectRegistryDatabase`, including GAMs, DataSources, and Signals. +- **Real-Time Execution Control**: Pause and Resume application logic globally to perform static inspection. +- **High-Speed Telemetry**: Visual oscilloscope with sub-millisecond precision via UDP. +- **Persistent Forcing**: Type-aware signal overrides (Last-Writer-Wins) with persistent re-application. +- **Isolated Log Streaming**: Dedicated TCP channel for real-time framework logs to ensure command responsiveness. + +## Components + +### 1. C++ Core (`libmarte_dev.so`) +The core service that handles registry patching, TCP/UDP communication, and real-time safe data capture. + +### 2. Rust GUI Client (`marte_debug_gui`) +A native, multi-threaded dashboard built with `egui`. +- **Side Panel**: Collapsible application tree and signal navigator. +- **Bottom Panel**: Advanced log terminal with Regex filtering and priority levels. +- **Right Panel**: Active Trace and Force management. +- **Central Pane**: High-frequency oscilloscope. + +## Quick Start + +### Build +```bash +# Build C++ Core +cd Build && cmake .. && make -j$(nproc) + +# Build GUI Client +cd Tools/gui_client +cargo build --release +``` + +### Run +1. Start your MARTe2 application with the `DebugService` enabled. +2. Launch the GUI: + ```bash + ./Tools/gui_client/target/release/marte_debug_gui + ``` + +## Communication Ports +- **8080 (TCP)**: Commands (TREE, FORCE, TRACE, PAUSE). +- **8082 (TCP)**: Real-time framework logs. +- **8081 (UDP)**: Signal telemetry data. diff --git a/Source/DebugService.cpp b/Source/DebugService.cpp new file mode 100644 index 0000000..272262c --- /dev/null +++ b/Source/DebugService.cpp @@ -0,0 +1,910 @@ +#include "DebugService.h" +#include "StandardParser.h" +#include "StreamString.h" +#include "BasicSocket.h" +#include "DebugBrokerWrapper.h" +#include "ObjectRegistryDatabase.h" +#include "ClassRegistryItem.h" +#include "ObjectBuilder.h" +#include "TypeConversion.h" +#include "HighResolutionTimer.h" +#include "ConfigurationDatabase.h" +#include "GAM.h" + +// Explicitly include target brokers for templating +#include "MemoryMapInputBroker.h" +#include "MemoryMapOutputBroker.h" +#include "MemoryMapSynchronisedInputBroker.h" +#include "MemoryMapSynchronisedOutputBroker.h" +#include "MemoryMapInterpolatedInputBroker.h" +#include "MemoryMapMultiBufferInputBroker.h" +#include "MemoryMapMultiBufferOutputBroker.h" +#include "MemoryMapSynchronisedMultiBufferInputBroker.h" +#include "MemoryMapSynchronisedMultiBufferOutputBroker.h" + +namespace MARTe { + +DebugService* DebugService::instance = NULL_PTR(DebugService*); +ErrorManagement::ErrorProcessFunctionType DebugService::originalLogCallback = NULL_PTR(ErrorManagement::ErrorProcessFunctionType); + +static void EscapeJson(const char8* src, StreamString &dst) { + if (src == NULL_PTR(const char8*)) return; + while (*src != '\0') { + if (*src == '"') dst += "\\\""; + else if (*src == '\\') dst += "\\\\"; + else if (*src == '\n') dst += "\\n"; + else if (*src == '\r') dst += "\\r"; + else if (*src == '\t') dst += "\\t"; + else dst += *src; + src++; + } +} + +CLASS_REGISTER(DebugService, "1.0") + +DebugService::DebugService() : + ReferenceContainer(), EmbeddedServiceMethodBinderI(), LoggerConsumerI(), + binderServer(this, ServiceBinder::ServerType), + binderStreamer(this, ServiceBinder::StreamerType), + binderLogStreamer(this, ServiceBinder::LogStreamerType), + threadService(binderServer), + streamerService(binderStreamer), + logStreamerService(binderLogStreamer) +{ + controlPort = 0; + streamPort = 8081; + logPort = 8082; + streamIP = "127.0.0.1"; + numberOfSignals = 0; + numberOfAliases = 0; + isServer = false; + suppressTimeoutLogs = true; + isPaused = false; + for (uint32 i=0; iClose(); + delete activeClients[i]; + } + if (activeLogClients[i] != NULL_PTR(BasicTCPSocket*)) { + activeLogClients[i]->Close(); + delete activeLogClients[i]; + } + } +} + +bool DebugService::Initialise(StructuredDataI & data) { + if (!ReferenceContainer::Initialise(data)) return false; + + if (!data.Read("ControlPort", controlPort)) { + (void)data.Read("TcpPort", controlPort); + } + + if (controlPort > 0) { + isServer = true; + instance = this; + } + + if (!data.Read("StreamPort", streamPort)) { + (void)data.Read("UdpPort", streamPort); + } + + if (!data.Read("LogPort", logPort)) { + (void)data.Read("TcpLogPort", logPort); + } + + (void)data.Read("StreamIP", streamIP); + + uint32 suppress = 1; + if (data.Read("SuppressTimeoutLogs", suppress)) { + suppressTimeoutLogs = (suppress == 1); + } + + if (isServer) { + if (ErrorManagement::errorMessageProcessFunction != &DebugService::LogCallback) { + originalLogCallback = ErrorManagement::errorMessageProcessFunction; + ErrorManagement::SetErrorProcessFunction(&DebugService::LogCallback); + } + + if (!traceBuffer.Init(1024 * 1024)) return false; + + (void)logEvent.Create(); + + PatchRegistry(); + + ConfigurationDatabase threadData; + threadData.Write("Timeout", (uint32)1000); + threadService.Initialise(threadData); + streamerService.Initialise(threadData); + logStreamerService.Initialise(threadData); + + if (!tcpServer.Open()) { + REPORT_ERROR(ErrorManagement::FatalError, "DebugService: Failed to open TCP Server Socket"); + return false; + } + if (!udpSocket.Open()) { + REPORT_ERROR(ErrorManagement::FatalError, "DebugService: Failed to open UDP Socket"); + return false; + } + if (!logServer.Open()) { + REPORT_ERROR(ErrorManagement::FatalError, "DebugService: Failed to open Log Server Socket"); + return false; + } + + if (threadService.Start() != ErrorManagement::NoError) { + REPORT_ERROR(ErrorManagement::FatalError, "DebugService: Failed to start Server thread"); + return false; + } + if (streamerService.Start() != ErrorManagement::NoError) { + REPORT_ERROR(ErrorManagement::FatalError, "DebugService: Failed to start Streamer thread"); + return false; + } + if (logStreamerService.Start() != ErrorManagement::NoError) { + REPORT_ERROR(ErrorManagement::FatalError, "DebugService: Failed to start LogStreamer thread"); + return false; + } + } + + return true; +} + +void PatchItemInternal(const char8* className, ObjectBuilder* builder) { + ClassRegistryDatabase *db = ClassRegistryDatabase::Instance(); + ClassRegistryItem *item = (ClassRegistryItem*)db->Find(className); + if (item != NULL_PTR(ClassRegistryItem*)) { + item->SetObjectBuilder(builder); + } +} + +void DebugService::PatchRegistry() { + static DebugMemoryMapInputBrokerBuilder b1; + PatchItemInternal("MemoryMapInputBroker", &b1); + static DebugMemoryMapOutputBrokerBuilder b2; + PatchItemInternal("MemoryMapOutputBroker", &b2); + static DebugMemoryMapSynchronisedInputBrokerBuilder b3; + PatchItemInternal("MemoryMapSynchronisedInputBroker", &b3); + static DebugMemoryMapSynchronisedOutputBrokerBuilder b4; + PatchItemInternal("MemoryMapSynchronisedOutputBroker", &b4); + static DebugMemoryMapInterpolatedInputBrokerBuilder b5; + PatchItemInternal("MemoryMapInterpolatedInputBroker", &b5); + static DebugMemoryMapMultiBufferInputBrokerBuilder b6; + PatchItemInternal("MemoryMapMultiBufferInputBroker", &b6); + static DebugMemoryMapMultiBufferOutputBrokerBuilder b7; + PatchItemInternal("MemoryMapMultiBufferOutputBroker", &b7); + static DebugMemoryMapSynchronisedMultiBufferInputBrokerBuilder b8; + PatchItemInternal("MemoryMapSynchronisedMultiBufferInputBroker", &b8); + static DebugMemoryMapSynchronisedMultiBufferOutputBrokerBuilder b9; + PatchItemInternal("MemoryMapSynchronisedMultiBufferOutputBroker", &b9); +} + +void DebugService::ProcessSignal(DebugSignalInfo* s, uint32 size) { + if (s != NULL_PTR(DebugSignalInfo*)) { + if (s->isForcing) { + MemoryOperationsHelper::Copy(s->memoryAddress, s->forcedValue, size); + } + if (s->isTracing) { + if (s->decimationFactor <= 1) { + (void)traceBuffer.Push(s->internalID, s->memoryAddress, size); + } + else { + if (s->decimationCounter == 0) { + (void)traceBuffer.Push(s->internalID, s->memoryAddress, size); + s->decimationCounter = s->decimationFactor - 1; + } + else { + s->decimationCounter--; + } + } + } + } +} + +DebugSignalInfo* DebugService::RegisterSignal(void* memoryAddress, TypeDescriptor type, const char8* name) { + mutex.FastLock(); + DebugSignalInfo* res = NULL_PTR(DebugSignalInfo*); + + uint32 sigIdx = 0xFFFFFFFF; + for(uint32 i=0; imemoryAddress = memoryAddress; + res->type = type; + res->name = name; + res->isTracing = false; + res->isForcing = false; + res->internalID = numberOfSignals; + res->decimationFactor = 1; + res->decimationCounter = 0; + numberOfSignals++; + } + + if (sigIdx != 0xFFFFFFFF && numberOfAliases < MAX_ALIASES) { + bool foundAlias = false; + for (uint32 i=0; iSize(); + for (uint32 i=0; iGet(i); + if (child.IsValid()) { + if (child.operator->() == &obj) { + path = child->GetName(); + return true; + } + ReferenceContainer *inner = dynamic_cast(child.operator->()); + if (inner) { + if (RecursiveGetFullObjectName(inner, obj, path)) { + StreamString prefix = child->GetName(); + prefix += "."; + prefix += path; + path = prefix; + return true; + } + } + } + } + return false; +} + +bool DebugService::GetFullObjectName(const Object &obj, StreamString &fullPath) { + fullPath = ""; + if (RecursiveGetFullObjectName(ObjectRegistryDatabase::Instance(), obj, fullPath)) { + StreamString abs = "Root."; + abs += fullPath; + fullPath = abs; + return true; + } + return false; +} + +ErrorManagement::ErrorType DebugService::Execute(ExecutionInfo & info) { + return ErrorManagement::FatalError; +} + +ErrorManagement::ErrorType DebugService::Server(ExecutionInfo & info) { + if (info.GetStage() == ExecutionInfo::TerminationStage) return ErrorManagement::NoError; + if (info.GetStage() == ExecutionInfo::StartupStage) { + serverThreadId = Threads::Id(); + if (!tcpServer.Listen(controlPort)) return ErrorManagement::FatalError; + return ErrorManagement::NoError; + } + + while (info.GetStage() == ExecutionInfo::MainStage) { + if (ErrorManagement::errorMessageProcessFunction != &DebugService::LogCallback) { + originalLogCallback = ErrorManagement::errorMessageProcessFunction; + ErrorManagement::SetErrorProcessFunction(&DebugService::LogCallback); + } + + BasicTCPSocket *newClient = tcpServer.WaitConnection(1); + if (newClient != NULL_PTR(BasicTCPSocket *)) { + clientsMutex.FastLock(); + bool added = false; + for (uint32 i=0; iClose(); + delete newClient; + } + } + + for (uint32 i=0; iRead(buffer, size, timeout); + + if (ok && size > 0) { + StreamString command; + command.Write(buffer, size); + HandleCommand(command, client); + } else if (!ok) { + if (!client->IsValid()) { + clientsMutex.FastLock(); + client->Close(); + delete client; + activeClients[i] = NULL_PTR(BasicTCPSocket*); + clientsMutex.FastUnLock(); + } + } + } + } + Sleep::MSec(10); + } + return ErrorManagement::NoError; +} + +ErrorManagement::ErrorType DebugService::LogStreamer(ExecutionInfo & info) { + if (info.GetStage() == ExecutionInfo::TerminationStage) return ErrorManagement::NoError; + if (info.GetStage() == ExecutionInfo::StartupStage) { + logStreamerThreadId = Threads::Id(); + if (!logServer.Listen(logPort)) return ErrorManagement::FatalError; + return ErrorManagement::NoError; + } + + while (info.GetStage() == ExecutionInfo::MainStage) { + BasicTCPSocket *newClient = logServer.WaitConnection(1); + if (newClient != NULL_PTR(BasicTCPSocket *)) { + logClientsMutex.FastLock(); + bool added = false; + for (uint32 i=0; iClose(); + delete newClient; + } + } + + bool hadData = false; + for (uint32 b=0; b<50; b++) { + if (logQueueRead == logQueueWrite) break; + hadData = true; + + uint32 idx = logQueueRead % LOG_QUEUE_SIZE; + LogEntry &entry = logQueue[idx]; + + StreamString level; + ErrorManagement::ErrorCodeToStream(entry.info.header.errorType, level); + + StreamString packet; + packet.Printf("LOG %s %s\n", level.Buffer(), entry.description); + uint32 size = packet.Size(); + + logClientsMutex.FastLock(); + for (uint32 j=0; jWrite(packet.Buffer(), s)) { + activeLogClients[j]->Close(); + delete activeLogClients[j]; + activeLogClients[j] = NULL_PTR(BasicTCPSocket*); + } + } + } + logClientsMutex.FastUnLock(); + logQueueRead++; + } + + if (!hadData) { + (void)logEvent.Wait(TimeoutType(100)); + logEvent.Reset(); + } else { + Sleep::MSec(1); + } + } + return ErrorManagement::NoError; +} + +ErrorManagement::ErrorType DebugService::Streamer(ExecutionInfo & info) { + if (info.GetStage() == ExecutionInfo::TerminationStage) return ErrorManagement::NoError; + if (info.GetStage() == ExecutionInfo::StartupStage) { + streamerThreadId = Threads::Id(); + return ErrorManagement::NoError; + } + + InternetHost dest(streamPort, streamIP.Buffer()); + udpSocket.SetDestination(dest); + + uint8 packetBuffer[4096]; + uint32 packetOffset = 0; + uint32 sequenceNumber = 0; + + while (info.GetStage() == ExecutionInfo::MainStage) { + uint32 id; + uint32 size; + uint8 sampleData[1024]; + bool hasData = false; + + while ((info.GetStage() == ExecutionInfo::MainStage) && traceBuffer.Pop(id, sampleData, size, 1024)) { + hasData = true; + if (packetOffset == 0) { + TraceHeader header; + header.magic = 0xDA7A57AD; + header.seq = sequenceNumber++; + header.timestamp = HighResolutionTimer::Counter(); + header.count = 0; + MemoryOperationsHelper::Copy(packetBuffer, &header, sizeof(TraceHeader)); + packetOffset = sizeof(TraceHeader); + } + + if (packetOffset + 8 + size > 1400) { + uint32 toWrite = packetOffset; + udpSocket.Write((char8*)packetBuffer, toWrite); + packetOffset = 0; + TraceHeader header; + header.magic = 0xDA7A57AD; + header.seq = sequenceNumber++; + header.timestamp = HighResolutionTimer::Counter(); + header.count = 0; + MemoryOperationsHelper::Copy(packetBuffer, &header, sizeof(TraceHeader)); + packetOffset = sizeof(TraceHeader); + } + + MemoryOperationsHelper::Copy(&packetBuffer[packetOffset], &id, 4); + MemoryOperationsHelper::Copy(&packetBuffer[packetOffset + 4], &size, 4); + MemoryOperationsHelper::Copy(&packetBuffer[packetOffset + 8], sampleData, size); + packetOffset += (8 + size); + TraceHeader *h = (TraceHeader*)packetBuffer; + h->count++; + } + + if (packetOffset > 0) { + uint32 toWrite = packetOffset; + udpSocket.Write((char8*)packetBuffer, toWrite); + packetOffset = 0; + } + if (!hasData) Sleep::MSec(1); + } + return ErrorManagement::NoError; +} + +static bool SuffixMatch(const char8* target, const char8* pattern) { + uint32 tLen = StringHelper::Length(target); + uint32 pLen = StringHelper::Length(pattern); + if (pLen > tLen) return false; + const char8* suffix = target + (tLen - pLen); + if (StringHelper::Compare(suffix, pattern) == 0) { + if (tLen == pLen || *(suffix - 1) == '.') return true; + } + return false; +} + +void DebugService::HandleCommand(StreamString cmd, BasicTCPSocket *client) { + StreamString token; + cmd.Seek(0); + char8 term; + const char8* delims = " \r\n"; + if (cmd.GetToken(token, delims, term)) { + if (token == "FORCE") { + StreamString name, val; + if (cmd.GetToken(name, delims, term) && cmd.GetToken(val, delims, term)) { + uint32 count = ForceSignal(name.Buffer(), val.Buffer()); + if (client) { + StreamString resp; resp.Printf("OK FORCE %u\n", count); + uint32 s = resp.Size(); client->Write(resp.Buffer(), s); + } + } + } + else if (token == "UNFORCE") { + StreamString name; + if (cmd.GetToken(name, delims, term)) { + uint32 count = UnforceSignal(name.Buffer()); + if (client) { + StreamString resp; resp.Printf("OK UNFORCE %u\n", count); + uint32 s = resp.Size(); client->Write(resp.Buffer(), s); + } + } + } + else if (token == "TRACE") { + StreamString name, state, decim; + if (cmd.GetToken(name, delims, term) && cmd.GetToken(state, delims, term)) { + bool enable = (state == "1"); + uint32 d = 1; + if (cmd.GetToken(decim, delims, term)) { + AnyType decimVal(UnsignedInteger32Bit, 0u, &d); + AnyType decimStr(CharString, 0u, decim.Buffer()); + TypeConvert(decimVal, decimStr); + } + uint32 count = TraceSignal(name.Buffer(), enable, d); + if (client) { + StreamString resp; resp.Printf("OK TRACE %u\n", count); + uint32 s = resp.Size(); client->Write(resp.Buffer(), s); + } + } + } + else if (token == "DISCOVER") Discover(client); + else if (token == "PAUSE") { + SetPaused(true); + if (client) { uint32 s = 3; client->Write("OK\n", s); } + } + else if (token == "RESUME") { + SetPaused(false); + if (client) { uint32 s = 3; client->Write("OK\n", s); } + } + else if (token == "TREE") { + StreamString json; + json = "{\"Name\": \"Root\", \"Class\": \"ObjectRegistryDatabase\", \"Children\": [\n"; + ExportTree(ObjectRegistryDatabase::Instance(), json); + json += "\n]}\nOK TREE\n"; + uint32 s = json.Size(); + client->Write(json.Buffer(), s); + } + else if (token == "INFO") { + StreamString path; + if (cmd.GetToken(path, delims, term)) InfoNode(path.Buffer(), client); + } + else if (token == "LS") { + StreamString path; + if (cmd.GetToken(path, delims, term)) ListNodes(path.Buffer(), client); + else ListNodes(NULL_PTR(const char8*), client); + } + else if (client) { + const char* msg = "ERROR: Unknown command\n"; + uint32 s = StringHelper::Length(msg); + client->Write(msg, s); + } + } +} + +void DebugService::InfoNode(const char8* path, BasicTCPSocket *client) { + if (!client) return; + Reference ref = ObjectRegistryDatabase::Instance()->Find(path); + StreamString json = "{"; + + if (ref.IsValid()) { + json += "\"Name\": \""; EscapeJson(ref->GetName(), json); + json += "\", \"Class\": \""; EscapeJson(ref->GetClassProperties()->GetName(), json); json += "\""; + + ConfigurationDatabase db; + if (ref->ExportData(db)) { + json += ", \"Config\": {"; + db.MoveToRoot(); + uint32 nChildren = db.GetNumberOfChildren(); + for (uint32 i=0; iWrite(json.Buffer(), s); +} + +uint32 DebugService::ExportTree(ReferenceContainer *container, StreamString &json) { + if (container == NULL_PTR(ReferenceContainer*)) return 0; + uint32 size = container->Size(); + uint32 validCount = 0; + for (uint32 i = 0u; i < size; i++) { + Reference child = container->Get(i); + if (child.IsValid()) { + if (validCount > 0u) json += ",\n"; + + StreamString nodeJson; + const char8* cname = child->GetName(); + if (cname == NULL_PTR(const char8*)) cname = "unnamed"; + const char8* clsname = child->GetClassProperties()->GetName(); + + nodeJson += "{\"Name\": \""; EscapeJson(cname, nodeJson); + nodeJson += "\", \"Class\": \""; EscapeJson(clsname, nodeJson); nodeJson += "\""; + + ReferenceContainer *inner = dynamic_cast(child.operator->()); + DataSourceI *ds = dynamic_cast(child.operator->()); + GAM *gam = dynamic_cast(child.operator->()); + + if ((inner != NULL_PTR(ReferenceContainer*)) || (ds != NULL_PTR(DataSourceI*)) || (gam != NULL_PTR(GAM*))) { + nodeJson += ", \"Children\": [\n"; + uint32 subCount = 0u; + if (inner != NULL_PTR(ReferenceContainer*)) subCount += ExportTree(inner, nodeJson); + + if (ds != NULL_PTR(DataSourceI*)) { + uint32 nSignals = ds->GetNumberOfSignals(); + for (uint32 j = 0u; j < nSignals; j++) { + if (subCount > 0u) nodeJson += ",\n"; + subCount++; + StreamString sname; (void)ds->GetSignalName(j, sname); + const char8* stype = TypeDescriptor::GetTypeNameFromTypeDescriptor(ds->GetSignalType(j)); + uint8 dims = 0u; (void)ds->GetSignalNumberOfDimensions(j, dims); + uint32 elems = 0u; (void)ds->GetSignalNumberOfElements(j, elems); + + nodeJson += "{\"Name\": \""; EscapeJson(sname.Buffer(), nodeJson); + nodeJson += "\", \"Class\": \"Signal\", \"Type\": \""; EscapeJson(stype ? stype : "Unknown", nodeJson); + nodeJson.Printf("\", \"Dimensions\": %d, \"Elements\": %u}", dims, elems); + } + } + + if (gam != NULL_PTR(GAM*)) { + uint32 nIn = gam->GetNumberOfInputSignals(); + for (uint32 j = 0u; j < nIn; j++) { + if (subCount > 0u) nodeJson += ",\n"; + subCount++; + StreamString sname; (void)gam->GetSignalName(InputSignals, j, sname); + const char8* stype = TypeDescriptor::GetTypeNameFromTypeDescriptor(gam->GetSignalType(InputSignals, j)); + uint32 dims = 0u; (void)gam->GetSignalNumberOfDimensions(InputSignals, j, dims); + uint32 elems = 0u; (void)gam->GetSignalNumberOfElements(InputSignals, j, elems); + + nodeJson += "{\"Name\": \"In."; EscapeJson(sname.Buffer(), nodeJson); + nodeJson += "\", \"Class\": \"InputSignal\", \"Type\": \""; EscapeJson(stype ? stype : "Unknown", nodeJson); + nodeJson.Printf("\", \"Dimensions\": %u, \"Elements\": %u}", dims, elems); + } + uint32 nOut = gam->GetNumberOfOutputSignals(); + for (uint32 j = 0u; j < nOut; j++) { + if (subCount > 0u) nodeJson += ",\n"; + subCount++; + StreamString sname; (void)gam->GetSignalName(OutputSignals, j, sname); + const char8* stype = TypeDescriptor::GetTypeNameFromTypeDescriptor(gam->GetSignalType(OutputSignals, j)); + uint32 dims = 0u; (void)gam->GetSignalNumberOfDimensions(OutputSignals, j, dims); + uint32 elems = 0u; (void)gam->GetSignalNumberOfElements(OutputSignals, j, elems); + + nodeJson += "{\"Name\": \"Out."; EscapeJson(sname.Buffer(), nodeJson); + nodeJson += "\", \"Class\": \"OutputSignal\", \"Type\": \""; EscapeJson(stype ? stype : "Unknown", nodeJson); + nodeJson.Printf("\", \"Dimensions\": %u, \"Elements\": %u}", dims, elems); + } + } + nodeJson += "\n]"; + } + nodeJson += "}"; + json += nodeJson; + validCount++; + } + } + return validCount; +} + +uint32 DebugService::ForceSignal(const char8* name, const char8* valueStr) { + mutex.FastLock(); + uint32 count = 0; + for (uint32 i = 0; i < numberOfAliases; i++) { + if (aliases[i].name == name || SuffixMatch(aliases[i].name.Buffer(), name)) { + DebugSignalInfo &s = signals[aliases[i].signalIndex]; + s.isForcing = true; + AnyType dest(s.type, 0u, s.forcedValue); + AnyType source(CharString, 0u, valueStr); + (void)TypeConvert(dest, source); + count++; + } + } + mutex.FastUnLock(); + return count; +} + +uint32 DebugService::UnforceSignal(const char8* name) { + mutex.FastLock(); + uint32 count = 0; + for (uint32 i = 0; i < numberOfAliases; i++) { + if (aliases[i].name == name || SuffixMatch(aliases[i].name.Buffer(), name)) { + signals[aliases[i].signalIndex].isForcing = false; + count++; + } + } + mutex.FastUnLock(); + return count; +} + +uint32 DebugService::TraceSignal(const char8* name, bool enable, uint32 decimation) { + mutex.FastLock(); + uint32 count = 0; + for (uint32 i = 0; i < numberOfAliases; i++) { + if (aliases[i].name == name || SuffixMatch(aliases[i].name.Buffer(), name)) { + DebugSignalInfo &s = signals[aliases[i].signalIndex]; + s.isTracing = enable; + s.decimationFactor = decimation; + s.decimationCounter = 0; + count++; + printf("[Debug] Tracing state for %s (ID: %u) set to %d\n", aliases[i].name.Buffer(), s.internalID, enable); + } + } + mutex.FastUnLock(); + return count; +} + +void DebugService::Discover(BasicTCPSocket *client) { + if (client) { + StreamString header = "{\n \"Signals\": [\n"; + uint32 s = header.Size(); + client->Write(header.Buffer(), s); + mutex.FastLock(); + for (uint32 i = 0; i < numberOfAliases; i++) { + StreamString line; + DebugSignalInfo &sig = signals[aliases[i].signalIndex]; + const char8* typeName = TypeDescriptor::GetTypeNameFromTypeDescriptor(sig.type); + if (typeName == NULL_PTR(const char8*)) typeName = "Unknown"; + line.Printf(" {\"name\": \"%s\", \"id\": %d, \"type\": \"%s\"}", aliases[i].name.Buffer(), sig.internalID, typeName); + if (i < numberOfAliases - 1) line += ","; + line += "\n"; + s = line.Size(); + client->Write(line.Buffer(), s); + } + mutex.FastUnLock(); + StreamString footer = " ]\n}\nOK DISCOVER\n"; + s = footer.Size(); + client->Write(footer.Buffer(), s); + } +} + +void DebugService::ListNodes(const char8* path, BasicTCPSocket *client) { + if (!client) return; + Reference ref; + if (path == NULL_PTR(const char8*) || StringHelper::Length(path) == 0 || StringHelper::Compare(path, "/") == 0) { + ref = ObjectRegistryDatabase::Instance(); + } else { + ref = ObjectRegistryDatabase::Instance()->Find(path); + } + + if (ref.IsValid()) { + StreamString header; + header.Printf("Nodes under %s:\n", path ? path : "/"); + uint32 s = header.Size(); + client->Write(header.Buffer(), s); + + ReferenceContainer *container = dynamic_cast(ref.operator->()); + if (container) { + uint32 size = container->Size(); + for (uint32 i=0; iGet(i); + if (child.IsValid()) { + StreamString line; + line.Printf(" %s [%s]\n", child->GetName(), child->GetClassProperties()->GetName()); + s = line.Size(); + client->Write(line.Buffer(), s); + } + } + } + + DataSourceI *ds = dynamic_cast(ref.operator->()); + if (ds) { + StreamString dsHeader = " Signals:\n"; + s = dsHeader.Size(); client->Write(dsHeader.Buffer(), s); + uint32 nSignals = ds->GetNumberOfSignals(); + for (uint32 i=0; iGetSignalName(i, sname); + TypeDescriptor stype = ds->GetSignalType(i); + const char8* stypeName = TypeDescriptor::GetTypeNameFromTypeDescriptor(stype); + line.Printf(" %s [%s]\n", sname.Buffer(), stypeName ? stypeName : "Unknown"); + s = line.Size(); client->Write(line.Buffer(), s); + } + } + + GAM *gam = dynamic_cast(ref.operator->()); + if (gam) { + uint32 nIn = gam->GetNumberOfInputSignals(); + uint32 nOut = gam->GetNumberOfOutputSignals(); + StreamString gamHeader; + gamHeader.Printf(" Input Signals (%d):\n", nIn); + s = gamHeader.Size(); client->Write(gamHeader.Buffer(), s); + for (uint32 i=0; iGetSignalName(InputSignals, i, sname); + line.Printf(" %s\n", sname.Buffer()); + s = line.Size(); client->Write(line.Buffer(), s); + } + gamHeader.SetSize(0); + gamHeader.Printf(" Output Signals (%d):\n", nOut); + s = gamHeader.Size(); client->Write(gamHeader.Buffer(), s); + for (uint32 i=0; iGetSignalName(OutputSignals, i, sname); + line.Printf(" %s\n", sname.Buffer()); + s = line.Size(); client->Write(line.Buffer(), s); + } + } + + const char* okMsg = "OK LS\n"; + s = StringHelper::Length(okMsg); + client->Write(okMsg, s); + } else { + const char* msg = "ERROR: Path not found\n"; + uint32 s = StringHelper::Length(msg); + client->Write(msg, s); + } +} + +void DebugService::ConsumeLogMessage(LoggerPage *logPage) { +} + +void DebugService::LogCallback(const ErrorManagement::ErrorInformation &errorInfo, const char8 * const errorDescription) { + ThreadIdentifier current = Threads::Id(); + if (instance != NULL_PTR(DebugService*)) { + StreamString levelStr; + ErrorManagement::ErrorCodeToStream(errorInfo.header.errorType, levelStr); + printf("[%s] %s\n", levelStr.Buffer(), errorDescription); + fflush(stdout); + + bool isWorkerThread = false; + if (instance->serverThreadId != InvalidThreadIdentifier && current == instance->serverThreadId) isWorkerThread = true; + if (instance->streamerThreadId != InvalidThreadIdentifier && current == instance->streamerThreadId) isWorkerThread = true; + if (instance->logStreamerThreadId != InvalidThreadIdentifier && current == instance->logStreamerThreadId) isWorkerThread = true; + + if (isWorkerThread) return; + + if (instance->suppressTimeoutLogs && StringHelper::SearchString(errorDescription, "Timeout expired in recv()") != NULL_PTR(const char8*)) return; + + LoggerPage tempPage; + tempPage.errorInfo = errorInfo; + StringHelper::Copy(tempPage.errorStrBuffer, errorDescription); + instance->InsertLogIntoQueue(&tempPage); + } + if (originalLogCallback) originalLogCallback(errorInfo, errorDescription); +} + +void DebugService::InsertLogIntoQueue(LoggerPage *logPage) { + uint32 next = (logQueueWrite + 1) % LOG_QUEUE_SIZE; + if (next != logQueueRead) { + LogEntry &entry = logQueue[logQueueWrite % LOG_QUEUE_SIZE]; + entry.info = logPage->errorInfo; + StringHelper::Copy(entry.description, logPage->errorStrBuffer); + logQueueWrite = next; + (void)logEvent.Post(); + } +} + +} diff --git a/Test/Configurations/debug_test.cfg b/Test/Configurations/debug_test.cfg new file mode 100644 index 0000000..da337d8 --- /dev/null +++ b/Test/Configurations/debug_test.cfg @@ -0,0 +1,101 @@ ++DebugService = { + Class = DebugService + ControlPort = 8080 + StreamPort = 8081 + StreamIP = "127.0.0.1" +} + ++LoggerService = { + Class = LoggerService + CPUs = 0x1 + +DebugConsumer = { + Class = DebugService + } +} + ++App = { + Class = RealTimeApplication + +Functions = { + Class = ReferenceContainer + +GAM1 = { + Class = IOGAM + InputSignals = { + Counter = { + DataSource = Timer + Type = uint32 + Frequency = 10 + } + Time = { + DataSource = Timer + Type = uint32 + } + } + OutputSignals = { + Counter = { + DataSource = DDB + Type = uint32 + } + Time = { + DataSource = Logger + Type = uint32 + } + } + } + } + +Data = { + Class = ReferenceContainer + DefaultDataSource = DDB + +Timer = { + Class = LinuxTimer + SleepTime = 1000000 // 1 second + Signals = { + Counter = { + Type = uint32 + } + Time = { + Type = uint32 + } + } + } + +Logger = { + Class = LoggerDataSource + Signals = { + CounterCopy = { + Type = uint32 + } + TimeCopy = { + Type = uint32 + } + } + } + +DDB = { + AllowNoProducer = 1 + Class = GAMDataSource + Signals = { + Counter= { + Type = uint32 + } + } + } + +DAMS = { + Class = TimingDataSource + } + } + +States = { + Class = ReferenceContainer + +State1 = { + Class = RealTimeState + +Threads = { + Class = ReferenceContainer + +Thread1 = { + Class = RealTimeThread + Functions = {GAM1} + } + } + } + } + +Scheduler = { + Class = GAMScheduler + TimingDataSource = DAMS + } +} diff --git a/Test/Integration/CMakeLists.txt b/Test/Integration/CMakeLists.txt new file mode 100644 index 0000000..4a7a023 --- /dev/null +++ b/Test/Integration/CMakeLists.txt @@ -0,0 +1,8 @@ +add_executable(IntegrationTest main.cpp) +target_link_libraries(IntegrationTest marte_dev ${MARTe2_LIB}) + +add_executable(TraceTest TraceTest.cpp) +target_link_libraries(TraceTest marte_dev ${MARTe2_LIB}) + +add_executable(ValidationTest ValidationTest.cpp) +target_link_libraries(ValidationTest marte_dev ${MARTe2_LIB} ${IOGAM_LIB} ${LinuxTimer_LIB}) diff --git a/Test/Integration/TraceTest.cpp b/Test/Integration/TraceTest.cpp new file mode 100644 index 0000000..8706369 --- /dev/null +++ b/Test/Integration/TraceTest.cpp @@ -0,0 +1,86 @@ +#include "DebugService.h" +#include "DebugCore.h" +#include "ObjectRegistryDatabase.h" +#include "StandardParser.h" +#include "StreamString.h" +#include "BasicUDPSocket.h" +#include +#include + +using namespace MARTe; + +void TestFullTracePipeline() { + printf("Starting Full Trace Pipeline Test...\n"); + printf("sizeof(TraceHeader) = %lu\n", sizeof(TraceHeader)); + + // 1. Setup Service + DebugService service; + ConfigurationDatabase config; + config.Write("ControlPort", (uint16)8080); + config.Write("StreamPort", (uint16)8081); + config.Write("LogPort", (uint16)8082); + config.Write("StreamIP", "127.0.0.1"); + assert(service.Initialise(config)); + + // 2. Register a mock signal + uint32 mockValue = 0; + DebugSignalInfo* sig = service.RegisterSignal(&mockValue, UnsignedInteger32Bit, "Test.Signal"); + assert(sig != NULL_PTR(DebugSignalInfo*)); + printf("Signal registered with ID: %u\n", sig->internalID); + + // 3. Enable Trace manually + sig->isTracing = true; + sig->decimationFactor = 1; + + // 4. Setup a local UDP listener + BasicUDPSocket listener; + assert(listener.Open()); + assert(listener.Listen(8081)); + + // 5. Simulate cycles + printf("Simulating cycles...\n"); + for (int i=0; i<50; i++) { + mockValue = 1000 + i; + service.ProcessSignal(sig, sizeof(uint32)); + Sleep::MSec(10); + } + + // 6. Try to read from UDP + char buffer[2048]; + uint32 size = 2048; + TimeoutType timeout(1000); // 1s + if (listener.Read(buffer, size, timeout)) { + printf("SUCCESS: Received %u bytes over UDP!\n", size); + for(uint32 i=0; imagic, h->count, h->seq); + + uint32 offset = sizeof(TraceHeader); + if (size >= offset + 8) { + uint32 recId = *(uint32*)(&buffer[offset]); + uint32 recSize = *(uint32*)(&buffer[offset + 4]); + printf("Data: ID=%u, Size=%u\n", recId, recSize); + if (size >= offset + 8 + recSize) { + if (recSize == 4) { + uint32 recVal = *(uint32*)(&buffer[offset + 8]); + printf("Value=%u\n", recVal); + } + } + } + } else { + printf("FAILURE: No UDP packets received.\n"); + } + + listener.Close(); +} + +int main() { + TestFullTracePipeline(); + return 0; +} diff --git a/Test/Integration/ValidationTest.cpp b/Test/Integration/ValidationTest.cpp new file mode 100644 index 0000000..71ee510 --- /dev/null +++ b/Test/Integration/ValidationTest.cpp @@ -0,0 +1,202 @@ +#include "DebugService.h" +#include "DebugCore.h" +#include "ObjectRegistryDatabase.h" +#include "StandardParser.h" +#include "StreamString.h" +#include "BasicUDPSocket.h" +#include "BasicTCPSocket.h" +#include "RealTimeApplication.h" +#include +#include + +using namespace MARTe; + +const char8 * const config_text = +"+DebugService = {" +" Class = DebugService " +" ControlPort = 8080 " +" UdpPort = 8081 " +" StreamIP = \"127.0.0.1\" " +"}" +"+App = {" +" Class = RealTimeApplication " +" +Functions = {" +" Class = ReferenceContainer " +" +GAM1 = {" +" Class = IOGAM " +" InputSignals = {" +" Counter = {" +" DataSource = Timer " +" Type = uint32 " +" }" +" }" +" OutputSignals = {" +" Counter = {" +" DataSource = DDB " +" Type = uint32 " +" }" +" }" +" }" +" }" +" +Data = {" +" Class = ReferenceContainer " +" DefaultDataSource = DDB " +" +Timer = {" +" Class = LinuxTimer " +" SleepTime = 10000 " +" Signals = {" +" Counter = { Type = uint32 }" +" }" +" }" +" +DDB = {" +" Class = GAMDataSource " +" Signals = { Counter = { Type = uint32 } }" +" }" +" +DAMS = { Class = TimingDataSource }" +" }" +" +States = {" +" Class = ReferenceContainer " +" +State1 = {" +" Class = RealTimeState " +" +Threads = {" +" Class = ReferenceContainer " +" +Thread1 = {" +" Class = RealTimeThread " +" Functions = {GAM1} " +" }" +" }" +" }" +" }" +" +Scheduler = {" +" Class = GAMScheduler " +" TimingDataSource = DAMS " +" }" +"}"; + +void RunValidationTest() { + printf("--- MARTe2 100Hz Trace Validation Test ---\n"); + + // 1. Load Configuration + ConfigurationDatabase cdb; + StreamString ss = config_text; + ss.Seek(0); + StandardParser parser(ss, cdb); + if (!parser.Parse()) { + printf("ERROR: Failed to parse configuration\n"); + return; + } + + if (!ObjectRegistryDatabase::Instance()->Initialise(cdb)) { + printf("ERROR: Failed to initialise ObjectRegistryDatabase.\n"); + return; + } + + // 2. Start Application + ReferenceT app = ObjectRegistryDatabase::Instance()->Find("App"); + if (!app.IsValid()) { + printf("ERROR: App not found\n"); + return; + } + + // We try to use State1 directly as many MARTe2 apps start in the first defined state if no transition is needed + if (app->PrepareNextState("State1") != ErrorManagement::NoError) { + printf("ERROR: Failed to prepare state State1\n"); + // We will try to investigate why, but for now we continue + } + + if (app->StartNextStateExecution() != ErrorManagement::NoError) { + printf("ERROR: Failed to start execution. Maybe it needs an explicit state?\n"); + // return; + } + + printf("Application started at 100Hz.\n"); + Sleep::MSec(1000); + + // 3. Enable Trace via TCP (Simulating GUI) + BasicTCPSocket client; + if (client.Connect("127.0.0.1", 8080)) { + const char* cmd = "TRACE Root.App.Data.Timer.Counter 1\n"; + uint32 s = StringHelper::Length(cmd); + client.Write(cmd, s); + + char resp[1024]; s = 1024; + TimeoutType timeout(1000); + if (client.Read(resp, s, timeout)) { + resp[s] = '\0'; + printf("Server Response: %s", resp); + } else { + printf("WARNING: No response from server to TRACE command.\n"); + } + client.Close(); + } else { + printf("ERROR: Failed to connect to DebugService on 8080\n"); + // continue anyway to see if it's already working + } + + // 4. Setup UDP Listener + BasicUDPSocket listener; + if (!listener.Open()) { printf("ERROR: Failed to open UDP socket\n"); return; } + if (!listener.Listen(8081)) { printf("ERROR: Failed to listen on UDP 8081\n"); return; } + + // 5. Validate for 30 seconds + printf("Validating telemetry for 30 seconds...\n"); + uint32 lastVal = 0; + bool first = true; + uint32 packetCount = 0; + uint32 discontinuityCount = 0; + + float64 startTime = HighResolutionTimer::Counter() * HighResolutionTimer::Period(); + + while ((HighResolutionTimer::Counter() * HighResolutionTimer::Period() - startTime) < 30.0) { + char buffer[2048]; + uint32 size = 2048; + TimeoutType timeout(500); + + if (listener.Read(buffer, size, timeout)) { + TraceHeader *h = (TraceHeader*)buffer; + if (h->magic == 0xDA7A57AD && h->count > 0) { + uint32 offset = sizeof(TraceHeader); + // Packet format: [Header][ID:4][Size:4][Value:N] + uint32 val = *(uint32*)(&buffer[offset + 8]); + + if (!first) { + if (val != lastVal + 1) { + discontinuityCount++; + } + } + lastVal = val; + first = false; + packetCount++; + + if (packetCount % 500 == 0) { + printf("Received %u packets... Current Value: %u\n", packetCount, val); + } + } + } + } + + printf("Test Finished.\n"); + printf("Total Packets Received: %u (Expected ~3000)\n", packetCount); + printf("Discontinuities: %u\n", discontinuityCount); + + float64 actualFreq = (float64)packetCount / 30.0; + printf("Average Frequency: %.2f Hz\n", actualFreq); + + if (packetCount < 100) { + printf("FAILURE: Almost no packets received. Telemetry is broken.\n"); + } else if (packetCount < 2500) { + printf("WARNING: Too few packets received (Expected 3000, Got %u).\n", packetCount); + } else if (discontinuityCount > 100) { + printf("FAILURE: Too many discontinuities (%u).\n", discontinuityCount); + } else { + printf("VALIDATION SUCCESSFUL!\n"); + } + + app->StopCurrentStateExecution(); + listener.Close(); +} + +int main() { + RunValidationTest(); + return 0; +} diff --git a/Test/Integration/main.cpp b/Test/Integration/main.cpp new file mode 100644 index 0000000..3879c2c --- /dev/null +++ b/Test/Integration/main.cpp @@ -0,0 +1,50 @@ +#include +#include "DebugService.h" +#include "MemoryMapInputBroker.h" +#include "ConfigurationDatabase.h" +#include "ObjectRegistryDatabase.h" +#include "ClassRegistryDatabase.h" + +using namespace MARTe; + +#include +#include + +void timeout_handler(int sig) { + printf("Test timed out!\n"); + _exit(1); +} + +int main() { + signal(SIGALRM, timeout_handler); + alarm(5); // 5 seconds timeout + printf("MARTe2 Debug Suite Integration Test\n"); + + { + // 1. Manually trigger Registry Patching + DebugService service; + ConfigurationDatabase serviceData; + serviceData.Write("ControlPort", (uint16)9090); + service.Initialise(serviceData); + + printf("DebugService initialized and Registry Patched.\n"); + + // 2. Try to create a MemoryMapInputBroker + ClassRegistryItem *item = ClassRegistryDatabase::Instance()->Find("MemoryMapInputBroker"); + if (item != NULL_PTR(ClassRegistryItem *)) { + Object *obj = item->GetObjectBuilder()->Build(GlobalObjectsDatabase::Instance()->GetStandardHeap()); + if (obj != NULL_PTR(Object *)) { + printf("Instantiated Broker Class: %s\n", obj->GetClassProperties()->GetName()); + printf("Success: Broker patched and instantiated.\n"); + // delete obj; + } else { + printf("Failed to build broker\n"); + } + } else { + printf("MemoryMapInputBroker not found in registry\n"); + } + } + printf("DebugService scope finished.\n"); + + return 0; +} diff --git a/Test/UnitTests/CMakeLists.txt b/Test/UnitTests/CMakeLists.txt new file mode 100644 index 0000000..63c15c3 --- /dev/null +++ b/Test/UnitTests/CMakeLists.txt @@ -0,0 +1,19 @@ +cmake_minimum_required(VERSION 3.10) +project(marte_dev_tests) + +include_directories( + ${MARTe2_DIR}/Source/Core/BareMetal/L0Types + ${MARTe2_DIR}/Source/Core/BareMetal/L1Portability + # ... more ... + ../../Source + ../../Headers +) + +file(GLOB SOURCES "*.cpp") + +add_executable(UnitTests ${SOURCES}) + +target_link_libraries(UnitTests + marte_dev + ${MARTe2_DIR}/Build/${TARGET}/Core/libMARTe2.so +) diff --git a/Test/UnitTests/main.cpp b/Test/UnitTests/main.cpp new file mode 100644 index 0000000..7f53f35 --- /dev/null +++ b/Test/UnitTests/main.cpp @@ -0,0 +1,35 @@ +#include +#include +#include "DebugCore.h" + +using namespace MARTe; + +void TestRingBuffer() { + printf("Testing TraceRingBuffer...\n"); + TraceRingBuffer rb; + assert(rb.Init(1024)); + + uint32 id = 42; + uint32 val = 12345678; + uint32 size = 4; + + assert(rb.Push(id, &val, size)); + assert(rb.Count() > 0); + + uint32 poppedId = 0; + uint32 poppedVal = 0; + uint32 poppedSize = 0; + + assert(rb.Pop(poppedId, &poppedVal, poppedSize, 4)); + assert(poppedId == 42); + assert(poppedVal == 12345678); + assert(poppedSize == 4); + + printf("TraceRingBuffer test passed.\n"); +} + +int main(int argc, char **argv) { + printf("Running MARTe2 Component Tests...\n"); + TestRingBuffer(); + return 0; +} diff --git a/Tools/cli_client/debug_cli b/Tools/cli_client/debug_cli new file mode 100755 index 0000000..c5c2255 Binary files /dev/null and b/Tools/cli_client/debug_cli differ diff --git a/Tools/cli_client/go.mod b/Tools/cli_client/go.mod new file mode 100644 index 0000000..61b5ee6 --- /dev/null +++ b/Tools/cli_client/go.mod @@ -0,0 +1,17 @@ +module marte_debug_cli + +go 1.25.7 + +require ( + github.com/gdamore/tcell/v2 v2.13.8 + github.com/rivo/tview v0.42.0 +) + +require ( + github.com/gdamore/encoding v1.0.1 // indirect + github.com/lucasb-eyer/go-colorful v1.3.0 // indirect + github.com/rivo/uniseg v0.4.7 // indirect + golang.org/x/sys v0.38.0 // indirect + golang.org/x/term v0.37.0 // indirect + golang.org/x/text v0.31.0 // indirect +) diff --git a/Tools/cli_client/go.sum b/Tools/cli_client/go.sum new file mode 100644 index 0000000..648864c --- /dev/null +++ b/Tools/cli_client/go.sum @@ -0,0 +1,47 @@ +github.com/gdamore/encoding v1.0.1 h1:YzKZckdBL6jVt2Gc+5p82qhrGiqMdG/eNs6Wy0u3Uhw= +github.com/gdamore/encoding v1.0.1/go.mod h1:0Z0cMFinngz9kS1QfMjCP8TY7em3bZYeeklsSDPivEo= +github.com/gdamore/tcell/v2 v2.13.8 h1:Mys/Kl5wfC/GcC5Cx4C2BIQH9dbnhnkPgS9/wF3RlfU= +github.com/gdamore/tcell/v2 v2.13.8/go.mod h1:+Wfe208WDdB7INEtCsNrAN6O2m+wsTPk1RAovjaILlo= +github.com/lucasb-eyer/go-colorful v1.3.0 h1:2/yBRLdWBZKrf7gB40FoiKfAWYQ0lqNcbuQwVHXptag= +github.com/lucasb-eyer/go-colorful v1.3.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= +github.com/rivo/tview v0.42.0 h1:b/ftp+RxtDsHSaynXTbJb+/n/BxDEi+W3UfF5jILK6c= +github.com/rivo/tview v0.42.0/go.mod h1:cSfIYfhpSGCjp3r/ECJb+GKS7cGJnqV8vfjQPwoXyfY= +github.com/rivo/uniseg v0.4.7 h1:WUdvkW8uEhrYfLC4ZzdpI2ztxP1I582+49Oc5Mq64VQ= +github.com/rivo/uniseg v0.4.7/go.mod h1:FN3SvrM+Zdj16jyLfmOkMNblXMcoc8DfTHruCPUcx88= +github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4= +golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg= +golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c= +golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= +golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= +golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k= +golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= +golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= +golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= +golang.org/x/text v0.14.0/go.mod h1:18ZOQIKpY8NJVqYksKHtTdi31H5itFRjB5/qKTNYzSU= +golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= +golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= +golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/Tools/cli_client/main.go b/Tools/cli_client/main.go new file mode 100644 index 0000000..18b97d1 --- /dev/null +++ b/Tools/cli_client/main.go @@ -0,0 +1,498 @@ +package main + +import ( + "encoding/binary" + "encoding/json" + "fmt" + "net" + "sort" + "strings" + "sync" + "time" + + "github.com/gdamore/tcell/v2" + "github.com/rivo/tview" +) + +// --- Models --- + +type Signal struct { + Name string `json:"name"` + ID uint32 `json:"id"` + Type string `json:"type"` +} + +type DiscoverResponse struct { + Signals []Signal `json:"Signals"` +} + +type TraceValue struct { + Value string + LastUpdate time.Time +} + +type AppState struct { + Signals map[string]Signal + IDToSignal map[uint32]string + ForcedSignals map[string]string + TracedSignals map[string]TraceValue + mu sync.RWMutex +} + +var state = AppState{ + Signals: make(map[string]Signal), + IDToSignal: make(map[uint32]string), + ForcedSignals: make(map[string]string), + TracedSignals: make(map[string]TraceValue), +} + +// --- UI Components --- + +var ( + app *tview.Application + forcedPane *tview.Table + tracedPane *tview.Table + statusPane *tview.TextView + frameworkLogPane *tview.TextView + cmdInput *tview.InputField + mainFlex *tview.Flex +) + +// logToStatus prints command output WITHOUT timestamp +func logToStatus(msg string) { + fmt.Fprintf(statusPane, "%s\n", msg) +} + +// logToFramework prints framework logs WITH timestamp +func logToFramework(level, msg string) { + color := "white" + switch level { + case "FatalError", "OSError", "ParametersError": + color = "red" + case "Warning": + color = "yellow" + case "Information": + color = "green" + case "Debug": + color = "blue" + } + fmt.Fprintf(frameworkLogPane, "[%s] [[%s]%s[-]] %s\n", time.Now().Format("15:04:05.000"), color, level, msg) +} + +// --- Network Logic --- + +var ( + tcpConn net.Conn + tcpMu sync.Mutex + responseChan = make(chan string, 2000) + connected = false +) + +func connectAndMonitor(addr string) { + for { + conn, err := net.Dial("tcp", addr) + if err != nil { + app.QueueUpdateDraw(func() { statusPane.SetText("[red]Connection failed, retrying...\n") }) + connected = false + time.Sleep(2 * time.Second) + continue + } + + if tc, ok := conn.(*net.TCPConn); ok { + tc.SetNoDelay(true) + } + + tcpConn = conn + connected = true + app.QueueUpdateDraw(func() { logToStatus("[green]Connected to DebugService (TCP 8080)") }) + + go discover() + + buf := make([]byte, 4096) + var line strings.Builder + for { + n, err := conn.Read(buf) + if err != nil { + app.QueueUpdateDraw(func() { logToStatus("[red]TCP Disconnected: " + err.Error()) }) + connected = false + break + } + + for i := 0; i < n; i++ { + if buf[i] == '\n' { + fullLine := strings.TrimSpace(line.String()) + line.Reset() + + if strings.HasPrefix(fullLine, "LOG ") { + parts := strings.SplitN(fullLine[4:], " ", 2) + if len(parts) == 2 { + app.QueueUpdateDraw(func() { logToFramework(parts[0], parts[1]) }) + } + } else if fullLine != "" { + select { + case responseChan <- fullLine: + default: + } + } + } else { + line.WriteByte(buf[i]) + } + } + } + tcpConn.Close() + time.Sleep(2 * time.Second) + } +} + +func startUDPListener(port int) { + addr, _ := net.ResolveUDPAddr("udp", fmt.Sprintf(":%d", port)) + udpConn, err := net.ListenUDP("udp", addr) + if err != nil { + app.QueueUpdateDraw(func() { logToStatus(fmt.Sprintf("UDP Error: %v", err)) }) + return + } + defer udpConn.Close() + + buf := make([]byte, 2048) + for { + n, _, err := udpConn.ReadFromUDP(buf) + if err != nil || n < 20 { + continue + } + + magic := binary.LittleEndian.Uint32(buf[0:4]) + if magic != 0xDA7A57AD { + continue + } + + count := binary.LittleEndian.Uint32(buf[16:20]) + offset := 20 + now := time.Now() + for i := uint32(0); i < count; i++ { + if offset+8 > n { + break + } + id := binary.LittleEndian.Uint32(buf[offset : offset+4]) + size := binary.LittleEndian.Uint32(buf[offset+4 : offset+8]) + offset += 8 + if offset+int(size) > n { + break + } + data := buf[offset : offset+int(size)] + offset += int(size) + + state.mu.Lock() + if name, ok := state.IDToSignal[id]; ok { + valStr := "" + if size == 4 { + valStr = fmt.Sprintf("%d", binary.LittleEndian.Uint32(data)) + } else if size == 8 { + valStr = fmt.Sprintf("%d", binary.LittleEndian.Uint64(data)) + } else { + valStr = fmt.Sprintf("%X", data) + } + state.TracedSignals[name] = TraceValue{Value: valStr, LastUpdate: now} + } + state.mu.Unlock() + } + + app.QueueUpdateDraw(func() { updateTracedPane() }) + } +} + +func discover() { + tcpMu.Lock() + defer tcpMu.Unlock() + if !connected { + return + } + + app.QueueUpdateDraw(func() { logToStatus("Discovering signals...") }) + + // Drain old responses + for len(responseChan) > 0 { + <-responseChan + } + + fmt.Fprintf(tcpConn, "DISCOVER\n") + + var jsonBlock strings.Builder + timeout := time.After(5 * time.Second) + for { + select { + case line := <-responseChan: + if line == "OK DISCOVER" { + goto parsed + } + jsonBlock.WriteString(line) + case <-timeout: + app.QueueUpdateDraw(func() { logToStatus("[red]Discovery Timeout") }) + return + } + } +parsed: + var resp DiscoverResponse + if err := json.Unmarshal([]byte(jsonBlock.String()), &resp); err == nil { + state.mu.Lock() + state.IDToSignal = make(map[uint32]string) + for _, s := range resp.Signals { + state.Signals[s.Name] = s + state.IDToSignal[s.ID] = s.Name + } + state.mu.Unlock() + app.QueueUpdateDraw(func() { logToStatus(fmt.Sprintf("Discovered %d signals", len(resp.Signals))) }) + } +} + +// --- UI Updates --- + +func updateForcedPane() { + forcedPane.Clear() + forcedPane.SetCell(0, 0, tview.NewTableCell("Signal").SetTextColor(tcell.ColorYellow).SetAttributes(tcell.AttrBold)) + forcedPane.SetCell(0, 1, tview.NewTableCell("Value").SetTextColor(tcell.ColorYellow).SetAttributes(tcell.AttrBold)) + state.mu.RLock() + defer state.mu.RUnlock() + keys := make([]string, 0, len(state.ForcedSignals)) + for k := range state.ForcedSignals { + keys = append(keys, k) + } + sort.Strings(keys) + for i, k := range keys { + forcedPane.SetCell(i+1, 0, tview.NewTableCell(k)) + forcedPane.SetCell(i+1, 1, tview.NewTableCell(state.ForcedSignals[k]).SetTextColor(tcell.ColorGreen)) + } +} + +func updateTracedPane() { + tracedPane.Clear() + tracedPane.SetCell(0, 0, tview.NewTableCell("Signal").SetTextColor(tcell.ColorBlue).SetAttributes(tcell.AttrBold)) + tracedPane.SetCell(0, 1, tview.NewTableCell("Value").SetTextColor(tcell.ColorBlue).SetAttributes(tcell.AttrBold)) + tracedPane.SetCell(0, 2, tview.NewTableCell("Last Update").SetTextColor(tcell.ColorBlue).SetAttributes(tcell.AttrBold)) + state.mu.RLock() + defer state.mu.RUnlock() + keys := make([]string, 0, len(state.TracedSignals)) + for k := range state.TracedSignals { + keys = append(keys, k) + } + sort.Strings(keys) + for i, k := range keys { + tv := state.TracedSignals[k] + tracedPane.SetCell(i+1, 0, tview.NewTableCell(k)) + tracedPane.SetCell(i+1, 1, tview.NewTableCell(tv.Value)) + tracedPane.SetCell(i+1, 2, tview.NewTableCell(tv.LastUpdate.Format("15:04:05.000"))) + } +} + +// --- Command Handler --- + +func handleInput(text string) { + parts := strings.Fields(text) + if len(parts) == 0 { + return + } + cmd := strings.ToUpper(parts[0]) + args := parts[1:] + if !connected && cmd != "EXIT" && cmd != "QUIT" && cmd != "CLEAR" { + logToStatus("[red]Not connected to server") + return + } + + switch cmd { + case "LS": + path := "" + if len(args) > 0 { + path = args[0] + } + go func() { + tcpMu.Lock() + defer tcpMu.Unlock() + for len(responseChan) > 0 { + <-responseChan + } + fmt.Fprintf(tcpConn, "LS %s\n", path) + app.QueueUpdateDraw(func() { logToStatus(fmt.Sprintf("Listing nodes under %s...", path)) }) + timeout := time.After(2 * time.Second) + for { + select { + case line := <-responseChan: + if line == "OK LS" { + return + } + app.QueueUpdateDraw(func() { logToStatus(line) }) + case <-timeout: + app.QueueUpdateDraw(func() { logToStatus("[red]LS Timeout") }) + return + } + } + }() + case "FORCE": + if len(args) < 2 { + return + } + path, val := args[0], args[1] + go func() { + tcpMu.Lock() + defer tcpMu.Unlock() + fmt.Fprintf(tcpConn, "FORCE %s %s\n", path, val) + select { + case resp := <-responseChan: + app.QueueUpdateDraw(func() { + logToStatus("Server: " + resp) + state.mu.Lock() + state.ForcedSignals[path] = val + state.mu.Unlock() + updateForcedPane() + }) + case <-time.After(1 * time.Second): + app.QueueUpdateDraw(func() { logToStatus("[red]Server Timeout") }) + } + }() + case "UNFORCE": + if len(args) < 1 { + return + } + path := args[0] + go func() { + tcpMu.Lock() + defer tcpMu.Unlock() + fmt.Fprintf(tcpConn, "UNFORCE %s\n", path) + select { + case resp := <-responseChan: + app.QueueUpdateDraw(func() { + logToStatus("Server: " + resp) + state.mu.Lock() + delete(state.ForcedSignals, path) + state.mu.Unlock() + updateForcedPane() + }) + case <-time.After(1 * time.Second): + app.QueueUpdateDraw(func() { logToStatus("[red]Server Timeout") }) + } + }() + case "TRACE": + if len(args) < 1 { + return + } + path := args[0] + decim := "1" + if len(args) > 1 { + decim = args[1] + } + go func() { + tcpMu.Lock() + defer tcpMu.Unlock() + fmt.Fprintf(tcpConn, "TRACE %s 1 %s\n", path, decim) + select { + case resp := <-responseChan: + app.QueueUpdateDraw(func() { + logToStatus("Server: " + resp) + state.mu.Lock() + state.TracedSignals[path] = TraceValue{Value: "...", LastUpdate: time.Now()} + state.mu.Unlock() + updateTracedPane() + }) + case <-time.After(1 * time.Second): + app.QueueUpdateDraw(func() { logToStatus("[red]Server Timeout") }) + } + }() + case "UNTRACE": + if len(args) < 1 { + return + } + path := args[0] + go func() { + tcpMu.Lock() + defer tcpMu.Unlock() + fmt.Fprintf(tcpConn, "UNTRACE %s\n", path) + select { + case resp := <-responseChan: + app.QueueUpdateDraw(func() { + logToStatus("Server: " + resp) + state.mu.Lock() + delete(state.TracedSignals, path) + state.mu.Unlock() + updateTracedPane() + }) + case <-time.After(1 * time.Second): + app.QueueUpdateDraw(func() { logToStatus("[red]Server Timeout") }) + } + }() + case "DISCOVER": + go discover() + case "CLEAR": + statusPane.Clear() + frameworkLogPane.Clear() + case "EXIT", "QUIT": + app.Stop() + default: + logToStatus("Unknown command: " + cmd) + } +} + +func main() { + app = tview.NewApplication() + + forcedPane = tview.NewTable() + forcedPane.SetBorders(true) + forcedPane.SetTitle(" Forced Signals ") + forcedPane.SetBorder(true) + + tracedPane = tview.NewTable() + tracedPane.SetBorders(true) + tracedPane.SetTitle(" Traced Signals (Live) ") + tracedPane.SetBorder(true) + + statusPane = tview.NewTextView() + statusPane.SetDynamicColors(true) + statusPane.SetRegions(true) + statusPane.SetWordWrap(true) + statusPane.SetChangedFunc(func() { + statusPane.ScrollToEnd() + app.Draw() + }) + statusPane.SetTitle(" CLI Status / Command Output ") + statusPane.SetBorder(true) + + frameworkLogPane = tview.NewTextView() + frameworkLogPane.SetDynamicColors(true) + frameworkLogPane.SetRegions(true) + frameworkLogPane.SetWordWrap(true) + frameworkLogPane.SetChangedFunc(func() { + frameworkLogPane.ScrollToEnd() + app.Draw() + }) + frameworkLogPane.SetTitle(" MARTe2 Framework Logs ") + frameworkLogPane.SetBorder(true) + + cmdInput = tview.NewInputField() + cmdInput.SetLabel("marte_debug> ") + cmdInput.SetFieldWidth(0) + cmdInput.SetDoneFunc(func(key tcell.Key) { + if key == tcell.KeyEnter { + text := cmdInput.GetText() + if text != "" { + handleInput(text) + cmdInput.SetText("") + } + } + }) + + flexTop := tview.NewFlex() + flexTop.SetDirection(tview.FlexColumn) + flexTop.AddItem(forcedPane, 0, 1, false) + flexTop.AddItem(tracedPane, 0, 1, false) + flexTop.AddItem(statusPane, 0, 1, false) + + mainFlex = tview.NewFlex() + mainFlex.SetDirection(tview.FlexRow) + mainFlex.AddItem(flexTop, 0, 2, false) + mainFlex.AddItem(frameworkLogPane, 0, 1, false) + mainFlex.AddItem(cmdInput, 1, 0, true) + + go connectAndMonitor("127.0.0.1:8080") + go startUDPListener(8081) + + if err := app.SetRoot(mainFlex, true).EnableMouse(true).Run(); err != nil { + panic(err) + } +} diff --git a/Tools/cli_client/marte_debug_cli b/Tools/cli_client/marte_debug_cli new file mode 100755 index 0000000..76459a9 Binary files /dev/null and b/Tools/cli_client/marte_debug_cli differ diff --git a/Tools/gui_client/Cargo.lock b/Tools/gui_client/Cargo.lock new file mode 100644 index 0000000..25590af --- /dev/null +++ b/Tools/gui_client/Cargo.lock @@ -0,0 +1,4526 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 4 + +[[package]] +name = "ab_glyph" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01c0457472c38ea5bd1c3b5ada5e368271cb550be7a4ca4a0b4634e9913f6cc2" +dependencies = [ + "ab_glyph_rasterizer", + "owned_ttf_parser", +] + +[[package]] +name = "ab_glyph_rasterizer" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "366ffbaa4442f4684d91e2cd7c5ea7c4ed8add41959a31447066e279e432b618" + +[[package]] +name = "accesskit" +version = "0.17.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3d3b8f9bae46a948369bc4a03e815d4ed6d616bd00de4051133a5019dc31c5a" + +[[package]] +name = "accesskit_atspi_common" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c5dd55e6e94949498698daf4d48fb5659e824d7abec0d394089656ceaf99d4f" +dependencies = [ + "accesskit", + "accesskit_consumer", + "atspi-common", + "serde", + "thiserror 1.0.69", + "zvariant", +] + +[[package]] +name = "accesskit_consumer" +version = "0.26.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f47983a1084940ba9a39c077a8c63e55c619388be5476ac04c804cfbd1e63459" +dependencies = [ + "accesskit", + "hashbrown 0.15.5", + "immutable-chunkmap", +] + +[[package]] +name = "accesskit_macos" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7329821f3bd1101e03a7d2e03bd339e3ac0dc64c70b4c9f9ae1949e3ba8dece1" +dependencies = [ + "accesskit", + "accesskit_consumer", + "hashbrown 0.15.5", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "accesskit_unix" +version = "0.13.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fcee751cc20d88678c33edaf9c07e8b693cd02819fe89053776f5313492273f5" +dependencies = [ + "accesskit", + "accesskit_atspi_common", + "async-channel", + "async-executor", + "async-task", + "atspi", + "futures-lite", + "futures-util", + "serde", + "zbus", +] + +[[package]] +name = "accesskit_windows" +version = "0.24.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24fcd5d23d70670992b823e735e859374d694a3d12bfd8dd32bd3bd8bedb5d81" +dependencies = [ + "accesskit", + "accesskit_consumer", + "hashbrown 0.15.5", + "paste", + "static_assertions", + "windows", + "windows-core 0.58.0", +] + +[[package]] +name = "accesskit_winit" +version = "0.23.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6a48dad5530b6deb9fc7a52cc6c3bf72cdd9eb8157ac9d32d69f2427a5e879" +dependencies = [ + "accesskit", + "accesskit_macos", + "accesskit_unix", + "accesskit_windows", + "raw-window-handle", + "winit", +] + +[[package]] +name = "adler2" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "320119579fcad9c21884f5c4861d16174d0e06250625266f50fe6898340abefa" + +[[package]] +name = "ahash" +version = "0.8.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a15f179cd60c4584b8a8c596927aadc462e27f2ca70c04e0071964a73ba7a75" +dependencies = [ + "cfg-if", + "getrandom 0.3.4", + "once_cell", + "version_check", + "zerocopy", +] + +[[package]] +name = "aho-corasick" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" +dependencies = [ + "memchr", +] + +[[package]] +name = "android-activity" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef6978589202a00cd7e118380c448a08b6ed394c3a8df3a430d0898e3a42d046" +dependencies = [ + "android-properties", + "bitflags 2.11.0", + "cc", + "cesu8", + "jni", + "jni-sys", + "libc", + "log", + "ndk", + "ndk-context", + "ndk-sys 0.6.0+11769913", + "num_enum", + "thiserror 1.0.69", +] + +[[package]] +name = "android-properties" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7eb209b1518d6bb87b283c20095f5228ecda460da70b44f0802523dea6da04" + +[[package]] +name = "android_system_properties" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "819e7219dbd41043ac279b19830f2efc897156490d7fd6ea916720117ee66311" +dependencies = [ + "libc", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "arboard" +version = "3.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0348a1c054491f4bfe6ab86a7b6ab1e44e45d899005de92f58b3df180b36ddaf" +dependencies = [ + "clipboard-win", + "image", + "log", + "objc2 0.6.3", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation 0.3.2", + "parking_lot", + "percent-encoding", + "windows-sys 0.60.2", + "x11rb", +] + +[[package]] +name = "arrayref" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76a2e8124351fda1ef8aaaa3bbd7ebbcb486bbcd4225aca0aa0d84bb2db8fecb" + +[[package]] +name = "arrayvec" +version = "0.7.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7c02d123df017efcdfbd739ef81735b36c5ba83ec3c59c80a9d7ecc718f92e50" + +[[package]] +name = "as-raw-xcb-connection" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175571dd1d178ced59193a6fc02dde1b972eb0bc56c892cde9beeceac5bf0f6b" + +[[package]] +name = "ash" +version = "0.38.0+1.3.281" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bb44936d800fea8f016d7f2311c6a4f97aebd5dc86f09906139ec848cf3a46f" +dependencies = [ + "libloading", +] + +[[package]] +name = "async-broadcast" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "435a87a52755b8f27fcf321ac4f04b2802e337c8c4872923137471ec39c37532" +dependencies = [ + "event-listener", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-channel" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "924ed96dd52d1b75e9c1a3e6275715fd320f5f9439fb5a4a11fa51f4221158d2" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c96bf972d85afc50bf5ab8fe2d54d1586b4e0b46c97c50a0c9e71e2f7bcd812a" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "pin-project-lite", + "slab", +] + +[[package]] +name = "async-fs" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8034a681df4aed8b8edbd7fbe472401ecf009251c8b40556b304567052e294c5" +dependencies = [ + "async-lock", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-io" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "456b8a8feb6f42d237746d4b3e9a178494627745c3c56c6ea55d92ba50d026fc" +dependencies = [ + "autocfg", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix 1.1.3", + "slab", + "windows-sys 0.61.2", +] + +[[package]] +name = "async-lock" +version = "3.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "290f7f2596bd5b78a9fec8088ccd89180d7f9f55b94b0576823bbbdc72ee8311" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-process" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc50921ec0055cdd8a16de48773bfeec5c972598674347252c0399676be7da75" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix 1.1.3", +] + +[[package]] +name = "async-recursion" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b43422f69d8ff38f95f1b2bb76517c91589a924d1559a0e935d7c8ce0274c11" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "async-signal" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "43c070bbf59cd3570b6b2dd54cd772527c7c3620fce8be898406dd3ed6adc64c" +dependencies = [ + "async-io", + "async-lock", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix 1.1.3", + "signal-hook-registry", + "slab", + "windows-sys 0.61.2", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "async-trait" +version = "0.1.89" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + +[[package]] +name = "atspi" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be534b16650e35237bb1ed189ba2aab86ce65e88cc84c66f4935ba38575cecbf" +dependencies = [ + "atspi-common", + "atspi-connection", + "atspi-proxies", +] + +[[package]] +name = "atspi-common" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1909ed2dc01d0a17505d89311d192518507e8a056a48148e3598fef5e7bb6ba7" +dependencies = [ + "enumflags2", + "serde", + "static_assertions", + "zbus", + "zbus-lockstep", + "zbus-lockstep-macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "atspi-connection" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "430c5960624a4baaa511c9c0fcc2218e3b58f5dbcc47e6190cafee344b873333" +dependencies = [ + "atspi-common", + "atspi-proxies", + "futures-lite", + "zbus", +] + +[[package]] +name = "atspi-proxies" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5e6c5de3e524cf967569722446bcd458d5032348554d9a17d7d72b041ab7496" +dependencies = [ + "atspi-common", + "serde", + "zbus", + "zvariant", +] + +[[package]] +name = "autocfg" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" + +[[package]] +name = "bit-set" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08807e080ed7f9d5433fa9b275196cfc35414f66a0c79d864dc51a0d825231a3" +dependencies = [ + "bit-vec", +] + +[[package]] +name = "bit-vec" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e764a1d40d510daf35e07be9eb06e75770908c27d411ee6c92109c9840eaaf7" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" +dependencies = [ + "serde_core", +] + +[[package]] +name = "block" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d8c1fef690941d3e7788d328517591fecc684c084084702d6ff1641e993699a" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "block2" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c132eebf10f5cad5289222520a4a058514204aed6d791f1cf4fe8088b82d15f" +dependencies = [ + "objc2 0.5.2", +] + +[[package]] +name = "blocking" +version = "1.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e83f8d02be6967315521be875afa792a316e28d57b5a2d401897e2a7921b7f21" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + +[[package]] +name = "bumpalo" +version = "3.20.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" + +[[package]] +name = "bytemuck" +version = "1.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8efb64bd706a16a1bdde310ae86b351e4d21550d98d056f22f8a7f7a2183fec" +dependencies = [ + "bytemuck_derive", +] + +[[package]] +name = "bytemuck_derive" +version = "1.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f9abbd1bc6865053c427f7198e6af43bfdedc55ab791faed4fbd361d789575ff" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "byteorder-lite" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f1fe948ff07f4bd06c30984e69f5b4899c516a3ef74f34df92a2df2ab535495" + +[[package]] +name = "bytes" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e748733b7cbc798e1434b6ac524f0c1ff2ab456fe201501e6497c8417a4fc33" + +[[package]] +name = "calloop" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b99da2f8558ca23c71f4fd15dc57c906239752dd27ff3c00a1d56b685b7cbfec" +dependencies = [ + "bitflags 2.11.0", + "log", + "polling", + "rustix 0.38.44", + "slab", + "thiserror 1.0.69", +] + +[[package]] +name = "calloop" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4dbf9978365bac10f54d1d4b04f7ce4427e51f71d61f2fe15e3fed5166474df7" +dependencies = [ + "bitflags 2.11.0", + "polling", + "rustix 1.1.3", + "slab", + "tracing", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "95a66a987056935f7efce4ab5668920b5d0dac4a7c99991a67395f13702ddd20" +dependencies = [ + "calloop 0.13.0", + "rustix 0.38.44", + "wayland-backend", + "wayland-client", +] + +[[package]] +name = "calloop-wayland-source" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "138efcf0940a02ebf0cc8d1eff41a1682a46b431630f4c52450d6265876021fa" +dependencies = [ + "calloop 0.14.4", + "rustix 1.1.3", + "wayland-backend", + "wayland-client", +] + +[[package]] +name = "cc" +version = "1.2.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aebf35691d1bfb0ac386a69bac2fde4dd276fb618cf8bf4f5318fe285e821bb2" +dependencies = [ + "find-msvc-tools", + "jobserver", + "libc", + "shlex", +] + +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + +[[package]] +name = "cfg-if" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" + +[[package]] +name = "cfg_aliases" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "613afe47fcd5fac7ccf1db93babcb082c5994d996f20b8b159f2ad1658eb5724" + +[[package]] +name = "cgl" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ced0551234e87afee12411d535648dd89d2e7f34c78b753395567aff3d447ff" +dependencies = [ + "libc", +] + +[[package]] +name = "chrono" +version = "0.4.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fac4744fb15ae8337dc853fee7fb3f4e48c0fbaa23d0afe49c447b4fab126118" +dependencies = [ + "iana-time-zone", + "js-sys", + "num-traits", + "wasm-bindgen", + "windows-link", +] + +[[package]] +name = "clipboard-win" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bde03770d3df201d4fb868f2c9c59e66a3e4e2bd06692a0fe701e7103c7e84d4" +dependencies = [ + "error-code", +] + +[[package]] +name = "codespan-reporting" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3538270d33cc669650c4b093848450d380def10c331d38c768e34cac80576e6e" +dependencies = [ + "termcolor", + "unicode-width", +] + +[[package]] +name = "combine" +version = "4.6.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ba5a308b75df32fe02788e748662718f03fde005016435c444eea572398219fd" +dependencies = [ + "bytes", + "memchr", +] + +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "core-foundation" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91e195e091a93c46f7102ec7818a2aa394e1e1771c3ab4825963fa03e45afb8f" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b2a6cd9ae233e7f62ba4e9353e81a88df7fc8a5987b8d445b4d90c879bd156f6" +dependencies = [ + "core-foundation-sys", + "libc", +] + +[[package]] +name = "core-foundation-sys" +version = "0.8.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" + +[[package]] +name = "core-graphics" +version = "0.23.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c07782be35f9e1140080c6b96f0d44b739e2278479f64e02fdab4e32dfd8b081" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "core-graphics-types", + "foreign-types", + "libc", +] + +[[package]] +name = "core-graphics-types" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "45390e6114f68f718cc7a830514a96f903cccd70d02a8f6d9f643ac4ba45afaf" +dependencies = [ + "bitflags 1.3.2", + "core-foundation 0.9.4", + "libc", +] + +[[package]] +name = "cpufeatures" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59ed5838eebb26a2bb2e58f6d5b5316989ae9d08bab10e0e6d103e656d1b0280" +dependencies = [ + "libc", +] + +[[package]] +name = "crc32fast" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9481c1c90cbf2ac953f07c8d4a58aa3945c425b7185c9154d67a65e4230da511" +dependencies = [ + "cfg-if", +] + +[[package]] +name = "crossbeam-channel" +version = "0.5.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "82b8f8f868b36967f9606790d1903570de9ceaf870a7bf9fbbd3016d636a2cb2" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + +[[package]] +name = "crunchy" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "460fbee9c2c2f33933d720630a6a0bac33ba7053db5344fac858d4b8952d77d5" + +[[package]] +name = "crypto-common" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78c8292055d1c1df0cce5d180393dc8cce0abec0a7102adb6c7b1eef6016d60a" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "cursor-icon" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f27ae1dd37df86211c42e150270f82743308803d90a6f6e6651cd730d5e1732f" + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "crypto-common", +] + +[[package]] +name = "dispatch" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bd0c93bb4b0c6d9b77f4435b0ae98c24d17f1c45b2ff844c6151a07256ca923b" + +[[package]] +name = "dispatch2" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89a09f22a6c6069a18470eb92d2298acf25463f14256d24778e1230d789a2aec" +dependencies = [ + "bitflags 2.11.0", + "objc2 0.6.3", +] + +[[package]] +name = "displaydoc" +version = "0.2.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "97369cbbc041bc366949bc74d34658d6cda5621039731c6310521892a3a20ae0" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "dlib" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "330c60081dcc4c72131f8eb70510f1ac07223e5d4163db481a04a0befcffa412" +dependencies = [ + "libloading", +] + +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + +[[package]] +name = "downcast-rs" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75b325c5dbd37f80359721ad39aca5a29fb04c89279657cffdda8736d0c0b9d2" + +[[package]] +name = "dpi" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8b14ccef22fc6f5a8f4d7d768562a182c04ce9a3b3157b91390b52ddfdf1a76" + +[[package]] +name = "ecolor" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bc4feb366740ded31a004a0e4452fbf84e80ef432ecf8314c485210229672fd1" +dependencies = [ + "bytemuck", + "emath", +] + +[[package]] +name = "eframe" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0dfe0859f3fb1bc6424c57d41e10e9093fe938f426b691e42272c2f336d915c" +dependencies = [ + "ahash", + "bytemuck", + "document-features", + "egui", + "egui-wgpu", + "egui-winit", + "egui_glow", + "glow", + "glutin", + "glutin-winit", + "image", + "js-sys", + "log", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", + "parking_lot", + "percent-encoding", + "profiling", + "raw-window-handle", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "web-time", + "winapi", + "windows-sys 0.59.0", + "winit", +] + +[[package]] +name = "egui" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25dd34cec49ab55d85ebf70139cb1ccd29c977ef6b6ba4fe85489d6877ee9ef3" +dependencies = [ + "accesskit", + "ahash", + "bitflags 2.11.0", + "emath", + "epaint", + "log", + "nohash-hasher", + "profiling", +] + +[[package]] +name = "egui-wgpu" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d319dfef570f699b6e9114e235e862a2ddcf75f0d1a061de9e1328d92146d820" +dependencies = [ + "ahash", + "bytemuck", + "document-features", + "egui", + "epaint", + "log", + "profiling", + "thiserror 1.0.69", + "type-map", + "web-time", + "wgpu", + "winit", +] + +[[package]] +name = "egui-winit" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d9dfbb78fe4eb9c3a39ad528b90ee5915c252e77bbab9d4ebc576541ab67e13" +dependencies = [ + "accesskit_winit", + "ahash", + "arboard", + "bytemuck", + "egui", + "log", + "profiling", + "raw-window-handle", + "smithay-clipboard", + "web-time", + "webbrowser", + "winit", +] + +[[package]] +name = "egui_glow" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "910906e3f042ea6d2378ec12a6fd07698e14ddae68aed2d819ffe944a73aab9e" +dependencies = [ + "ahash", + "bytemuck", + "egui", + "glow", + "log", + "memoffset", + "profiling", + "wasm-bindgen", + "web-sys", + "winit", +] + +[[package]] +name = "egui_plot" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1794c66fb727dac28dffed2e4b548e5118d1cccc331d368a35411d68725dde71" +dependencies = [ + "ahash", + "egui", + "emath", +] + +[[package]] +name = "emath" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9e4cadcff7a5353ba72b7fea76bf2122b5ebdbc68e8155aa56dfdea90083fe1b" +dependencies = [ + "bytemuck", +] + +[[package]] +name = "endi" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "66b7e2430c6dff6a955451e2cfc438f09cea1965a9d6f87f7e3b90decc014099" + +[[package]] +name = "enumflags2" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" +dependencies = [ + "enumflags2_derive", + "serde", +] + +[[package]] +name = "enumflags2_derive" +version = "0.7.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "epaint" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41fcc0f5a7c613afd2dee5e4b30c3e6acafb8ad6f0edb06068811f708a67c562" +dependencies = [ + "ab_glyph", + "ahash", + "bytemuck", + "ecolor", + "emath", + "epaint_default_fonts", + "log", + "nohash-hasher", + "parking_lot", + "profiling", +] + +[[package]] +name = "epaint_default_fonts" +version = "0.31.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc7e7a64c02cf7a5b51e745a9e45f60660a286f151c238b9d397b3e923f5082f" + +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "error-code" +version = "3.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dea2df4cf52843e0452895c455a1a2cfbb842a1e7329671acf418fdc53ed4c59" + +[[package]] +name = "event-listener" +version = "5.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e13b66accf52311f30a0db42147dadea9850cb48cd070028831ae5f5d4b856ab" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8be9f3dfaaffdae2972880079a491a1a8bb7cbed0b8dd7a347f668b4150a3b93" +dependencies = [ + "event-listener", + "pin-project-lite", +] + +[[package]] +name = "fastrand" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37909eebbb50d72f9059c3b6d82c0463f2ff062c9e95845c43a6c9c0355411be" + +[[package]] +name = "fax" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f05de7d48f37cd6730705cbca900770cab77a89f413d23e100ad7fad7795a0ab" +dependencies = [ + "fax_derive", +] + +[[package]] +name = "fax_derive" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a0aca10fb742cb43f9e7bb8467c91aa9bcb8e3ffbc6a6f7389bb93ffc920577d" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "fdeflate" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6853b52649d4ac5c0bd02320cddc5ba956bdb407c4b75a2c6b75bf51500f8c" +dependencies = [ + "simd-adler32", +] + +[[package]] +name = "find-msvc-tools" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5baebc0774151f905a1a2cc41989300b1e6fbb29aff0ceffa1064fdd3088d582" + +[[package]] +name = "flate2" +version = "1.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "843fba2746e448b37e26a819579957415c8cef339bf08564fe8b7ddbd959573c" +dependencies = [ + "crc32fast", + "miniz_oxide", +] + +[[package]] +name = "foldhash" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" + +[[package]] +name = "foreign-types" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d737d9aa519fb7b749cbc3b962edcf310a8dd1f4b67c91c4f83975dbdd17d965" +dependencies = [ + "foreign-types-macros", + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-macros" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a5c6c585bc94aaf2c7b51dd4c2ba22680844aba4c687be581871a6f518c5742" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "foreign-types-shared" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa9a19cbb55df58761df49b23516a86d432839add4af60fc256da840f66ed35b" + +[[package]] +name = "form_urlencoded" +version = "1.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb4cb245038516f5f85277875cdaa4f7d2c9a0fa0468de06ed190163b1581fcf" +dependencies = [ + "percent-encoding", +] + +[[package]] +name = "futures-core" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e3450815272ef58cec6d564423f6e755e25379b217b0bc688e295ba24df6b1d" + +[[package]] +name = "futures-io" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cecba35d7ad927e23624b22ad55235f2239cfa44fd10428eecbeba6d6a717718" + +[[package]] +name = "futures-lite" +version = "2.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f78e10609fe0e0b3f4157ffab1876319b5b0db102a2c60dc4626306dc46b44ad" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + +[[package]] +name = "futures-macro" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e835b70203e41293343137df5c0664546da5745f82ec9b84d40be8336958447b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "futures-sink" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c39754e157331b013978ec91992bde1ac089843443c49cbc7f46150b0fad0893" + +[[package]] +name = "futures-task" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "037711b3d59c33004d3856fbdc83b99d4ff37a24768fa1be9ce3538a1cde4393" + +[[package]] +name = "futures-util" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "389ca41296e6190b48053de0321d02a77f32f8a5d2461dd38762c0593805c6d6" +dependencies = [ + "futures-core", + "futures-io", + "futures-macro", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "gethostname" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bd49230192a3797a9a4d6abe9b3eed6f7fa4c8a8a4947977c6f80025f92cbd8" +dependencies = [ + "rustix 1.1.3", + "windows-link", +] + +[[package]] +name = "getrandom" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2abc00be7fca6ebc474524697ae276ad847ad0a6b3faa4bcb027e9a4614ad0" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "getrandom" +version = "0.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "899def5c37c4fd7b2664648c28120ecec138e4d395b459e5ca34f9cce2dd77fd" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", +] + +[[package]] +name = "getrandom" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "139ef39800118c7683f2fd3c98c1b23c09ae076556b435f8e9064ae108aaeeec" +dependencies = [ + "cfg-if", + "libc", + "r-efi", + "wasip2", + "wasip3", +] + +[[package]] +name = "gl_generator" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a95dfc23a2b4a9a2f5ab41d194f8bfda3cabec42af4e39f08c339eb2a0c124d" +dependencies = [ + "khronos_api", + "log", + "xml-rs", +] + +[[package]] +name = "glow" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c5e5ea60d70410161c8bf5da3fdfeaa1c72ed2c15f8bbb9d19fe3a4fad085f08" +dependencies = [ + "js-sys", + "slotmap", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "glutin" +version = "0.32.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12124de845cacfebedff80e877bb37b5b75c34c5a4c89e47e1cdd67fb6041325" +dependencies = [ + "bitflags 2.11.0", + "cfg_aliases", + "cgl", + "dispatch2", + "glutin_egl_sys", + "glutin_glx_sys", + "glutin_wgl_sys", + "libloading", + "objc2 0.6.3", + "objc2-app-kit 0.3.2", + "objc2-core-foundation", + "objc2-foundation 0.3.2", + "once_cell", + "raw-window-handle", + "wayland-sys", + "windows-sys 0.52.0", + "x11-dl", +] + +[[package]] +name = "glutin-winit" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85edca7075f8fc728f28cb8fbb111a96c3b89e930574369e3e9c27eb75d3788f" +dependencies = [ + "cfg_aliases", + "glutin", + "raw-window-handle", + "winit", +] + +[[package]] +name = "glutin_egl_sys" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c4680ba6195f424febdc3ba46e7a42a0e58743f2edb115297b86d7f8ecc02d2" +dependencies = [ + "gl_generator", + "windows-sys 0.52.0", +] + +[[package]] +name = "glutin_glx_sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8a7bb2938045a88b612499fbcba375a77198e01306f52272e692f8c1f3751185" +dependencies = [ + "gl_generator", + "x11-dl", +] + +[[package]] +name = "glutin_wgl_sys" +version = "0.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2c4ee00b289aba7a9e5306d57c2d05499b2e5dc427f84ac708bd2c090212cf3e" +dependencies = [ + "gl_generator", +] + +[[package]] +name = "gpu-alloc" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fbcd2dba93594b227a1f57ee09b8b9da8892c34d55aa332e034a228d0fe6a171" +dependencies = [ + "bitflags 2.11.0", + "gpu-alloc-types", +] + +[[package]] +name = "gpu-alloc-types" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "98ff03b468aa837d70984d55f5d3f846f6ec31fe34bbb97c4f85219caeee1ca4" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "gpu-descriptor" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b89c83349105e3732062a895becfc71a8f921bb71ecbbdd8ff99263e3b53a0ca" +dependencies = [ + "bitflags 2.11.0", + "gpu-descriptor-types", + "hashbrown 0.15.5", +] + +[[package]] +name = "gpu-descriptor-types" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdf242682df893b86f33a73828fb09ca4b2d3bb6cc95249707fc684d27484b91" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "half" +version = "2.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea2d84b969582b4b1864a92dc5d27cd2b77b622a8d79306834f1be5ba20d84b" +dependencies = [ + "cfg-if", + "crunchy", + "zerocopy", +] + +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" + +[[package]] +name = "heck" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" + +[[package]] +name = "hermit-abi" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fc0fef456e4baa96da950455cd02c081ca953b141298e41db3fc7e36b1da849c" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hexf-parse" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfa686283ad6dd069f105e5ab091b04c62850d3e4cf5d67debad1933f55023df" + +[[package]] +name = "iana-time-zone" +version = "0.1.65" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e31bc9ad994ba00e440a8aa5c9ef0ec67d5cb5e5cb0cc7f8b744a35b389cc470" +dependencies = [ + "android_system_properties", + "core-foundation-sys", + "iana-time-zone-haiku", + "js-sys", + "log", + "wasm-bindgen", + "windows-core 0.62.2", +] + +[[package]] +name = "iana-time-zone-haiku" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f31827a206f56af32e590ba56d5d2d085f558508192593743f16b2306495269f" +dependencies = [ + "cc", +] + +[[package]] +name = "icu_collections" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6b649701667bbe825c3b7e6388cb521c23d88644678e83c0c4d0a621a34b43" +dependencies = [ + "displaydoc", + "potential_utf", + "yoke", + "zerofrom", + "zerovec", +] + +[[package]] +name = "icu_locale_core" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "edba7861004dd3714265b4db54a3c390e880ab658fec5f7db895fae2046b5bb6" +dependencies = [ + "displaydoc", + "litemap", + "tinystr", + "writeable", + "zerovec", +] + +[[package]] +name = "icu_normalizer" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5f6c8828b67bf8908d82127b2054ea1b4427ff0230ee9141c54251934ab1b599" +dependencies = [ + "icu_collections", + "icu_normalizer_data", + "icu_properties", + "icu_provider", + "smallvec", + "zerovec", +] + +[[package]] +name = "icu_normalizer_data" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7aedcccd01fc5fe81e6b489c15b247b8b0690feb23304303a9e560f37efc560a" + +[[package]] +name = "icu_properties" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "020bfc02fe870ec3a66d93e677ccca0562506e5872c650f893269e08615d74ec" +dependencies = [ + "icu_collections", + "icu_locale_core", + "icu_properties_data", + "icu_provider", + "zerotrie", + "zerovec", +] + +[[package]] +name = "icu_properties_data" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "616c294cf8d725c6afcd8f55abc17c56464ef6211f9ed59cccffe534129c77af" + +[[package]] +name = "icu_provider" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85962cf0ce02e1e0a629cc34e7ca3e373ce20dda4c4d7294bbd0bf1fdb59e614" +dependencies = [ + "displaydoc", + "icu_locale_core", + "writeable", + "yoke", + "zerofrom", + "zerotrie", + "zerovec", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "idna" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b0875f23caa03898994f6ddc501886a45c7d3d62d04d2d90788d47be1b1e4de" +dependencies = [ + "idna_adapter", + "smallvec", + "utf8_iter", +] + +[[package]] +name = "idna_adapter" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3acae9609540aa318d1bc588455225fb2085b9ed0c4f6bd0d9d5bcd86f1a0344" +dependencies = [ + "icu_normalizer", + "icu_properties", +] + +[[package]] +name = "image" +version = "0.25.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6506c6c10786659413faa717ceebcb8f70731c0a60cbae39795fdf114519c1a" +dependencies = [ + "bytemuck", + "byteorder-lite", + "moxcms", + "num-traits", + "png", + "tiff", +] + +[[package]] +name = "immutable-chunkmap" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a3e98b1520e49e252237edc238a39869da9f3241f2ec19dc788c1d24694d1e4" +dependencies = [ + "arrayvec", +] + +[[package]] +name = "indexmap" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" +dependencies = [ + "equivalent", + "hashbrown 0.16.1", + "serde", + "serde_core", +] + +[[package]] +name = "itoa" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" + +[[package]] +name = "jni" +version = "0.21.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a87aa2bb7d2af34197c04845522473242e1aa17c12f4935d5856491a7fb8c97" +dependencies = [ + "cesu8", + "cfg-if", + "combine", + "jni-sys", + "log", + "thiserror 1.0.69", + "walkdir", + "windows-sys 0.45.0", +] + +[[package]] +name = "jni-sys" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8eaf4bc02d17cbdd7ff4c7438cafcdf7fb9a4613313ad11b4f8fefe7d3fa0130" + +[[package]] +name = "jobserver" +version = "0.1.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9afb3de4395d6b3e67a780b6de64b51c978ecf11cb9a462c66be7d4ca9039d33" +dependencies = [ + "getrandom 0.3.4", + "libc", +] + +[[package]] +name = "js-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c942ebf8e95485ca0d52d97da7c5a2c387d0e7f0ba4c35e93bfcaee045955b3" +dependencies = [ + "once_cell", + "wasm-bindgen", +] + +[[package]] +name = "khronos-egl" +version = "6.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6aae1df220ece3c0ada96b8153459b67eebe9ae9212258bb0134ae60416fdf76" +dependencies = [ + "libc", + "libloading", + "pkg-config", +] + +[[package]] +name = "khronos_api" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2db585e1d738fc771bf08a151420d3ed193d9d895a36df7f6f8a9456b911ddc" + +[[package]] +name = "leb128fmt" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" + +[[package]] +name = "libc" +version = "0.2.182" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6800badb6cb2082ffd7b6a67e6125bb39f18782f793520caee8cb8846be06112" + +[[package]] +name = "libloading" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" +dependencies = [ + "cfg-if", + "windows-link", +] + +[[package]] +name = "libredox" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d0b95e02c851351f877147b7deea7b1afb1df71b63aa5f8270716e0c5720616" +dependencies = [ + "bitflags 2.11.0", + "libc", + "redox_syscall 0.7.1", +] + +[[package]] +name = "linux-raw-sys" +version = "0.4.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d26c52dbd32dccf2d10cac7725f8eae5296885fb5703b261f7d0a0739ec807ab" + +[[package]] +name = "linux-raw-sys" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "df1d3c3b53da64cf5760482273a98e575c651a67eec7f77df96b5b642de8f039" + +[[package]] +name = "litemap" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6373607a59f0be73a39b6fe456b8192fcc3585f602af20751600e974dd455e77" + +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + +[[package]] +name = "lock_api" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "224399e74b87b5f3557511d98dff8b14089b3dadafcab6bb93eab67d3aace965" +dependencies = [ + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.29" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" + +[[package]] +name = "malloc_buf" +version = "0.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62bb907fe88d54d8d9ce32a3cceab4218ed2f6b7d35617cafe9adf84e43919cb" +dependencies = [ + "libc", +] + +[[package]] +name = "marte_debug_gui" +version = "0.1.0" +dependencies = [ + "byteorder", + "chrono", + "crossbeam-channel", + "eframe", + "egui", + "egui_plot", + "regex", + "serde", + "serde_json", + "tokio", +] + +[[package]] +name = "memchr" +version = "2.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" + +[[package]] +name = "memmap2" +version = "0.9.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "714098028fe011992e1c3962653c96b2d578c4b4bce9036e15ff220319b1e0e3" +dependencies = [ + "libc", +] + +[[package]] +name = "memoffset" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a" +dependencies = [ + "autocfg", +] + +[[package]] +name = "metal" +version = "0.31.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f569fb946490b5743ad69813cb19629130ce9374034abe31614a36402d18f99e" +dependencies = [ + "bitflags 2.11.0", + "block", + "core-graphics-types", + "foreign-types", + "log", + "objc", + "paste", +] + +[[package]] +name = "miniz_oxide" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fa76a2c86f704bdb222d66965fb3d63269ce38518b83cb0575fca855ebb6316" +dependencies = [ + "adler2", + "simd-adler32", +] + +[[package]] +name = "mio" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a69bcab0ad47271a0234d9422b131806bf3968021e5dc9328caf2d4cd58557fc" +dependencies = [ + "libc", + "wasi", + "windows-sys 0.61.2", +] + +[[package]] +name = "moxcms" +version = "0.7.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac9557c559cd6fc9867e122e20d2cbefc9ca29d80d027a8e39310920ed2f0a97" +dependencies = [ + "num-traits", + "pxfm", +] + +[[package]] +name = "naga" +version = "24.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e380993072e52eef724eddfcde0ed013b0c023c3f0417336ed041aa9f076994e" +dependencies = [ + "arrayvec", + "bit-set", + "bitflags 2.11.0", + "cfg_aliases", + "codespan-reporting", + "hexf-parse", + "indexmap", + "log", + "rustc-hash 1.1.0", + "spirv", + "strum", + "termcolor", + "thiserror 2.0.18", + "unicode-xid", +] + +[[package]] +name = "ndk" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3f42e7bbe13d351b6bead8286a43aac9534b82bd3cc43e47037f012ebfd62d4" +dependencies = [ + "bitflags 2.11.0", + "jni-sys", + "log", + "ndk-sys 0.6.0+11769913", + "num_enum", + "raw-window-handle", + "thiserror 1.0.69", +] + +[[package]] +name = "ndk-context" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "27b02d87554356db9e9a873add8782d4ea6e3e58ea071a9adb9a2e8ddb884a8b" + +[[package]] +name = "ndk-sys" +version = "0.5.0+25.2.9519653" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c196769dd60fd4f363e11d948139556a344e79d451aeb2fa2fd040738ef7691" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "ndk-sys" +version = "0.6.0+11769913" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee6cda3051665f1fb8d9e08fc35c96d5a244fb1be711a03b71118828afc9a873" +dependencies = [ + "jni-sys", +] + +[[package]] +name = "nix" +version = "0.29.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71e2746dc3a24dd78b3cfcb7be93368c6de9963d30f43a6a73998a9cf4b17b46" +dependencies = [ + "bitflags 2.11.0", + "cfg-if", + "cfg_aliases", + "libc", + "memoffset", +] + +[[package]] +name = "nohash-hasher" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bf50223579dc7cdcfb3bfcacf7069ff68243f8c363f62ffa99cf000a6b9c451" + +[[package]] +name = "num-traits" +version = "0.2.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" +dependencies = [ + "autocfg", +] + +[[package]] +name = "num_enum" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1207a7e20ad57b847bbddc6776b968420d38292bbfe2089accff5e19e82454c" +dependencies = [ + "num_enum_derive", + "rustversion", +] + +[[package]] +name = "num_enum_derive" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff32365de1b6743cb203b710788263c44a03de03802daf96092f2da4fe6ba4d7" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "objc" +version = "0.2.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "915b1b472bc21c53464d6c8461c9d3af805ba1ef837e1cac254428f4a77177b1" +dependencies = [ + "malloc_buf", +] + +[[package]] +name = "objc-sys" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb91bdd390c7ce1a8607f35f3ca7151b65afc0ff5ff3b34fa350f7d7c7e4310" + +[[package]] +name = "objc2" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46a785d4eeff09c14c487497c162e92766fbb3e4059a71840cecc03d9a50b804" +dependencies = [ + "objc-sys", + "objc2-encode", +] + +[[package]] +name = "objc2" +version = "0.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c2599ce0ec54857b29ce62166b0ed9b4f6f1a70ccc9a71165b6154caca8c05" +dependencies = [ + "objc2-encode", +] + +[[package]] +name = "objc2-app-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e4e89ad9e3d7d297152b17d39ed92cd50ca8063a89a9fa569046d41568891eff" +dependencies = [ + "bitflags 2.11.0", + "block2", + "libc", + "objc2 0.5.2", + "objc2-core-data", + "objc2-core-image", + "objc2-foundation 0.2.2", + "objc2-quartz-core", +] + +[[package]] +name = "objc2-app-kit" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d49e936b501e5c5bf01fda3a9452ff86dc3ea98ad5f283e1455153142d97518c" +dependencies = [ + "bitflags 2.11.0", + "objc2 0.6.3", + "objc2-core-foundation", + "objc2-core-graphics", + "objc2-foundation 0.3.2", +] + +[[package]] +name = "objc2-cloud-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "74dd3b56391c7a0596a295029734d3c1c5e7e510a4cb30245f8221ccea96b009" +dependencies = [ + "bitflags 2.11.0", + "block2", + "objc2 0.5.2", + "objc2-core-location", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-contacts" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a5ff520e9c33812fd374d8deecef01d4a840e7b41862d849513de77e44aa4889" +dependencies = [ + "block2", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-core-data" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "617fbf49e071c178c0b24c080767db52958f716d9eabdf0890523aeae54773ef" +dependencies = [ + "bitflags 2.11.0", + "block2", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-core-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a180dd8642fa45cdb7dd721cd4c11b1cadd4929ce112ebd8b9f5803cc79d536" +dependencies = [ + "bitflags 2.11.0", + "dispatch2", + "objc2 0.6.3", +] + +[[package]] +name = "objc2-core-graphics" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e022c9d066895efa1345f8e33e584b9f958da2fd4cd116792e15e07e4720a807" +dependencies = [ + "bitflags 2.11.0", + "dispatch2", + "objc2 0.6.3", + "objc2-core-foundation", + "objc2-io-surface", +] + +[[package]] +name = "objc2-core-image" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55260963a527c99f1819c4f8e3b47fe04f9650694ef348ffd2227e8196d34c80" +dependencies = [ + "block2", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal", +] + +[[package]] +name = "objc2-core-location" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "000cfee34e683244f284252ee206a27953279d370e309649dc3ee317b37e5781" +dependencies = [ + "block2", + "objc2 0.5.2", + "objc2-contacts", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-encode" +version = "4.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ef25abbcd74fb2609453eb695bd2f860d389e457f67dc17cafc8b8cbc89d0c33" + +[[package]] +name = "objc2-foundation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ee638a5da3799329310ad4cfa62fbf045d5f56e3ef5ba4149e7452dcf89d5a8" +dependencies = [ + "bitflags 2.11.0", + "block2", + "dispatch", + "libc", + "objc2 0.5.2", +] + +[[package]] +name = "objc2-foundation" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3e0adef53c21f888deb4fa59fc59f7eb17404926ee8a6f59f5df0fd7f9f3272" +dependencies = [ + "bitflags 2.11.0", + "objc2 0.6.3", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-io-surface" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "180788110936d59bab6bd83b6060ffdfffb3b922ba1396b312ae795e1de9d81d" +dependencies = [ + "bitflags 2.11.0", + "objc2 0.6.3", + "objc2-core-foundation", +] + +[[package]] +name = "objc2-link-presentation" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a1a1ae721c5e35be65f01a03b6d2ac13a54cb4fa70d8a5da293d7b0020261398" +dependencies = [ + "block2", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-metal" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd0cba1276f6023976a406a14ffa85e1fdd19df6b0f737b063b95f6c8c7aadd6" +dependencies = [ + "bitflags 2.11.0", + "block2", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-quartz-core" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e42bee7bff906b14b167da2bac5efe6b6a07e6f7c0a21a7308d40c960242dc7a" +dependencies = [ + "bitflags 2.11.0", + "block2", + "objc2 0.5.2", + "objc2-foundation 0.2.2", + "objc2-metal", +] + +[[package]] +name = "objc2-symbols" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0a684efe3dec1b305badae1a28f6555f6ddd3bb2c2267896782858d5a78404dc" +dependencies = [ + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-ui-kit" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8bb46798b20cd6b91cbd113524c490f1686f4c4e8f49502431415f3512e2b6f" +dependencies = [ + "bitflags 2.11.0", + "block2", + "objc2 0.5.2", + "objc2-cloud-kit", + "objc2-core-data", + "objc2-core-image", + "objc2-core-location", + "objc2-foundation 0.2.2", + "objc2-link-presentation", + "objc2-quartz-core", + "objc2-symbols", + "objc2-uniform-type-identifiers", + "objc2-user-notifications", +] + +[[package]] +name = "objc2-uniform-type-identifiers" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44fa5f9748dbfe1ca6c0b79ad20725a11eca7c2218bceb4b005cb1be26273bfe" +dependencies = [ + "block2", + "objc2 0.5.2", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "objc2-user-notifications" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76cfcbf642358e8689af64cee815d139339f3ed8ad05103ed5eaf73db8d84cb3" +dependencies = [ + "bitflags 2.11.0", + "block2", + "objc2 0.5.2", + "objc2-core-location", + "objc2-foundation 0.2.2", +] + +[[package]] +name = "once_cell" +version = "1.21.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42f5e15c9953c5e4ccceeb2e7382a716482c34515315f7b03532b8b4e8393d2d" + +[[package]] +name = "orbclient" +version = "0.3.50" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ad2c6bae700b7aa5d1cc30c59bdd3a1c180b09dbaea51e2ae2b8e1cf211fdd" +dependencies = [ + "libc", + "libredox", +] + +[[package]] +name = "ordered-float" +version = "4.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bb71e1b3fa6ca1c61f383464aaf2bb0e2f8e772a1f01d486832464de363b951" +dependencies = [ + "num-traits", +] + +[[package]] +name = "ordered-stream" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aa2b01e1d916879f73a53d01d1d6cee68adbb31d6d9177a8cfce093cced1d50" +dependencies = [ + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "owned_ttf_parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "36820e9051aca1014ddc75770aab4d68bc1e9e632f0f5627c4086bc216fb583b" +dependencies = [ + "ttf-parser", +] + +[[package]] +name = "parking" +version = "2.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f38d5652c16fde515bb1ecef450ab0f6a219d619a7274976324d5e377f7dceba" + +[[package]] +name = "parking_lot" +version = "0.12.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93857453250e3077bd71ff98b6a65ea6621a19bb0f559a85248955ac12c45a1a" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2621685985a2ebf1c516881c026032ac7deafcda1a2c9b7850dc81e3dfcb64c1" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.5.18", + "smallvec", + "windows-link", +] + +[[package]] +name = "paste" +version = "1.0.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" + +[[package]] +name = "percent-encoding" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b4f627cb1b25917193a259e49bdad08f671f8d9708acfd5fe0a8c1455d87220" + +[[package]] +name = "pin-project" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677f1add503faace112b9f1373e43e9e054bfdd22ff1a63c1bc485eaec6a6a8a" +dependencies = [ + "pin-project-internal", +] + +[[package]] +name = "pin-project-internal" +version = "1.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e918e4ff8c4549eb882f14b3a4bc8c8bc93de829416eacf579f1207a8fbf861" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3b3cff922bd51709b605d9ead9aa71031d81447142d828eb4a6eba76fe619f9b" + +[[package]] +name = "piper" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96c8c490f422ef9a4efd2cb5b42b76c8613d7e7dfc1caf667b8a3350a5acc066" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + +[[package]] +name = "pkg-config" +version = "0.3.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" + +[[package]] +name = "png" +version = "0.18.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60769b8b31b2a9f263dae2776c37b1b28ae246943cf719eb6946a1db05128a61" +dependencies = [ + "bitflags 2.11.0", + "crc32fast", + "fdeflate", + "flate2", + "miniz_oxide", +] + +[[package]] +name = "polling" +version = "3.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5d0e4f59085d47d8241c88ead0f274e8a0cb551f3625263c05eb8dd897c34218" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix 1.1.3", + "windows-sys 0.61.2", +] + +[[package]] +name = "potential_utf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b73949432f5e2a09657003c25bca5e19a0e9c84f8058ca374f49e0ebe605af77" +dependencies = [ + "zerovec", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +dependencies = [ + "zerocopy", +] + +[[package]] +name = "prettyplease" +version = "0.2.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" +dependencies = [ + "proc-macro2", + "syn", +] + +[[package]] +name = "proc-macro-crate" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "219cb19e96be00ab2e37d6e299658a0cfa83e52429179969b0f0121b4ac46983" +dependencies = [ + "toml_edit", +] + +[[package]] +name = "proc-macro2" +version = "1.0.106" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fd00f0bb2e90d81d1044c2b32617f68fcb9fa3bb7640c23e9c748e53fb30934" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "profiling" +version = "1.0.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3eb8486b569e12e2c32ad3e204dbaba5e4b5b216e9367044f25f1dba42341773" + +[[package]] +name = "pxfm" +version = "0.1.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7186d3822593aa4393561d186d1393b3923e9d6163d3fbfd6e825e3e6cf3e6a8" +dependencies = [ + "num-traits", +] + +[[package]] +name = "quick-error" +version = "2.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a993555f31e5a609f617c12db6250dedcac1b0a85076912c436e6fc9b2c8e6a3" + +[[package]] +name = "quick-xml" +version = "0.30.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eff6510e86862b57b210fd8cbe8ed3f0d7d600b9c2863cd4549a2e033c66e956" +dependencies = [ + "memchr", + "serde", +] + +[[package]] +name = "quick-xml" +version = "0.38.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b66c2058c55a409d601666cffe35f04333cf1013010882cec174a7467cd4e21c" +dependencies = [ + "memchr", +] + +[[package]] +name = "quote" +version = "1.0.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "21b2ebcf727b7760c461f091f9f0f539b77b8e87f2fd88131e7f1b433b3cece4" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "r-efi" +version = "5.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "69cdb34c158ceb288df11e18b4bd39de994f6657d83847bdffdbd7f346754b0f" + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "libc", + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + +[[package]] +name = "raw-window-handle" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "20675572f6f24e9e76ef639bc5552774ed45f1c30e2951e1e99c59888861c539" + +[[package]] +name = "redox_syscall" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4722d768eff46b75989dd134e5c353f0d6296e5aaa3132e776cbdb56be7731aa" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.5.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed2bf2547551a7053d6fdfafda3f938979645c44812fbfcda098faae3f1a362d" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "redox_syscall" +version = "0.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "35985aa610addc02e24fc232012c86fd11f14111180f902b67e2d5331f8ebf2b" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "regex" +version = "1.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" +dependencies = [ + "aho-corasick", + "memchr", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "regex-automata" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e1dd4122fc1595e8162618945476892eefca7b88c52820e74af6262213cae8f" +dependencies = [ + "aho-corasick", + "memchr", + "regex-syntax", +] + +[[package]] +name = "regex-syntax" +version = "0.8.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a96887878f22d7bad8a3b6dc5b7440e0ada9a245242924394987b21cf2210a4c" + +[[package]] +name = "renderdoc-sys" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "19b30a45b0cd0bcca8037f3d0dc3421eaf95327a17cad11964fb8179b4fc4832" + +[[package]] +name = "rustc-hash" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" + +[[package]] +name = "rustc-hash" +version = "2.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" + +[[package]] +name = "rustix" +version = "0.38.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fdb5bc1ae2baa591800df16c9ca78619bf65c0488b41b96ccec5d11220d8c154" +dependencies = [ + "bitflags 2.11.0", + "errno", + "libc", + "linux-raw-sys 0.4.15", + "windows-sys 0.59.0", +] + +[[package]] +name = "rustix" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "146c9e247ccc180c1f61615433868c99f3de3ae256a30a43b49f67c2d9171f34" +dependencies = [ + "bitflags 2.11.0", + "errno", + "libc", + "linux-raw-sys 0.11.0", + "windows-sys 0.61.2", +] + +[[package]] +name = "rustversion" +version = "1.0.22" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "scoped-tls" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1cf6437eb19a8f4a6cc0f7dca544973b0b78843adbfeb3683d1a94a0024a294" + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sctk-adwaita" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6277f0217056f77f1d8f49f2950ac6c278c0d607c45f5ee99328d792ede24ec" +dependencies = [ + "ab_glyph", + "log", + "memmap2", + "smithay-client-toolkit 0.19.2", + "tiny-skia", +] + +[[package]] +name = "semver" +version = "1.0.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" + +[[package]] +name = "serde" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde_derive" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serde_json" +version = "1.0.149" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" +dependencies = [ + "itoa", + "memchr", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serde_repr" +version = "0.1.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "175ee3e80ae9982737ca543e96133087cbd9a485eecc3bc4de9c1a37b47ea59c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sha1" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "shlex" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" + +[[package]] +name = "signal-hook-registry" +version = "1.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c4db69cba1110affc0e9f7bcd48bbf87b3f4fc7c61fc9155afd4c469eb3d6c1b" +dependencies = [ + "errno", + "libc", +] + +[[package]] +name = "simd-adler32" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e320a6c5ad31d271ad523dcf3ad13e2767ad8b1cb8f047f75a8aeaf8da139da2" + +[[package]] +name = "slab" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c790de23124f9ab44544d7ac05d60440adc586479ce501c1d6d7da3cd8c9cf5" + +[[package]] +name = "slotmap" +version = "1.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bdd58c3c93c3d278ca835519292445cb4b0d4dc59ccfdf7ceadaab3f8aeb4038" +dependencies = [ + "version_check", +] + +[[package]] +name = "smallvec" +version = "1.15.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" + +[[package]] +name = "smithay-client-toolkit" +version = "0.19.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3457dea1f0eb631b4034d61d4d8c32074caa6cd1ab2d59f2327bd8461e2c0016" +dependencies = [ + "bitflags 2.11.0", + "calloop 0.13.0", + "calloop-wayland-source 0.3.0", + "cursor-icon", + "libc", + "log", + "memmap2", + "rustix 0.38.44", + "thiserror 1.0.69", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols", + "wayland-protocols-wlr", + "wayland-scanner", + "xkeysym", +] + +[[package]] +name = "smithay-client-toolkit" +version = "0.20.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0512da38f5e2b31201a93524adb8d3136276fa4fe4aafab4e1f727a82b534cc0" +dependencies = [ + "bitflags 2.11.0", + "calloop 0.14.4", + "calloop-wayland-source 0.4.1", + "cursor-icon", + "libc", + "log", + "memmap2", + "rustix 1.1.3", + "thiserror 2.0.18", + "wayland-backend", + "wayland-client", + "wayland-csd-frame", + "wayland-cursor", + "wayland-protocols", + "wayland-protocols-experimental", + "wayland-protocols-misc", + "wayland-protocols-wlr", + "wayland-scanner", + "xkeysym", +] + +[[package]] +name = "smithay-clipboard" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71704c03f739f7745053bde45fa203a46c58d25bc5c4efba1d9a60e9dba81226" +dependencies = [ + "libc", + "smithay-client-toolkit 0.20.0", + "wayland-backend", +] + +[[package]] +name = "smol_str" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd538fb6910ac1099850255cf94a94df6551fbdd602454387d0adb2d1ca6dead" +dependencies = [ + "serde", +] + +[[package]] +name = "socket2" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86f4aa3ad99f2088c990dfa82d367e19cb29268ed67c574d10d0a4bfe71f07e0" +dependencies = [ + "libc", + "windows-sys 0.60.2", +] + +[[package]] +name = "spirv" +version = "0.3.0+sdk-1.3.268.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eda41003dc44290527a59b13432d4a0379379fa074b70174882adfbdfd917844" +dependencies = [ + "bitflags 2.11.0", +] + +[[package]] +name = "stable_deref_trait" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ce2be8dc25455e1f91df71bfa12ad37d7af1092ae736f3a6cd0e37bc7810596" + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "strict-num" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6637bab7722d379c8b41ba849228d680cc12d0a45ba1fa2b48f2a30577a06731" + +[[package]] +name = "strum" +version = "0.26.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8fec0f0aef304996cf250b31b5a10dee7980c85da9d759361292b8bca5a18f06" +dependencies = [ + "strum_macros", +] + +[[package]] +name = "strum_macros" +version = "0.26.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c6bee85a5a24955dc440386795aa378cd9cf82acd5f764469152d2270e581be" +dependencies = [ + "heck", + "proc-macro2", + "quote", + "rustversion", + "syn", +] + +[[package]] +name = "syn" +version = "2.0.117" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "synstructure" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "728a70f3dbaf5bab7f0c4b1ac8d7ae5ea60a4b5549c8a5914361c99147a709d2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tempfile" +version = "3.25.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0136791f7c95b1f6dd99f9cc786b91bb81c3800b639b3478e561ddb7be95e5f1" +dependencies = [ + "fastrand", + "getrandom 0.4.1", + "once_cell", + "rustix 1.1.3", + "windows-sys 0.61.2", +] + +[[package]] +name = "termcolor" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "06794f8f6c5c898b3275aebefa6b8a1cb24cd2c6c79397ab15774837a0bc5755" +dependencies = [ + "winapi-util", +] + +[[package]] +name = "thiserror" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" +dependencies = [ + "thiserror-impl 1.0.69", +] + +[[package]] +name = "thiserror" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4288b5bcbc7920c07a1149a35cf9590a2aa808e0bc1eafaade0b80947865fbc4" +dependencies = [ + "thiserror-impl 2.0.18", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.69" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "thiserror-impl" +version = "2.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc4ee7f67670e9b64d05fa4253e753e016c6c95ff35b89b7941d6b856dec1d5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tiff" +version = "0.10.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af9605de7fee8d9551863fd692cce7637f548dbd9db9180fcc07ccc6d26c336f" +dependencies = [ + "fax", + "flate2", + "half", + "quick-error", + "weezl", + "zune-jpeg", +] + +[[package]] +name = "tiny-skia" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "83d13394d44dae3207b52a326c0c85a8bf87f1541f23b0d143811088497b09ab" +dependencies = [ + "arrayref", + "arrayvec", + "bytemuck", + "cfg-if", + "log", + "tiny-skia-path", +] + +[[package]] +name = "tiny-skia-path" +version = "0.11.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c9e7fc0c2e86a30b117d0462aa261b72b7a99b7ebd7deb3a14ceda95c5bdc93" +dependencies = [ + "arrayref", + "bytemuck", + "strict-num", +] + +[[package]] +name = "tinystr" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42d3e9c45c09de15d06dd8acf5f4e0e399e85927b7f00711024eb7ae10fa4869" +dependencies = [ + "displaydoc", + "zerovec", +] + +[[package]] +name = "tokio" +version = "1.49.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72a2903cd7736441aac9df9d7688bd0ce48edccaadf181c3b90be801e81d3d86" +dependencies = [ + "bytes", + "libc", + "mio", + "parking_lot", + "pin-project-lite", + "signal-hook-registry", + "socket2", + "tokio-macros", + "windows-sys 0.61.2", +] + +[[package]] +name = "tokio-macros" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af407857209536a95c8e56f8231ef2c2e2aff839b22e07a1ffcbc617e9db9fa5" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "toml_datetime" +version = "0.7.5+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92e1cfed4a3038bc5a127e35a2d360f145e1f4b971b551a2ba5fd7aedf7e1347" +dependencies = [ + "serde_core", +] + +[[package]] +name = "toml_edit" +version = "0.23.10+spec-1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "84c8b9f757e028cee9fa244aea147aab2a9ec09d5325a9b01e0a49730c2b5269" +dependencies = [ + "indexmap", + "toml_datetime", + "toml_parser", + "winnow", +] + +[[package]] +name = "toml_parser" +version = "1.0.9+spec-1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "702d4415e08923e7e1ef96cd5727c0dfed80b4d2fa25db9647fe5eb6f7c5a4c4" +dependencies = [ + "winnow", +] + +[[package]] +name = "tracing" +version = "0.1.44" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "63e71662fa4b2a2c3a26f570f037eb95bb1f85397f3cd8076caed2f026a6d100" +dependencies = [ + "log", + "pin-project-lite", + "tracing-attributes", + "tracing-core", +] + +[[package]] +name = "tracing-attributes" +version = "0.1.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7490cfa5ec963746568740651ac6781f701c9c5ea257c58e057f3ba8cf69e8da" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "tracing-core" +version = "0.1.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db97caf9d906fbde555dd62fa95ddba9eecfd14cb388e4f491a66d74cd5fb79a" +dependencies = [ + "once_cell", +] + +[[package]] +name = "ttf-parser" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31" + +[[package]] +name = "type-map" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cb30dbbd9036155e74adad6812e9898d03ec374946234fbcebd5dfc7b9187b90" +dependencies = [ + "rustc-hash 2.1.1", +] + +[[package]] +name = "typenum" +version = "1.19.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" + +[[package]] +name = "uds_windows" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89daebc3e6fd160ac4aa9fc8b3bf71e1f74fbf92367ae71fb83a037e8bf164b9" +dependencies = [ + "memoffset", + "tempfile", + "winapi", +] + +[[package]] +name = "unicode-ident" +version = "1.0.24" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6e4313cd5fcd3dad5cafa179702e2b244f760991f45397d14d4ebf38247da75" + +[[package]] +name = "unicode-segmentation" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6ccf251212114b54433ec949fd6a7841275f9ada20dddd2f29e9ceea4501493" + +[[package]] +name = "unicode-width" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dd6e30e90baa6f72411720665d41d89b9a3d039dc45b8faea1ddd07f617f6af" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" + +[[package]] +name = "url" +version = "2.5.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff67a8a4397373c3ef660812acab3268222035010ab8680ec4215f38ba3d0eed" +dependencies = [ + "form_urlencoded", + "idna", + "percent-encoding", + "serde", +] + +[[package]] +name = "utf8_iter" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6c140620e7ffbb22c2dee59cafe6084a59b5ffc27a8859a5f0d494b5d52b6be" + +[[package]] +name = "version_check" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" + +[[package]] +name = "walkdir" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] + +[[package]] +name = "wasi" +version = "0.11.1+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccf3ec651a847eb01de73ccad15eb7d99f80485de043efb2f370cd654f4ea44b" + +[[package]] +name = "wasip2" +version = "1.0.2+wasi-0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen", +] + +[[package]] +name = "wasm-bindgen" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64024a30ec1e37399cf85a7ffefebdb72205ca1c972291c51512360d90bd8566" +dependencies = [ + "cfg-if", + "once_cell", + "rustversion", + "wasm-bindgen-macro", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-futures" +version = "0.4.58" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70a6e77fd0ae8029c9ea0063f87c46fde723e7d887703d74ad2616d792e51e6f" +dependencies = [ + "cfg-if", + "futures-util", + "js-sys", + "once_cell", + "wasm-bindgen", + "web-sys", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "008b239d9c740232e71bd39e8ef6429d27097518b6b30bdf9086833bd5b6d608" +dependencies = [ + "quote", + "wasm-bindgen-macro-support", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5256bae2d58f54820e6490f9839c49780dff84c65aeab9e772f15d5f0e913a55" +dependencies = [ + "bumpalo", + "proc-macro2", + "quote", + "syn", + "wasm-bindgen-shared", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.108" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1f01b580c9ac74c8d8f0c0e4afb04eeef2acf145458e52c03845ee9cd23e3d12" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags 2.11.0", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "wayland-backend" +version = "0.3.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fee64194ccd96bf648f42a65a7e589547096dfa702f7cadef84347b66ad164f9" +dependencies = [ + "cc", + "downcast-rs", + "rustix 1.1.3", + "scoped-tls", + "smallvec", + "wayland-sys", +] + +[[package]] +name = "wayland-client" +version = "0.31.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e6faa537fbb6c186cb9f1d41f2f811a4120d1b57ec61f50da451a0c5122bec" +dependencies = [ + "bitflags 2.11.0", + "rustix 1.1.3", + "wayland-backend", + "wayland-scanner", +] + +[[package]] +name = "wayland-csd-frame" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "625c5029dbd43d25e6aa9615e88b829a5cad13b2819c4ae129fdbb7c31ab4c7e" +dependencies = [ + "bitflags 2.11.0", + "cursor-icon", + "wayland-backend", +] + +[[package]] +name = "wayland-cursor" +version = "0.31.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5864c4b5b6064b06b1e8b74ead4a98a6c45a285fe7a0e784d24735f011fdb078" +dependencies = [ + "rustix 1.1.3", + "wayland-client", + "xcursor", +] + +[[package]] +name = "wayland-protocols" +version = "0.32.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baeda9ffbcfc8cd6ddaade385eaf2393bd2115a69523c735f12242353c3df4f3" +dependencies = [ + "bitflags 2.11.0", + "wayland-backend", + "wayland-client", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-experimental" +version = "20250721.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "40a1f863128dcaaec790d7b4b396cc9b9a7a079e878e18c47e6c2d2c5a8dcbb1" +dependencies = [ + "bitflags 2.11.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-misc" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791c58fdeec5406aa37169dd815327d1e47f334219b523444bc26d70ceb4c34e" +dependencies = [ + "bitflags 2.11.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-plasma" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa98634619300a535a9a97f338aed9a5ff1e01a461943e8346ff4ae26007306b" +dependencies = [ + "bitflags 2.11.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-protocols-wlr" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e9597cdf02cf0c34cd5823786dce6b5ae8598f05c2daf5621b6e178d4f7345f3" +dependencies = [ + "bitflags 2.11.0", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-scanner", +] + +[[package]] +name = "wayland-scanner" +version = "0.31.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5423e94b6a63e68e439803a3e153a9252d5ead12fd853334e2ad33997e3889e3" +dependencies = [ + "proc-macro2", + "quick-xml 0.38.4", + "quote", +] + +[[package]] +name = "wayland-sys" +version = "0.31.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e6dbfc3ac5ef974c92a2235805cc0114033018ae1290a72e474aa8b28cbbdfd" +dependencies = [ + "dlib", + "log", + "once_cell", + "pkg-config", +] + +[[package]] +name = "web-sys" +version = "0.3.85" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "312e32e551d92129218ea9a2452120f4aabc03529ef03e4d0d82fb2780608598" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "web-time" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a6580f308b1fad9207618087a65c04e7a10bc77e02c8e84e9b00dd4b12fa0bb" +dependencies = [ + "js-sys", + "wasm-bindgen", +] + +[[package]] +name = "webbrowser" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f00bb839c1cf1e3036066614cbdcd035ecf215206691ea646aa3c60a24f68f2" +dependencies = [ + "core-foundation 0.10.1", + "jni", + "log", + "ndk-context", + "objc2 0.6.3", + "objc2-foundation 0.3.2", + "url", + "web-sys", +] + +[[package]] +name = "weezl" +version = "0.1.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" + +[[package]] +name = "wgpu" +version = "24.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b0b3436f0729f6cdf2e6e9201f3d39dc95813fad61d826c1ed07918b4539353" +dependencies = [ + "arrayvec", + "bitflags 2.11.0", + "cfg_aliases", + "document-features", + "js-sys", + "log", + "parking_lot", + "profiling", + "raw-window-handle", + "smallvec", + "static_assertions", + "wasm-bindgen", + "wasm-bindgen-futures", + "web-sys", + "wgpu-core", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-core" +version = "24.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f0aa306497a238d169b9dc70659105b4a096859a34894544ca81719242e1499" +dependencies = [ + "arrayvec", + "bit-vec", + "bitflags 2.11.0", + "cfg_aliases", + "document-features", + "indexmap", + "log", + "naga", + "once_cell", + "parking_lot", + "profiling", + "raw-window-handle", + "rustc-hash 1.1.0", + "smallvec", + "thiserror 2.0.18", + "wgpu-hal", + "wgpu-types", +] + +[[package]] +name = "wgpu-hal" +version = "24.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f112f464674ca69f3533248508ee30cb84c67cf06c25ff6800685f5e0294e259" +dependencies = [ + "android_system_properties", + "arrayvec", + "ash", + "bitflags 2.11.0", + "bytemuck", + "cfg_aliases", + "core-graphics-types", + "glow", + "glutin_wgl_sys", + "gpu-alloc", + "gpu-descriptor", + "js-sys", + "khronos-egl", + "libc", + "libloading", + "log", + "metal", + "naga", + "ndk-sys 0.5.0+25.2.9519653", + "objc", + "once_cell", + "ordered-float", + "parking_lot", + "profiling", + "raw-window-handle", + "renderdoc-sys", + "rustc-hash 1.1.0", + "smallvec", + "thiserror 2.0.18", + "wasm-bindgen", + "web-sys", + "wgpu-types", + "windows", +] + +[[package]] +name = "wgpu-types" +version = "24.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50ac044c0e76c03a0378e7786ac505d010a873665e2d51383dcff8dd227dc69c" +dependencies = [ + "bitflags 2.11.0", + "js-sys", + "log", + "web-sys", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +dependencies = [ + "winapi-i686-pc-windows-gnu", + "winapi-x86_64-pc-windows-gnu", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" + +[[package]] +name = "winapi-util" +version = "0.1.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" +dependencies = [ + "windows-sys 0.61.2", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" + +[[package]] +name = "windows" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6" +dependencies = [ + "windows-core 0.58.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99" +dependencies = [ + "windows-implement 0.58.0", + "windows-interface 0.58.0", + "windows-result 0.2.0", + "windows-strings 0.1.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-core" +version = "0.62.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8e83a14d34d0623b51dce9581199302a221863196a1dde71a7663a4c2be9deb" +dependencies = [ + "windows-implement 0.60.2", + "windows-interface 0.59.3", + "windows-link", + "windows-result 0.4.1", + "windows-strings 0.5.1", +] + +[[package]] +name = "windows-implement" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-implement" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053e2e040ab57b9dc951b72c264860db7eb3b0200ba345b4e4c3b14f67855ddf" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.58.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-interface" +version = "0.59.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f316c4a2570ba26bbec722032c4099d8c8bc095efccdc15688708623367e358" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + +[[package]] +name = "windows-result" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-result" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7781fa89eaf60850ac3d2da7af8e5242a5ea78d1a11c49bf2910bb5a73853eb5" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-strings" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10" +dependencies = [ + "windows-result 0.2.0", + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-strings" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7837d08f69c77cf6b07689544538e017c1bfcf57e34b4c0ff58e6c2cd3b37091" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-sys" +version = "0.45.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0" +dependencies = [ + "windows-targets 0.42.2", +] + +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.59.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" +dependencies = [ + "windows-targets 0.52.6", +] + +[[package]] +name = "windows-sys" +version = "0.60.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f2f500e4d28234f72040990ec9d39e3a6b950f9f22d3dba18416c35882612bcb" +dependencies = [ + "windows-targets 0.53.5", +] + +[[package]] +name = "windows-sys" +version = "0.61.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" +dependencies = [ + "windows-link", +] + +[[package]] +name = "windows-targets" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e5180c00cd44c9b1c88adb3693291f1cd93605ded80c250a75d472756b4d071" +dependencies = [ + "windows_aarch64_gnullvm 0.42.2", + "windows_aarch64_msvc 0.42.2", + "windows_i686_gnu 0.42.2", + "windows_i686_msvc 0.42.2", + "windows_x86_64_gnu 0.42.2", + "windows_x86_64_gnullvm 0.42.2", + "windows_x86_64_msvc 0.42.2", +] + +[[package]] +name = "windows-targets" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" +dependencies = [ + "windows_aarch64_gnullvm 0.52.6", + "windows_aarch64_msvc 0.52.6", + "windows_i686_gnu 0.52.6", + "windows_i686_gnullvm 0.52.6", + "windows_i686_msvc 0.52.6", + "windows_x86_64_gnu 0.52.6", + "windows_x86_64_gnullvm 0.52.6", + "windows_x86_64_msvc 0.52.6", +] + +[[package]] +name = "windows-targets" +version = "0.53.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4945f9f551b88e0d65f3db0bc25c33b8acea4d9e41163edf90dcd0b19f9069f3" +dependencies = [ + "windows-link", + "windows_aarch64_gnullvm 0.53.1", + "windows_aarch64_msvc 0.53.1", + "windows_i686_gnu 0.53.1", + "windows_i686_gnullvm 0.53.1", + "windows_i686_msvc 0.53.1", + "windows_x86_64_gnu 0.53.1", + "windows_x86_64_gnullvm 0.53.1", + "windows_x86_64_msvc 0.53.1", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "597a5118570b68bc08d8d59125332c54f1ba9d9adeedeef5b99b02ba2b0698f8" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9d8416fa8b42f5c947f8482c43e7d89e73a173cead56d044f6a56104a6d1b53" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e08e8864a60f06ef0d0ff4ba04124db8b0fb3be5776a5cd47641e942e58c4d43" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9d782e804c2f632e395708e99a94275910eb9100b2114651e04744e9b125006" + +[[package]] +name = "windows_i686_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c61d927d8da41da96a81f029489353e68739737d3beca43145c8afec9a31a84f" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8e9b5ad5ab802e97eb8e295ac6720e509ee4c243f69d781394014ebfe8bbfa0b" + +[[package]] +name = "windows_i686_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "960e6da069d81e09becb0ca57a65220ddff016ff2d6af6a223cf372a506593a3" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" + +[[package]] +name = "windows_i686_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fa7359d10048f68ab8b09fa71c3daccfb0e9b559aed648a8f95469c27057180c" + +[[package]] +name = "windows_i686_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44d840b6ec649f480a41c8d80f9c65108b92d89345dd94027bfe06ac444d1060" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" + +[[package]] +name = "windows_i686_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e7ac75179f18232fe9c285163565a57ef8d3c89254a30685b57d83a38d326c2" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8de912b8b8feb55c064867cf047dda097f92d51efad5b491dfb98f6bbb70cb36" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c3842cdd74a865a8066ab39c8a7a473c0778a3f29370b5fd6b4b9aa7df4a499" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26d41b46a36d453748aedef1486d5c7a85db22e56aff34643984ea85514e94a3" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0ffa179e2d07eee8ad8f57493436566c7cc30ac536a3379fdf008f47f6bb7ae1" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.42.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9aec5da331524158c6d1a4ac0ab1541149c0b9505fde06423b02f5ef0106b9f0" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "589f6da84c646204747d1270a2a5661ea66ed1cced2631d546fdfb155959f9ec" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.53.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d6bbff5f0aada427a1e5a6da5f1f98158182f26556f345ac9e04d36d0ebed650" + +[[package]] +name = "winit" +version = "0.30.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c66d4b9ed69c4009f6321f762d6e61ad8a2389cd431b97cb1e146812e9e6c732" +dependencies = [ + "ahash", + "android-activity", + "atomic-waker", + "bitflags 2.11.0", + "block2", + "bytemuck", + "calloop 0.13.0", + "cfg_aliases", + "concurrent-queue", + "core-foundation 0.9.4", + "core-graphics", + "cursor-icon", + "dpi", + "js-sys", + "libc", + "memmap2", + "ndk", + "objc2 0.5.2", + "objc2-app-kit 0.2.2", + "objc2-foundation 0.2.2", + "objc2-ui-kit", + "orbclient", + "percent-encoding", + "pin-project", + "raw-window-handle", + "redox_syscall 0.4.1", + "rustix 0.38.44", + "sctk-adwaita", + "smithay-client-toolkit 0.19.2", + "smol_str", + "tracing", + "unicode-segmentation", + "wasm-bindgen", + "wasm-bindgen-futures", + "wayland-backend", + "wayland-client", + "wayland-protocols", + "wayland-protocols-plasma", + "web-sys", + "web-time", + "windows-sys 0.52.0", + "x11-dl", + "x11rb", + "xkbcommon-dl", +] + +[[package]] +name = "winnow" +version = "0.7.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5a5364e9d77fcdeeaa6062ced926ee3381faa2ee02d3eb83a5c27a8825540829" +dependencies = [ + "memchr", +] + +[[package]] +name = "wit-bindgen" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" +dependencies = [ + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", +] + +[[package]] +name = "wit-bindgen-rust" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" +dependencies = [ + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", +] + +[[package]] +name = "wit-bindgen-rust-macro" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" +dependencies = [ + "anyhow", + "prettyplease", + "proc-macro2", + "quote", + "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags 2.11.0", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "writeable" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9edde0db4769d2dc68579893f2306b26c6ecfbe0ef499b013d731b7b9247e0b9" + +[[package]] +name = "x11-dl" +version = "2.21.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "38735924fedd5314a6e548792904ed8c6de6636285cb9fec04d5b1db85c1516f" +dependencies = [ + "libc", + "once_cell", + "pkg-config", +] + +[[package]] +name = "x11rb" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9993aa5be5a26815fe2c3eacfc1fde061fc1a1f094bf1ad2a18bf9c495dd7414" +dependencies = [ + "as-raw-xcb-connection", + "gethostname", + "libc", + "libloading", + "once_cell", + "rustix 1.1.3", + "x11rb-protocol", +] + +[[package]] +name = "x11rb-protocol" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea6fc2961e4ef194dcbfe56bb845534d0dc8098940c7e5c012a258bfec6701bd" + +[[package]] +name = "xcursor" +version = "0.3.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bec9e4a500ca8864c5b47b8b482a73d62e4237670e5b5f1d6b9e3cae50f28f2b" + +[[package]] +name = "xdg-home" +version = "1.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec1cdab258fb55c0da61328dc52c8764709b249011b2cad0454c72f0bf10a1f6" +dependencies = [ + "libc", + "windows-sys 0.59.0", +] + +[[package]] +name = "xkbcommon-dl" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d039de8032a9a8856a6be89cea3e5d12fdd82306ab7c94d74e6deab2460651c5" +dependencies = [ + "bitflags 2.11.0", + "dlib", + "log", + "once_cell", + "xkeysym", +] + +[[package]] +name = "xkeysym" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b9cc00251562a284751c9973bace760d86c0276c471b4be569fe6b068ee97a56" + +[[package]] +name = "xml-rs" +version = "0.8.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3ae8337f8a065cfc972643663ea4279e04e7256de865aa66fe25cec5fb912d3f" + +[[package]] +name = "yoke" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72d6e5c6afb84d73944e5cedb052c4680d5657337201555f9f2a16b7406d4954" +dependencies = [ + "stable_deref_trait", + "yoke-derive", + "zerofrom", +] + +[[package]] +name = "yoke-derive" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b659052874eb698efe5b9e8cf382204678a0086ebf46982b79d6ca3182927e5d" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zbus" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb97012beadd29e654708a0fdb4c84bc046f537aecfde2c3ee0a9e4b4d48c725" +dependencies = [ + "async-broadcast", + "async-executor", + "async-fs", + "async-io", + "async-lock", + "async-process", + "async-recursion", + "async-task", + "async-trait", + "blocking", + "enumflags2", + "event-listener", + "futures-core", + "futures-sink", + "futures-util", + "hex", + "nix", + "ordered-stream", + "rand", + "serde", + "serde_repr", + "sha1", + "static_assertions", + "tracing", + "uds_windows", + "windows-sys 0.52.0", + "xdg-home", + "zbus_macros", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zbus-lockstep" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca2c5dceb099bddaade154055c926bb8ae507a18756ba1d8963fd7b51d8ed1d" +dependencies = [ + "zbus_xml", + "zvariant", +] + +[[package]] +name = "zbus-lockstep-macros" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "709ab20fc57cb22af85be7b360239563209258430bccf38d8b979c5a2ae3ecce" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "zbus-lockstep", + "zbus_xml", + "zvariant", +] + +[[package]] +name = "zbus_macros" +version = "4.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "267db9407081e90bbfa46d841d3cbc60f59c0351838c4bc65199ecd79ab1983e" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", + "zvariant_utils", +] + +[[package]] +name = "zbus_names" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4b9b1fef7d021261cc16cba64c351d291b715febe0fa10dc3a443ac5a5022e6c" +dependencies = [ + "serde", + "static_assertions", + "zvariant", +] + +[[package]] +name = "zbus_xml" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab3f374552b954f6abb4bd6ce979e6c9b38fb9d0cd7cc68a7d796e70c9f3a233" +dependencies = [ + "quick-xml 0.30.0", + "serde", + "static_assertions", + "zbus_names", + "zvariant", +] + +[[package]] +name = "zerocopy" +version = "0.8.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db6d35d663eadb6c932438e763b262fe1a70987f9ae936e60158176d710cae4a" +dependencies = [ + "zerocopy-derive", +] + +[[package]] +name = "zerocopy-derive" +version = "0.8.39" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4122cd3169e94605190e77839c9a40d40ed048d305bfdc146e7df40ab0f3e517" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zerofrom" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "50cc42e0333e05660c3587f3bf9d0478688e15d870fab3346451ce7f8c9fbea5" +dependencies = [ + "zerofrom-derive", +] + +[[package]] +name = "zerofrom-derive" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d71e5d6e06ab090c67b5e44993ec16b72dcbaabc526db883a360057678b48502" +dependencies = [ + "proc-macro2", + "quote", + "syn", + "synstructure", +] + +[[package]] +name = "zerotrie" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a59c17a5562d507e4b54960e8569ebee33bee890c70aa3fe7b97e85a9fd7851" +dependencies = [ + "displaydoc", + "yoke", + "zerofrom", +] + +[[package]] +name = "zerovec" +version = "0.11.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c28719294829477f525be0186d13efa9a3c602f7ec202ca9e353d310fb9a002" +dependencies = [ + "yoke", + "zerofrom", + "zerovec-derive", +] + +[[package]] +name = "zerovec-derive" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "eadce39539ca5cb3985590102671f2567e659fca9666581ad3411d59207951f3" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "zmij" +version = "1.0.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8848ee67ecc8aedbaf3e4122217aff892639231befc6a1b58d29fff4c2cabaa" + +[[package]] +name = "zune-core" +version = "0.4.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f423a2c17029964870cfaabb1f13dfab7d092a62a29a89264f4d36990ca414a" + +[[package]] +name = "zune-jpeg" +version = "0.4.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "29ce2c8a9384ad323cf564b67da86e21d3cfdff87908bc1223ed5c99bc792713" +dependencies = [ + "zune-core", +] + +[[package]] +name = "zvariant" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2084290ab9a1c471c38fc524945837734fbf124487e105daec2bb57fd48c81fe" +dependencies = [ + "endi", + "enumflags2", + "serde", + "static_assertions", + "zvariant_derive", +] + +[[package]] +name = "zvariant_derive" +version = "4.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "73e2ba546bda683a90652bac4a279bc146adad1386f25379cf73200d2002c449" +dependencies = [ + "proc-macro-crate", + "proc-macro2", + "quote", + "syn", + "zvariant_utils", +] + +[[package]] +name = "zvariant_utils" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c51bcff7cc3dbb5055396bcf774748c3dab426b4b8659046963523cee4808340" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] diff --git a/Tools/gui_client/Cargo.toml b/Tools/gui_client/Cargo.toml new file mode 100644 index 0000000..7005519 --- /dev/null +++ b/Tools/gui_client/Cargo.toml @@ -0,0 +1,16 @@ +[package] +name = "marte_debug_gui" +version = "0.1.0" +edition = "2021" + +[dependencies] +eframe = "0.31.0" +egui = "0.31.0" +egui_plot = "0.31.0" +tokio = { version = "1.0", features = ["full"] } +serde = { version = "1.0", features = ["derive"] } +serde_json = "1.0" +byteorder = "1.4" +chrono = "0.4" +crossbeam-channel = "0.5" +regex = "1.12.3" diff --git a/Tools/gui_client/src/main.rs b/Tools/gui_client/src/main.rs new file mode 100644 index 0000000..433eb21 --- /dev/null +++ b/Tools/gui_client/src/main.rs @@ -0,0 +1,673 @@ +use eframe::egui; +use egui_plot::{Line, Plot, PlotPoints}; +use std::collections::{HashMap, VecDeque}; +use std::net::{TcpStream, UdpSocket}; +use std::io::{Write, BufReader, BufRead}; +use std::sync::{Arc, Mutex}; +use std::thread; +use serde::{Deserialize, Serialize}; +use chrono::Local; +use crossbeam_channel::{unbounded, Receiver, Sender}; +use regex::Regex; + +// --- Models --- + +#[derive(Serialize, Deserialize, Clone, Debug)] +struct Signal { + name: String, + id: u32, + #[serde(rename = "type")] + sig_type: String, +} + +#[derive(Deserialize)] +struct DiscoverResponse { + #[serde(rename = "Signals")] + signals: Vec, +} + +#[derive(Serialize, Deserialize, Clone, Debug)] +struct TreeItem { + #[serde(rename = "Name")] + name: String, + #[serde(rename = "Class")] + class: String, + #[serde(rename = "Children")] + children: Option>, + #[serde(rename = "Type")] + sig_type: Option, + #[serde(rename = "Dimensions")] + dimensions: Option, + #[serde(rename = "Elements")] + elements: Option, +} + +#[derive(Clone)] +struct LogEntry { + time: String, + level: String, + message: String, +} + +struct TraceData { + values: VecDeque<[f64; 2]>, +} + +struct SignalMetadata { + names: Vec, + sig_type: String, +} + +enum InternalEvent { + Log(LogEntry), + Discovery(Vec), + Tree(TreeItem), + CommandResponse(String), + NodeInfo(String), + Connected, + InternalLog(String), + TraceRequested(String), + ClearTrace(String), + UdpStats(u64), +} + +// --- App State --- + +struct ForcingDialog { + signal_path: String, + sig_type: String, + dims: u8, + elems: u32, + value: String, +} + +struct LogFilters { + content_regex: String, + show_debug: bool, + show_info: bool, + show_warning: bool, + show_error: bool, + paused: bool, +} + +struct MarteDebugApp { + #[allow(dead_code)] + connected: bool, + tcp_addr: String, + log_addr: String, + + signals: Vec, + app_tree: Option, + + traced_signals: Arc>>, + id_to_meta: Arc>>, + + forced_signals: HashMap, + is_paused: bool, + + logs: VecDeque, + log_filters: LogFilters, + + // UI Panels + show_left_panel: bool, + show_right_panel: bool, + show_bottom_panel: bool, + + selected_node: String, + node_info: String, + + udp_packets: u64, + + forcing_dialog: Option, + + tx_cmd: Sender, + rx_events: Receiver, + internal_tx: Sender, +} + +impl MarteDebugApp { + fn new(_cc: &eframe::CreationContext<'_>) -> Self { + let (tx_cmd, rx_cmd_internal) = unbounded::(); + let (tx_events, rx_events) = unbounded::(); + let internal_tx = tx_events.clone(); + + let tcp_addr = "127.0.0.1:8080".to_string(); + let log_addr = "127.0.0.1:8082".to_string(); + + let id_to_meta = Arc::new(Mutex::new(HashMap::new())); + let traced_signals = Arc::new(Mutex::new(HashMap::new())); + + let id_to_meta_clone = id_to_meta.clone(); + let traced_signals_clone = traced_signals.clone(); + + let tx_events_c = tx_events.clone(); + thread::spawn(move || { + tcp_command_worker(tcp_addr, rx_cmd_internal, tx_events_c); + }); + + let tx_events_log = tx_events.clone(); + thread::spawn(move || { + tcp_log_worker(log_addr, tx_events_log); + }); + + let tx_events_udp = tx_events.clone(); + thread::spawn(move || { + udp_worker(8081, id_to_meta_clone, traced_signals_clone, tx_events_udp); + }); + + Self { + connected: false, + tcp_addr: "127.0.0.1:8080".to_string(), + log_addr: "127.0.0.1:8082".to_string(), + signals: Vec::new(), + app_tree: None, + id_to_meta, + traced_signals, + forced_signals: HashMap::new(), + is_paused: false, + logs: VecDeque::with_capacity(2000), + log_filters: LogFilters { + content_regex: "".to_string(), + show_debug: true, + show_info: true, + show_warning: true, + show_error: true, + paused: false, + }, + show_left_panel: true, + show_right_panel: true, + show_bottom_panel: true, + selected_node: "".to_string(), + node_info: "".to_string(), + udp_packets: 0, + forcing_dialog: None, + tx_cmd, + rx_events, + internal_tx, + } + } + + fn render_tree(&mut self, ui: &mut egui::Ui, item: &TreeItem, path: String) { + let current_path = if path.is_empty() { + item.name.clone() + } else if path == "Root" { + item.name.clone() + } else { + format!("{}.{}", path, item.name) + }; + + if let Some(children) = &item.children { + let header = egui::CollapsingHeader::new(format!("{} [{}]", item.name, item.class)) + .id_salt(¤t_path); + + header.show(ui, |ui| { + ui.horizontal(|ui| { + if ui.selectable_label(self.selected_node == current_path, "ℹ Info").clicked() { + self.selected_node = current_path.clone(); + let _ = self.tx_cmd.send(format!("INFO {}", current_path)); + } + }); + for child in children { + self.render_tree(ui, child, current_path.clone()); + } + }); + } else { + ui.horizontal(|ui| { + if ui.selectable_label(self.selected_node == current_path, format!("{} [{}]", item.name, item.class)).clicked() { + self.selected_node = current_path.clone(); + let _ = self.tx_cmd.send(format!("INFO {}", current_path)); + } + if item.class.contains("Signal") { + if ui.button("📈 Trace").clicked() { + let _ = self.tx_cmd.send(format!("TRACE {} 1", current_path)); + let _ = self.internal_tx.send(InternalEvent::TraceRequested(current_path.clone())); + } + if ui.button("⚡ Force").clicked() { + self.forcing_dialog = Some(ForcingDialog { + signal_path: current_path.clone(), + sig_type: item.sig_type.clone().unwrap_or_else(|| "Unknown".to_string()), + dims: item.dimensions.unwrap_or(0), + elems: item.elements.unwrap_or(1), + value: "".to_string(), + }); + } + } + }); + } + } +} + +fn tcp_command_worker(addr: String, rx_cmd: Receiver, tx_events: Sender) { + loop { + if let Ok(mut stream) = TcpStream::connect(&addr) { + let _ = stream.set_nodelay(true); + let mut reader = BufReader::new(stream.try_clone().unwrap()); + let _ = tx_events.send(InternalEvent::Connected); + + let tx_events_inner = tx_events.clone(); + thread::spawn(move || { + let mut line = String::new(); + let mut json_acc = String::new(); + let mut in_json = false; + + while reader.read_line(&mut line).is_ok() { + let trimmed = line.trim(); + if trimmed.is_empty() { line.clear(); continue; } + + if !in_json && trimmed.starts_with("{") { + in_json = true; + json_acc.clear(); + } + + if in_json { + json_acc.push_str(trimmed); + if trimmed == "OK DISCOVER" { + in_json = false; + let json_clean = json_acc.trim_end_matches("OK DISCOVER").trim(); + match serde_json::from_str::(json_clean) { + Ok(resp) => { let _ = tx_events_inner.send(InternalEvent::Discovery(resp.signals)); } + Err(e) => { let _ = tx_events_inner.send(InternalEvent::InternalLog(format!("JSON Parse Error (Discover): {}", e))); } + } + json_acc.clear(); + } else if trimmed == "OK TREE" { + in_json = false; + let json_clean = json_acc.trim_end_matches("OK TREE").trim(); + match serde_json::from_str::(json_clean) { + Ok(resp) => { let _ = tx_events_inner.send(InternalEvent::Tree(resp)); } + Err(e) => { let _ = tx_events_inner.send(InternalEvent::InternalLog(format!("JSON Parse Error (Tree): {}", e))); } + } + json_acc.clear(); + } else if trimmed == "OK INFO" { + in_json = false; + let json_clean = json_acc.trim_end_matches("OK INFO").trim(); + let _ = tx_events_inner.send(InternalEvent::NodeInfo(json_clean.to_string())); + json_acc.clear(); + } + } else { + let _ = tx_events_inner.send(InternalEvent::CommandResponse(trimmed.to_string())); + } + line.clear(); + } + }); + + while let Ok(cmd) = rx_cmd.recv() { + if stream.write_all(format!("{}\n", cmd).as_bytes()).is_err() { + break; + } + } + } + thread::sleep(std::time::Duration::from_secs(2)); + } +} + +fn tcp_log_worker(addr: String, tx_events: Sender) { + loop { + if let Ok(stream) = TcpStream::connect(&addr) { + let mut reader = BufReader::new(stream); + let mut line = String::new(); + while reader.read_line(&mut line).is_ok() { + let trimmed = line.trim(); + if trimmed.starts_with("LOG ") { + let parts: Vec<&str> = trimmed[4..].splitn(2, ' ').collect(); + if parts.len() == 2 { + let _ = tx_events.send(InternalEvent::Log(LogEntry { + time: Local::now().format("%H:%M:%S%.3f").to_string(), + level: parts[0].to_string(), + message: parts[1].to_string(), + })); + } + } + line.clear(); + } + } + thread::sleep(std::time::Duration::from_secs(2)); + } +} + +fn udp_worker(port: u16, id_to_meta: Arc>>, traced_data: Arc>>, tx_events: Sender) { + if let Ok(socket) = UdpSocket::bind(format!("0.0.0.0:{}", port)) { + let mut buf = [0u8; 4096]; + let start_time = std::time::Instant::now(); + let mut total_packets = 0u64; + + loop { + if let Ok(n) = socket.recv(&mut buf) { + total_packets += 1; + if (total_packets % 100) == 0 { + let _ = tx_events.send(InternalEvent::UdpStats(total_packets)); + } + + if n < 20 { continue; } + + let mut magic_buf = [0u8; 4]; magic_buf.copy_from_slice(&buf[0..4]); + if u32::from_le_bytes(magic_buf) != 0xDA7A57AD { continue; } + + let mut count_buf = [0u8; 4]; count_buf.copy_from_slice(&buf[16..20]); + let count = u32::from_le_bytes(count_buf); + + let mut offset = 20; + let now = start_time.elapsed().as_secs_f64(); + + let metas = id_to_meta.lock().unwrap(); + let mut data_map = traced_data.lock().unwrap(); + + for _ in 0..count { + if offset + 8 > n { break; } + let mut id_buf = [0u8; 4]; id_buf.copy_from_slice(&buf[offset..offset+4]); + let id = u32::from_le_bytes(id_buf); + let mut size_buf = [0u8; 4]; size_buf.copy_from_slice(&buf[offset+4..offset+8]); + let size = u32::from_le_bytes(size_buf); + offset += 8; + if offset + size as usize > n { break; } + + let data_slice = &buf[offset..offset + size as usize]; + + if let Some(meta) = metas.get(&id) { + let t = meta.sig_type.as_str(); + let val = match size { + 1 => { if t.contains('u') { data_slice[0] as f64 } else { (data_slice[0] as i8) as f64 } }, + 2 => { + let mut b = [0u8; 2]; b.copy_from_slice(data_slice); + if t.contains('u') { u16::from_le_bytes(b) as f64 } else { i16::from_le_bytes(b) as f64 } + }, + 4 => { + let mut b = [0u8; 4]; b.copy_from_slice(data_slice); + if t.contains("float") { f32::from_le_bytes(b) as f64 } + else if t.contains('u') { u32::from_le_bytes(b) as f64 } + else { i32::from_le_bytes(b) as f64 } + }, + 8 => { + let mut b = [0u8; 8]; b.copy_from_slice(data_slice); + if t.contains("float") { f64::from_le_bytes(b) } + else if t.contains('u') { u64::from_le_bytes(b) as f64 } + else { i64::from_le_bytes(b) as f64 } + }, + _ => 0.0, + }; + + for name in &meta.names { + if let Some(entry) = data_map.get_mut(name) { + entry.values.push_back([now, val]); + if entry.values.len() > 2000 { entry.values.pop_front(); } + } + } + } + offset += size as usize; + } + } + } + } +} + +impl eframe::App for MarteDebugApp { + fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { + while let Ok(event) = self.rx_events.try_recv() { + match event { + InternalEvent::Log(log) => { + if !self.log_filters.paused { + self.logs.push_back(log); + if self.logs.len() > 2000 { self.logs.pop_front(); } + } + } + InternalEvent::InternalLog(msg) => { + self.logs.push_back(LogEntry { + time: Local::now().format("%H:%M:%S").to_string(), + level: "GUI_ERROR".to_string(), + message: msg, + }); + } + InternalEvent::Discovery(signals) => { + let mut metas = self.id_to_meta.lock().unwrap(); + metas.clear(); + for s in &signals { + let meta = metas.entry(s.id).or_insert_with(|| SignalMetadata { names: Vec::new(), sig_type: s.sig_type.clone() }); + if !meta.names.contains(&s.name) { meta.names.push(s.name.clone()); } + } + self.signals = signals; + } + InternalEvent::Tree(tree) => { + self.app_tree = Some(tree); + } + InternalEvent::NodeInfo(info) => { + self.node_info = info; + } + InternalEvent::TraceRequested(name) => { + let mut data_map = self.traced_signals.lock().unwrap(); + data_map.entry(name).or_insert_with(|| TraceData { values: VecDeque::with_capacity(2000) }); + } + InternalEvent::ClearTrace(name) => { + let mut data_map = self.traced_signals.lock().unwrap(); + data_map.remove(&name); + } + InternalEvent::CommandResponse(resp) => { + self.logs.push_back(LogEntry { + time: Local::now().format("%H:%M:%S").to_string(), + level: "CMD_RESP".to_string(), + message: resp, + }); + } + InternalEvent::UdpStats(count) => { + self.udp_packets = count; + } + InternalEvent::Connected => { + let _ = self.tx_cmd.send("TREE".to_string()); + let _ = self.tx_cmd.send("DISCOVER".to_string()); + } + } + } + + if let Some(dialog) = &mut self.forcing_dialog { + let mut close = false; + egui::Window::new("Force Signal").collapsible(false).resizable(false).show(ctx, |ui| { + ui.label(format!("Signal: {}", dialog.signal_path)); + ui.label(format!("Type: {} (Dims: {}, Elems: {})", dialog.sig_type, dialog.dims, dialog.elems)); + ui.horizontal(|ui| { + ui.label("Value:"); + ui.text_edit_singleline(&mut dialog.value); + }); + ui.horizontal(|ui| { + if ui.button("Apply Force").clicked() { + let _ = self.tx_cmd.send(format!("FORCE {} {}", dialog.signal_path, dialog.value)); + self.forced_signals.insert(dialog.signal_path.clone(), dialog.value.clone()); + close = true; + } + if ui.button("Cancel").clicked() { close = true; } + }); + }); + if close { self.forcing_dialog = None; } + } + + egui::TopBottomPanel::top("top_panel").show(ctx, |ui| { + ui.horizontal(|ui| { + ui.toggle_value(&mut self.show_left_panel, "🗂 Tree"); + ui.toggle_value(&mut self.show_right_panel, "⚙ Debug"); + ui.toggle_value(&mut self.show_bottom_panel, "📜 Logs"); + ui.separator(); + ui.heading("MARTe2 Debug Explorer"); + ui.separator(); + if ui.button("🔄 Refresh").clicked() { + let _ = self.tx_cmd.send("TREE".to_string()); + let _ = self.tx_cmd.send("DISCOVER".to_string()); + } + ui.separator(); + if self.is_paused { + if ui.button("▶ Resume").clicked() { + let _ = self.tx_cmd.send("RESUME".to_string()); + self.is_paused = false; + } + } else { + if ui.button("⏸ Pause").clicked() { + let _ = self.tx_cmd.send("PAUSE".to_string()); + self.is_paused = true; + } + } + ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { + ui.label(format!("UDP Packets: {}", self.udp_packets)); + }); + }); + }); + + if self.show_bottom_panel { + egui::TopBottomPanel::bottom("log_panel").resizable(true).default_height(200.0).show(ctx, |ui| { + ui.horizontal(|ui| { + ui.heading("System Logs"); + ui.separator(); + ui.label("Filter:"); + ui.text_edit_singleline(&mut self.log_filters.content_regex); + ui.checkbox(&mut self.log_filters.show_debug, "Debug"); + ui.checkbox(&mut self.log_filters.show_info, "Info"); + ui.checkbox(&mut self.log_filters.show_warning, "Warn"); + ui.checkbox(&mut self.log_filters.show_error, "Error"); + ui.separator(); + ui.toggle_value(&mut self.log_filters.paused, "⏸ Pause Logs"); + ui.with_layout(egui::Layout::right_to_left(egui::Align::Center), |ui| { + if ui.button("🗑 Clear").clicked() { self.logs.clear(); } + }); + }); + ui.separator(); + + let regex = if !self.log_filters.content_regex.is_empty() { Regex::new(&self.log_filters.content_regex).ok() } else { None }; + + egui::ScrollArea::vertical() + .stick_to_bottom(true) + .auto_shrink([false, false]) + .show(ui, |ui| { + for log in &self.logs { + let show = match log.level.as_str() { + "Debug" => self.log_filters.show_debug, + "Information" => self.log_filters.show_info, + "Warning" => self.log_filters.show_warning, + "FatalError" | "OSError" | "ParametersError" => self.log_filters.show_error, + _ => true, + }; + if !show { continue; } + if let Some(re) = ®ex { if !re.is_match(&log.message) && !re.is_match(&log.level) { continue; } } + + let color = match log.level.as_str() { + "FatalError" | "OSError" | "ParametersError" => egui::Color32::from_rgb(255, 100, 100), + "Warning" => egui::Color32::from_rgb(255, 255, 100), + "Information" => egui::Color32::from_rgb(100, 255, 100), + "Debug" => egui::Color32::from_rgb(100, 100, 255), + "GUI_ERROR" => egui::Color32::from_rgb(255, 50, 255), + "CMD_RESP" => egui::Color32::from_rgb(255, 255, 255), + _ => egui::Color32::WHITE, + }; + + ui.scope(|ui| { + ui.horizontal(|ui| { + ui.label(egui::RichText::new(&log.time).monospace().color(egui::Color32::GRAY)); + ui.label(egui::RichText::new(format!("[{}]", log.level)).color(color).strong()); + ui.add(egui::Label::new(&log.message).wrap()); + ui.allocate_space(egui::vec2(ui.available_width(), 0.0)); + }); + }); + } + }); + }); + } + + if self.show_left_panel { + egui::SidePanel::left("signals_panel").resizable(true).width_range(300.0..=600.0).show(ctx, |ui| { + ui.heading("Application Tree"); + ui.separator(); + egui::ScrollArea::vertical().id_salt("tree_scroll").show(ui, |ui| { + if let Some(tree) = self.app_tree.clone() { + self.render_tree(ui, &tree, "".to_string()); + } else { + ui.label("Connecting to server..."); + } + }); + + ui.separator(); + ui.heading("Node Information"); + egui::ScrollArea::vertical().id_salt("info_scroll").show(ui, |ui| { + if self.node_info.is_empty() { + ui.label("Click 'Info' on a node to view details"); + } else { + ui.add(egui::Label::new(egui::RichText::new(&self.node_info).monospace()).wrap()); + } + }); + }); + } + + if self.show_right_panel { + egui::SidePanel::right("debug_panel").resizable(true).width_range(200.0..=400.0).show(ctx, |ui| { + ui.heading("Active Controls"); + ui.separator(); + ui.label(egui::RichText::new("Forced Signals").strong()); + egui::ScrollArea::vertical().id_salt("forced_scroll").show(ui, |ui| { + let mut to_update = None; + let mut to_remove = None; + for (path, val) in &self.forced_signals { + ui.horizontal(|ui| { + if ui.selectable_label(false, format!("{}: {}", path, val)).clicked() { + to_update = Some(path.clone()); + } + if ui.button("❌").clicked() { + let _ = self.tx_cmd.send(format!("UNFORCE {}", path)); + to_remove = Some(path.clone()); + } + }); + } + if let Some(p) = to_remove { self.forced_signals.remove(&p); } + if let Some(p) = to_update { + self.forcing_dialog = Some(ForcingDialog { + signal_path: p.clone(), sig_type: "Unknown".to_string(), dims: 0, elems: 1, + value: self.forced_signals.get(&p).unwrap().clone(), + }); + } + }); + + ui.separator(); + ui.label(egui::RichText::new("Traced Signals").strong()); + egui::ScrollArea::vertical().id_salt("traced_scroll").show(ui, |ui| { + let mut names: Vec<_> = { + let data_map = self.traced_signals.lock().unwrap(); + data_map.keys().cloned().collect() + }; + names.sort(); + for key in names { + ui.horizontal(|ui| { + ui.label(&key); + if ui.button("❌").clicked() { + let _ = self.tx_cmd.send(format!("TRACE {} 0", key)); + let _ = self.internal_tx.send(InternalEvent::ClearTrace(key)); + } + }); + } + }); + }); + } + + egui::CentralPanel::default().show(ctx, |ui| { + ui.heading("Oscilloscope"); + let plot = Plot::new("traces_plot") + .legend(egui_plot::Legend::default()) + .auto_bounds_x() + .auto_bounds_y() + .y_axis_min_width(4.0); + + plot.show(ui, |plot_ui| { + let data_map = self.traced_signals.lock().unwrap(); + for (name, data) in data_map.iter() { + let points: PlotPoints = data.values.iter().cloned().collect(); + plot_ui.line(Line::new(points).name(name)); + } + }); + }); + + ctx.request_repaint_after(std::time::Duration::from_millis(16)); + } +} + +fn main() -> Result<(), eframe::Error> { + let options = eframe::NativeOptions { + viewport: egui::ViewportBuilder::default().with_inner_size([1280.0, 800.0]), + ..Default::default() + }; + eframe::run_native( + "MARTe2 Debug Explorer", + options, + Box::new(|cc| Ok(Box::new(MarteDebugApp::new(cc)))), + ) +} diff --git a/compile_commands.json b/compile_commands.json new file mode 100644 index 0000000..f12b4a0 --- /dev/null +++ b/compile_commands.json @@ -0,0 +1,180 @@ +[ + { + "file": "CMakeCCompilerId.c", + "arguments": [ + "cc", + "CMakeCCompilerId.c" + ], + "directory": "/home/martino/Projects/marte_debug/Build/CMakeFiles/4.2.3/CompilerIdC" + }, + { + "file": "CMakeCXXCompilerId.cpp", + "arguments": [ + "c++", + "CMakeCXXCompilerId.cpp" + ], + "directory": "/home/martino/Projects/marte_debug/Build/CMakeFiles/4.2.3/CompilerIdCXX" + }, + { + "file": "/usr/share/cmake/Modules/CMakeCCompilerABI.c", + "arguments": [ + "cc", + "-v", + "-o", + "CMakeFiles/cmTC_27c6b.dir/CMakeCCompilerABI.c.o", + "-c", + "/usr/share/cmake/Modules/CMakeCCompilerABI.c" + ], + "directory": "/home/martino/Projects/marte_debug/Build/CMakeFiles/CMakeScratch/TryCompile-0cxTtB", + "output": "CMakeFiles/cmTC_27c6b.dir/CMakeCCompilerABI.c.o" + }, + { + "file": "/usr/share/cmake/Modules/CMakeCXXCompilerABI.cpp", + "arguments": [ + "c++", + "-v", + "-o", + "CMakeFiles/cmTC_2b812.dir/CMakeCXXCompilerABI.cpp.o", + "-c", + "/usr/share/cmake/Modules/CMakeCXXCompilerABI.cpp" + ], + "directory": "/home/martino/Projects/marte_debug/Build/CMakeFiles/CMakeScratch/TryCompile-JvDZsz", + "output": "CMakeFiles/cmTC_2b812.dir/CMakeCXXCompilerABI.cpp.o" + }, + { + "file": "/home/martino/Projects/marte_debug/Source/DebugService.cpp", + "arguments": [ + "c++", + "-DARCHITECTURE=x86_gcc", + "-DENVIRONMENT=Linux", + "-DMARTe2_TEST_ENVIRONMENT=GTest", + "-DUSE_PTHREAD", + "-Dmarte_dev_EXPORTS", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L0Types", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L1Portability", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L2Objects", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L3Streams", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Configuration", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Events", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Logger", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Messages", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L5FILES", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L5GAMs", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L6App", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L1Portability", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L3Services", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4Configuration", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4LoggerService", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L1Portability", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L3Streams", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2-components/Source/Components/DataSources/EpicsDataSource", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2-components/Source/Components/DataSources/FileDataSource", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2-components/Source/Components/GAMs/IOGAM", + "-I/home/martino/Projects/marte_debug/Source", + "-I/home/martino/Projects/marte_debug/Headers", + "-pthread", + "-fPIC", + "-MD", + "-MT", + "CMakeFiles/marte_dev.dir/Source/DebugService.cpp.o", + "-MF", + "CMakeFiles/marte_dev.dir/Source/DebugService.cpp.o.d", + "-o", + "CMakeFiles/marte_dev.dir/Source/DebugService.cpp.o", + "-c", + "/home/martino/Projects/marte_debug/Source/DebugService.cpp" + ], + "directory": "/home/martino/Projects/marte_debug/Build", + "output": "CMakeFiles/marte_dev.dir/Source/DebugService.cpp.o" + }, + { + "file": "/home/martino/Projects/marte_debug/Test/UnitTests/main.cpp", + "arguments": [ + "c++", + "-DARCHITECTURE=x86_gcc", + "-DENVIRONMENT=Linux", + "-DMARTe2_TEST_ENVIRONMENT=GTest", + "-DUSE_PTHREAD", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L0Types", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L1Portability", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L2Objects", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L3Streams", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Configuration", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Events", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Logger", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Messages", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L5FILES", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L5GAMs", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L6App", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L1Portability", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L3Services", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4Configuration", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4LoggerService", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L1Portability", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L3Streams", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2-components/Source/Components/DataSources/EpicsDataSource", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2-components/Source/Components/DataSources/FileDataSource", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2-components/Source/Components/GAMs/IOGAM", + "-I/home/martino/Projects/marte_debug/Source", + "-I/home/martino/Projects/marte_debug/Headers", + "-I/home/martino/Projects/marte_debug/Test/UnitTests/../../Source", + "-I/home/martino/Projects/marte_debug/Test/UnitTests/../../Headers", + "-pthread", + "-MD", + "-MT", + "Test/UnitTests/CMakeFiles/UnitTests.dir/main.cpp.o", + "-MF", + "CMakeFiles/UnitTests.dir/main.cpp.o.d", + "-o", + "CMakeFiles/UnitTests.dir/main.cpp.o", + "-c", + "/home/martino/Projects/marte_debug/Test/UnitTests/main.cpp" + ], + "directory": "/home/martino/Projects/marte_debug/Build/Test/UnitTests", + "output": "CMakeFiles/UnitTests.dir/main.cpp.o" + }, + { + "file": "/home/martino/Projects/marte_debug/Test/Integration/main.cpp", + "arguments": [ + "c++", + "-DARCHITECTURE=x86_gcc", + "-DENVIRONMENT=Linux", + "-DMARTe2_TEST_ENVIRONMENT=GTest", + "-DUSE_PTHREAD", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L0Types", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L1Portability", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L2Objects", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L3Streams", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Configuration", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Events", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Logger", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L4Messages", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L5FILES", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L5GAMs", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/BareMetal/L6App", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L1Portability", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L3Services", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4Configuration", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/Scheduler/L4LoggerService", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L1Portability", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2/Source/Core/FileSystem/L3Streams", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2-components/Source/Components/DataSources/EpicsDataSource", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2-components/Source/Components/DataSources/FileDataSource", + "-I/home/martino/Projects/marte_debug/dependency/MARTe2-components/Source/Components/GAMs/IOGAM", + "-I/home/martino/Projects/marte_debug/Source", + "-I/home/martino/Projects/marte_debug/Headers", + "-pthread", + "-MD", + "-MT", + "Test/Integration/CMakeFiles/IntegrationTest.dir/main.cpp.o", + "-MF", + "CMakeFiles/IntegrationTest.dir/main.cpp.o.d", + "-o", + "CMakeFiles/IntegrationTest.dir/main.cpp.o", + "-c", + "/home/martino/Projects/marte_debug/Test/Integration/main.cpp" + ], + "directory": "/home/martino/Projects/marte_debug/Build/Test/Integration", + "output": "CMakeFiles/IntegrationTest.dir/main.cpp.o" + } +] \ No newline at end of file diff --git a/env.sh b/env.sh new file mode 100644 index 0000000..3166cb7 --- /dev/null +++ b/env.sh @@ -0,0 +1,11 @@ +#!/bin/bash +# Get the directory of this script +DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" >/dev/null 2>&1 && pwd )" + +export MARTe2_DIR=$DIR/dependency/MARTe2 +export MARTe2_Components_DIR=$DIR/dependency/MARTe2-components +export TARGET=x86-linux +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MARTe2_DIR/Build/$TARGET/Core +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$MARTe2_Components_DIR/Build/$TARGET/Components +echo "MARTe2 Environment Set (MARTe2_DIR=$MARTe2_DIR)" +echo "MARTe2 Components Environment Set (MARTe2_Components_DIR=$MARTe2_Components_DIR)" diff --git a/run_test.sh b/run_test.sh new file mode 100755 index 0000000..d6b10f1 --- /dev/null +++ b/run_test.sh @@ -0,0 +1,21 @@ +#!/bin/bash +DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" >/dev/null 2>&1 && pwd)" +source $DIR/env.sh + +export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. +export MARTe2_DIR=/home/martino/Projects/marte_debug/dependency/MARTe2 +export TARGET=x86-linux + +MARTE_APP=$MARTe2_DIR/Build/$TARGET/App/MARTeApp.ex + +# Build paths for all components +LIBS=$DIR/Build +LIBS=$LIBS:$MARTe2_DIR/Build/$TARGET/Core +LIBS=$LIBS:$MARTe2_Components_DIR/Build/$TARGET/Components/DataSources/LinuxTimer +LIBS=$LIBS:$MARTe2_Components_DIR/Build/$TARGET/Components/DataSources/LoggerDataSource +LIBS=$LIBS:$MARTe2_Components_DIR/Build/$TARGET/Components/GAMs/IOGAM + +export LD_LIBRARY_PATH=$LIBS:$LD_LIBRARY_PATH + +# ./Build/Test/Integration/IntegrationTest -f Test/Configurations/debug_test.cfg -l RealTimeLoader -s State1 +$MARTE_APP -f $DIR/Test/Configurations/debug_test.cfg -l RealTimeLoader -s State1 diff --git a/specs.md b/specs.md new file mode 100644 index 0000000..f3a0f36 --- /dev/null +++ b/specs.md @@ -0,0 +1,41 @@ +Project Specification: MARTe2 Universal Observability & Debugging Suite + +Version: 1.1 + +Date: 2023-10-27 + +Status: Active / Implemented + +1. Executive Summary + +This project implements a "Zero-Code-Change" observability and debugging layer for the MARTe2 real-time framework. The system allows developers to Trace, Force, and Monitor any signal in a running MARTe2 application without modifying existing source code. + +2. System Architecture + +- The Universal Debug Service (C++ Core): A singleton MARTe2 Object that patches the registry and manages communication. +- The Broker Injection Layer (C++ Templates): Templated wrappers that intercept Copy() calls for tracing, forcing, and execution control. +- The Remote Analyser (Rust/egui): A high-performance, multi-threaded GUI for visualization and control. + +3. Functional Requirements + +3.1 Execution Control +- REQ-25: Execution Control (Pause/Resume): The system SHALL provide a mechanism to pause and resume the execution of all patched real-time threads (via Brokers), allowing for static inspection of the system state. + +3.2 Discovery +- REQ-24: Tree Exploration: The GUI client SHALL request the full application tree upon connection and display it in a hierarchical tree view. +- TREE Command: Returns a recursive JSON structure representing the entire application tree, including signal metadata (Type, Dimensions, Elements). + +3.3 Multi-Threaded Client (REQ-23) +- Port 8080 (TCP): Commands and Metadata. +- Port 8082 (TCP): Independent Real-Time Log Stream. +- Port 8081 (UDP): High-Speed Telemetry for Oscilloscope. + +4. Communication Protocol + +- LS [Path]: List nodes. +- TREE: Full recursive JSON application map. +- PAUSE / RESUME: Execution control. +- TRACE <1/0> [Decimation]: Telemetry control. +- FORCE : Persistent signal override. +- UNFORCE : Remove override. +- LOG : Port 8082 streaming format.