- Refactored entire codebase (excluding the Insight component) to accommodate multiple target architectures (no longer specific to AVR) - Deleted 'generate SVD' GDB monitor command - I will eventually move this functionality to the Bloom website - Added unit size property to address spaces - Many other changes which I couldn't be bothered to describe here
78 lines
2.8 KiB
C++
78 lines
2.8 KiB
C++
#pragma once
|
|
|
|
#include <memory>
|
|
#include <chrono>
|
|
#include <optional>
|
|
|
|
#include "Commands/Command.hpp"
|
|
#include "Responses/Response.hpp"
|
|
#include "Responses/Error.hpp"
|
|
#include "AtomicSession.hpp"
|
|
#include "TargetControllerComponent.hpp"
|
|
|
|
#include "src/Exceptions/Exception.hpp"
|
|
|
|
#include "src/Logger/Logger.hpp"
|
|
|
|
namespace 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,
|
|
std::optional<AtomicSessionIdType> atomicSessionId = std::nullopt
|
|
) const {
|
|
using SuccessResponseType = typename CommandType::SuccessResponseType;
|
|
|
|
const auto commandId = command->id;
|
|
Logger::debug(
|
|
"Issuing " + CommandType::name + " command (ID: " + std::to_string(commandId) + ") to TargetController"
|
|
);
|
|
|
|
TargetControllerComponent::registerCommand(std::move(command), atomicSessionId);
|
|
|
|
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 (ID: "
|
|
+ std::to_string(commandId) + "). Error: " + errorResponse->errorMessage
|
|
);
|
|
throw Exceptions::Exception{errorResponse->errorMessage};
|
|
}
|
|
|
|
Logger::debug(
|
|
"Delivering response for " + CommandType::name + " command (ID: " + std::to_string(commandId) + ")"
|
|
);
|
|
|
|
// 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())
|
|
);
|
|
|
|
} else {
|
|
return std::move(response);
|
|
}
|
|
}
|
|
};
|
|
}
|