#pragma once #include #include #include #include #include #include #include "src/Helpers/Thread.hpp" #include "src/Logger/Logger.hpp" #include "src/EventManager/EventListener.hpp" #include "src/DebugToolDrivers/DebugTools.hpp" #include "src/Targets/Target.hpp" #include "src/Targets/Targets.hpp" #include "src/EventManager/EventManager.hpp" #include "src/EventManager/Events/Events.hpp" namespace Bloom { using namespace Targets; using namespace DebugToolDrivers; using namespace Targets::Microchip::Avr; using Avr8Bit::Avr8; using Events::EventPointer; /** * The TargetController possesses full control of the debugging target and the debug tool. * ` * The TargetController runs on a dedicated thread. Its sole purpose is to handle communication to &from the * debug tool and target. * * The TargetController should be oblivious to any manufacture/device specific functionality. It should * only ever interface with the base Target and DebugTool classes. */ class TargetController: public Thread { private: ApplicationConfig applicationConfig; EnvironmentConfig environmentConfig; std::unique_ptr target = nullptr; std::unique_ptr debugTool = nullptr; EventManager& eventManager; EventListenerPointer eventListener = std::make_shared("TargetControllerEventListener"); TargetState lastTargetState = TargetState::UNKNOWN; std::optional cachedTargetDescriptor; /** * Constructs a mapping of supported debug tool names to lambdas. The lambdas should *only* instantiate * and return an instance to the derived DebugTool class. They should never attempt to establish * a connection to the device. * * Currently, the only debug tool we support is the Atmel-ICE. * * @return */ static auto getSupportedDebugTools() { return std::map()>> { { "atmel-ice", []() -> std::unique_ptr { return std::make_unique(); } }, { "power-debugger", []() -> std::unique_ptr { return std::make_unique(); } }, }; } /** * Constructs a mapping of supported target names to lambdas. The lambdas should instantiate and return an * instance to the appropriate Target class. * * @return */ static auto getSupportedTargets() { auto mapping = std::map()>> { { "avr8", []() -> std::unique_ptr { return std::make_unique(); } }, }; // Include all targets from AVR8 part description files auto avr8PdMapping = Avr8Bit::PartDescriptionFile::getPartDescriptionMapping(); for (auto mapIt = avr8PdMapping.begin(); mapIt != avr8PdMapping.end(); mapIt++) { // Each target signature maps to an array of targets, as numerous targets can possess the same signature. auto targets = mapIt.value().toArray(); for (auto targetIt = targets.begin(); targetIt != targets.end(); targetIt++) { auto targetName = targetIt->toObject().find("targetName").value().toString() .toLower().toStdString(); if (mapping.find(targetName) == mapping.end()) { mapping.insert({ targetName, [targetName]() -> std::unique_ptr { return std::make_unique(targetName); } }); } } } return mapping; } void setDebugTool(std::unique_ptr debugTool) { this->debugTool = std::move(debugTool); } void setTarget(std::unique_ptr target) { this->target = std::move(target); } Targets::Target* getTarget() { return this->target.get(); } DebugTool* getDebugTool() { return this->debugTool.get(); } /** * Updates the state of the TargetController and emits a state changed event. * * @param state * @param emitEvent */ void setStateAndEmitEvent(ThreadState state) { this->setState(state); this->eventManager.triggerEvent( std::make_shared(state) ); }; /** * 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 * are required for writing to files in /etc/udev). */ 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. * * Handles deactivating the target among other clean-up related things. */ void shutdown(); /** * Should fire any events queued on the target. */ void fireTargetEvents(); void emitErrorEvent(int correlationId); public: 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(); void onExtractTargetDescriptor(EventPointer event); /** * Callback for StopTargetExecution event. * * Will attempt to stop the target and emit a TargetExecutionStopped event. */ void onStopTargetExecutionEvent(EventPointer event); void onStepTargetExecutionEvent(EventPointer event); /** * Callback for ResumeTargetExecution event. */ void onResumeTargetExecutionEvent(EventPointer event); /** * Callback for ShutdownTargetController event. */ void onShutdownTargetControllerEvent(EventPointer event); void onReadRegistersEvent(EventPointer event); void onWriteRegistersEvent(EventPointer event); void onReadMemoryEvent(EventPointer event); void onWriteMemoryEvent(EventPointer event); void onSetBreakpointEvent(EventPointer event); void onRemoveBreakpointEvent(EventPointer event); void onDebugSessionStartedEvent(EventPointer event); void onDebugSessionFinishedEvent(EventPointer event); void onSetProgramCounterEvent(EventPointer event); void onInsightStateChangedEvent(EventPointer event); void onRetrieveTargetPinStatesEvent(EventPointer event); void onSetPinStateEvent(EventPointer event); }; }