2022-04-09 15:26:56 +01:00
|
|
|
#include "TargetControllerComponent.hpp"
|
2021-08-15 01:47:48 +01:00
|
|
|
|
2021-04-04 21:04:12 +01:00
|
|
|
#include <thread>
|
|
|
|
|
#include <filesystem>
|
|
|
|
|
#include <typeindex>
|
2021-09-11 20:39:31 +01:00
|
|
|
#include <algorithm>
|
2021-04-04 21:04:12 +01:00
|
|
|
|
|
|
|
|
#include "src/Application.hpp"
|
2021-05-30 19:05:18 +01:00
|
|
|
#include "src/Helpers/Paths.hpp"
|
2021-10-06 21:12:31 +01:00
|
|
|
#include "src/Logger/Logger.hpp"
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2021-08-15 01:47:48 +01:00
|
|
|
#include "src/TargetController/Exceptions/DeviceFailure.hpp"
|
|
|
|
|
#include "src/TargetController/Exceptions/TargetOperationFailure.hpp"
|
|
|
|
|
#include "src/Exceptions/TargetControllerStartupFailure.hpp"
|
|
|
|
|
#include "src/Exceptions/InvalidConfig.hpp"
|
|
|
|
|
|
2022-04-09 15:57:24 +01:00
|
|
|
namespace Bloom::TargetController
|
2022-02-05 15:32:08 +00:00
|
|
|
{
|
|
|
|
|
using namespace Bloom::Targets;
|
|
|
|
|
using namespace Bloom::Events;
|
|
|
|
|
using namespace Bloom::Exceptions;
|
|
|
|
|
|
2022-04-17 23:55:34 +01:00
|
|
|
using Commands::CommandIdType;
|
2022-05-01 19:23:58 +01:00
|
|
|
|
|
|
|
|
using Commands::Command;
|
2022-05-01 18:30:58 +01:00
|
|
|
using Commands::GetTargetDescriptor;
|
2022-04-28 21:02:45 +01:00
|
|
|
using Commands::GetTargetState;
|
2022-04-18 18:50:23 +01:00
|
|
|
using Commands::StopTargetExecution;
|
2022-04-19 21:12:59 +01:00
|
|
|
using Commands::ResumeTargetExecution;
|
2022-04-23 17:41:02 +01:00
|
|
|
using Commands::ResetTarget;
|
2022-04-24 16:41:40 +01:00
|
|
|
using Commands::ReadTargetRegisters;
|
2022-04-24 17:37:58 +01:00
|
|
|
using Commands::WriteTargetRegisters;
|
2022-04-24 18:55:19 +01:00
|
|
|
using Commands::ReadTargetMemory;
|
2022-04-30 01:30:57 +01:00
|
|
|
using Commands::WriteTargetMemory;
|
2022-04-29 22:12:09 +01:00
|
|
|
using Commands::StepTargetExecution;
|
2022-04-30 22:03:28 +01:00
|
|
|
using Commands::SetBreakpoint;
|
2022-04-30 22:45:46 +01:00
|
|
|
using Commands::RemoveBreakpoint;
|
2022-05-01 18:47:57 +01:00
|
|
|
using Commands::SetTargetProgramCounter;
|
2022-05-01 00:07:12 +01:00
|
|
|
using Commands::GetTargetPinStates;
|
2022-05-01 17:33:09 +01:00
|
|
|
using Commands::SetTargetPinState;
|
2022-05-01 18:01:01 +01:00
|
|
|
using Commands::GetTargetStackPointer;
|
2022-05-01 18:44:04 +01:00
|
|
|
using Commands::GetTargetProgramCounter;
|
2022-06-05 16:13:43 +01:00
|
|
|
using Commands::EnableProgrammingMode;
|
|
|
|
|
using Commands::DisableProgrammingMode;
|
2022-04-18 18:50:23 +01:00
|
|
|
|
2022-04-17 23:55:34 +01:00
|
|
|
using Responses::Response;
|
2022-04-24 16:41:40 +01:00
|
|
|
using Responses::TargetRegistersRead;
|
2022-04-24 18:55:19 +01:00
|
|
|
using Responses::TargetMemoryRead;
|
2022-05-01 00:07:12 +01:00
|
|
|
using Responses::TargetPinStates;
|
2022-05-01 18:01:01 +01:00
|
|
|
using Responses::TargetStackPointer;
|
2022-05-01 18:44:04 +01:00
|
|
|
using Responses::TargetProgramCounter;
|
2022-04-18 18:50:23 +01:00
|
|
|
|
2022-04-15 22:06:38 +01:00
|
|
|
TargetControllerComponent::TargetControllerComponent(
|
|
|
|
|
const ProjectConfig& projectConfig,
|
|
|
|
|
const EnvironmentConfig& environmentConfig
|
|
|
|
|
)
|
|
|
|
|
: projectConfig(projectConfig)
|
|
|
|
|
, environmentConfig(environmentConfig)
|
|
|
|
|
{}
|
|
|
|
|
|
2022-04-09 15:26:56 +01:00
|
|
|
void TargetControllerComponent::run() {
|
2022-02-05 15:32:08 +00:00
|
|
|
try {
|
|
|
|
|
this->startup();
|
|
|
|
|
|
|
|
|
|
this->setThreadStateAndEmitEvent(ThreadState::READY);
|
|
|
|
|
Logger::debug("TargetController ready and waiting for events.");
|
|
|
|
|
|
|
|
|
|
while (this->getThreadState() == ThreadState::READY) {
|
|
|
|
|
try {
|
|
|
|
|
if (this->state == TargetControllerState::ACTIVE) {
|
|
|
|
|
this->fireTargetEvents();
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-04-17 23:55:34 +01:00
|
|
|
TargetControllerComponent::notifier.waitForNotification(std::chrono::milliseconds(60));
|
|
|
|
|
|
|
|
|
|
this->processQueuedCommands();
|
|
|
|
|
this->eventListener->dispatchCurrentEvents();
|
2022-02-05 15:32:08 +00:00
|
|
|
|
|
|
|
|
} catch (const DeviceFailure& exception) {
|
|
|
|
|
/*
|
|
|
|
|
* Upon a device failure, we assume Bloom has lost control of the debug tool. This could be the
|
|
|
|
|
* result of the user disconnecting the debug tool, or issuing a soft reset. The soft reset could
|
|
|
|
|
* have been issued via another application, without the user's knowledge.
|
|
|
|
|
* See https://github.com/navnavnav/Bloom/issues/3 for more on that.
|
|
|
|
|
*
|
|
|
|
|
* The TC will go into a suspended state and the DebugServer should terminate any active debug
|
|
|
|
|
* session. When the user attempts to start another debug session, we will try to re-connect to the
|
|
|
|
|
* debug tool.
|
|
|
|
|
*/
|
|
|
|
|
Logger::error("Device failure detected - " + exception.getMessage());
|
|
|
|
|
Logger::error("Suspending TargetController");
|
|
|
|
|
this->suspend();
|
2021-05-30 16:52:32 +01:00
|
|
|
}
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
} catch (const TargetControllerStartupFailure& exception) {
|
|
|
|
|
Logger::error("TargetController failed to startup. See below for errors:");
|
|
|
|
|
Logger::error(exception.getMessage());
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
} catch (const Exception& exception) {
|
|
|
|
|
Logger::error("The TargetController encountered a fatal error. See below for errors:");
|
|
|
|
|
Logger::error(exception.getMessage());
|
|
|
|
|
|
|
|
|
|
} catch (const std::exception& exception) {
|
|
|
|
|
Logger::error("The TargetController encountered a fatal error. See below for errors:");
|
|
|
|
|
Logger::error(std::string(exception.what()));
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->shutdown();
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-04-27 21:27:59 +01:00
|
|
|
TargetControllerState TargetControllerComponent::getState() {
|
|
|
|
|
return TargetControllerComponent::state;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-17 23:55:34 +01:00
|
|
|
void TargetControllerComponent::registerCommand(std::unique_ptr<Command> command) {
|
|
|
|
|
auto commandQueueLock = TargetControllerComponent::commandQueue.acquireLock();
|
|
|
|
|
TargetControllerComponent::commandQueue.getValue().push(std::move(command));
|
|
|
|
|
TargetControllerComponent::notifier.notify();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<std::unique_ptr<Responses::Response>> TargetControllerComponent::waitForResponse(
|
|
|
|
|
CommandIdType commandId,
|
|
|
|
|
std::optional<std::chrono::milliseconds> timeout
|
|
|
|
|
) {
|
|
|
|
|
auto response = std::unique_ptr<Response>(nullptr);
|
|
|
|
|
|
|
|
|
|
const auto predicate = [commandId, &response] {
|
|
|
|
|
auto& responsesByCommandId = TargetControllerComponent::responsesByCommandId.getValue();
|
|
|
|
|
auto responseIt = responsesByCommandId.find(commandId);
|
|
|
|
|
|
|
|
|
|
if (responseIt != responsesByCommandId.end()) {
|
|
|
|
|
response.swap(responseIt->second);
|
|
|
|
|
responsesByCommandId.erase(responseIt);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
auto responsesByCommandIdLock = TargetControllerComponent::responsesByCommandId.acquireLock();
|
|
|
|
|
|
|
|
|
|
if (timeout.has_value()) {
|
|
|
|
|
TargetControllerComponent::responsesByCommandIdCv.wait_for(
|
|
|
|
|
responsesByCommandIdLock,
|
|
|
|
|
timeout.value(),
|
|
|
|
|
predicate
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
TargetControllerComponent::responsesByCommandIdCv.wait(responsesByCommandIdLock, predicate);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return (response != nullptr) ? std::optional(std::move(response)) : std::nullopt;
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-18 18:49:49 +01:00
|
|
|
void TargetControllerComponent::deregisterCommandHandler(Commands::CommandType commandType) {
|
|
|
|
|
this->commandHandlersByCommandType.erase(commandType);
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-09 15:26:56 +01:00
|
|
|
void TargetControllerComponent::startup() {
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setName("TC");
|
|
|
|
|
Logger::info("Starting TargetController");
|
|
|
|
|
this->setThreadState(ThreadState::STARTING);
|
|
|
|
|
this->blockAllSignalsOnCurrentThread();
|
2022-04-30 15:51:47 +01:00
|
|
|
this->eventListener->setInterruptEventNotifier(&TargetControllerComponent::notifier);
|
2022-03-20 17:37:36 +00:00
|
|
|
EventManager::registerListener(this->eventListener);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
// Install Bloom's udev rules if not already installed
|
2022-04-09 15:26:56 +01:00
|
|
|
TargetControllerComponent::checkUdevRules();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-08-14 17:39:35 +01:00
|
|
|
// Register command handlers
|
|
|
|
|
|
|
|
|
|
this->registerCommandHandler<GetTargetDescriptor>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleGetTargetDescriptor, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this->registerCommandHandler<GetTargetState>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleGetTargetState, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this->registerCommandHandler<StopTargetExecution>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleStopTargetExecution, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this->registerCommandHandler<ResumeTargetExecution>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleResumeTargetExecution, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this->registerCommandHandler<ResetTarget>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleResetTarget, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this->registerCommandHandler<ReadTargetRegisters>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleReadTargetRegisters, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this->registerCommandHandler<WriteTargetRegisters>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleWriteTargetRegisters, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this->registerCommandHandler<ReadTargetMemory>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleReadTargetMemory, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this->registerCommandHandler<WriteTargetMemory>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleWriteTargetMemory, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this->registerCommandHandler<StepTargetExecution>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleStepTargetExecution, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this->registerCommandHandler<SetBreakpoint>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleSetBreakpoint, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this->registerCommandHandler<RemoveBreakpoint>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleRemoveBreakpoint, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this->registerCommandHandler<SetTargetProgramCounter>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleSetProgramCounter, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this->registerCommandHandler<GetTargetPinStates>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleGetTargetPinStates, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this->registerCommandHandler<SetTargetPinState>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleSetTargetPinState, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this->registerCommandHandler<GetTargetStackPointer>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleGetTargetStackPointer, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this->registerCommandHandler<GetTargetProgramCounter>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleGetTargetProgramCounter, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this->registerCommandHandler<EnableProgrammingMode>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleEnableProgrammingMode, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this->registerCommandHandler<DisableProgrammingMode>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleDisableProgrammingMode, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
// Register event handlers
|
|
|
|
|
this->eventListener->registerCallbackForEventType<Events::ShutdownTargetController>(
|
2022-04-09 15:26:56 +01:00
|
|
|
std::bind(&TargetControllerComponent::onShutdownTargetControllerEvent, this, std::placeholders::_1)
|
2022-02-05 15:32:08 +00:00
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->eventListener->registerCallbackForEventType<Events::DebugSessionStarted>(
|
2022-04-09 15:26:56 +01:00
|
|
|
std::bind(&TargetControllerComponent::onDebugSessionStartedEvent, this, std::placeholders::_1)
|
2022-02-05 15:32:08 +00:00
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->resume();
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-04-17 23:55:34 +01:00
|
|
|
std::map<
|
|
|
|
|
std::string,
|
|
|
|
|
std::function<std::unique_ptr<DebugTool>()>
|
|
|
|
|
> TargetControllerComponent::getSupportedDebugTools() {
|
2022-05-01 17:33:39 +01:00
|
|
|
// The debug tool names in this mapping should always be lower-case.
|
2022-04-17 23:55:34 +01:00
|
|
|
return std::map<std::string, std::function<std::unique_ptr<DebugTool>()>> {
|
|
|
|
|
{
|
|
|
|
|
"atmel-ice",
|
|
|
|
|
[] {
|
|
|
|
|
return std::make_unique<DebugToolDrivers::AtmelIce>();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"power-debugger",
|
|
|
|
|
[] {
|
|
|
|
|
return std::make_unique<DebugToolDrivers::PowerDebugger>();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"snap",
|
|
|
|
|
[] {
|
|
|
|
|
return std::make_unique<DebugToolDrivers::MplabSnap>();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"pickit-4",
|
|
|
|
|
[] {
|
|
|
|
|
return std::make_unique<DebugToolDrivers::MplabPickit4>();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"xplained-pro",
|
|
|
|
|
[] {
|
|
|
|
|
return std::make_unique<DebugToolDrivers::XplainedPro>();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"xplained-mini",
|
|
|
|
|
[] {
|
|
|
|
|
return std::make_unique<DebugToolDrivers::XplainedMini>();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"xplained-nano",
|
|
|
|
|
[] {
|
|
|
|
|
return std::make_unique<DebugToolDrivers::XplainedNano>();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"curiosity-nano",
|
|
|
|
|
[] {
|
|
|
|
|
return std::make_unique<DebugToolDrivers::CuriosityNano>();
|
|
|
|
|
}
|
|
|
|
|
},
|
2022-05-02 22:51:21 +01:00
|
|
|
{
|
|
|
|
|
"jtagice3",
|
|
|
|
|
[] {
|
|
|
|
|
return std::make_unique<DebugToolDrivers::JtagIce3>();
|
|
|
|
|
}
|
|
|
|
|
},
|
2022-04-17 23:55:34 +01:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::map<
|
|
|
|
|
std::string,
|
|
|
|
|
std::function<std::unique_ptr<Targets::Target>()>
|
|
|
|
|
> TargetControllerComponent::getSupportedTargets() {
|
|
|
|
|
using Avr8TargetDescriptionFile = Targets::Microchip::Avr::Avr8Bit::TargetDescription::TargetDescriptionFile;
|
|
|
|
|
|
|
|
|
|
auto mapping = std::map<std::string, std::function<std::unique_ptr<Targets::Target>()>>({
|
|
|
|
|
{
|
|
|
|
|
"avr8",
|
|
|
|
|
[] {
|
|
|
|
|
return std::make_unique<Targets::Microchip::Avr::Avr8Bit::Avr8>();
|
|
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Include all targets from AVR8 target description files
|
2022-06-18 16:02:01 +01:00
|
|
|
const auto avr8PdMapping = Avr8TargetDescriptionFile::getTargetDescriptionMapping();
|
2022-04-17 23:55:34 +01:00
|
|
|
|
|
|
|
|
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)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return mapping;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TargetControllerComponent::processQueuedCommands() {
|
|
|
|
|
auto commands = std::queue<std::unique_ptr<Command>>();
|
|
|
|
|
|
|
|
|
|
{
|
2022-06-18 16:02:01 +01:00
|
|
|
const auto queueLock = TargetControllerComponent::commandQueue.acquireLock();
|
2022-04-17 23:55:34 +01:00
|
|
|
commands.swap(TargetControllerComponent::commandQueue.getValue());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
while (!commands.empty()) {
|
|
|
|
|
const auto command = std::move(commands.front());
|
|
|
|
|
commands.pop();
|
|
|
|
|
|
|
|
|
|
const auto commandId = command->id;
|
|
|
|
|
const auto commandType = command->getType();
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
if (!this->commandHandlersByCommandType.contains(commandType)) {
|
|
|
|
|
throw Exception("No handler registered for this command.");
|
|
|
|
|
}
|
|
|
|
|
|
2022-08-14 17:39:35 +01:00
|
|
|
if (this->state != TargetControllerState::ACTIVE && command->requiresActiveState()) {
|
|
|
|
|
throw Exception("Command rejected - TargetController not in active state.");
|
2022-04-29 22:06:05 +01:00
|
|
|
}
|
|
|
|
|
|
2022-08-14 17:39:35 +01:00
|
|
|
if (this->state == TargetControllerState::ACTIVE) {
|
|
|
|
|
if (command->requiresStoppedTargetState() && this->lastTargetState != TargetState::STOPPED) {
|
|
|
|
|
throw Exception("Command rejected - command requires target execution to be stopped.");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (this->target->programmingModeEnabled() && command->requiresDebugMode()) {
|
|
|
|
|
throw Exception(
|
|
|
|
|
"Command rejected - command cannot be serviced whilst the target is in programming mode."
|
|
|
|
|
);
|
|
|
|
|
}
|
2022-06-05 16:13:43 +01:00
|
|
|
}
|
|
|
|
|
|
2022-04-17 23:55:34 +01:00
|
|
|
this->registerCommandResponse(
|
|
|
|
|
commandId,
|
|
|
|
|
this->commandHandlersByCommandType.at(commandType)(*(command.get()))
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
} catch (const Exception& exception) {
|
|
|
|
|
this->registerCommandResponse(
|
|
|
|
|
commandId,
|
|
|
|
|
std::make_unique<Responses::Error>(exception.getMessage())
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TargetControllerComponent::registerCommandResponse(
|
|
|
|
|
CommandIdType commandId,
|
|
|
|
|
std::unique_ptr<Response> response
|
|
|
|
|
) {
|
2022-06-18 16:02:01 +01:00
|
|
|
const auto responseMappingLock = TargetControllerComponent::responsesByCommandId.acquireLock();
|
2022-04-17 23:55:34 +01:00
|
|
|
TargetControllerComponent::responsesByCommandId.getValue().insert(
|
|
|
|
|
std::pair(commandId, std::move(response))
|
|
|
|
|
);
|
|
|
|
|
TargetControllerComponent::responsesByCommandIdCv.notify_all();
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-09 15:26:56 +01:00
|
|
|
void TargetControllerComponent::checkUdevRules() {
|
2022-02-05 15:32:08 +00:00
|
|
|
auto bloomRulesPath = std::string("/etc/udev/rules.d/99-bloom.rules");
|
|
|
|
|
auto latestBloomRulesPath = Paths::resourcesDirPath() + "/UDevRules/99-bloom.rules";
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!std::filesystem::exists(bloomRulesPath)) {
|
|
|
|
|
Logger::warning("Bloom udev rules missing - attempting installation");
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
// We can only install them if we're running as root
|
|
|
|
|
if (!Application::isRunningAsRoot()) {
|
|
|
|
|
Logger::error("Bloom udev rules missing - cannot install udev rules without root privileges.\n"
|
|
|
|
|
"Running Bloom once with root privileges will allow it to automatically install the udev rules. "
|
|
|
|
|
"Alternatively, instructions on manually installing the udev rules can be found "
|
|
|
|
|
"here: " + Paths::homeDomainName() + "/docs/getting-started\nBloom may fail to connect to some "
|
|
|
|
|
"debug tools until this is resolved.");
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!std::filesystem::exists(latestBloomRulesPath)) {
|
|
|
|
|
// This shouldn't happen, but it can if someone has been messing with the installation files
|
|
|
|
|
Logger::error(
|
|
|
|
|
"Unable to install Bloom udev rules - \"" + latestBloomRulesPath + "\" does not exist."
|
|
|
|
|
);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::filesystem::copy(latestBloomRulesPath, bloomRulesPath);
|
|
|
|
|
Logger::warning("Bloom udev rules installed - a reconnect of the debug tool may be required "
|
|
|
|
|
"before the new udev rules come into effect.");
|
2021-05-30 16:52:32 +01:00
|
|
|
}
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-05-30 16:52:32 +01:00
|
|
|
|
2022-04-09 15:26:56 +01:00
|
|
|
void TargetControllerComponent::shutdown() {
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->getThreadState() == ThreadState::STOPPED) {
|
2021-05-30 16:52:32 +01:00
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
try {
|
|
|
|
|
Logger::info("Shutting down TargetController");
|
2022-03-20 17:37:36 +00:00
|
|
|
EventManager::deregisterListener(this->eventListener->getId());
|
2022-02-05 15:32:08 +00:00
|
|
|
this->releaseHardware();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
} catch (const std::exception& exception) {
|
|
|
|
|
this->target.reset();
|
|
|
|
|
this->debugTool.reset();
|
|
|
|
|
Logger::error(
|
|
|
|
|
"Failed to properly shutdown TargetController. Error: " + std::string(exception.what())
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->setThreadStateAndEmitEvent(ThreadState::STOPPED);
|
2021-05-30 16:52:32 +01:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-04-09 15:26:56 +01:00
|
|
|
void TargetControllerComponent::suspend() {
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->getThreadState() != ThreadState::READY) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::debug("Suspending TargetController");
|
2021-05-30 16:52:32 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
try {
|
|
|
|
|
this->releaseHardware();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
} catch (const std::exception& exception) {
|
|
|
|
|
Logger::error("Failed to release connected debug tool and target resources. Error: "
|
|
|
|
|
+ std::string(exception.what()));
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->eventListener->deregisterCallbacksForEventType<Events::DebugSessionFinished>();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->lastTargetState = TargetState::UNKNOWN;
|
|
|
|
|
this->cachedTargetDescriptor = std::nullopt;
|
|
|
|
|
this->registerDescriptorsByMemoryType.clear();
|
|
|
|
|
this->registerAddressRangeByMemoryType.clear();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-04-27 21:27:59 +01:00
|
|
|
TargetControllerComponent::state = TargetControllerState::SUSPENDED;
|
|
|
|
|
EventManager::triggerEvent(std::make_shared<TargetControllerStateChanged>(TargetControllerComponent::state));
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::debug("TargetController suspended");
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-04-09 15:26:56 +01:00
|
|
|
void TargetControllerComponent::resume() {
|
2022-02-05 15:32:08 +00:00
|
|
|
this->acquireHardware();
|
|
|
|
|
this->loadRegisterDescriptors();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->eventListener->registerCallbackForEventType<Events::DebugSessionFinished>(
|
2022-04-09 15:26:56 +01:00
|
|
|
std::bind(&TargetControllerComponent::onDebugSessionFinishedEvent, this, std::placeholders::_1)
|
2022-02-05 15:32:08 +00:00
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-04-27 21:27:59 +01:00
|
|
|
TargetControllerComponent::state = TargetControllerState::ACTIVE;
|
2022-03-20 17:37:36 +00:00
|
|
|
EventManager::triggerEvent(
|
2022-04-27 21:27:59 +01:00
|
|
|
std::make_shared<TargetControllerStateChanged>(TargetControllerComponent::state)
|
2022-02-05 15:32:08 +00:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
if (this->target->getState() != TargetState::RUNNING) {
|
|
|
|
|
this->target->run();
|
2022-04-30 15:52:59 +01:00
|
|
|
this->lastTargetState = TargetState::RUNNING;
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-04-09 15:26:56 +01:00
|
|
|
void TargetControllerComponent::acquireHardware() {
|
2022-02-05 15:32:08 +00:00
|
|
|
auto debugToolName = this->environmentConfig.debugToolConfig.name;
|
|
|
|
|
auto targetName = this->environmentConfig.targetConfig.name;
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-04-17 23:55:34 +01:00
|
|
|
static auto supportedDebugTools = this->getSupportedDebugTools();
|
|
|
|
|
static auto supportedTargets = this->getSupportedTargets();
|
2021-05-30 16:52:32 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!supportedDebugTools.contains(debugToolName)) {
|
|
|
|
|
throw Exceptions::InvalidConfig(
|
|
|
|
|
"Debug tool name (\"" + debugToolName + "\") not recognised. Please check your configuration!"
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-05-30 16:52:32 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!supportedTargets.contains(targetName)) {
|
|
|
|
|
throw Exceptions::InvalidConfig(
|
|
|
|
|
"Target name (\"" + targetName + "\") not recognised. Please check your configuration!"
|
|
|
|
|
);
|
|
|
|
|
}
|
2021-05-30 16:52:32 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
// Initiate debug tool and target
|
|
|
|
|
this->debugTool = supportedDebugTools.at(debugToolName)();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::info("Connecting to debug tool");
|
|
|
|
|
this->debugTool->init();
|
2021-05-30 16:52:32 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::info("Debug tool connected");
|
|
|
|
|
Logger::info("Debug tool name: " + this->debugTool->getName());
|
|
|
|
|
Logger::info("Debug tool serial: " + this->debugTool->getSerialNumber());
|
2021-05-30 16:52:32 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->target = supportedTargets.at(targetName)();
|
2021-05-30 16:52:32 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!this->target->isDebugToolSupported(this->debugTool.get())) {
|
|
|
|
|
throw Exceptions::InvalidConfig(
|
|
|
|
|
"Debug tool (\"" + this->debugTool->getName() + "\") not supported " +
|
|
|
|
|
"by target (\"" + this->target->getName() + "\")."
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
2021-04-12 19:43:42 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->target->setDebugTool(this->debugTool.get());
|
|
|
|
|
this->target->preActivationConfigure(this->environmentConfig.targetConfig);
|
2021-05-30 16:52:32 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::info("Activating target");
|
|
|
|
|
this->target->activate();
|
|
|
|
|
Logger::info("Target activated");
|
|
|
|
|
this->target->postActivationConfigure();
|
2021-05-30 16:52:32 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
while (this->target->supportsPromotion()) {
|
|
|
|
|
auto promotedTarget = this->target->promote();
|
2021-05-30 16:52:32 +01:00
|
|
|
|
2022-06-18 16:02:01 +01:00
|
|
|
if (
|
|
|
|
|
promotedTarget == nullptr
|
2022-02-05 15:32:08 +00:00
|
|
|
|| std::type_index(typeid(*promotedTarget)) == std::type_index(typeid(*this->target))
|
|
|
|
|
) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->target = std::move(promotedTarget);
|
|
|
|
|
this->target->postPromotionConfigure();
|
2021-05-30 16:52:32 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::info("Target ID: " + this->target->getHumanReadableId());
|
|
|
|
|
Logger::info("Target name: " + this->target->getName());
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-04-09 15:26:56 +01:00
|
|
|
void TargetControllerComponent::releaseHardware() {
|
2022-03-17 00:00:40 +00:00
|
|
|
/*
|
|
|
|
|
* Transferring ownership of this->debugTool and this->target to this function block means if an exception is
|
|
|
|
|
* thrown, the objects will still be destroyed.
|
|
|
|
|
*/
|
|
|
|
|
auto debugTool = std::move(this->debugTool);
|
|
|
|
|
auto target = std::move(this->target);
|
2022-02-05 15:32:08 +00:00
|
|
|
|
|
|
|
|
if (debugTool != nullptr && debugTool->isInitialised()) {
|
|
|
|
|
if (target != nullptr) {
|
|
|
|
|
/*
|
|
|
|
|
* We call deactivate() without checking if the target is activated. This will address any cases
|
|
|
|
|
* where a target is only partially activated (where the call to activate() failed).
|
|
|
|
|
*/
|
|
|
|
|
Logger::info("Deactivating target");
|
|
|
|
|
target->deactivate();
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::info("Closing debug tool");
|
|
|
|
|
debugTool->close();
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-04-09 15:26:56 +01:00
|
|
|
void TargetControllerComponent::loadRegisterDescriptors() {
|
2022-02-05 15:32:08 +00:00
|
|
|
auto& targetDescriptor = this->getTargetDescriptor();
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
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);
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!this->registerAddressRangeByMemoryType.contains(registerDescriptor.memoryType)) {
|
|
|
|
|
auto addressRange = TargetMemoryAddressRange();
|
2021-10-06 21:12:31 +01:00
|
|
|
addressRange.startAddress = startAddress;
|
|
|
|
|
addressRange.endAddress = endAddress;
|
2022-02-05 15:32:08 +00:00
|
|
|
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;
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->registerDescriptorsByMemoryType[registerDescriptor.memoryType].insert(registerDescriptor);
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-09 15:26:56 +01:00
|
|
|
TargetRegisterDescriptors TargetControllerComponent::getRegisterDescriptorsWithinAddressRange(
|
2022-02-05 15:32:08 +00:00
|
|
|
std::uint32_t startAddress,
|
|
|
|
|
std::uint32_t endAddress,
|
|
|
|
|
Targets::TargetMemoryType memoryType
|
2021-10-06 21:12:31 +01:00
|
|
|
) {
|
2022-02-05 15:32:08 +00:00
|
|
|
auto output = TargetRegisterDescriptors();
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->registerAddressRangeByMemoryType.contains(memoryType)
|
|
|
|
|
&& this->registerDescriptorsByMemoryType.contains(memoryType)
|
2021-10-06 21:12:31 +01:00
|
|
|
) {
|
2022-02-05 15:32:08 +00:00
|
|
|
auto& registersAddressRange = this->registerAddressRangeByMemoryType.at(memoryType);
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (
|
|
|
|
|
(startAddress <= registersAddressRange.startAddress && endAddress >= registersAddressRange.startAddress)
|
|
|
|
|
|| (startAddress <= registersAddressRange.endAddress && endAddress >= registersAddressRange.startAddress)
|
|
|
|
|
) {
|
|
|
|
|
auto& registerDescriptors = this->registerDescriptorsByMemoryType.at(memoryType);
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
for (const auto& registerDescriptor : registerDescriptors) {
|
|
|
|
|
if (!registerDescriptor.startAddress.has_value() || registerDescriptor.size < 1) {
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto registerStartAddress = registerDescriptor.startAddress.value();
|
|
|
|
|
auto registerEndAddress = registerStartAddress + registerDescriptor.size;
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (
|
|
|
|
|
(startAddress <= registerStartAddress && endAddress >= registerStartAddress)
|
|
|
|
|
|| (startAddress <= registerEndAddress && endAddress >= registerStartAddress)
|
|
|
|
|
) {
|
|
|
|
|
output.insert(registerDescriptor);
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
return output;
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2022-04-09 15:26:56 +01:00
|
|
|
void TargetControllerComponent::fireTargetEvents() {
|
2022-02-05 15:32:08 +00:00
|
|
|
auto newTargetState = this->target->getState();
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (newTargetState != this->lastTargetState) {
|
|
|
|
|
this->lastTargetState = newTargetState;
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (newTargetState == TargetState::STOPPED) {
|
|
|
|
|
Logger::debug("Target state changed - STOPPED");
|
2022-03-20 17:37:36 +00:00
|
|
|
EventManager::triggerEvent(std::make_shared<TargetExecutionStopped>(
|
2022-02-05 15:32:08 +00:00
|
|
|
this->target->getProgramCounter(),
|
|
|
|
|
TargetBreakCause::UNKNOWN
|
|
|
|
|
));
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (newTargetState == TargetState::RUNNING) {
|
|
|
|
|
Logger::debug("Target state changed - RUNNING");
|
2022-03-20 17:37:36 +00:00
|
|
|
EventManager::triggerEvent(std::make_shared<TargetExecutionResumed>());
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-23 17:41:02 +01:00
|
|
|
void TargetControllerComponent::resetTarget() {
|
2022-04-08 22:14:01 +01:00
|
|
|
this->target->reset();
|
|
|
|
|
|
2022-04-23 17:41:02 +01:00
|
|
|
EventManager::triggerEvent(std::make_shared<Events::TargetReset>());
|
2022-04-08 22:14:01 +01:00
|
|
|
}
|
|
|
|
|
|
2022-06-05 16:13:43 +01:00
|
|
|
void TargetControllerComponent::enableProgrammingMode() {
|
2022-06-05 21:04:47 +01:00
|
|
|
Logger::debug("Enabling programming mode");
|
2022-06-05 16:13:43 +01:00
|
|
|
this->target->enableProgrammingMode();
|
2022-06-05 21:04:47 +01:00
|
|
|
Logger::warning("Programming mode enabled");
|
2022-06-05 16:13:43 +01:00
|
|
|
|
|
|
|
|
EventManager::triggerEvent(std::make_shared<Events::ProgrammingModeEnabled>());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TargetControllerComponent::disableProgrammingMode() {
|
2022-06-05 21:04:47 +01:00
|
|
|
Logger::debug("Disabling programming mode");
|
2022-06-05 16:13:43 +01:00
|
|
|
this->target->disableProgrammingMode();
|
2022-06-05 21:04:47 +01:00
|
|
|
Logger::info("Programming mode disabled");
|
2022-06-05 16:13:43 +01:00
|
|
|
|
|
|
|
|
EventManager::triggerEvent(std::make_shared<Events::ProgrammingModeDisabled>());
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-09 15:26:56 +01:00
|
|
|
Targets::TargetDescriptor& TargetControllerComponent::getTargetDescriptor() {
|
2022-02-05 15:32:08 +00:00
|
|
|
if (!this->cachedTargetDescriptor.has_value()) {
|
|
|
|
|
this->cachedTargetDescriptor = this->target->getDescriptor();
|
|
|
|
|
}
|
2021-05-30 16:52:32 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
return this->cachedTargetDescriptor.value();
|
2021-05-30 16:52:32 +01:00
|
|
|
}
|
|
|
|
|
|
2022-04-09 15:26:56 +01:00
|
|
|
void TargetControllerComponent::onShutdownTargetControllerEvent(const Events::ShutdownTargetController&) {
|
2022-02-05 15:32:08 +00:00
|
|
|
this->shutdown();
|
2021-05-30 16:52:32 +01:00
|
|
|
}
|
|
|
|
|
|
2022-04-09 15:26:56 +01:00
|
|
|
void TargetControllerComponent::onDebugSessionStartedEvent(const Events::DebugSessionStarted&) {
|
2022-04-27 21:27:59 +01:00
|
|
|
if (TargetControllerComponent::state == TargetControllerState::SUSPENDED) {
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::debug("Waking TargetController");
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
this->resume();
|
|
|
|
|
this->fireTargetEvents();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-09 15:26:56 +01:00
|
|
|
void TargetControllerComponent::onDebugSessionFinishedEvent(const DebugSessionFinished&) {
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->target->getState() != TargetState::RUNNING) {
|
|
|
|
|
this->target->run();
|
|
|
|
|
this->fireTargetEvents();
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->environmentConfig.debugToolConfig.releasePostDebugSession) {
|
|
|
|
|
this->suspend();
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-05-01 18:30:58 +01:00
|
|
|
std::unique_ptr<Responses::TargetDescriptor> TargetControllerComponent::handleGetTargetDescriptor(
|
|
|
|
|
GetTargetDescriptor& command
|
|
|
|
|
) {
|
|
|
|
|
return std::make_unique<Responses::TargetDescriptor>(this->getTargetDescriptor());
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-28 21:02:45 +01:00
|
|
|
std::unique_ptr<Responses::TargetState> TargetControllerComponent::handleGetTargetState(GetTargetState& command) {
|
|
|
|
|
return std::make_unique<Responses::TargetState>(this->target->getState());
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-18 18:50:23 +01:00
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleStopTargetExecution(StopTargetExecution& command) {
|
2022-02-05 15:32:08 +00:00
|
|
|
if (this->target->getState() != TargetState::STOPPED) {
|
|
|
|
|
this->target->stop();
|
|
|
|
|
this->lastTargetState = TargetState::STOPPED;
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-04-18 18:50:23 +01:00
|
|
|
EventManager::triggerEvent(std::make_shared<Events::TargetExecutionStopped>(
|
2022-02-05 15:32:08 +00:00
|
|
|
this->target->getProgramCounter(),
|
|
|
|
|
TargetBreakCause::UNKNOWN
|
2022-04-18 18:50:23 +01:00
|
|
|
));
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-04-18 18:50:23 +01:00
|
|
|
return std::make_unique<Response>();
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-04-24 16:41:40 +01:00
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleResumeTargetExecution(
|
2022-04-19 21:12:59 +01:00
|
|
|
ResumeTargetExecution& command
|
|
|
|
|
) {
|
|
|
|
|
if (this->target->getState() != TargetState::RUNNING) {
|
|
|
|
|
if (command.fromProgramCounter.has_value()) {
|
|
|
|
|
this->target->setProgramCounter(command.fromProgramCounter.value());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->target->run();
|
|
|
|
|
this->lastTargetState = TargetState::RUNNING;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventManager::triggerEvent(std::make_shared<Events::TargetExecutionResumed>());
|
|
|
|
|
|
|
|
|
|
return std::make_unique<Response>();
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-24 16:41:40 +01:00
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleResetTarget(ResetTarget& command) {
|
2022-04-23 17:41:02 +01:00
|
|
|
this->resetTarget();
|
|
|
|
|
return std::make_unique<Response>();
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-24 16:41:40 +01:00
|
|
|
std::unique_ptr<TargetRegistersRead> TargetControllerComponent::handleReadTargetRegisters(
|
|
|
|
|
ReadTargetRegisters& command
|
|
|
|
|
) {
|
|
|
|
|
return std::make_unique<TargetRegistersRead>(this->target->readRegisters(command.descriptors));
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-24 17:37:58 +01:00
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleWriteTargetRegisters(WriteTargetRegisters& command) {
|
|
|
|
|
this->target->writeRegisters(command.registers);
|
|
|
|
|
|
|
|
|
|
auto registersWrittenEvent = std::make_shared<Events::RegistersWrittenToTarget>();
|
|
|
|
|
registersWrittenEvent->registers = command.registers;
|
|
|
|
|
|
|
|
|
|
EventManager::triggerEvent(registersWrittenEvent);
|
|
|
|
|
|
|
|
|
|
return std::make_unique<Response>();
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-24 18:55:19 +01:00
|
|
|
std::unique_ptr<TargetMemoryRead> TargetControllerComponent::handleReadTargetMemory(ReadTargetMemory& command) {
|
|
|
|
|
return std::make_unique<TargetMemoryRead>(this->target->readMemory(
|
|
|
|
|
command.memoryType,
|
|
|
|
|
command.startAddress,
|
|
|
|
|
command.bytes,
|
|
|
|
|
command.excludedAddressRanges
|
|
|
|
|
));
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-30 01:30:57 +01:00
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleWriteTargetMemory(WriteTargetMemory& command) {
|
|
|
|
|
const auto& buffer = command.buffer;
|
|
|
|
|
const auto bufferSize = command.buffer.size();
|
|
|
|
|
const auto bufferStartAddress = command.startAddress;
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-06-05 16:13:43 +01:00
|
|
|
const auto& targetDescriptor = this->getTargetDescriptor();
|
|
|
|
|
|
|
|
|
|
if (command.memoryType == targetDescriptor.programMemoryType && !this->target->programmingModeEnabled()) {
|
|
|
|
|
throw Exception("Cannot write to program memory - programming mode not enabled.");
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-30 01:30:57 +01:00
|
|
|
this->target->writeMemory(command.memoryType, bufferStartAddress, buffer);
|
2022-04-30 01:37:00 +01:00
|
|
|
EventManager::triggerEvent(
|
|
|
|
|
std::make_shared<Events::MemoryWrittenToTarget>(command.memoryType, bufferStartAddress, bufferSize)
|
|
|
|
|
);
|
2021-09-11 20:39:31 +01:00
|
|
|
|
2022-04-30 01:30:57 +01:00
|
|
|
if (
|
|
|
|
|
EventManager::isEventTypeListenedFor(Events::RegistersWrittenToTarget::type)
|
2022-06-05 16:13:43 +01:00
|
|
|
&& command.memoryType == targetDescriptor.programMemoryType
|
2022-04-30 01:30:57 +01:00
|
|
|
&& this->registerDescriptorsByMemoryType.contains(command.memoryType)
|
|
|
|
|
) {
|
|
|
|
|
/*
|
|
|
|
|
* The memory type we just wrote to contains some number of registers - if we've written to any address
|
|
|
|
|
* that is known to store the value of a register, trigger a RegistersWrittenToTarget event
|
|
|
|
|
*/
|
|
|
|
|
const auto bufferEndAddress = static_cast<std::uint32_t>(bufferStartAddress + (bufferSize - 1));
|
|
|
|
|
auto registerDescriptors = this->getRegisterDescriptorsWithinAddressRange(
|
|
|
|
|
bufferStartAddress,
|
|
|
|
|
bufferEndAddress,
|
|
|
|
|
command.memoryType
|
|
|
|
|
);
|
2021-09-12 23:25:34 +01:00
|
|
|
|
2022-04-30 01:30:57 +01:00
|
|
|
if (!registerDescriptors.empty()) {
|
|
|
|
|
auto registersWrittenEvent = std::make_shared<Events::RegistersWrittenToTarget>();
|
2021-09-12 23:25:34 +01:00
|
|
|
|
2022-04-30 01:30:57 +01:00
|
|
|
for (const auto& registerDescriptor : registerDescriptors) {
|
|
|
|
|
const auto registerSize = registerDescriptor.size;
|
|
|
|
|
const auto registerStartAddress = registerDescriptor.startAddress.value();
|
|
|
|
|
const auto registerEndAddress = registerStartAddress + (registerSize - 1);
|
2022-02-05 15:32:08 +00:00
|
|
|
|
2022-04-30 01:30:57 +01:00
|
|
|
if (registerStartAddress < bufferStartAddress || registerEndAddress > bufferEndAddress) {
|
|
|
|
|
continue;
|
2021-09-12 23:25:34 +01:00
|
|
|
}
|
|
|
|
|
|
2022-04-30 01:30:57 +01:00
|
|
|
const auto bufferBeginIt = buffer.begin() + (registerStartAddress - bufferStartAddress);
|
|
|
|
|
registersWrittenEvent->registers.emplace_back(TargetRegister(
|
|
|
|
|
registerDescriptor,
|
|
|
|
|
TargetMemoryBuffer(bufferBeginIt, bufferBeginIt + registerSize)
|
|
|
|
|
));
|
2021-09-12 23:25:34 +01:00
|
|
|
}
|
2022-04-30 01:30:57 +01:00
|
|
|
|
|
|
|
|
EventManager::triggerEvent(registersWrittenEvent);
|
2021-09-11 20:39:31 +01:00
|
|
|
}
|
2022-04-30 01:30:57 +01:00
|
|
|
}
|
2021-09-11 20:39:31 +01:00
|
|
|
|
2022-04-30 01:30:57 +01:00
|
|
|
return std::make_unique<Response>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleStepTargetExecution(StepTargetExecution& command) {
|
|
|
|
|
if (command.fromProgramCounter.has_value()) {
|
|
|
|
|
this->target->setProgramCounter(command.fromProgramCounter.value());
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2022-04-30 01:30:57 +01:00
|
|
|
|
|
|
|
|
this->target->step();
|
|
|
|
|
this->lastTargetState = TargetState::RUNNING;
|
|
|
|
|
EventManager::triggerEvent(std::make_shared<Events::TargetExecutionResumed>());
|
|
|
|
|
|
|
|
|
|
return std::make_unique<Response>();
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-04-30 22:03:28 +01:00
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleSetBreakpoint(SetBreakpoint& command) {
|
|
|
|
|
this->target->setBreakpoint(command.breakpoint.address);
|
|
|
|
|
return std::make_unique<Response>();
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-04-30 22:45:46 +01:00
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleRemoveBreakpoint(RemoveBreakpoint& command) {
|
|
|
|
|
this->target->removeBreakpoint(command.breakpoint.address);
|
|
|
|
|
return std::make_unique<Response>();
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-05-01 18:47:57 +01:00
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleSetProgramCounter(SetTargetProgramCounter& command) {
|
2022-04-30 23:10:07 +01:00
|
|
|
this->target->setProgramCounter(command.address);
|
|
|
|
|
return std::make_unique<Response>();
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-05-01 00:07:12 +01:00
|
|
|
std::unique_ptr<TargetPinStates> TargetControllerComponent::handleGetTargetPinStates(GetTargetPinStates& command) {
|
|
|
|
|
return std::make_unique<TargetPinStates>(this->target->getPinStates(command.variantId));
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-05-01 17:33:09 +01:00
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleSetTargetPinState(SetTargetPinState& command) {
|
|
|
|
|
this->target->setPinState(command.pinDescriptor, command.pinState);
|
|
|
|
|
return std::make_unique<Response>();
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
2021-11-11 19:05:24 +00:00
|
|
|
|
2022-05-01 18:01:01 +01:00
|
|
|
std::unique_ptr<TargetStackPointer> TargetControllerComponent::handleGetTargetStackPointer(
|
|
|
|
|
GetTargetStackPointer& command
|
|
|
|
|
) {
|
|
|
|
|
return std::make_unique<TargetStackPointer>(this->target->getStackPointer());
|
2021-11-11 19:05:24 +00:00
|
|
|
}
|
2022-05-01 18:44:04 +01:00
|
|
|
|
|
|
|
|
std::unique_ptr<TargetProgramCounter> TargetControllerComponent::handleGetTargetProgramCounter(
|
|
|
|
|
GetTargetProgramCounter& command
|
|
|
|
|
) {
|
|
|
|
|
return std::make_unique<TargetProgramCounter>(this->target->getProgramCounter());
|
|
|
|
|
}
|
2022-06-05 16:13:43 +01:00
|
|
|
|
|
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleEnableProgrammingMode(EnableProgrammingMode& command) {
|
|
|
|
|
if (!this->target->programmingModeEnabled()) {
|
|
|
|
|
this->enableProgrammingMode();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return std::make_unique<Response>();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleDisableProgrammingMode(DisableProgrammingMode& command) {
|
|
|
|
|
if (this->target->programmingModeEnabled()) {
|
|
|
|
|
this->disableProgrammingMode();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return std::make_unique<Response>();
|
|
|
|
|
}
|
2021-11-11 19:05:24 +00:00
|
|
|
}
|