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 <filesystem>
|
|
|
|
|
#include <typeindex>
|
2021-09-11 20:39:31 +01:00
|
|
|
#include <algorithm>
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
#include "src/Targets/Microchip/AVR8/TargetDescriptionFile.hpp"
|
|
|
|
|
#include "src/Targets/RiscV/TargetDescriptionFile.hpp"
|
2023-12-17 18:12:53 +00:00
|
|
|
|
2022-10-05 20:58:25 +01:00
|
|
|
#include "Responses/Error.hpp"
|
|
|
|
|
|
2024-03-16 00:07:55 +00:00
|
|
|
#include "src/Services/TargetService.hpp"
|
2023-12-17 18:12:53 +00:00
|
|
|
#include "src/Services/PathService.hpp"
|
2022-12-26 21:35:24 +00:00
|
|
|
#include "src/Services/ProcessService.hpp"
|
2023-09-20 23:37:54 +01:00
|
|
|
#include "src/Services/StringService.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/Exceptions/InvalidConfig.hpp"
|
|
|
|
|
|
2023-08-13 15:47:51 +01:00
|
|
|
namespace TargetController
|
2022-02-05 15:32:08 +00:00
|
|
|
{
|
2023-08-13 15:47:51 +01:00
|
|
|
using namespace Targets;
|
|
|
|
|
using namespace Events;
|
|
|
|
|
using namespace Exceptions;
|
2022-02-05 15:32:08 +00:00
|
|
|
|
2022-04-17 23:55:34 +01:00
|
|
|
using Commands::CommandIdType;
|
2022-05-01 19:23:58 +01:00
|
|
|
|
|
|
|
|
using Commands::Command;
|
2023-06-01 22:13:07 +01:00
|
|
|
using Commands::StartAtomicSession;
|
|
|
|
|
using Commands::EndAtomicSession;
|
2023-05-26 01:02:51 +01:00
|
|
|
using Commands::Shutdown;
|
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-12-11 23:25:15 +00:00
|
|
|
using Commands::EraseTargetMemory;
|
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;
|
2024-07-23 21:14:22 +01:00
|
|
|
using Commands::SetTargetStackPointer;
|
2024-08-16 22:50:06 +01:00
|
|
|
using Commands::GetTargetGpioPadStates;
|
|
|
|
|
using Commands::SetTargetGpioPadState;
|
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;
|
2023-06-01 22:13:07 +01:00
|
|
|
using Responses::AtomicSessionId;
|
2022-04-24 16:41:40 +01:00
|
|
|
using Responses::TargetRegistersRead;
|
2022-04-24 18:55:19 +01:00
|
|
|
using Responses::TargetMemoryRead;
|
2024-08-16 22:50:06 +01:00
|
|
|
using Responses::TargetGpioPadStates;
|
2022-05-01 18:01:01 +01:00
|
|
|
using Responses::TargetStackPointer;
|
2022-05-01 18:44:04 +01:00
|
|
|
using Responses::TargetProgramCounter;
|
2023-09-20 23:37:54 +01:00
|
|
|
using Responses::Breakpoint;
|
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);
|
2023-11-23 12:59:36 +00:00
|
|
|
Logger::debug("TargetController ready");
|
2022-02-05 15:32:08 +00:00
|
|
|
|
|
|
|
|
while (this->getThreadState() == ThreadState::READY) {
|
2024-07-23 21:14:22 +01:00
|
|
|
this->refreshExecutionState();
|
2023-05-25 00:29:46 +01:00
|
|
|
|
|
|
|
|
TargetControllerComponent::notifier.waitForNotification(std::chrono::milliseconds(60));
|
|
|
|
|
|
|
|
|
|
this->processQueuedCommands();
|
|
|
|
|
this->eventListener->dispatchCurrentEvents();
|
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 std::exception& exception) {
|
|
|
|
|
Logger::error("The TargetController encountered a fatal error. See below for errors:");
|
2024-07-23 21:14:22 +01:00
|
|
|
Logger::error(std::string{exception.what()});
|
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->shutdown();
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2023-06-01 22:13:07 +01:00
|
|
|
void TargetControllerComponent::registerCommand(
|
|
|
|
|
std::unique_ptr<Command> command,
|
|
|
|
|
const std::optional<AtomicSessionIdType>& atomicSessionId
|
|
|
|
|
) {
|
2023-05-26 00:23:07 +01:00
|
|
|
if (TargetControllerComponent::state != TargetControllerState::ACTIVE) {
|
2024-07-23 21:14:22 +01:00
|
|
|
throw Exception{"Command rejected - TargetController not in active state."};
|
2023-05-26 00:23:07 +01:00
|
|
|
}
|
|
|
|
|
|
2023-06-01 22:13:07 +01:00
|
|
|
if (atomicSessionId.has_value()) {
|
|
|
|
|
// This command is part of an atomic session - put it in the dedicated queue
|
2023-06-02 00:16:58 +01:00
|
|
|
TargetControllerComponent::atomicSessionCommandQueue.accessor()->push(std::move(command));
|
2023-06-01 22:13:07 +01:00
|
|
|
TargetControllerComponent::notifier.notify();
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
2023-06-02 00:16:58 +01:00
|
|
|
TargetControllerComponent::commandQueue.accessor()->push(std::move(command));
|
2022-04-17 23:55:34 +01:00
|
|
|
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] {
|
2023-06-02 00:16:58 +01:00
|
|
|
// We will already hold the lock here, so we can use Synchronised::unsafeReference() here.
|
|
|
|
|
auto& responsesByCommandId = TargetControllerComponent::responsesByCommandId.unsafeReference();
|
2022-04-17 23:55:34 +01:00
|
|
|
auto responseIt = responsesByCommandId.find(commandId);
|
|
|
|
|
|
|
|
|
|
if (responseIt != responsesByCommandId.end()) {
|
|
|
|
|
response.swap(responseIt->second);
|
|
|
|
|
responsesByCommandId.erase(responseIt);
|
|
|
|
|
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return false;
|
|
|
|
|
};
|
|
|
|
|
|
2023-06-02 00:16:58 +01:00
|
|
|
auto responsesByCommandIdLock = TargetControllerComponent::responsesByCommandId.lock();
|
2022-04-17 23:55:34 +01:00
|
|
|
|
|
|
|
|
if (timeout.has_value()) {
|
|
|
|
|
TargetControllerComponent::responsesByCommandIdCv.wait_for(
|
|
|
|
|
responsesByCommandIdLock,
|
|
|
|
|
timeout.value(),
|
|
|
|
|
predicate
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
TargetControllerComponent::responsesByCommandIdCv.wait(responsesByCommandIdLock, predicate);
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
return (response != nullptr) ? std::optional{std::move(response)} : std::nullopt;
|
2022-04-17 23:55:34 +01:00
|
|
|
}
|
|
|
|
|
|
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");
|
2023-05-25 23:16:30 +01:00
|
|
|
this->threadState = ThreadState::STARTING;
|
2022-07-28 22:45:21 +01:00
|
|
|
this->blockAllSignals();
|
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-08-14 17:39:35 +01:00
|
|
|
// Register command handlers
|
2023-06-01 22:13:07 +01:00
|
|
|
this->registerCommandHandler<StartAtomicSession>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleStartAtomicSession, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this->registerCommandHandler<EndAtomicSession>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleEndAtomicSession, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
2023-05-26 01:02:51 +01:00
|
|
|
this->registerCommandHandler<Shutdown>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleShutdown, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
2022-08-14 17:39:35 +01:00
|
|
|
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)
|
|
|
|
|
);
|
|
|
|
|
|
2022-12-11 23:25:15 +00:00
|
|
|
this->registerCommandHandler<EraseTargetMemory>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleEraseTargetMemory, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
2022-08-14 17:39:35 +01:00
|
|
|
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)
|
|
|
|
|
);
|
|
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
this->registerCommandHandler<SetTargetStackPointer>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleSetStackPointer, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
2022-08-14 17:39:35 +01:00
|
|
|
this->registerCommandHandler<SetTargetProgramCounter>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleSetProgramCounter, this, std::placeholders::_1)
|
|
|
|
|
);
|
|
|
|
|
|
2024-08-16 22:50:06 +01:00
|
|
|
this->registerCommandHandler<GetTargetGpioPadStates>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleGetTargetGpioPadStates, this, std::placeholders::_1)
|
2022-08-14 17:39:35 +01:00
|
|
|
);
|
|
|
|
|
|
2024-08-16 22:50:06 +01:00
|
|
|
this->registerCommandHandler<SetTargetGpioPadState>(
|
|
|
|
|
std::bind(&TargetControllerComponent::handleSetTargetGpioPadState, this, std::placeholders::_1)
|
2022-08-14 17:39:35 +01:00
|
|
|
);
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
2023-05-26 00:23:07 +01:00
|
|
|
this->eventListener->registerCallbackForEventType<Events::DebugSessionFinished>(
|
|
|
|
|
std::bind(&TargetControllerComponent::onDebugSessionFinishedEvent, this, std::placeholders::_1)
|
2022-02-05 15:32:08 +00:00
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2023-05-26 00:23:07 +01:00
|
|
|
this->acquireHardware();
|
|
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
if (this->targetState->executionState != TargetExecutionState::RUNNING) {
|
|
|
|
|
// this->target->run();
|
|
|
|
|
// this->targetState->executionState = TargetExecutionState::RUNNING;
|
2023-05-26 00:23:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->state = TargetControllerState::ACTIVE;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TargetControllerComponent::shutdown() {
|
|
|
|
|
const auto threadState = this->getThreadState();
|
|
|
|
|
if (threadState == ThreadState::SHUTDOWN_INITIATED || threadState == ThreadState::STOPPED) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->threadState = ThreadState::SHUTDOWN_INITIATED;
|
|
|
|
|
|
|
|
|
|
try {
|
|
|
|
|
Logger::info("Shutting down TargetController");
|
|
|
|
|
this->state = TargetControllerState::INACTIVE;
|
|
|
|
|
EventManager::deregisterListener(this->eventListener->getId());
|
|
|
|
|
|
2023-06-01 22:13:07 +01:00
|
|
|
if (this->activeAtomicSession.has_value()) {
|
|
|
|
|
// Reject any commands on the dedicated queue
|
|
|
|
|
this->processQueuedCommands();
|
|
|
|
|
this->endActiveAtomicSession();
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-26 00:23:07 +01:00
|
|
|
// Reject any commands still waiting in the queue
|
|
|
|
|
this->processQueuedCommands();
|
|
|
|
|
|
|
|
|
|
this->releaseHardware();
|
|
|
|
|
|
|
|
|
|
} catch (const std::exception& exception) {
|
|
|
|
|
this->target.reset();
|
|
|
|
|
this->debugTool.reset();
|
|
|
|
|
Logger::error(
|
2024-07-23 21:14:22 +01:00
|
|
|
"Failed to properly shut down TargetController. Error: " + std::string{exception.what()}
|
2023-05-26 00:23:07 +01:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->setThreadStateAndEmitEvent(ThreadState::STOPPED);
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
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",
|
|
|
|
|
[] {
|
2023-11-18 23:50:08 +00:00
|
|
|
return std::make_unique<DebugToolDrivers::Microchip::AtmelIce>();
|
2022-04-17 23:55:34 +01:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"power-debugger",
|
|
|
|
|
[] {
|
2023-11-18 23:50:08 +00:00
|
|
|
return std::make_unique<DebugToolDrivers::Microchip::PowerDebugger>();
|
2022-04-17 23:55:34 +01:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"snap",
|
|
|
|
|
[] {
|
2023-11-18 23:50:08 +00:00
|
|
|
return std::make_unique<DebugToolDrivers::Microchip::MplabSnap>();
|
2022-04-17 23:55:34 +01:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"pickit-4",
|
|
|
|
|
[] {
|
2023-11-18 23:50:08 +00:00
|
|
|
return std::make_unique<DebugToolDrivers::Microchip::MplabPickit4>();
|
2022-04-17 23:55:34 +01:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"xplained-pro",
|
|
|
|
|
[] {
|
2023-11-18 23:50:08 +00:00
|
|
|
return std::make_unique<DebugToolDrivers::Microchip::XplainedPro>();
|
2022-04-17 23:55:34 +01:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"xplained-mini",
|
|
|
|
|
[] {
|
2023-11-18 23:50:08 +00:00
|
|
|
return std::make_unique<DebugToolDrivers::Microchip::XplainedMini>();
|
2022-04-17 23:55:34 +01:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"xplained-nano",
|
|
|
|
|
[] {
|
2023-11-18 23:50:08 +00:00
|
|
|
return std::make_unique<DebugToolDrivers::Microchip::XplainedNano>();
|
2022-04-17 23:55:34 +01:00
|
|
|
}
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
"curiosity-nano",
|
|
|
|
|
[] {
|
2023-11-18 23:50:08 +00:00
|
|
|
return std::make_unique<DebugToolDrivers::Microchip::CuriosityNano>();
|
2022-04-17 23:55:34 +01:00
|
|
|
}
|
|
|
|
|
},
|
2022-05-02 22:51:21 +01:00
|
|
|
{
|
|
|
|
|
"jtagice3",
|
|
|
|
|
[] {
|
2023-11-18 23:50:08 +00:00
|
|
|
return std::make_unique<DebugToolDrivers::Microchip::JtagIce3>();
|
2022-05-02 22:51:21 +01:00
|
|
|
}
|
|
|
|
|
},
|
2023-11-18 22:58:48 +00:00
|
|
|
{
|
|
|
|
|
"wch-link-e",
|
|
|
|
|
[] {
|
|
|
|
|
return std::make_unique<DebugToolDrivers::Wch::WchLinkE>();
|
|
|
|
|
}
|
|
|
|
|
},
|
2022-04-17 23:55:34 +01:00
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-02 01:59:55 +00:00
|
|
|
std::unique_ptr<Target> TargetControllerComponent::constructTarget(const BriefTargetDescriptor& briefDescriptor) {
|
2023-12-17 18:12:53 +00:00
|
|
|
using Services::PathService;
|
|
|
|
|
|
2024-03-02 01:59:55 +00:00
|
|
|
if (briefDescriptor.family == TargetFamily::AVR_8) {
|
2024-07-23 21:14:22 +01:00
|
|
|
return std::make_unique<Microchip::Avr8::Avr8>(
|
2023-12-17 18:12:53 +00:00
|
|
|
this->environmentConfig.targetConfig,
|
2024-07-23 21:14:22 +01:00
|
|
|
Microchip::Avr8::TargetDescriptionFile{
|
|
|
|
|
PathService::targetDescriptionFilesDirPath() + "/" + briefDescriptor.relativeTdfPath
|
|
|
|
|
}
|
2023-12-17 18:12:53 +00:00
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
2024-03-02 01:59:55 +00:00
|
|
|
if (briefDescriptor.family == TargetFamily::RISC_V) {
|
2023-12-17 18:12:53 +00:00
|
|
|
return std::make_unique<RiscV::RiscV>(
|
|
|
|
|
this->environmentConfig.targetConfig,
|
2024-07-23 21:14:22 +01:00
|
|
|
RiscV::TargetDescriptionFile{
|
|
|
|
|
PathService::targetDescriptionFilesDirPath() + "/" + briefDescriptor.relativeTdfPath
|
|
|
|
|
}
|
2023-12-17 18:12:53 +00:00
|
|
|
);
|
2022-04-17 23:55:34 +01:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
throw Exception{"Cannot construct target instance - invalid target family in BriefTargetDescriptor"};
|
2022-04-17 23:55:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TargetControllerComponent::processQueuedCommands() {
|
2024-07-23 21:14:22 +01:00
|
|
|
auto commands = std::queue<std::unique_ptr<Command>>{};
|
2022-04-17 23:55:34 +01:00
|
|
|
|
2023-06-02 00:16:58 +01:00
|
|
|
commands.swap(
|
|
|
|
|
this->activeAtomicSession.has_value()
|
|
|
|
|
? *(TargetControllerComponent::atomicSessionCommandQueue.accessor())
|
|
|
|
|
: *(TargetControllerComponent::commandQueue.accessor())
|
|
|
|
|
);
|
2022-04-17 23:55:34 +01:00
|
|
|
|
|
|
|
|
while (!commands.empty()) {
|
|
|
|
|
const auto command = std::move(commands.front());
|
|
|
|
|
commands.pop();
|
|
|
|
|
|
|
|
|
|
const auto commandId = command->id;
|
|
|
|
|
const auto commandType = command->getType();
|
|
|
|
|
|
|
|
|
|
try {
|
2022-12-03 22:16:21 +00:00
|
|
|
const auto commandHandlerIt = this->commandHandlersByCommandType.find(commandType);
|
|
|
|
|
|
|
|
|
|
if (commandHandlerIt == this->commandHandlersByCommandType.end()) {
|
2024-07-23 21:14:22 +01:00
|
|
|
throw Exception{"No handler registered for this command."};
|
2022-04-17 23:55:34 +01:00
|
|
|
}
|
|
|
|
|
|
2023-05-26 00:23:07 +01:00
|
|
|
if (this->state != TargetControllerState::ACTIVE) {
|
2024-07-23 21:14:22 +01:00
|
|
|
throw Exception{"Command rejected - TargetController not in active state."};
|
2022-04-29 22:06:05 +01:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
if (
|
|
|
|
|
command->requiresStoppedTargetState()
|
|
|
|
|
&& this->targetState->executionState != TargetExecutionState::STOPPED
|
|
|
|
|
) {
|
|
|
|
|
throw Exception{"Command rejected - command requires target execution to be stopped."};
|
2023-05-26 00:23:07 +01:00
|
|
|
}
|
2022-08-14 17:39:35 +01:00
|
|
|
|
2023-05-26 00:23:07 +01:00
|
|
|
if (this->target->programmingModeEnabled() && command->requiresDebugMode()) {
|
2024-07-23 21:14:22 +01:00
|
|
|
throw Exception{
|
2023-05-26 00:23:07 +01:00
|
|
|
"Command rejected - command cannot be serviced whilst the target is in programming mode."
|
2024-07-23 21:14:22 +01:00
|
|
|
};
|
2022-06-05 16:13:43 +01:00
|
|
|
}
|
|
|
|
|
|
2022-12-03 22:16:21 +00:00
|
|
|
this->registerCommandResponse(commandId, commandHandlerIt->second(*(command.get())));
|
2022-04-17 23:55:34 +01:00
|
|
|
|
2023-05-25 00:29:46 +01:00
|
|
|
} catch (const DeviceFailure& exception) {
|
|
|
|
|
this->registerCommandResponse(
|
|
|
|
|
commandId,
|
|
|
|
|
std::make_unique<Responses::Error>(exception.getMessage())
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
throw exception;
|
|
|
|
|
|
2022-04-17 23:55:34 +01:00
|
|
|
} catch (const Exception& exception) {
|
|
|
|
|
this->registerCommandResponse(
|
|
|
|
|
commandId,
|
|
|
|
|
std::make_unique<Responses::Error>(exception.getMessage())
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TargetControllerComponent::registerCommandResponse(
|
|
|
|
|
CommandIdType commandId,
|
|
|
|
|
std::unique_ptr<Response> response
|
|
|
|
|
) {
|
2023-06-02 00:16:58 +01:00
|
|
|
TargetControllerComponent::responsesByCommandId.accessor()->emplace(commandId, std::move(response));
|
2022-04-17 23:55:34 +01:00
|
|
|
TargetControllerComponent::responsesByCommandIdCv.notify_all();
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-09 15:26:56 +01:00
|
|
|
void TargetControllerComponent::acquireHardware() {
|
2023-09-20 18:56:44 +01:00
|
|
|
const auto& debugToolName = this->environmentConfig.debugToolConfig.name;
|
|
|
|
|
const auto& targetName = this->environmentConfig.targetConfig.name;
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2022-12-03 22:16:21 +00:00
|
|
|
static const auto supportedDebugTools = this->getSupportedDebugTools();
|
2021-05-30 16:52:32 +01:00
|
|
|
|
2022-12-03 22:16:21 +00:00
|
|
|
const auto debugToolIt = supportedDebugTools.find(debugToolName);
|
2024-03-02 01:59:55 +00:00
|
|
|
const auto briefTargetDescriptor = Services::TargetService::briefDescriptor(targetName);
|
2022-12-03 22:16:21 +00:00
|
|
|
|
|
|
|
|
if (debugToolIt == supportedDebugTools.end()) {
|
2024-07-23 21:14:22 +01:00
|
|
|
throw Exceptions::InvalidConfig{
|
2022-02-05 15:32:08 +00:00
|
|
|
"Debug tool name (\"" + debugToolName + "\") not recognised. Please check your configuration!"
|
2024-07-23 21:14:22 +01:00
|
|
|
};
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-05-30 16:52:32 +01:00
|
|
|
|
2024-03-02 01:59:55 +00:00
|
|
|
if (!briefTargetDescriptor.has_value()) {
|
2024-07-23 21:14:22 +01:00
|
|
|
throw Exceptions::InvalidConfig{
|
2022-02-05 15:32:08 +00:00
|
|
|
"Target name (\"" + targetName + "\") not recognised. Please check your configuration!"
|
2024-07-23 21:14:22 +01:00
|
|
|
};
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-05-30 16:52:32 +01:00
|
|
|
|
2022-12-03 22:16:21 +00:00
|
|
|
this->debugTool = debugToolIt->second();
|
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();
|
|
|
|
|
Logger::info("Debug tool connected");
|
2024-07-23 21:44:15 +01:00
|
|
|
|
|
|
|
|
this->debugTool->postInit();
|
|
|
|
|
|
2022-02-05 15:32:08 +00:00
|
|
|
Logger::info("Debug tool name: " + this->debugTool->getName());
|
|
|
|
|
Logger::info("Debug tool serial: " + this->debugTool->getSerialNumber());
|
2021-05-30 16:52:32 +01:00
|
|
|
|
2024-03-02 01:59:55 +00:00
|
|
|
this->target = this->constructTarget(*briefTargetDescriptor);
|
2021-05-30 16:52:32 +01:00
|
|
|
|
2023-05-21 21:08:25 +01:00
|
|
|
if (!this->target->supportsDebugTool(this->debugTool.get())) {
|
2024-07-23 21:14:22 +01:00
|
|
|
throw Exceptions::InvalidConfig{
|
2023-11-18 22:53:20 +00:00
|
|
|
"Debug tool \"" + this->debugTool->getName() + "\" is not compatible with target \""
|
2024-07-23 21:14:22 +01:00
|
|
|
+ targetName + "\"."
|
|
|
|
|
};
|
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());
|
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");
|
2024-09-07 13:07:40 +01:00
|
|
|
|
|
|
|
|
this->targetDescriptor = std::make_unique<const TargetDescriptor>(this->target->targetDescriptor());
|
2024-07-25 19:04:13 +01:00
|
|
|
Logger::info("Target name: " + this->targetDescriptor->name);
|
2021-05-30 16:52:32 +01:00
|
|
|
|
2024-07-23 21:35:12 +01:00
|
|
|
this->target->postActivate();
|
|
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
this->targetState = std::make_unique<TargetState>(
|
|
|
|
|
TargetExecutionState::UNKNOWN,
|
|
|
|
|
TargetMode::DEBUGGING,
|
|
|
|
|
std::nullopt
|
|
|
|
|
);
|
|
|
|
|
this->refreshExecutionState();
|
2023-09-20 23:37:54 +01:00
|
|
|
|
|
|
|
|
if (!this->environmentConfig.targetConfig.hardwareBreakpoints) {
|
|
|
|
|
Logger::warning("Hardware breakpoints have been disabled");
|
|
|
|
|
|
2023-09-23 21:50:04 +01:00
|
|
|
} else {
|
2024-07-23 21:14:22 +01:00
|
|
|
const auto& breakpointResources = this->targetDescriptor->breakpointResources;
|
2023-09-23 21:50:04 +01:00
|
|
|
if (breakpointResources.maximumHardwareBreakpoints.has_value()) {
|
|
|
|
|
Logger::info(
|
|
|
|
|
"Available hardware breakpoints: " + std::to_string(
|
|
|
|
|
*(breakpointResources.maximumHardwareBreakpoints)
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (breakpointResources.reservedHardwareBreakpoints > 0) {
|
|
|
|
|
Logger::info(
|
2024-07-23 21:14:22 +01:00
|
|
|
"Reserved hardware breakpoints: " + std::to_string(breakpointResources.reservedHardwareBreakpoints)
|
2023-09-23 21:50:04 +01:00
|
|
|
);
|
|
|
|
|
}
|
2023-09-20 23:37:54 +01:00
|
|
|
}
|
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
|
|
|
|
2023-06-01 22:13:07 +01:00
|
|
|
void TargetControllerComponent::startAtomicSession() {
|
|
|
|
|
if (this->activeAtomicSession.has_value()) {
|
2024-07-23 21:14:22 +01:00
|
|
|
throw Exception{"Atomic session already active - nested sessions are not supported"};
|
2023-06-01 22:13:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->activeAtomicSession.emplace();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TargetControllerComponent::endActiveAtomicSession() {
|
|
|
|
|
if (!this->activeAtomicSession.has_value()) {
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
{
|
2023-06-02 00:16:58 +01:00
|
|
|
auto commandQueue = TargetControllerComponent::atomicSessionCommandQueue.accessor();
|
2024-07-23 21:14:22 +01:00
|
|
|
auto empty = std::queue<std::unique_ptr<Commands::Command>>{};
|
2023-06-02 00:16:58 +01:00
|
|
|
commandQueue->swap(empty);
|
2023-06-01 22:13:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->activeAtomicSession.reset();
|
|
|
|
|
TargetControllerComponent::notifier.notify();
|
|
|
|
|
}
|
|
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
void TargetControllerComponent::refreshExecutionState() {
|
|
|
|
|
auto newExecutionState = this->target->getExecutionState();
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
if (newExecutionState != this->targetState->executionState) {
|
|
|
|
|
Logger::debug("Target execution state changed");
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
auto newState = *(this->targetState);
|
|
|
|
|
newState.executionState = newExecutionState;
|
2022-12-03 22:16:21 +00:00
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
if (newExecutionState == TargetExecutionState::STOPPED) {
|
|
|
|
|
Logger::debug("Target stopped");
|
|
|
|
|
newState.programCounter = this->target->getProgramCounter();
|
2022-02-05 15:32:08 +00:00
|
|
|
|
2023-05-21 21:08:25 +01:00
|
|
|
} else {
|
2024-07-23 21:14:22 +01:00
|
|
|
Logger::debug("Target resumed");
|
|
|
|
|
newState.programCounter = std::nullopt;
|
|
|
|
|
}
|
2022-02-05 15:32:08 +00:00
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
this->updateTargetState(newState);
|
|
|
|
|
}
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
void TargetControllerComponent::updateTargetState(const TargetState& newState) {
|
|
|
|
|
if (newState == *(this->targetState)) {
|
|
|
|
|
// Nothing has changed, nothing to do
|
|
|
|
|
return;
|
|
|
|
|
}
|
2023-05-21 21:08:25 +01:00
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
const auto previousState = *(this->targetState);
|
|
|
|
|
*(this->targetState) = newState;
|
|
|
|
|
EventManager::triggerEvent(std::make_shared<TargetStateChanged>(*(this->targetState), previousState));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TargetControllerComponent::stopTarget() {
|
|
|
|
|
if (this->target->getExecutionState() != TargetExecutionState::STOPPED) {
|
|
|
|
|
this->target->stop();
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
2024-07-23 21:14:22 +01:00
|
|
|
|
|
|
|
|
auto newState = *(this->targetState);
|
|
|
|
|
newState.executionState = TargetExecutionState::STOPPED;
|
|
|
|
|
newState.programCounter = this->target->getProgramCounter();
|
|
|
|
|
this->updateTargetState(newState);
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
void TargetControllerComponent::resumeTarget() {
|
|
|
|
|
if (this->target->getExecutionState() != TargetExecutionState::RUNNING) {
|
|
|
|
|
this->target->run(std::nullopt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto newState = *(this->targetState);
|
|
|
|
|
newState.executionState = TargetExecutionState::RUNNING;
|
|
|
|
|
newState.programCounter = std::nullopt;
|
|
|
|
|
this->updateTargetState(newState);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TargetControllerComponent::stepTarget() {
|
|
|
|
|
this->target->step();
|
|
|
|
|
|
|
|
|
|
auto newState = *(this->targetState);
|
|
|
|
|
newState.executionState = TargetExecutionState::STEPPING;
|
|
|
|
|
newState.programCounter = std::nullopt;
|
|
|
|
|
this->updateTargetState(newState);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TargetControllerComponent::resetTarget() {
|
|
|
|
|
this->target->reset();
|
|
|
|
|
EventManager::triggerEvent(std::make_shared<Events::TargetReset>());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TargetRegisterDescriptorAndValuePairs TargetControllerComponent::readTargetRegisters(
|
|
|
|
|
const TargetRegisterDescriptors& descriptors
|
2021-10-06 21:12:31 +01:00
|
|
|
) {
|
2024-07-23 21:14:22 +01:00
|
|
|
return this->target->readRegisters(descriptors);
|
|
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
void TargetControllerComponent::writeTargetRegisters(const TargetRegisterDescriptorAndValuePairs& registers) {
|
|
|
|
|
this->target->writeRegisters(registers);
|
|
|
|
|
EventManager::triggerEvent(std::make_shared<Events::RegistersWrittenToTarget>(registers));
|
|
|
|
|
}
|
2022-12-03 22:16:21 +00:00
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
Targets::TargetMemoryBuffer TargetControllerComponent::readTargetMemory(
|
|
|
|
|
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
|
|
|
|
|
const TargetMemorySegmentDescriptor& memorySegmentDescriptor,
|
|
|
|
|
TargetMemoryAddress startAddress,
|
|
|
|
|
TargetMemorySize bytes,
|
|
|
|
|
const std::set<TargetMemoryAddressRange>& excludedAddressRanges,
|
|
|
|
|
bool bypassCache
|
|
|
|
|
) {
|
2022-12-03 22:16:21 +00:00
|
|
|
if (
|
2024-07-23 21:14:22 +01:00
|
|
|
!bypassCache
|
|
|
|
|
&& this->environmentConfig.targetConfig.programMemoryCache
|
|
|
|
|
&& this->target->isProgramMemory(addressSpaceDescriptor, memorySegmentDescriptor, startAddress, bytes)
|
2021-10-06 21:12:31 +01:00
|
|
|
) {
|
2024-07-23 21:14:22 +01:00
|
|
|
auto& cache = this->getProgramMemoryCache(addressSpaceDescriptor);
|
|
|
|
|
|
|
|
|
|
if (!cache.contains(startAddress, bytes)) {
|
|
|
|
|
Logger::debug(
|
|
|
|
|
"Program memory cache miss at 0x" + Services::StringService::toHex(startAddress) + ", "
|
|
|
|
|
+ std::to_string(bytes) + " bytes"
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* TODO: We're currently ignoring excludedAddressRanges when populating the program
|
|
|
|
|
* memory cache. This isn't a big deal, so I'll sort it later.
|
|
|
|
|
*/
|
|
|
|
|
cache.insert(
|
|
|
|
|
startAddress,
|
|
|
|
|
this->target->readMemory(
|
|
|
|
|
addressSpaceDescriptor,
|
|
|
|
|
memorySegmentDescriptor,
|
|
|
|
|
startAddress,
|
|
|
|
|
std::max(
|
|
|
|
|
bytes,
|
|
|
|
|
memorySegmentDescriptor.pageSize.value_or(0)
|
|
|
|
|
),
|
|
|
|
|
{}
|
|
|
|
|
)
|
|
|
|
|
);
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
2024-07-23 21:14:22 +01:00
|
|
|
|
|
|
|
|
return cache.fetch(startAddress, bytes);
|
2021-10-06 21:12:31 +01:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
return this->target->readMemory(
|
|
|
|
|
addressSpaceDescriptor,
|
|
|
|
|
memorySegmentDescriptor,
|
|
|
|
|
startAddress,
|
|
|
|
|
bytes,
|
|
|
|
|
excludedAddressRanges
|
|
|
|
|
);
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-10-06 21:12:31 +01:00
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
void TargetControllerComponent::writeTargetMemory(
|
|
|
|
|
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
|
|
|
|
|
const TargetMemorySegmentDescriptor& memorySegmentDescriptor,
|
|
|
|
|
Targets::TargetMemoryAddress startAddress,
|
|
|
|
|
const TargetMemoryBuffer& buffer
|
|
|
|
|
) {
|
|
|
|
|
const auto isProgramMemory = this->target->isProgramMemory(
|
|
|
|
|
addressSpaceDescriptor,
|
|
|
|
|
memorySegmentDescriptor,
|
|
|
|
|
startAddress,
|
|
|
|
|
static_cast<TargetMemorySize>(buffer.size())
|
|
|
|
|
);
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
if (isProgramMemory && !this->target->programmingModeEnabled()) {
|
|
|
|
|
throw Exception{"Cannot write to program memory - programming mode not enabled."};
|
|
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
this->target->writeMemory(addressSpaceDescriptor, memorySegmentDescriptor, startAddress, buffer);
|
|
|
|
|
|
|
|
|
|
if (isProgramMemory && this->environmentConfig.targetConfig.programMemoryCache) {
|
|
|
|
|
this->getProgramMemoryCache(addressSpaceDescriptor).insert(startAddress, buffer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
EventManager::triggerEvent(
|
|
|
|
|
std::make_shared<Events::MemoryWrittenToTarget>(
|
|
|
|
|
addressSpaceDescriptor,
|
|
|
|
|
memorySegmentDescriptor,
|
|
|
|
|
startAddress,
|
|
|
|
|
static_cast<TargetMemorySize>(buffer.size())
|
|
|
|
|
)
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TargetControllerComponent::eraseTargetMemory(
|
|
|
|
|
const TargetAddressSpaceDescriptor& addressSpaceDescriptor,
|
|
|
|
|
const TargetMemorySegmentDescriptor& memorySegmentDescriptor
|
|
|
|
|
) {
|
|
|
|
|
if (this->target->isProgramMemory(
|
|
|
|
|
addressSpaceDescriptor,
|
|
|
|
|
memorySegmentDescriptor,
|
|
|
|
|
memorySegmentDescriptor.addressRange.startAddress,
|
|
|
|
|
memorySegmentDescriptor.addressRange.size()
|
|
|
|
|
)) {
|
|
|
|
|
if (!this->target->programmingModeEnabled()) {
|
|
|
|
|
throw Exception{"Cannot erase program memory - programming mode not enabled."};
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
if (this->environmentConfig.targetConfig.programMemoryCache) {
|
|
|
|
|
Logger::debug("Clearing program memory cache");
|
|
|
|
|
this->getProgramMemoryCache(addressSpaceDescriptor).clear();
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
2024-07-23 21:14:22 +01:00
|
|
|
|
|
|
|
|
this->target->eraseMemory(addressSpaceDescriptor, memorySegmentDescriptor);
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
void TargetControllerComponent::setBreakpoint(const TargetBreakpoint& breakpoint) {
|
|
|
|
|
using Services::StringService;
|
2022-04-08 22:14:01 +01:00
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
if (breakpoint.type == TargetBreakpoint::Type::HARDWARE) {
|
|
|
|
|
Logger::debug(
|
|
|
|
|
"Installing hardware breakpoint at byte address 0x" + StringService::toHex(breakpoint.address)
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
this->target->setHardwareBreakpoint(breakpoint.address);
|
|
|
|
|
this->hardwareBreakpointsByAddress.emplace(breakpoint.address, breakpoint);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Logger::debug("Installing software breakpoint at byte address 0x" + StringService::toHex(breakpoint.address));
|
|
|
|
|
|
|
|
|
|
this->target->setSoftwareBreakpoint(breakpoint.address);
|
|
|
|
|
this->softwareBreakpointsByAddress.emplace(breakpoint.address, breakpoint);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void TargetControllerComponent::removeBreakpoint(const TargetBreakpoint& breakpoint) {
|
|
|
|
|
using Services::StringService;
|
|
|
|
|
|
|
|
|
|
if (breakpoint.type == Targets::TargetBreakpoint::Type::HARDWARE) {
|
|
|
|
|
Logger::debug("Removing hardware breakpoint at byte address 0x" + StringService::toHex(breakpoint.address));
|
|
|
|
|
|
|
|
|
|
this->target->removeHardwareBreakpoint(breakpoint.address);
|
|
|
|
|
this->hardwareBreakpointsByAddress.erase(breakpoint.address);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Logger::debug("Removing software breakpoint at byte address 0x" + StringService::toHex(breakpoint.address));
|
|
|
|
|
|
|
|
|
|
this->target->removeSoftwareBreakpoint(breakpoint.address);
|
|
|
|
|
this->softwareBreakpointsByAddress.erase(breakpoint.address);
|
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
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
auto newState = *(this->targetState);
|
|
|
|
|
newState.mode = TargetMode::PROGRAMMING;
|
|
|
|
|
this->updateTargetState(newState);
|
2022-06-05 16:13:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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
|
|
|
|
2023-09-22 20:55:00 +01:00
|
|
|
Logger::info("Restoring breakpoints");
|
|
|
|
|
this->target->stop();
|
|
|
|
|
|
|
|
|
|
for (const auto& [address, breakpoint] : this->softwareBreakpointsByAddress) {
|
|
|
|
|
this->target->setSoftwareBreakpoint(address);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const auto& [address, breakpoint] : this->hardwareBreakpointsByAddress) {
|
|
|
|
|
this->target->setHardwareBreakpoint(address);
|
|
|
|
|
}
|
2024-07-23 21:14:22 +01:00
|
|
|
|
|
|
|
|
auto newState = *(this->targetState);
|
|
|
|
|
newState.mode = TargetMode::DEBUGGING;
|
|
|
|
|
newState.executionState = TargetExecutionState::STOPPED;
|
|
|
|
|
this->updateTargetState(newState);
|
2022-06-05 16:13:43 +01:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
TargetMemoryCache& TargetControllerComponent::getProgramMemoryCache(
|
|
|
|
|
const TargetAddressSpaceDescriptor& addressSpaceDescriptor
|
|
|
|
|
) {
|
|
|
|
|
auto cacheIt = this->programMemoryCachesByAddressSpaceKey.find(addressSpaceDescriptor.key);
|
|
|
|
|
|
|
|
|
|
if (cacheIt == this->programMemoryCachesByAddressSpaceKey.end()) {
|
|
|
|
|
cacheIt = this->programMemoryCachesByAddressSpaceKey.emplace(
|
|
|
|
|
addressSpaceDescriptor.key,
|
|
|
|
|
TargetMemoryCache(addressSpaceDescriptor)
|
|
|
|
|
).first;
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-05-30 16:52:32 +01:00
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
return cacheIt->second;
|
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
|
|
|
}
|
|
|
|
|
|
2023-05-26 00:23:07 +01:00
|
|
|
void TargetControllerComponent::onDebugSessionFinishedEvent(const DebugSessionFinished&) {
|
|
|
|
|
if (this->state != TargetControllerState::ACTIVE) {
|
|
|
|
|
return;
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
if (this->target->getExecutionState() != TargetExecutionState::RUNNING) {
|
|
|
|
|
this->target->run(std::nullopt);
|
|
|
|
|
this->refreshExecutionState();
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
2022-02-05 15:32:08 +00:00
|
|
|
}
|
2021-04-04 21:04:12 +01:00
|
|
|
|
2023-06-01 22:13:07 +01:00
|
|
|
std::unique_ptr<AtomicSessionId> TargetControllerComponent::handleStartAtomicSession(StartAtomicSession& command) {
|
|
|
|
|
this->startAtomicSession();
|
|
|
|
|
return std::make_unique<AtomicSessionId>(this->activeAtomicSession->id);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleEndAtomicSession(EndAtomicSession& command) {
|
|
|
|
|
if (!this->activeAtomicSession.has_value() || this->activeAtomicSession->id != command.sessionId) {
|
2024-07-23 21:14:22 +01:00
|
|
|
throw Exception{"Atomic session is not active"};
|
2023-06-01 22:13:07 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->endActiveAtomicSession();
|
|
|
|
|
return std::make_unique<Response>();
|
|
|
|
|
}
|
|
|
|
|
|
2023-05-26 01:02:51 +01:00
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleShutdown(Shutdown& command) {
|
|
|
|
|
this->shutdown();
|
|
|
|
|
return std::make_unique<Response>();
|
|
|
|
|
}
|
|
|
|
|
|
2022-05-01 18:30:58 +01:00
|
|
|
std::unique_ptr<Responses::TargetDescriptor> TargetControllerComponent::handleGetTargetDescriptor(
|
|
|
|
|
GetTargetDescriptor& command
|
|
|
|
|
) {
|
2024-07-23 21:14:22 +01:00
|
|
|
return std::make_unique<Responses::TargetDescriptor>(*(this->targetDescriptor));
|
2022-05-01 18:30:58 +01:00
|
|
|
}
|
|
|
|
|
|
2022-04-28 21:02:45 +01:00
|
|
|
std::unique_ptr<Responses::TargetState> TargetControllerComponent::handleGetTargetState(GetTargetState& command) {
|
2024-07-23 21:14:22 +01:00
|
|
|
return std::make_unique<Responses::TargetState>(*(this->targetState));
|
2022-04-28 21:02:45 +01:00
|
|
|
}
|
|
|
|
|
|
2022-04-18 18:50:23 +01:00
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleStopTargetExecution(StopTargetExecution& command) {
|
2024-07-23 21:14:22 +01:00
|
|
|
this->stopTarget();
|
2022-04-18 18:50:23 +01:00
|
|
|
return std::make_unique<Response>();
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleResumeTargetExecution(ResumeTargetExecution& command) {
|
|
|
|
|
this->resumeTarget();
|
2022-04-19 21:12:59 +01:00
|
|
|
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
|
|
|
|
|
) {
|
2024-07-23 21:14:22 +01:00
|
|
|
if (command.descriptors.empty()) {
|
|
|
|
|
throw Exception{"No register descriptors provided"};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return std::make_unique<TargetRegistersRead>(this->readTargetRegisters(command.descriptors));
|
2022-04-24 16:41:40 +01:00
|
|
|
}
|
|
|
|
|
|
2022-04-24 17:37:58 +01:00
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleWriteTargetRegisters(WriteTargetRegisters& command) {
|
2024-07-23 21:14:22 +01:00
|
|
|
if (command.registers.empty()) {
|
|
|
|
|
throw Exception{"No register values provided"};
|
2023-05-21 21:08:25 +01:00
|
|
|
}
|
2022-04-24 17:37:58 +01:00
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
this->writeTargetRegisters(std::move(command.registers));
|
2022-04-24 17:37:58 +01:00
|
|
|
return std::make_unique<Response>();
|
|
|
|
|
}
|
|
|
|
|
|
2022-04-24 18:55:19 +01:00
|
|
|
std::unique_ptr<TargetMemoryRead> TargetControllerComponent::handleReadTargetMemory(ReadTargetMemory& command) {
|
2024-07-23 21:14:22 +01:00
|
|
|
if (command.bytes == 0) {
|
|
|
|
|
throw Exception{"Zero bytes requested"};
|
|
|
|
|
}
|
2023-09-22 17:52:28 +01:00
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
const auto addressRange = TargetMemoryAddressRange(
|
|
|
|
|
command.startAddress,
|
|
|
|
|
command.startAddress + command.bytes - 1
|
|
|
|
|
);
|
2023-09-22 17:52:28 +01:00
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
if (
|
|
|
|
|
!command.addressSpaceDescriptor.addressRange.contains(addressRange)
|
|
|
|
|
|| !command.memorySegmentDescriptor.addressRange.contains(addressRange)
|
|
|
|
|
) {
|
|
|
|
|
throw Exception{"Invalid address range"};
|
2023-09-22 17:52:28 +01:00
|
|
|
}
|
|
|
|
|
|
2023-05-21 21:08:25 +01:00
|
|
|
return std::make_unique<TargetMemoryRead>(
|
2024-07-23 21:14:22 +01:00
|
|
|
this->readTargetMemory(
|
|
|
|
|
command.addressSpaceDescriptor,
|
|
|
|
|
command.memorySegmentDescriptor,
|
|
|
|
|
command.startAddress,
|
|
|
|
|
command.bytes,
|
|
|
|
|
command.excludedAddressRanges,
|
|
|
|
|
command.bypassCache
|
|
|
|
|
)
|
2023-05-21 21:08:25 +01:00
|
|
|
);
|
2022-04-24 18:55:19 +01:00
|
|
|
}
|
|
|
|
|
|
2022-04-30 01:30:57 +01:00
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleWriteTargetMemory(WriteTargetMemory& command) {
|
2024-07-23 21:14:22 +01:00
|
|
|
if (command.buffer.empty()) {
|
|
|
|
|
throw Exception{"Empty buffer"};
|
2022-06-05 16:13:43 +01:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
const auto addressRange = TargetMemoryAddressRange{
|
|
|
|
|
command.startAddress,
|
|
|
|
|
static_cast<TargetMemoryAddress>(command.startAddress + command.buffer.size() - 1)
|
|
|
|
|
};
|
2023-09-22 17:52:28 +01:00
|
|
|
|
|
|
|
|
if (
|
2024-07-23 21:14:22 +01:00
|
|
|
!command.addressSpaceDescriptor.addressRange.contains(addressRange)
|
|
|
|
|
|| !command.memorySegmentDescriptor.addressRange.contains(addressRange)
|
2023-09-22 17:52:28 +01:00
|
|
|
) {
|
2024-07-23 21:14:22 +01:00
|
|
|
throw Exception{"Invalid address range"};
|
2023-09-22 17:52:28 +01:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
this->writeTargetMemory(
|
|
|
|
|
command.addressSpaceDescriptor,
|
|
|
|
|
command.memorySegmentDescriptor,
|
|
|
|
|
command.startAddress,
|
|
|
|
|
command.buffer
|
2022-04-30 01:37:00 +01:00
|
|
|
);
|
2021-09-11 20:39:31 +01:00
|
|
|
|
2022-04-30 01:30:57 +01:00
|
|
|
return std::make_unique<Response>();
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-11 23:25:15 +00:00
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleEraseTargetMemory(EraseTargetMemory& command) {
|
2024-07-23 21:14:22 +01:00
|
|
|
this->eraseTargetMemory(command.addressSpaceDescriptor, command.memorySegmentDescriptor);
|
2022-12-11 23:25:15 +00:00
|
|
|
return std::make_unique<Response>();
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-16 22:50:06 +01:00
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleStepTargetExecution(StepTargetExecution&) {
|
2024-07-23 21:14:22 +01:00
|
|
|
this->stepTarget();
|
2022-04-30 01:30:57 +01:00
|
|
|
return std::make_unique<Response>();
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2023-09-20 23:37:54 +01:00
|
|
|
std::unique_ptr<Breakpoint> TargetControllerComponent::handleSetBreakpoint(SetBreakpoint& command) {
|
|
|
|
|
using Targets::TargetBreakpoint;
|
|
|
|
|
using Services::StringService;
|
|
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
const auto& targetBreakpointResources = this->targetDescriptor->breakpointResources;
|
2023-09-20 23:37:54 +01:00
|
|
|
if (
|
|
|
|
|
command.preferredType == Targets::TargetBreakpoint::Type::HARDWARE
|
|
|
|
|
&& this->environmentConfig.targetConfig.hardwareBreakpoints
|
2024-07-23 21:14:22 +01:00
|
|
|
&& (
|
2023-09-20 23:37:54 +01:00
|
|
|
!targetBreakpointResources.maximumHardwareBreakpoints.has_value()
|
2023-09-23 21:50:04 +01:00
|
|
|
|| this->hardwareBreakpointsByAddress.size() < (*(targetBreakpointResources.maximumHardwareBreakpoints)
|
|
|
|
|
- targetBreakpointResources.reservedHardwareBreakpoints)
|
2024-07-23 21:14:22 +01:00
|
|
|
)
|
|
|
|
|
) {
|
|
|
|
|
const auto hwBreakpoint = TargetBreakpoint{command.address, TargetBreakpoint::Type::HARDWARE};
|
|
|
|
|
this->setBreakpoint(hwBreakpoint);
|
2023-09-20 23:37:54 +01:00
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
return std::make_unique<Breakpoint>(hwBreakpoint);
|
2023-09-20 23:37:54 +01:00
|
|
|
}
|
|
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
const auto swBreakpoint = TargetBreakpoint(command.address, TargetBreakpoint::Type::SOFTWARE);
|
|
|
|
|
this->setBreakpoint(swBreakpoint);
|
2023-09-20 23:37:54 +01:00
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
return std::make_unique<Breakpoint>(swBreakpoint);
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2022-04-30 22:45:46 +01:00
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleRemoveBreakpoint(RemoveBreakpoint& command) {
|
2024-07-23 21:14:22 +01:00
|
|
|
this->removeBreakpoint(command.breakpoint);
|
2022-04-30 22:45:46 +01:00
|
|
|
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
|
|
|
}
|
|
|
|
|
|
2024-07-23 21:14:22 +01:00
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleSetStackPointer(SetTargetStackPointer& command) {
|
|
|
|
|
this->target->setStackPointer(command.stackPointer);
|
|
|
|
|
return std::make_unique<Response>();
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-16 22:50:06 +01:00
|
|
|
std::unique_ptr<TargetGpioPadStates> TargetControllerComponent::handleGetTargetGpioPadStates(
|
|
|
|
|
GetTargetGpioPadStates& command
|
2024-07-23 21:14:22 +01:00
|
|
|
) {
|
2024-08-16 22:50:06 +01:00
|
|
|
return std::make_unique<TargetGpioPadStates>(this->target->getGpioPadStates(command.padDescriptors));
|
2021-04-04 21:04:12 +01:00
|
|
|
}
|
|
|
|
|
|
2024-08-16 22:50:06 +01:00
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleSetTargetGpioPadState(SetTargetGpioPadState& command) {
|
|
|
|
|
this->target->setGpioPadState(command.padDescriptor, command.state);
|
2022-05-01 17:33:09 +01:00
|
|
|
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
|
|
|
|
2024-08-16 22:50:06 +01:00
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleEnableProgrammingMode(EnableProgrammingMode&) {
|
2022-06-05 16:13:43 +01:00
|
|
|
if (!this->target->programmingModeEnabled()) {
|
|
|
|
|
this->enableProgrammingMode();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return std::make_unique<Response>();
|
|
|
|
|
}
|
|
|
|
|
|
2024-08-16 22:50:06 +01:00
|
|
|
std::unique_ptr<Response> TargetControllerComponent::handleDisableProgrammingMode(DisableProgrammingMode&) {
|
2022-06-05 16:13:43 +01:00
|
|
|
if (this->target->programmingModeEnabled()) {
|
|
|
|
|
this->disableProgrammingMode();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return std::make_unique<Response>();
|
|
|
|
|
}
|
2021-11-11 19:05:24 +00:00
|
|
|
}
|