From 6edfb7376afc0fb55cf023838ae2068206a3bda8 Mon Sep 17 00:00:00 2001 From: Nav Date: Wed, 6 Oct 2021 21:12:31 +0100 Subject: [PATCH] Tidied structure of all classes within the entire code base Also some other small bits of tidying --- src/Application.cpp | 70 +- src/Application.hpp | 101 +- src/DebugServers/DebugServer.hpp | 89 +- .../GdbRsp/AvrGdbRsp/AvrGdbRsp.hpp | 24 +- .../CommandPackets/CommandPacketFactory.cpp | 90 +- .../CommandPackets/ContinueExecution.cpp | 8 +- .../CommandPackets/ContinueExecution.hpp | 6 +- .../GdbRsp/CommandPackets/ReadMemory.cpp | 8 +- .../GdbRsp/CommandPackets/ReadMemory.hpp | 6 +- .../GdbRsp/CommandPackets/ReadRegisters.cpp | 8 +- .../GdbRsp/CommandPackets/ReadRegisters.hpp | 6 +- .../CommandPackets/RemoveBreakpoint.cpp | 8 +- .../CommandPackets/RemoveBreakpoint.hpp | 6 +- .../GdbRsp/CommandPackets/SetBreakpoint.cpp | 8 +- .../GdbRsp/CommandPackets/SetBreakpoint.hpp | 6 +- .../GdbRsp/CommandPackets/StepExecution.cpp | 8 +- .../GdbRsp/CommandPackets/StepExecution.hpp | 6 +- .../CommandPackets/SupportedFeaturesQuery.cpp | 8 +- .../CommandPackets/SupportedFeaturesQuery.hpp | 10 +- .../GdbRsp/CommandPackets/WriteMemory.cpp | 8 +- .../GdbRsp/CommandPackets/WriteMemory.hpp | 6 +- .../GdbRsp/CommandPackets/WriteRegister.cpp | 8 +- .../GdbRsp/CommandPackets/WriteRegister.hpp | 6 +- src/DebugServers/GdbRsp/Connection.cpp | 110 +- src/DebugServers/GdbRsp/Connection.hpp | 106 +- src/DebugServers/GdbRsp/GdbRspDebugServer.cpp | 388 +++--- src/DebugServers/GdbRsp/GdbRspDebugServer.hpp | 174 +-- src/DebugServers/GdbRsp/Packet.hpp | 22 +- .../GdbRsp/ResponsePackets/Ok.hpp | 2 - .../SupportedFeaturesResponse.hpp | 6 +- src/DebugToolDrivers/DebugTool.hpp | 24 +- .../Microchip/AtmelICE/AtmelIce.hpp | 38 +- .../Microchip/MplabSnap/MplabSnap.hpp | 22 +- .../Microchip/PowerDebugger/PowerDebugger.hpp | 36 +- .../Protocols/CMSIS-DAP/CmsisDapInterface.cpp | 2 - .../Protocols/CMSIS-DAP/CmsisDapInterface.hpp | 42 +- .../Protocols/CMSIS-DAP/Command.hpp | 10 +- .../Protocols/CMSIS-DAP/Response.hpp | 29 +- .../VendorSpecific/EDBG/AVR/AvrCommand.hpp | 12 +- .../VendorSpecific/EDBG/AVR/AvrEvent.cpp | 6 +- .../VendorSpecific/EDBG/AVR/AvrEvent.hpp | 19 +- .../VendorSpecific/EDBG/AVR/AvrResponse.cpp | 2 - .../VendorSpecific/EDBG/AVR/AvrResponse.hpp | 38 +- .../EDBG/AVR/AvrResponseCommand.hpp | 2 + .../AVR8Generic/ActivatePhysical.hpp | 6 +- .../AVR/CommandFrames/AVR8Generic/Attach.hpp | 6 +- .../ClearAllSoftwareBreakpoints.hpp | 10 +- .../AVR8Generic/ClearSoftwareBreakpoints.hpp | 6 +- .../AVR8Generic/DeactivatePhysical.hpp | 10 +- .../AVR/CommandFrames/AVR8Generic/Detach.hpp | 10 +- .../AVR8Generic/DisableDebugWire.hpp | 10 +- .../CommandFrames/AVR8Generic/GetDeviceId.hpp | 14 +- .../AVR8Generic/GetParameter.hpp | 8 +- .../AVR8Generic/GetProgramCounter.hpp | 14 +- .../CommandFrames/AVR8Generic/ReadMemory.hpp | 12 +- .../AVR/CommandFrames/AVR8Generic/Reset.hpp | 6 +- .../AVR/CommandFrames/AVR8Generic/Run.hpp | 10 +- .../AVR/CommandFrames/AVR8Generic/RunTo.hpp | 6 +- .../AVR8Generic/SetParameter.hpp | 8 +- .../AVR8Generic/SetProgramCounter.hpp | 6 +- .../AVR8Generic/SetSoftwareBreakpoints.hpp | 6 +- .../SetXmegaSoftwareBreakpoint.hpp | 6 +- .../AVR/CommandFrames/AVR8Generic/Stop.hpp | 6 +- .../CommandFrames/AVR8Generic/WriteMemory.hpp | 10 +- .../AVR/CommandFrames/AvrCommandFrame.hpp | 36 +- .../AVR/CommandFrames/Discovery/Query.hpp | 6 +- .../CommandFrames/HouseKeeping/EndSession.hpp | 10 +- .../HouseKeeping/StartSession.hpp | 10 +- .../EDBG/AVR/EdbgAvr8Interface.cpp | 1214 ++++++++--------- .../EDBG/AVR/EdbgAvr8Interface.hpp | 384 +++--- .../AVR/Events/AVR8Generic/BreakEvent.cpp | 2 - .../AVR/Events/AVR8Generic/BreakEvent.hpp | 12 +- .../AVR/Exceptions/Avr8CommandFailure.hpp | 42 +- .../AVR8Generic/GetDeviceId.hpp | 1 + .../AVR8Generic/GetProgramCounter.hpp | 1 - .../AVR/ResponseFrames/AvrResponseFrame.cpp | 2 - .../AVR/ResponseFrames/AvrResponseFrame.hpp | 68 +- .../VendorSpecific/EDBG/EdbgInterface.cpp | 2 - .../VendorSpecific/EDBG/EdbgInterface.hpp | 10 +- src/DebugToolDrivers/USB/HID/HidInterface.cpp | 99 +- src/DebugToolDrivers/USB/HID/HidInterface.hpp | 96 +- src/DebugToolDrivers/USB/Interface.hpp | 26 +- src/DebugToolDrivers/USB/UsbDevice.cpp | 103 +- src/DebugToolDrivers/USB/UsbDevice.hpp | 32 +- src/EventManager/EventListener.cpp | 90 +- src/EventManager/EventListener.hpp | 71 +- src/EventManager/EventManager.hpp | 14 +- .../Events/DebugServerThreadStateChanged.hpp | 5 +- src/EventManager/Events/Event.hpp | 6 +- .../Events/InsightThreadStateChanged.hpp | 6 +- .../TargetControllerThreadStateChanged.hpp | 6 +- src/Exceptions/Exception.hpp | 6 +- src/Helpers/BiMap.hpp | 8 +- src/Helpers/DateTime.hpp | 6 +- src/Helpers/EventNotifier.hpp | 40 +- src/Helpers/SyncSafe.hpp | 8 +- src/Helpers/Thread.hpp | 12 +- src/Insight/InsightWorker/InsightWorker.cpp | 39 +- src/Insight/InsightWorker/InsightWorker.hpp | 45 +- .../InsightWorker/Tasks/InsightWorkerTask.cpp | 2 + .../InsightWorker/Tasks/InsightWorkerTask.hpp | 7 +- .../Tasks/ReadTargetRegisters.hpp | 13 +- .../Tasks/RefreshTargetPinStates.hpp | 13 +- .../InsightWorker/Tasks/SetTargetPinState.hpp | 15 +- .../Tasks/WriteTargetRegister.hpp | 13 +- .../InsightWindow/AboutWindow.cpp | 7 +- .../InsightWindow/AboutWindow.hpp | 7 +- .../InsightWindow/InsightWindow.cpp | 218 +-- .../InsightWindow/InsightWindow.hpp | 65 +- .../UserInterfaces/InsightWindow/UiLoader.cpp | 3 +- .../UserInterfaces/InsightWindow/UiLoader.hpp | 10 +- .../InsightWindow/Widgets/ClickableWidget.hpp | 8 +- .../Widgets/ErrorDialogue/ErrorDialogue.cpp | 2 +- .../Widgets/ErrorDialogue/ErrorDialogue.hpp | 10 +- .../ExpandingHeightScrollAreaWidget.hpp | 10 +- .../InsightWindow/Widgets/PanelWidget.cpp | 28 +- .../InsightWindow/Widgets/PanelWidget.hpp | 38 +- .../InsightWindow/Widgets/RotatableLabel.hpp | 24 +- .../InsightWindow/Widgets/SvgToolButton.hpp | 13 +- .../InsightWindow/Widgets/SvgWidget.hpp | 25 +- .../BitsetWidget/BitBodyWidget.cpp | 22 +- .../BitsetWidget/BitBodyWidget.hpp | 25 +- .../BitsetWidget/BitWidget.cpp | 1 - .../BitsetWidget/BitWidget.hpp | 24 +- .../BitsetWidget/BitsetWidget.cpp | 10 +- .../BitsetWidget/BitsetWidget.hpp | 25 +- .../RegisterHistoryWidget/CurrentItem.hpp | 8 +- .../RegisterHistoryWidget/Item.hpp | 2 +- .../RegisterHistoryItem.hpp | 12 +- .../RegisterHistoryWidget.cpp | 2 +- .../RegisterHistoryWidget.hpp | 41 +- .../TargetRegisterInspectorWindow.cpp | 3 - .../TargetRegisterInspectorWindow.hpp | 29 +- .../TargetRegistersPane/ItemWidget.hpp | 7 +- .../RegisterGroupWidget.hpp | 17 +- .../TargetRegistersPane/RegisterWidget.cpp | 58 +- .../TargetRegistersPane/RegisterWidget.hpp | 49 +- .../TargetRegistersPaneWidget.cpp | 98 +- .../TargetRegistersPaneWidget.hpp | 58 +- .../Widgets/TargetWidgets/DIP/BodyWidget.cpp | 4 +- .../Widgets/TargetWidgets/DIP/BodyWidget.hpp | 24 +- .../DIP/DualInlinePackageWidget.cpp | 3 - .../DIP/DualInlinePackageWidget.hpp | 14 +- .../TargetWidgets/DIP/PinBodyWidget.cpp | 9 +- .../TargetWidgets/DIP/PinBodyWidget.hpp | 12 +- .../Widgets/TargetWidgets/DIP/PinWidget.cpp | 8 - .../Widgets/TargetWidgets/DIP/PinWidget.hpp | 31 +- .../Widgets/TargetWidgets/QFP/BodyWidget.cpp | 5 +- .../Widgets/TargetWidgets/QFP/BodyWidget.hpp | 24 +- .../TargetWidgets/QFP/PinBodyWidget.cpp | 4 +- .../TargetWidgets/QFP/PinBodyWidget.hpp | 15 +- .../Widgets/TargetWidgets/QFP/PinWidget.cpp | 1 - .../Widgets/TargetWidgets/QFP/PinWidget.hpp | 29 +- .../QFP/QuadFlatPackageWidget.cpp | 1 - .../QFP/QuadFlatPackageWidget.hpp | 17 +- .../TargetWidgets/TargetPackageWidget.hpp | 25 +- .../TargetPackageWidgetContainer.cpp | 16 +- .../TargetPackageWidgetContainer.hpp | 13 +- .../TargetWidgets/TargetPinBodyWidget.cpp | 44 +- .../TargetWidgets/TargetPinBodyWidget.hpp | 54 +- .../Widgets/TargetWidgets/TargetPinWidget.hpp | 17 +- src/Logger/Logger.cpp | 29 +- src/Logger/Logger.hpp | 36 +- src/SignalHandler/SignalHandler.cpp | 50 +- src/SignalHandler/SignalHandler.hpp | 30 +- src/TargetController/TargetController.cpp | 161 +-- src/TargetController/TargetController.hpp | 102 +- .../TargetControllerConsole.cpp | 2 - .../TargetControllerConsole.hpp | 144 +- src/Targets/Microchip/AVR/AVR8/Avr8.cpp | 229 ++-- src/Targets/Microchip/AVR/AVR8/Avr8.hpp | 70 +- src/Targets/Microchip/AVR/AVR8/Mega/Mega.hpp | 2 - .../TargetDescriptionFile.cpp | 36 +- .../TargetDescriptionFile.hpp | 170 ++- src/Targets/Microchip/AVR/Target.hpp | 15 +- src/Targets/Target.hpp | 20 +- .../TargetDescriptionFile.cpp | 8 +- .../TargetDescriptionFile.hpp | 148 +- src/Targets/TargetRegister.hpp | 13 +- 179 files changed, 3446 insertions(+), 3493 deletions(-) diff --git a/src/Application.cpp b/src/Application.cpp index 2262ea0d..5895382b 100644 --- a/src/Application.cpp +++ b/src/Application.cpp @@ -81,6 +81,10 @@ int Application::run(const std::vector& arguments) { return EXIT_SUCCESS; } +bool Application::isRunningAsRoot() { + return geteuid() == 0; +} + void Application::startup() { auto applicationEventListener = this->applicationEventListener; this->eventManager.registerListener(applicationEventListener); @@ -131,6 +135,37 @@ void Application::startup() { Thread::setThreadState(ThreadState::READY); } +void Application::shutdown() { + auto appState = Thread::getThreadState(); + if (appState == ThreadState::STOPPED || appState == ThreadState::SHUTDOWN_INITIATED) { + return; + } + + Thread::setThreadState(ThreadState::SHUTDOWN_INITIATED); + Logger::info("Shutting down Bloom"); + + this->stopDebugServer(); + this->stopTargetController(); + + if (this->signalHandler.getThreadState() != ThreadState::STOPPED + && this->signalHandler.getThreadState() != ThreadState::UNINITIALISED + ) { + // Signal handler is still running + this->signalHandler.triggerShutdown(); + + // Send meaningless signal to the SignalHandler thread to have it shutdown. + pthread_kill(this->signalHandlerThread.native_handle(), SIGUSR1); + } + + if (this->signalHandlerThread.joinable()) { + Logger::debug("Joining SignalHandler thread"); + this->signalHandlerThread.join(); + Logger::debug("SignalHandler thread joined"); + } + + Thread::setThreadState(ThreadState::STOPPED); +} + ApplicationConfig Application::extractConfig() { auto appConfig = ApplicationConfig(); auto currentPath = std::filesystem::current_path().string(); @@ -227,37 +262,6 @@ int Application::initProject() { return EXIT_SUCCESS; } -void Application::shutdown() { - auto appState = Thread::getThreadState(); - if (appState == ThreadState::STOPPED || appState == ThreadState::SHUTDOWN_INITIATED) { - return; - } - - Thread::setThreadState(ThreadState::SHUTDOWN_INITIATED); - Logger::info("Shutting down Bloom"); - - this->stopDebugServer(); - this->stopTargetController(); - - if (this->signalHandler.getThreadState() != ThreadState::STOPPED - && this->signalHandler.getThreadState() != ThreadState::UNINITIALISED - ) { - // Signal handler is still running - this->signalHandler.triggerShutdown(); - - // Send meaningless signal to the SignalHandler thread to have it shutdown. - pthread_kill(this->signalHandlerThread.native_handle(), SIGUSR1); - } - - if (this->signalHandlerThread.joinable()) { - Logger::debug("Joining SignalHandler thread"); - this->signalHandlerThread.join(); - Logger::debug("SignalHandler thread joined"); - } - - Thread::setThreadState(ThreadState::STOPPED); -} - void Application::startTargetController() { this->targetController.setApplicationConfig(this->applicationConfig); this->targetController.setEnvironmentConfig(this->environmentConfig); @@ -354,7 +358,3 @@ void Application::onDebugServerThreadStateChanged(const Events::DebugServerThrea this->shutdown(); } } - -bool Application::isRunningAsRoot() { - return geteuid() == 0; -} diff --git a/src/Application.hpp b/src/Application.hpp index 730c825c..6161b572 100644 --- a/src/Application.hpp +++ b/src/Application.hpp @@ -31,6 +31,44 @@ namespace Bloom public: static const inline std::string VERSION_STR = "0.4.2"; + explicit Application() = default; + + /** + * This mapping is used to map debug server names from project configuration files to polymorphic instances of + * the DebugServer class. + * + * See Application::startDebugServer() for more on this. + * + * @return + */ + auto getSupportedDebugServers() { + return std::map()>> { + { + "avr-gdb-rsp", + [this]() -> std::unique_ptr { + return std::make_unique(this->eventManager); + } + }, + }; + }; + + /** + * Main entry-point for the Bloom program. + * + * @param arguments + * A vector of string arguments passed from the user via the cli. + * + * @return + */ + int run(const std::vector& arguments); + + /** + * Checks if the current effective user running Bloom has root privileges. + * + * @return + */ + static bool isRunningAsRoot(); + private: /** * This is the application wide event manager. It should be the only instance of the EventManager class at @@ -139,6 +177,18 @@ namespace Bloom }; } + /** + * Kicks off the application. + * + * Will start the TargetController and DebugServer. And register the main application's event handlers. + */ + void startup(); + + /** + * Will cleanly shutdown the application. This should never fail. + */ + void shutdown(); + /** * Extracts config from the user's JSON config file and generates an ApplicationConfig object. * @@ -168,18 +218,6 @@ namespace Bloom */ int initProject(); - /** - * Kicks off the application. - * - * Will start the TargetController and DebugServer. And register the main application's event handlers. - */ - void startup(); - - /** - * Will cleanly shutdown the application. This should never fail. - */ - void shutdown(); - /** * Prepares a dedicated thread for the TargetController and kicks it off. */ @@ -203,38 +241,6 @@ namespace Bloom */ void stopDebugServer(); - public: - explicit Application() = default; - - /** - * This mapping is used to map debug server names from project configuration files to polymorphic instances of - * the DebugServer class. - * - * See Application::startDebugServer() for more on this. - * - * @return - */ - auto getSupportedDebugServers() { - return std::map()>> { - { - "avr-gdb-rsp", - [this]() -> std::unique_ptr { - return std::make_unique(this->eventManager); - } - }, - }; - }; - - /** - * Main entry-point for the Bloom program. - * - * @param arguments - * A vector of string arguments passed from the user via the cli. - * - * @return - */ - int run(const std::vector& arguments); - /** * If the TargetController unexpectedly shuts down, the rest of the application will follow. * @@ -254,12 +260,5 @@ namespace Bloom * Triggers a shutdown of Bloom and all of its components. */ void onShutdownApplicationRequest(const Events::ShutdownApplication&); - - /** - * Checks if the current effective user running Bloom has root privileges. - * - * @return - */ - static bool isRunningAsRoot(); }; } diff --git a/src/DebugServers/DebugServer.hpp b/src/DebugServers/DebugServer.hpp index 42eaf04a..76adedfb 100644 --- a/src/DebugServers/DebugServer.hpp +++ b/src/DebugServers/DebugServer.hpp @@ -27,40 +27,28 @@ namespace Bloom::DebugServers */ class DebugServer: public Thread { - private: - /** - * Prepares the debug server thread and then calls init(). - * - * Derived classes should not override this method - they should instead use init(). - */ - void startup(); + public: + explicit DebugServer(EventManager& eventManager): eventManager(eventManager) {}; + virtual ~DebugServer() = default; - /** - * Calls close() and updates the thread state. - * - * As with startup(), derived classes should not override this method. They should use close() instead. - */ - void shutdown(); + void setApplicationConfig(const ApplicationConfig& applicationConfig) { + this->applicationConfig = applicationConfig; + } - /** - * Updates the state of the DebugServer and emits a state changed event. - * - * @param state - * @param emitEvent - */ - void setThreadStateAndEmitEvent(ThreadState state) { - Thread::setThreadState(state); - this->eventManager.triggerEvent( - std::make_shared(state) - ); + void setEnvironmentConfig(const EnvironmentConfig& environmentConfig) { + this->environmentConfig = environmentConfig; + } + + void setDebugServerConfig(const DebugServerConfig& debugServerConfig) { + this->debugServerConfig = debugServerConfig; } /** - * Handles a shutdown request. - * - * @param event + * Entry point for the DebugServer. This must called from a dedicated thread. */ - void onShutdownDebugServerEvent(const Events::ShutdownDebugServer& event); + void run(); + + virtual std::string getName() const = 0; protected: /** @@ -100,28 +88,39 @@ namespace Bloom::DebugServers */ virtual void close() = 0; - public: - explicit DebugServer(EventManager& eventManager): eventManager(eventManager) {}; + private: + /** + * Prepares the debug server thread and then calls init(). + * + * Derived classes should not override this method - they should instead use init(). + */ + void startup(); - void setApplicationConfig(const ApplicationConfig& applicationConfig) { - this->applicationConfig = applicationConfig; - } + /** + * Calls close() and updates the thread state. + * + * As with startup(), derived classes should not override this method. They should use close() instead. + */ + void shutdown(); - void setEnvironmentConfig(const EnvironmentConfig& environmentConfig) { - this->environmentConfig = environmentConfig; - } - - void setDebugServerConfig(const DebugServerConfig& debugServerConfig) { - this->debugServerConfig = debugServerConfig; + /** + * Updates the state of the DebugServer and emits a state changed event. + * + * @param state + * @param emitEvent + */ + void setThreadStateAndEmitEvent(ThreadState state) { + Thread::setThreadState(state); + this->eventManager.triggerEvent( + std::make_shared(state) + ); } /** - * Entry point for the DebugServer. This must called from a dedicated thread. + * Handles a shutdown request. + * + * @param event */ - void run(); - - virtual std::string getName() const = 0; - - virtual ~DebugServer() = default; + void onShutdownDebugServerEvent(const Events::ShutdownDebugServer& event); }; } diff --git a/src/DebugServers/GdbRsp/AvrGdbRsp/AvrGdbRsp.hpp b/src/DebugServers/GdbRsp/AvrGdbRsp/AvrGdbRsp.hpp index 5059d793..63342b52 100644 --- a/src/DebugServers/GdbRsp/AvrGdbRsp/AvrGdbRsp.hpp +++ b/src/DebugServers/GdbRsp/AvrGdbRsp/AvrGdbRsp.hpp @@ -25,14 +25,12 @@ namespace Bloom::DebugServers::Gdb */ class AvrGdbRsp: public GdbRspDebugServer { - private: - /** - * The mask used by the AVR GDB client to encode the memory type into memory addresses. - * See AvrGdbRsp::getMemoryTypeFromGdbAddress() for more. - */ - unsigned int gdbInternalMemoryMask = 0xFE0000u; + public: + explicit AvrGdbRsp(EventManager& eventManager): GdbRspDebugServer(eventManager) {}; - BiMap registerNumberToDescriptorMapping = {}; + std::string getName() const override { + return "AVR GDB Remote Serial Protocol Debug Server"; + } protected: /** @@ -80,11 +78,13 @@ namespace Bloom::DebugServers::Gdb void init() override; - public: - explicit AvrGdbRsp(EventManager& eventManager): GdbRspDebugServer(eventManager) {}; + private: + /** + * The mask used by the AVR GDB client to encode the memory type into memory addresses. + * See AvrGdbRsp::getMemoryTypeFromGdbAddress() for more. + */ + unsigned int gdbInternalMemoryMask = 0xFE0000u; - std::string getName() const override { - return "AVR GDB Remote Serial Protocol Debug Server"; - } + BiMap registerNumberToDescriptorMapping = {}; }; } diff --git a/src/DebugServers/GdbRsp/CommandPackets/CommandPacketFactory.cpp b/src/DebugServers/GdbRsp/CommandPackets/CommandPacketFactory.cpp index f239b7ff..973b358c 100644 --- a/src/DebugServers/GdbRsp/CommandPackets/CommandPacketFactory.cpp +++ b/src/DebugServers/GdbRsp/CommandPackets/CommandPacketFactory.cpp @@ -7,51 +7,6 @@ using namespace Bloom::DebugServers::Gdb; using namespace Bloom::DebugServers::Gdb::CommandPackets; -std::unique_ptr CommandPacketFactory::create(std::vector rawPacket) { - if (rawPacket.size() == 5 && rawPacket[1] == 0x03) { - // This is an interrupt request - create a fake packet for it - return std::make_unique(rawPacket); - } - - auto rawPacketString = std::string(rawPacket.begin(), rawPacket.end()); - - if (rawPacketString.size() >= 2) { - /* - * First byte of the raw packet will be 0x24 ('$'), so find() should return 1, not 0, when - * looking for a command identifier string. - */ - if (rawPacketString.find("qSupported") == 1) { - return std::make_unique(rawPacket); - - } else if (rawPacketString[1] == 'g' || rawPacketString[1] == 'p') { - return std::make_unique(rawPacket); - - } else if (rawPacketString[1] == 'P') { - return std::make_unique(rawPacket); - - } else if (rawPacketString[1] == 'c') { - return std::make_unique(rawPacket); - - } else if (rawPacketString[1] == 's') { - return std::make_unique(rawPacket); - - } else if (rawPacketString[1] == 'm') { - return std::make_unique(rawPacket); - - } else if (rawPacketString[1] == 'M') { - return std::make_unique(rawPacket); - - } else if (rawPacketString[1] == 'Z') { - return std::make_unique(rawPacket); - - } else if (rawPacketString[1] == 'z') { - return std::make_unique(rawPacket); - } - } - - return std::make_unique(rawPacket); -} - std::vector> CommandPacketFactory::extractRawPackets(std::vector buffer) { std::vector> output; @@ -127,3 +82,48 @@ std::vector> CommandPacketFactory::extractRawPackets( return output; } + +std::unique_ptr CommandPacketFactory::create(std::vector rawPacket) { + if (rawPacket.size() == 5 && rawPacket[1] == 0x03) { + // This is an interrupt request - create a fake packet for it + return std::make_unique(rawPacket); + } + + auto rawPacketString = std::string(rawPacket.begin(), rawPacket.end()); + + if (rawPacketString.size() >= 2) { + /* + * First byte of the raw packet will be 0x24 ('$'), so find() should return 1, not 0, when + * looking for a command identifier string. + */ + if (rawPacketString.find("qSupported") == 1) { + return std::make_unique(rawPacket); + + } else if (rawPacketString[1] == 'g' || rawPacketString[1] == 'p') { + return std::make_unique(rawPacket); + + } else if (rawPacketString[1] == 'P') { + return std::make_unique(rawPacket); + + } else if (rawPacketString[1] == 'c') { + return std::make_unique(rawPacket); + + } else if (rawPacketString[1] == 's') { + return std::make_unique(rawPacket); + + } else if (rawPacketString[1] == 'm') { + return std::make_unique(rawPacket); + + } else if (rawPacketString[1] == 'M') { + return std::make_unique(rawPacket); + + } else if (rawPacketString[1] == 'Z') { + return std::make_unique(rawPacket); + + } else if (rawPacketString[1] == 'z') { + return std::make_unique(rawPacket); + } + } + + return std::make_unique(rawPacket); +} diff --git a/src/DebugServers/GdbRsp/CommandPackets/ContinueExecution.cpp b/src/DebugServers/GdbRsp/CommandPackets/ContinueExecution.cpp index b1bbcd3e..ef9d882b 100644 --- a/src/DebugServers/GdbRsp/CommandPackets/ContinueExecution.cpp +++ b/src/DebugServers/GdbRsp/CommandPackets/ContinueExecution.cpp @@ -6,6 +6,10 @@ using namespace Bloom::DebugServers::Gdb::CommandPackets; +void ContinueExecution::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) { + gdbRspDebugServer.handleGdbPacket(*this); +} + void ContinueExecution::init() { if (this->data.size() > 1) { this->fromProgramCounter = static_cast( @@ -13,7 +17,3 @@ void ContinueExecution::init() { ); } } - -void ContinueExecution::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) { - gdbRspDebugServer.handleGdbPacket(*this); -} diff --git a/src/DebugServers/GdbRsp/CommandPackets/ContinueExecution.hpp b/src/DebugServers/GdbRsp/CommandPackets/ContinueExecution.hpp index 68aef7e8..df248abb 100644 --- a/src/DebugServers/GdbRsp/CommandPackets/ContinueExecution.hpp +++ b/src/DebugServers/GdbRsp/CommandPackets/ContinueExecution.hpp @@ -15,9 +15,6 @@ namespace Bloom::DebugServers::Gdb::CommandPackets */ class ContinueExecution: public CommandPacket { - private: - void init(); - public: /** * The "c" packet can contain an address which defines the point from which the execution should be resumed on @@ -32,5 +29,8 @@ namespace Bloom::DebugServers::Gdb::CommandPackets } void dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) override; + + private: + void init(); }; } diff --git a/src/DebugServers/GdbRsp/CommandPackets/ReadMemory.cpp b/src/DebugServers/GdbRsp/CommandPackets/ReadMemory.cpp index e3043e76..77f4802d 100644 --- a/src/DebugServers/GdbRsp/CommandPackets/ReadMemory.cpp +++ b/src/DebugServers/GdbRsp/CommandPackets/ReadMemory.cpp @@ -5,6 +5,10 @@ using namespace Bloom::DebugServers::Gdb::CommandPackets; using namespace Bloom::Exceptions; +void ReadMemory::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) { + gdbRspDebugServer.handleGdbPacket(*this); +} + void ReadMemory::init() { if (this->data.size() < 4) { throw Exception("Invalid packet length"); @@ -38,7 +42,3 @@ void ReadMemory::init() { throw Exception("Failed to parse read length from read memory packet data"); } } - -void ReadMemory::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) { - gdbRspDebugServer.handleGdbPacket(*this); -} diff --git a/src/DebugServers/GdbRsp/CommandPackets/ReadMemory.hpp b/src/DebugServers/GdbRsp/CommandPackets/ReadMemory.hpp index 3f46016c..a517b2a3 100644 --- a/src/DebugServers/GdbRsp/CommandPackets/ReadMemory.hpp +++ b/src/DebugServers/GdbRsp/CommandPackets/ReadMemory.hpp @@ -13,9 +13,6 @@ namespace Bloom::DebugServers::Gdb::CommandPackets */ class ReadMemory: public CommandPacket { - private: - void init(); - public: /** * The startAddress sent from the GDB client may include additional bits used to indicate the memory type. @@ -36,5 +33,8 @@ namespace Bloom::DebugServers::Gdb::CommandPackets }; void dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) override; + + private: + void init(); }; } diff --git a/src/DebugServers/GdbRsp/CommandPackets/ReadRegisters.cpp b/src/DebugServers/GdbRsp/CommandPackets/ReadRegisters.cpp index 31aa86a9..9326a7c7 100644 --- a/src/DebugServers/GdbRsp/CommandPackets/ReadRegisters.cpp +++ b/src/DebugServers/GdbRsp/CommandPackets/ReadRegisters.cpp @@ -4,13 +4,13 @@ using namespace Bloom::DebugServers::Gdb::CommandPackets; +void ReadRegisters::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) { + gdbRspDebugServer.handleGdbPacket(*this); +} + void ReadRegisters::init() { if (this->data.size() >= 2 && this->data.front() == 'p') { // This command packet is requesting a specific register this->registerNumber = static_cast(std::stoi(std::string(this->data.begin() + 1, this->data.end()))); } } - -void ReadRegisters::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) { - gdbRspDebugServer.handleGdbPacket(*this); -} diff --git a/src/DebugServers/GdbRsp/CommandPackets/ReadRegisters.hpp b/src/DebugServers/GdbRsp/CommandPackets/ReadRegisters.hpp index 22d576bc..20055bbe 100644 --- a/src/DebugServers/GdbRsp/CommandPackets/ReadRegisters.hpp +++ b/src/DebugServers/GdbRsp/CommandPackets/ReadRegisters.hpp @@ -13,9 +13,6 @@ namespace Bloom::DebugServers::Gdb::CommandPackets */ class ReadRegisters: public CommandPacket { - private: - void init(); - public: /** * "p" packets include a register number to indicate which register is requested for reading. When this is set, @@ -31,5 +28,8 @@ namespace Bloom::DebugServers::Gdb::CommandPackets }; void dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) override; + + private: + void init(); }; } diff --git a/src/DebugServers/GdbRsp/CommandPackets/RemoveBreakpoint.cpp b/src/DebugServers/GdbRsp/CommandPackets/RemoveBreakpoint.cpp index fe7b8e7c..22a21699 100644 --- a/src/DebugServers/GdbRsp/CommandPackets/RemoveBreakpoint.cpp +++ b/src/DebugServers/GdbRsp/CommandPackets/RemoveBreakpoint.cpp @@ -7,6 +7,10 @@ using namespace Bloom::DebugServers::Gdb::CommandPackets; using namespace Bloom::Exceptions; +void RemoveBreakpoint::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) { + gdbRspDebugServer.handleGdbPacket(*this); +} + void RemoveBreakpoint::init() { if (data.size() < 6) { throw Exception("Unexpected RemoveBreakpoint packet size"); @@ -33,7 +37,3 @@ void RemoveBreakpoint::init() { throw Exception("Failed to convert address hex value from RemoveBreakpoint packet."); } } - -void RemoveBreakpoint::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) { - gdbRspDebugServer.handleGdbPacket(*this); -} diff --git a/src/DebugServers/GdbRsp/CommandPackets/RemoveBreakpoint.hpp b/src/DebugServers/GdbRsp/CommandPackets/RemoveBreakpoint.hpp index b27e4b53..94fee821 100644 --- a/src/DebugServers/GdbRsp/CommandPackets/RemoveBreakpoint.hpp +++ b/src/DebugServers/GdbRsp/CommandPackets/RemoveBreakpoint.hpp @@ -20,9 +20,6 @@ namespace Bloom::DebugServers::Gdb::CommandPackets */ class RemoveBreakpoint: public CommandPacket { - private: - void init(); - public: /** * Breakpoint type (Software or Hardware) @@ -39,5 +36,8 @@ namespace Bloom::DebugServers::Gdb::CommandPackets }; void dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) override; + + private: + void init(); }; } diff --git a/src/DebugServers/GdbRsp/CommandPackets/SetBreakpoint.cpp b/src/DebugServers/GdbRsp/CommandPackets/SetBreakpoint.cpp index 47da012e..0c1e32c1 100644 --- a/src/DebugServers/GdbRsp/CommandPackets/SetBreakpoint.cpp +++ b/src/DebugServers/GdbRsp/CommandPackets/SetBreakpoint.cpp @@ -8,6 +8,10 @@ using namespace Bloom::DebugServers::Gdb::CommandPackets; using namespace Bloom::Exceptions; +void SetBreakpoint::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) { + gdbRspDebugServer.handleGdbPacket(*this); +} + void SetBreakpoint::init() { if (data.size() < 6) { throw Exception("Unexpected SetBreakpoint packet size"); @@ -34,7 +38,3 @@ void SetBreakpoint::init() { throw Exception("Failed to convert address hex value from SetBreakpoint packet."); } } - -void SetBreakpoint::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) { - gdbRspDebugServer.handleGdbPacket(*this); -} diff --git a/src/DebugServers/GdbRsp/CommandPackets/SetBreakpoint.hpp b/src/DebugServers/GdbRsp/CommandPackets/SetBreakpoint.hpp index 9fc070c2..3465317e 100644 --- a/src/DebugServers/GdbRsp/CommandPackets/SetBreakpoint.hpp +++ b/src/DebugServers/GdbRsp/CommandPackets/SetBreakpoint.hpp @@ -20,9 +20,6 @@ namespace Bloom::DebugServers::Gdb::CommandPackets */ class SetBreakpoint: public CommandPacket { - private: - void init(); - public: /** * Breakpoint type (Software or Hardware) @@ -39,5 +36,8 @@ namespace Bloom::DebugServers::Gdb::CommandPackets }; void dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) override; + + private: + void init(); }; } diff --git a/src/DebugServers/GdbRsp/CommandPackets/StepExecution.cpp b/src/DebugServers/GdbRsp/CommandPackets/StepExecution.cpp index 626f9900..2935d15a 100644 --- a/src/DebugServers/GdbRsp/CommandPackets/StepExecution.cpp +++ b/src/DebugServers/GdbRsp/CommandPackets/StepExecution.cpp @@ -5,6 +5,10 @@ using namespace Bloom::DebugServers::Gdb::CommandPackets; +void StepExecution::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) { + gdbRspDebugServer.handleGdbPacket(*this); +} + void StepExecution::init() { if (this->data.size() > 1) { this->fromProgramCounter = static_cast( @@ -12,7 +16,3 @@ void StepExecution::init() { ); } } - -void StepExecution::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) { - gdbRspDebugServer.handleGdbPacket(*this); -} diff --git a/src/DebugServers/GdbRsp/CommandPackets/StepExecution.hpp b/src/DebugServers/GdbRsp/CommandPackets/StepExecution.hpp index 3b6502ff..96166b8b 100644 --- a/src/DebugServers/GdbRsp/CommandPackets/StepExecution.hpp +++ b/src/DebugServers/GdbRsp/CommandPackets/StepExecution.hpp @@ -12,9 +12,6 @@ namespace Bloom::DebugServers::Gdb::CommandPackets */ class StepExecution: public CommandPacket { - private: - void init(); - public: /** * The address from which to begin the step. @@ -26,5 +23,8 @@ namespace Bloom::DebugServers::Gdb::CommandPackets }; void dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) override; + + private: + void init(); }; } diff --git a/src/DebugServers/GdbRsp/CommandPackets/SupportedFeaturesQuery.cpp b/src/DebugServers/GdbRsp/CommandPackets/SupportedFeaturesQuery.cpp index db193158..760b4087 100644 --- a/src/DebugServers/GdbRsp/CommandPackets/SupportedFeaturesQuery.cpp +++ b/src/DebugServers/GdbRsp/CommandPackets/SupportedFeaturesQuery.cpp @@ -6,6 +6,10 @@ using namespace Bloom::DebugServers::Gdb::CommandPackets; +void SupportedFeaturesQuery::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) { + gdbRspDebugServer.handleGdbPacket(*this); +} + void SupportedFeaturesQuery::init() { /* * For qSupported packets, supported and unsupported GDB features are reported in the packet @@ -37,7 +41,3 @@ void SupportedFeaturesQuery::init() { } } } - -void SupportedFeaturesQuery::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) { - gdbRspDebugServer.handleGdbPacket(*this); -} diff --git a/src/DebugServers/GdbRsp/CommandPackets/SupportedFeaturesQuery.hpp b/src/DebugServers/GdbRsp/CommandPackets/SupportedFeaturesQuery.hpp index 641ebb48..bebae6b5 100644 --- a/src/DebugServers/GdbRsp/CommandPackets/SupportedFeaturesQuery.hpp +++ b/src/DebugServers/GdbRsp/CommandPackets/SupportedFeaturesQuery.hpp @@ -21,11 +21,6 @@ namespace Bloom::DebugServers::Gdb::CommandPackets */ class SupportedFeaturesQuery: public CommandPacket { - private: - std::set supportedFeatures; - - void init(); - public: explicit SupportedFeaturesQuery(const std::vector& rawPacket): CommandPacket(rawPacket) { this->init(); @@ -40,5 +35,10 @@ namespace Bloom::DebugServers::Gdb::CommandPackets } void dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) override; + + private: + std::set supportedFeatures; + + void init(); }; } diff --git a/src/DebugServers/GdbRsp/CommandPackets/WriteMemory.cpp b/src/DebugServers/GdbRsp/CommandPackets/WriteMemory.cpp index 3bcb9ab7..8e3214c5 100644 --- a/src/DebugServers/GdbRsp/CommandPackets/WriteMemory.cpp +++ b/src/DebugServers/GdbRsp/CommandPackets/WriteMemory.cpp @@ -5,6 +5,10 @@ using namespace Bloom::DebugServers::Gdb::CommandPackets; using namespace Bloom::Exceptions; +void WriteMemory::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) { + gdbRspDebugServer.handleGdbPacket(*this); +} + void WriteMemory::init() { if (this->data.size() < 4) { throw Exception("Invalid packet length"); @@ -47,7 +51,3 @@ void WriteMemory::init() { throw Exception("Buffer size does not match length value given in write memory packet"); } } - -void WriteMemory::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) { - gdbRspDebugServer.handleGdbPacket(*this); -} diff --git a/src/DebugServers/GdbRsp/CommandPackets/WriteMemory.hpp b/src/DebugServers/GdbRsp/CommandPackets/WriteMemory.hpp index 0b41ec3f..73fb761e 100644 --- a/src/DebugServers/GdbRsp/CommandPackets/WriteMemory.hpp +++ b/src/DebugServers/GdbRsp/CommandPackets/WriteMemory.hpp @@ -14,9 +14,6 @@ namespace Bloom::DebugServers::Gdb::CommandPackets */ class WriteMemory: public CommandPacket { - private: - void init(); - public: /** * Like with the ReadMemory command packet, the start address carries additional bits that indicate @@ -31,5 +28,8 @@ namespace Bloom::DebugServers::Gdb::CommandPackets }; void dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) override; + + private: + void init(); }; } diff --git a/src/DebugServers/GdbRsp/CommandPackets/WriteRegister.cpp b/src/DebugServers/GdbRsp/CommandPackets/WriteRegister.cpp index 34f4055f..dcd75d0b 100644 --- a/src/DebugServers/GdbRsp/CommandPackets/WriteRegister.cpp +++ b/src/DebugServers/GdbRsp/CommandPackets/WriteRegister.cpp @@ -6,6 +6,10 @@ using namespace Bloom::DebugServers::Gdb::CommandPackets; using namespace Bloom::Exceptions; +void WriteRegister::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) { + gdbRspDebugServer.handleGdbPacket(*this); +} + void WriteRegister::init() { // The P packet updates a single register auto packet = std::string(this->data.begin(), this->data.end()); @@ -23,7 +27,3 @@ void WriteRegister::init() { this->registerValue = Packet::hexToData(packetSegments.back().toStdString()); std::reverse(this->registerValue.begin(), this->registerValue.end()); } - -void WriteRegister::dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) { - gdbRspDebugServer.handleGdbPacket(*this); -} diff --git a/src/DebugServers/GdbRsp/CommandPackets/WriteRegister.hpp b/src/DebugServers/GdbRsp/CommandPackets/WriteRegister.hpp index d05a361c..c2b7ce9c 100644 --- a/src/DebugServers/GdbRsp/CommandPackets/WriteRegister.hpp +++ b/src/DebugServers/GdbRsp/CommandPackets/WriteRegister.hpp @@ -13,9 +13,6 @@ namespace Bloom::DebugServers::Gdb::CommandPackets */ class WriteRegister: public CommandPacket { - private: - void init(); - public: int registerNumber = 0; std::vector registerValue; @@ -25,5 +22,8 @@ namespace Bloom::DebugServers::Gdb::CommandPackets }; void dispatchToHandler(Gdb::GdbRspDebugServer& gdbRspDebugServer) override; + + private: + void init(); }; } diff --git a/src/DebugServers/GdbRsp/Connection.cpp b/src/DebugServers/GdbRsp/Connection.cpp index c43cb0bd..c58b7e5b 100644 --- a/src/DebugServers/GdbRsp/Connection.cpp +++ b/src/DebugServers/GdbRsp/Connection.cpp @@ -6,10 +6,12 @@ #include #include "CommandPackets/CommandPacketFactory.hpp" + #include "Exceptions/ClientDisconnected.hpp" #include "Exceptions/ClientCommunicationError.hpp" #include "src/Exceptions/Exception.hpp" #include "src/Exceptions/DebugServerInterrupted.hpp" + #include "src/Logger/Logger.hpp" using namespace Bloom::DebugServers::Gdb; @@ -51,32 +53,6 @@ void Connection::accept(int serverSocketFileDescriptor) { this->enableReadInterrupts(); } -void Connection::disableReadInterrupts() { - if (::epoll_ctl( - this->eventFileDescriptor, - EPOLL_CTL_DEL, - this->interruptEventNotifier->getFileDescriptor(), - NULL) != 0 - ) { - throw Exception("Failed to disable GDB client connection read interrupts - epoll_ctl failed"); - } - - this->readInterruptEnabled = false; -} - -void Connection::enableReadInterrupts() { - auto interruptFileDescriptor = this->interruptEventNotifier->getFileDescriptor(); - struct epoll_event event = {}; - event.events = EPOLLIN; - event.data.fd = interruptFileDescriptor; - - if (::epoll_ctl(this->eventFileDescriptor, EPOLL_CTL_ADD, interruptFileDescriptor, &event) != 0) { - throw Exception("Failed to enable GDB client connection read interrupts - epoll_ctl failed"); - } - - this->readInterruptEnabled = true; -} - void Connection::close() noexcept { if (this->socketFileDescriptor > 0) { ::close(this->socketFileDescriptor); @@ -84,18 +60,28 @@ void Connection::close() noexcept { } } -void Connection::write(const std::vector& buffer) { - Logger::debug("Writing packet: " + std::string(buffer.begin(), buffer.end())); - if (::write(this->socketFileDescriptor, buffer.data(), buffer.size()) == -1) { - if (errno == EPIPE || errno == ECONNRESET) { - // Connection was closed - throw ClientDisconnected(); +std::vector> Connection::readPackets() { + auto buffer = this->read(); + Logger::debug("GDB client data received (" + std::to_string(buffer.size()) + " bytes): " + std::string(buffer.begin(), buffer.end())); - } else { - throw ClientCommunicationError("Failed to write " + std::to_string(buffer.size()) - + " bytes to GDP client socket - error no: " + std::to_string(errno)); + auto rawPackets = CommandPacketFactory::extractRawPackets(buffer); + std::vector> output; + + for (const auto& rawPacket : rawPackets) { + try { + output.push_back(CommandPacketFactory::create(rawPacket)); + this->write({'+'}); + + } catch (const ClientDisconnected& exception) { + throw exception; + + } catch (const Exception& exception) { + Logger::error("Failed to parse GDB packet - " + exception.getMessage()); + this->write({'-'}); } } + + return output; } void Connection::writePacket(const ResponsePacket& packet) { @@ -185,26 +171,42 @@ std::optional Connection::readSingleByte(bool interruptible) { return std::nullopt; } -std::vector> Connection::readPackets() { - auto buffer = this->read(); - Logger::debug("GDB client data received (" + std::to_string(buffer.size()) + " bytes): " + std::string(buffer.begin(), buffer.end())); +void Connection::write(const std::vector& buffer) { + Logger::debug("Writing packet: " + std::string(buffer.begin(), buffer.end())); + if (::write(this->socketFileDescriptor, buffer.data(), buffer.size()) == -1) { + if (errno == EPIPE || errno == ECONNRESET) { + // Connection was closed + throw ClientDisconnected(); - auto rawPackets = CommandPacketFactory::extractRawPackets(buffer); - std::vector> output; - - for (const auto& rawPacket : rawPackets) { - try { - output.push_back(CommandPacketFactory::create(rawPacket)); - this->write({'+'}); - - } catch (const ClientDisconnected& exception) { - throw exception; - - } catch (const Exception& exception) { - Logger::error("Failed to parse GDB packet - " + exception.getMessage()); - this->write({'-'}); + } else { + throw ClientCommunicationError("Failed to write " + std::to_string(buffer.size()) + + " bytes to GDP client socket - error no: " + std::to_string(errno)); } } - - return output; +} + +void Connection::disableReadInterrupts() { + if (::epoll_ctl( + this->eventFileDescriptor, + EPOLL_CTL_DEL, + this->interruptEventNotifier->getFileDescriptor(), + NULL) != 0 + ) { + throw Exception("Failed to disable GDB client connection read interrupts - epoll_ctl failed"); + } + + this->readInterruptEnabled = false; +} + +void Connection::enableReadInterrupts() { + auto interruptFileDescriptor = this->interruptEventNotifier->getFileDescriptor(); + struct epoll_event event = {}; + event.events = EPOLLIN; + event.data.fd = interruptFileDescriptor; + + if (::epoll_ctl(this->eventFileDescriptor, EPOLL_CTL_ADD, interruptFileDescriptor, &event) != 0) { + throw Exception("Failed to enable GDB client connection read interrupts - epoll_ctl failed"); + } + + this->readInterruptEnabled = true; } diff --git a/src/DebugServers/GdbRsp/Connection.hpp b/src/DebugServers/GdbRsp/Connection.hpp index 85fc4e52..3036947c 100644 --- a/src/DebugServers/GdbRsp/Connection.hpp +++ b/src/DebugServers/GdbRsp/Connection.hpp @@ -22,59 +22,6 @@ namespace Bloom::DebugServers::Gdb */ class Connection { - private: - int socketFileDescriptor = -1; - int eventFileDescriptor = -1; - - struct sockaddr_in socketAddress = {}; - int maxPacketSize = 1024; - - /** - * The interruptEventNotifier allows us to interrupt blocking IO calls on the GDB debug server. - * Under the hood, this is just a wrapper for a Linux event notifier. See the EventNotifier class for more. - */ - std::shared_ptr interruptEventNotifier = nullptr; - bool readInterruptEnabled = false; - - /** - * Reads data from the client into a raw buffer. - * - * @param bytes - * Number of bytes to read. - * - * @param interruptible - * If this flag is set to false, no other component within Bloom will be able to gracefully interrupt - * the read (via means of this->interruptEventNotifier). This flag has no effect if this->readInterruptEnabled - * is false. - * - * @param msTimeout - * The timeout in milliseconds. If not supplied, no timeout will be applied. - * - * @return - */ - std::vector read(std::size_t bytes = 0, bool interruptible = true, std::optional msTimeout = std::nullopt); - - /** - * Does the same as Connection::read(), but only reads a single byte. - * - * @param interruptible - * See Connection::read(). - * - * @return - */ - std::optional readSingleByte(bool interruptible = true); - - /** - * Writes data from a raw buffer to the client connection. - * - * @param buffer - */ - void write(const std::vector& buffer); - - void disableReadInterrupts(); - - void enableReadInterrupts(); - public: /** * When the GDB client is waiting for the target to reach a breakpoint, this is set to true so we know when to @@ -131,5 +78,58 @@ namespace Bloom::DebugServers::Gdb [[nodiscard]] int getMaxPacketSize() const { return this->maxPacketSize; } + + private: + int socketFileDescriptor = -1; + int eventFileDescriptor = -1; + + struct sockaddr_in socketAddress = {}; + int maxPacketSize = 1024; + + /** + * The interruptEventNotifier allows us to interrupt blocking IO calls on the GDB debug server. + * Under the hood, this is just a wrapper for a Linux event notifier. See the EventNotifier class for more. + */ + std::shared_ptr interruptEventNotifier = nullptr; + bool readInterruptEnabled = false; + + /** + * Reads data from the client into a raw buffer. + * + * @param bytes + * Number of bytes to read. + * + * @param interruptible + * If this flag is set to false, no other component within Bloom will be able to gracefully interrupt + * the read (via means of this->interruptEventNotifier). This flag has no effect if this->readInterruptEnabled + * is false. + * + * @param msTimeout + * The timeout in milliseconds. If not supplied, no timeout will be applied. + * + * @return + */ + std::vector read(std::size_t bytes = 0, bool interruptible = true, std::optional msTimeout = std::nullopt); + + /** + * Does the same as Connection::read(), but only reads a single byte. + * + * @param interruptible + * See Connection::read(). + * + * @return + */ + std::optional readSingleByte(bool interruptible = true); + + /** + * Writes data from a raw buffer to the client connection. + * + * @param buffer + */ + void write(const std::vector& buffer); + + void disableReadInterrupts(); + + void enableReadInterrupts(); }; } diff --git a/src/DebugServers/GdbRsp/GdbRspDebugServer.cpp b/src/DebugServers/GdbRsp/GdbRspDebugServer.cpp index 2f7b5a99..6f7380c7 100644 --- a/src/DebugServers/GdbRsp/GdbRspDebugServer.cpp +++ b/src/DebugServers/GdbRsp/GdbRspDebugServer.cpp @@ -2,7 +2,8 @@ #include #include -#include + +#include "src/Logger/Logger.hpp" #include "Exceptions/ClientDisconnected.hpp" #include "Exceptions/ClientNotSupported.hpp" @@ -10,7 +11,6 @@ #include "Exceptions/DebugSessionAborted.hpp" #include "src/Exceptions/Exception.hpp" #include "src/Exceptions/InvalidConfig.hpp" -#include "src/Logger/Logger.hpp" using namespace Bloom::DebugServers::Gdb; using namespace Bloom::DebugServers::Gdb::CommandPackets; @@ -25,191 +25,6 @@ using Bloom::Targets::TargetRegisterDescriptor; using Bloom::Targets::TargetRegisterDescriptors; using Bloom::Targets::TargetBreakpoint; -void GdbRspDebugServer::init() { - auto ipAddress = this->debugServerConfig.jsonObject.find("ipAddress")->toString().toStdString(); - auto configPortJsonValue = this->debugServerConfig.jsonObject.find("port"); - auto configPortValue = configPortJsonValue->isString() - ? static_cast(configPortJsonValue->toString().toInt(nullptr, 10)) - : static_cast(configPortJsonValue->toInt()); - - if (!ipAddress.empty()) { - this->listeningAddress = ipAddress; - } - - if (configPortValue > 0) { - this->listeningPortNumber = configPortValue; - } - - this->socketAddress.sin_family = AF_INET; - this->socketAddress.sin_port = htons(this->listeningPortNumber); - - if (::inet_pton(AF_INET, this->listeningAddress.c_str(), &(this->socketAddress.sin_addr)) == 0) { - // Invalid IP address - throw InvalidConfig("Invalid IP address provided in config file: (\"" + this->listeningAddress + "\")"); - } - - int socketFileDescriptor; - - if ((socketFileDescriptor = ::socket(AF_INET, SOCK_STREAM, 0)) == 0) { - throw Exception("Failed to create socket file descriptor."); - } - - if (::setsockopt( - socketFileDescriptor, - SOL_SOCKET, - SO_REUSEADDR, - &(this->enableReuseAddressSocketOption), - sizeof(this->enableReuseAddressSocketOption) - ) < 0 - ) { - Logger::error("Failed to set socket SO_REUSEADDR option."); - } - - if (::bind( - socketFileDescriptor, - reinterpret_cast(&(this->socketAddress)), - sizeof(this->socketAddress) - ) < 0 - ) { - throw Exception("Failed to bind address. The selected port number (" - + std::to_string(this->listeningPortNumber) + ") may be in use."); - } - - this->serverSocketFileDescriptor = socketFileDescriptor; - - this->eventFileDescriptor = ::epoll_create(2); - struct epoll_event event = {}; - event.events = EPOLLIN; - event.data.fd = this->serverSocketFileDescriptor; - - if (::epoll_ctl(this->eventFileDescriptor, EPOLL_CTL_ADD, this->serverSocketFileDescriptor, &event) != 0) { - throw Exception("Failed epoll_ctl server socket"); - } - - if (this->interruptEventNotifier != nullptr) { - auto interruptFileDescriptor = this->interruptEventNotifier->getFileDescriptor(); - event.events = EPOLLIN; - event.data.fd = interruptFileDescriptor; - - if (::epoll_ctl(this->eventFileDescriptor, EPOLL_CTL_ADD, interruptFileDescriptor, &event) != 0) { - throw Exception("Failed epoll_ctl interrupt event fd"); - } - } - - Logger::info("GDB RSP address: " + this->listeningAddress); - Logger::info("GDB RSP port: " + std::to_string(this->listeningPortNumber)); - - this->eventListener->registerCallbackForEventType( - std::bind(&GdbRspDebugServer::onTargetControllerStateReported, this, std::placeholders::_1) - ); - - this->eventListener->registerCallbackForEventType( - std::bind(&GdbRspDebugServer::onTargetExecutionStopped, this, std::placeholders::_1) - ); -} - -void GdbRspDebugServer::close() { - this->closeClientConnection(); - - if (this->serverSocketFileDescriptor > 0) { - ::close(this->serverSocketFileDescriptor); - } -} - -void GdbRspDebugServer::serve() { - try { - if (!this->clientConnection.has_value()) { - Logger::info("Waiting for GDB RSP connection"); - - do { - this->waitForConnection(); - - } while (!this->clientConnection.has_value()); - - this->clientConnection->accept(this->serverSocketFileDescriptor); - Logger::info("Accepted GDP RSP connection from " + this->clientConnection->getIpAddress()); - this->eventManager.triggerEvent(std::make_shared()); - - /* - * Before proceeding with a new debug session, we must ensure that the TargetController is able to - * service it. - */ - if (!this->targetControllerConsole.isTargetControllerInService()) { - this->closeClientConnection(); - throw DebugSessionAborted("TargetController not in service"); - } - } - - auto packets = this->clientConnection->readPackets(); - - // Only process the last packet - any others will likely be duplicates from an impatient client - if (!packets.empty()) { - // Double-dispatch to appropriate handler - packets.back()->dispatchToHandler(*this); - } - - } catch (const ClientDisconnected&) { - Logger::info("GDB RSP client disconnected"); - this->closeClientConnection(); - return; - - } catch (const ClientCommunicationError& exception) { - Logger::error("GDB RSP client communication error - " + exception.getMessage() + " - closing connection"); - this->closeClientConnection(); - return; - - } catch (const ClientNotSupported& exception) { - Logger::error("Invalid GDB RSP client - " + exception.getMessage() + " - closing connection"); - this->closeClientConnection(); - return; - - } catch (const DebugSessionAborted& exception) { - Logger::warning("GDB debug session aborted - " + exception.getMessage()); - this->closeClientConnection(); - return; - - } catch (const DebugServerInterrupted&) { - // Server was interrupted - Logger::debug("GDB RSP interrupted"); - return; - } -} - -void GdbRspDebugServer::waitForConnection() { - if (::listen(this->serverSocketFileDescriptor, 3) != 0) { - throw Exception("Failed to listen on server socket"); - } - - std::array events = {}; - int eventCount = ::epoll_wait( - this->eventFileDescriptor, - events.data(), - 5, - -1 - ); - - if (eventCount > 0) { - for (size_t i = 0; i < eventCount; i++) { - auto fileDescriptor = events[i].data.fd; - - if (fileDescriptor == this->interruptEventNotifier->getFileDescriptor()) { - // Interrupted - this->interruptEventNotifier->clear(); - throw DebugServerInterrupted(); - } - } - - this->clientConnection = Connection(this->interruptEventNotifier); - } -} - -void GdbRspDebugServer::onTargetControllerStateReported(const Events::TargetControllerStateReported& event) { - if (event.state == TargetControllerState::SUSPENDED && this->clientConnection.has_value()) { - Logger::warning("Terminating debug session - TargetController suspended unexpectedly"); - this->closeClientConnection(); - } -} - void GdbRspDebugServer::handleGdbPacket(CommandPacket& packet) { auto packetData = packet.getData(); auto packetString = std::string(packetData.begin(), packetData.end()); @@ -234,13 +49,6 @@ void GdbRspDebugServer::handleGdbPacket(CommandPacket& packet) { } } -void GdbRspDebugServer::onTargetExecutionStopped(const Events::TargetExecutionStopped&) { - if (this->clientConnection.has_value() && this->clientConnection->waitingForBreak) { - this->clientConnection->writePacket(TargetStopped(Signal::TRAP)); - this->clientConnection->waitingForBreak = false; - } -} - void GdbRspDebugServer::handleGdbPacket(CommandPackets::SupportedFeaturesQuery& packet) { Logger::debug("Handling QuerySupport packet"); @@ -455,3 +263,195 @@ void GdbRspDebugServer::handleGdbPacket(CommandPackets::InterruptExecution& pack this->clientConnection->writePacket(ResponsePacket({'E', '0', '1'})); } } + +void GdbRspDebugServer::init() { + auto ipAddress = this->debugServerConfig.jsonObject.find("ipAddress")->toString().toStdString(); + auto configPortJsonValue = this->debugServerConfig.jsonObject.find("port"); + auto configPortValue = configPortJsonValue->isString() + ? static_cast(configPortJsonValue->toString().toInt(nullptr, 10)) + : static_cast(configPortJsonValue->toInt()); + + if (!ipAddress.empty()) { + this->listeningAddress = ipAddress; + } + + if (configPortValue > 0) { + this->listeningPortNumber = configPortValue; + } + + this->socketAddress.sin_family = AF_INET; + this->socketAddress.sin_port = htons(this->listeningPortNumber); + + if (::inet_pton(AF_INET, this->listeningAddress.c_str(), &(this->socketAddress.sin_addr)) == 0) { + // Invalid IP address + throw InvalidConfig("Invalid IP address provided in config file: (\"" + this->listeningAddress + "\")"); + } + + int socketFileDescriptor; + + if ((socketFileDescriptor = ::socket(AF_INET, SOCK_STREAM, 0)) == 0) { + throw Exception("Failed to create socket file descriptor."); + } + + if (::setsockopt( + socketFileDescriptor, + SOL_SOCKET, + SO_REUSEADDR, + &(this->enableReuseAddressSocketOption), + sizeof(this->enableReuseAddressSocketOption) + ) < 0 + ) { + Logger::error("Failed to set socket SO_REUSEADDR option."); + } + + if (::bind( + socketFileDescriptor, + reinterpret_cast(&(this->socketAddress)), + sizeof(this->socketAddress) + ) < 0 + ) { + throw Exception("Failed to bind address. The selected port number (" + + std::to_string(this->listeningPortNumber) + ") may be in use."); + } + + this->serverSocketFileDescriptor = socketFileDescriptor; + + this->eventFileDescriptor = ::epoll_create(2); + struct epoll_event event = {}; + event.events = EPOLLIN; + event.data.fd = this->serverSocketFileDescriptor; + + if (::epoll_ctl(this->eventFileDescriptor, EPOLL_CTL_ADD, this->serverSocketFileDescriptor, &event) != 0) { + throw Exception("Failed epoll_ctl server socket"); + } + + if (this->interruptEventNotifier != nullptr) { + auto interruptFileDescriptor = this->interruptEventNotifier->getFileDescriptor(); + event.events = EPOLLIN; + event.data.fd = interruptFileDescriptor; + + if (::epoll_ctl(this->eventFileDescriptor, EPOLL_CTL_ADD, interruptFileDescriptor, &event) != 0) { + throw Exception("Failed epoll_ctl interrupt event fd"); + } + } + + Logger::info("GDB RSP address: " + this->listeningAddress); + Logger::info("GDB RSP port: " + std::to_string(this->listeningPortNumber)); + + this->eventListener->registerCallbackForEventType( + std::bind(&GdbRspDebugServer::onTargetControllerStateReported, this, std::placeholders::_1) + ); + + this->eventListener->registerCallbackForEventType( + std::bind(&GdbRspDebugServer::onTargetExecutionStopped, this, std::placeholders::_1) + ); +} + +void GdbRspDebugServer::close() { + this->closeClientConnection(); + + if (this->serverSocketFileDescriptor > 0) { + ::close(this->serverSocketFileDescriptor); + } +} + +void GdbRspDebugServer::serve() { + try { + if (!this->clientConnection.has_value()) { + Logger::info("Waiting for GDB RSP connection"); + + do { + this->waitForConnection(); + + } while (!this->clientConnection.has_value()); + + this->clientConnection->accept(this->serverSocketFileDescriptor); + Logger::info("Accepted GDP RSP connection from " + this->clientConnection->getIpAddress()); + this->eventManager.triggerEvent(std::make_shared()); + + /* + * Before proceeding with a new debug session, we must ensure that the TargetController is able to + * service it. + */ + if (!this->targetControllerConsole.isTargetControllerInService()) { + this->closeClientConnection(); + throw DebugSessionAborted("TargetController not in service"); + } + } + + auto packets = this->clientConnection->readPackets(); + + // Only process the last packet - any others will likely be duplicates from an impatient client + if (!packets.empty()) { + // Double-dispatch to appropriate handler + packets.back()->dispatchToHandler(*this); + } + + } catch (const ClientDisconnected&) { + Logger::info("GDB RSP client disconnected"); + this->closeClientConnection(); + return; + + } catch (const ClientCommunicationError& exception) { + Logger::error("GDB RSP client communication error - " + exception.getMessage() + " - closing connection"); + this->closeClientConnection(); + return; + + } catch (const ClientNotSupported& exception) { + Logger::error("Invalid GDB RSP client - " + exception.getMessage() + " - closing connection"); + this->closeClientConnection(); + return; + + } catch (const DebugSessionAborted& exception) { + Logger::warning("GDB debug session aborted - " + exception.getMessage()); + this->closeClientConnection(); + return; + + } catch (const DebugServerInterrupted&) { + // Server was interrupted + Logger::debug("GDB RSP interrupted"); + return; + } +} + +void GdbRspDebugServer::waitForConnection() { + if (::listen(this->serverSocketFileDescriptor, 3) != 0) { + throw Exception("Failed to listen on server socket"); + } + + std::array events = {}; + int eventCount = ::epoll_wait( + this->eventFileDescriptor, + events.data(), + 5, + -1 + ); + + if (eventCount > 0) { + for (size_t i = 0; i < eventCount; i++) { + auto fileDescriptor = events[i].data.fd; + + if (fileDescriptor == this->interruptEventNotifier->getFileDescriptor()) { + // Interrupted + this->interruptEventNotifier->clear(); + throw DebugServerInterrupted(); + } + } + + this->clientConnection = Connection(this->interruptEventNotifier); + } +} + +void GdbRspDebugServer::onTargetControllerStateReported(const Events::TargetControllerStateReported& event) { + if (event.state == TargetControllerState::SUSPENDED && this->clientConnection.has_value()) { + Logger::warning("Terminating debug session - TargetController suspended unexpectedly"); + this->closeClientConnection(); + } +} + +void GdbRspDebugServer::onTargetExecutionStopped(const Events::TargetExecutionStopped&) { + if (this->clientConnection.has_value() && this->clientConnection->waitingForBreak) { + this->clientConnection->writePacket(TargetStopped(Signal::TRAP)); + this->clientConnection->waitingForBreak = false; + } +} diff --git a/src/DebugServers/GdbRsp/GdbRspDebugServer.hpp b/src/DebugServers/GdbRsp/GdbRspDebugServer.hpp index 3122f033..95fe2a47 100644 --- a/src/DebugServers/GdbRsp/GdbRspDebugServer.hpp +++ b/src/DebugServers/GdbRsp/GdbRspDebugServer.hpp @@ -35,6 +35,92 @@ namespace Bloom::DebugServers::Gdb */ class GdbRspDebugServer: public DebugServer { + public: + explicit GdbRspDebugServer(EventManager& eventManager): DebugServer(eventManager) {}; + + std::string getName() const override { + return "GDB Remote Serial Protocol DebugServer"; + }; + + /** + * Handles any other GDB command packet that has not been promoted to a more specific type. + * This would be packets like "?" and "qAttached". + * + * @param packet + */ + virtual void handleGdbPacket(CommandPackets::CommandPacket& packet); + + /** + * Handles the supported features query ("qSupported") command packet. + * + * @param packet + */ + virtual void handleGdbPacket(CommandPackets::SupportedFeaturesQuery& packet); + + /** + * Handles the read registers ("g" and "p") command packet. + * + * @param packet + */ + virtual void handleGdbPacket(CommandPackets::ReadRegisters& packet); + + /** + * Handles the write general register ("P") command packet. + * + * @param packet + */ + virtual void handleGdbPacket(CommandPackets::WriteRegister& packet); + + /** + * Handles the continue execution ("c") command packet. + * + * @param packet + */ + virtual void handleGdbPacket(CommandPackets::ContinueExecution& packet); + + /** + * Handles the step execution ("s") packet. + * + * @param packet + */ + virtual void handleGdbPacket(CommandPackets::StepExecution& packet); + + /** + * Handles the read memory ("m") command packet. + * + * @param packet + */ + virtual void handleGdbPacket(CommandPackets::ReadMemory& packet); + + /** + * Handles the write memory ("M") command packet. + * + * @param packet + */ + virtual void handleGdbPacket(CommandPackets::WriteMemory& packet); + + /** + * Handles the set breakpoint ("Z") command packet. + * + * @param packet + */ + virtual void handleGdbPacket(CommandPackets::SetBreakpoint& packet); + + /** + * Handles the remove breakpoint ("z") command packet. + * + * @param packet + */ + virtual void handleGdbPacket(CommandPackets::RemoveBreakpoint& packet); + + /** + * Handles the interrupt command packet. + * Will attempt to halt execution on the target. Should respond with a "stop reply" packet, or an error code. + * + * @param packet + */ + virtual void handleGdbPacket(CommandPackets::InterruptExecution& packet); + protected: /** * The port number for the GDB server to listen on. @@ -156,19 +242,12 @@ namespace Bloom::DebugServers::Gdb if (!mapping.contains(number)) { throw Exceptions::Exception("Unknown register from GDB - register number (" - + std::to_string(number) + ") not mapped to any register descriptor."); + + std::to_string(number) + ") not mapped to any register descriptor."); } return mapping.valueAt(number).value(); } - public: - explicit GdbRspDebugServer(EventManager& eventManager): DebugServer(eventManager) {}; - - std::string getName() const override { - return "GDB Remote Serial Protocol DebugServer"; - }; - void onTargetControllerStateReported(const Events::TargetControllerStateReported& event); /** @@ -176,84 +255,5 @@ namespace Bloom::DebugServers::Gdb * a "stop reply" packet to the client once the target execution stops. */ void onTargetExecutionStopped(const Events::TargetExecutionStopped&); - - /** - * Handles any other GDB command packet that has not been promoted to a more specific type. - * This would be packets like "?" and "qAttached". - * - * @param packet - */ - virtual void handleGdbPacket(CommandPackets::CommandPacket& packet); - - /** - * Handles the supported features query ("qSupported") command packet. - * - * @param packet - */ - virtual void handleGdbPacket(CommandPackets::SupportedFeaturesQuery& packet); - - /** - * Handles the read registers ("g" and "p") command packet. - * - * @param packet - */ - virtual void handleGdbPacket(CommandPackets::ReadRegisters& packet); - - /** - * Handles the write general register ("P") command packet. - * - * @param packet - */ - virtual void handleGdbPacket(CommandPackets::WriteRegister& packet); - - /** - * Handles the continue execution ("c") command packet. - * - * @param packet - */ - virtual void handleGdbPacket(CommandPackets::ContinueExecution& packet); - - /** - * Handles the step execution ("s") packet. - * - * @param packet - */ - virtual void handleGdbPacket(CommandPackets::StepExecution& packet); - - /** - * Handles the read memory ("m") command packet. - * - * @param packet - */ - virtual void handleGdbPacket(CommandPackets::ReadMemory& packet); - - /** - * Handles the write memory ("M") command packet. - * - * @param packet - */ - virtual void handleGdbPacket(CommandPackets::WriteMemory& packet); - - /** - * Handles the set breakpoint ("Z") command packet. - * - * @param packet - */ - virtual void handleGdbPacket(CommandPackets::SetBreakpoint& packet); - - /** - * Handles the remove breakpoint ("z") command packet. - * - * @param packet - */ - virtual void handleGdbPacket(CommandPackets::RemoveBreakpoint& packet); - - /** - * Handles the interrupt command packet. - * Will attempt to halt execution on the target. Should respond with a "stop reply" packet, or an error code. - * - * @param packet - */ - virtual void handleGdbPacket(CommandPackets::InterruptExecution& packet); }; } diff --git a/src/DebugServers/GdbRsp/Packet.hpp b/src/DebugServers/GdbRsp/Packet.hpp index 8fffa17c..fb198b57 100644 --- a/src/DebugServers/GdbRsp/Packet.hpp +++ b/src/DebugServers/GdbRsp/Packet.hpp @@ -16,21 +16,12 @@ namespace Bloom::DebugServers::Gdb */ class Packet { - protected: - std::vector data; - - void init(const std::vector& rawPacket) { - this->data.insert( - this->data.begin(), - rawPacket.begin() + 1, - rawPacket.end() - 3 - ); - } public: Packet() = default; explicit Packet(const std::vector& rawPacket) { this->init(rawPacket); } + virtual ~Packet() = default; [[nodiscard]] virtual std::vector getData() const { return this->data; @@ -118,6 +109,15 @@ namespace Bloom::DebugServers::Gdb return output; } - virtual ~Packet() = default; + protected: + std::vector data; + + void init(const std::vector& rawPacket) { + this->data.insert( + this->data.begin(), + rawPacket.begin() + 1, + rawPacket.end() - 3 + ); + } }; } diff --git a/src/DebugServers/GdbRsp/ResponsePackets/Ok.hpp b/src/DebugServers/GdbRsp/ResponsePackets/Ok.hpp index 88e364d3..7867a917 100644 --- a/src/DebugServers/GdbRsp/ResponsePackets/Ok.hpp +++ b/src/DebugServers/GdbRsp/ResponsePackets/Ok.hpp @@ -1,7 +1,5 @@ #pragma once -#include - #include "ResponsePacket.hpp" namespace Bloom::DebugServers::Gdb { diff --git a/src/DebugServers/GdbRsp/ResponsePackets/SupportedFeaturesResponse.hpp b/src/DebugServers/GdbRsp/ResponsePackets/SupportedFeaturesResponse.hpp index 95645b70..b36bcfa8 100644 --- a/src/DebugServers/GdbRsp/ResponsePackets/SupportedFeaturesResponse.hpp +++ b/src/DebugServers/GdbRsp/ResponsePackets/SupportedFeaturesResponse.hpp @@ -13,14 +13,14 @@ namespace Bloom::DebugServers::Gdb::ResponsePackets */ class SupportedFeaturesResponse: public ResponsePacket { - protected: - std::set>> supportedFeatures; - public: SupportedFeaturesResponse() = default; explicit SupportedFeaturesResponse(std::set>> supportedFeatures) : supportedFeatures(std::move(supportedFeatures)) {}; [[nodiscard]] std::vector getData() const override; + + protected: + std::set>> supportedFeatures; }; } diff --git a/src/DebugToolDrivers/DebugTool.hpp b/src/DebugToolDrivers/DebugTool.hpp index b4b83f99..4f20da0e 100644 --- a/src/DebugToolDrivers/DebugTool.hpp +++ b/src/DebugToolDrivers/DebugTool.hpp @@ -14,18 +14,8 @@ namespace Bloom */ class DebugTool { - private: - bool initialised = false; - - protected: - void setInitialised(bool initialised) { - this->initialised = initialised; - } - public: - [[nodiscard]] bool isInitialised() const { - return this->initialised; - } + virtual ~DebugTool() = default; /** * Should establish a connection to the device and prepare it for a debug session. @@ -55,6 +45,16 @@ namespace Bloom return nullptr; }; - virtual ~DebugTool() = default; + [[nodiscard]] bool isInitialised() const { + return this->initialised; + } + + protected: + void setInitialised(bool initialised) { + this->initialised = initialised; + } + + private: + bool initialised = false; }; } diff --git a/src/DebugToolDrivers/Microchip/AtmelICE/AtmelIce.hpp b/src/DebugToolDrivers/Microchip/AtmelICE/AtmelIce.hpp index abb7de51..e83dc59a 100644 --- a/src/DebugToolDrivers/Microchip/AtmelICE/AtmelIce.hpp +++ b/src/DebugToolDrivers/Microchip/AtmelICE/AtmelIce.hpp @@ -40,25 +40,6 @@ namespace Bloom::DebugToolDrivers */ class AtmelIce: public DebugTool, public Usb::UsbDevice { - private: - /** - * The EDBG interface implements additional functionality via vendor specific CMSIS-DAP commands. - * In other words, all EDBG commands are just CMSIS-DAP vendor commands that allow the debug tool - * to support additional functionality, like AVR programming and debugging. - * - * Any non-EDBG CMSIS-DAP commands for the Atmel-ICE can be sent through the EdbgInterface (as the - * EdbgInterface extends the CmsisDapInterface). - */ - Protocols::CmsisDap::Edbg::EdbgInterface edbgInterface = Protocols::CmsisDap::Edbg::EdbgInterface(); - - /** - * The Atmel-ICE employs the EDBG AVR8 Generic protocol, for debugging AVR8 targets. This protocol is - * implemented in EdbgAvr8Interface. See the EdbgAvr8Interface class for more information. - */ - std::unique_ptr edbgAvr8Interface = nullptr; - - bool sessionStarted = false; - public: static const std::uint16_t USB_VENDOR_ID = 1003; static const std::uint16_t USB_PRODUCT_ID = 8513; @@ -97,5 +78,24 @@ namespace Bloom::DebugToolDrivers * Ends the active session with the debug tool. */ void endSession(); + + private: + /** + * The EDBG interface implements additional functionality via vendor specific CMSIS-DAP commands. + * In other words, all EDBG commands are just CMSIS-DAP vendor commands that allow the debug tool + * to support additional functionality, like AVR programming and debugging. + * + * Any non-EDBG CMSIS-DAP commands for the Atmel-ICE can be sent through the EdbgInterface (as the + * EdbgInterface extends the CmsisDapInterface). + */ + Protocols::CmsisDap::Edbg::EdbgInterface edbgInterface = Protocols::CmsisDap::Edbg::EdbgInterface(); + + /** + * The Atmel-ICE employs the EDBG AVR8 Generic protocol, for debugging AVR8 targets. This protocol is + * implemented in EdbgAvr8Interface. See the EdbgAvr8Interface class for more information. + */ + std::unique_ptr edbgAvr8Interface = nullptr; + + bool sessionStarted = false; }; } diff --git a/src/DebugToolDrivers/Microchip/MplabSnap/MplabSnap.hpp b/src/DebugToolDrivers/Microchip/MplabSnap/MplabSnap.hpp index 472ba776..cab83a52 100644 --- a/src/DebugToolDrivers/Microchip/MplabSnap/MplabSnap.hpp +++ b/src/DebugToolDrivers/Microchip/MplabSnap/MplabSnap.hpp @@ -34,17 +34,6 @@ namespace Bloom::DebugToolDrivers */ class MplabSnap: public DebugTool, public Usb::UsbDevice { - private: - Protocols::CmsisDap::Edbg::EdbgInterface edbgInterface = Protocols::CmsisDap::Edbg::EdbgInterface(); - - /** - * The MPLAB Snap employs the EDBG AVR8 Generic protocol, for debugging AVR8 targets. This protocol is - * implemented in EdbgAvr8Interface. See the EdbgAvr8Interface class for more information. - */ - std::unique_ptr edbgAvr8Interface = nullptr; - - bool sessionStarted = false; - public: static const std::uint16_t USB_VENDOR_ID = 1003; static const std::uint16_t USB_PRODUCT_ID = 8576; @@ -83,5 +72,16 @@ namespace Bloom::DebugToolDrivers * Ends the active session with the debug tool. */ void endSession(); + + private: + Protocols::CmsisDap::Edbg::EdbgInterface edbgInterface = Protocols::CmsisDap::Edbg::EdbgInterface(); + + /** + * The MPLAB Snap employs the EDBG AVR8 Generic protocol, for debugging AVR8 targets. This protocol is + * implemented in EdbgAvr8Interface. See the EdbgAvr8Interface class for more information. + */ + std::unique_ptr edbgAvr8Interface = nullptr; + + bool sessionStarted = false; }; } diff --git a/src/DebugToolDrivers/Microchip/PowerDebugger/PowerDebugger.hpp b/src/DebugToolDrivers/Microchip/PowerDebugger/PowerDebugger.hpp index 5cc8e1fe..3d2de836 100644 --- a/src/DebugToolDrivers/Microchip/PowerDebugger/PowerDebugger.hpp +++ b/src/DebugToolDrivers/Microchip/PowerDebugger/PowerDebugger.hpp @@ -27,24 +27,6 @@ namespace Bloom::DebugToolDrivers */ class PowerDebugger: public DebugTool, public Usb::UsbDevice { - private: - /** - * The EDBG interface implements additional functionality via vendor specific CMSIS-DAP commands. - * In other words, all EDBG commands are just CMSIS-DAP vendor commands that allow the debug tool - * to support additional functionality, like AVR programming and debugging. - * - * Any non-EDBG CMSIS-DAP commands for the Power Debugger can be sent through the EDBGInterface (as the - * EdbgInterface extends the CmsisDapInterface). - */ - Protocols::CmsisDap::Edbg::EdbgInterface edbgInterface = Protocols::CmsisDap::Edbg::EdbgInterface(); - - /** - * The Power Debugger employs the EDBG AVR8Generic protocol for interfacing with AVR8 targets. - */ - std::unique_ptr edbgAvr8Interface; - - bool sessionStarted = false; - public: static const std::uint16_t USB_VENDOR_ID = 1003; static const std::uint16_t USB_PRODUCT_ID = 8516; @@ -83,5 +65,23 @@ namespace Bloom::DebugToolDrivers * Ends the active session with the debug tool. */ void endSession(); + + private: + /** + * The EDBG interface implements additional functionality via vendor specific CMSIS-DAP commands. + * In other words, all EDBG commands are just CMSIS-DAP vendor commands that allow the debug tool + * to support additional functionality, like AVR programming and debugging. + * + * Any non-EDBG CMSIS-DAP commands for the Power Debugger can be sent through the EDBGInterface (as the + * EdbgInterface extends the CmsisDapInterface). + */ + Protocols::CmsisDap::Edbg::EdbgInterface edbgInterface = Protocols::CmsisDap::Edbg::EdbgInterface(); + + /** + * The Power Debugger employs the EDBG AVR8Generic protocol for interfacing with AVR8 targets. + */ + std::unique_ptr edbgAvr8Interface; + + bool sessionStarted = false; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/CmsisDapInterface.cpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/CmsisDapInterface.cpp index 203d95fc..d69303a8 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/CmsisDapInterface.cpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/CmsisDapInterface.cpp @@ -1,7 +1,5 @@ #include "CmsisDapInterface.hpp" -#include -#include #include #include "src/DebugToolDrivers/Protocols/CMSIS-DAP/Command.hpp" diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/CmsisDapInterface.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/CmsisDapInterface.hpp index a1d6a87e..22461806 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/CmsisDapInterface.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/CmsisDapInterface.hpp @@ -17,27 +17,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap */ class CmsisDapInterface { - private: - /** - * All CMSIS-DAP devices employ the USB HID interface for communication. - * - * For many CMSIS-DAP devices, the USB HID interface parameters (interface number, endpoint config, etc) vary - * amongst devices, so we'll need to be able to preActivationConfigure the CMSISDAPInterface from a - * higher level. For an example, see the constructor of the AtmelIce device class. - */ - Usb::HidInterface usbHidInterface = Usb::HidInterface(); - - /** - * Some CMSIS-DAP debug tools fail to operate properly when we send commands too quickly. Even if we've - * received a response from every previous command. - * - * Because of this, we may need to enforce a minimum time gap between sending CMSIS commands. - * Setting msSendCommandDelay to any value above 0 will enforce an x millisecond gap between each command - * being sent, where x is the value of msSendCommandDelay. - */ - std::chrono::milliseconds msSendCommandDelay = std::chrono::milliseconds(0); - long lastCommandSentTimeStamp = 0; - public: explicit CmsisDapInterface() = default; @@ -81,5 +60,26 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap virtual std::unique_ptr sendCommandAndWaitForResponse( const Protocols::CmsisDap::Command& cmsisDapCommand ); + + private: + /** + * All CMSIS-DAP devices employ the USB HID interface for communication. + * + * For many CMSIS-DAP devices, the USB HID interface parameters (interface number, endpoint config, etc) vary + * amongst devices, so we'll need to be able to preActivationConfigure the CMSISDAPInterface from a + * higher level. For an example, see the constructor of the AtmelIce device class. + */ + Usb::HidInterface usbHidInterface = Usb::HidInterface(); + + /** + * Some CMSIS-DAP debug tools fail to operate properly when we send commands too quickly. Even if we've + * received a response from every previous command. + * + * Because of this, we may need to enforce a minimum time gap between sending CMSIS commands. + * Setting msSendCommandDelay to any value above 0 will enforce an x millisecond gap between each command + * being sent, where x is the value of msSendCommandDelay. + */ + std::chrono::milliseconds msSendCommandDelay = std::chrono::milliseconds(0); + long lastCommandSentTimeStamp = 0; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/Command.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/Command.hpp index d9ddd75b..1294e049 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/Command.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/Command.hpp @@ -7,11 +7,9 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap { class Command { - private: - unsigned char commandId = 0x00; - std::vector data; - public: + virtual ~Command() = default; + [[nodiscard]] unsigned char getCommandId() const { return this->commandId; } @@ -45,6 +43,8 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap */ explicit virtual operator std::vector() const; - virtual ~Command() = default; + private: + unsigned char commandId = 0x00; + std::vector data; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/Response.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/Response.hpp index ca73c2f3..f1eefc9c 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/Response.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/Response.hpp @@ -6,22 +6,10 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap { class Response { - private: - unsigned char responseId = 0x00; - - std::vector data; - - protected: - void setResponseId(unsigned char commandId) { - this->responseId = commandId; - } - - void setData(const std::vector& data) { - this->data = data; - } - public: Response() = default; + virtual ~Response() = default; + virtual void init(const std::vector& rawResponse); [[nodiscard]] unsigned char getResponseId() const { @@ -32,6 +20,17 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap return this->data; } - virtual ~Response() = default; + protected: + void setResponseId(unsigned char commandId) { + this->responseId = commandId; + } + + void setData(const std::vector& data) { + this->data = data; + } + + private: + unsigned char responseId = 0x00; + std::vector data; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrCommand.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrCommand.hpp index 8fdb9f5c..d83dc66a 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrCommand.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrCommand.hpp @@ -8,12 +8,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr { class AvrCommand: public Command { - private: - size_t fragmentNumber = 1; - size_t fragmentCount = 1; - - std::vector commandPacket; - public: AvrCommand() { this->setCommandId(0x80); @@ -49,5 +43,11 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr void setCommandPacket(const std::vector& commandPacket) { this->commandPacket = commandPacket; } + + private: + size_t fragmentNumber = 1; + size_t fragmentCount = 1; + + std::vector commandPacket; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrEvent.cpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrEvent.cpp index ae35c492..a13cdd41 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrEvent.cpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrEvent.cpp @@ -17,16 +17,16 @@ void AvrEvent::init(const std::vector& rawResponse) { if (responseData.size() < 2) { // All AVR_EVT responses should consist of at least two bytes (excluding the AVR_EVT ID) throw Exception("Failed to construct AvrEvent object - AVR_EVT response " - "returned no additional data."); + "returned no additional data."); } // Response size is two bytes, MSB - auto responsePacketSize = static_cast((responseData[0] << 8) | responseData[1]); + auto responsePacketSize = static_cast((responseData[0] << 8) | responseData[1]); if (responseData.size() < 2) { // All AVR_EVT responses should consist of at least two bytes (excluding the AVR_EVT ID) throw Exception("Failed to construct AvrEvent object - AVR_EVT response " - "contained invalid event data size."); + "contained invalid event data size."); } auto eventData = std::vector(); diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrEvent.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrEvent.hpp index 353f9d5f..eee452be 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrEvent.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrEvent.hpp @@ -22,16 +22,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr class AvrEvent: public Response { - private: - unsigned char eventId = 0; - - std::vector eventData; - - protected: - void setEventData(const std::vector& eventData) { - this->eventData = eventData; - } - public: AvrEvent() = default; @@ -59,5 +49,14 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr [[nodiscard]] AvrEventId getEventId() const { return static_cast(this->eventId); } + + protected: + void setEventData(const std::vector& eventData) { + this->eventData = eventData; + } + + private: + unsigned char eventId = 0; + std::vector eventData; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrResponse.cpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrResponse.cpp index 04ab7f1f..60cf7d2e 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrResponse.cpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrResponse.cpp @@ -1,7 +1,5 @@ #include "AvrResponse.hpp" -#include - #include "src/Exceptions/Exception.hpp" using namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr; diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrResponse.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrResponse.hpp index c00bc70a..935b9da5 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrResponse.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrResponse.hpp @@ -9,25 +9,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr { class AvrResponse: public Response { - private: - std::uint8_t fragmentNumber = 0; - std::uint8_t fragmentCount = 0; - - std::vector responsePacket; - - protected: - void setFragmentNumber(std::uint8_t fragmentNumber) { - this->fragmentNumber = fragmentNumber; - } - - void setFragmentCount(std::uint8_t fragmentCount) { - this->fragmentCount = fragmentCount; - } - - void setResponsePacket(const std::vector& responsePacket) { - this->responsePacket = responsePacket; - } - public: AvrResponse() = default; @@ -55,5 +36,24 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr [[nodiscard]] const std::vector& getResponsePacket() const { return this->responsePacket; } + + protected: + void setFragmentNumber(std::uint8_t fragmentNumber) { + this->fragmentNumber = fragmentNumber; + } + + void setFragmentCount(std::uint8_t fragmentCount) { + this->fragmentCount = fragmentCount; + } + + void setResponsePacket(const std::vector& responsePacket) { + this->responsePacket = responsePacket; + } + + private: + std::uint8_t fragmentNumber = 0; + std::uint8_t fragmentCount = 0; + + std::vector responsePacket; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrResponseCommand.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrResponseCommand.hpp index 7b9725a5..21f44217 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrResponseCommand.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrResponseCommand.hpp @@ -1,5 +1,7 @@ #pragma once + #include + #include "src/DebugToolDrivers/Protocols/CMSIS-DAP/Command.hpp" namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/ActivatePhysical.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/ActivatePhysical.hpp index cfa3a699..6b627edc 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/ActivatePhysical.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/ActivatePhysical.hpp @@ -6,9 +6,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames { class ActivatePhysical: public Avr8GenericCommandFrame { - private: - bool reset = false; - public: ActivatePhysical() = default; explicit ActivatePhysical(bool reset): reset(reset) {}; @@ -31,6 +28,9 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames return output; } + + private: + bool reset = false; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/Attach.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/Attach.hpp index f45e930f..dfa355f0 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/Attach.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/Attach.hpp @@ -6,9 +6,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames { class Attach: public Avr8GenericCommandFrame { - private: - bool breakAfterAttach = false; - public: Attach() = default; explicit Attach(bool breakAfterAttach): breakAfterAttach(breakAfterAttach) {}; @@ -31,6 +28,9 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames return output; } + + private: + bool breakAfterAttach = false; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/ClearAllSoftwareBreakpoints.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/ClearAllSoftwareBreakpoints.hpp index 9b7311be..fba99ead 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/ClearAllSoftwareBreakpoints.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/ClearAllSoftwareBreakpoints.hpp @@ -6,6 +6,11 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames { class ClearAllSoftwareBreakpoints: public Avr8GenericCommandFrame { + public: + ClearAllSoftwareBreakpoints() { + init(); + }; + private: void init() { /* @@ -18,10 +23,5 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames payload[1] = 0x00; this->setPayload(payload); } - - public: - ClearAllSoftwareBreakpoints() { - init(); - }; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/ClearSoftwareBreakpoints.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/ClearSoftwareBreakpoints.hpp index 6ffb9bce..cb8566af 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/ClearSoftwareBreakpoints.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/ClearSoftwareBreakpoints.hpp @@ -9,9 +9,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames { class ClearSoftwareBreakpoints: public Avr8GenericCommandFrame { - private: - std::vector addresses; - public: ClearSoftwareBreakpoints() = default; @@ -43,5 +40,8 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames return output; } + + private: + std::vector addresses; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/DeactivatePhysical.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/DeactivatePhysical.hpp index 29fe7c57..78bb5c3a 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/DeactivatePhysical.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/DeactivatePhysical.hpp @@ -6,6 +6,11 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames { class DeactivatePhysical: public Avr8GenericCommandFrame { + public: + DeactivatePhysical() { + init(); + }; + private: void init() { /* @@ -18,10 +23,5 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames payload[1] = 0x00; this->setPayload(payload); } - - public: - DeactivatePhysical() { - init(); - }; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/Detach.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/Detach.hpp index 22fdfca1..9a639f38 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/Detach.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/Detach.hpp @@ -6,6 +6,11 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames { class Detach: public Avr8GenericCommandFrame { + public: + Detach() { + init(); + }; + private: void init() { /* @@ -18,10 +23,5 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames payload[1] = 0x00; this->setPayload(payload); } - - public: - Detach() { - init(); - }; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/DisableDebugWire.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/DisableDebugWire.hpp index 33edc59f..25f7d944 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/DisableDebugWire.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/DisableDebugWire.hpp @@ -6,6 +6,11 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames { class DisableDebugWire: public Avr8GenericCommandFrame { + public: + DisableDebugWire() { + init(); + }; + private: void init() { /* @@ -18,10 +23,5 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames payload[1] = 0x00; this->setPayload(payload); } - - public: - DisableDebugWire() { - init(); - }; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/GetDeviceId.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/GetDeviceId.hpp index ffaccf26..9924351b 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/GetDeviceId.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/GetDeviceId.hpp @@ -7,6 +7,13 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames { class GetDeviceId: public Avr8GenericCommandFrame { + public: + using ResponseFrameType = ResponseFrames::Avr8Generic::GetDeviceId; + + GetDeviceId() { + init(); + }; + private: void init() { /* @@ -19,12 +26,5 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames payload[1] = 0x00; this->setPayload(payload); } - - public: - using ResponseFrameType = ResponseFrames::Avr8Generic::GetDeviceId; - - GetDeviceId() { - init(); - }; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/GetParameter.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/GetParameter.hpp index c332ce43..93efa935 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/GetParameter.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/GetParameter.hpp @@ -8,10 +8,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames { class GetParameter: public Avr8GenericCommandFrame { - private: - Avr8EdbgParameter parameter; - std::uint8_t size = 0; - public: GetParameter() = default; @@ -49,5 +45,9 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames return output; } + + private: + Avr8EdbgParameter parameter; + std::uint8_t size = 0; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/GetProgramCounter.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/GetProgramCounter.hpp index 9b9c02d4..a0ea98fa 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/GetProgramCounter.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/GetProgramCounter.hpp @@ -7,6 +7,13 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames { class GetProgramCounter: public Avr8GenericCommandFrame { + public: + using ResponseFrameType = ResponseFrames::Avr8Generic::GetProgramCounter; + + GetProgramCounter() { + init(); + }; + private: void init() { /* @@ -19,12 +26,5 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames payload[1] = 0x00; this->setPayload(payload); } - - public: - using ResponseFrameType = ResponseFrames::Avr8Generic::GetProgramCounter; - - GetProgramCounter() { - init(); - }; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/ReadMemory.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/ReadMemory.hpp index ad65765e..65f8060f 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/ReadMemory.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/ReadMemory.hpp @@ -10,12 +10,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames { class ReadMemory: public Avr8GenericCommandFrame { - private: - Avr8MemoryType type = Avr8MemoryType::SRAM; - std::uint32_t address = 0; - std::uint32_t bytes = 0; - std::set excludedAddresses; - public: using ResponseFrameType = ResponseFrames::Avr8Generic::ReadMemory; @@ -38,5 +32,11 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames } [[nodiscard]] std::vector getPayload() const override; + + private: + Avr8MemoryType type = Avr8MemoryType::SRAM; + std::uint32_t address = 0; + std::uint32_t bytes = 0; + std::set excludedAddresses; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/Reset.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/Reset.hpp index 206fdb87..e92384c5 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/Reset.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/Reset.hpp @@ -6,9 +6,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames { class Reset: public Avr8GenericCommandFrame { - private: - bool stopAtMainAddress = false; - public: Reset() = default; explicit Reset(bool stopAtMainAddress): stopAtMainAddress(stopAtMainAddress) {}; @@ -31,5 +28,8 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames return output; } + + private: + bool stopAtMainAddress = false; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/Run.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/Run.hpp index b6f42444..842cbd43 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/Run.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/Run.hpp @@ -6,6 +6,11 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames { class Run: public Avr8GenericCommandFrame { + public: + Run() { + init(); + }; + private: void init() { /* @@ -18,10 +23,5 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames payload[1] = 0x00; this->setPayload(payload); } - - public: - Run() { - init(); - }; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/RunTo.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/RunTo.hpp index ab9792f1..5c22f15d 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/RunTo.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/RunTo.hpp @@ -8,9 +8,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames { class RunTo: public Avr8GenericCommandFrame { - private: - std::uint32_t address = 0; - public: RunTo() = default; @@ -41,5 +38,8 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames return output; } + + private: + std::uint32_t address = 0; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/SetParameter.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/SetParameter.hpp index 64ec0184..75b9383e 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/SetParameter.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/SetParameter.hpp @@ -6,10 +6,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames { class SetParameter: public Avr8GenericCommandFrame { - private: - Avr8EdbgParameter parameter; - std::vector value; - public: SetParameter() = default; @@ -57,5 +53,9 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames return output; } + + private: + Avr8EdbgParameter parameter; + std::vector value; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/SetProgramCounter.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/SetProgramCounter.hpp index a935a75c..c9c3f081 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/SetProgramCounter.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/SetProgramCounter.hpp @@ -8,9 +8,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames { class SetProgramCounter: public Avr8GenericCommandFrame { - private: - std::uint32_t programCounter = 0; - public: explicit SetProgramCounter(std::uint32_t programCounter): programCounter(programCounter) {} @@ -31,5 +28,8 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames return output; } + + private: + std::uint32_t programCounter = 0; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/SetSoftwareBreakpoints.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/SetSoftwareBreakpoints.hpp index a7a6514c..53138786 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/SetSoftwareBreakpoints.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/SetSoftwareBreakpoints.hpp @@ -9,9 +9,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames { class SetSoftwareBreakpoints: public Avr8GenericCommandFrame { - private: - std::vector addresses; - public: SetSoftwareBreakpoints() = default; @@ -43,5 +40,8 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames return output; } + + private: + std::vector addresses; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/SetXmegaSoftwareBreakpoint.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/SetXmegaSoftwareBreakpoint.hpp index ddd02318..e09decee 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/SetXmegaSoftwareBreakpoint.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/SetXmegaSoftwareBreakpoint.hpp @@ -8,9 +8,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames { class SetXmegaSoftwareBreakpoint: public Avr8GenericCommandFrame { - private: - std::uint32_t address = 0; - public: SetXmegaSoftwareBreakpoint() = default; @@ -40,5 +37,8 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames return output; } + + private: + std::uint32_t address = 0; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/Stop.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/Stop.hpp index 2734d6c6..199a0c79 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/Stop.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/Stop.hpp @@ -6,9 +6,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames { class Stop: public Avr8GenericCommandFrame { - private: - bool stopImmediately = true; - public: Stop() = default; explicit Stop(bool stopImmediately): stopImmediately(stopImmediately) {}; @@ -31,5 +28,8 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames return output; } + + private: + bool stopImmediately = true; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/WriteMemory.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/WriteMemory.hpp index cc5eda8b..e5126072 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/WriteMemory.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/WriteMemory.hpp @@ -9,11 +9,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames { class WriteMemory: public Avr8GenericCommandFrame { - private: - Avr8MemoryType type = Avr8MemoryType::SRAM; - std::uint32_t address = 0; - Targets::TargetMemoryBuffer buffer; - public: WriteMemory() = default; @@ -62,5 +57,10 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames return output; } + + private: + Avr8MemoryType type = Avr8MemoryType::SRAM; + std::uint32_t address = 0; + Targets::TargetMemoryBuffer buffer; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AvrCommandFrame.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AvrCommandFrame.hpp index 658e749e..7a3b6c7d 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AvrCommandFrame.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AvrCommandFrame.hpp @@ -14,24 +14,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr { class AvrCommandFrame { - private: - unsigned char SOF = 0x0E; - - unsigned char protocolVersion = 0x00; - - /** - * Incrementing from 0x00 - */ - std::uint16_t sequenceId = 0; - inline static std::uint16_t lastSequenceId = 0; - - /** - * Destination sub-protocol handler ID - */ - ProtocolHandlerId protocolHandlerID = ProtocolHandlerId::DISCOVERY; - - std::vector payload; - public: using ResponseFrameType = AvrResponseFrame; @@ -102,6 +84,24 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr * @return */ explicit virtual operator std::vector () const; + + private: + unsigned char SOF = 0x0E; + + unsigned char protocolVersion = 0x00; + + /** + * Incrementing from 0x00 + */ + std::uint16_t sequenceId = 0; + inline static std::uint16_t lastSequenceId = 0; + + /** + * Destination sub-protocol handler ID + */ + ProtocolHandlerId protocolHandlerID = ProtocolHandlerId::DISCOVERY; + + std::vector payload; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/Discovery/Query.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/Discovery/Query.hpp index 97d31f91..5326ca89 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/Discovery/Query.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/Discovery/Query.hpp @@ -21,9 +21,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames */ class Query: public DiscoveryCommandFrame { - private: - QueryContext context = QueryContext::COMMAND_HANDLERS; - public: Query(): DiscoveryCommandFrame() {} @@ -45,5 +42,8 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames return output; } + + private: + QueryContext context = QueryContext::COMMAND_HANDLERS; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/HouseKeeping/EndSession.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/HouseKeeping/EndSession.hpp index 9274ecc1..0ecd1f03 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/HouseKeeping/EndSession.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/HouseKeeping/EndSession.hpp @@ -9,6 +9,11 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames */ class EndSession: public HouseKeepingCommandFrame { + public: + EndSession(): HouseKeepingCommandFrame() { + this->init(); + } + private: void init() { /* @@ -21,10 +26,5 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames payload[2] = 0x00; this->setPayload(payload); } - - public: - EndSession(): HouseKeepingCommandFrame() { - this->init(); - } }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/HouseKeeping/StartSession.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/HouseKeeping/StartSession.hpp index 77c24ffb..53c797e6 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/HouseKeeping/StartSession.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/HouseKeeping/StartSession.hpp @@ -9,6 +9,11 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames */ class StartSession: public HouseKeepingCommandFrame { + public: + StartSession(): HouseKeepingCommandFrame() { + this->init(); + } + private: void init() { /* @@ -20,10 +25,5 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames payload[1] = 0x00; this->setPayload(payload); } - - public: - StartSession(): HouseKeepingCommandFrame() { - this->init(); - } }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.cpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.cpp index 92d9446c..5804dc34 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.cpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.cpp @@ -49,6 +49,577 @@ using Bloom::Targets::TargetRegisterDescriptors; using Bloom::Targets::TargetRegisterType; using Bloom::Targets::TargetRegisters; +void EdbgAvr8Interface::configure(const TargetConfig& targetConfig) { + auto physicalInterface = targetConfig.jsonObject.find("physicalInterface")->toString().toLower().toStdString(); + + auto availablePhysicalInterfaces = this->getPhysicalInterfacesByName(); + + if (physicalInterface.empty() + || availablePhysicalInterfaces.find(physicalInterface) == availablePhysicalInterfaces.end() + ) { + throw InvalidConfig("Invalid physical interface config parameter for AVR8 target."); + } + + auto selectedPhysicalInterface = availablePhysicalInterfaces.find(physicalInterface)->second; + + if (selectedPhysicalInterface == PhysicalInterface::DEBUG_WIRE) { + Logger::warning("AVR8 debugWire interface selected - the DWEN fuse will need to be enabled"); + } + + this->physicalInterface = selectedPhysicalInterface; + + if (!this->family.has_value()) { + if (this->physicalInterface == PhysicalInterface::JTAG) { + throw InvalidConfig("The JTAG physical interface cannot be used with an ambiguous target name" + " - please specify the exact name of the target in your configuration file. " + "See https://bloom.oscillate.io/docs/supported-targets" + ); + + } else if (this->physicalInterface == PhysicalInterface::UPDI) { + throw InvalidConfig("The UPDI physical interface cannot be used with an ambiguous target name" + " - please specify the exact name of the target in your configuration file. " + "See https://bloom.oscillate.io/docs/supported-targets" + ); + } + } + + this->configVariant = this->resolveConfigVariant().value_or(Avr8ConfigVariant::NONE); +} + +void EdbgAvr8Interface::setTargetParameters(const Avr8Bit::TargetParameters& config) { + this->targetParameters = config; + + if (!config.stackPointerRegisterLowAddress.has_value()) { + throw DeviceInitializationFailure("Failed to find stack pointer register start address"); + } + + if (!config.stackPointerRegisterSize.has_value()) { + throw DeviceInitializationFailure("Failed to find stack pointer register size"); + } + + if (!config.statusRegisterStartAddress.has_value()) { + throw DeviceInitializationFailure("Failed to find status register start address"); + } + + if (!config.statusRegisterSize.has_value()) { + throw DeviceInitializationFailure("Failed to find status register size"); + } + + if (this->configVariant == Avr8ConfigVariant::NONE) { + auto configVariant = this->resolveConfigVariant(); + + if (!configVariant.has_value()) { + throw DeviceInitializationFailure("Failed to resolve config variant for the selected " + "physical interface and AVR8 family. The selected physical interface is not known to be supported " + "by the AVR8 family." + ); + } + + this->configVariant = configVariant.value(); + } + + switch (this->configVariant) { + case Avr8ConfigVariant::DEBUG_WIRE: + case Avr8ConfigVariant::MEGAJTAG: { + this->setDebugWireAndJtagParameters(); + break; + } + case Avr8ConfigVariant::XMEGA: { + this->setPdiParameters(); + break; + } + case Avr8ConfigVariant::UPDI: { + this->setUpdiParameters(); + break; + } + default: { + break; + } + } +} + +void EdbgAvr8Interface::init() { + if (this->configVariant == Avr8ConfigVariant::XMEGA) { + // Default PDI clock to 4MHz + // TODO: Make this adjustable via a target config parameter + this->setParameter(Avr8EdbgParameters::PDI_CLOCK_SPEED, static_cast(0x0FA0)); + } + + if (this->configVariant == Avr8ConfigVariant::UPDI) { + // Default UPDI clock to 1.8MHz + this->setParameter(Avr8EdbgParameters::PDI_CLOCK_SPEED, static_cast(0x0708)); + this->setParameter(Avr8EdbgParameters::ENABLE_HIGH_VOLTAGE_UPDI, static_cast(0x00)); + } + + if (this->configVariant == Avr8ConfigVariant::MEGAJTAG) { + // Default clock value for mega debugging is 2KHz + // TODO: Make this adjustable via a target config parameter + this->setParameter(Avr8EdbgParameters::MEGA_DEBUG_CLOCK, static_cast(0x00C8)); + this->setParameter(Avr8EdbgParameters::JTAG_DAISY_CHAIN_SETTINGS, static_cast(0)); + } + + this->setParameter( + Avr8EdbgParameters::CONFIG_VARIANT, + static_cast(this->configVariant) + ); + + this->setParameter( + Avr8EdbgParameters::CONFIG_FUNCTION, + static_cast(this->configFunction) + ); + + this->setParameter( + Avr8EdbgParameters::PHYSICAL_INTERFACE, + getAvr8PhysicalInterfaceToIdMapping().at(this->physicalInterface) + ); +} + +void EdbgAvr8Interface::stop() { + auto commandFrame = CommandFrames::Avr8Generic::Stop(); + + auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); + if (response.getResponseId() == Avr8ResponseId::FAILED) { + throw Avr8CommandFailure("AVR8 Stop target command failed", response); + } + + if (this->getTargetState() == TargetState::RUNNING) { + this->waitForStoppedEvent(); + } +} + +void EdbgAvr8Interface::run() { + this->clearEvents(); + auto commandFrame = CommandFrames::Avr8Generic::Run(); + + auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); + if (response.getResponseId() == Avr8ResponseId::FAILED) { + throw Avr8CommandFailure("AVR8 Run command failed", response); + } + + this->targetState = TargetState::RUNNING; +} + +void EdbgAvr8Interface::runTo(std::uint32_t address) { + this->clearEvents(); + Logger::debug("Running to address: " + std::to_string(address)); + auto commandFrame = CommandFrames::Avr8Generic::RunTo(address); + + auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); + if (response.getResponseId() == Avr8ResponseId::FAILED) { + throw Avr8CommandFailure("AVR8 Run-to command failed", response); + } + + this->targetState = TargetState::RUNNING; +} + +void EdbgAvr8Interface::step() { + auto commandFrame = CommandFrames::Avr8Generic::Step(); + + auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); + if (response.getResponseId() == Avr8ResponseId::FAILED) { + throw Avr8CommandFailure("AVR8 Step target command failed", response); + } + + this->targetState = TargetState::RUNNING; +} + +void EdbgAvr8Interface::reset() { + auto commandFrame = CommandFrames::Avr8Generic::Reset(); + + auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); + if (response.getResponseId() == Avr8ResponseId::FAILED) { + throw Avr8CommandFailure("AVR8 Reset target command failed", response); + } +} + +void EdbgAvr8Interface::activate() { + if (!this->physicalInterfaceActivated) { + this->activatePhysical(); + } + + if (!this->targetAttached) { + this->attach(); + } +} + +void EdbgAvr8Interface::deactivate() { + if (this->targetAttached) { + if (this->physicalInterface == PhysicalInterface::DEBUG_WIRE && this->disableDebugWireOnDeactivate) { + try { + this->disableDebugWire(); + Logger::warning("Successfully disabled debugWire on the AVR8 target - this is only temporary - " + "the debugWire module has lost control of the RESET pin. Bloom will no longer be able to interface " + "with the target until the next power cycle."); + + } catch (const Exception& exception) { + // Failing to disable debugWire should never prevent us from proceeding with target deactivation. + Logger::error(exception.getMessage()); + } + } + + this->stop(); + this->clearAllBreakpoints(); + this->run(); + + this->detach(); + } + + if (this->physicalInterfaceActivated) { + this->deactivatePhysical(); + } +} + +std::uint32_t EdbgAvr8Interface::getProgramCounter() { + if (this->targetState != TargetState::STOPPED) { + this->stop(); + } + + auto commandFrame = CommandFrames::Avr8Generic::GetProgramCounter(); + auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); + if (response.getResponseId() == Avr8ResponseId::FAILED) { + throw Avr8CommandFailure("AVR8 Get program counter command failed", response); + } + + return response.extractProgramCounter(); +} + +void EdbgAvr8Interface::setProgramCounter(std::uint32_t programCounter) { + if (this->targetState != TargetState::STOPPED) { + this->stop(); + } + + /* + * The program counter will be given in byte address form, but the EDBG tool will be expecting it in word + * address (16-bit) form. This is why we divide it by 2. + */ + auto commandFrame = CommandFrames::Avr8Generic::SetProgramCounter(programCounter / 2); + auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); + if (response.getResponseId() == Avr8ResponseId::FAILED) { + throw Avr8CommandFailure("AVR8 Set program counter command failed", response); + } +} + +TargetSignature EdbgAvr8Interface::getDeviceId() { + if (this->configVariant == Avr8ConfigVariant::UPDI) { + /* + * When using the UPDI physical interface, the 'Get device ID' command behaves in an odd manner, where it + * doesn't actually return the target signature, but instead a fixed four byte string reading: + * 'A', 'V', 'R' and ' ' (white space). + * + * So it appears we cannot use that command for UPDI sessions. As an alternative, we will just read the + * signature from memory using the signature base address. + * + * TODO: Currently, we're assuming the signature will always only ever be three bytes in size, but we may + * want to consider pulling the size from the TDF. + */ + auto signatureMemory = this->readMemory( + Avr8MemoryType::SRAM, + this->targetParameters.signatureSegmentStartAddress.value(), + 3 + ); + + if (signatureMemory.size() != 3) { + throw Exception("Failed to read AVR8 signature from target - unexpected response size"); + } + + return TargetSignature(signatureMemory[0], signatureMemory[1], signatureMemory[2]); + } + + auto commandFrame = CommandFrames::Avr8Generic::GetDeviceId(); + + auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); + if (response.getResponseId() == Avr8ResponseId::FAILED) { + throw Avr8CommandFailure("AVR8 Get device ID command failed", response); + } + + return response.extractSignature(this->physicalInterface); +} + +void EdbgAvr8Interface::setBreakpoint(std::uint32_t address) { + auto commandFrame = CommandFrames::Avr8Generic::SetSoftwareBreakpoints({address}); + + auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); + if (response.getResponseId() == Avr8ResponseId::FAILED) { + throw Avr8CommandFailure("AVR8 Set software breakpoint command failed", response); + } +} + +void EdbgAvr8Interface::clearBreakpoint(std::uint32_t address) { + auto commandFrame = CommandFrames::Avr8Generic::ClearSoftwareBreakpoints({address}); + + auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); + if (response.getResponseId() == Avr8ResponseId::FAILED) { + throw Avr8CommandFailure("AVR8 Clear software breakpoint command failed", response); + } +} + +void EdbgAvr8Interface::clearAllBreakpoints() { + auto commandFrame = CommandFrames::Avr8Generic::ClearAllSoftwareBreakpoints(); + + auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); + if (response.getResponseId() == Avr8ResponseId::FAILED) { + throw Avr8CommandFailure("AVR8 Clear all software breakpoints command failed", response); + } +} + +TargetRegisters EdbgAvr8Interface::readRegisters(const TargetRegisterDescriptors& descriptors) { + /* + * This function needs to be fast. Insight eagerly requests the values of all known registers that it can present + * to the user. It does this on numerous occasions (target stopped, user clicked refresh, etc). This means we will + * be frequently loading over 100 register values in a single instance. + * + * For the above reason, we do not read each register value individually. That would take far too long if we have + * over 100 registers to read. Instead, we group the register descriptors into collections by register type, and + * resolve the address range for each collection. We then perform a single read operation for each collection + * and hold the memory buffer in a random access container (std::vector). Finally, we extract the data for + * each register descriptor, from the memory buffer, and construct the relevant TargetRegister object. + * + * TODO: We should be grouping the register descriptors by memory type, as opposed to register type. This + * isn't much of a problem ATM, as currently, we only work with registers that are stored in the data + * address space or the register file. This will need to be addressed before we can work with any other + * registers stored elsewhere. + */ + auto output = TargetRegisters(); + + // Group descriptors by type and resolve the address range for each type + auto descriptorsByType = std::map>(); + + /* + * An address range is just an std::pair of integers - the first being the start address, the second being the + * end address. + */ + using AddressRange = std::pair; + auto addressRangeByType = std::map(); + + for (const auto& descriptor : descriptors) { + if (!descriptor.startAddress.has_value()) { + Logger::debug( + "Attempted to read register in the absence of a start address - register name: " + + descriptor.name.value_or("unknown") + ); + continue; + } + + descriptorsByType[descriptor.type].insert(&descriptor); + + const auto startAddress = descriptor.startAddress.value(); + const auto endAddress = startAddress + (descriptor.size - 1); + + if (!addressRangeByType.contains(descriptor.type)) { + auto addressRange = AddressRange(); + addressRange.first = startAddress; + addressRange.second = endAddress; + addressRangeByType[descriptor.type] = addressRange; + + } else { + auto& addressRange = addressRangeByType[descriptor.type]; + + if (startAddress < addressRange.first) { + addressRange.first = startAddress; + } + + if (endAddress > addressRange.second) { + addressRange.second = endAddress; + } + } + } + + /* + * Now that we have our address ranges and grouped descriptors, we can perform a single read call for each + * register type. + */ + for (const auto& [registerType, descriptors] : descriptorsByType) { + const auto& addressRange = addressRangeByType[registerType]; + const auto startAddress = addressRange.first; + const auto endAddress = addressRange.second; + const auto bufferSize = (endAddress - startAddress) + 1; + + const auto memoryType = (registerType != TargetRegisterType::GENERAL_PURPOSE_REGISTER) ? Avr8MemoryType::SRAM : ( + this->configVariant == Avr8ConfigVariant::XMEGA || this->configVariant == Avr8ConfigVariant::UPDI + ? Avr8MemoryType::REGISTER_FILE : Avr8MemoryType::SRAM + ); + + /* + * When reading the entire range, we must avoid any attempts to access the OCD data register (OCDDR), as the + * debug tool will reject the command and respond with a 0x36 error code (invalid address error). + * + * For this reason, we specify the OCDDR address as an excluded address. This will mean + * the EdbgAvr8Interface::readMemory() function will employ the masked read memory command, as opposed to the + * general read memory command. The masked read memory command allows us to specify which addresses to + * read and which ones to ignore. For ignored addresses, the debug tool will just return a 0x00 byte. + * For more info, see section 7.1.22 titled 'Memory Read Masked', in the EDBG protocol document. + * + * Interestingly, the masked read memory command doesn't seem to require us to explicitly specify the OCDDR + * address as an excluded address. It seems to exclude the OCDDR automatically, even if we've not + * instructed it to do so. This is plausible, as we send the OCDDR address to the debug tool during target + * initialisation (see EdbgAvr8Interface::setDebugWireAndJtagParameters()). So this means we don't have to + * specify the OCDDR address as an excluded address, but the EdbgAvr8Interface::readMemory() function will + * only employ the masked read memory command when we supply at least one excluded address. For this reason, + * we still pass the OCDDR address to EdbgAvr8Interface::readMemory(), as an excluded address (provided we + * have it). + * + * See CommandFrames::Avr8Generic::ReadMemory(); and the Microchip EDBG documentation for more. + */ + auto excludedAddresses = std::set(); + if (memoryType == Avr8MemoryType::SRAM && this->targetParameters.ocdDataRegister.has_value()) { + excludedAddresses.insert( + this->targetParameters.ocdDataRegister.value() + + this->targetParameters.mappedIoSegmentStartAddress.value_or(0) + ); + } + + const auto flatMemoryBuffer = this->readMemory( + memoryType, + startAddress, + bufferSize, + excludedAddresses + ); + + if (flatMemoryBuffer.size() != bufferSize) { + throw Exception( + "Failed to read memory within register type address range (" + std::to_string(startAddress) + + " - " + std::to_string(endAddress) +"). Expected " + std::to_string(bufferSize) + + " bytes, got " + std::to_string(flatMemoryBuffer.size()) + ); + } + + // Construct our TargetRegister objects directly from the flat memory buffer + for (const auto& descriptor : descriptors) { + /* + * Multi-byte AVR8 registers are stored in LSB form. + * + * This is why we use reverse iterators when extracting our data from flatMemoryBuffer. Doing so allows + * us to extract the data in MSB form (as is expected for all register values held in TargetRegister + * objects). + */ + const auto bufferStartIt = flatMemoryBuffer.rend() - (descriptor->startAddress.value() - startAddress) + - descriptor->size; + + output.emplace_back( + TargetRegister( + *descriptor, + TargetMemoryBuffer(bufferStartIt, bufferStartIt + descriptor->size) + ) + ); + } + } + + return output; +} + +void EdbgAvr8Interface::writeRegisters(const Targets::TargetRegisters& registers) { + for (const auto& reg : registers) { + const auto& registerDescriptor = reg.descriptor; + auto registerValue = reg.value; + + if (registerValue.empty()) { + throw Exception("Cannot write empty register value"); + } + + if (registerValue.size() > registerDescriptor.size) { + throw Exception("Register value exceeds size specified by register descriptor."); + + } else if (registerValue.size() < registerDescriptor.size) { + // Fill the missing most-significant bytes with 0x00 + registerValue.insert(registerValue.begin(), registerDescriptor.size - registerValue.size(), 0x00); + } + + if (registerValue.size() > 1) { + // AVR8 registers are stored in LSB + std::reverse(registerValue.begin(), registerValue.end()); + } + + auto memoryType = Avr8MemoryType::SRAM; + if (registerDescriptor.type == TargetRegisterType::GENERAL_PURPOSE_REGISTER + && (this->configVariant == Avr8ConfigVariant::XMEGA || this->configVariant == Avr8ConfigVariant::UPDI) + ) { + memoryType = Avr8MemoryType::REGISTER_FILE; + } + + // TODO: This can be inefficient when updating many registers, maybe do something a little smarter here. + this->writeMemory( + memoryType, + registerDescriptor.startAddress.value(), + registerValue + ); + } +} + +TargetMemoryBuffer EdbgAvr8Interface::readMemory(TargetMemoryType memoryType, std::uint32_t startAddress, std::uint32_t bytes) { + auto avr8MemoryType = Avr8MemoryType::SRAM; + + switch (memoryType) { + case TargetMemoryType::RAM: { + avr8MemoryType = Avr8MemoryType::SRAM; + break; + } + case TargetMemoryType::FLASH: { + if (this->configVariant == Avr8ConfigVariant::DEBUG_WIRE) { + avr8MemoryType = Avr8MemoryType::FLASH_PAGE; + + } else if (this->configVariant == Avr8ConfigVariant::XMEGA || this->configVariant == Avr8ConfigVariant::UPDI) { + avr8MemoryType = Avr8MemoryType::APPL_FLASH; + + } else { + avr8MemoryType = Avr8MemoryType::SPM; + } + break; + } + case TargetMemoryType::EEPROM: { + avr8MemoryType = Avr8MemoryType::EEPROM; + } + } + + return this->readMemory(avr8MemoryType, startAddress, bytes); +} + +void EdbgAvr8Interface::writeMemory(TargetMemoryType memoryType, std::uint32_t startAddress, const TargetMemoryBuffer& buffer) { + auto avr8MemoryType = Avr8MemoryType::SRAM; + + switch (memoryType) { + case TargetMemoryType::RAM: { + avr8MemoryType = Avr8MemoryType::SRAM; + break; + } + case TargetMemoryType::FLASH: { + if (this->configVariant == Avr8ConfigVariant::DEBUG_WIRE) { + avr8MemoryType = Avr8MemoryType::FLASH_PAGE; + + } else if (this->configVariant == Avr8ConfigVariant::MEGAJTAG) { + avr8MemoryType = Avr8MemoryType::FLASH_PAGE; + // TODO: Enable programming mode + + } else if (this->configVariant == Avr8ConfigVariant::XMEGA || this->configVariant == Avr8ConfigVariant::UPDI) { + avr8MemoryType = Avr8MemoryType::APPL_FLASH; + + } else { + avr8MemoryType = Avr8MemoryType::SPM; + } + break; + } + case TargetMemoryType::EEPROM: { + avr8MemoryType = Avr8MemoryType::EEPROM; + } + } + + return this->writeMemory(avr8MemoryType, startAddress, buffer); +} + +TargetState EdbgAvr8Interface::getTargetState() { + /* + * We are not informed when a target goes from a stopped state to a running state, so there is no need + * to query the tool when we already know the target has stopped. + * + * This means we have to rely on the assumption that the target cannot enter a running state without + * our instruction. + */ + if (this->targetState != TargetState::STOPPED) { + this->refreshTargetState(); + } + + return this->targetState; +} + void EdbgAvr8Interface::setParameter(const Avr8EdbgParameter& parameter, const std::vector& value) { auto commandFrame = CommandFrames::Avr8Generic::SetParameter(parameter, value); @@ -498,157 +1069,6 @@ void EdbgAvr8Interface::setUpdiParameters() { ); } -void EdbgAvr8Interface::configure(const TargetConfig& targetConfig) { - auto physicalInterface = targetConfig.jsonObject.find("physicalInterface")->toString().toLower().toStdString(); - - auto availablePhysicalInterfaces = this->getPhysicalInterfacesByName(); - - if (physicalInterface.empty() - || availablePhysicalInterfaces.find(physicalInterface) == availablePhysicalInterfaces.end() - ) { - throw InvalidConfig("Invalid physical interface config parameter for AVR8 target."); - } - - auto selectedPhysicalInterface = availablePhysicalInterfaces.find(physicalInterface)->second; - - if (selectedPhysicalInterface == PhysicalInterface::DEBUG_WIRE) { - Logger::warning("AVR8 debugWire interface selected - the DWEN fuse will need to be enabled"); - } - - this->physicalInterface = selectedPhysicalInterface; - - if (!this->family.has_value()) { - if (this->physicalInterface == PhysicalInterface::JTAG) { - throw InvalidConfig("The JTAG physical interface cannot be used with an ambiguous target name" - " - please specify the exact name of the target in your configuration file. " - "See https://bloom.oscillate.io/docs/supported-targets" - ); - - } else if (this->physicalInterface == PhysicalInterface::UPDI) { - throw InvalidConfig("The UPDI physical interface cannot be used with an ambiguous target name" - " - please specify the exact name of the target in your configuration file. " - "See https://bloom.oscillate.io/docs/supported-targets" - ); - } - } - - this->configVariant = this->resolveConfigVariant().value_or(Avr8ConfigVariant::NONE); -} - -void EdbgAvr8Interface::setTargetParameters(const Avr8Bit::TargetParameters& config) { - this->targetParameters = config; - - if (!config.stackPointerRegisterLowAddress.has_value()) { - throw DeviceInitializationFailure("Failed to find stack pointer register start address"); - } - - if (!config.stackPointerRegisterSize.has_value()) { - throw DeviceInitializationFailure("Failed to find stack pointer register size"); - } - - if (!config.statusRegisterStartAddress.has_value()) { - throw DeviceInitializationFailure("Failed to find status register start address"); - } - - if (!config.statusRegisterSize.has_value()) { - throw DeviceInitializationFailure("Failed to find status register size"); - } - - if (this->configVariant == Avr8ConfigVariant::NONE) { - auto configVariant = this->resolveConfigVariant(); - - if (!configVariant.has_value()) { - throw DeviceInitializationFailure("Failed to resolve config variant for the selected " - "physical interface and AVR8 family. The selected physical interface is not known to be supported " - "by the AVR8 family." - ); - } - - this->configVariant = configVariant.value(); - } - - switch (this->configVariant) { - case Avr8ConfigVariant::DEBUG_WIRE: - case Avr8ConfigVariant::MEGAJTAG: { - this->setDebugWireAndJtagParameters(); - break; - } - case Avr8ConfigVariant::XMEGA: { - this->setPdiParameters(); - break; - } - case Avr8ConfigVariant::UPDI: { - this->setUpdiParameters(); - break; - } - default: { - break; - } - } -} - -void EdbgAvr8Interface::init() { - if (this->configVariant == Avr8ConfigVariant::XMEGA) { - // Default PDI clock to 4MHz - // TODO: Make this adjustable via a target config parameter - this->setParameter(Avr8EdbgParameters::PDI_CLOCK_SPEED, static_cast(0x0FA0)); - } - - if (this->configVariant == Avr8ConfigVariant::UPDI) { - // Default UPDI clock to 1.8MHz - this->setParameter(Avr8EdbgParameters::PDI_CLOCK_SPEED, static_cast(0x0708)); - this->setParameter(Avr8EdbgParameters::ENABLE_HIGH_VOLTAGE_UPDI, static_cast(0x00)); - } - - if (this->configVariant == Avr8ConfigVariant::MEGAJTAG) { - // Default clock value for mega debugging is 2KHz - // TODO: Make this adjustable via a target config parameter - this->setParameter(Avr8EdbgParameters::MEGA_DEBUG_CLOCK, static_cast(0x00C8)); - this->setParameter(Avr8EdbgParameters::JTAG_DAISY_CHAIN_SETTINGS, static_cast(0)); - } - - this->setParameter( - Avr8EdbgParameters::CONFIG_VARIANT, - static_cast(this->configVariant) - ); - - this->setParameter( - Avr8EdbgParameters::CONFIG_FUNCTION, - static_cast(this->configFunction) - ); - - this->setParameter( - Avr8EdbgParameters::PHYSICAL_INTERFACE, - getAvr8PhysicalInterfaceToIdMapping().at(this->physicalInterface) - ); -} - -std::unique_ptr EdbgAvr8Interface::getAvrEvent() { - auto event = this->edbgInterface.requestAvrEvent(); - - if (!event.has_value()) { - return nullptr; - } - - switch (event->getEventId()) { - case AvrEventId::AVR8_BREAK_EVENT: { - // Break event - return std::make_unique(event.value()); - } - default: { - /* - * TODO: This isn't very nice as we're performing an unnecessary copy. Maybe requestAvrEvents should - * return a unique_ptr instead? - */ - return std::make_unique(event.value()); - } - } -} - -void EdbgAvr8Interface::clearEvents() { - while (this->getAvrEvent() != nullptr) {} -} - void EdbgAvr8Interface::activatePhysical(bool applyExternalReset) { auto commandFrame = CommandFrames::Avr8Generic::ActivatePhysical(applyExternalReset); @@ -718,243 +1138,30 @@ void EdbgAvr8Interface::detach() { this->targetAttached = false; } -void EdbgAvr8Interface::activate() { - if (!this->physicalInterfaceActivated) { - this->activatePhysical(); +std::unique_ptr EdbgAvr8Interface::getAvrEvent() { + auto event = this->edbgInterface.requestAvrEvent(); + + if (!event.has_value()) { + return nullptr; } - if (!this->targetAttached) { - this->attach(); - } -} - -void EdbgAvr8Interface::deactivate() { - if (this->targetAttached) { - if (this->physicalInterface == PhysicalInterface::DEBUG_WIRE && this->disableDebugWireOnDeactivate) { - try { - this->disableDebugWire(); - Logger::warning("Successfully disabled debugWire on the AVR8 target - this is only temporary - " - "the debugWire module has lost control of the RESET pin. Bloom will no longer be able to interface " - "with the target until the next power cycle."); - - } catch (const Exception& exception) { - // Failing to disable debugWire should never prevent us from proceeding with target deactivation. - Logger::error(exception.getMessage()); - } + switch (event->getEventId()) { + case AvrEventId::AVR8_BREAK_EVENT: { + // Break event + return std::make_unique(event.value()); } - - this->stop(); - this->clearAllBreakpoints(); - this->run(); - - this->detach(); - } - - if (this->physicalInterfaceActivated) { - this->deactivatePhysical(); - } -} - -void EdbgAvr8Interface::reset() { - auto commandFrame = CommandFrames::Avr8Generic::Reset(); - - auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); - if (response.getResponseId() == Avr8ResponseId::FAILED) { - throw Avr8CommandFailure("AVR8 Reset target command failed", response); - } -} - -void EdbgAvr8Interface::stop() { - auto commandFrame = CommandFrames::Avr8Generic::Stop(); - - auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); - if (response.getResponseId() == Avr8ResponseId::FAILED) { - throw Avr8CommandFailure("AVR8 Stop target command failed", response); - } - - if (this->getTargetState() == TargetState::RUNNING) { - this->waitForStoppedEvent(); - } -} - -void EdbgAvr8Interface::step() { - auto commandFrame = CommandFrames::Avr8Generic::Step(); - - auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); - if (response.getResponseId() == Avr8ResponseId::FAILED) { - throw Avr8CommandFailure("AVR8 Step target command failed", response); - } - - this->targetState = TargetState::RUNNING; -} - -void EdbgAvr8Interface::waitForStoppedEvent() { - auto breakEvent = this->waitForAvrEvent(); - - if (breakEvent == nullptr) { - throw Exception("Failed to receive break event for AVR8 target"); - } - - this->targetState = TargetState::STOPPED; -} - -void EdbgAvr8Interface::disableDebugWire() { - auto commandFrame = CommandFrames::Avr8Generic::DisableDebugWire(); - - auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); - if (response.getResponseId() == Avr8ResponseId::FAILED) { - throw Avr8CommandFailure("AVR8 Disable debugWire command failed", response); - } -} - -void EdbgAvr8Interface::run() { - this->clearEvents(); - auto commandFrame = CommandFrames::Avr8Generic::Run(); - - auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); - if (response.getResponseId() == Avr8ResponseId::FAILED) { - throw Avr8CommandFailure("AVR8 Run command failed", response); - } - - this->targetState = TargetState::RUNNING; -} - -void EdbgAvr8Interface::runTo(std::uint32_t address) { - this->clearEvents(); - Logger::debug("Running to address: " + std::to_string(address)); - auto commandFrame = CommandFrames::Avr8Generic::RunTo(address); - - auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); - if (response.getResponseId() == Avr8ResponseId::FAILED) { - throw Avr8CommandFailure("AVR8 Run-to command failed", response); - } - - this->targetState = TargetState::RUNNING; -} - -std::uint32_t EdbgAvr8Interface::getProgramCounter() { - if (this->targetState != TargetState::STOPPED) { - this->stop(); - } - - auto commandFrame = CommandFrames::Avr8Generic::GetProgramCounter(); - auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); - if (response.getResponseId() == Avr8ResponseId::FAILED) { - throw Avr8CommandFailure("AVR8 Get program counter command failed", response); - } - - return response.extractProgramCounter(); -} - -void EdbgAvr8Interface::setProgramCounter(std::uint32_t programCounter) { - if (this->targetState != TargetState::STOPPED) { - this->stop(); - } - - /* - * The program counter will be given in byte address form, but the EDBG tool will be expecting it in word - * address (16-bit) form. This is why we divide it by 2. - */ - auto commandFrame = CommandFrames::Avr8Generic::SetProgramCounter(programCounter / 2); - auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); - if (response.getResponseId() == Avr8ResponseId::FAILED) { - throw Avr8CommandFailure("AVR8 Set program counter command failed", response); - } -} - -TargetSignature EdbgAvr8Interface::getDeviceId() { - if (this->configVariant == Avr8ConfigVariant::UPDI) { - /* - * When using the UPDI physical interface, the 'Get device ID' command behaves in an odd manner, where it - * doesn't actually return the target signature, but instead a fixed four byte string reading: - * 'A', 'V', 'R' and ' ' (white space). - * - * So it appears we cannot use that command for UPDI sessions. As an alternative, we will just read the - * signature from memory using the signature base address. - * - * TODO: Currently, we're assuming the signature will always only ever be three bytes in size, but we may - * want to consider pulling the size from the TDF. - */ - auto signatureMemory = this->readMemory( - Avr8MemoryType::SRAM, - this->targetParameters.signatureSegmentStartAddress.value(), - 3 - ); - - if (signatureMemory.size() != 3) { - throw Exception("Failed to read AVR8 signature from target - unexpected response size"); + default: { + /* + * TODO: This isn't very nice as we're performing an unnecessary copy. Maybe requestAvrEvents should + * return a unique_ptr instead? + */ + return std::make_unique(event.value()); } - - return TargetSignature(signatureMemory[0], signatureMemory[1], signatureMemory[2]); - } - - auto commandFrame = CommandFrames::Avr8Generic::GetDeviceId(); - - auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); - if (response.getResponseId() == Avr8ResponseId::FAILED) { - throw Avr8CommandFailure("AVR8 Get device ID command failed", response); - } - - return response.extractSignature(this->physicalInterface); -} - -void EdbgAvr8Interface::setBreakpoint(std::uint32_t address) { - auto commandFrame = CommandFrames::Avr8Generic::SetSoftwareBreakpoints({address}); - - auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); - if (response.getResponseId() == Avr8ResponseId::FAILED) { - throw Avr8CommandFailure("AVR8 Set software breakpoint command failed", response); } } -void EdbgAvr8Interface::clearBreakpoint(std::uint32_t address) { - auto commandFrame = CommandFrames::Avr8Generic::ClearSoftwareBreakpoints({address}); - - auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); - if (response.getResponseId() == Avr8ResponseId::FAILED) { - throw Avr8CommandFailure("AVR8 Clear software breakpoint command failed", response); - } -} - -void EdbgAvr8Interface::clearAllBreakpoints() { - auto commandFrame = CommandFrames::Avr8Generic::ClearAllSoftwareBreakpoints(); - - auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); - if (response.getResponseId() == Avr8ResponseId::FAILED) { - throw Avr8CommandFailure("AVR8 Clear all software breakpoints command failed", response); - } -} - -void EdbgAvr8Interface::refreshTargetState() { - auto avrEvent = this->getAvrEvent(); - - if (avrEvent != nullptr && avrEvent->getEventId() == AvrEventId::AVR8_BREAK_EVENT) { - auto breakEvent = dynamic_cast(avrEvent.get()); - - if (breakEvent == nullptr) { - throw Exception("Failed to process AVR8 break event"); - } - - this->targetState = TargetState::STOPPED; - return; - } - - this->targetState = TargetState::RUNNING; -} - -TargetState EdbgAvr8Interface::getTargetState() { - /* - * We are not informed when a target goes from a stopped state to a running state, so there is no need - * to query the tool when we already know the target has stopped. - * - * This means we have to rely on the assumption that the target cannot enter a running state without - * our instruction. - */ - if (this->targetState != TargetState::STOPPED) { - this->refreshTargetState(); - } - - return this->targetState; +void EdbgAvr8Interface::clearEvents() { + while (this->getAvrEvent() != nullptr) {} } TargetMemoryBuffer EdbgAvr8Interface::readMemory( @@ -1174,245 +1381,38 @@ void EdbgAvr8Interface::writeMemory(Avr8MemoryType type, std::uint32_t address, } } -TargetRegisters EdbgAvr8Interface::readRegisters(const TargetRegisterDescriptors& descriptors) { - /* - * This function needs to be fast. Insight eagerly requests the values of all known registers that it can present - * to the user. It does this on numerous occasions (target stopped, user clicked refresh, etc). This means we will - * be frequently loading over 100 register values in a single instance. - * - * For the above reason, we do not read each register value individually. That would take far too long if we have - * over 100 registers to read. Instead, we group the register descriptors into collections by register type, and - * resolve the address range for each collection. We then perform a single read operation for each collection - * and hold the memory buffer in a random access container (std::vector). Finally, we extract the data for - * each register descriptor, from the memory buffer, and construct the relevant TargetRegister object. - * - * TODO: We should be grouping the register descriptors by memory type, as opposed to register type. This - * isn't much of a problem ATM, as currently, we only work with registers that are stored in the data - * address space or the register file. This will need to be addressed before we can work with any other - * registers stored elsewhere. - */ - auto output = TargetRegisters(); +void EdbgAvr8Interface::refreshTargetState() { + auto avrEvent = this->getAvrEvent(); - // Group descriptors by type and resolve the address range for each type - auto descriptorsByType = std::map>(); + if (avrEvent != nullptr && avrEvent->getEventId() == AvrEventId::AVR8_BREAK_EVENT) { + auto breakEvent = dynamic_cast(avrEvent.get()); - /* - * An address range is just an std::pair of integers - the first being the start address, the second being the - * end address. - */ - using AddressRange = std::pair; - auto addressRangeByType = std::map(); - - for (const auto& descriptor : descriptors) { - if (!descriptor.startAddress.has_value()) { - Logger::debug( - "Attempted to read register in the absence of a start address - register name: " - + descriptor.name.value_or("unknown") - ); - continue; + if (breakEvent == nullptr) { + throw Exception("Failed to process AVR8 break event"); } - descriptorsByType[descriptor.type].insert(&descriptor); - - const auto startAddress = descriptor.startAddress.value(); - const auto endAddress = startAddress + (descriptor.size - 1); - - if (!addressRangeByType.contains(descriptor.type)) { - auto addressRange = AddressRange(); - addressRange.first = startAddress; - addressRange.second = endAddress; - addressRangeByType[descriptor.type] = addressRange; - - } else { - auto& addressRange = addressRangeByType[descriptor.type]; - - if (startAddress < addressRange.first) { - addressRange.first = startAddress; - } - - if (endAddress > addressRange.second) { - addressRange.second = endAddress; - } - } + this->targetState = TargetState::STOPPED; + return; } - /* - * Now that we have our address ranges and grouped descriptors, we can perform a single read call for each - * register type. - */ - for (const auto& [registerType, descriptors] : descriptorsByType) { - const auto& addressRange = addressRangeByType[registerType]; - const auto startAddress = addressRange.first; - const auto endAddress = addressRange.second; - const auto bufferSize = (endAddress - startAddress) + 1; - - const auto memoryType = (registerType != TargetRegisterType::GENERAL_PURPOSE_REGISTER) ? Avr8MemoryType::SRAM : ( - this->configVariant == Avr8ConfigVariant::XMEGA || this->configVariant == Avr8ConfigVariant::UPDI - ? Avr8MemoryType::REGISTER_FILE : Avr8MemoryType::SRAM - ); - - /* - * When reading the entire range, we must avoid any attempts to access the OCD data register (OCDDR), as the - * debug tool will reject the command and respond with a 0x36 error code (invalid address error). - * - * For this reason, we specify the OCDDR address as an excluded address. This will mean - * the EdbgAvr8Interface::readMemory() function will employ the masked read memory command, as opposed to the - * general read memory command. The masked read memory command allows us to specify which addresses to - * read and which ones to ignore. For ignored addresses, the debug tool will just return a 0x00 byte. - * For more info, see section 7.1.22 titled 'Memory Read Masked', in the EDBG protocol document. - * - * Interestingly, the masked read memory command doesn't seem to require us to explicitly specify the OCDDR - * address as an excluded address. It seems to exclude the OCDDR automatically, even if we've not - * instructed it to do so. This is plausible, as we send the OCDDR address to the debug tool during target - * initialisation (see EdbgAvr8Interface::setDebugWireAndJtagParameters()). So this means we don't have to - * specify the OCDDR address as an excluded address, but the EdbgAvr8Interface::readMemory() function will - * only employ the masked read memory command when we supply at least one excluded address. For this reason, - * we still pass the OCDDR address to EdbgAvr8Interface::readMemory(), as an excluded address (provided we - * have it). - * - * See CommandFrames::Avr8Generic::ReadMemory(); and the Microchip EDBG documentation for more. - */ - auto excludedAddresses = std::set(); - if (memoryType == Avr8MemoryType::SRAM && this->targetParameters.ocdDataRegister.has_value()) { - excludedAddresses.insert( - this->targetParameters.ocdDataRegister.value() - + this->targetParameters.mappedIoSegmentStartAddress.value_or(0) - ); - } - - const auto flatMemoryBuffer = this->readMemory( - memoryType, - startAddress, - bufferSize, - excludedAddresses - ); - - if (flatMemoryBuffer.size() != bufferSize) { - throw Exception( - "Failed to read memory within register type address range (" + std::to_string(startAddress) - + " - " + std::to_string(endAddress) +"). Expected " + std::to_string(bufferSize) - + " bytes, got " + std::to_string(flatMemoryBuffer.size()) - ); - } - - // Construct our TargetRegister objects directly from the flat memory buffer - for (const auto& descriptor : descriptors) { - /* - * Multi-byte AVR8 registers are stored in LSB form. - * - * This is why we use reverse iterators when extracting our data from flatMemoryBuffer. Doing so allows - * us to extract the data in MSB form (as is expected for all register values held in TargetRegister - * objects). - */ - const auto bufferStartIt = flatMemoryBuffer.rend() - (descriptor->startAddress.value() - startAddress) - - descriptor->size; - - output.emplace_back( - TargetRegister( - *descriptor, - TargetMemoryBuffer(bufferStartIt, bufferStartIt + descriptor->size) - ) - ); - } - } - - return output; + this->targetState = TargetState::RUNNING; } -void EdbgAvr8Interface::writeRegisters(const Targets::TargetRegisters& registers) { - for (const auto& reg : registers) { - const auto& registerDescriptor = reg.descriptor; - auto registerValue = reg.value; +void EdbgAvr8Interface::disableDebugWire() { + auto commandFrame = CommandFrames::Avr8Generic::DisableDebugWire(); - if (registerValue.empty()) { - throw Exception("Cannot write empty register value"); - } - - if (registerValue.size() > registerDescriptor.size) { - throw Exception("Register value exceeds size specified by register descriptor."); - - } else if (registerValue.size() < registerDescriptor.size) { - // Fill the missing most-significant bytes with 0x00 - registerValue.insert(registerValue.begin(), registerDescriptor.size - registerValue.size(), 0x00); - } - - if (registerValue.size() > 1) { - // AVR8 registers are stored in LSB - std::reverse(registerValue.begin(), registerValue.end()); - } - - auto memoryType = Avr8MemoryType::SRAM; - if (registerDescriptor.type == TargetRegisterType::GENERAL_PURPOSE_REGISTER - && (this->configVariant == Avr8ConfigVariant::XMEGA || this->configVariant == Avr8ConfigVariant::UPDI) - ) { - memoryType = Avr8MemoryType::REGISTER_FILE; - } - - // TODO: This can be inefficient when updating many registers, maybe do something a little smarter here. - this->writeMemory( - memoryType, - registerDescriptor.startAddress.value(), - registerValue - ); + auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame); + if (response.getResponseId() == Avr8ResponseId::FAILED) { + throw Avr8CommandFailure("AVR8 Disable debugWire command failed", response); } } -TargetMemoryBuffer EdbgAvr8Interface::readMemory(TargetMemoryType memoryType, std::uint32_t startAddress, std::uint32_t bytes) { - auto avr8MemoryType = Avr8MemoryType::SRAM; +void EdbgAvr8Interface::waitForStoppedEvent() { + auto breakEvent = this->waitForAvrEvent(); - switch (memoryType) { - case TargetMemoryType::RAM: { - avr8MemoryType = Avr8MemoryType::SRAM; - break; - } - case TargetMemoryType::FLASH: { - if (this->configVariant == Avr8ConfigVariant::DEBUG_WIRE) { - avr8MemoryType = Avr8MemoryType::FLASH_PAGE; - - } else if (this->configVariant == Avr8ConfigVariant::XMEGA || this->configVariant == Avr8ConfigVariant::UPDI) { - avr8MemoryType = Avr8MemoryType::APPL_FLASH; - - } else { - avr8MemoryType = Avr8MemoryType::SPM; - } - break; - } - case TargetMemoryType::EEPROM: { - avr8MemoryType = Avr8MemoryType::EEPROM; - } + if (breakEvent == nullptr) { + throw Exception("Failed to receive break event for AVR8 target"); } - return this->readMemory(avr8MemoryType, startAddress, bytes); -} - -void EdbgAvr8Interface::writeMemory(TargetMemoryType memoryType, std::uint32_t startAddress, const TargetMemoryBuffer& buffer) { - auto avr8MemoryType = Avr8MemoryType::SRAM; - - switch (memoryType) { - case TargetMemoryType::RAM: { - avr8MemoryType = Avr8MemoryType::SRAM; - break; - } - case TargetMemoryType::FLASH: { - if (this->configVariant == Avr8ConfigVariant::DEBUG_WIRE) { - avr8MemoryType = Avr8MemoryType::FLASH_PAGE; - - } else if (this->configVariant == Avr8ConfigVariant::MEGAJTAG) { - avr8MemoryType = Avr8MemoryType::FLASH_PAGE; - // TODO: Enable programming mode - - } else if (this->configVariant == Avr8ConfigVariant::XMEGA || this->configVariant == Avr8ConfigVariant::UPDI) { - avr8MemoryType = Avr8MemoryType::APPL_FLASH; - - } else { - avr8MemoryType = Avr8MemoryType::SPM; - } - break; - } - case TargetMemoryType::EEPROM: { - avr8MemoryType = Avr8MemoryType::EEPROM; - } - } - - return this->writeMemory(avr8MemoryType, startAddress, buffer); + this->targetState = TargetState::STOPPED; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.hpp index a5b934e9..0694a207 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/EdbgAvr8Interface.hpp @@ -25,6 +25,198 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr */ class EdbgAvr8Interface: public TargetInterfaces::Microchip::Avr::Avr8::Avr8Interface { + public: + explicit EdbgAvr8Interface(EdbgInterface& edbgInterface) + : edbgInterface(edbgInterface) {}; + + /** + * Disables use of the masked read memory EDBG command. Masking will be performed at the driver-side. + * + * @param avoidMaskedMemoryRead + */ + void setAvoidMaskedMemoryRead(bool avoidMaskedMemoryRead) { + this->avoidMaskedMemoryRead = avoidMaskedMemoryRead; + } + + /* + * The public methods below implement the interface defined by the Avr8Interface class. + * See the comments in that class for more info on the expected behaviour of each method. + */ + + /** + * As already mentioned in numerous comments above, the EdbgAvr8Interface requires some configuration from + * the user. This is supplied via the user's Bloom configuration. + * + * @param targetConfig + */ + void configure(const TargetConfig& targetConfig) override; + + /** + * Configures the target family. For some physical interfaces, the target family is required in order + * properly configure the EDBG tool. See EdbgAvr8Interface::resolveConfigVariant() for more. + * + * @param family + */ + void setFamily(Targets::Microchip::Avr::Avr8Bit::Family family) override { + this->family = family; + } + + /** + * Accepts target parameters from the AVR8 target instance and sends the necessary target parameters to the + * debug tool. + * + * @param config + */ + void setTargetParameters(const Targets::Microchip::Avr::Avr8Bit::TargetParameters& config) override; + + /** + * Initialises the AVR8 Generic protocol interface by setting the appropriate parameters on the debug tool. + */ + void init() override; + + /** + * Issues the "stop" command to the debug tool, halting target execution. + */ + void stop() override; + + /** + * Issues the "run" command to the debug tool, resuming execution on the target. + */ + void run() override; + + /** + * Issues the "run to" command to the debug tool, resuming execution on the target, up to a specific byte + * address. The target will dispatch an AVR BREAK event once it reaches the specified address. + * + * @param address + * The (byte) address to run to. + */ + void runTo(std::uint32_t address) override; + + /** + * Issues the "step" command to the debug tool, stepping the execution on the target. The stepping can be + * configured to step in, out or over. But currently we only support stepping in. The target will dispatch + * an AVR BREAK event once it reaches the next instruction. + */ + void step() override; + + /** + * Issues the "reset" command to the debug tool, resetting target execution. + */ + void reset() override; + + /** + * Activates the physical interface and starts a debug session on the target (via attach()). + */ + void activate() override; + + /** + * Terminates any active debug session on the target and severs the connection between the debug tool and + * the target (by deactivating the physical interface). + */ + void deactivate() override; + + /** + * Issues the "PC Read" command to the debug tool, to extract the current program counter. + * + * @return + */ + std::uint32_t getProgramCounter() override; + + /** + * Issues the "PC Write" command to the debug tool, setting the program counter on the target. + * + * @param programCounter + * The byte address to set as the program counter. + */ + void setProgramCounter(std::uint32_t programCounter) override; + + /** + * Issues the "Get ID" command to the debug tool, to extract the signature from the target. + * + * @return + */ + Targets::Microchip::Avr::TargetSignature getDeviceId() override; + + /** + * Issues the "Software Breakpoint Set" command to the debug tool, setting a software breakpoint at the given + * byte address. + * + * @param address + * The byte address to position the breakpoint. + */ + void setBreakpoint(std::uint32_t address) override; + + /** + * Issues the "Software Breakpoint Clear" command to the debug tool, clearing any breakpoint at the given + * byte address. + * + * @param address + * The byte address of the breakpoint to clear. + */ + void clearBreakpoint(std::uint32_t address) override; + + /** + * Issues the "Software Breakpoint Clear All" command to the debug tool, clearing all software breakpoints + * that were set *in the current debug session*. + * + * If the debug session ended before any of the set breakpoints were cleared, this will *not* clear them. + */ + void clearAllBreakpoints() override; + + /** + * Reads registers from the target. + * + * @param descriptors + * @return + */ + Targets::TargetRegisters readRegisters(const Targets::TargetRegisterDescriptors& descriptors) override; + + /** + * Writes registers to target. + * + * @param registers + */ + void writeRegisters(const Targets::TargetRegisters& registers) override; + + /** + * This is an overloaded method. + * + * Resolves the correct Avr8MemoryType from the given TargetMemoryType and calls readMemory(). + * + * @param memoryType + * @param startAddress + * @param bytes + * @return + */ + Targets::TargetMemoryBuffer readMemory( + Targets::TargetMemoryType memoryType, + std::uint32_t startAddress, + std::uint32_t bytes + ) override; + + /** + * This is an overloaded method. + * + * Resolves the correct Avr8MemoryType from the given TargetMemoryType and calls writeMemory(). + * + * @param memoryType + * @param startAddress + * @param buffer + */ + void writeMemory( + Targets::TargetMemoryType memoryType, + std::uint32_t startAddress, + const Targets::TargetMemoryBuffer& buffer + ) override; + + /** + * Returns the current state of the target. + * + * @return + */ + Targets::TargetState getTargetState() override; + private: /** * The AVR8 Generic protocol is a sub-protocol of the EDBG AVR protocol, which is served via CMSIS-DAP vendor @@ -459,197 +651,5 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr * This should only be used when a BreakEvent is always expected. */ void waitForStoppedEvent(); - - public: - explicit EdbgAvr8Interface(EdbgInterface& edbgInterface) - : edbgInterface(edbgInterface) {}; - - /** - * Disables use of the masked read memory EDBG command. Masking will be performed at the driver-side. - * - * @param avoidMaskedMemoryRead - */ - void setAvoidMaskedMemoryRead(bool avoidMaskedMemoryRead) { - this->avoidMaskedMemoryRead = avoidMaskedMemoryRead; - } - - /* - * The public methods below implement the interface defined by the Avr8Interface class. - * See the comments in that class for more info on the expected behaviour of each method. - */ - - /** - * As already mentioned in numerous comments above, the EdbgAvr8Interface requires some configuration from - * the user. This is supplied via the user's Bloom configuration. - * - * @param targetConfig - */ - void configure(const TargetConfig& targetConfig) override; - - /** - * Configures the target family. For some physical interfaces, the target family is required in order - * properly configure the EDBG tool. See EdbgAvr8Interface::resolveConfigVariant() for more. - * - * @param family - */ - void setFamily(Targets::Microchip::Avr::Avr8Bit::Family family) override { - this->family = family; - } - - /** - * Accepts target parameters from the AVR8 target instance and sends the necessary target parameters to the - * debug tool. - * - * @param config - */ - void setTargetParameters(const Targets::Microchip::Avr::Avr8Bit::TargetParameters& config) override; - - /** - * Initialises the AVR8 Generic protocol interface by setting the appropriate parameters on the debug tool. - */ - void init() override; - - /** - * Issues the "stop" command to the debug tool, halting target execution. - */ - void stop() override; - - /** - * Issues the "run" command to the debug tool, resuming execution on the target. - */ - void run() override; - - /** - * Issues the "run to" command to the debug tool, resuming execution on the target, up to a specific byte - * address. The target will dispatch an AVR BREAK event once it reaches the specified address. - * - * @param address - * The (byte) address to run to. - */ - void runTo(std::uint32_t address) override; - - /** - * Issues the "step" command to the debug tool, stepping the execution on the target. The stepping can be - * configured to step in, out or over. But currently we only support stepping in. The target will dispatch - * an AVR BREAK event once it reaches the next instruction. - */ - void step() override; - - /** - * Issues the "reset" command to the debug tool, resetting target execution. - */ - void reset() override; - - /** - * Activates the physical interface and starts a debug session on the target (via attach()). - */ - void activate() override; - - /** - * Terminates any active debug session on the target and severs the connection between the debug tool and - * the target (by deactivating the physical interface). - */ - void deactivate() override; - - /** - * Issues the "PC Read" command to the debug tool, to extract the current program counter. - * - * @return - */ - std::uint32_t getProgramCounter() override; - - /** - * Issues the "PC Write" command to the debug tool, setting the program counter on the target. - * - * @param programCounter - * The byte address to set as the program counter. - */ - void setProgramCounter(std::uint32_t programCounter) override; - - /** - * Issues the "Get ID" command to the debug tool, to extract the signature from the target. - * - * @return - */ - Targets::Microchip::Avr::TargetSignature getDeviceId() override; - - /** - * Issues the "Software Breakpoint Set" command to the debug tool, setting a software breakpoint at the given - * byte address. - * - * @param address - * The byte address to position the breakpoint. - */ - void setBreakpoint(std::uint32_t address) override; - - /** - * Issues the "Software Breakpoint Clear" command to the debug tool, clearing any breakpoint at the given - * byte address. - * - * @param address - * The byte address of the breakpoint to clear. - */ - void clearBreakpoint(std::uint32_t address) override; - - /** - * Issues the "Software Breakpoint Clear All" command to the debug tool, clearing all software breakpoints - * that were set *in the current debug session*. - * - * If the debug session ended before any of the set breakpoints were cleared, this will *not* clear them. - */ - void clearAllBreakpoints() override; - - /** - * Reads registers from the target. - * - * @param descriptors - * @return - */ - Targets::TargetRegisters readRegisters(const Targets::TargetRegisterDescriptors& descriptors) override; - - /** - * Writes registers to target. - * - * @param registers - */ - void writeRegisters(const Targets::TargetRegisters& registers) override; - - /** - * This is an overloaded method. - * - * Resolves the correct Avr8MemoryType from the given TargetMemoryType and calls readMemory(). - * - * @param memoryType - * @param startAddress - * @param bytes - * @return - */ - Targets::TargetMemoryBuffer readMemory( - Targets::TargetMemoryType memoryType, - std::uint32_t startAddress, - std::uint32_t bytes - ) override; - - /** - * This is an overloaded method. - * - * Resolves the correct Avr8MemoryType from the given TargetMemoryType and calls writeMemory(). - * - * @param memoryType - * @param startAddress - * @param buffer - */ - void writeMemory( - Targets::TargetMemoryType memoryType, - std::uint32_t startAddress, - const Targets::TargetMemoryBuffer& buffer - ) override; - - /** - * Returns the current state of the target. - * - * @return - */ - Targets::TargetState getTargetState() override; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/Events/AVR8Generic/BreakEvent.cpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/Events/AVR8Generic/BreakEvent.cpp index 519253e8..778ab147 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/Events/AVR8Generic/BreakEvent.cpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/Events/AVR8Generic/BreakEvent.cpp @@ -1,7 +1,5 @@ #include "BreakEvent.hpp" -#include - #include "src/Exceptions/Exception.hpp" using namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr; diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/Events/AVR8Generic/BreakEvent.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/Events/AVR8Generic/BreakEvent.hpp index 5fbe5bb1..a2ca811b 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/Events/AVR8Generic/BreakEvent.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/Events/AVR8Generic/BreakEvent.hpp @@ -9,12 +9,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr { class BreakEvent: public AvrEvent { - private: - std::uint32_t programCounter = 0; - Targets::TargetBreakCause breakCause = Targets::TargetBreakCause::UNKNOWN; - - void init(const AvrEvent& event); - public: explicit BreakEvent(const AvrEvent& event) { this->init(event); @@ -27,5 +21,11 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr [[nodiscard]] Targets::TargetBreakCause getBreakCause() const { return this->breakCause; } + + private: + std::uint32_t programCounter = 0; + Targets::TargetBreakCause breakCause = Targets::TargetBreakCause::UNKNOWN; + + void init(const AvrEvent& event); }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/Exceptions/Avr8CommandFailure.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/Exceptions/Avr8CommandFailure.hpp index 2a40ff64..f623be8e 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/Exceptions/Avr8CommandFailure.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/Exceptions/Avr8CommandFailure.hpp @@ -7,6 +7,27 @@ namespace Bloom::Exceptions { class Avr8CommandFailure: public TargetOperationFailure { + public: + explicit Avr8CommandFailure(const std::string& message): TargetOperationFailure(message) { + this->message = message; + } + + explicit Avr8CommandFailure(const char* message): TargetOperationFailure(message) { + this->message = std::string(message); + } + + explicit Avr8CommandFailure( + const std::string& message, + DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::ResponseFrames::Avr8Generic::Avr8GenericResponseFrame& responseFrame + ): TargetOperationFailure(message) { + this->message = message; + + auto responsePayload = responseFrame.getPayload(); + if (responsePayload.size() == 3 && this->failureCodeToDescription.contains(responsePayload[2])) { + this->message += " - Failure reason: " + this->failureCodeToDescription.find(responsePayload[2])->second; + } + } + private: static inline auto failureCodeToDescription = std::map({ {0x10, "debugWIRE physical error"}, @@ -57,26 +78,5 @@ namespace Bloom::Exceptions {0x91, "Command has not been implemented"}, {0xFF, "Unknown error reported by EDBG device"}, }); - - public: - explicit Avr8CommandFailure(const std::string& message): TargetOperationFailure(message) { - this->message = message; - } - - explicit Avr8CommandFailure(const char* message): TargetOperationFailure(message) { - this->message = std::string(message); - } - - explicit Avr8CommandFailure( - const std::string& message, - DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::ResponseFrames::Avr8Generic::Avr8GenericResponseFrame& responseFrame - ): TargetOperationFailure(message) { - this->message = message; - - auto responsePayload = responseFrame.getPayload(); - if (responsePayload.size() == 3 && this->failureCodeToDescription.contains(responsePayload[2])) { - this->message += " - Failure reason: " + this->failureCodeToDescription.find(responsePayload[2])->second; - } - } }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/ResponseFrames/AVR8Generic/GetDeviceId.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/ResponseFrames/AVR8Generic/GetDeviceId.hpp index 97ffb738..03cb1a81 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/ResponseFrames/AVR8Generic/GetDeviceId.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/ResponseFrames/AVR8Generic/GetDeviceId.hpp @@ -1,6 +1,7 @@ #pragma once #include "Avr8GenericResponseFrame.hpp" + #include "src/Targets/Microchip/AVR/AVR8/PhysicalInterface.hpp" namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::ResponseFrames::Avr8Generic diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/ResponseFrames/AVR8Generic/GetProgramCounter.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/ResponseFrames/AVR8Generic/GetProgramCounter.hpp index 585d17b8..960397a0 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/ResponseFrames/AVR8Generic/GetProgramCounter.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/ResponseFrames/AVR8Generic/GetProgramCounter.hpp @@ -27,5 +27,4 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::ResponseFrame return static_cast(payload[5] << 24 | payload[4] << 16 | payload[3] << 8 | payload[2]) * 2; } }; - } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/ResponseFrames/AvrResponseFrame.cpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/ResponseFrames/AvrResponseFrame.cpp index 1adf7428..a03d0bd8 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/ResponseFrames/AvrResponseFrame.cpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/ResponseFrames/AvrResponseFrame.cpp @@ -1,7 +1,5 @@ #include "AvrResponseFrame.hpp" -#include - #include "src/Exceptions/Exception.hpp" using namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr; diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/ResponseFrames/AvrResponseFrame.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/ResponseFrames/AvrResponseFrame.hpp index 8b66b9d3..a932c3e6 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/ResponseFrames/AvrResponseFrame.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/ResponseFrames/AvrResponseFrame.hpp @@ -13,40 +13,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr { class AvrResponseFrame { - private: - unsigned char SOF = 0x0E; - - /** - * Incrementing from 0x00 - */ - std::uint16_t sequenceID = 1; - - /** - * Destination sub-protocol handler ID - */ - ProtocolHandlerId protocolHandlerID = ProtocolHandlerId::AVR8_GENERIC; - - std::vector payload; - - protected: - virtual void initFromRawFrame(const std::vector& rawFrame); - - void setSequenceId(std::uint16_t sequenceId) { - this->sequenceID = sequenceId; - } - - void setProtocolHandlerId(ProtocolHandlerId protocolHandlerId) { - this->protocolHandlerID = protocolHandlerId; - } - - void setProtocolHandlerId(unsigned char protocolHandlerId) { - this->protocolHandlerID = static_cast(protocolHandlerId); - } - - void setPayload(const std::vector& payload) { - this->payload = payload; - } - public: explicit AvrResponseFrame() = default; @@ -82,5 +48,39 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr [[nodiscard]] virtual std::vector getPayloadData() { return this->payload; } + + protected: + virtual void initFromRawFrame(const std::vector& rawFrame); + + void setSequenceId(std::uint16_t sequenceId) { + this->sequenceID = sequenceId; + } + + void setProtocolHandlerId(ProtocolHandlerId protocolHandlerId) { + this->protocolHandlerID = protocolHandlerId; + } + + void setProtocolHandlerId(unsigned char protocolHandlerId) { + this->protocolHandlerID = static_cast(protocolHandlerId); + } + + void setPayload(const std::vector& payload) { + this->payload = payload; + } + + private: + unsigned char SOF = 0x0E; + + /** + * Incrementing from 0x00 + */ + std::uint16_t sequenceID = 1; + + /** + * Destination sub-protocol handler ID + */ + ProtocolHandlerId protocolHandlerID = ProtocolHandlerId::AVR8_GENERIC; + + std::vector payload; }; } diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgInterface.cpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgInterface.cpp index bf1cc389..14ff73ed 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgInterface.cpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgInterface.cpp @@ -1,7 +1,5 @@ #include "EdbgInterface.hpp" -#include -#include #include #include "src/TargetController/Exceptions/DeviceCommunicationFailure.hpp" diff --git a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgInterface.hpp b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgInterface.hpp index 0f1bda7b..68352caf 100644 --- a/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgInterface.hpp +++ b/src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/EdbgInterface.hpp @@ -39,11 +39,6 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg Protocols::CmsisDap::Edbg::Avr::AvrResponse getAvrResponse(); - virtual std::vector requestAvrResponses(); - - virtual std::optional requestAvrEvent(); - - template typename CommandFrameType::ResponseFrameType sendAvrCommandFrameAndWaitForResponseFrame( const CommandFrameType& avrCommandFrame @@ -72,5 +67,10 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg responseFrame.initFromAvrResponses(responses); return responseFrame; } + + virtual std::optional requestAvrEvent(); + + private: + virtual std::vector requestAvrResponses(); }; } diff --git a/src/DebugToolDrivers/USB/HID/HidInterface.cpp b/src/DebugToolDrivers/USB/HID/HidInterface.cpp index b8bbbdb0..3faee7ac 100644 --- a/src/DebugToolDrivers/USB/HID/HidInterface.cpp +++ b/src/DebugToolDrivers/USB/HID/HidInterface.cpp @@ -1,36 +1,13 @@ #include "HidInterface.hpp" -#include -#include - -#include "hidapi.hpp" #include "src/Logger/Logger.hpp" + #include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp" #include "src/TargetController/Exceptions/DeviceCommunicationFailure.hpp" using namespace Bloom::Usb; using namespace Bloom::Exceptions; -std::string HidInterface::getDevicePathByInterfaceNumber(const std::uint16_t& interfaceNumber) { - hid_device_info* hidDeviceInfoList = hid_enumerate(this->getVendorId(), this->getProductId()); - - while (hidDeviceInfoList != nullptr) { - if (hidDeviceInfoList->interface_number == interfaceNumber) { - break; - } - - hidDeviceInfoList = hidDeviceInfoList->next; - } - - if (hidDeviceInfoList == nullptr) { - throw DeviceInitializationFailure("Failed to match interface number with HID interface."); - } - - auto path = std::string(hidDeviceInfoList->path); - hid_free_enumeration(hidDeviceInfoList); - return path; -} - void HidInterface::init() { if (this->libUsbDevice == nullptr) { throw DeviceInitializationFailure("Cannot initialise interface without libusb device pointer."); @@ -72,20 +49,24 @@ void HidInterface::close() { Interface::close(); } -std::size_t HidInterface::read(unsigned char* buffer, std::size_t maxLength, unsigned int timeout) { - int transferred; +std::vector HidInterface::read(unsigned int timeout) { + std::vector output; + auto readSize = this->getInputReportSize(); - if ((transferred = hid_read_timeout( - this->hidDevice, - buffer, - maxLength, - timeout == 0 ? -1 : static_cast(timeout)) - ) == -1 - ) { - throw DeviceCommunicationFailure("Failed to read from HID device."); + // Attempt to read the first HID report packet, and whatever is left after that. + output.resize(readSize); + auto transferredByteCount = this->read(output.data(), readSize, timeout); + auto totalByteCount = transferredByteCount; + + while (transferredByteCount >= readSize) { + output.resize(totalByteCount + readSize); + + transferredByteCount = this->read(output.data() + totalByteCount, readSize, 1); + totalByteCount += transferredByteCount; } - return static_cast(transferred); + output.resize(totalByteCount); + return output; } void HidInterface::write(std::vector buffer) { @@ -107,27 +88,43 @@ void HidInterface::write(std::vector buffer) { if ((transferred = hid_write(this->getHidDevice(), buffer.data(), length)) != length) { Logger::debug("Attempted to write " + std::to_string(length) - + " bytes to HID interface. Bytes written: " + std::to_string(transferred)); + + " bytes to HID interface. Bytes written: " + std::to_string(transferred)); throw DeviceCommunicationFailure("Failed to write data to HID interface."); } } -std::vector HidInterface::read(unsigned int timeout) { - std::vector output; - auto readSize = this->getInputReportSize(); +std::size_t HidInterface::read(unsigned char* buffer, std::size_t maxLength, unsigned int timeout) { + int transferred; - // Attempt to read the first HID report packet, and whatever is left after that. - output.resize(readSize); - auto transferredByteCount = this->read(output.data(), readSize, timeout); - auto totalByteCount = transferredByteCount; - - while (transferredByteCount >= readSize) { - output.resize(totalByteCount + readSize); - - transferredByteCount = this->read(output.data() + totalByteCount, readSize, 1); - totalByteCount += transferredByteCount; + if ((transferred = hid_read_timeout( + this->hidDevice, + buffer, + maxLength, + timeout == 0 ? -1 : static_cast(timeout)) + ) == -1 + ) { + throw DeviceCommunicationFailure("Failed to read from HID device."); } - output.resize(totalByteCount); - return output; + return static_cast(transferred); +} + +std::string HidInterface::getDevicePathByInterfaceNumber(const std::uint16_t& interfaceNumber) { + hid_device_info* hidDeviceInfoList = hid_enumerate(this->getVendorId(), this->getProductId()); + + while (hidDeviceInfoList != nullptr) { + if (hidDeviceInfoList->interface_number == interfaceNumber) { + break; + } + + hidDeviceInfoList = hidDeviceInfoList->next; + } + + if (hidDeviceInfoList == nullptr) { + throw DeviceInitializationFailure("Failed to match interface number with HID interface."); + } + + auto path = std::string(hidDeviceInfoList->path); + hid_free_enumeration(hidDeviceInfoList); + return path; } diff --git a/src/DebugToolDrivers/USB/HID/HidInterface.hpp b/src/DebugToolDrivers/USB/HID/HidInterface.hpp index 1ff01197..6c07b816 100644 --- a/src/DebugToolDrivers/USB/HID/HidInterface.hpp +++ b/src/DebugToolDrivers/USB/HID/HidInterface.hpp @@ -17,6 +17,54 @@ namespace Bloom::Usb */ class HidInterface: public Interface { + public: + std::size_t getInputReportSize() const { + return this->inputReportSize; + } + + /** + * Claims the USB HID interface and obtains a hid_device instance + */ + void init() override; + + /** + * Closes the hid_device and releases any claimed interfaces (via hid_close()) + */ + void close() override; + + /** + * Reads as much data as the device has to offer, into a vector. + * + * If `timeout` is set to 0, this method will block until at least one HID report + * packet is received. + * + * @param timeout + * + * @return + * A vector of the data received from the device. + */ + std::vector read(unsigned int timeout = 0); + + /** + * Writes buffer to HID output endpoint. + * + * @param buffer + */ + void write(std::vector buffer); + + /** + * Resolves a device path from a USB interface number. + * + * @param interfaceNumber + * @return + */ + std::string getDevicePathByInterfaceNumber(const std::uint16_t& interfaceNumber); + + protected: + hid_device* getHidDevice() const { + return this->hidDevice; + } + private: /** * The HIDAPI library provides a hid_device data structure to represent a USB HID interface. @@ -58,53 +106,5 @@ namespace Bloom::Usb * Number of bytes read. */ std::size_t read(unsigned char* buffer, std::size_t maxLength, unsigned int timeout); - - protected: - hid_device* getHidDevice() const { - return this->hidDevice; - } - - public: - std::size_t getInputReportSize() const { - return this->inputReportSize; - } - - /** - * Claims the USB HID interface and obtains a hid_device instance - */ - void init() override; - - /** - * Closes the hid_device and releases any claimed interfaces (via hid_close()) - */ - void close() override; - - /** - * Writes buffer to HID output endpoint. - * - * @param buffer - */ - void write(std::vector buffer); - - /** - * Reads as much data as the device has to offer, into a vector. - * - * If `timeout` is set to 0, this method will block until at least one HID report - * packet is received. - * - * @param timeout - * - * @return - * A vector of the data received from the device. - */ - std::vector read(unsigned int timeout = 0); - - /** - * Resolves a device path from a USB interface number. - * - * @param interfaceNumber - * @return - */ - std::string getDevicePathByInterfaceNumber(const std::uint16_t& interfaceNumber); }; } diff --git a/src/DebugToolDrivers/USB/Interface.hpp b/src/DebugToolDrivers/USB/Interface.hpp index c2e0cda9..806cf51b 100644 --- a/src/DebugToolDrivers/USB/Interface.hpp +++ b/src/DebugToolDrivers/USB/Interface.hpp @@ -10,19 +10,6 @@ namespace Bloom::Usb { class Interface { - protected: - libusb_device* libUsbDevice = nullptr; - libusb_device_handle* libUsbDeviceHandle = nullptr; - - std::uint16_t vendorId = 0; - std::uint16_t productId = 0; - - std::uint8_t number = 0; - std::string name; - - bool initialised = false; - bool claimed = false; - public: explicit Interface(const std::uint8_t& interfaceNumber = 0) { this->setNumber(interfaceNumber); @@ -112,5 +99,18 @@ namespace Bloom::Usb */ virtual int read(unsigned char* buffer, unsigned char endPoint, std::size_t length, std::size_t timeout); virtual void write(unsigned char* buffer, unsigned char endPoint, int length); + + protected: + libusb_device* libUsbDevice = nullptr; + libusb_device_handle* libUsbDeviceHandle = nullptr; + + std::uint16_t vendorId = 0; + std::uint16_t productId = 0; + + std::uint8_t number = 0; + std::string name; + + bool initialised = false; + bool claimed = false; }; } diff --git a/src/DebugToolDrivers/USB/UsbDevice.cpp b/src/DebugToolDrivers/USB/UsbDevice.cpp index 795d2b48..9b259926 100644 --- a/src/DebugToolDrivers/USB/UsbDevice.cpp +++ b/src/DebugToolDrivers/USB/UsbDevice.cpp @@ -1,14 +1,61 @@ #include "UsbDevice.hpp" -#include -#include - #include "src/Logger/Logger.hpp" #include "src/TargetController/Exceptions/DeviceInitializationFailure.hpp" using Bloom::Usb::UsbDevice; using namespace Bloom::Exceptions; +void UsbDevice::init() { + libusb_init(&this->libUsbContext); +// libusb_set_option(this->libUsbContext, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_NONE); + auto devices = this->findMatchingDevices(); + + if (devices.empty()) { + throw DeviceInitializationFailure("Failed to find USB device with matching vendor & product ID."); + + } else if (devices.size() > 1) { + // TODO: implement support for multiple devices (maybe via serial number?) + throw DeviceInitializationFailure( + "Numerous devices of matching vendor & product ID found.\n" + "Please ensure that only one debug tool is connected and then try again." + ); + } + + // For now, just use the first device found. + auto device = devices.front(); + this->setLibUsbDevice(device); + + int libUsbStatusCode; + + // Obtain a device handle from libusb + if ((libUsbStatusCode = libusb_open(libUsbDevice, &this->libUsbDeviceHandle)) < 0) { + throw DeviceInitializationFailure( + "Failed to open USB device - error code " + std::to_string(libUsbStatusCode) + " returned." + ); + } +} + +void UsbDevice::setConfiguration(int configIndex) { + libusb_config_descriptor* configDescriptor = {}; + int libUsbStatusCode; + + if ((libUsbStatusCode = libusb_get_config_descriptor(this->libUsbDevice, 0, &configDescriptor))) { + throw DeviceInitializationFailure( + "Failed to obtain USB configuration descriptor - error code " + std::to_string(libUsbStatusCode) + + " returned." + ); + } + + if ((libUsbStatusCode = libusb_set_configuration(this->libUsbDeviceHandle, configDescriptor->bConfigurationValue))) { + throw DeviceInitializationFailure( + "Failed to set USB configuration - error code " + std::to_string(libUsbStatusCode) + " returned." + ); + } + + libusb_free_config_descriptor(configDescriptor); +} + std::vector UsbDevice::findMatchingDevices( std::optional vendorId, std::optional productId ) { @@ -45,36 +92,6 @@ std::vector UsbDevice::findMatchingDevices( return matchedDevices; } -void UsbDevice::init() { - libusb_init(&this->libUsbContext); -// libusb_set_option(this->libUsbContext, LIBUSB_OPTION_LOG_LEVEL, LIBUSB_LOG_LEVEL_NONE); - auto devices = this->findMatchingDevices(); - - if (devices.empty()) { - throw DeviceInitializationFailure("Failed to find USB device with matching vendor & product ID."); - - } else if (devices.size() > 1) { - // TODO: implement support for multiple devices (maybe via serial number?) - throw DeviceInitializationFailure( - "Numerous devices of matching vendor & product ID found.\n" - "Please ensure that only one debug tool is connected and then try again." - ); - } - - // For now, just use the first device found. - auto device = devices.front(); - this->setLibUsbDevice(device); - - int libUsbStatusCode; - - // Obtain a device handle from libusb - if ((libUsbStatusCode = libusb_open(libUsbDevice, &this->libUsbDeviceHandle)) < 0) { - throw DeviceInitializationFailure( - "Failed to open USB device - error code " + std::to_string(libUsbStatusCode) + " returned." - ); - } -} - void UsbDevice::close() { if (this->libUsbDeviceHandle != nullptr) { libusb_close(this->libUsbDeviceHandle); @@ -85,23 +102,3 @@ void UsbDevice::close() { libusb_exit(this->libUsbContext); } } - -void UsbDevice::setConfiguration(int configIndex) { - libusb_config_descriptor* configDescriptor = {}; - int libUsbStatusCode; - - if ((libUsbStatusCode = libusb_get_config_descriptor(this->libUsbDevice, 0, &configDescriptor))) { - throw DeviceInitializationFailure( - "Failed to obtain USB configuration descriptor - error code " + std::to_string(libUsbStatusCode) - + " returned." - ); - } - - if ((libUsbStatusCode = libusb_set_configuration(this->libUsbDeviceHandle, configDescriptor->bConfigurationValue))) { - throw DeviceInitializationFailure( - "Failed to set USB configuration - error code " + std::to_string(libUsbStatusCode) + " returned." - ); - } - - libusb_free_config_descriptor(configDescriptor); -} diff --git a/src/DebugToolDrivers/USB/UsbDevice.hpp b/src/DebugToolDrivers/USB/UsbDevice.hpp index 47b948c2..394c7f6e 100644 --- a/src/DebugToolDrivers/USB/UsbDevice.hpp +++ b/src/DebugToolDrivers/USB/UsbDevice.hpp @@ -12,25 +12,8 @@ namespace Bloom::Usb { class UsbDevice { - protected: - libusb_context* libUsbContext = nullptr; - libusb_device* libUsbDevice = nullptr; - libusb_device_handle* libUsbDeviceHandle = nullptr; - std::uint16_t vendorId; - std::uint16_t productId; - - std::vector findMatchingDevices( - std::optional vendorId = std::nullopt, std::optional productId = std::nullopt - ); - - void close(); - public: - UsbDevice(std::uint16_t vendorId, std::uint16_t productId) { - this->vendorId = vendorId; - this->productId = productId; - }; - + UsbDevice(std::uint16_t vendorId, std::uint16_t productId): vendorId(vendorId), productId(productId) {}; ~UsbDevice() = default; void init(); @@ -57,5 +40,18 @@ namespace Bloom::Usb * @param configIndex */ virtual void setConfiguration(int configIndex); + + protected: + libusb_context* libUsbContext = nullptr; + libusb_device* libUsbDevice = nullptr; + libusb_device_handle* libUsbDeviceHandle = nullptr; + std::uint16_t vendorId; + std::uint16_t productId; + + std::vector findMatchingDevices( + std::optional vendorId = std::nullopt, std::optional productId = std::nullopt + ); + + void close(); }; } diff --git a/src/EventManager/EventListener.cpp b/src/EventManager/EventListener.cpp index 73128d3b..051a454c 100644 --- a/src/EventManager/EventListener.cpp +++ b/src/EventManager/EventListener.cpp @@ -1,5 +1,7 @@ #include "EventListener.hpp" +#include "src/Logger/Logger.hpp" + using namespace Bloom; using namespace Bloom::Events; @@ -7,11 +9,6 @@ std::set EventListener::getRegisteredEventTypes() { return this->registeredEventTypes.getValue(); } -void EventListener::clearAllCallbacks() { - auto lock = this->eventTypeToCallbacksMapping.acquireLock(); - this->eventTypeToCallbacksMapping.getReference().clear(); -} - void EventListener::registerEvent(SharedGenericEventPointer event) { Logger::debug("Event \"" + event->getName() + "\" (" + std::to_string(event->id) + ") registered for listener " + this->name); @@ -26,45 +23,6 @@ void EventListener::registerEvent(SharedGenericEventPointer event) { } } -std::vector EventListener::getEvents() { - auto queueLock = this->eventQueueByEventType.acquireLock(); - auto& eventQueueByType = this->eventQueueByEventType.getReference(); - std::vector output; - - for (auto& eventQueue: eventQueueByType) { - if (!eventQueue.second.empty()) { - output.push_back(std::move(eventQueue.second.front())); - eventQueue.second.pop(); - } - } - - std::sort(output.begin(), output.end(), [](const SharedGenericEventPointer& a, const SharedGenericEventPointer& b) { - return a->id < b->id; - }); - - return output; -} - -void EventListener::dispatchEvent(const SharedGenericEventPointer& event) { - Logger::debug("Dispatching event " + event->getName() + " (" + std::to_string(event->id) + ")."); - // Dispatch the event to all registered handlers - auto mappingLock = this->eventTypeToCallbacksMapping.acquireLock(); - auto& callbacks = this->eventTypeToCallbacksMapping.getReference().find(event->getType())->second; - mappingLock.unlock(); - - for (auto& callback : callbacks) { - callback(*(event.get())); - } -} - -void EventListener::dispatchCurrentEvents() { - auto events = this->getEvents(); - - for (auto const& event: events) { - dispatchEvent(event); - } -} - void EventListener::waitAndDispatch(int msTimeout) { auto queueLock = this->eventQueueByEventType.acquireLock(); auto& eventQueueByType = this->eventQueueByEventType.getReference(); @@ -95,3 +53,47 @@ void EventListener::waitAndDispatch(int msTimeout) { this->dispatchCurrentEvents(); } + +void EventListener::dispatchEvent(const SharedGenericEventPointer& event) { + Logger::debug("Dispatching event " + event->getName() + " (" + std::to_string(event->id) + ")."); + // Dispatch the event to all registered handlers + auto mappingLock = this->eventTypeToCallbacksMapping.acquireLock(); + auto& callbacks = this->eventTypeToCallbacksMapping.getReference().find(event->getType())->second; + mappingLock.unlock(); + + for (auto& callback : callbacks) { + callback(*(event.get())); + } +} + +void EventListener::dispatchCurrentEvents() { + auto events = this->getEvents(); + + for (auto const& event: events) { + dispatchEvent(event); + } +} + +std::vector EventListener::getEvents() { + auto queueLock = this->eventQueueByEventType.acquireLock(); + auto& eventQueueByType = this->eventQueueByEventType.getReference(); + std::vector output; + + for (auto& eventQueue: eventQueueByType) { + if (!eventQueue.second.empty()) { + output.push_back(std::move(eventQueue.second.front())); + eventQueue.second.pop(); + } + } + + std::sort(output.begin(), output.end(), [](const SharedGenericEventPointer& a, const SharedGenericEventPointer& b) { + return a->id < b->id; + }); + + return output; +} + +void EventListener::clearAllCallbacks() { + auto lock = this->eventTypeToCallbacksMapping.acquireLock(); + this->eventTypeToCallbacksMapping.getReference().clear(); +} diff --git a/src/EventManager/EventListener.hpp b/src/EventManager/EventListener.hpp index a8c9a7dc..a9698756 100644 --- a/src/EventManager/EventListener.hpp +++ b/src/EventManager/EventListener.hpp @@ -14,7 +14,6 @@ #include #include "src/EventManager/Events/Events.hpp" -#include "src/Logger/Logger.hpp" #include "src/Helpers/SyncSafe.hpp" #include "src/Helpers/EventNotifier.hpp" @@ -42,41 +41,6 @@ namespace Bloom */ class EventListener { - private: - /** - * Human readable name for event listeners. - * - * TODO: This was useful during development, but may no longer be needed. - */ - std::string name; - - static inline std::atomic lastId = 0; - std::size_t id = ++(EventListener::lastId); - - /** - * Holds all events registered to this listener. - * - * Events are grouped by event type, and removed from their queue just *before* the dispatching to - * registered handlers begins. - */ - SyncSafe>> eventQueueByEventType; - std::condition_variable eventQueueByEventTypeCV; - - /** - * A mapping of event types to a vector of callback functions. Events will be dispatched to these - * callback functions, during a call to EventListener::dispatchEvent(). - * - * Each callback will be passed a reference to the event (we wrap all registered callbacks in a lambda, where - * we perform a downcast before invoking the callback. See EventListener::registerCallbackForEventType() - * for more) - */ - SyncSafe>>> eventTypeToCallbacksMapping; - SyncSafe> registeredEventTypes; - - std::shared_ptr interruptEventNotifier = nullptr; - - std::vector getEvents(); - public: explicit EventListener(std::string name): name(std::move(name)) {}; @@ -370,6 +334,41 @@ namespace Bloom * Removes all callbacks registered for the event listener. */ void clearAllCallbacks(); + + private: + /** + * Human readable name for event listeners. + * + * TODO: This was useful during development, but may no longer be needed. + */ + std::string name; + + static inline std::atomic lastId = 0; + std::size_t id = ++(EventListener::lastId); + + /** + * Holds all events registered to this listener. + * + * Events are grouped by event type, and removed from their queue just *before* the dispatching to + * registered handlers begins. + */ + SyncSafe>> eventQueueByEventType; + std::condition_variable eventQueueByEventTypeCV; + + /** + * A mapping of event types to a vector of callback functions. Events will be dispatched to these + * callback functions, during a call to EventListener::dispatchEvent(). + * + * Each callback will be passed a reference to the event (we wrap all registered callbacks in a lambda, where + * we perform a downcast before invoking the callback. See EventListener::registerCallbackForEventType() + * for more) + */ + SyncSafe>>> eventTypeToCallbacksMapping; + SyncSafe> registeredEventTypes; + + std::shared_ptr interruptEventNotifier = nullptr; + + std::vector getEvents(); }; /** diff --git a/src/EventManager/EventManager.hpp b/src/EventManager/EventManager.hpp index a5cc8471..e6132e7b 100644 --- a/src/EventManager/EventManager.hpp +++ b/src/EventManager/EventManager.hpp @@ -19,13 +19,6 @@ namespace Bloom */ class EventManager { - private: - /** - * A mapping of listener IDs to registered listeners. Each registered listener is given an interger ID. - */ - std::map> registeredListeners; - std::mutex registerListenerMutex; - public: /** * Registers an EventListener instance with this manager. @@ -62,5 +55,12 @@ namespace Bloom * @return */ bool isEventTypeListenedFor(Events::EventType eventType); + + private: + /** + * A mapping of listener IDs to registered listeners. Each registered listener is given an interger ID. + */ + std::map> registeredListeners; + std::mutex registerListenerMutex; }; } diff --git a/src/EventManager/Events/DebugServerThreadStateChanged.hpp b/src/EventManager/Events/DebugServerThreadStateChanged.hpp index 592285cc..29d09796 100644 --- a/src/EventManager/Events/DebugServerThreadStateChanged.hpp +++ b/src/EventManager/Events/DebugServerThreadStateChanged.hpp @@ -9,8 +9,6 @@ namespace Bloom::Events { class DebugServerThreadStateChanged: public Event { - private: - ThreadState state; public: static inline EventType type = EventType::DEBUG_SERVER_THREAD_STATE_CHANGED; static inline const std::string name = "DebugServerThreadStateChanged"; @@ -28,5 +26,8 @@ namespace Bloom::Events [[nodiscard]] ThreadState getState() const { return this->state; } + + private: + ThreadState state; }; } diff --git a/src/EventManager/Events/Event.hpp b/src/EventManager/Events/Event.hpp index ae61a6bc..5024fc7b 100644 --- a/src/EventManager/Events/Event.hpp +++ b/src/EventManager/Events/Event.hpp @@ -55,9 +55,6 @@ namespace Bloom::Events class Event { - private: - static inline std::atomic lastEventId = 0; - public: int id = ++(Event::lastEventId); QDateTime createdTimestamp = DateTime::currentDateTime(); @@ -73,5 +70,8 @@ namespace Bloom::Events [[nodiscard]] virtual EventType getType() const { return Event::type; } + + private: + static inline std::atomic lastEventId = 0; }; } diff --git a/src/EventManager/Events/InsightThreadStateChanged.hpp b/src/EventManager/Events/InsightThreadStateChanged.hpp index c6c8d442..771e81b3 100644 --- a/src/EventManager/Events/InsightThreadStateChanged.hpp +++ b/src/EventManager/Events/InsightThreadStateChanged.hpp @@ -9,9 +9,6 @@ namespace Bloom::Events { class InsightThreadStateChanged: public Event { - private: - ThreadState state; - public: explicit InsightThreadStateChanged(ThreadState state): state(state) {}; @@ -29,5 +26,8 @@ namespace Bloom::Events ThreadState getState() const { return this->state; } + + private: + ThreadState state; }; } diff --git a/src/EventManager/Events/TargetControllerThreadStateChanged.hpp b/src/EventManager/Events/TargetControllerThreadStateChanged.hpp index c18a42f1..a423513e 100644 --- a/src/EventManager/Events/TargetControllerThreadStateChanged.hpp +++ b/src/EventManager/Events/TargetControllerThreadStateChanged.hpp @@ -9,9 +9,6 @@ namespace Bloom::Events { class TargetControllerThreadStateChanged: public Event { - private: - ThreadState state; - public: static inline EventType type = EventType::TARGET_CONTROLLER_THREAD_STATE_CHANGED; static inline const std::string name = "TargetControllerThreadStateChanged"; @@ -29,5 +26,8 @@ namespace Bloom::Events ThreadState getState() const { return this->state; } + + private: + ThreadState state; }; } diff --git a/src/Exceptions/Exception.hpp b/src/Exceptions/Exception.hpp index 3c0fe02a..ed49d4ec 100644 --- a/src/Exceptions/Exception.hpp +++ b/src/Exceptions/Exception.hpp @@ -6,9 +6,6 @@ namespace Bloom::Exceptions { class Exception: public std::runtime_error { - protected: - std::string message; - public: explicit Exception(): std::runtime_error("") {} @@ -27,5 +24,8 @@ namespace Bloom::Exceptions std::string getMessage() const { return this->message; } + + protected: + std::string message; }; } diff --git a/src/Helpers/BiMap.hpp b/src/Helpers/BiMap.hpp index a350c27a..ae3e3ff2 100644 --- a/src/Helpers/BiMap.hpp +++ b/src/Helpers/BiMap.hpp @@ -19,10 +19,6 @@ namespace Bloom template class BiMap { - private: - std::unordered_map map = {}; - std::unordered_map::iterator> flippedMap = {}; - public: BiMap(std::initializer_list> elements) { for (auto it = elements.begin(); it != elements.end(); ++it) { @@ -75,5 +71,9 @@ namespace Bloom insertResultPair.first )); } + + private: + std::unordered_map map = {}; + std::unordered_map::iterator> flippedMap = {}; }; } diff --git a/src/Helpers/DateTime.hpp b/src/Helpers/DateTime.hpp index 3d87b3f0..c1f5c956 100644 --- a/src/Helpers/DateTime.hpp +++ b/src/Helpers/DateTime.hpp @@ -11,9 +11,6 @@ namespace Bloom */ class DateTime { - private: - static inline std::mutex currentDateTimeMutex; - public: /** * The QDateTime::currentDateTime() static function is not thread-safe. This may be caused by the @@ -38,5 +35,8 @@ namespace Bloom auto lock = std::unique_lock(DateTime::currentDateTimeMutex); return dateTime.timeZoneAbbreviation(); } + + private: + static inline std::mutex currentDateTimeMutex; }; } diff --git a/src/Helpers/EventNotifier.hpp b/src/Helpers/EventNotifier.hpp index 42d685e6..66d98ab3 100644 --- a/src/Helpers/EventNotifier.hpp +++ b/src/Helpers/EventNotifier.hpp @@ -25,26 +25,6 @@ namespace Bloom */ class EventNotifier { - private: - int fileDescriptor = -1; - std::atomic initialised = false; - - void init() { - this->fileDescriptor = ::eventfd(0, EFD_NONBLOCK); - - if (this->fileDescriptor < -1) { - throw Exceptions::Exception("Failed to create new eventfd object - error number: " - + std::to_string(errno)); - } - - this->initialised = true; - } - - void close() { - ::close(this->fileDescriptor); - this->initialised = false; - } - public: EventNotifier() { this->init(); @@ -78,5 +58,25 @@ namespace Bloom "error number: " + std::to_string(errno)); } } + + private: + int fileDescriptor = -1; + std::atomic initialised = false; + + void init() { + this->fileDescriptor = ::eventfd(0, EFD_NONBLOCK); + + if (this->fileDescriptor < -1) { + throw Exceptions::Exception("Failed to create new eventfd object - error number: " + + std::to_string(errno)); + } + + this->initialised = true; + } + + void close() { + ::close(this->fileDescriptor); + this->initialised = false; + } }; } diff --git a/src/Helpers/SyncSafe.hpp b/src/Helpers/SyncSafe.hpp index b6856cae..4885df0f 100644 --- a/src/Helpers/SyncSafe.hpp +++ b/src/Helpers/SyncSafe.hpp @@ -17,10 +17,6 @@ namespace Bloom template class SyncSafe { - private: - std::mutex mutex; - Type value; - public: SyncSafe() = default; @@ -51,5 +47,9 @@ namespace Bloom std::unique_lock acquireLock() { return std::unique_lock(this->mutex); }; + + private: + std::mutex mutex; + Type value; }; } diff --git a/src/Helpers/Thread.hpp b/src/Helpers/Thread.hpp index dfc41e96..d86c5e59 100644 --- a/src/Helpers/Thread.hpp +++ b/src/Helpers/Thread.hpp @@ -18,8 +18,10 @@ namespace Bloom class Thread { - private: - SyncSafe state = SyncSafe(ThreadState::UNINITIALISED); + public: + virtual ThreadState getThreadState() { + return this->state.getValue(); + }; protected: virtual void setThreadState(ThreadState state) { @@ -42,9 +44,7 @@ namespace Bloom pthread_setname_np(pthread_self(), name.c_str()); } - public: - virtual ThreadState getThreadState() { - return this->state.getValue(); - }; + private: + SyncSafe state = SyncSafe(ThreadState::UNINITIALISED); }; } diff --git a/src/Insight/InsightWorker/InsightWorker.cpp b/src/Insight/InsightWorker/InsightWorker.cpp index adc92fd4..cb60c84e 100644 --- a/src/Insight/InsightWorker/InsightWorker.cpp +++ b/src/Insight/InsightWorker/InsightWorker.cpp @@ -1,6 +1,5 @@ #include "InsightWorker.hpp" -#include #include #include @@ -12,6 +11,16 @@ using namespace Bloom::Exceptions; using Bloom::Targets::TargetState; +InsightWorker::InsightWorker(EventManager& eventManager): eventManager(eventManager) {} + +void InsightWorker::queueTask(InsightWorkerTask* task) { + auto taskQueueLock = this->queuedTasks.acquireLock(); + task->moveToThread(this->thread()); + task->setParent(this); + this->queuedTasks.getReference().push(task); + emit this->taskQueued(); +} + void InsightWorker::startup() { Logger::debug("Starting InsightWorker thread"); this->eventManager.registerListener(this->eventListener); @@ -43,12 +52,8 @@ void InsightWorker::startup() { ); } -void InsightWorker::queueTask(InsightWorkerTask* task) { - auto taskQueueLock = this->queuedTasks.acquireLock(); - task->moveToThread(this->thread()); - task->setParent(this); - this->queuedTasks.getReference().push(task); - emit this->taskQueued(); +void InsightWorker::requestPinStates(int variantId) { + this->targetControllerConsole.requestPinStates(variantId); } std::optional InsightWorker::getQueuedTask() { @@ -65,18 +70,6 @@ std::optional InsightWorker::getQueuedTask() { return task; } -void InsightWorker::executeTasks() { - auto task = std::optional(); - - while ((task = this->getQueuedTask()).has_value()) { - task.value()->execute(this->targetControllerConsole); - } -} - -void InsightWorker::requestPinStates(int variantId) { - this->targetControllerConsole.requestPinStates(variantId); -} - void InsightWorker::onTargetStoppedEvent(const Events::TargetExecutionStopped& event) { /* * When we report a target halt to Insight, Insight will immediately seek more data from the target (such as GPIO @@ -135,3 +128,11 @@ void InsightWorker::onTargetControllerStateReportedEvent(const Events::TargetCon } this->lastTargetControllerState = event.state; } + +void InsightWorker::executeTasks() { + auto task = std::optional(); + + while ((task = this->getQueuedTask()).has_value()) { + task.value()->execute(this->targetControllerConsole); + } +} diff --git a/src/Insight/InsightWorker/InsightWorker.hpp b/src/Insight/InsightWorker/InsightWorker.hpp index fc37bc0f..880bc4ad 100644 --- a/src/Insight/InsightWorker/InsightWorker.hpp +++ b/src/Insight/InsightWorker/InsightWorker.hpp @@ -20,7 +20,29 @@ namespace Bloom */ class InsightWorker: public QObject { - Q_OBJECT + Q_OBJECT + + public: + explicit InsightWorker(EventManager& eventManager); + + void queueTask(InsightWorkerTask* task); + + void dispatchEvents() { + this->eventListener->dispatchCurrentEvents(); + } + + public slots: + void startup(); + void requestPinStates(int variantId); + + signals: + void taskQueued(); + void targetStateUpdated(Bloom::Targets::TargetState newState); + void targetProgramCounterUpdated(quint32 programCounter); + void targetControllerSuspended(); + void targetControllerResumed(const Bloom::Targets::TargetDescriptor& targetDescriptor); + void targetRegistersWritten(const Bloom::Targets::TargetRegisters& targetRegisters, const QDateTime& timestamp); + private: EventManager& eventManager; EventListenerPointer eventListener = std::make_shared("InsightWorkerEventListener"); @@ -44,26 +66,5 @@ namespace Bloom private slots: void executeTasks(); - - public: - explicit InsightWorker(EventManager& eventManager): eventManager(eventManager) {}; - - void dispatchEvents() { - this->eventListener->dispatchCurrentEvents(); - } - - void queueTask(InsightWorkerTask* task); - - public slots: - void startup(); - void requestPinStates(int variantId); - - signals: - void taskQueued(); - void targetStateUpdated(Bloom::Targets::TargetState newState); - void targetProgramCounterUpdated(quint32 programCounter); - void targetControllerSuspended(); - void targetControllerResumed(const Bloom::Targets::TargetDescriptor& targetDescriptor); - void targetRegistersWritten(const Bloom::Targets::TargetRegisters& targetRegisters, const QDateTime& timestamp); }; } diff --git a/src/Insight/InsightWorker/Tasks/InsightWorkerTask.cpp b/src/Insight/InsightWorker/Tasks/InsightWorkerTask.cpp index 2e2f980e..310ee870 100644 --- a/src/Insight/InsightWorker/Tasks/InsightWorkerTask.cpp +++ b/src/Insight/InsightWorker/Tasks/InsightWorkerTask.cpp @@ -1,5 +1,7 @@ #include "InsightWorkerTask.hpp" +#include "src/Logger/Logger.hpp" + using namespace Bloom; void InsightWorkerTask::execute(TargetControllerConsole& targetControllerConsole) { diff --git a/src/Insight/InsightWorker/Tasks/InsightWorkerTask.hpp b/src/Insight/InsightWorker/Tasks/InsightWorkerTask.hpp index a4f0259b..fcfd4cb3 100644 --- a/src/Insight/InsightWorker/Tasks/InsightWorkerTask.hpp +++ b/src/Insight/InsightWorker/Tasks/InsightWorkerTask.hpp @@ -17,9 +17,7 @@ namespace Bloom class InsightWorkerTask: public QObject { - Q_OBJECT - protected: - virtual void run(TargetControllerConsole& targetControllerConsole) = 0; + Q_OBJECT public: InsightWorkerTaskState state; @@ -32,5 +30,8 @@ namespace Bloom void started(); void failed(QString errorMessage); void completed(); + + protected: + virtual void run(TargetControllerConsole& targetControllerConsole) = 0; }; } diff --git a/src/Insight/InsightWorker/Tasks/ReadTargetRegisters.hpp b/src/Insight/InsightWorker/Tasks/ReadTargetRegisters.hpp index 9a586835..3fccefa9 100644 --- a/src/Insight/InsightWorker/Tasks/ReadTargetRegisters.hpp +++ b/src/Insight/InsightWorker/Tasks/ReadTargetRegisters.hpp @@ -7,12 +7,7 @@ namespace Bloom { class ReadTargetRegisters: public InsightWorkerTask { - Q_OBJECT - private: - Targets::TargetRegisterDescriptors descriptors; - - protected: - void run(TargetControllerConsole& targetControllerConsole) override; + Q_OBJECT public: ReadTargetRegisters(const Targets::TargetRegisterDescriptors& descriptors): @@ -20,5 +15,11 @@ namespace Bloom signals: void targetRegistersRead(Targets::TargetRegisters registers); + + protected: + void run(TargetControllerConsole& targetControllerConsole) override; + + private: + Targets::TargetRegisterDescriptors descriptors; }; } diff --git a/src/Insight/InsightWorker/Tasks/RefreshTargetPinStates.hpp b/src/Insight/InsightWorker/Tasks/RefreshTargetPinStates.hpp index 88368e87..b6819106 100644 --- a/src/Insight/InsightWorker/Tasks/RefreshTargetPinStates.hpp +++ b/src/Insight/InsightWorker/Tasks/RefreshTargetPinStates.hpp @@ -8,17 +8,18 @@ namespace Bloom { class RefreshTargetPinStates: public InsightWorkerTask { - Q_OBJECT - private: - int variantId; - - protected: - void run(TargetControllerConsole& targetControllerConsole) override; + Q_OBJECT public: RefreshTargetPinStates(int variantId): InsightWorkerTask(), variantId(variantId) {} signals: void targetPinStatesRetrieved(Bloom::Targets::TargetPinStateMappingType pinStatesByNumber); + + protected: + void run(TargetControllerConsole& targetControllerConsole) override; + + private: + int variantId; }; } diff --git a/src/Insight/InsightWorker/Tasks/SetTargetPinState.hpp b/src/Insight/InsightWorker/Tasks/SetTargetPinState.hpp index f4d027c0..4957f26b 100644 --- a/src/Insight/InsightWorker/Tasks/SetTargetPinState.hpp +++ b/src/Insight/InsightWorker/Tasks/SetTargetPinState.hpp @@ -7,16 +7,17 @@ namespace Bloom { class SetTargetPinState: public InsightWorkerTask { - Q_OBJECT - private: - Targets::TargetPinDescriptor pinDescriptor; - Targets::TargetPinState pinState; - - protected: - void run(TargetControllerConsole& targetControllerConsole) override; + Q_OBJECT public: SetTargetPinState(const Targets::TargetPinDescriptor& pinDescriptor, const Targets::TargetPinState& pinState): InsightWorkerTask(), pinDescriptor(pinDescriptor), pinState(pinState) {} + + protected: + void run(TargetControllerConsole& targetControllerConsole) override; + + private: + Targets::TargetPinDescriptor pinDescriptor; + Targets::TargetPinState pinState; }; } diff --git a/src/Insight/InsightWorker/Tasks/WriteTargetRegister.hpp b/src/Insight/InsightWorker/Tasks/WriteTargetRegister.hpp index 3ee30968..fd86bc6b 100644 --- a/src/Insight/InsightWorker/Tasks/WriteTargetRegister.hpp +++ b/src/Insight/InsightWorker/Tasks/WriteTargetRegister.hpp @@ -7,15 +7,16 @@ namespace Bloom { class WriteTargetRegister: public InsightWorkerTask { - Q_OBJECT - private: - Targets::TargetRegister targetRegister; - - protected: - void run(TargetControllerConsole& targetControllerConsole) override; + Q_OBJECT public: WriteTargetRegister(const Targets::TargetRegister& targetRegister): InsightWorkerTask(), targetRegister(targetRegister) {} + + protected: + void run(TargetControllerConsole& targetControllerConsole) override; + + private: + Targets::TargetRegister targetRegister; }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/AboutWindow.cpp b/src/Insight/UserInterfaces/InsightWindow/AboutWindow.cpp index d541b9fc..51465ab7 100644 --- a/src/Insight/UserInterfaces/InsightWindow/AboutWindow.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/AboutWindow.cpp @@ -1,11 +1,10 @@ +#include "AboutWindow.hpp" + #include -#include "AboutWindow.hpp" -#include "Widgets/TargetWidgets/DIP/DualInlinePackageWidget.hpp" -#include "src/Logger/Logger.hpp" #include "src/Exceptions/Exception.hpp" -#include "src/Application.hpp" #include "src/Helpers/Paths.hpp" +#include "src/Application.hpp" using namespace Bloom; using namespace Exceptions; diff --git a/src/Insight/UserInterfaces/InsightWindow/AboutWindow.hpp b/src/Insight/UserInterfaces/InsightWindow/AboutWindow.hpp index 2bddf2d8..cf7d9152 100644 --- a/src/Insight/UserInterfaces/InsightWindow/AboutWindow.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/AboutWindow.hpp @@ -9,9 +9,7 @@ namespace Bloom { class AboutWindow: public QObject { - Q_OBJECT - private: - QWidget* windowWidget = nullptr; + Q_OBJECT public: explicit AboutWindow(QWidget* parent); @@ -24,5 +22,8 @@ namespace Bloom this->windowWidget->show(); } } + + private: + QWidget* windowWidget = nullptr; }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/InsightWindow.cpp b/src/Insight/UserInterfaces/InsightWindow/InsightWindow.cpp index 80d376a7..e4bdaec8 100644 --- a/src/Insight/UserInterfaces/InsightWindow/InsightWindow.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/InsightWindow.cpp @@ -143,15 +143,109 @@ void InsightWindow::init(TargetDescriptor targetDescriptor) { this->activate(); } -void InsightWindow::toggleUi(bool disable) { - this->uiDisabled = disable; - - if (this->refreshIoInspectionButton != nullptr) { - this->refreshIoInspectionButton->setDisabled(disable); - this->refreshIoInspectionButton->repaint(); +void InsightWindow::onTargetControllerSuspended() { + if (this->activated) { + this->deactivate(); } } +void InsightWindow::onTargetControllerResumed(const TargetDescriptor& targetDescriptor) { + if (!this->activated) { + this->targetDescriptor = targetDescriptor; + this->activate(); + } +} + +void InsightWindow::onTargetStateUpdate(TargetState newState) { + this->targetState = newState; + + if (newState == TargetState::RUNNING) { + this->targetStatusLabel->setText("Running"); + this->programCounterValueLabel->setText("-"); + + } else if (newState == TargetState::STOPPED) { + this->targetStatusLabel->setText("Stopped"); + this->toggleUi(false); + + } else { + this->targetStatusLabel->setText("Unknown"); + } +} + +void InsightWindow::onTargetProgramCounterUpdate(quint32 programCounter) { + this->programCounterValueLabel->setText( + "0x" + QString::number(programCounter, 16).toUpper() + " (" + QString::number(programCounter) + ")" + ); +} + +void InsightWindow::openReportIssuesUrl() { + auto url = QUrl("https://bloom.oscillate.io/report-issue"); + /* + * The https://bloom.oscillate.io/report-issue URL just redirects to the Bloom GitHub issue page. + * + * We can use query parameters in the URL to pre-fill the body of the issue. We use this to include some + * target information. + */ + auto urlQuery = QUrlQuery(); + auto issueBody = QString("Issue reported via Bloom Insight.\nTarget name: " + + QString::fromStdString(this->targetDescriptor.name) + "\n" + + "Target ID: " + QString::fromStdString(this->targetDescriptor.id) + "\n" + ); + + if (this->selectedVariant != nullptr) { + issueBody += "Target variant: " + QString::fromStdString(this->selectedVariant->name) + "\n"; + } + + issueBody += "\nPlease describe your issue below. Include as much detail as possible."; + urlQuery.addQueryItem("body", issueBody); + url.setQuery(urlQuery); + + QDesktopServices::openUrl(url); +} + +void InsightWindow::openGettingStartedUrl() { + QDesktopServices::openUrl(QUrl("https://bloom.oscillate.io/docs/getting-started")); +} + +void InsightWindow::openAboutWindow() { + if (this->aboutWindowWidget == nullptr) { + this->aboutWindowWidget = new AboutWindow(this->windowContainer); + } + + this->aboutWindowWidget->show(); +} + +void InsightWindow::toggleTargetRegistersPane() { + if (this->targetRegistersSidePane->activated) { + this->targetRegistersSidePane->deactivate(); + this->targetRegistersButton->setChecked(false); + + /* + * Given that the target registers side pane is currently the only pane in the left panel, the panel will be + * empty so no need to leave it visible. + */ + this->leftPanel->setVisible(false); + + } else { + this->targetRegistersSidePane->activate(); + this->targetRegistersButton->setChecked(true); + this->leftPanel->setVisible(true); + } +} + +void InsightWindow::resizeEvent(QResizeEvent* event) { + const auto windowSize = this->size(); + + this->windowContainer->setFixedSize(windowSize); + this->layoutContainer->setFixedSize(windowSize); + + this->adjustPanels(); +} + +void InsightWindow::showEvent(QShowEvent* event) { + this->adjustPanels(); +} + bool InsightWindow::isVariantSupported(const TargetVariant& variant) { /* * Because the size of the pin body widget is fixed, for all of our target package widgets, we run out of screen @@ -243,6 +337,15 @@ void InsightWindow::selectVariant(const TargetVariant* variant) { } } +void InsightWindow::toggleUi(bool disable) { + this->uiDisabled = disable; + + if (this->refreshIoInspectionButton != nullptr) { + this->refreshIoInspectionButton->setDisabled(disable); + this->refreshIoInspectionButton->repaint(); + } +} + void InsightWindow::activate() { auto targetNameLabel = this->footer->findChild("target-name"); auto targetIdLabel = this->footer->findChild("target-id"); @@ -432,106 +535,3 @@ void InsightWindow::adjustPanels() { ) ); } - -void InsightWindow::resizeEvent(QResizeEvent* event) { - const auto windowSize = this->size(); - - this->windowContainer->setFixedSize(windowSize); - this->layoutContainer->setFixedSize(windowSize); - - this->adjustPanels(); -} - -void InsightWindow::showEvent(QShowEvent* event) { - this->adjustPanels(); -} - -void InsightWindow::onTargetControllerSuspended() { - if (this->activated) { - this->deactivate(); - } -} - -void InsightWindow::onTargetControllerResumed(const TargetDescriptor& targetDescriptor) { - if (!this->activated) { - this->targetDescriptor = targetDescriptor; - this->activate(); - } -} - -void InsightWindow::openReportIssuesUrl() { - auto url = QUrl("https://bloom.oscillate.io/report-issue"); - /* - * The https://bloom.oscillate.io/report-issue URL just redirects to the Bloom GitHub issue page. - * - * We can use query parameters in the URL to pre-fill the body of the issue. We use this to include some - * target information. - */ - auto urlQuery = QUrlQuery(); - auto issueBody = QString("Issue reported via Bloom Insight.\nTarget name: " - + QString::fromStdString(this->targetDescriptor.name) + "\n" - + "Target ID: " + QString::fromStdString(this->targetDescriptor.id) + "\n" - ); - - if (this->selectedVariant != nullptr) { - issueBody += "Target variant: " + QString::fromStdString(this->selectedVariant->name) + "\n"; - } - - issueBody += "\nPlease describe your issue below. Include as much detail as possible."; - urlQuery.addQueryItem("body", issueBody); - url.setQuery(urlQuery); - - QDesktopServices::openUrl(url); -} - -void InsightWindow::openGettingStartedUrl() { - QDesktopServices::openUrl(QUrl("https://bloom.oscillate.io/docs/getting-started")); -} - -void InsightWindow::openAboutWindow() { - if (this->aboutWindowWidget == nullptr) { - this->aboutWindowWidget = new AboutWindow(this->windowContainer); - } - - this->aboutWindowWidget->show(); -} - -void InsightWindow::onTargetStateUpdate(TargetState newState) { - this->targetState = newState; - - if (newState == TargetState::RUNNING) { - this->targetStatusLabel->setText("Running"); - this->programCounterValueLabel->setText("-"); - - } else if (newState == TargetState::STOPPED) { - this->targetStatusLabel->setText("Stopped"); - this->toggleUi(false); - - } else { - this->targetStatusLabel->setText("Unknown"); - } -} - -void InsightWindow::onTargetProgramCounterUpdate(quint32 programCounter) { - this->programCounterValueLabel->setText( - "0x" + QString::number(programCounter, 16).toUpper() + " (" + QString::number(programCounter) + ")" - ); -} - -void InsightWindow::toggleTargetRegistersPane() { - if (this->targetRegistersSidePane->activated) { - this->targetRegistersSidePane->deactivate(); - this->targetRegistersButton->setChecked(false); - - /* - * Given that the target registers side pane is currently the only pane in the left panel, the panel will be - * empty so no need to leave it visible. - */ - this->leftPanel->setVisible(false); - - } else { - this->targetRegistersSidePane->activate(); - this->targetRegistersButton->setChecked(true); - this->leftPanel->setVisible(true); - } -} diff --git a/src/Insight/UserInterfaces/InsightWindow/InsightWindow.hpp b/src/Insight/UserInterfaces/InsightWindow/InsightWindow.hpp index ec49e520..6e9da7b6 100644 --- a/src/Insight/UserInterfaces/InsightWindow/InsightWindow.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/InsightWindow.hpp @@ -24,7 +24,39 @@ namespace Bloom { class InsightWindow: public QMainWindow { - Q_OBJECT + Q_OBJECT + + public: + InsightWindow(InsightWorker& insightWorker); + + void setEnvironmentConfig(const EnvironmentConfig& environmentConfig) { + this->environmentConfig = environmentConfig; + this->targetConfig = environmentConfig.targetConfig; + } + + void setInsightConfig(const InsightConfig& insightConfig) { + this->insightConfig = insightConfig; + } + + void init(Targets::TargetDescriptor targetDescriptor); + + public slots: + void onTargetControllerSuspended(); + void onTargetControllerResumed(const Bloom::Targets::TargetDescriptor& targetDescriptor); + void onTargetStateUpdate(Targets::TargetState newState); + void onTargetProgramCounterUpdate(quint32 programCounter); + void openReportIssuesUrl(); + void openGettingStartedUrl(); + void openAboutWindow(); + void toggleTargetRegistersPane(); + + signals: + void refreshTargetPinStates(int variantId); + + protected: + void resizeEvent(QResizeEvent* event) override; + void showEvent(QShowEvent* event) override; + private: InsightConfig insightConfig; EnvironmentConfig environmentConfig; @@ -76,36 +108,5 @@ namespace Bloom void deactivate(); void adjustPanels(); - - protected: - void resizeEvent(QResizeEvent* event) override; - void showEvent(QShowEvent* event) override; - - public: - InsightWindow(InsightWorker& insightWorker); - - void setEnvironmentConfig(const EnvironmentConfig& environmentConfig) { - this->environmentConfig = environmentConfig; - this->targetConfig = environmentConfig.targetConfig; - } - - void setInsightConfig(const InsightConfig& insightConfig) { - this->insightConfig = insightConfig; - } - - void init(Targets::TargetDescriptor targetDescriptor); - - public slots: - void onTargetControllerSuspended(); - void onTargetControllerResumed(const Bloom::Targets::TargetDescriptor& targetDescriptor); - void onTargetStateUpdate(Targets::TargetState newState); - void onTargetProgramCounterUpdate(quint32 programCounter); - void openReportIssuesUrl(); - void openGettingStartedUrl(); - void openAboutWindow(); - void toggleTargetRegistersPane(); - - signals: - void refreshTargetPinStates(int variantId); }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/UiLoader.cpp b/src/Insight/UserInterfaces/InsightWindow/UiLoader.cpp index fb59c33e..84b34c96 100644 --- a/src/Insight/UserInterfaces/InsightWindow/UiLoader.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/UiLoader.cpp @@ -2,6 +2,7 @@ #include +// Custom widgets #include "Widgets/PanelWidget.hpp" #include "Widgets/RotatableLabel.hpp" #include "Widgets/SvgWidget.hpp" @@ -9,8 +10,6 @@ #include "Widgets/ExpandingHeightScrollAreaWidget.hpp" #include "Widgets/TargetWidgets/TargetPackageWidgetContainer.hpp" -#include "src/Logger/Logger.hpp" - using namespace Bloom; using namespace Bloom::Widgets; diff --git a/src/Insight/UserInterfaces/InsightWindow/UiLoader.hpp b/src/Insight/UserInterfaces/InsightWindow/UiLoader.hpp index 7985b5ae..edfd5bc2 100644 --- a/src/Insight/UserInterfaces/InsightWindow/UiLoader.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/UiLoader.hpp @@ -7,13 +7,17 @@ namespace Bloom { class UiLoader: public QUiLoader { - Q_OBJECT - private: - std::map> customWidgetConstructorsByWidgetName = {}; + Q_OBJECT public: explicit UiLoader(QObject* parent); QWidget* createWidget(const QString& className, QWidget* parent, const QString& name) override; + + private: + std::map< + QString, + std::function + > customWidgetConstructorsByWidgetName = {}; }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/ClickableWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/ClickableWidget.hpp index 874e15b9..18ea8f4e 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/ClickableWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/ClickableWidget.hpp @@ -8,10 +8,7 @@ namespace Bloom::Widgets { class Q_WIDGETS_EXPORT ClickableWidget: public QFrame { - Q_OBJECT - protected: - void mouseReleaseEvent(QMouseEvent* event) override; - void mouseDoubleClickEvent(QMouseEvent* event) override; + Q_OBJECT public: explicit ClickableWidget(QWidget* parent): QFrame(parent) {}; @@ -21,5 +18,8 @@ namespace Bloom::Widgets void clicked(); void doubleClicked(); + protected: + void mouseReleaseEvent(QMouseEvent* event) override; + void mouseDoubleClickEvent(QMouseEvent* event) override; }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/ErrorDialogue/ErrorDialogue.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/ErrorDialogue/ErrorDialogue.cpp index e9d360f4..fb74559d 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/ErrorDialogue/ErrorDialogue.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/ErrorDialogue/ErrorDialogue.cpp @@ -3,8 +3,8 @@ #include #include -#include "src/Helpers/Paths.hpp" #include "src/Insight/UserInterfaces/InsightWindow/UiLoader.hpp" +#include "src/Helpers/Paths.hpp" #include "src/Exceptions/Exception.hpp" using namespace Bloom::Widgets; diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/ErrorDialogue/ErrorDialogue.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/ErrorDialogue/ErrorDialogue.hpp index 1cf018e2..1593437a 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/ErrorDialogue/ErrorDialogue.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/ErrorDialogue/ErrorDialogue.hpp @@ -8,12 +8,14 @@ namespace Bloom::Widgets { class Q_WIDGETS_EXPORT ErrorDialogue: public QDialog { - Q_OBJECT - QWidget* container = nullptr; - QLabel* errorMessageLabel = nullptr; - QPushButton* okButton = nullptr; + Q_OBJECT public: ErrorDialogue(const QString& windowTitle, const QString& errorMessage, QWidget* parent); + + private: + QWidget* container = nullptr; + QLabel* errorMessageLabel = nullptr; + QPushButton* okButton = nullptr; }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/ExpandingHeightScrollAreaWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/ExpandingHeightScrollAreaWidget.hpp index 86a4cb06..d0014664 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/ExpandingHeightScrollAreaWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/ExpandingHeightScrollAreaWidget.hpp @@ -8,7 +8,11 @@ namespace Bloom::Widgets { class Q_WIDGETS_EXPORT ExpandingHeightScrollAreaWidget: public QScrollArea { - Q_OBJECT + Q_OBJECT + + public: + explicit ExpandingHeightScrollAreaWidget(QWidget* parent): QScrollArea(parent) {}; + protected: [[nodiscard]] QSize scrollAreaSize() const { auto parentWidget = this->parentWidget(); @@ -34,9 +38,5 @@ namespace Bloom::Widgets [[nodiscard]] QSize minimumSizeHint() const override { return this->scrollAreaSize(); }; - - public: - explicit ExpandingHeightScrollAreaWidget(QWidget* parent): QScrollArea(parent) {}; - }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/PanelWidget.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/PanelWidget.cpp index 4f5eac54..c10b2178 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/PanelWidget.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/PanelWidget.cpp @@ -35,6 +35,20 @@ void PanelWidget::setMaximumResize(int maximumResize) { } } +bool PanelWidget::event(QEvent* event) { + if (event->type() == QEvent::Type::HoverMove) { + auto hoverEvent = static_cast(event); + if (this->resizingActive || this->isPositionWithinHandleArea(hoverEvent->position().toPoint())) { + this->setCursor(this->resizeCursor); + + } else { + this->setCursor(Qt::ArrowCursor); + } + } + + return QFrame::event(event); +} + void PanelWidget::mousePressEvent(QMouseEvent* event) { const auto position = event->pos(); @@ -61,20 +75,6 @@ void PanelWidget::mouseReleaseEvent(QMouseEvent* event) { } } -bool PanelWidget::event(QEvent* event) { - if (event->type() == QEvent::Type::HoverMove) { - auto hoverEvent = static_cast(event); - if (this->resizingActive || this->isPositionWithinHandleArea(hoverEvent->position().toPoint())) { - this->setCursor(this->resizeCursor); - - } else { - this->setCursor(Qt::ArrowCursor); - } - } - - return QFrame::event(event); -} - void PanelWidget::mouseMoveEvent(QMouseEvent* event) { const auto position = event->pos(); diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/PanelWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/PanelWidget.hpp index fd4df456..c64a3d41 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/PanelWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/PanelWidget.hpp @@ -19,29 +19,11 @@ namespace Bloom::Widgets class Q_WIDGETS_EXPORT PanelWidget: public QFrame { - Q_OBJECT + Q_OBJECT Q_PROPERTY(int handleSize READ getHandleSize WRITE setHandleSize DESIGNABLE true) Q_PROPERTY(int minimumResize READ getMinimumResize WRITE setMinimumResize DESIGNABLE true) Q_PROPERTY(Bloom::Widgets::PanelWidgetType panelType READ getPanelType WRITE setPanelType DESIGNABLE true) - protected: - int handleSize = 10; - int minimumResize = 10; - int maximumResize = 500; - - PanelWidgetType panelType = PanelWidgetType::LEFT; - QCursor resizeCursor = Qt::SplitHCursor; - bool resizingActive = false; - int resizingOffset = 0; - - void mousePressEvent(QMouseEvent* event) override; - void mouseReleaseEvent(QMouseEvent* event) override; - bool event(QEvent* event) override; - void mouseMoveEvent(QMouseEvent* event) override; - - std::pair getHandleArea() const; - bool isPositionWithinHandleArea(const QPoint& position) const; - public: explicit PanelWidget(QWidget* parent); @@ -73,5 +55,23 @@ namespace Bloom::Widgets PanelWidgetType getPanelType() { return this->panelType; } + + protected: + int handleSize = 10; + int minimumResize = 10; + int maximumResize = 500; + + PanelWidgetType panelType = PanelWidgetType::LEFT; + QCursor resizeCursor = Qt::SplitHCursor; + bool resizingActive = false; + int resizingOffset = 0; + + bool event(QEvent* event) override; + void mousePressEvent(QMouseEvent* event) override; + void mouseReleaseEvent(QMouseEvent* event) override; + void mouseMoveEvent(QMouseEvent* event) override; + + std::pair getHandleArea() const; + bool isPositionWithinHandleArea(const QPoint& position) const; }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/RotatableLabel.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/RotatableLabel.hpp index 47db9f6f..32123e68 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/RotatableLabel.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/RotatableLabel.hpp @@ -7,11 +7,16 @@ namespace Bloom::Widgets { class RotatableLabel: public QLabel { - Q_OBJECT - private: - int angle = 90; + Q_OBJECT - [[nodiscard]] QSize getContainerSize() const; + public: + RotatableLabel(const QString& text, QWidget* parent): QLabel(text, parent) {}; + RotatableLabel(int angleDegrees, const QString& text, QWidget* parent) + : QLabel(text, parent), angle(angleDegrees) {}; + + void setAngle(int angleDegrees) { + this->angle = angleDegrees; + } protected: void paintEvent(QPaintEvent* event) override; @@ -24,14 +29,9 @@ namespace Bloom::Widgets return this->getContainerSize(); }; - public: - RotatableLabel(const QString& text, QWidget* parent): QLabel(text, parent) {}; - RotatableLabel(int angleDegrees, const QString& text, QWidget* parent): QLabel(text, parent) { - this->setAngle(angleDegrees); - }; + private: + int angle = 90; - void setAngle(int angleDegrees) { - this->angle = angleDegrees; - } + [[nodiscard]] QSize getContainerSize() const; }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/SvgToolButton.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/SvgToolButton.hpp index f1a4b066..0a0df0f7 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/SvgToolButton.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/SvgToolButton.hpp @@ -9,19 +9,13 @@ namespace Bloom::Widgets { class SvgToolButton: public QToolButton { - Q_OBJECT + Q_OBJECT Q_PROPERTY(QString svgFilePath READ getSvgFilePath WRITE setSvgFilePath DESIGNABLE true) Q_PROPERTY(QString disabledSvgFilePath READ getDisabledSvgFilePath WRITE setDisabledSvgFilePath DESIGNABLE true) Q_PROPERTY(int buttonWidth READ getButtonWidth WRITE setButtonWidth DESIGNABLE true) Q_PROPERTY(int buttonHeight READ getButtonHeight WRITE setButtonHeight DESIGNABLE true) - private: - SvgWidget* svgWidget = new SvgWidget(this); - SvgWidget* disabledSvgWidget = nullptr; - int buttonWidth = 0; - int buttonHeight = 0; - public: explicit SvgToolButton(QWidget* parent): QToolButton(parent) { this->setButtonWidth(10); @@ -63,5 +57,10 @@ namespace Bloom::Widgets [[nodiscard]] int getButtonHeight() const { return this->buttonHeight; } + + private: + SvgWidget* svgWidget = new SvgWidget(this); + int buttonWidth = 0; + int buttonHeight = 0; }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/SvgWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/SvgWidget.hpp index ed2f6ef9..315aec53 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/SvgWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/SvgWidget.hpp @@ -10,25 +10,13 @@ namespace Bloom::Widgets { class SvgWidget: public QFrame { - Q_OBJECT + Q_OBJECT Q_PROPERTY(QString svgFilePath READ getSvgFilePath WRITE setSvgFilePath DESIGNABLE true) Q_PROPERTY(QString disabledSvgFilePath READ getDisabledSvgFilePath WRITE setDisabledSvgFilePath DESIGNABLE true) Q_PROPERTY(int containerWidth READ getContainerWidth WRITE setContainerWidth DESIGNABLE true) Q_PROPERTY(int containerHeight READ getContainerHeight WRITE setContainerHeight DESIGNABLE true) Q_PROPERTY(int angle READ getAngle WRITE setAngle DESIGNABLE true) - private: - QSvgRenderer renderer = new QSvgRenderer(this); - QString svgFilePath; - QString disabledSvgFilePath; - int containerWidth = 0; - int containerHeight = 0; - int angle = 0; - - protected: - void paintEvent(QPaintEvent* paintEvent) override; - void changeEvent(QEvent* event) override; - public: explicit SvgWidget(QWidget* parent); @@ -73,5 +61,16 @@ namespace Bloom::Widgets return this->angle; } + protected: + void paintEvent(QPaintEvent* paintEvent) override; + void changeEvent(QEvent* event) override; + + private: + QSvgRenderer renderer = new QSvgRenderer(this); + QString svgFilePath; + QString disabledSvgFilePath; + int containerWidth = 0; + int containerHeight = 0; + int angle = 0; }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitBodyWidget.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitBodyWidget.cpp index 652e1c68..b02173f0 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitBodyWidget.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitBodyWidget.cpp @@ -16,17 +16,6 @@ BitBodyWidget::BitBodyWidget( this->setContentsMargins(0, 0, 0, 0); } -void BitBodyWidget::mouseReleaseEvent(QMouseEvent* event) { - if (this->isEnabled()) { - if (!this->readOnly && event->button() == Qt::MouseButton::LeftButton) { - this->bit = !this->bit; - this->update(); - } - - ClickableWidget::mouseReleaseEvent(event); - } -} - bool BitBodyWidget::event(QEvent* event) { if (this->isEnabled() && !this->readOnly) { switch (event->type()) { @@ -49,6 +38,17 @@ bool BitBodyWidget::event(QEvent* event) { return QWidget::event(event); } +void BitBodyWidget::mouseReleaseEvent(QMouseEvent* event) { + if (this->isEnabled()) { + if (!this->readOnly && event->button() == Qt::MouseButton::LeftButton) { + this->bit = !this->bit; + this->update(); + } + + ClickableWidget::mouseReleaseEvent(event); + } +} + void BitBodyWidget::paintEvent(QPaintEvent* event) { auto painter = QPainter(this); this->drawWidget(painter); diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitBodyWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitBodyWidget.hpp index 135d58ec..b1112478 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitBodyWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitBodyWidget.hpp @@ -15,18 +15,7 @@ namespace Bloom::Widgets { class BitBodyWidget: public ClickableWidget { - Q_OBJECT - private: - int bitIndex = 0; - std::bitset::digits>::reference bit; - bool readOnly = true; - bool hoverActive = false; - - protected: - bool event(QEvent* event) override; - void mouseReleaseEvent(QMouseEvent* event) override; - void paintEvent(QPaintEvent* event) override; - void drawWidget(QPainter& painter); + Q_OBJECT public: constexpr static int WIDTH = 23; @@ -38,5 +27,17 @@ namespace Bloom::Widgets bool readOnly, QWidget* parent ); + + protected: + bool event(QEvent* event) override; + void mouseReleaseEvent(QMouseEvent* event) override; + void paintEvent(QPaintEvent* event) override; + void drawWidget(QPainter& painter); + + private: + int bitIndex = 0; + std::bitset::digits>::reference bit; + bool readOnly = true; + bool hoverActive = false; }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitWidget.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitWidget.cpp index 1c00fe2f..8c8de52b 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitWidget.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitWidget.cpp @@ -3,7 +3,6 @@ #include #include #include -#include #include "BitBodyWidget.hpp" diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitWidget.hpp index 7ad4d375..a833141c 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitWidget.hpp @@ -17,20 +17,11 @@ namespace Bloom::Widgets { class BitWidget: public QWidget { - Q_OBJECT + Q_OBJECT + private: const static int VERTICAL_SPACING = 3; - int bitIndex = 0; - int bitNumber = 0; - std::bitset::digits>& bitset; - bool readOnly = true; - - BitBodyWidget* body = nullptr; - - QLabel* bitLabel = nullptr; - QLabel* bitNumberLabel = nullptr; - public: constexpr static int LABEL_HEIGHT = 14; constexpr static int LABEL_COUNT = 2; @@ -49,5 +40,16 @@ namespace Bloom::Widgets signals: void bitChanged(); + + private: + int bitIndex = 0; + int bitNumber = 0; + std::bitset::digits>& bitset; + bool readOnly = true; + + BitBodyWidget* body = nullptr; + + QLabel* bitLabel = nullptr; + QLabel* bitNumberLabel = nullptr; }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitsetWidget.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitsetWidget.cpp index 84e244df..f77ca001 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitsetWidget.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitsetWidget.cpp @@ -45,6 +45,11 @@ QWidget(parent), byteNumber(byteNumber), byte(byte), readOnly(readOnly) { } } +void BitsetWidget::updateValue() { + this->bitset = {this->byte}; + this->update(); +} + void BitsetWidget::paintEvent(QPaintEvent* event) { QWidget::paintEvent(event); auto painter = QPainter(this); @@ -101,8 +106,3 @@ void BitsetWidget::drawWidget(QPainter& painter) { byteHex ); } - -void BitsetWidget::updateValue() { - this->bitset = {this->byte}; - this->update(); -} diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitsetWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitsetWidget.hpp index 9c167419..be4178e9 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitsetWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/BitsetWidget/BitsetWidget.hpp @@ -13,18 +13,7 @@ namespace Bloom::Widgets { class BitsetWidget: public QWidget { - Q_OBJECT - private: - int byteNumber = 0; - unsigned char& byte; - std::bitset::digits> bitset = {byte}; - bool readOnly = true; - - QWidget* container = nullptr; - - protected: - void paintEvent(QPaintEvent* event) override; - void drawWidget(QPainter& painter); + Q_OBJECT public: constexpr static int VALUE_GRAPHIC_HEIGHT = 20; @@ -37,5 +26,17 @@ namespace Bloom::Widgets signals: void byteChanged(); + + protected: + void paintEvent(QPaintEvent* event) override; + void drawWidget(QPainter& painter); + + private: + int byteNumber = 0; + unsigned char& byte; + std::bitset::digits> bitset = {byte}; + bool readOnly = true; + + QWidget* container = nullptr; }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/CurrentItem.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/CurrentItem.hpp index 097121c3..db271008 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/CurrentItem.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/CurrentItem.hpp @@ -13,14 +13,16 @@ namespace Bloom::Widgets { class CurrentItem: public Item { - Q_OBJECT - QHBoxLayout* layout = new QHBoxLayout(this); - QLabel* titleLabel = new QLabel(this); + Q_OBJECT public: CurrentItem( const Targets::TargetMemoryBuffer& registerValue, QWidget *parent ); + + private: + QHBoxLayout* layout = new QHBoxLayout(this); + QLabel* titleLabel = new QLabel(this); }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/Item.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/Item.hpp index 608b2939..01e45089 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/Item.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/Item.hpp @@ -8,7 +8,7 @@ namespace Bloom::Widgets { class Item: public ClickableWidget { - Q_OBJECT + Q_OBJECT public: Targets::TargetMemoryBuffer registerValue; Item(const Targets::TargetMemoryBuffer& registerValue, QWidget *parent); diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/RegisterHistoryItem.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/RegisterHistoryItem.hpp index 50606a7f..615d6680 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/RegisterHistoryItem.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/RegisterHistoryItem.hpp @@ -10,11 +10,7 @@ namespace Bloom::Widgets { class RegisterHistoryItem: public Item { - Q_OBJECT - QVBoxLayout* layout = new QVBoxLayout(this); - QLabel* dateLabel = new QLabel(this); - QLabel* valueLabel = new QLabel(this); - QLabel* descriptionLayout = new QLabel(this); + Q_OBJECT public: RegisterHistoryItem( @@ -22,5 +18,11 @@ namespace Bloom::Widgets const QDateTime& changeDate, QWidget *parent ); + + private: + QVBoxLayout* layout = new QVBoxLayout(this); + QLabel* dateLabel = new QLabel(this); + QLabel* valueLabel = new QLabel(this); + QLabel* descriptionLayout = new QLabel(this); }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/RegisterHistoryWidget.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/RegisterHistoryWidget.cpp index 78c88c63..fd471f5b 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/RegisterHistoryWidget.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/RegisterHistoryWidget.cpp @@ -6,7 +6,7 @@ #include #include -#include "../../../UiLoader.hpp" +#include "src/Insight/UserInterfaces/InsightWindow/UiLoader.hpp" #include "src/Helpers/Paths.hpp" #include "src/Helpers/DateTime.hpp" diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/RegisterHistoryWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/RegisterHistoryWidget.hpp index f7b7c2a5..082bf8b9 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/RegisterHistoryWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/RegisterHistoryWidget/RegisterHistoryWidget.hpp @@ -23,26 +23,7 @@ namespace Bloom::Widgets { class RegisterHistoryWidget: public QWidget { - Q_OBJECT - private: - Targets::TargetRegisterDescriptor registerDescriptor; - InsightWorker& insightWorker; - - QWidget* container = nullptr; - QWidget* itemContainer = nullptr; - QVBoxLayout* itemContainerLayout = nullptr; - - Targets::TargetState targetState = Targets::TargetState::UNKNOWN; - CurrentItem* currentItem = nullptr; - Item* selectedItemWidget = nullptr; - - private slots: - void onTargetStateChanged(Targets::TargetState newState); - void onItemSelectionChange(Item* newlySelectedWidget); - void onRegistersWritten(Targets::TargetRegisters targetRegisters, const QDateTime& changeDate); - - protected: - void resizeEvent(QResizeEvent* event) override; + Q_OBJECT public: RegisterHistoryWidget( @@ -64,5 +45,25 @@ namespace Bloom::Widgets signals: void historyItemSelected(const Targets::TargetMemoryBuffer& registerValue); + + protected: + void resizeEvent(QResizeEvent* event) override; + + private: + Targets::TargetRegisterDescriptor registerDescriptor; + InsightWorker& insightWorker; + + QWidget* container = nullptr; + QWidget* itemContainer = nullptr; + QVBoxLayout* itemContainerLayout = nullptr; + + Targets::TargetState targetState = Targets::TargetState::UNKNOWN; + CurrentItem* currentItem = nullptr; + Item* selectedItemWidget = nullptr; + + private slots: + void onTargetStateChanged(Targets::TargetState newState); + void onItemSelectionChange(Item* newlySelectedWidget); + void onRegistersWritten(Targets::TargetRegisters targetRegisters, const QDateTime& changeDate); }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/TargetRegisterInspectorWindow.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/TargetRegisterInspectorWindow.cpp index 47cc477c..1902fba2 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/TargetRegisterInspectorWindow.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/TargetRegisterInspectorWindow.cpp @@ -2,9 +2,6 @@ #include #include -#include -#include -#include #include #include "src/Insight/UserInterfaces/InsightWindow/UiLoader.hpp" diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/TargetRegisterInspectorWindow.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/TargetRegisterInspectorWindow.hpp index 409d179a..8cf48d9a 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/TargetRegisterInspectorWindow.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegisterInspector/TargetRegisterInspectorWindow.hpp @@ -22,7 +22,21 @@ namespace Bloom::Widgets { class TargetRegisterInspectorWindow: public QWidget { - Q_OBJECT + Q_OBJECT + + public: + TargetRegisterInspectorWindow( + const Targets::TargetRegisterDescriptor& registerDescriptor, + InsightWorker& insightWorker, + Targets::TargetState currentTargetState, + std::optional registerValue = std::nullopt, + QWidget* parent = nullptr + ); + + static bool registerSupported(const Targets::TargetRegisterDescriptor& descriptor); + + void setValue(const Targets::TargetMemoryBuffer& registerValue); + private: Targets::TargetRegisterDescriptor registerDescriptor; Targets::TargetMemoryBuffer registerValue; @@ -57,18 +71,5 @@ namespace Bloom::Widgets void refreshRegisterValue(); void applyChanges(); void openHelpPage(); - - public: - TargetRegisterInspectorWindow( - const Targets::TargetRegisterDescriptor& registerDescriptor, - InsightWorker& insightWorker, - Targets::TargetState currentTargetState, - std::optional registerValue = std::nullopt, - QWidget* parent = nullptr - ); - - static bool registerSupported(const Targets::TargetRegisterDescriptor& descriptor); - - void setValue(const Targets::TargetMemoryBuffer& registerValue); }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/ItemWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/ItemWidget.hpp index b7f90d8e..2a6283fc 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/ItemWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/ItemWidget.hpp @@ -6,9 +6,7 @@ namespace Bloom::Widgets { class ItemWidget: public ClickableWidget { - Q_OBJECT - protected: - virtual void postSetSelected(bool selected) {}; + Q_OBJECT public: ItemWidget(QWidget *parent); @@ -18,5 +16,8 @@ namespace Bloom::Widgets signals: void selected(ItemWidget*); + + protected: + virtual void postSetSelected(bool selected) {}; }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/RegisterGroupWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/RegisterGroupWidget.hpp index dbdcaa30..c1c8ea6d 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/RegisterGroupWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/RegisterGroupWidget.hpp @@ -20,14 +20,7 @@ namespace Bloom::Widgets class RegisterWidget; class RegisterGroupWidget: public ItemWidget { - Q_OBJECT - private: - QVBoxLayout* layout = new QVBoxLayout(this); - ItemWidget* headerWidget = new ItemWidget(this); - SvgWidget* arrowIcon = new SvgWidget(this->headerWidget); - SvgWidget* registerGroupIcon = new SvgWidget(this->headerWidget); - QLabel* label = new QLabel(this->headerWidget); - QWidget* bodyWidget = new QWidget(this); + Q_OBJECT public: QString name; @@ -48,5 +41,13 @@ namespace Bloom::Widgets void setAllRegistersVisible(bool visible); void filterRegisters(const std::string& keyword); + + private: + QVBoxLayout* layout = new QVBoxLayout(this); + ItemWidget* headerWidget = new ItemWidget(this); + SvgWidget* arrowIcon = new SvgWidget(this->headerWidget); + SvgWidget* registerGroupIcon = new SvgWidget(this->headerWidget); + QLabel* label = new QLabel(this->headerWidget); + QWidget* bodyWidget = new QWidget(this); }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/RegisterWidget.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/RegisterWidget.cpp index 03d595f6..e904e945 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/RegisterWidget.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/RegisterWidget.cpp @@ -92,6 +92,35 @@ void RegisterWidget::clearInlineValue() { this->valueLabel->clear(); } +void RegisterWidget::contextMenuEvent(QContextMenuEvent* event) { + this->setSelected(true); + + auto menu = new QMenu(this); + menu->addAction(this->openInspectionWindowAction); + menu->addAction(this->refreshValueAction); + menu->addSeparator(); + + auto copyMenu = new QMenu("Copy", this); + copyMenu->addAction(this->copyValueNameAction); + copyMenu->addSeparator(); + copyMenu->addAction(this->copyValueDecimalAction); + copyMenu->addAction(this->copyValueHexAction); + copyMenu->addAction(this->copyValueBinaryAction); + + menu->addMenu(copyMenu); + + this->openInspectionWindowAction->setEnabled(TargetRegisterInspectorWindow::registerSupported(this->descriptor)); + + const auto targetStopped = this->targetState == Targets::TargetState::STOPPED; + const auto targetStoppedAndValuePresent = targetStopped && this->currentRegister.has_value(); + this->refreshValueAction->setEnabled(targetStopped); + this->copyValueDecimalAction->setEnabled(targetStoppedAndValuePresent); + this->copyValueHexAction->setEnabled(targetStoppedAndValuePresent); + this->copyValueBinaryAction->setEnabled(targetStoppedAndValuePresent); + + menu->exec(event->globalPos()); +} + void RegisterWidget::openInspectionWindow() { if (!TargetRegisterInspectorWindow::registerSupported(this->descriptor)) { return; @@ -183,35 +212,6 @@ void RegisterWidget::copyValueBinary() { } } -void RegisterWidget::contextMenuEvent(QContextMenuEvent* event) { - this->setSelected(true); - - auto menu = new QMenu(this); - menu->addAction(this->openInspectionWindowAction); - menu->addAction(this->refreshValueAction); - menu->addSeparator(); - - auto copyMenu = new QMenu("Copy", this); - copyMenu->addAction(this->copyValueNameAction); - copyMenu->addSeparator(); - copyMenu->addAction(this->copyValueDecimalAction); - copyMenu->addAction(this->copyValueHexAction); - copyMenu->addAction(this->copyValueBinaryAction); - - menu->addMenu(copyMenu); - - this->openInspectionWindowAction->setEnabled(TargetRegisterInspectorWindow::registerSupported(this->descriptor)); - - const auto targetStopped = this->targetState == Targets::TargetState::STOPPED; - const auto targetStoppedAndValuePresent = targetStopped && this->currentRegister.has_value(); - this->refreshValueAction->setEnabled(targetStopped); - this->copyValueDecimalAction->setEnabled(targetStoppedAndValuePresent); - this->copyValueHexAction->setEnabled(targetStoppedAndValuePresent); - this->copyValueBinaryAction->setEnabled(targetStoppedAndValuePresent); - - menu->exec(event->globalPos()); -} - void RegisterWidget::postSetSelected(bool selected) { auto valueLabelStyle = this->valueLabel->style(); valueLabelStyle->unpolish(this->valueLabel); diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/RegisterWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/RegisterWidget.hpp index 3904f066..918869c3 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/RegisterWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/RegisterWidget.hpp @@ -19,30 +19,7 @@ namespace Bloom::Widgets { class RegisterWidget: public ItemWidget { - Q_OBJECT - private: - InsightWorker& insightWorker; - QHBoxLayout* layout = new QHBoxLayout(this); - SvgWidget* registerIcon = new SvgWidget(this); - QLabel* nameLabel = new QLabel(this); - QLabel* valueLabel = new QLabel(this); - - // Context-menu actions - QAction* openInspectionWindowAction = new QAction("Inspect", this); - QAction* refreshValueAction = new QAction("Refresh Value", this); - QAction* copyValueNameAction = new QAction("Copy Register Name", this); - QAction* copyValueHexAction = new QAction("Copy Hexadecimal Value", this); - QAction* copyValueDecimalAction = new QAction("Copy Decimal Value", this); - QAction* copyValueBinaryAction = new QAction("Copy Binary Value", this); - - TargetRegisterInspectorWindow* inspectWindow = nullptr; - - void postSetSelected(bool selected) override; - - Targets::TargetState targetState = Targets::TargetState::UNKNOWN; - - private slots: - void onTargetStateChange(Targets::TargetState newState); + Q_OBJECT public: Targets::TargetRegisterDescriptor descriptor; @@ -71,5 +48,29 @@ namespace Bloom::Widgets void copyValueHex(); void copyValueDecimal(); void copyValueBinary(); + + private: + InsightWorker& insightWorker; + QHBoxLayout* layout = new QHBoxLayout(this); + SvgWidget* registerIcon = new SvgWidget(this); + QLabel* nameLabel = new QLabel(this); + QLabel* valueLabel = new QLabel(this); + + // Context-menu actions + QAction* openInspectionWindowAction = new QAction("Inspect", this); + QAction* refreshValueAction = new QAction("Refresh Value", this); + QAction* copyValueNameAction = new QAction("Copy Register Name", this); + QAction* copyValueHexAction = new QAction("Copy Hexadecimal Value", this); + QAction* copyValueDecimalAction = new QAction("Copy Decimal Value", this); + QAction* copyValueBinaryAction = new QAction("Copy Binary Value", this); + + TargetRegisterInspectorWindow* inspectWindow = nullptr; + + void postSetSelected(bool selected) override; + + Targets::TargetState targetState = Targets::TargetState::UNKNOWN; + + private slots: + void onTargetStateChange(Targets::TargetState newState); }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/TargetRegistersPaneWidget.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/TargetRegistersPaneWidget.cpp index e9c6daef..f9d4bafb 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/TargetRegistersPaneWidget.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/TargetRegistersPaneWidget.cpp @@ -3,7 +3,7 @@ #include #include -#include "../../UiLoader.hpp" +#include "src/Insight/UserInterfaces/InsightWindow/UiLoader.hpp" #include "RegisterGroupWidget.hpp" #include "RegisterWidget.hpp" @@ -123,54 +123,6 @@ TargetRegistersPaneWidget::TargetRegistersPaneWidget( ); } -void TargetRegistersPaneWidget::resizeEvent(QResizeEvent* event) { - const auto parentSize = this->parent->size(); - const auto width = parentSize.width() - 1; - this->container->setFixedSize(width, parentSize.height()); - this->searchInput->setFixedWidth(width - 20); - - /* - * In order to avoid the panel resize handle overlapping the scroll bar handle, we reduce the size of - * the scroll area. - */ - this->itemScrollArea->setFixedSize( - width - this->parent->getHandleSize(), - parentSize.height() - this->toolBar->height() - this->searchInput->height() - 5 - ); -} - -void TargetRegistersPaneWidget::postActivate() { - if (this->targetState == Targets::TargetState::STOPPED) { - this->refreshRegisterValues(); - } -} - -void TargetRegistersPaneWidget::postDeactivate() { - -} - -void TargetRegistersPaneWidget::onTargetStateChanged(Targets::TargetState newState) { - using Targets::TargetState; - this->targetState = newState; - - if (newState == TargetState::STOPPED && this->activated) { - this->refreshRegisterValues(); - } -} - -void TargetRegistersPaneWidget::onRegistersRead(const Targets::TargetRegisters& registers) { - for (const auto& targetRegister : registers) { - auto& descriptor = targetRegister.descriptor; - - for (const auto& registerGroupWidget : this->registerGroupWidgets) { - if (registerGroupWidget->registerWidgetsMappedByDescriptor.contains(descriptor)) { - registerGroupWidget->registerWidgetsMappedByDescriptor.at(descriptor)->setRegisterValue(targetRegister); - break; - } - } - } -} - void TargetRegistersPaneWidget::filterRegisters(const QString& keyword) { auto stdKeyword = keyword.toLower().toStdString(); @@ -254,3 +206,51 @@ void TargetRegistersPaneWidget::onItemSelectionChange(ItemWidget* newlySelectedW this->selectedItemWidget = newlySelectedWidget; } } + +void TargetRegistersPaneWidget::resizeEvent(QResizeEvent* event) { + const auto parentSize = this->parent->size(); + const auto width = parentSize.width() - 1; + this->container->setFixedSize(width, parentSize.height()); + this->searchInput->setFixedWidth(width - 20); + + /* + * In order to avoid the panel resize handle overlapping the scroll bar handle, we reduce the size of + * the scroll area. + */ + this->itemScrollArea->setFixedSize( + width - this->parent->getHandleSize(), + parentSize.height() - this->toolBar->height() - this->searchInput->height() - 5 + ); +} + +void TargetRegistersPaneWidget::postActivate() { + if (this->targetState == Targets::TargetState::STOPPED) { + this->refreshRegisterValues(); + } +} + +void TargetRegistersPaneWidget::postDeactivate() { + +} + +void TargetRegistersPaneWidget::onTargetStateChanged(Targets::TargetState newState) { + using Targets::TargetState; + this->targetState = newState; + + if (newState == TargetState::STOPPED && this->activated) { + this->refreshRegisterValues(); + } +} + +void TargetRegistersPaneWidget::onRegistersRead(const Targets::TargetRegisters& registers) { + for (const auto& targetRegister : registers) { + auto& descriptor = targetRegister.descriptor; + + for (const auto& registerGroupWidget : this->registerGroupWidgets) { + if (registerGroupWidget->registerWidgetsMappedByDescriptor.contains(descriptor)) { + registerGroupWidget->registerWidgetsMappedByDescriptor.at(descriptor)->setRegisterValue(targetRegister); + break; + } + } + } +} diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/TargetRegistersPaneWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/TargetRegistersPaneWidget.hpp index 73c5d681..aaca08cf 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/TargetRegistersPaneWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetRegistersPane/TargetRegistersPaneWidget.hpp @@ -19,10 +19,37 @@ namespace Bloom::Widgets { class RegisterGroupWidget; - class TargetRegistersPaneWidget: public QWidget { - Q_OBJECT + Q_OBJECT + + public: + bool activated = false; + + TargetRegistersPaneWidget( + const Targets::TargetDescriptor& targetDescriptor, + InsightWorker& insightWorker, + PanelWidget *parent + ); + + void filterRegisters(const QString& keyword); + void collapseAllRegisterGroups(); + void expandAllRegisterGroups(); + + void refreshRegisterValues(std::optional> callback = std::nullopt); + + void activate(); + void deactivate(); + + public slots: + void onItemSelectionChange(ItemWidget* newlySelectedWidget); + + protected: + void resizeEvent(QResizeEvent* event) override; + + virtual void postActivate(); + virtual void postDeactivate(); + private: const Targets::TargetDescriptor& targetDescriptor; InsightWorker& insightWorker; @@ -48,32 +75,5 @@ namespace Bloom::Widgets private slots: void onTargetStateChanged(Targets::TargetState newState); void onRegistersRead(const Targets::TargetRegisters& registers); - - protected: - void resizeEvent(QResizeEvent* event) override; - - virtual void postActivate(); - virtual void postDeactivate(); - - public: - bool activated = false; - - TargetRegistersPaneWidget( - const Targets::TargetDescriptor& targetDescriptor, - InsightWorker& insightWorker, - PanelWidget *parent - ); - - void filterRegisters(const QString& keyword); - void collapseAllRegisterGroups(); - void expandAllRegisterGroups(); - - void refreshRegisterValues(std::optional> callback = std::nullopt); - - void activate(); - void deactivate(); - - public slots: - void onItemSelectionChange(ItemWidget* newlySelectedWidget); }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/BodyWidget.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/BodyWidget.cpp index 66707a38..16cb5ec7 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/BodyWidget.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/BodyWidget.cpp @@ -1,7 +1,7 @@ +#include "BodyWidget.hpp" + #include -#include "BodyWidget.hpp" -#include "src/Logger/Logger.hpp" #include "src/Exceptions/Exception.hpp" using namespace Bloom::Widgets::InsightTargetWidgets::Dip; diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/BodyWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/BodyWidget.hpp index 8f841e9d..d85173e9 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/BodyWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/BodyWidget.hpp @@ -6,18 +6,9 @@ namespace Bloom::Widgets::InsightTargetWidgets::Dip { class BodyWidget: public QWidget { - Q_OBJECT - Q_PROPERTY(QColor bodyColor READ getBodyColor WRITE setBodyColor DESIGNABLE true) - Q_PROPERTY(int disableAlphaLevel READ getDisableAlphaLevel WRITE setDisableAlphaLevel DESIGNABLE true) - - private: - // These properties can be modified via Qt style sheets (see Stylesheets/DualInlinePackage.qss) - QColor bodyColor = QColor("#8E8B83"); - int disableAlphaLevel = 100; - - protected: - void paintEvent(QPaintEvent* event) override; - void drawWidget(QPainter& painter); + Q_OBJECT + Q_PROPERTY(QColor bodyColor READ getBodyColor WRITE setBodyColor DESIGNABLE true) + Q_PROPERTY(int disableAlphaLevel READ getDisableAlphaLevel WRITE setDisableAlphaLevel DESIGNABLE true) public: explicit BodyWidget(QWidget* parent): QWidget(parent) { @@ -39,5 +30,14 @@ namespace Bloom::Widgets::InsightTargetWidgets::Dip void setDisableAlphaLevel(int level) { this->disableAlphaLevel = level; } + + protected: + void paintEvent(QPaintEvent* event) override; + void drawWidget(QPainter& painter); + + private: + // These properties can be modified via Qt style sheets (see Stylesheets/DualInlinePackage.qss) + QColor bodyColor = QColor("#8E8B83"); + int disableAlphaLevel = 100; }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/DualInlinePackageWidget.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/DualInlinePackageWidget.cpp index 6ccb4349..fbe8d9f9 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/DualInlinePackageWidget.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/DualInlinePackageWidget.cpp @@ -6,10 +6,7 @@ #include #include -#include "../../../InsightWindow.hpp" #include "src/Helpers/Paths.hpp" -#include "PinWidget.hpp" -#include "BodyWidget.hpp" using namespace Bloom::Widgets::InsightTargetWidgets::Dip; using namespace Bloom::Exceptions; diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/DualInlinePackageWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/DualInlinePackageWidget.hpp index 9663e162..f3efc189 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/DualInlinePackageWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/DualInlinePackageWidget.hpp @@ -6,6 +6,7 @@ #include #include "../TargetPackageWidget.hpp" + #include "PinWidget.hpp" #include "BodyWidget.hpp" #include "src/Targets/TargetVariant.hpp" @@ -17,12 +18,7 @@ namespace Bloom::Widgets::InsightTargetWidgets::Dip */ class DualInlinePackageWidget: public TargetPackageWidget { - Q_OBJECT - private: - QVBoxLayout* layout = nullptr; - QHBoxLayout* topPinLayout = nullptr; - QHBoxLayout* bottomPinLayout = nullptr; - BodyWidget* bodyWidget = nullptr; + Q_OBJECT public: DualInlinePackageWidget( @@ -30,5 +26,11 @@ namespace Bloom::Widgets::InsightTargetWidgets::Dip InsightWorker& insightWorker, QWidget* parent ); + + private: + QVBoxLayout* layout = nullptr; + QHBoxLayout* topPinLayout = nullptr; + QHBoxLayout* bottomPinLayout = nullptr; + BodyWidget* bodyWidget = nullptr; }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/PinBodyWidget.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/PinBodyWidget.cpp index 011ace3c..1db36979 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/PinBodyWidget.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/PinBodyWidget.cpp @@ -1,10 +1,7 @@ -#include -#include -#include -#include -#include - #include "PinBodyWidget.hpp" + +#include + #include "src/Logger/Logger.hpp" using namespace Bloom::Widgets::InsightTargetWidgets::Dip; diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/PinBodyWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/PinBodyWidget.hpp index 382642ee..cc2d92a7 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/PinBodyWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/PinBodyWidget.hpp @@ -1,19 +1,17 @@ #pragma once #include -#include -#include +#include #include "../TargetPinBodyWidget.hpp" + #include "src/Targets/TargetPinDescriptor.hpp" namespace Bloom::Widgets::InsightTargetWidgets::Dip { class PinBodyWidget: public TargetPinBodyWidget { - protected: - void paintEvent(QPaintEvent* event) override; - void drawWidget(QPainter& painter); + Q_OBJECT public: static const int WIDTH = 30; @@ -26,5 +24,9 @@ namespace Bloom::Widgets::InsightTargetWidgets::Dip this->setFixedSize(PinBodyWidget::WIDTH, PinBodyWidget::HEIGHT); this->setObjectName("target-pin-body"); } + + protected: + void paintEvent(QPaintEvent* event) override; + void drawWidget(QPainter& painter); }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/PinWidget.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/PinWidget.cpp index 88076742..fc9fa13d 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/PinWidget.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/PinWidget.cpp @@ -1,12 +1,4 @@ -#include -#include -#include -#include -#include - #include "PinWidget.hpp" -#include "PinBodyWidget.hpp" -#include "src/Logger/Logger.hpp" using namespace Bloom::Widgets::InsightTargetWidgets::Dip; using namespace Bloom::Targets; diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/PinWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/PinWidget.hpp index 26211490..d89697e1 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/PinWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/DIP/PinWidget.hpp @@ -1,9 +1,11 @@ #pragma once #include +#include #include #include "../TargetPinWidget.hpp" + #include "PinBodyWidget.hpp" #include "src/Targets/TargetVariant.hpp" @@ -11,20 +13,7 @@ namespace Bloom::Widgets::InsightTargetWidgets::Dip { class PinWidget: public TargetPinWidget { - Q_OBJECT - private: - QVBoxLayout* layout = nullptr; - QLabel* pinNumberLabel = nullptr; - QLabel* pinNameLabel = nullptr; - QLabel* pinDirectionLabel = nullptr; - PinBodyWidget* bodyWidget = nullptr; - - void setLabelColor(const QString& hexColor) { - auto style = QString("QLabel { color: " + hexColor + "; }"); - if (this->pinNameLabel != nullptr) { - this->pinNameLabel->setStyleSheet(style); - } - } + Q_OBJECT public: static const int MINIMUM_WIDTH = 30; @@ -59,5 +48,19 @@ namespace Bloom::Widgets::InsightTargetWidgets::Dip this->setLabelColor(this->pinStateChanged ? "#4d7bba" : "#a6a7aa"); } + + private: + QVBoxLayout* layout = nullptr; + QLabel* pinNumberLabel = nullptr; + QLabel* pinNameLabel = nullptr; + QLabel* pinDirectionLabel = nullptr; + PinBodyWidget* bodyWidget = nullptr; + + void setLabelColor(const QString& hexColor) { + auto style = QString("QLabel { color: " + hexColor + "; }"); + if (this->pinNameLabel != nullptr) { + this->pinNameLabel->setStyleSheet(style); + } + } }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/BodyWidget.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/BodyWidget.cpp index 813520ba..778671b3 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/BodyWidget.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/BodyWidget.cpp @@ -1,7 +1,6 @@ -#include - #include "BodyWidget.hpp" -#include "src/Logger/Logger.hpp" + +#include using namespace Bloom::Widgets::InsightTargetWidgets::Qfp; diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/BodyWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/BodyWidget.hpp index e3eb35a3..14d68a91 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/BodyWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/BodyWidget.hpp @@ -6,18 +6,9 @@ namespace Bloom::Widgets::InsightTargetWidgets::Qfp { class BodyWidget: public QWidget { - Q_OBJECT - Q_PROPERTY(QColor bodyColor READ getBodyColor WRITE setBodyColor DESIGNABLE true) - Q_PROPERTY(int disableAlphaLevel READ getDisableAlphaLevel WRITE setDisableAlphaLevel DESIGNABLE true) - - private: - // These properties can be modified via Qt style sheets (see Stylesheets/QuadFlatPackage.qss) - QColor bodyColor = QColor("#8E8B83"); - int disableAlphaLevel = 100; - - protected: - void paintEvent(QPaintEvent* event) override; - void drawWidget(QPainter& painter); + Q_OBJECT + Q_PROPERTY(QColor bodyColor READ getBodyColor WRITE setBodyColor DESIGNABLE true) + Q_PROPERTY(int disableAlphaLevel READ getDisableAlphaLevel WRITE setDisableAlphaLevel DESIGNABLE true) public: explicit BodyWidget(QWidget* parent): QWidget(parent) { @@ -39,5 +30,14 @@ namespace Bloom::Widgets::InsightTargetWidgets::Qfp void setDisableAlphaLevel(int level) { this->disableAlphaLevel = level; } + + protected: + void paintEvent(QPaintEvent* event) override; + void drawWidget(QPainter& painter); + + private: + // These properties can be modified via Qt style sheets (see Stylesheets/QuadFlatPackage.qss) + QColor bodyColor = QColor("#8E8B83"); + int disableAlphaLevel = 100; }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/PinBodyWidget.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/PinBodyWidget.cpp index 229aa20f..67b8a771 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/PinBodyWidget.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/PinBodyWidget.cpp @@ -1,8 +1,8 @@ +#include "PinBodyWidget.hpp" + #include #include -#include "PinBodyWidget.hpp" - using namespace Bloom::Widgets::InsightTargetWidgets::Qfp; using namespace Bloom::Targets; diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/PinBodyWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/PinBodyWidget.hpp index 40aa05a5..90de8b76 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/PinBodyWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/PinBodyWidget.hpp @@ -5,18 +5,14 @@ #include #include "../TargetPinBodyWidget.hpp" + #include "src/Targets/TargetPinDescriptor.hpp" namespace Bloom::Widgets::InsightTargetWidgets::Qfp { class PinBodyWidget: public TargetPinBodyWidget { - private: - bool isVertical = false; - - protected: - void paintEvent(QPaintEvent* event) override; - void drawWidget(QPainter& painter); + Q_OBJECT public: static const int WIDTH = 30; @@ -33,5 +29,12 @@ namespace Bloom::Widgets::InsightTargetWidgets::Qfp this->setFixedSize(PinBodyWidget::HEIGHT, PinBodyWidget::WIDTH); } } + + protected: + void paintEvent(QPaintEvent* event) override; + void drawWidget(QPainter& painter); + + private: + bool isVertical = false; }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/PinWidget.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/PinWidget.cpp index e0b62aeb..407902e4 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/PinWidget.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/PinWidget.cpp @@ -6,7 +6,6 @@ #include "PinWidget.hpp" #include "PinBodyWidget.hpp" -#include "src/Logger/Logger.hpp" using namespace Bloom::Widgets::InsightTargetWidgets::Qfp; using namespace Bloom::Targets; diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/PinWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/PinWidget.hpp index c2234e5e..57d4094a 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/PinWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/PinWidget.hpp @@ -12,20 +12,7 @@ namespace Bloom::Widgets::InsightTargetWidgets::Qfp { class PinWidget: public TargetPinWidget { - Q_OBJECT - private: - QBoxLayout* layout = nullptr; - QLabel* pinNumberLabel = nullptr; - QLabel* pinNameLabel = nullptr; - QLabel* pinDirectionLabel = nullptr; - PinBodyWidget* bodyWidget = nullptr; - - bool isLeftLayout = false; - bool isBottomLayout = false; - bool isRightLayout = false; - bool isTopLayout = false; - - void setLabelColor(const QString& hexColor); + Q_OBJECT public: static const int PIN_WIDGET_LAYOUT_PADDING = 46; @@ -49,5 +36,19 @@ namespace Bloom::Widgets::InsightTargetWidgets::Qfp ); void updatePinState(const Targets::TargetPinState& pinState) override; + + private: + QBoxLayout* layout = nullptr; + QLabel* pinNumberLabel = nullptr; + QLabel* pinNameLabel = nullptr; + QLabel* pinDirectionLabel = nullptr; + PinBodyWidget* bodyWidget = nullptr; + + bool isLeftLayout = false; + bool isBottomLayout = false; + bool isRightLayout = false; + bool isTopLayout = false; + + void setLabelColor(const QString& hexColor); }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/QuadFlatPackageWidget.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/QuadFlatPackageWidget.cpp index c01e6fb8..b2f3cc65 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/QuadFlatPackageWidget.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/QuadFlatPackageWidget.cpp @@ -7,7 +7,6 @@ #include #include -#include "../../../InsightWindow.hpp" #include "src/Helpers/Paths.hpp" #include "PinWidget.hpp" #include "BodyWidget.hpp" diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/QuadFlatPackageWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/QuadFlatPackageWidget.hpp index c2bfb446..8e90ddf5 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/QuadFlatPackageWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/QFP/QuadFlatPackageWidget.hpp @@ -17,7 +17,15 @@ namespace Bloom::Widgets::InsightTargetWidgets::Qfp */ class QuadFlatPackageWidget: public TargetPackageWidget { - Q_OBJECT + Q_OBJECT + + public: + QuadFlatPackageWidget( + const Targets::TargetVariant& targetVariant, + InsightWorker& insightWorker, + QWidget* parent + ); + private: QVBoxLayout* layout = nullptr; QHBoxLayout* horizontalLayout = nullptr; @@ -26,12 +34,5 @@ namespace Bloom::Widgets::InsightTargetWidgets::Qfp QHBoxLayout* bottomPinLayout = nullptr; QVBoxLayout* leftPinLayout = nullptr; BodyWidget* bodyWidget = nullptr; - - public: - QuadFlatPackageWidget( - const Targets::TargetVariant& targetVariant, - InsightWorker& insightWorker, - QWidget* parent - ); }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPackageWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPackageWidget.hpp index 014b6f60..71460190 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPackageWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPackageWidget.hpp @@ -18,18 +18,7 @@ namespace Bloom::Widgets::InsightTargetWidgets */ class TargetPackageWidget: public QWidget { - Q_OBJECT - protected: - Targets::TargetVariant targetVariant; - InsightWorker& insightWorker; - std::vector pinWidgets; - - Targets::TargetState targetState = Targets::TargetState::UNKNOWN; - - protected slots: - virtual void updatePinStates(const Targets::TargetPinStateMappingType& pinStatesByNumber); - void onTargetStateChanged(Targets::TargetState newState); - void onRegistersWritten(Targets::TargetRegisters targetRegisters); + Q_OBJECT public: TargetPackageWidget(Targets::TargetVariant targetVariant, InsightWorker& insightWorker, QWidget* parent); @@ -46,5 +35,17 @@ namespace Bloom::Widgets::InsightTargetWidgets QSize minimumSizeHint() const override { return this->sizeHint(); } + + protected: + Targets::TargetVariant targetVariant; + InsightWorker& insightWorker; + std::vector pinWidgets; + + Targets::TargetState targetState = Targets::TargetState::UNKNOWN; + + protected slots: + virtual void updatePinStates(const Targets::TargetPinStateMappingType& pinStatesByNumber); + void onTargetStateChanged(Targets::TargetState newState); + void onRegistersWritten(Targets::TargetRegisters targetRegisters); }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPackageWidgetContainer.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPackageWidgetContainer.cpp index c070af18..c2fe6495 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPackageWidgetContainer.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPackageWidgetContainer.cpp @@ -7,6 +7,14 @@ using namespace Bloom::Widgets::InsightTargetWidgets; TargetPackageWidgetContainer::TargetPackageWidgetContainer(QWidget* parent): QWidget(parent) {} +void TargetPackageWidgetContainer::setPackageWidget(TargetPackageWidget* packageWidget) { + this->packageWidget = packageWidget; + + if (packageWidget != nullptr) { + this->layout()->addWidget(packageWidget); + } +} + void TargetPackageWidgetContainer::resizeEvent(QResizeEvent* event) { if (this->packageWidget == nullptr) { return; @@ -20,11 +28,3 @@ void TargetPackageWidgetContainer::resizeEvent(QResizeEvent* event) { packageSize.height() ); } - -void TargetPackageWidgetContainer::setPackageWidget(TargetPackageWidget* packageWidget) { - this->packageWidget = packageWidget; - - if (packageWidget != nullptr) { - this->layout()->addWidget(packageWidget); - } -} diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPackageWidgetContainer.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPackageWidgetContainer.hpp index 605e6ea6..91241265 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPackageWidgetContainer.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPackageWidgetContainer.hpp @@ -9,16 +9,17 @@ namespace Bloom::Widgets::InsightTargetWidgets { class TargetPackageWidgetContainer: public QWidget { - Q_OBJECT - private: - TargetPackageWidget* packageWidget = nullptr; - - protected: - void resizeEvent(QResizeEvent* event) override; + Q_OBJECT public: TargetPackageWidgetContainer(QWidget* parent); void setPackageWidget(TargetPackageWidget* packageWidget); + + protected: + void resizeEvent(QResizeEvent* event) override; + + private: + TargetPackageWidget* packageWidget = nullptr; }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPinBodyWidget.cpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPinBodyWidget.cpp index 9e3e2103..4695130d 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPinBodyWidget.cpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPinBodyWidget.cpp @@ -5,28 +5,6 @@ using namespace Bloom::Widgets::InsightTargetWidgets; using namespace Bloom::Targets; -bool TargetPinBodyWidget::event(QEvent* event) { - if (this->pinState.has_value() && this->pinState->ioDirection == TargetPinState::IoDirection::OUTPUT) { - switch (event->type()) { - case QEvent::Enter: { - this->hoverActive = true; - this->repaint(); - break; - } - case QEvent::Leave: { - this->hoverActive = false; - this->repaint(); - break; - } - default: { - break; - } - } - } - - return QWidget::event(event); -} - QColor TargetPinBodyWidget::getBodyColor() { auto pinColor = this->defaultBodyColor; @@ -65,3 +43,25 @@ QColor TargetPinBodyWidget::getBodyColor() { return pinColor; } + +bool TargetPinBodyWidget::event(QEvent* event) { + if (this->pinState.has_value() && this->pinState->ioDirection == TargetPinState::IoDirection::OUTPUT) { + switch (event->type()) { + case QEvent::Enter: { + this->hoverActive = true; + this->repaint(); + break; + } + case QEvent::Leave: { + this->hoverActive = false; + this->repaint(); + break; + } + default: { + break; + } + } + } + + return QWidget::event(event); +} diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPinBodyWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPinBodyWidget.hpp index 2bc5ba47..1a84fc98 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPinBodyWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPinBodyWidget.hpp @@ -11,7 +11,7 @@ namespace Bloom::Widgets::InsightTargetWidgets { class TargetPinBodyWidget: public QWidget { - Q_OBJECT + Q_OBJECT /* * Pin body colors can be set in QSS files. */ @@ -23,38 +23,12 @@ namespace Bloom::Widgets::InsightTargetWidgets Q_PROPERTY(int disableAlphaLevel READ getDisableAlphaLevel WRITE setDisableAlphaLevel DESIGNABLE true) - protected: - Targets::TargetPinDescriptor pinDescriptor; - std::optional pinState; - - bool hoverActive = false; - - QColor defaultBodyColor = QColor("#908D85"); - QColor vccBodyColor = QColor("#70383A"); - QColor gndBodyColor = QColor("#484A4B"); - QColor outputHighBodyColor = QColor("#3C5E62"); - QColor inputHighBodyColor = QColor("#7B5E38"); - - int disableAlphaLevel = 100; - - bool event(QEvent* event) override; - - void mouseReleaseEvent(QMouseEvent* event) override { - if (event->button() == Qt::MouseButton::LeftButton) { - emit this->clicked(); - } - - QWidget::mouseReleaseEvent(event); - } - public: TargetPinBodyWidget(QWidget* parent, Targets::TargetPinDescriptor pinDescriptor): QWidget(parent), pinDescriptor(std::move(pinDescriptor)) { this->setObjectName("target-pin-body"); } - QColor getBodyColor(); - void setPinState(const Targets::TargetPinState& pinState) { this->pinState = pinState; } @@ -109,5 +83,31 @@ namespace Bloom::Widgets::InsightTargetWidgets signals: void clicked(); + + protected: + Targets::TargetPinDescriptor pinDescriptor; + std::optional pinState; + + bool hoverActive = false; + + QColor defaultBodyColor = QColor("#908D85"); + QColor vccBodyColor = QColor("#70383A"); + QColor gndBodyColor = QColor("#484A4B"); + QColor outputHighBodyColor = QColor("#3C5E62"); + QColor inputHighBodyColor = QColor("#7B5E38"); + + int disableAlphaLevel = 100; + + QColor getBodyColor(); + + bool event(QEvent* event) override; + + void mouseReleaseEvent(QMouseEvent* event) override { + if (event->button() == Qt::MouseButton::LeftButton) { + emit this->clicked(); + } + + QWidget::mouseReleaseEvent(event); + } }; } diff --git a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPinWidget.hpp b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPinWidget.hpp index 3a21c33b..d269760a 100644 --- a/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPinWidget.hpp +++ b/src/Insight/UserInterfaces/InsightWindow/Widgets/TargetWidgets/TargetPinWidget.hpp @@ -11,14 +11,7 @@ namespace Bloom::Widgets::InsightTargetWidgets { class TargetPinWidget: public QWidget { - Q_OBJECT - protected: - InsightWorker& insightWorker; - - Targets::TargetVariant targetVariant; - Targets::TargetPinDescriptor pinDescriptor; - std::optional pinState; - bool pinStateChanged = false; + Q_OBJECT public: TargetPinWidget( @@ -42,5 +35,13 @@ namespace Bloom::Widgets::InsightTargetWidgets public slots: virtual void onWidgetBodyClicked(); + + protected: + InsightWorker& insightWorker; + + Targets::TargetVariant targetVariant; + Targets::TargetPinDescriptor pinDescriptor; + std::optional pinState; + bool pinStateChanged = false; }; } diff --git a/src/Logger/Logger.cpp b/src/Logger/Logger.cpp index 33cb8863..7642be33 100644 --- a/src/Logger/Logger.cpp +++ b/src/Logger/Logger.cpp @@ -1,10 +1,23 @@ #include "Logger.hpp" #include -#include using namespace Bloom; +void Logger::configure(ApplicationConfig& applicationConfig) { + if (applicationConfig.debugLoggingEnabled) { + Logger::debugPrintingEnabled = true; + Logger::debug("Debug log printing has been enabled."); + } +} + +void Logger::silence() { + Logger::debugPrintingEnabled = false; + Logger::infoPrintingEnabled = false; + Logger::errorPrintingEnabled = false; + Logger::warningPrintingEnabled = false; +} + void Logger::log(const std::string& message, LogLevel logLevel, bool print) { auto lock = std::unique_lock(Logger::logMutex); auto logEntry = LogEntry(message, logLevel); @@ -51,17 +64,3 @@ void Logger::log(const std::string& message, LogLevel logLevel, bool print) { std::cout << logEntry.message << "\033[0m" << std::endl; } } - -void Logger::configure(ApplicationConfig& applicationConfig) { - if (applicationConfig.debugLoggingEnabled) { - Logger::debugPrintingEnabled = true; - Logger::debug("Debug log printing has been enabled."); - } -} - -void Logger::silence() { - Logger::debugPrintingEnabled = false; - Logger::infoPrintingEnabled = false; - Logger::errorPrintingEnabled = false; - Logger::warningPrintingEnabled = false; -} diff --git a/src/Logger/Logger.hpp b/src/Logger/Logger.hpp index 271be211..ae1a778e 100644 --- a/src/Logger/Logger.hpp +++ b/src/Logger/Logger.hpp @@ -52,23 +52,11 @@ namespace Bloom */ class Logger { - private: - /** - * We keep a record of every log entry for future processing. Maybe dumping to a file or something - * of that nature when a fatal error occurs. - */ - static inline std::vector logEntries; - - static inline bool errorPrintingEnabled = true; - static inline bool warningPrintingEnabled = true; - static inline bool infoPrintingEnabled = true; - static inline bool debugPrintingEnabled = false; - - static inline std::mutex logMutex; - - static void log(const std::string& message, LogLevel logLevel, bool print); - public: + static void configure(ApplicationConfig& applicationConfig); + + static void silence(); + static void setInfoPrinting(bool enabled) { Logger::infoPrintingEnabled = enabled; } @@ -97,8 +85,20 @@ namespace Bloom Logger::log(message, LogLevel::DEBUG, Logger::debugPrintingEnabled); } - static void configure(ApplicationConfig& applicationConfig); + private: + /** + * We keep a record of every log entry for future processing. Maybe dumping to a file or something + * of that nature when a fatal error occurs. + */ + static inline std::vector logEntries; - static void silence(); + static inline bool errorPrintingEnabled = true; + static inline bool warningPrintingEnabled = true; + static inline bool infoPrintingEnabled = true; + static inline bool debugPrintingEnabled = false; + + static inline std::mutex logMutex; + + static void log(const std::string& message, LogLevel logLevel, bool print); }; } diff --git a/src/SignalHandler/SignalHandler.cpp b/src/SignalHandler/SignalHandler.cpp index 70b67968..502baaba 100644 --- a/src/SignalHandler/SignalHandler.cpp +++ b/src/SignalHandler/SignalHandler.cpp @@ -8,31 +8,6 @@ using namespace Bloom; -void SignalHandler::startup() { - this->setName("SH"); - Thread::setThreadState(ThreadState::STARTING); - Logger::debug("Starting SignalHandler"); - // Block all signal interrupts - auto signalSet = this->getRegisteredSignalSet(); - sigprocmask(SIG_SETMASK, &signalSet, NULL); - - // Register handlers here - this->handlersMappedBySignalNum.insert(std::pair( - SIGINT, - std::bind(&SignalHandler::triggerApplicationShutdown, this) - )); - - this->handlersMappedBySignalNum.insert(std::pair( - SIGTERM, - std::bind(&SignalHandler::triggerApplicationShutdown, this) - )); - - // It's possible that the SignalHandler has been instructed to shutdown, before it could finish starting up. - if (this->getThreadState() != ThreadState::SHUTDOWN_INITIATED) { - Thread::setThreadState(ThreadState::READY); - } -} - void SignalHandler::run() { try { this->startup(); @@ -58,6 +33,31 @@ void SignalHandler::run() { Thread::setThreadState(ThreadState::STOPPED); } +void SignalHandler::startup() { + this->setName("SH"); + Thread::setThreadState(ThreadState::STARTING); + Logger::debug("Starting SignalHandler"); + // Block all signal interrupts + auto signalSet = this->getRegisteredSignalSet(); + sigprocmask(SIG_SETMASK, &signalSet, NULL); + + // Register handlers here + this->handlersMappedBySignalNum.insert(std::pair( + SIGINT, + std::bind(&SignalHandler::triggerApplicationShutdown, this) + )); + + this->handlersMappedBySignalNum.insert(std::pair( + SIGTERM, + std::bind(&SignalHandler::triggerApplicationShutdown, this) + )); + + // It's possible that the SignalHandler has been instructed to shutdown, before it could finish starting up. + if (this->getThreadState() != ThreadState::SHUTDOWN_INITIATED) { + Thread::setThreadState(ThreadState::READY); + } +} + sigset_t SignalHandler::getRegisteredSignalSet() const { sigset_t set = {}; if (sigfillset(&set) == -1) { diff --git a/src/SignalHandler/SignalHandler.hpp b/src/SignalHandler/SignalHandler.hpp index 860b6a1e..8bbd1ba6 100644 --- a/src/SignalHandler/SignalHandler.hpp +++ b/src/SignalHandler/SignalHandler.hpp @@ -10,6 +10,21 @@ namespace Bloom { class SignalHandler: public Thread { + public: + explicit SignalHandler(EventManager& eventManager): eventManager(eventManager) {}; + + /** + * Entry point for SignalHandler thread. + */ + void run(); + + /** + * Triggers the shutdown of the SignalHandler thread. + */ + void triggerShutdown() { + this->setThreadState(ThreadState::SHUTDOWN_INITIATED); + }; + private: EventManager& eventManager; @@ -45,20 +60,5 @@ namespace Bloom * program immediately if numerous SIGINT signals have been received. */ void triggerApplicationShutdown(); - - public: - explicit SignalHandler(EventManager& eventManager): eventManager(eventManager) {}; - - /** - * Entry point for SignalHandler thread. - */ - void run(); - - /** - * Triggers the shutdown of the SignalHandler thread. - */ - void triggerShutdown() { - this->setThreadState(ThreadState::SHUTDOWN_INITIATED); - }; }; } diff --git a/src/TargetController/TargetController.cpp b/src/TargetController/TargetController.cpp index e98d58b4..7cb4b1f1 100644 --- a/src/TargetController/TargetController.cpp +++ b/src/TargetController/TargetController.cpp @@ -7,6 +7,7 @@ #include "src/Application.hpp" #include "src/Helpers/Paths.hpp" +#include "src/Logger/Logger.hpp" #include "src/TargetController/Exceptions/DeviceFailure.hpp" #include "src/TargetController/Exceptions/TargetOperationFailure.hpp" @@ -261,78 +262,6 @@ void TargetController::resume() { } } -void TargetController::loadRegisterDescriptors() { - auto& targetDescriptor = this->getTargetDescriptor(); - - for (const auto& [registerType, registerDescriptors] : targetDescriptor.registerDescriptorsByType) { - for (const auto& registerDescriptor : registerDescriptors) { - auto startAddress = registerDescriptor.startAddress.value_or(0); - auto endAddress = startAddress + (registerDescriptor.size - 1); - - if (!this->registerAddressRangeByMemoryType.contains(registerDescriptor.memoryType)) { - auto addressRange = TargetMemoryAddressRange(); - addressRange.startAddress = startAddress; - addressRange.endAddress = endAddress; - this->registerAddressRangeByMemoryType.insert( - std::pair(registerDescriptor.memoryType, addressRange) - ); - - } else { - auto& addressRange = this->registerAddressRangeByMemoryType.at(registerDescriptor.memoryType); - - if (startAddress < addressRange.startAddress) { - addressRange.startAddress = startAddress; - } - - if (endAddress > addressRange.endAddress) { - addressRange.endAddress = endAddress; - } - } - - this->registerDescriptorsByMemoryType[registerDescriptor.memoryType].insert(registerDescriptor); - } - } -} - -TargetRegisterDescriptors TargetController::getRegisterDescriptorsWithinAddressRange( - std::uint32_t startAddress, - std::uint32_t endAddress, - Targets::TargetMemoryType memoryType -) { - auto output = TargetRegisterDescriptors(); - - if (this->registerAddressRangeByMemoryType.contains(memoryType) - && this->registerDescriptorsByMemoryType.contains(memoryType) - ) { - auto& registersAddressRange = this->registerAddressRangeByMemoryType.at(memoryType); - - if ( - (startAddress <= registersAddressRange.startAddress && endAddress >= registersAddressRange.startAddress) - || (startAddress <= registersAddressRange.endAddress && endAddress >= registersAddressRange.startAddress) - ) { - auto& registerDescriptors = this->registerDescriptorsByMemoryType.at(memoryType); - - for (const auto& registerDescriptor : registerDescriptors) { - if (!registerDescriptor.startAddress.has_value() || registerDescriptor.size < 1) { - continue; - } - - auto registerStartAddress = registerDescriptor.startAddress.value(); - auto registerEndAddress = registerStartAddress + registerDescriptor.size; - - if ( - (startAddress <= registerStartAddress && endAddress >= registerStartAddress) - || (startAddress <= registerEndAddress && endAddress >= registerStartAddress) - ) { - output.insert(registerDescriptor); - } - } - } - } - - return output; -} - void TargetController::acquireHardware() { auto debugToolName = this->environmentConfig.debugToolConfig.name; auto targetName = this->environmentConfig.targetConfig.name; @@ -418,6 +347,78 @@ void TargetController::releaseHardware() { this->target.reset(); } +void TargetController::loadRegisterDescriptors() { + auto& targetDescriptor = this->getTargetDescriptor(); + + for (const auto& [registerType, registerDescriptors] : targetDescriptor.registerDescriptorsByType) { + for (const auto& registerDescriptor : registerDescriptors) { + auto startAddress = registerDescriptor.startAddress.value_or(0); + auto endAddress = startAddress + (registerDescriptor.size - 1); + + if (!this->registerAddressRangeByMemoryType.contains(registerDescriptor.memoryType)) { + auto addressRange = TargetMemoryAddressRange(); + addressRange.startAddress = startAddress; + addressRange.endAddress = endAddress; + this->registerAddressRangeByMemoryType.insert( + std::pair(registerDescriptor.memoryType, addressRange) + ); + + } else { + auto& addressRange = this->registerAddressRangeByMemoryType.at(registerDescriptor.memoryType); + + if (startAddress < addressRange.startAddress) { + addressRange.startAddress = startAddress; + } + + if (endAddress > addressRange.endAddress) { + addressRange.endAddress = endAddress; + } + } + + this->registerDescriptorsByMemoryType[registerDescriptor.memoryType].insert(registerDescriptor); + } + } +} + +TargetRegisterDescriptors TargetController::getRegisterDescriptorsWithinAddressRange( + std::uint32_t startAddress, + std::uint32_t endAddress, + Targets::TargetMemoryType memoryType +) { + auto output = TargetRegisterDescriptors(); + + if (this->registerAddressRangeByMemoryType.contains(memoryType) + && this->registerDescriptorsByMemoryType.contains(memoryType) + ) { + auto& registersAddressRange = this->registerAddressRangeByMemoryType.at(memoryType); + + if ( + (startAddress <= registersAddressRange.startAddress && endAddress >= registersAddressRange.startAddress) + || (startAddress <= registersAddressRange.endAddress && endAddress >= registersAddressRange.startAddress) + ) { + auto& registerDescriptors = this->registerDescriptorsByMemoryType.at(memoryType); + + for (const auto& registerDescriptor : registerDescriptors) { + if (!registerDescriptor.startAddress.has_value() || registerDescriptor.size < 1) { + continue; + } + + auto registerStartAddress = registerDescriptor.startAddress.value(); + auto registerEndAddress = registerStartAddress + registerDescriptor.size; + + if ( + (startAddress <= registerStartAddress && endAddress >= registerStartAddress) + || (startAddress <= registerEndAddress && endAddress >= registerStartAddress) + ) { + output.insert(registerDescriptor); + } + } + } + } + + return output; +} + void TargetController::fireTargetEvents() { auto newTargetState = this->target->getState(); @@ -464,6 +465,14 @@ void TargetController::onStateReportRequest(const Events::ReportTargetController this->eventManager.triggerEvent(stateEvent); } +void TargetController::onExtractTargetDescriptor(const Events::ExtractTargetDescriptor& event) { + auto targetDescriptorExtracted = std::make_shared(); + targetDescriptorExtracted->targetDescriptor = this->getTargetDescriptor(); + + targetDescriptorExtracted->correlationId = event.id; + this->eventManager.triggerEvent(targetDescriptorExtracted); +} + void TargetController::onDebugSessionStartedEvent(const Events::DebugSessionStarted&) { if (this->state == TargetControllerState::SUSPENDED) { Logger::debug("Waking TargetController"); @@ -490,14 +499,6 @@ void TargetController::onDebugSessionFinishedEvent(const DebugSessionFinished&) } } -void TargetController::onExtractTargetDescriptor(const Events::ExtractTargetDescriptor& event) { - auto targetDescriptorExtracted = std::make_shared(); - targetDescriptorExtracted->targetDescriptor = this->getTargetDescriptor(); - - targetDescriptorExtracted->correlationId = event.id; - this->eventManager.triggerEvent(targetDescriptorExtracted); -} - void TargetController::onStopTargetExecutionEvent(const Events::StopTargetExecution& event) { if (this->target->getState() != TargetState::STOPPED) { this->target->stop(); diff --git a/src/TargetController/TargetController.hpp b/src/TargetController/TargetController.hpp index b5974e51..d3a3a242 100644 --- a/src/TargetController/TargetController.hpp +++ b/src/TargetController/TargetController.hpp @@ -20,8 +20,6 @@ #include "src/EventManager/EventListener.hpp" #include "src/EventManager/Events/Events.hpp" -#include "src/Logger/Logger.hpp" - namespace Bloom { /** @@ -35,6 +33,22 @@ namespace Bloom */ class TargetController: public Thread { + public: + explicit TargetController(EventManager& eventManager): eventManager(eventManager) {}; + + void setApplicationConfig(const ApplicationConfig& applicationConfig) { + this->applicationConfig = applicationConfig; + } + + void setEnvironmentConfig(const EnvironmentConfig& environmentConfig) { + this->environmentConfig = environmentConfig; + } + + /** + * Entry point for the TargetController. + */ + void run(); + private: /** * The TC starts off in a suspended state. TargetController::resume() is invoked from the startup routine. @@ -180,6 +194,11 @@ namespace Bloom ); } + /** + * Because the TargetController hogs the thread, this method must be called in a dedicated thread. + */ + void startup(); + /** * Installs Bloom's udev rules on user's machine. Rules are copied from build/Distribution/Resources/UdevRules * to /etc/udev/rules.d/. This method will report an error if Bloom isn't running as root (as root privileges @@ -187,11 +206,6 @@ namespace Bloom */ static void checkUdevRules(); - /** - * Because the TargetController hogs the thread, this method must be called in a dedicated thread. - */ - void startup(); - /** * Exit point - must be called before the TargetController thread is terminated. * @@ -199,17 +213,6 @@ namespace Bloom */ void shutdown(); - /** - * Establishes a connection with the debug tool and target. Prepares the hardware for a debug session. - */ - void acquireHardware(); - - /** - * Attempts to gracefully disconnect from the debug tool and the target. All control of the debug tool and - * target will cease. - */ - void releaseHardware(); - /** * Puts the TargetController into the suspended state. * @@ -222,6 +225,17 @@ namespace Bloom */ void resume(); + /** + * Establishes a connection with the debug tool and target. Prepares the hardware for a debug session. + */ + void acquireHardware(); + + /** + * Attempts to gracefully disconnect from the debug tool and the target. All control of the debug tool and + * target will cease. + */ + void releaseHardware(); + /** * Extracts address ranges and groups target register descriptors. */ @@ -257,21 +271,12 @@ namespace Bloom Targets::TargetDescriptor& getTargetDescriptor(); - public: - explicit TargetController(EventManager& eventManager): eventManager(eventManager) {}; - - void setApplicationConfig(const ApplicationConfig& applicationConfig) { - this->applicationConfig = applicationConfig; - } - - void setEnvironmentConfig(const EnvironmentConfig& environmentConfig) { - this->environmentConfig = environmentConfig; - } - /** - * Entry point for the TargetController. + * Invokes a shutdown. + * + * @param event */ - void run(); + void onShutdownTargetControllerEvent(const Events::ShutdownTargetController& event); /** * Reports the current state of the TargetController. @@ -287,6 +292,20 @@ namespace Bloom */ void onExtractTargetDescriptor(const Events::ExtractTargetDescriptor& event); + /** + * Will hold the target stopped at it's current state. + * + * @param event + */ + void onDebugSessionStartedEvent(const Events::DebugSessionStarted& event); + + /** + * Will simply kick off execution on the target. + * + * @param event + */ + void onDebugSessionFinishedEvent(const Events::DebugSessionFinished& event); + /** * Will attempt to stop execution on the target and emit a TargetExecutionStopped event. * @@ -308,13 +327,6 @@ namespace Bloom */ void onResumeTargetExecutionEvent(const Events::ResumeTargetExecution& event); - /** - * Invokes a shutdown. - * - * @param event - */ - void onShutdownTargetControllerEvent(const Events::ShutdownTargetController& event); - /** * Will attempt to read the requested registers and emit a RegistersRetrievedFromTarget event. * @@ -359,20 +371,6 @@ namespace Bloom */ void onRemoveBreakpointEvent(const Events::RemoveBreakpointOnTarget& event); - /** - * Will hold the target stopped at it's current state. - * - * @param event - */ - void onDebugSessionStartedEvent(const Events::DebugSessionStarted& event); - - /** - * Will simply kick off execution on the target. - * - * @param event - */ - void onDebugSessionFinishedEvent(const Events::DebugSessionFinished& event); - /** * Will update the program counter value on the target. On success, a ProgramCounterSetOnTarget event is * emitted. diff --git a/src/TargetController/TargetControllerConsole.cpp b/src/TargetController/TargetControllerConsole.cpp index f50bd306..7ff4693b 100644 --- a/src/TargetController/TargetControllerConsole.cpp +++ b/src/TargetController/TargetControllerConsole.cpp @@ -1,7 +1,5 @@ #include "TargetControllerConsole.hpp" -#include - #include "src/EventManager/Events/Events.hpp" #include "src/Logger/Logger.hpp" diff --git a/src/TargetController/TargetControllerConsole.hpp b/src/TargetController/TargetControllerConsole.hpp index a1bc0231..17050af0 100644 --- a/src/TargetController/TargetControllerConsole.hpp +++ b/src/TargetController/TargetControllerConsole.hpp @@ -23,78 +23,6 @@ namespace Bloom */ class TargetControllerConsole { - private: - EventManager& eventManager; - EventListener& eventListener; - - std::chrono::milliseconds defaultTimeout = std::chrono::milliseconds(10000); - - /** - * Triggers an event for the TargetController and waits for a response. - * - * To use this method, the triggered event must define a 'TargetControllerResponseType' alias, which should - * specify the type of response expected by the TargetController. - * For an example of this, see the Events::ExtractTargetDescriptor class. - * - * If the TargetController fails to respond within the given time specified by the timeout parameter, or it - * responds with an instance of Events::TargetControllerErrorOccurred, this method will throw an exception. - * - * @tparam TriggerEventType - * - * @param event - * Event to trigger. - * - * @param timeout - * The time, in milliseconds, to wait for the TargetController to respond to the event. If this is not - * supplied, this->defaultTimeout will be used. - * - * @return - */ - template - auto triggerTargetControllerEventAndWaitForResponse( - const Events::SharedEventPointerNonConst event, - std::optional timeout = {} - ) { - using Bloom::Events::SharedEventPointer; - using Bloom::Events::TargetControllerErrorOccurred; - - using ResponseEventType = typename TriggerEventType::TargetControllerResponseType; - - bool deRegisterEventType = false; - - if (!this->eventListener.isEventTypeRegistered()) { - this->eventListener.registerEventType(); - deRegisterEventType = true; - } - - this->eventManager.triggerEvent(event); - - auto responseEvent = this->eventListener.waitForEvent< - ResponseEventType, - TargetControllerErrorOccurred - >(timeout.value_or(this->defaultTimeout), event->id); - - if (deRegisterEventType) { - this->eventListener.deRegisterEventType(); - } - - if (!responseEvent.has_value()) { - throw Bloom::Exceptions::Exception("Timed out waiting for response from TargetController."); - } - - if (!std::holds_alternative>(responseEvent.value())) { - if (std::holds_alternative>(responseEvent.value())) { - auto& tcErrorEvent = std::get>(responseEvent.value()); - throw Bloom::Exceptions::Exception(tcErrorEvent->errorMessage); - - } else { - throw Bloom::Exceptions::Exception("Unexpected response from TargetController"); - } - } - - return std::get>(responseEvent.value()); - } - public: TargetControllerConsole(EventManager& eventManager, EventListener& eventListener): eventManager(eventManager), eventListener(eventListener) {}; @@ -212,5 +140,77 @@ namespace Bloom * @param pinState */ void setPinState(Targets::TargetPinDescriptor pinDescriptor, Targets::TargetPinState pinState); + + private: + EventManager& eventManager; + EventListener& eventListener; + + std::chrono::milliseconds defaultTimeout = std::chrono::milliseconds(10000); + + /** + * Triggers an event for the TargetController and waits for a response. + * + * To use this method, the triggered event must define a 'TargetControllerResponseType' alias, which should + * specify the type of response expected by the TargetController. + * For an example of this, see the Events::ExtractTargetDescriptor class. + * + * If the TargetController fails to respond within the given time specified by the timeout parameter, or it + * responds with an instance of Events::TargetControllerErrorOccurred, this method will throw an exception. + * + * @tparam TriggerEventType + * + * @param event + * Event to trigger. + * + * @param timeout + * The time, in milliseconds, to wait for the TargetController to respond to the event. If this is not + * supplied, this->defaultTimeout will be used. + * + * @return + */ + template + auto triggerTargetControllerEventAndWaitForResponse( + const Events::SharedEventPointerNonConst event, + std::optional timeout = {} + ) { + using Bloom::Events::SharedEventPointer; + using Bloom::Events::TargetControllerErrorOccurred; + + using ResponseEventType = typename TriggerEventType::TargetControllerResponseType; + + bool deRegisterEventType = false; + + if (!this->eventListener.isEventTypeRegistered()) { + this->eventListener.registerEventType(); + deRegisterEventType = true; + } + + this->eventManager.triggerEvent(event); + + auto responseEvent = this->eventListener.waitForEvent< + ResponseEventType, + TargetControllerErrorOccurred + >(timeout.value_or(this->defaultTimeout), event->id); + + if (deRegisterEventType) { + this->eventListener.deRegisterEventType(); + } + + if (!responseEvent.has_value()) { + throw Bloom::Exceptions::Exception("Timed out waiting for response from TargetController."); + } + + if (!std::holds_alternative>(responseEvent.value())) { + if (std::holds_alternative>(responseEvent.value())) { + auto& tcErrorEvent = std::get>(responseEvent.value()); + throw Bloom::Exceptions::Exception(tcErrorEvent->errorMessage); + + } else { + throw Bloom::Exceptions::Exception("Unexpected response from TargetController"); + } + } + + return std::get>(responseEvent.value()); + } }; } diff --git a/src/Targets/Microchip/AVR/AVR8/Avr8.cpp b/src/Targets/Microchip/AVR/AVR8/Avr8.cpp index e0524465..bcac1e32 100644 --- a/src/Targets/Microchip/AVR/AVR8/Avr8.cpp +++ b/src/Targets/Microchip/AVR/AVR8/Avr8.cpp @@ -8,7 +8,6 @@ #include #include "PadDescriptor.hpp" -#include "PhysicalInterface.hpp" #include "src/Logger/Logger.hpp" #include "src/Exceptions/InvalidConfig.hpp" #include "src/Targets/TargetRegister.hpp" @@ -25,110 +24,6 @@ using namespace Bloom::Targets::Microchip::Avr; using namespace Bloom::Targets::Microchip::Avr::Avr8Bit; using namespace Exceptions; -void Avr8::loadTargetDescriptionFile() { - this->targetDescriptionFile = TargetDescription::TargetDescriptionFile( - this->getId(), - (!this->name.empty()) ? std::optional(this->name) : std::nullopt - ); -} - -void Avr8::initFromTargetDescriptionFile() { - assert(this->targetDescriptionFile.has_value()); - this->name = this->targetDescriptionFile->getTargetName(); - this->family = this->targetDescriptionFile->getFamily(); - - this->targetParameters = this->targetDescriptionFile->getTargetParameters(); - this->padDescriptorsByName = this->targetDescriptionFile->getPadDescriptorsMappedByName(); - this->targetVariantsById = this->targetDescriptionFile->getVariantsMappedById(); - - if (!this->targetParameters->stackPointerRegisterLowAddress.has_value()) { - throw Exception("Failed to load sufficient AVR8 target paramters - missting stack pointer start address"); - } - - if (!this->targetParameters->statusRegisterStartAddress.has_value()) { - throw Exception("Failed to load sufficient AVR8 target parameters - missting status register start address"); - } - - this->loadTargetRegisterDescriptors(); -} - -void Avr8::loadTargetRegisterDescriptors() { - this->targetRegisterDescriptorsByType = this->targetDescriptionFile->getRegisterDescriptorsMappedByType(); - - /* - * All AVR8 targets possess 32 general purpose CPU registers. These are not described in the TDF, so we - * construct the descriptors for them here. - */ - auto gpRegisterStartAddress = this->targetParameters->gpRegisterStartAddress.value_or(0); - for (std::uint8_t i = 0; i <= 31; i++) { - auto generalPurposeRegisterDescriptor = TargetRegisterDescriptor(); - generalPurposeRegisterDescriptor.startAddress = gpRegisterStartAddress + i; - generalPurposeRegisterDescriptor.size = 1; - generalPurposeRegisterDescriptor.type = TargetRegisterType::GENERAL_PURPOSE_REGISTER; - generalPurposeRegisterDescriptor.name = "r" + std::to_string(i); - generalPurposeRegisterDescriptor.groupName = "general purpose cpu"; - generalPurposeRegisterDescriptor.readable = true; - generalPurposeRegisterDescriptor.writable = true; - - this->targetRegisterDescriptorsByType[generalPurposeRegisterDescriptor.type].insert( - generalPurposeRegisterDescriptor - ); - } - - /* - * The SP and SREG registers are described in the TDF, so we could just use the descriptors extracted from the - * TDF. The problem with that is, sometimes the SP register consists of two bytes; an SPL and an SPH. These need - * to be combined into one register descriptor. This is why we just use what we already have in - * this->targetParameters. - */ - auto stackPointerRegisterDescriptor = TargetRegisterDescriptor(); - stackPointerRegisterDescriptor.type = TargetRegisterType::STACK_POINTER; - stackPointerRegisterDescriptor.startAddress = this->targetParameters->stackPointerRegisterLowAddress.value(); - stackPointerRegisterDescriptor.size = this->targetParameters->stackPointerRegisterSize.value(); - stackPointerRegisterDescriptor.name = "SP"; - stackPointerRegisterDescriptor.groupName = "CPU"; - stackPointerRegisterDescriptor.description = "Stack Pointer Register"; - stackPointerRegisterDescriptor.readable = true; - stackPointerRegisterDescriptor.writable = true; - - auto statusRegisterDescriptor = TargetRegisterDescriptor(); - statusRegisterDescriptor.type = TargetRegisterType::STATUS_REGISTER; - statusRegisterDescriptor.startAddress = this->targetParameters->statusRegisterStartAddress.value(); - statusRegisterDescriptor.size = this->targetParameters->statusRegisterSize.value(); - statusRegisterDescriptor.name = "SREG"; - statusRegisterDescriptor.groupName = "CPU"; - statusRegisterDescriptor.description = "Status Register"; - statusRegisterDescriptor.readable = true; - statusRegisterDescriptor.writable = true; - - auto programCounterRegisterDescriptor = TargetRegisterDescriptor(); - programCounterRegisterDescriptor.type = TargetRegisterType::PROGRAM_COUNTER; - programCounterRegisterDescriptor.size = 4; - programCounterRegisterDescriptor.name = "PC"; - programCounterRegisterDescriptor.groupName = "CPU"; - programCounterRegisterDescriptor.description = "Program Counter"; - programCounterRegisterDescriptor.readable = true; - programCounterRegisterDescriptor.writable = true; - - this->targetRegisterDescriptorsByType[stackPointerRegisterDescriptor.type].insert( - stackPointerRegisterDescriptor - ); - this->targetRegisterDescriptorsByType[statusRegisterDescriptor.type].insert( - statusRegisterDescriptor - ); - this->targetRegisterDescriptorsByType[programCounterRegisterDescriptor.type].insert( - programCounterRegisterDescriptor - ); -} - -TargetSignature Avr8::getId() { - if (!this->id.has_value()) { - this->id = this->avr8Interface->getDeviceId(); - } - - return this->id.value(); -} - void Avr8::preActivationConfigure(const TargetConfig& targetConfig) { Target::preActivationConfigure(targetConfig); @@ -188,6 +83,16 @@ void Avr8::activate() { this->activated = true; } +void Avr8::deactivate() { + try { + this->avr8Interface->deactivate(); + this->activated = false; + + } catch (const Exception& exception) { + Logger::error("Failed to deactivate AVR8 target - " + exception.getMessage()); + } +} + std::unique_ptr Avr8::promote() { std::unique_ptr promoted = nullptr; @@ -218,16 +123,6 @@ std::unique_ptr Avr8::promote() { return promoted; } -void Avr8::deactivate() { - try { - this->avr8Interface->deactivate(); - this->activated = false; - - } catch (const Exception& exception) { - Logger::error("Failed to deactivate AVR8 target - " + exception.getMessage()); - } -} - TargetDescriptor Avr8Bit::Avr8::getDescriptor() { auto descriptor = TargetDescriptor(); descriptor.id = this->getHumanReadableId(); @@ -560,3 +455,107 @@ void Avr8::setPinState(const TargetPinDescriptor& pinDescriptor, const TargetPin } } } + +void Avr8::loadTargetDescriptionFile() { + this->targetDescriptionFile = TargetDescription::TargetDescriptionFile( + this->getId(), + (!this->name.empty()) ? std::optional(this->name) : std::nullopt + ); +} + +void Avr8::initFromTargetDescriptionFile() { + assert(this->targetDescriptionFile.has_value()); + this->name = this->targetDescriptionFile->getTargetName(); + this->family = this->targetDescriptionFile->getFamily(); + + this->targetParameters = this->targetDescriptionFile->getTargetParameters(); + this->padDescriptorsByName = this->targetDescriptionFile->getPadDescriptorsMappedByName(); + this->targetVariantsById = this->targetDescriptionFile->getVariantsMappedById(); + + if (!this->targetParameters->stackPointerRegisterLowAddress.has_value()) { + throw Exception("Failed to load sufficient AVR8 target paramters - missting stack pointer start address"); + } + + if (!this->targetParameters->statusRegisterStartAddress.has_value()) { + throw Exception("Failed to load sufficient AVR8 target parameters - missting status register start address"); + } + + this->loadTargetRegisterDescriptors(); +} + +void Avr8::loadTargetRegisterDescriptors() { + this->targetRegisterDescriptorsByType = this->targetDescriptionFile->getRegisterDescriptorsMappedByType(); + + /* + * All AVR8 targets possess 32 general purpose CPU registers. These are not described in the TDF, so we + * construct the descriptors for them here. + */ + auto gpRegisterStartAddress = this->targetParameters->gpRegisterStartAddress.value_or(0); + for (std::uint8_t i = 0; i <= 31; i++) { + auto generalPurposeRegisterDescriptor = TargetRegisterDescriptor(); + generalPurposeRegisterDescriptor.startAddress = gpRegisterStartAddress + i; + generalPurposeRegisterDescriptor.size = 1; + generalPurposeRegisterDescriptor.type = TargetRegisterType::GENERAL_PURPOSE_REGISTER; + generalPurposeRegisterDescriptor.name = "r" + std::to_string(i); + generalPurposeRegisterDescriptor.groupName = "general purpose cpu"; + generalPurposeRegisterDescriptor.readable = true; + generalPurposeRegisterDescriptor.writable = true; + + this->targetRegisterDescriptorsByType[generalPurposeRegisterDescriptor.type].insert( + generalPurposeRegisterDescriptor + ); + } + + /* + * The SP and SREG registers are described in the TDF, so we could just use the descriptors extracted from the + * TDF. The problem with that is, sometimes the SP register consists of two bytes; an SPL and an SPH. These need + * to be combined into one register descriptor. This is why we just use what we already have in + * this->targetParameters. + */ + auto stackPointerRegisterDescriptor = TargetRegisterDescriptor(); + stackPointerRegisterDescriptor.type = TargetRegisterType::STACK_POINTER; + stackPointerRegisterDescriptor.startAddress = this->targetParameters->stackPointerRegisterLowAddress.value(); + stackPointerRegisterDescriptor.size = this->targetParameters->stackPointerRegisterSize.value(); + stackPointerRegisterDescriptor.name = "SP"; + stackPointerRegisterDescriptor.groupName = "CPU"; + stackPointerRegisterDescriptor.description = "Stack Pointer Register"; + stackPointerRegisterDescriptor.readable = true; + stackPointerRegisterDescriptor.writable = true; + + auto statusRegisterDescriptor = TargetRegisterDescriptor(); + statusRegisterDescriptor.type = TargetRegisterType::STATUS_REGISTER; + statusRegisterDescriptor.startAddress = this->targetParameters->statusRegisterStartAddress.value(); + statusRegisterDescriptor.size = this->targetParameters->statusRegisterSize.value(); + statusRegisterDescriptor.name = "SREG"; + statusRegisterDescriptor.groupName = "CPU"; + statusRegisterDescriptor.description = "Status Register"; + statusRegisterDescriptor.readable = true; + statusRegisterDescriptor.writable = true; + + auto programCounterRegisterDescriptor = TargetRegisterDescriptor(); + programCounterRegisterDescriptor.type = TargetRegisterType::PROGRAM_COUNTER; + programCounterRegisterDescriptor.size = 4; + programCounterRegisterDescriptor.name = "PC"; + programCounterRegisterDescriptor.groupName = "CPU"; + programCounterRegisterDescriptor.description = "Program Counter"; + programCounterRegisterDescriptor.readable = true; + programCounterRegisterDescriptor.writable = true; + + this->targetRegisterDescriptorsByType[stackPointerRegisterDescriptor.type].insert( + stackPointerRegisterDescriptor + ); + this->targetRegisterDescriptorsByType[statusRegisterDescriptor.type].insert( + statusRegisterDescriptor + ); + this->targetRegisterDescriptorsByType[programCounterRegisterDescriptor.type].insert( + programCounterRegisterDescriptor + ); +} + +TargetSignature Avr8::getId() { + if (!this->id.has_value()) { + this->id = this->avr8Interface->getDeviceId(); + } + + return this->id.value(); +} diff --git a/src/Targets/Microchip/AVR/AVR8/Avr8.hpp b/src/Targets/Microchip/AVR/AVR8/Avr8.hpp index d503e877..3a20cf98 100644 --- a/src/Targets/Microchip/AVR/AVR8/Avr8.hpp +++ b/src/Targets/Microchip/AVR/AVR8/Avr8.hpp @@ -21,41 +21,6 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit { class Avr8: public Target { - protected: - DebugToolDrivers::TargetInterfaces::Microchip::Avr::Avr8::Avr8Interface* avr8Interface = nullptr; - std::string name; - std::optional family; - std::optional targetDescriptionFile; - std::optional targetParameters; - std::map padDescriptorsByName; - std::map targetVariantsById; - std::map targetRegisterDescriptorsByType; - - /** - * Resolves the appropriate TDF for the AVR8 target and populates this->targetDescriptionFile. - */ - void loadTargetDescriptionFile(); - - /** - * Initiates the AVR8 instance from data extracted from the TDF. - */ - void initFromTargetDescriptionFile(); - - /** - * Populates this->targetRegisterDescriptorsByType with registers extracted from the TDF, as well as general - * purpose and other CPU registers. - */ - void loadTargetRegisterDescriptors(); - - /** - * Extracts the ID from the target's memory. - * - * This function will cache the ID value and use the cached version for any subsequent calls. - * - * @return - */ - TargetSignature getId() override; - public: explicit Avr8() = default; Avr8(std::string name, const TargetSignature& signature): name(std::move(name)) { @@ -149,5 +114,40 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit const TargetPinDescriptor& pinDescriptor, const TargetPinState& state ) override; + + protected: + DebugToolDrivers::TargetInterfaces::Microchip::Avr::Avr8::Avr8Interface* avr8Interface = nullptr; + std::string name; + std::optional family; + std::optional targetDescriptionFile; + std::optional targetParameters; + std::map padDescriptorsByName; + std::map targetVariantsById; + std::map targetRegisterDescriptorsByType; + + /** + * Resolves the appropriate TDF for the AVR8 target and populates this->targetDescriptionFile. + */ + void loadTargetDescriptionFile(); + + /** + * Initiates the AVR8 instance from data extracted from the TDF. + */ + void initFromTargetDescriptionFile(); + + /** + * Populates this->targetRegisterDescriptorsByType with registers extracted from the TDF, as well as general + * purpose and other CPU registers. + */ + void loadTargetRegisterDescriptors(); + + /** + * Extracts the ID from the target's memory. + * + * This function will cache the ID value and use the cached version for any subsequent calls. + * + * @return + */ + TargetSignature getId() override; }; } diff --git a/src/Targets/Microchip/AVR/AVR8/Mega/Mega.hpp b/src/Targets/Microchip/AVR/AVR8/Mega/Mega.hpp index 2e7ff0ab..02f34901 100644 --- a/src/Targets/Microchip/AVR/AVR8/Mega/Mega.hpp +++ b/src/Targets/Microchip/AVR/AVR8/Mega/Mega.hpp @@ -6,8 +6,6 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit { class Mega: public Avr8 { - protected: - public: explicit Mega(const Avr8& avr8): Avr8(avr8) {}; diff --git a/src/Targets/Microchip/AVR/AVR8/TargetDescription/TargetDescriptionFile.cpp b/src/Targets/Microchip/AVR/AVR8/TargetDescription/TargetDescriptionFile.cpp index e1aa9851..19c62cd0 100644 --- a/src/Targets/Microchip/AVR/AVR8/TargetDescription/TargetDescriptionFile.cpp +++ b/src/Targets/Microchip/AVR/AVR8/TargetDescription/TargetDescriptionFile.cpp @@ -4,9 +4,10 @@ #include #include "src/Helpers/Paths.hpp" +#include "src/Logger/Logger.hpp" + #include "src/Exceptions/Exception.hpp" #include "src/Targets/TargetDescription/Exceptions/TargetDescriptionParsingFailureException.hpp" -#include "src/Logger/Logger.hpp" using namespace Bloom::Targets::Microchip::Avr::Avr8Bit::TargetDescription; using namespace Bloom::Targets::Microchip::Avr::Avr8Bit; @@ -1127,36 +1128,3 @@ void TargetDescriptionFile::loadUpdiTargetParameters(TargetParameters& targetPar targetParameters.lockbitsSegmentStartAddress = lockbitsMemorySegment->startAddress; } } - -std::uint32_t TargetDescriptionFile::getRegisterAddressOffsetByModuleName(const std::string& moduleName) const { - if (this->peripheralModulesMappedByName.contains(moduleName)) { - auto& peripheralModule = this->peripheralModulesMappedByName.at(moduleName); - - if (peripheralModule.instancesMappedByName.contains(moduleName)) { - auto& moduleInstance = peripheralModule.instancesMappedByName.at(moduleName); - - if (moduleInstance.registerGroupsMappedByName.contains(moduleName)) { - auto& registerGroup = moduleInstance.registerGroupsMappedByName.at(moduleName); - - if (!registerGroup.moduleName.has_value() || registerGroup.moduleName.value() == moduleName) { - return registerGroup.offset.value_or(0); - } - } - - /* - * If we get here, that means we couldn't find the right register group by module name. This will happen - * if the register group name doesn't match the module name attribute ("name-in-module") against the - * register group node, in the TDF. - * - * As a final attempt, we'll brute force search all register groups in the module instance. - */ - for (const auto& [registerGroupName, registerGroup] : moduleInstance.registerGroupsMappedByName) { - if (registerGroup.moduleName.has_value() && registerGroup.moduleName.value() == moduleName) { - return registerGroup.offset.value_or(0); - } - } - } - } - - return 0; -} diff --git a/src/Targets/Microchip/AVR/AVR8/TargetDescription/TargetDescriptionFile.hpp b/src/Targets/Microchip/AVR/AVR8/TargetDescription/TargetDescriptionFile.hpp index 1c72a9d8..95e374d8 100644 --- a/src/Targets/Microchip/AVR/AVR8/TargetDescription/TargetDescriptionFile.hpp +++ b/src/Targets/Microchip/AVR/AVR8/TargetDescription/TargetDescriptionFile.hpp @@ -27,6 +27,87 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit::TargetDescription */ class TargetDescriptionFile: public Targets::TargetDescription::TargetDescriptionFile { + public: + /** + * Will resolve the target description file using the target description JSON mapping and a given target signature. + * + * @param targetSignatureHex + * @param targetName + */ + TargetDescriptionFile(const TargetSignature& targetSignature, std::optional targetName); + + /** + * Extends TDF initialisation to include the loading of physical interfaces for debugging AVR8 targets, among + * other things. + * + * @param xml + */ + void init(const QDomDocument& xml) override; + + /** + * Loads the AVR8 target description JSON mapping file. + * + * @return + */ + static QJsonObject getTargetDescriptionMapping(); + + /** + * Extracts the AVR8 target signature from the TDF. + * + * @return + */ + [[nodiscard]] TargetSignature getTargetSignature() const; + + /** + * Extracts the AVR8 target family from the TDF. + * + * @return + */ + [[nodiscard]] Family getFamily() const; + + /** + * Constructs an instance of TargetParameters, for the AVR8 target, with data from the TDF. + * + * @return + */ + [[nodiscard]] TargetParameters getTargetParameters() const; + + /** + * Returns a set of all supported physical interfaces for debugging. + * + * @return + */ + [[nodiscard]] const auto& getSupportedDebugPhysicalInterfaces() const { + return this->supportedDebugPhysicalInterfaces; + } + + /** + * Returns a mapping of all pad descriptors extracted from TDF, mapped by name. + * + * @return + */ + [[nodiscard]] const auto& getPadDescriptorsMappedByName() const { + return this->padDescriptorsByName; + } + + /** + * Returns a mapping of all target variants extracted from the TDF, mapped by ID. + * + * @return + */ + [[nodiscard]] const auto& getVariantsMappedById() const { + return this->targetVariantsById; + } + + /** + * Returns a mapping of all target register descriptors extracted from the TDF, by type. + * + * @return + */ + [[nodiscard]] const auto& getRegisterDescriptorsMappedByType() const { + return this->targetRegisterDescriptorsByType; + } + private: /**` * AVR8 target description files include the target family name. This method returns a mapping of part @@ -124,94 +205,5 @@ namespace Bloom::Targets::Microchip::Avr::Avr8Bit::TargetDescription * @param targetParameters */ virtual void loadUpdiTargetParameters(TargetParameters& targetParameters) const; - - /** - * Extracts the register address offset, for registers from a particular module. - * - * @param moduleName - * @return - */ - [[nodiscard]] virtual std::uint32_t getRegisterAddressOffsetByModuleName(const std::string& moduleName) const; - - public: - /** - * Will resolve the target description file using the target description JSON mapping and a given target signature. - * - * @param targetSignatureHex - * @param targetName - */ - TargetDescriptionFile(const TargetSignature& targetSignature, std::optional targetName); - - /** - * Extends TDF initialisation to include the loading of physical interfaces for debugging AVR8 targets, among - * other things. - * - * @param xml - */ - void init(const QDomDocument& xml) override; - - /** - * Loads the AVR8 target description JSON mapping file. - * - * @return - */ - static QJsonObject getTargetDescriptionMapping(); - - /** - * Extracts the AVR8 target signature from the TDF. - * - * @return - */ - [[nodiscard]] TargetSignature getTargetSignature() const; - - /** - * Extracts the AVR8 target family from the TDF. - * - * @return - */ - [[nodiscard]] Family getFamily() const; - - /** - * Constructs an instance of TargetParameters, for the AVR8 target, with data from the TDF. - * - * @return - */ - [[nodiscard]] TargetParameters getTargetParameters() const; - - /** - * Returns a set of all supported physical interfaces for debugging. - * - * @return - */ - [[nodiscard]] const auto& getSupportedDebugPhysicalInterfaces() const { - return this->supportedDebugPhysicalInterfaces; - } - - /** - * Returns a mapping of all pad descriptors extracted from TDF, mapped by name. - * - * @return - */ - [[nodiscard]] const auto& getPadDescriptorsMappedByName() const { - return this->padDescriptorsByName; - } - - /** - * Returns a mapping of all target variants extracted from the TDF, mapped by ID. - * - * @return - */ - [[nodiscard]] const auto& getVariantsMappedById() const { - return this->targetVariantsById; - } - - /** - * Returns a mapping of all target register descriptors extracted from the TDF, by type. - * - * @return - */ - [[nodiscard]] const auto& getRegisterDescriptorsMappedByType() const { - return this->targetRegisterDescriptorsByType; - } }; } diff --git a/src/Targets/Microchip/AVR/Target.hpp b/src/Targets/Microchip/AVR/Target.hpp index a3c060ec..263c1192 100644 --- a/src/Targets/Microchip/AVR/Target.hpp +++ b/src/Targets/Microchip/AVR/Target.hpp @@ -4,12 +4,20 @@ #include #include "../../Target.hpp" + #include "TargetSignature.hpp" namespace Bloom::Targets::Microchip::Avr { class Target: public ::Bloom::Targets::Target { + public: + explicit Target() = default; + + std::string getHumanReadableId() override { + return this->getId().toHex(); + } + protected: std::optional id; @@ -18,12 +26,5 @@ namespace Bloom::Targets::Microchip::Avr } virtual TargetSignature getId() = 0; - - public: - explicit Target() = default; - - std::string getHumanReadableId() override { - return this->getId().toHex(); - } }; } diff --git a/src/Targets/Target.hpp b/src/Targets/Target.hpp index eb3fe408..f41e34a5 100644 --- a/src/Targets/Target.hpp +++ b/src/Targets/Target.hpp @@ -29,18 +29,11 @@ namespace Bloom::Targets */ class Target { - protected: - /** - * Target related configuration provided by the user. This is passed in via the first stage of target - * configuration. See Target::preActivationConfigure() for more. - */ - TargetConfig config; - - bool activated = false; - public: explicit Target() = default; + virtual ~Target() = default; + bool isActivated() const { return this->activated; } @@ -300,6 +293,13 @@ namespace Bloom::Targets const TargetPinState& state ) = 0; - virtual ~Target() = default; + protected: + /** + * Target related configuration provided by the user. This is passed in via the first stage of target + * configuration. See Target::preActivationConfigure() for more. + */ + TargetConfig config; + + bool activated = false; }; } diff --git a/src/Targets/TargetDescription/TargetDescriptionFile.cpp b/src/Targets/TargetDescription/TargetDescriptionFile.cpp index 31f0332c..8de0e192 100644 --- a/src/Targets/TargetDescription/TargetDescriptionFile.cpp +++ b/src/Targets/TargetDescription/TargetDescriptionFile.cpp @@ -9,6 +9,10 @@ using namespace Bloom::Targets::TargetDescription; using namespace Bloom::Exceptions; +std::string TargetDescriptionFile::getTargetName() const { + return this->deviceElement.attributes().namedItem("name").nodeValue().toStdString(); +} + void TargetDescriptionFile::init(const QString& xmlFilePath) { auto file = QFile(xmlFilePath); if (!file.exists()) { @@ -45,10 +49,6 @@ void TargetDescriptionFile::init(const QDomDocument& xml) { this->loadInterfaces(); } -std::string TargetDescriptionFile::getTargetName() const { - return this->deviceElement.attributes().namedItem("name").nodeValue().toStdString(); -} - AddressSpace TargetDescriptionFile::generateAddressSpaceFromXml(const QDomElement& xmlElement) { if ( !xmlElement.hasAttribute("id") diff --git a/src/Targets/TargetDescription/TargetDescriptionFile.hpp b/src/Targets/TargetDescription/TargetDescriptionFile.hpp index f4afcd38..73de36f6 100644 --- a/src/Targets/TargetDescription/TargetDescriptionFile.hpp +++ b/src/Targets/TargetDescription/TargetDescriptionFile.hpp @@ -35,6 +35,80 @@ namespace Bloom::Targets::TargetDescription */ class TargetDescriptionFile { + public: + TargetDescriptionFile() = default; + + /** + * Will construct a TargetDescriptionFile instance from the XML of a target description file, the path to which + * is given via xmlFilePath. + * + * @param xmlFilePath + */ + explicit TargetDescriptionFile(const QString& xmlFilePath) { + this->init(xmlFilePath); + } + + /** + * Will construct a TargetDescriptionFile instance from pre-loaded XML. + * + * @param xml + */ + explicit TargetDescriptionFile(const QDomDocument& xml) { + this->init(xml); + } + + /** + * Extracts target name. + * + * @return + */ + [[nodiscard]] std::string getTargetName() const; + + /** + * Returns a mapping of all property groups, with the property group name being the key. + * + * @return + */ + [[nodiscard]] const std::map& getPropertyGroupsMappedByName() const { + return this->propertyGroupsMappedByName; + } + + /** + * Returns a mapping of all modules, with the module name being the key. + * + * @return + */ + [[nodiscard]] const std::map& getModulesMappedByName() const { + return this->modulesMappedByName; + } + + /** + * Returns a mapping of all peripheral modules, with the peripheral module name being the key. + * + * @return + */ + [[nodiscard]] const std::map& getPeripheralModulesMappedByName() const { + return this->peripheralModulesMappedByName; + } + + /** + * Returns all variants found in the TDF. + * + * @return + */ + [[nodiscard]] const std::vector& getVariants() const { + return this->variants; + } + + /** + * Returns a mapping of pinouts, with the pinout name being the key. + * + * @return + */ + [[nodiscard]] const std::map& getPinoutsMappedByName() const { + return this->pinoutsMappedByName; + } + protected: QDomDocument xml; QDomElement deviceElement; @@ -119,79 +193,5 @@ namespace Bloom::Targets::TargetDescription * Extracts all interfaces and loads them into this->interfacesByName */ void loadInterfaces(); - - public: - TargetDescriptionFile() = default; - - /** - * Will construct a TargetDescriptionFile instance from the XML of a target description file, the path to which - * is given via xmlFilePath. - * - * @param xmlFilePath - */ - explicit TargetDescriptionFile(const QString& xmlFilePath) { - this->init(xmlFilePath); - } - - /** - * Will construct a TargetDescriptionFile instance from pre-loaded XML. - * - * @param xml - */ - explicit TargetDescriptionFile(const QDomDocument& xml) { - this->init(xml); - } - - /** - * Extracts target name. - * - * @return - */ - [[nodiscard]] std::string getTargetName() const; - - /** - * Returns a mapping of all property groups, with the property group name being the key. - * - * @return - */ - [[nodiscard]] const std::map& getPropertyGroupsMappedByName() const { - return this->propertyGroupsMappedByName; - } - - /** - * Returns a mapping of all modules, with the module name being the key. - * - * @return - */ - [[nodiscard]] const std::map& getModulesMappedByName() const { - return this->modulesMappedByName; - } - - /** - * Returns a mapping of all peripheral modules, with the peripheral module name being the key. - * - * @return - */ - [[nodiscard]] const std::map& getPeripheralModulesMappedByName() const { - return this->peripheralModulesMappedByName; - } - - /** - * Returns all variants found in the TDF. - * - * @return - */ - [[nodiscard]] const std::vector& getVariants() const { - return this->variants; - } - - /** - * Returns a mapping of pinouts, with the pinout name being the key. - * - * @return - */ - [[nodiscard]] const std::map& getPinoutsMappedByName() const { - return this->pinoutsMappedByName; - } }; } diff --git a/src/Targets/TargetRegister.hpp b/src/Targets/TargetRegister.hpp index d587c391..a056a718 100644 --- a/src/Targets/TargetRegister.hpp +++ b/src/Targets/TargetRegister.hpp @@ -24,13 +24,6 @@ namespace Bloom::Targets struct TargetRegisterDescriptor { - friend std::hash; - - private: - mutable std::optional cachedHash; - - std::size_t getHash() const; - public: std::optional startAddress; std::uint32_t size = 0; @@ -63,6 +56,12 @@ namespace Bloom::Targets return this->getHash() < other.getHash(); } } + + private: + mutable std::optional cachedHash; + std::size_t getHash() const; + + friend std::hash; }; struct TargetRegister