Implemented new command-response-based interface for the TargetController
This commit is contained in:
68
src/TargetController/CommandManager.hpp
Normal file
68
src/TargetController/CommandManager.hpp
Normal file
@@ -0,0 +1,68 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <memory>
|
||||||
|
#include <chrono>
|
||||||
|
#include <optional>
|
||||||
|
|
||||||
|
#include "Commands/Command.hpp"
|
||||||
|
#include "Responses/Response.hpp"
|
||||||
|
#include "Responses/Error.hpp"
|
||||||
|
#include "TargetControllerComponent.hpp"
|
||||||
|
|
||||||
|
#include "src/Exceptions/Exception.hpp"
|
||||||
|
|
||||||
|
#include "src/Logger/Logger.hpp"
|
||||||
|
|
||||||
|
namespace Bloom::TargetController
|
||||||
|
{
|
||||||
|
class CommandManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
template<class CommandType>
|
||||||
|
requires
|
||||||
|
std::is_base_of_v<Commands::Command, CommandType>
|
||||||
|
&& std::is_base_of_v<Responses::Response, typename CommandType::SuccessResponseType>
|
||||||
|
auto sendCommandAndWaitForResponse(
|
||||||
|
std::unique_ptr<CommandType> command,
|
||||||
|
std::chrono::milliseconds timeout
|
||||||
|
) {
|
||||||
|
using SuccessResponseType = typename CommandType::SuccessResponseType;
|
||||||
|
|
||||||
|
Logger::debug("Issuing " + CommandType::name + " command to TargetController");
|
||||||
|
|
||||||
|
const auto commandId = command->id;
|
||||||
|
TargetControllerComponent::registerCommand(std::move(command));
|
||||||
|
|
||||||
|
auto optionalResponse = TargetControllerComponent::waitForResponse(commandId, timeout);
|
||||||
|
|
||||||
|
if (!optionalResponse.has_value()) {
|
||||||
|
Logger::debug(
|
||||||
|
"Timed out whilst waiting for TargetController to respond to " + CommandType::name + " command"
|
||||||
|
);
|
||||||
|
throw Exceptions::Exception("Command timed out");
|
||||||
|
}
|
||||||
|
|
||||||
|
auto& response = optionalResponse.value();
|
||||||
|
|
||||||
|
if (response->getType() == Responses::ResponseType::ERROR) {
|
||||||
|
const auto errorResponse = dynamic_cast<Responses::Error*>(response.get());
|
||||||
|
|
||||||
|
Logger::debug(
|
||||||
|
"TargetController returned error in response to " + CommandType::name + " command. Error: "
|
||||||
|
+ errorResponse->errorMessage
|
||||||
|
);
|
||||||
|
throw Exceptions::Exception(errorResponse->errorMessage);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Only downcast if the command's SuccessResponseType is not the generic Response type.
|
||||||
|
if constexpr (!std::is_same_v<SuccessResponseType, Responses::Response>) {
|
||||||
|
assert(response->getType() == SuccessResponseType::type);
|
||||||
|
return std::unique_ptr<SuccessResponseType>(
|
||||||
|
dynamic_cast<SuccessResponseType*>(response.release())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return std::move(response);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
42
src/TargetController/Commands/Command.hpp
Normal file
42
src/TargetController/Commands/Command.hpp
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <string>
|
||||||
|
#include <atomic>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "CommandTypes.hpp"
|
||||||
|
|
||||||
|
#include "src/TargetController/Responses/Response.hpp"
|
||||||
|
|
||||||
|
namespace Bloom::TargetController::Commands
|
||||||
|
{
|
||||||
|
using CommandIdType = int;
|
||||||
|
static_assert(std::atomic<CommandIdType>::is_always_lock_free);
|
||||||
|
|
||||||
|
class Command
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using SuccessResponseType = Responses::Response;
|
||||||
|
|
||||||
|
CommandIdType id = ++(Command::lastCommandId);
|
||||||
|
|
||||||
|
static constexpr CommandType type = CommandType::GENERIC;
|
||||||
|
static inline const std::string name = "GenericCommand";
|
||||||
|
|
||||||
|
Command() = default;
|
||||||
|
virtual ~Command() = default;
|
||||||
|
|
||||||
|
Command(const Command& other) = default;
|
||||||
|
Command(Command&& other) = default;
|
||||||
|
|
||||||
|
Command& operator = (const Command& other) = default;
|
||||||
|
Command& operator = (Command&& other) = default;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual CommandType getType() const {
|
||||||
|
return Command::type;
|
||||||
|
}
|
||||||
|
|
||||||
|
private:
|
||||||
|
static inline std::atomic<CommandIdType> lastCommandId = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
11
src/TargetController/Commands/CommandTypes.hpp
Normal file
11
src/TargetController/Commands/CommandTypes.hpp
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace Bloom::TargetController::Commands
|
||||||
|
{
|
||||||
|
enum class CommandType: std::uint8_t
|
||||||
|
{
|
||||||
|
GENERIC,
|
||||||
|
};
|
||||||
|
}
|
||||||
22
src/TargetController/Responses/Error.hpp
Normal file
22
src/TargetController/Responses/Error.hpp
Normal file
@@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Response.hpp"
|
||||||
|
|
||||||
|
namespace Bloom::TargetController::Responses
|
||||||
|
{
|
||||||
|
class Error: public Response
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr ResponseType type = ResponseType::ERROR;
|
||||||
|
|
||||||
|
std::string errorMessage;
|
||||||
|
|
||||||
|
explicit Error(const std::string& errorMessage)
|
||||||
|
: errorMessage(errorMessage)
|
||||||
|
{}
|
||||||
|
|
||||||
|
[[nodiscard]] ResponseType getType() const override {
|
||||||
|
return Error::type;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
25
src/TargetController/Responses/Response.hpp
Normal file
25
src/TargetController/Responses/Response.hpp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "ResponseTypes.hpp"
|
||||||
|
|
||||||
|
namespace Bloom::TargetController::Responses
|
||||||
|
{
|
||||||
|
class Response
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr ResponseType type = ResponseType::GENERIC;
|
||||||
|
|
||||||
|
Response() = default;
|
||||||
|
virtual ~Response() = default;
|
||||||
|
|
||||||
|
Response(const Response& other) = default;
|
||||||
|
Response(Response&& other) = default;
|
||||||
|
|
||||||
|
Response& operator = (const Response& other) = default;
|
||||||
|
Response& operator = (Response&& other) = default;
|
||||||
|
|
||||||
|
[[nodiscard]] virtual ResponseType getType() const {
|
||||||
|
return Response::type;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
12
src/TargetController/Responses/ResponseTypes.hpp
Normal file
12
src/TargetController/Responses/ResponseTypes.hpp
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace Bloom::TargetController::Responses
|
||||||
|
{
|
||||||
|
enum class ResponseType: std::uint8_t
|
||||||
|
{
|
||||||
|
GENERIC,
|
||||||
|
ERROR,
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -20,6 +20,9 @@ namespace Bloom::TargetController
|
|||||||
using namespace Bloom::Events;
|
using namespace Bloom::Events;
|
||||||
using namespace Bloom::Exceptions;
|
using namespace Bloom::Exceptions;
|
||||||
|
|
||||||
|
using Commands::Command;
|
||||||
|
using Commands::CommandIdType;
|
||||||
|
using Responses::Response;
|
||||||
TargetControllerComponent::TargetControllerComponent(
|
TargetControllerComponent::TargetControllerComponent(
|
||||||
const ProjectConfig& projectConfig,
|
const ProjectConfig& projectConfig,
|
||||||
const EnvironmentConfig& environmentConfig
|
const EnvironmentConfig& environmentConfig
|
||||||
@@ -41,7 +44,10 @@ namespace Bloom::TargetController
|
|||||||
this->fireTargetEvents();
|
this->fireTargetEvents();
|
||||||
}
|
}
|
||||||
|
|
||||||
this->eventListener->waitAndDispatch(60);
|
TargetControllerComponent::notifier.waitForNotification(std::chrono::milliseconds(60));
|
||||||
|
|
||||||
|
this->processQueuedCommands();
|
||||||
|
this->eventListener->dispatchCurrentEvents();
|
||||||
|
|
||||||
} catch (const DeviceFailure& exception) {
|
} catch (const DeviceFailure& exception) {
|
||||||
/*
|
/*
|
||||||
@@ -76,6 +82,48 @@ namespace Bloom::TargetController
|
|||||||
this->shutdown();
|
this->shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
void TargetControllerComponent::startup() {
|
void TargetControllerComponent::startup() {
|
||||||
this->setName("TC");
|
this->setName("TC");
|
||||||
Logger::info("Starting TargetController");
|
Logger::info("Starting TargetController");
|
||||||
@@ -102,6 +150,151 @@ namespace Bloom::TargetController
|
|||||||
this->resume();
|
this->resume();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::map<
|
||||||
|
std::string,
|
||||||
|
std::function<std::unique_ptr<DebugTool>()>
|
||||||
|
> TargetControllerComponent::getSupportedDebugTools() {
|
||||||
|
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>();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
auto avr8PdMapping = Avr8TargetDescriptionFile::getTargetDescriptionMapping();
|
||||||
|
|
||||||
|
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>>();
|
||||||
|
|
||||||
|
{
|
||||||
|
auto queueLock = TargetControllerComponent::commandQueue.acquireLock();
|
||||||
|
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.");
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
) {
|
||||||
|
auto responseMappingLock = TargetControllerComponent::responsesByCommandId.acquireLock();
|
||||||
|
TargetControllerComponent::responsesByCommandId.getValue().insert(
|
||||||
|
std::pair(commandId, std::move(response))
|
||||||
|
);
|
||||||
|
TargetControllerComponent::responsesByCommandIdCv.notify_all();
|
||||||
|
}
|
||||||
|
|
||||||
void TargetControllerComponent::checkUdevRules() {
|
void TargetControllerComponent::checkUdevRules() {
|
||||||
auto bloomRulesPath = std::string("/etc/udev/rules.d/99-bloom.rules");
|
auto bloomRulesPath = std::string("/etc/udev/rules.d/99-bloom.rules");
|
||||||
auto latestBloomRulesPath = Paths::resourcesDirPath() + "/UDevRules/99-bloom.rules";
|
auto latestBloomRulesPath = Paths::resourcesDirPath() + "/UDevRules/99-bloom.rules";
|
||||||
@@ -283,8 +476,8 @@ namespace Bloom::TargetController
|
|||||||
auto debugToolName = this->environmentConfig.debugToolConfig.name;
|
auto debugToolName = this->environmentConfig.debugToolConfig.name;
|
||||||
auto targetName = this->environmentConfig.targetConfig.name;
|
auto targetName = this->environmentConfig.targetConfig.name;
|
||||||
|
|
||||||
auto supportedDebugTools = TargetControllerComponent::getSupportedDebugTools();
|
static auto supportedDebugTools = this->getSupportedDebugTools();
|
||||||
auto supportedTargets = TargetControllerComponent::getSupportedTargets();
|
static auto supportedTargets = this->getSupportedTargets();
|
||||||
|
|
||||||
if (!supportedDebugTools.contains(debugToolName)) {
|
if (!supportedDebugTools.contains(debugToolName)) {
|
||||||
throw Exceptions::InvalidConfig(
|
throw Exceptions::InvalidConfig(
|
||||||
|
|||||||
@@ -1,6 +1,10 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <queue>
|
||||||
|
#include <condition_variable>
|
||||||
|
#include <optional>
|
||||||
|
#include <chrono>
|
||||||
#include <map>
|
#include <map>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <functional>
|
#include <functional>
|
||||||
@@ -8,6 +12,15 @@
|
|||||||
#include <QJsonArray>
|
#include <QJsonArray>
|
||||||
|
|
||||||
#include "src/Helpers/Thread.hpp"
|
#include "src/Helpers/Thread.hpp"
|
||||||
|
#include "src/Helpers/SyncSafe.hpp"
|
||||||
|
#include "src/Helpers/ConditionVariableNotifier.hpp"
|
||||||
|
|
||||||
|
// Commands
|
||||||
|
#include "Commands/Command.hpp"
|
||||||
|
|
||||||
|
// Responses
|
||||||
|
#include "Responses/Response.hpp"
|
||||||
|
|
||||||
#include "TargetControllerState.hpp"
|
#include "TargetControllerState.hpp"
|
||||||
|
|
||||||
#include "src/DebugToolDrivers/DebugTools.hpp"
|
#include "src/DebugToolDrivers/DebugTools.hpp"
|
||||||
@@ -44,7 +57,24 @@ namespace Bloom::TargetController
|
|||||||
*/
|
*/
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
|
static void registerCommand(std::unique_ptr<Commands::Command> command);
|
||||||
|
|
||||||
|
static std::optional<std::unique_ptr<Responses::Response>> waitForResponse(
|
||||||
|
Commands::CommandIdType commandId,
|
||||||
|
std::optional<std::chrono::milliseconds> timeout = std::nullopt
|
||||||
|
);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
static inline SyncSafe<
|
||||||
|
std::queue<std::unique_ptr<Commands::Command>>
|
||||||
|
> commandQueue;
|
||||||
|
|
||||||
|
static inline SyncSafe<
|
||||||
|
std::map<Commands::CommandIdType, std::unique_ptr<Responses::Response>>
|
||||||
|
> responsesByCommandId;
|
||||||
|
|
||||||
|
static inline ConditionVariableNotifier notifier = ConditionVariableNotifier();
|
||||||
|
static inline std::condition_variable responsesByCommandIdCv = std::condition_variable();
|
||||||
/**
|
/**
|
||||||
* The TC starts off in a suspended state. TargetController::resume() is invoked from the startup routine.
|
* The TC starts off in a suspended state. TargetController::resume() is invoked from the startup routine.
|
||||||
*/
|
*/
|
||||||
@@ -61,6 +91,11 @@ namespace Bloom::TargetController
|
|||||||
std::unique_ptr<Targets::Target> target = nullptr;
|
std::unique_ptr<Targets::Target> target = nullptr;
|
||||||
std::unique_ptr<DebugTool> debugTool = nullptr;
|
std::unique_ptr<DebugTool> debugTool = nullptr;
|
||||||
|
|
||||||
|
std::map<
|
||||||
|
Commands::CommandType,
|
||||||
|
std::function<std::unique_ptr<Responses::Response>(Commands::Command&)>
|
||||||
|
> commandHandlersByCommandType;
|
||||||
|
|
||||||
EventListenerPointer eventListener = std::make_shared<EventListener>("TargetControllerEventListener");
|
EventListenerPointer eventListener = std::make_shared<EventListener>("TargetControllerEventListener");
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -85,116 +120,14 @@ namespace Bloom::TargetController
|
|||||||
*/
|
*/
|
||||||
std::map<Targets::TargetMemoryType, Targets::TargetMemoryAddressRange> registerAddressRangeByMemoryType;
|
std::map<Targets::TargetMemoryType, Targets::TargetMemoryAddressRange> registerAddressRangeByMemoryType;
|
||||||
|
|
||||||
/**
|
template<class CommandType>
|
||||||
* Constructs a mapping of supported debug tool names to lambdas. The lambdas should *only* instantiate
|
void registerCommandHandler(std::function<std::unique_ptr<Responses::Response>(CommandType&)> callback) {
|
||||||
* and return an instance to the derived DebugTool class. They should not attempt to establish
|
auto parentCallback = [callback] (Commands::Command& command) {
|
||||||
* a connection to the device.
|
// Downcast the command to the expected type
|
||||||
*
|
return callback(dynamic_cast<CommandType&>(command));
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
static auto getSupportedDebugTools() {
|
|
||||||
static auto mapping = 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>();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return mapping;
|
this->commandHandlersByCommandType.insert(std::pair(CommandType::type, parentCallback));
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs a mapping of supported target names to lambdas. The lambdas should instantiate and return an
|
|
||||||
* instance to the appropriate Target class.
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
static auto getSupportedTargets() {
|
|
||||||
static auto mapping = std::map<std::string, std::function<std::unique_ptr<Targets::Target>()>>();
|
|
||||||
|
|
||||||
if (mapping.empty()) {
|
|
||||||
mapping = {
|
|
||||||
{
|
|
||||||
"avr8",
|
|
||||||
[] {
|
|
||||||
return std::make_unique<Targets::Microchip::Avr::Avr8Bit::Avr8>();
|
|
||||||
}
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
// Include all targets from AVR8 target description files
|
|
||||||
auto avr8PdMapping =
|
|
||||||
Targets::Microchip::Avr::Avr8Bit::TargetDescription::TargetDescriptionFile::getTargetDescriptionMapping();
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -215,6 +148,27 @@ namespace Bloom::TargetController
|
|||||||
*/
|
*/
|
||||||
void startup();
|
void startup();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a mapping of supported debug tool names to lambdas. The lambdas should *only* instantiate
|
||||||
|
* and return an instance to the derived DebugTool class. They should not attempt to establish
|
||||||
|
* a connection to the device.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
std::map<std::string, std::function<std::unique_ptr<DebugTool>()>> getSupportedDebugTools();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs a mapping of supported target names to lambdas. The lambdas should instantiate and return an
|
||||||
|
* instance to the appropriate Target class.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
std::map<std::string, std::function<std::unique_ptr<Targets::Target>()>> getSupportedTargets();
|
||||||
|
|
||||||
|
void processQueuedCommands();
|
||||||
|
|
||||||
|
void registerCommandResponse(Commands::CommandIdType commandId, std::unique_ptr<Responses::Response> response);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Installs Bloom's udev rules on user's machine. Rules are copied from build/Distribution/Resources/UdevRules
|
* Installs Bloom's udev rules on user's machine. Rules are copied from build/Distribution/Resources/UdevRules
|
||||||
* to /etc/udev/rules.d/. This method will report an error if Bloom isn't running as root (as root privileges
|
* to /etc/udev/rules.d/. This method will report an error if Bloom isn't running as root (as root privileges
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
|
||||||
|
#include "CommandManager.hpp"
|
||||||
#include "TargetControllerState.hpp"
|
#include "TargetControllerState.hpp"
|
||||||
|
|
||||||
#include "src/EventManager/EventListener.hpp"
|
#include "src/EventManager/EventListener.hpp"
|
||||||
@@ -171,6 +172,7 @@ namespace Bloom::TargetController
|
|||||||
void resetTarget();
|
void resetTarget();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
CommandManager commandManager = CommandManager();
|
||||||
EventListener& eventListener;
|
EventListener& eventListener;
|
||||||
|
|
||||||
std::chrono::milliseconds defaultTimeout = std::chrono::milliseconds(20000);
|
std::chrono::milliseconds defaultTimeout = std::chrono::milliseconds(20000);
|
||||||
|
|||||||
Reference in New Issue
Block a user