2021-04-04 21:04:12 +01:00
|
|
|
#pragma once
|
|
|
|
|
|
|
|
|
|
#include <memory>
|
|
|
|
|
#include <map>
|
|
|
|
|
#include <string>
|
|
|
|
|
#include <functional>
|
|
|
|
|
#include <QJsonObject>
|
|
|
|
|
#include <QJsonArray>
|
|
|
|
|
|
|
|
|
|
#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
|
|
|
|
|
{
|
|
|
|
|
/**
|
|
|
|
|
* The TargetController possesses full control of the debugging target and the debug tool.
|
|
|
|
|
*
|
2021-04-08 20:39:53 +01:00
|
|
|
` * The TargetController runs on a dedicated thread. Its sole purpose is to handle communication to & from the
|
2021-04-04 21:04:12 +01:00
|
|
|
* 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;
|
|
|
|
|
|
2021-04-06 02:10:14 +01:00
|
|
|
/**
|
|
|
|
|
* The TargetController should be the sole owner of the target and debugTool. They are constructed and
|
|
|
|
|
* destroyed within the TargetController. Under no circumstance should ownership of these resources be
|
|
|
|
|
* transferred to any other component within Bloom.
|
|
|
|
|
*/
|
2021-04-04 21:04:12 +01:00
|
|
|
std::unique_ptr<Targets::Target> target = nullptr;
|
|
|
|
|
std::unique_ptr<DebugTool> debugTool = nullptr;
|
|
|
|
|
|
|
|
|
|
EventManager& eventManager;
|
|
|
|
|
EventListenerPointer eventListener = std::make_shared<EventListener>("TargetControllerEventListener");
|
|
|
|
|
|
2021-04-06 02:10:14 +01:00
|
|
|
/**
|
|
|
|
|
* We keep record of the last known execution state of the target. When the connected target reports a
|
|
|
|
|
* different state to what's stored in lastTargetState, a state change (TargetExecutionStopped/TargetExecutionResumed)
|
|
|
|
|
* event is emitted.
|
|
|
|
|
*/
|
2021-05-24 20:58:49 +01:00
|
|
|
Targets::TargetState lastTargetState = Targets::TargetState::UNKNOWN;
|
2021-04-06 02:10:14 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Obtaining a TargetDescriptor for the connected target can be quite expensive. We cache it here.
|
|
|
|
|
*/
|
2021-05-24 20:58:49 +01:00
|
|
|
std::optional<Targets::TargetDescriptor> cachedTargetDescriptor;
|
2021-04-04 21:04:12 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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.
|
|
|
|
|
*
|
|
|
|
|
* @return
|
|
|
|
|
*/
|
|
|
|
|
static auto getSupportedDebugTools() {
|
2021-05-24 20:58:49 +01:00
|
|
|
static auto mapping = std::map<std::string, std::function<std::unique_ptr<DebugTool>()>> {
|
2021-04-04 21:04:12 +01:00
|
|
|
{
|
|
|
|
|
"atmel-ice",
|
2021-04-08 20:39:53 +01:00
|
|
|
[]() {
|
2021-05-24 20:58:49 +01:00
|
|
|
return std::make_unique<DebugToolDrivers::AtmelIce>();
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"power-debugger",
|
2021-04-08 20:39:53 +01:00
|
|
|
[]() {
|
2021-05-24 20:58:49 +01:00
|
|
|
return std::make_unique<DebugToolDrivers::PowerDebugger>();
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
},
|
2021-04-07 23:30:30 +01:00
|
|
|
{
|
|
|
|
|
"snap",
|
2021-04-08 20:39:53 +01:00
|
|
|
[]() {
|
2021-05-24 20:58:49 +01:00
|
|
|
return std::make_unique<DebugToolDrivers::MplabSnap>();
|
2021-04-07 23:30:30 +01:00
|
|
|
}
|
|
|
|
|
},
|
2021-04-04 21:04:12 +01:00
|
|
|
};
|
2021-05-24 20:58:49 +01:00
|
|
|
|
|
|
|
|
return mapping;
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 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() {
|
2021-05-24 20:58:49 +01:00
|
|
|
static std::map<std::string, std::function<std::unique_ptr<Targets::Target>()>> mapping;
|
|
|
|
|
|
|
|
|
|
if (mapping.empty()) {
|
|
|
|
|
mapping = {
|
|
|
|
|
{
|
|
|
|
|
"avr8",
|
|
|
|
|
[]() {
|
|
|
|
|
return std::make_unique<Targets::Microchip::Avr::Avr8Bit::Avr8>();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// Include all targets from AVR8 part description files
|
|
|
|
|
auto avr8PdMapping =
|
|
|
|
|
Targets::Microchip::Avr::Avr8Bit::PartDescription::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();
|
|
|
|
|
auto targetSignatureHex = mapIt.key().toLower().toStdString();
|
|
|
|
|
|
|
|
|
|
if (!mapping.contains(targetName)) {
|
|
|
|
|
mapping.insert({
|
|
|
|
|
targetName,
|
|
|
|
|
[targetName, targetSignatureHex]() {
|
|
|
|
|
return std::make_unique<Targets::Microchip::Avr::Avr8Bit::Avr8>(
|
|
|
|
|
targetName,
|
|
|
|
|
Targets::Microchip::Avr::TargetSignature(targetSignatureHex)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return mapping;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setDebugTool(std::unique_ptr<DebugTool> debugTool) {
|
|
|
|
|
this->debugTool = std::move(debugTool);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setTarget(std::unique_ptr<Targets::Target> 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<Events::TargetControllerStateChanged>(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();
|
|
|
|
|
|
2021-04-06 02:10:14 +01:00
|
|
|
/**
|
|
|
|
|
* When the TargetController fails to handle an event, a TargetControllerErrorOccurred event is emitted, with
|
|
|
|
|
* a correlation ID matching the ID of the event that triggered the handler.
|
|
|
|
|
*
|
|
|
|
|
* @param correlationId
|
|
|
|
|
*/
|
2021-04-04 21:04:12 +01:00
|
|
|
void emitErrorEvent(int correlationId);
|
2021-04-09 20:33:24 +01:00
|
|
|
|
2021-04-04 21:04:12 +01:00
|
|
|
public:
|
2021-04-06 02:10:14 +01:00
|
|
|
TargetController(EventManager& eventManager): eventManager(eventManager) {};
|
2021-04-04 21:04:12 +01:00
|
|
|
|
|
|
|
|
void setApplicationConfig(const ApplicationConfig& applicationConfig) {
|
|
|
|
|
this->applicationConfig = applicationConfig;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void setEnvironmentConfig(const EnvironmentConfig& environmentConfig) {
|
|
|
|
|
this->environmentConfig = environmentConfig;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Entry point for the TargetController.
|
|
|
|
|
*/
|
|
|
|
|
void run();
|
|
|
|
|
|
2021-04-06 02:10:14 +01:00
|
|
|
/**
|
|
|
|
|
* Obtains a TargetDescriptor from the target and includes it in a TargetDescriptorExtracted event.
|
|
|
|
|
*
|
|
|
|
|
* @param event
|
|
|
|
|
*/
|
2021-05-24 20:58:49 +01:00
|
|
|
void onExtractTargetDescriptor(Events::EventPointer<Events::ExtractTargetDescriptor> event);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
|
|
|
|
/**
|
2021-04-06 02:10:14 +01:00
|
|
|
* Will attempt to stop execution on the target and emit a TargetExecutionStopped event.
|
2021-04-04 21:04:12 +01:00
|
|
|
*
|
2021-04-06 02:10:14 +01:00
|
|
|
* @param event
|
2021-04-04 21:04:12 +01:00
|
|
|
*/
|
2021-05-24 20:58:49 +01:00
|
|
|
void onStopTargetExecutionEvent(Events::EventPointer<Events::StopTargetExecution> event);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2021-04-06 02:10:14 +01:00
|
|
|
/**
|
|
|
|
|
* Will attempt to step execution on the target and emit a TargetExecutionResumed event.
|
|
|
|
|
*
|
|
|
|
|
* @param event
|
|
|
|
|
*/
|
2021-05-24 20:58:49 +01:00
|
|
|
void onStepTargetExecutionEvent(Events::EventPointer<Events::StepTargetExecution> event);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
|
|
|
|
/**
|
2021-04-06 02:10:14 +01:00
|
|
|
* Will attempt to resume execution on the target and emit a TargetExecutionResumed event.
|
|
|
|
|
*
|
|
|
|
|
* @param event
|
2021-04-04 21:04:12 +01:00
|
|
|
*/
|
2021-05-24 20:58:49 +01:00
|
|
|
void onResumeTargetExecutionEvent(Events::EventPointer<Events::ResumeTargetExecution> event);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
|
|
|
|
/**
|
2021-04-06 02:10:14 +01:00
|
|
|
* Invokes a shutdown.
|
|
|
|
|
*
|
|
|
|
|
* @param event
|
2021-04-04 21:04:12 +01:00
|
|
|
*/
|
2021-05-24 20:58:49 +01:00
|
|
|
void onShutdownTargetControllerEvent(Events::EventPointer<Events::ShutdownTargetController> event);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2021-04-06 02:10:14 +01:00
|
|
|
/**
|
|
|
|
|
* Will attempt to read the requested registers and emit a RegistersRetrievedFromTarget event.
|
|
|
|
|
*
|
|
|
|
|
* @param event
|
|
|
|
|
*/
|
2021-05-24 20:58:49 +01:00
|
|
|
void onReadRegistersEvent(Events::EventPointer<Events::RetrieveRegistersFromTarget> event);
|
2021-04-06 02:10:14 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Will attempt to write the specified register values and emit a RegistersWrittenToTarget event.
|
|
|
|
|
*
|
|
|
|
|
* @param event
|
|
|
|
|
*/
|
2021-05-24 20:58:49 +01:00
|
|
|
void onWriteRegistersEvent(Events::EventPointer<Events::WriteRegistersToTarget> event);
|
2021-04-06 02:10:14 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Will attempt to read memory from the target and include the data in a MemoryRetrievedFromTarget event.
|
|
|
|
|
*
|
|
|
|
|
* @param event
|
|
|
|
|
*/
|
2021-05-24 20:58:49 +01:00
|
|
|
void onReadMemoryEvent(Events::EventPointer<Events::RetrieveMemoryFromTarget> event);
|
2021-04-06 02:10:14 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Will attempt to write memory to the target. On success, a MemoryWrittenToTarget event is emitted.
|
|
|
|
|
*
|
|
|
|
|
* @param event
|
|
|
|
|
*/
|
2021-05-24 20:58:49 +01:00
|
|
|
void onWriteMemoryEvent(Events::EventPointer<Events::WriteMemoryToTarget> event);
|
2021-04-06 02:10:14 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Will attempt to set the specific breakpoint on the target. On success, the BreakpointSetOnTarget event will
|
|
|
|
|
* be emitted.
|
|
|
|
|
*
|
|
|
|
|
* @param event
|
|
|
|
|
*/
|
2021-05-24 20:58:49 +01:00
|
|
|
void onSetBreakpointEvent(Events::EventPointer<Events::SetBreakpointOnTarget> event);
|
2021-04-06 02:10:14 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Will attempt to remove a breakpoint at the specified address, on the target. On success, the
|
|
|
|
|
* BreakpointRemovedOnTarget event is emitted.
|
|
|
|
|
*
|
|
|
|
|
* @param event
|
|
|
|
|
*/
|
2021-05-24 20:58:49 +01:00
|
|
|
void onRemoveBreakpointEvent(Events::EventPointer<Events::RemoveBreakpointOnTarget> event);
|
2021-04-06 02:10:14 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Will hold the target stopped at it's current state.
|
|
|
|
|
*
|
|
|
|
|
* @param event
|
|
|
|
|
*/
|
2021-05-24 20:58:49 +01:00
|
|
|
void onDebugSessionStartedEvent(Events::EventPointer<Events::DebugSessionStarted> event);
|
2021-04-06 02:10:14 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Will simply kick off execution on the target.
|
|
|
|
|
*
|
|
|
|
|
* @param event
|
|
|
|
|
*/
|
2021-05-24 20:58:49 +01:00
|
|
|
void onDebugSessionFinishedEvent(Events::EventPointer<Events::DebugSessionFinished> event);
|
2021-04-06 02:10:14 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Will update the program counter value on the target. On success, a ProgramCounterSetOnTarget event is
|
|
|
|
|
* emitted.
|
|
|
|
|
*
|
|
|
|
|
* @param event
|
|
|
|
|
*/
|
2021-05-24 20:58:49 +01:00
|
|
|
void onSetProgramCounterEvent(Events::EventPointer<Events::SetProgramCounterOnTarget> event);
|
2021-04-06 02:10:14 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Will automatically fire a target state update event.
|
|
|
|
|
* @TODO: get rid of this - Insight should request this itself.
|
|
|
|
|
*
|
|
|
|
|
* @param event
|
|
|
|
|
*/
|
2021-05-24 20:58:49 +01:00
|
|
|
void onInsightStateChangedEvent(Events::EventPointer<Events::InsightStateChanged> event);
|
2021-04-06 02:10:14 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Will attempt to obtain the pin states from the target. Will emit a TargetPinStatesRetrieved event on success.
|
|
|
|
|
*
|
|
|
|
|
* @param event
|
|
|
|
|
*/
|
2021-05-24 20:58:49 +01:00
|
|
|
void onRetrieveTargetPinStatesEvent(Events::EventPointer<Events::RetrieveTargetPinStates> event);
|
2021-04-06 02:10:14 +01:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Will update a pin state for a particular pin. Will emit a TargetPinStatesRetrieved with the new pin
|
|
|
|
|
* state, on success.
|
|
|
|
|
*
|
|
|
|
|
* @param event
|
|
|
|
|
*/
|
2021-05-24 20:58:49 +01:00
|
|
|
void onSetPinStateEvent(Events::EventPointer<Events::SetTargetPinState> event);
|
2021-04-04 21:04:12 +01:00
|
|
|
};
|
|
|
|
|
}
|