Added atomic sessions in TC
This commit is contained in:
@@ -1,6 +1,8 @@
|
|||||||
#include "TargetControllerService.hpp"
|
#include "TargetControllerService.hpp"
|
||||||
|
|
||||||
// Commands
|
// Commands
|
||||||
|
#include "src/TargetController/Commands/StartAtomicSession.hpp"
|
||||||
|
#include "src/TargetController/Commands/EndAtomicSession.hpp"
|
||||||
#include "src/TargetController/Commands/GetTargetDescriptor.hpp"
|
#include "src/TargetController/Commands/GetTargetDescriptor.hpp"
|
||||||
#include "src/TargetController/Commands/GetTargetState.hpp"
|
#include "src/TargetController/Commands/GetTargetState.hpp"
|
||||||
#include "src/TargetController/Commands/StopTargetExecution.hpp"
|
#include "src/TargetController/Commands/StopTargetExecution.hpp"
|
||||||
@@ -23,8 +25,12 @@
|
|||||||
#include "src/TargetController/Commands/DisableProgrammingMode.hpp"
|
#include "src/TargetController/Commands/DisableProgrammingMode.hpp"
|
||||||
#include "src/TargetController/Commands/Shutdown.hpp"
|
#include "src/TargetController/Commands/Shutdown.hpp"
|
||||||
|
|
||||||
|
#include "src/Exceptions/Exception.hpp"
|
||||||
|
|
||||||
namespace Bloom::Services
|
namespace Bloom::Services
|
||||||
{
|
{
|
||||||
|
using TargetController::Commands::StartAtomicSession;
|
||||||
|
using TargetController::Commands::EndAtomicSession;
|
||||||
using TargetController::Commands::GetTargetDescriptor;
|
using TargetController::Commands::GetTargetDescriptor;
|
||||||
using TargetController::Commands::GetTargetState;
|
using TargetController::Commands::GetTargetState;
|
||||||
using TargetController::Commands::StopTargetExecution;
|
using TargetController::Commands::StopTargetExecution;
|
||||||
@@ -67,24 +73,57 @@ namespace Bloom::Services
|
|||||||
using Targets::TargetPinState;
|
using Targets::TargetPinState;
|
||||||
using Targets::TargetPinStateMapping;
|
using Targets::TargetPinStateMapping;
|
||||||
|
|
||||||
|
TargetControllerService::AtomicSession::AtomicSession(TargetControllerService& targetControllerService)
|
||||||
|
: targetControllerService(targetControllerService)
|
||||||
|
{
|
||||||
|
if (this->targetControllerService.activeAtomicSessionId.has_value()) {
|
||||||
|
throw Exceptions::Exception("Atomic session already active in TargetControllerService instance.");
|
||||||
|
}
|
||||||
|
|
||||||
|
this->sessionId = this->targetControllerService.startAtomicSession();
|
||||||
|
this->targetControllerService.activeAtomicSessionId = this->sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
TargetControllerService::AtomicSession::~AtomicSession() {
|
||||||
|
try {
|
||||||
|
this->targetControllerService.endAtomicSession(this->sessionId);
|
||||||
|
|
||||||
|
} catch (const std::exception& exception) {
|
||||||
|
Logger::error(
|
||||||
|
"Failed to end atomic session (ID: " + std::to_string(this->sessionId) + ") - "
|
||||||
|
+ std::string(exception.what())
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (
|
||||||
|
this->targetControllerService.activeAtomicSessionId.has_value()
|
||||||
|
&& this->targetControllerService.activeAtomicSessionId == this->sessionId
|
||||||
|
) {
|
||||||
|
this->targetControllerService.activeAtomicSessionId.reset();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const TargetDescriptor& TargetControllerService::getTargetDescriptor() const {
|
const TargetDescriptor& TargetControllerService::getTargetDescriptor() const {
|
||||||
return this->commandManager.sendCommandAndWaitForResponse(
|
return this->commandManager.sendCommandAndWaitForResponse(
|
||||||
std::make_unique<GetTargetDescriptor>(),
|
std::make_unique<GetTargetDescriptor>(),
|
||||||
this->defaultTimeout
|
this->defaultTimeout,
|
||||||
|
this->activeAtomicSessionId
|
||||||
)->targetDescriptor;
|
)->targetDescriptor;
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetState TargetControllerService::getTargetState() const {
|
TargetState TargetControllerService::getTargetState() const {
|
||||||
return this->commandManager.sendCommandAndWaitForResponse(
|
return this->commandManager.sendCommandAndWaitForResponse(
|
||||||
std::make_unique<GetTargetState>(),
|
std::make_unique<GetTargetState>(),
|
||||||
this->defaultTimeout
|
this->defaultTimeout,
|
||||||
|
this->activeAtomicSessionId
|
||||||
)->targetState;
|
)->targetState;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TargetControllerService::stopTargetExecution() const {
|
void TargetControllerService::stopTargetExecution() const {
|
||||||
this->commandManager.sendCommandAndWaitForResponse(
|
this->commandManager.sendCommandAndWaitForResponse(
|
||||||
std::make_unique<StopTargetExecution>(),
|
std::make_unique<StopTargetExecution>(),
|
||||||
this->defaultTimeout
|
this->defaultTimeout,
|
||||||
|
this->activeAtomicSessionId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -104,7 +143,8 @@ namespace Bloom::Services
|
|||||||
|
|
||||||
this->commandManager.sendCommandAndWaitForResponse(
|
this->commandManager.sendCommandAndWaitForResponse(
|
||||||
std::move(resumeExecutionCommand),
|
std::move(resumeExecutionCommand),
|
||||||
this->defaultTimeout
|
this->defaultTimeout,
|
||||||
|
this->activeAtomicSessionId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -117,7 +157,8 @@ namespace Bloom::Services
|
|||||||
|
|
||||||
this->commandManager.sendCommandAndWaitForResponse(
|
this->commandManager.sendCommandAndWaitForResponse(
|
||||||
std::move(stepExecutionCommand),
|
std::move(stepExecutionCommand),
|
||||||
this->defaultTimeout
|
this->defaultTimeout,
|
||||||
|
this->activeAtomicSessionId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -126,14 +167,16 @@ namespace Bloom::Services
|
|||||||
) const {
|
) const {
|
||||||
return this->commandManager.sendCommandAndWaitForResponse(
|
return this->commandManager.sendCommandAndWaitForResponse(
|
||||||
std::make_unique<ReadTargetRegisters>(descriptorIds),
|
std::make_unique<ReadTargetRegisters>(descriptorIds),
|
||||||
this->defaultTimeout
|
this->defaultTimeout,
|
||||||
|
this->activeAtomicSessionId
|
||||||
)->registers;
|
)->registers;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TargetControllerService::writeRegisters(const TargetRegisters& registers) const {
|
void TargetControllerService::writeRegisters(const TargetRegisters& registers) const {
|
||||||
this->commandManager.sendCommandAndWaitForResponse(
|
this->commandManager.sendCommandAndWaitForResponse(
|
||||||
std::make_unique<WriteTargetRegisters>(registers),
|
std::make_unique<WriteTargetRegisters>(registers),
|
||||||
this->defaultTimeout
|
this->defaultTimeout,
|
||||||
|
this->activeAtomicSessionId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,7 +193,8 @@ namespace Bloom::Services
|
|||||||
bytes,
|
bytes,
|
||||||
excludedAddressRanges
|
excludedAddressRanges
|
||||||
),
|
),
|
||||||
this->defaultTimeout
|
this->defaultTimeout,
|
||||||
|
this->activeAtomicSessionId
|
||||||
)->data;
|
)->data;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -161,91 +205,124 @@ namespace Bloom::Services
|
|||||||
) const {
|
) const {
|
||||||
this->commandManager.sendCommandAndWaitForResponse(
|
this->commandManager.sendCommandAndWaitForResponse(
|
||||||
std::make_unique<WriteTargetMemory>(memoryType, startAddress, buffer),
|
std::make_unique<WriteTargetMemory>(memoryType, startAddress, buffer),
|
||||||
this->defaultTimeout
|
this->defaultTimeout,
|
||||||
|
this->activeAtomicSessionId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TargetControllerService::eraseMemory(Targets::TargetMemoryType memoryType) const {
|
void TargetControllerService::eraseMemory(Targets::TargetMemoryType memoryType) const {
|
||||||
this->commandManager.sendCommandAndWaitForResponse(
|
this->commandManager.sendCommandAndWaitForResponse(
|
||||||
std::make_unique<EraseTargetMemory>(memoryType),
|
std::make_unique<EraseTargetMemory>(memoryType),
|
||||||
this->defaultTimeout
|
this->defaultTimeout,
|
||||||
|
this->activeAtomicSessionId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TargetControllerService::setBreakpoint(TargetBreakpoint breakpoint) const {
|
void TargetControllerService::setBreakpoint(TargetBreakpoint breakpoint) const {
|
||||||
this->commandManager.sendCommandAndWaitForResponse(
|
this->commandManager.sendCommandAndWaitForResponse(
|
||||||
std::make_unique<SetBreakpoint>(breakpoint),
|
std::make_unique<SetBreakpoint>(breakpoint),
|
||||||
this->defaultTimeout
|
this->defaultTimeout,
|
||||||
|
this->activeAtomicSessionId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TargetControllerService::removeBreakpoint(TargetBreakpoint breakpoint) const {
|
void TargetControllerService::removeBreakpoint(TargetBreakpoint breakpoint) const {
|
||||||
this->commandManager.sendCommandAndWaitForResponse(
|
this->commandManager.sendCommandAndWaitForResponse(
|
||||||
std::make_unique<RemoveBreakpoint>(breakpoint),
|
std::make_unique<RemoveBreakpoint>(breakpoint),
|
||||||
this->defaultTimeout
|
this->defaultTimeout,
|
||||||
|
this->activeAtomicSessionId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetProgramCounter TargetControllerService::getProgramCounter() const {
|
TargetProgramCounter TargetControllerService::getProgramCounter() const {
|
||||||
return this->commandManager.sendCommandAndWaitForResponse(
|
return this->commandManager.sendCommandAndWaitForResponse(
|
||||||
std::make_unique<GetTargetProgramCounter>(),
|
std::make_unique<GetTargetProgramCounter>(),
|
||||||
this->defaultTimeout
|
this->defaultTimeout,
|
||||||
|
this->activeAtomicSessionId
|
||||||
)->programCounter;
|
)->programCounter;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TargetControllerService::setProgramCounter(TargetProgramCounter address) const {
|
void TargetControllerService::setProgramCounter(TargetProgramCounter address) const {
|
||||||
this->commandManager.sendCommandAndWaitForResponse(
|
this->commandManager.sendCommandAndWaitForResponse(
|
||||||
std::make_unique<SetTargetProgramCounter>(address),
|
std::make_unique<SetTargetProgramCounter>(address),
|
||||||
this->defaultTimeout
|
this->defaultTimeout,
|
||||||
|
this->activeAtomicSessionId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetPinStateMapping TargetControllerService::getPinStates(int variantId) const {
|
TargetPinStateMapping TargetControllerService::getPinStates(int variantId) const {
|
||||||
return this->commandManager.sendCommandAndWaitForResponse(
|
return this->commandManager.sendCommandAndWaitForResponse(
|
||||||
std::make_unique<GetTargetPinStates>(variantId),
|
std::make_unique<GetTargetPinStates>(variantId),
|
||||||
this->defaultTimeout
|
this->defaultTimeout,
|
||||||
|
this->activeAtomicSessionId
|
||||||
)->pinStatesByNumber;
|
)->pinStatesByNumber;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TargetControllerService::setPinState(TargetPinDescriptor pinDescriptor, TargetPinState pinState) const {
|
void TargetControllerService::setPinState(TargetPinDescriptor pinDescriptor, TargetPinState pinState) const {
|
||||||
this->commandManager.sendCommandAndWaitForResponse(
|
this->commandManager.sendCommandAndWaitForResponse(
|
||||||
std::make_unique<SetTargetPinState>(pinDescriptor, pinState),
|
std::make_unique<SetTargetPinState>(pinDescriptor, pinState),
|
||||||
this->defaultTimeout
|
this->defaultTimeout,
|
||||||
|
this->activeAtomicSessionId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
TargetStackPointer TargetControllerService::getStackPointer() const {
|
TargetStackPointer TargetControllerService::getStackPointer() const {
|
||||||
return this->commandManager.sendCommandAndWaitForResponse(
|
return this->commandManager.sendCommandAndWaitForResponse(
|
||||||
std::make_unique<GetTargetStackPointer>(),
|
std::make_unique<GetTargetStackPointer>(),
|
||||||
this->defaultTimeout
|
this->defaultTimeout,
|
||||||
|
this->activeAtomicSessionId
|
||||||
)->stackPointer;
|
)->stackPointer;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TargetControllerService::resetTarget() const {
|
void TargetControllerService::resetTarget() const {
|
||||||
this->commandManager.sendCommandAndWaitForResponse(
|
this->commandManager.sendCommandAndWaitForResponse(
|
||||||
std::make_unique<ResetTarget>(),
|
std::make_unique<ResetTarget>(),
|
||||||
this->defaultTimeout
|
this->defaultTimeout,
|
||||||
|
this->activeAtomicSessionId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TargetControllerService::enableProgrammingMode() const {
|
void TargetControllerService::enableProgrammingMode() const {
|
||||||
this->commandManager.sendCommandAndWaitForResponse(
|
this->commandManager.sendCommandAndWaitForResponse(
|
||||||
std::make_unique<EnableProgrammingMode>(),
|
std::make_unique<EnableProgrammingMode>(),
|
||||||
this->defaultTimeout
|
this->defaultTimeout,
|
||||||
|
this->activeAtomicSessionId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TargetControllerService::disableProgrammingMode() const {
|
void TargetControllerService::disableProgrammingMode() const {
|
||||||
this->commandManager.sendCommandAndWaitForResponse(
|
this->commandManager.sendCommandAndWaitForResponse(
|
||||||
std::make_unique<DisableProgrammingMode>(),
|
std::make_unique<DisableProgrammingMode>(),
|
||||||
this->defaultTimeout
|
this->defaultTimeout,
|
||||||
|
this->activeAtomicSessionId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void TargetControllerService::shutdown() const {
|
void TargetControllerService::shutdown() const {
|
||||||
this->commandManager.sendCommandAndWaitForResponse(
|
this->commandManager.sendCommandAndWaitForResponse(
|
||||||
std::make_unique<Shutdown>(),
|
std::make_unique<Shutdown>(),
|
||||||
this->defaultTimeout
|
this->defaultTimeout,
|
||||||
|
this->activeAtomicSessionId
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
TargetControllerService::AtomicSession TargetControllerService::makeAtomicSession() {
|
||||||
|
return AtomicSession(*this);
|
||||||
|
}
|
||||||
|
|
||||||
|
TargetController::AtomicSessionIdType TargetControllerService::startAtomicSession() {
|
||||||
|
return this->commandManager.sendCommandAndWaitForResponse(
|
||||||
|
std::make_unique<StartAtomicSession>(),
|
||||||
|
this->defaultTimeout,
|
||||||
|
this->activeAtomicSessionId
|
||||||
|
)->sessionId;
|
||||||
|
}
|
||||||
|
|
||||||
|
void TargetControllerService::endAtomicSession(TargetController::AtomicSessionIdType sessionId) {
|
||||||
|
this->commandManager.sendCommandAndWaitForResponse(
|
||||||
|
std::make_unique<EndAtomicSession>(sessionId),
|
||||||
|
this->defaultTimeout,
|
||||||
|
this->activeAtomicSessionId
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,8 +3,10 @@
|
|||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <optional>
|
#include <optional>
|
||||||
|
#include <functional>
|
||||||
|
|
||||||
#include "src/TargetController/CommandManager.hpp"
|
#include "src/TargetController/CommandManager.hpp"
|
||||||
|
#include "src/TargetController/AtomicSession.hpp"
|
||||||
|
|
||||||
#include "src/Targets/TargetState.hpp"
|
#include "src/Targets/TargetState.hpp"
|
||||||
#include "src/Targets/TargetRegister.hpp"
|
#include "src/Targets/TargetRegister.hpp"
|
||||||
@@ -23,6 +25,25 @@ namespace Bloom::Services
|
|||||||
class TargetControllerService
|
class TargetControllerService
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* RAII wrapper for atomic sessions.
|
||||||
|
*/
|
||||||
|
class AtomicSession
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
explicit AtomicSession(TargetControllerService& targetControllerService);
|
||||||
|
~AtomicSession();
|
||||||
|
|
||||||
|
AtomicSession(const AtomicSession&) = delete;
|
||||||
|
AtomicSession(const AtomicSession&&) = delete;
|
||||||
|
AtomicSession& operator = (const AtomicSession&) = delete;
|
||||||
|
AtomicSession& operator = (const AtomicSession&&) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
TargetControllerService& targetControllerService;
|
||||||
|
TargetController::AtomicSessionIdType sessionId;
|
||||||
|
};
|
||||||
|
|
||||||
TargetControllerService() = default;
|
TargetControllerService() = default;
|
||||||
|
|
||||||
void setDefaultTimeout(std::chrono::milliseconds timeout) {
|
void setDefaultTimeout(std::chrono::milliseconds timeout) {
|
||||||
@@ -192,9 +213,22 @@ namespace Bloom::Services
|
|||||||
*/
|
*/
|
||||||
void shutdown() const;
|
void shutdown() const;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Starts a new atomic session with the TC, via an TargetControllerService::AtomicSession RAII object.
|
||||||
|
* The session will end when the object is destroyed.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
TargetControllerService::AtomicSession makeAtomicSession();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
TargetController::CommandManager commandManager = TargetController::CommandManager();
|
TargetController::CommandManager commandManager = TargetController::CommandManager();
|
||||||
|
|
||||||
|
std::optional<TargetController::AtomicSessionIdType> activeAtomicSessionId = std::nullopt;
|
||||||
|
|
||||||
std::chrono::milliseconds defaultTimeout = std::chrono::milliseconds(60000);
|
std::chrono::milliseconds defaultTimeout = std::chrono::milliseconds(60000);
|
||||||
|
|
||||||
|
TargetController::AtomicSessionIdType startAtomicSession();
|
||||||
|
void endAtomicSession(TargetController::AtomicSessionIdType sessionId);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
25
src/TargetController/AtomicSession.hpp
Normal file
25
src/TargetController/AtomicSession.hpp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <atomic>
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
namespace Bloom::TargetController
|
||||||
|
{
|
||||||
|
using AtomicSessionIdType = int;
|
||||||
|
static_assert(std::atomic<AtomicSessionIdType>::is_always_lock_free);
|
||||||
|
|
||||||
|
class AtomicSession
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
const AtomicSessionIdType id = ++(AtomicSession::lastSessionId);
|
||||||
|
|
||||||
|
AtomicSession() = default;
|
||||||
|
AtomicSession(const AtomicSession&) = delete;
|
||||||
|
AtomicSession(const AtomicSession&&) = delete;
|
||||||
|
AtomicSession& operator = (AtomicSession&) = delete;
|
||||||
|
AtomicSession& operator = (AtomicSession&&) = delete;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static inline std::atomic<AtomicSessionIdType> lastSessionId = 0;
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "Commands/Command.hpp"
|
#include "Commands/Command.hpp"
|
||||||
#include "Responses/Response.hpp"
|
#include "Responses/Response.hpp"
|
||||||
#include "Responses/Error.hpp"
|
#include "Responses/Error.hpp"
|
||||||
|
#include "AtomicSession.hpp"
|
||||||
#include "TargetControllerComponent.hpp"
|
#include "TargetControllerComponent.hpp"
|
||||||
|
|
||||||
#include "src/Exceptions/Exception.hpp"
|
#include "src/Exceptions/Exception.hpp"
|
||||||
@@ -24,7 +25,8 @@ namespace Bloom::TargetController
|
|||||||
&& std::is_base_of_v<Responses::Response, typename CommandType::SuccessResponseType>
|
&& std::is_base_of_v<Responses::Response, typename CommandType::SuccessResponseType>
|
||||||
auto sendCommandAndWaitForResponse(
|
auto sendCommandAndWaitForResponse(
|
||||||
std::unique_ptr<CommandType> command,
|
std::unique_ptr<CommandType> command,
|
||||||
std::chrono::milliseconds timeout
|
std::chrono::milliseconds timeout,
|
||||||
|
std::optional<AtomicSessionIdType> atomicSessionId = std::nullopt
|
||||||
) const {
|
) const {
|
||||||
using SuccessResponseType = typename CommandType::SuccessResponseType;
|
using SuccessResponseType = typename CommandType::SuccessResponseType;
|
||||||
|
|
||||||
@@ -33,7 +35,7 @@ namespace Bloom::TargetController
|
|||||||
"Issuing " + CommandType::name + " command (ID: " + std::to_string(commandId) + ") to TargetController"
|
"Issuing " + CommandType::name + " command (ID: " + std::to_string(commandId) + ") to TargetController"
|
||||||
);
|
);
|
||||||
|
|
||||||
TargetControllerComponent::registerCommand(std::move(command));
|
TargetControllerComponent::registerCommand(std::move(command), atomicSessionId);
|
||||||
|
|
||||||
auto optionalResponse = TargetControllerComponent::waitForResponse(commandId, timeout);
|
auto optionalResponse = TargetControllerComponent::waitForResponse(commandId, timeout);
|
||||||
|
|
||||||
|
|||||||
@@ -9,6 +9,8 @@ namespace Bloom::TargetController::Commands
|
|||||||
GENERIC,
|
GENERIC,
|
||||||
SHUTDOWN,
|
SHUTDOWN,
|
||||||
GET_TARGET_DESCRIPTOR,
|
GET_TARGET_DESCRIPTOR,
|
||||||
|
START_ATOMIC_SESSION,
|
||||||
|
END_ATOMIC_SESSION,
|
||||||
STOP_TARGET_EXECUTION,
|
STOP_TARGET_EXECUTION,
|
||||||
RESUME_TARGET_EXECUTION,
|
RESUME_TARGET_EXECUTION,
|
||||||
RESET_TARGET,
|
RESET_TARGET,
|
||||||
|
|||||||
25
src/TargetController/Commands/EndAtomicSession.hpp
Normal file
25
src/TargetController/Commands/EndAtomicSession.hpp
Normal file
@@ -0,0 +1,25 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Command.hpp"
|
||||||
|
|
||||||
|
#include "src/TargetController/Responses/AtomicSessionId.hpp"
|
||||||
|
|
||||||
|
namespace Bloom::TargetController::Commands
|
||||||
|
{
|
||||||
|
class EndAtomicSession: public Command
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr CommandType type = CommandType::END_ATOMIC_SESSION;
|
||||||
|
static const inline std::string name = "EndAtomicSession";
|
||||||
|
|
||||||
|
AtomicSessionIdType sessionId;
|
||||||
|
|
||||||
|
explicit EndAtomicSession(AtomicSessionIdType sessionId)
|
||||||
|
: sessionId(sessionId)
|
||||||
|
{}
|
||||||
|
|
||||||
|
[[nodiscard]] CommandType getType() const override {
|
||||||
|
return EndAtomicSession::type;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
21
src/TargetController/Commands/StartAtomicSession.hpp
Normal file
21
src/TargetController/Commands/StartAtomicSession.hpp
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include "Command.hpp"
|
||||||
|
|
||||||
|
#include "src/TargetController/Responses/AtomicSessionId.hpp"
|
||||||
|
|
||||||
|
namespace Bloom::TargetController::Commands
|
||||||
|
{
|
||||||
|
class StartAtomicSession: public Command
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using SuccessResponseType = Responses::AtomicSessionId;
|
||||||
|
|
||||||
|
static constexpr CommandType type = CommandType::START_ATOMIC_SESSION;
|
||||||
|
static const inline std::string name = "StartAtomicSession";
|
||||||
|
|
||||||
|
[[nodiscard]] CommandType getType() const override {
|
||||||
|
return StartAtomicSession::type;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
26
src/TargetController/Responses/AtomicSessionId.hpp
Normal file
26
src/TargetController/Responses/AtomicSessionId.hpp
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <cstdint>
|
||||||
|
|
||||||
|
#include "Response.hpp"
|
||||||
|
|
||||||
|
#include "src/TargetController/AtomicSession.hpp"
|
||||||
|
|
||||||
|
namespace Bloom::TargetController::Responses
|
||||||
|
{
|
||||||
|
class AtomicSessionId: public Response
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static constexpr ResponseType type = ResponseType::ATOMIC_SESSION_ID;
|
||||||
|
|
||||||
|
AtomicSessionIdType sessionId;
|
||||||
|
|
||||||
|
explicit AtomicSessionId(AtomicSessionIdType sessionId)
|
||||||
|
: sessionId(sessionId)
|
||||||
|
{}
|
||||||
|
|
||||||
|
[[nodiscard]] ResponseType getType() const override {
|
||||||
|
return AtomicSessionId::type;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
@@ -9,6 +9,7 @@ namespace Bloom::TargetController::Responses
|
|||||||
GENERIC,
|
GENERIC,
|
||||||
ERROR,
|
ERROR,
|
||||||
STATE,
|
STATE,
|
||||||
|
ATOMIC_SESSION_ID,
|
||||||
TARGET_DESCRIPTOR,
|
TARGET_DESCRIPTOR,
|
||||||
TARGET_REGISTERS_READ,
|
TARGET_REGISTERS_READ,
|
||||||
TARGET_MEMORY_READ,
|
TARGET_MEMORY_READ,
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ namespace Bloom::TargetController
|
|||||||
using Commands::CommandIdType;
|
using Commands::CommandIdType;
|
||||||
|
|
||||||
using Commands::Command;
|
using Commands::Command;
|
||||||
|
using Commands::StartAtomicSession;
|
||||||
|
using Commands::EndAtomicSession;
|
||||||
using Commands::Shutdown;
|
using Commands::Shutdown;
|
||||||
using Commands::GetTargetDescriptor;
|
using Commands::GetTargetDescriptor;
|
||||||
using Commands::GetTargetState;
|
using Commands::GetTargetState;
|
||||||
@@ -43,6 +45,7 @@ namespace Bloom::TargetController
|
|||||||
using Commands::DisableProgrammingMode;
|
using Commands::DisableProgrammingMode;
|
||||||
|
|
||||||
using Responses::Response;
|
using Responses::Response;
|
||||||
|
using Responses::AtomicSessionId;
|
||||||
using Responses::TargetRegistersRead;
|
using Responses::TargetRegistersRead;
|
||||||
using Responses::TargetMemoryRead;
|
using Responses::TargetMemoryRead;
|
||||||
using Responses::TargetPinStates;
|
using Responses::TargetPinStates;
|
||||||
@@ -81,12 +84,23 @@ namespace Bloom::TargetController
|
|||||||
this->shutdown();
|
this->shutdown();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TargetControllerComponent::registerCommand(std::unique_ptr<Command> command) {
|
void TargetControllerComponent::registerCommand(
|
||||||
|
std::unique_ptr<Command> command,
|
||||||
|
const std::optional<AtomicSessionIdType>& atomicSessionId
|
||||||
|
) {
|
||||||
if (TargetControllerComponent::state != TargetControllerState::ACTIVE) {
|
if (TargetControllerComponent::state != TargetControllerState::ACTIVE) {
|
||||||
throw Exception("Command rejected - TargetController not in active state.");
|
throw Exception("Command rejected - TargetController not in active state.");
|
||||||
}
|
}
|
||||||
|
|
||||||
auto commandQueueLock = TargetControllerComponent::commandQueue.acquireLock();
|
if (atomicSessionId.has_value()) {
|
||||||
|
// This command is part of an atomic session - put it in the dedicated queue
|
||||||
|
const auto commandQueueLock = TargetControllerComponent::atomicSessionCommandQueue.acquireLock();
|
||||||
|
TargetControllerComponent::atomicSessionCommandQueue.getValue().push(std::move(command));
|
||||||
|
TargetControllerComponent::notifier.notify();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto commandQueueLock = TargetControllerComponent::commandQueue.acquireLock();
|
||||||
TargetControllerComponent::commandQueue.getValue().push(std::move(command));
|
TargetControllerComponent::commandQueue.getValue().push(std::move(command));
|
||||||
TargetControllerComponent::notifier.notify();
|
TargetControllerComponent::notifier.notify();
|
||||||
}
|
}
|
||||||
@@ -140,6 +154,14 @@ namespace Bloom::TargetController
|
|||||||
EventManager::registerListener(this->eventListener);
|
EventManager::registerListener(this->eventListener);
|
||||||
|
|
||||||
// Register command handlers
|
// Register command handlers
|
||||||
|
this->registerCommandHandler<StartAtomicSession>(
|
||||||
|
std::bind(&TargetControllerComponent::handleStartAtomicSession, this, std::placeholders::_1)
|
||||||
|
);
|
||||||
|
|
||||||
|
this->registerCommandHandler<EndAtomicSession>(
|
||||||
|
std::bind(&TargetControllerComponent::handleEndAtomicSession, this, std::placeholders::_1)
|
||||||
|
);
|
||||||
|
|
||||||
this->registerCommandHandler<Shutdown>(
|
this->registerCommandHandler<Shutdown>(
|
||||||
std::bind(&TargetControllerComponent::handleShutdown, this, std::placeholders::_1)
|
std::bind(&TargetControllerComponent::handleShutdown, this, std::placeholders::_1)
|
||||||
);
|
);
|
||||||
@@ -257,6 +279,12 @@ namespace Bloom::TargetController
|
|||||||
this->state = TargetControllerState::INACTIVE;
|
this->state = TargetControllerState::INACTIVE;
|
||||||
EventManager::deregisterListener(this->eventListener->getId());
|
EventManager::deregisterListener(this->eventListener->getId());
|
||||||
|
|
||||||
|
if (this->activeAtomicSession.has_value()) {
|
||||||
|
// Reject any commands on the dedicated queue
|
||||||
|
this->processQueuedCommands();
|
||||||
|
this->endActiveAtomicSession();
|
||||||
|
}
|
||||||
|
|
||||||
// Reject any commands still waiting in the queue
|
// Reject any commands still waiting in the queue
|
||||||
this->processQueuedCommands();
|
this->processQueuedCommands();
|
||||||
|
|
||||||
@@ -367,7 +395,11 @@ namespace Bloom::TargetController
|
|||||||
void TargetControllerComponent::processQueuedCommands() {
|
void TargetControllerComponent::processQueuedCommands() {
|
||||||
auto commands = std::queue<std::unique_ptr<Command>>();
|
auto commands = std::queue<std::unique_ptr<Command>>();
|
||||||
|
|
||||||
{
|
if (this->activeAtomicSession.has_value()) {
|
||||||
|
const auto queueLock = TargetControllerComponent::atomicSessionCommandQueue.acquireLock();
|
||||||
|
commands.swap(TargetControllerComponent::atomicSessionCommandQueue.getValue());
|
||||||
|
|
||||||
|
} else {
|
||||||
const auto queueLock = TargetControllerComponent::commandQueue.acquireLock();
|
const auto queueLock = TargetControllerComponent::commandQueue.acquireLock();
|
||||||
commands.swap(TargetControllerComponent::commandQueue.getValue());
|
commands.swap(TargetControllerComponent::commandQueue.getValue());
|
||||||
}
|
}
|
||||||
@@ -504,6 +536,29 @@ namespace Bloom::TargetController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void TargetControllerComponent::startAtomicSession() {
|
||||||
|
if (this->activeAtomicSession.has_value()) {
|
||||||
|
throw Exception("Atomic session already active - nested sessions are not supported");
|
||||||
|
}
|
||||||
|
|
||||||
|
this->activeAtomicSession.emplace();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TargetControllerComponent::endActiveAtomicSession() {
|
||||||
|
if (!this->activeAtomicSession.has_value()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
const auto commandQueueLock = TargetControllerComponent::atomicSessionCommandQueue.acquireLock();
|
||||||
|
auto empty = std::queue<std::unique_ptr<Commands::Command>>();
|
||||||
|
TargetControllerComponent::atomicSessionCommandQueue.getValue().swap(empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
this->activeAtomicSession.reset();
|
||||||
|
TargetControllerComponent::notifier.notify();
|
||||||
|
}
|
||||||
|
|
||||||
void TargetControllerComponent::loadRegisterDescriptors() {
|
void TargetControllerComponent::loadRegisterDescriptors() {
|
||||||
const auto& targetDescriptor = this->getTargetDescriptor();
|
const auto& targetDescriptor = this->getTargetDescriptor();
|
||||||
|
|
||||||
@@ -645,6 +700,20 @@ namespace Bloom::TargetController
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
throw Exception("Atomic session is not active");
|
||||||
|
}
|
||||||
|
|
||||||
|
this->endActiveAtomicSession();
|
||||||
|
return std::make_unique<Response>();
|
||||||
|
}
|
||||||
|
|
||||||
std::unique_ptr<Response> TargetControllerComponent::handleShutdown(Shutdown& command) {
|
std::unique_ptr<Response> TargetControllerComponent::handleShutdown(Shutdown& command) {
|
||||||
this->shutdown();
|
this->shutdown();
|
||||||
return std::make_unique<Response>();
|
return std::make_unique<Response>();
|
||||||
|
|||||||
@@ -17,9 +17,12 @@
|
|||||||
#include "src/Helpers/ConditionVariableNotifier.hpp"
|
#include "src/Helpers/ConditionVariableNotifier.hpp"
|
||||||
|
|
||||||
#include "TargetControllerState.hpp"
|
#include "TargetControllerState.hpp"
|
||||||
|
#include "AtomicSession.hpp"
|
||||||
|
|
||||||
// Commands
|
// Commands
|
||||||
#include "Commands/Command.hpp"
|
#include "Commands/Command.hpp"
|
||||||
|
#include "Commands/StartAtomicSession.hpp"
|
||||||
|
#include "Commands/EndAtomicSession.hpp"
|
||||||
#include "Commands/Shutdown.hpp"
|
#include "Commands/Shutdown.hpp"
|
||||||
#include "Commands/GetTargetDescriptor.hpp"
|
#include "Commands/GetTargetDescriptor.hpp"
|
||||||
#include "Commands/GetTargetState.hpp"
|
#include "Commands/GetTargetState.hpp"
|
||||||
@@ -44,6 +47,7 @@
|
|||||||
|
|
||||||
// Responses
|
// Responses
|
||||||
#include "Responses/Response.hpp"
|
#include "Responses/Response.hpp"
|
||||||
|
#include "Responses/AtomicSessionId.hpp"
|
||||||
#include "Responses/TargetDescriptor.hpp"
|
#include "Responses/TargetDescriptor.hpp"
|
||||||
#include "Responses/TargetState.hpp"
|
#include "Responses/TargetState.hpp"
|
||||||
#include "Responses/TargetRegistersRead.hpp"
|
#include "Responses/TargetRegistersRead.hpp"
|
||||||
@@ -88,7 +92,10 @@ namespace Bloom::TargetController
|
|||||||
*/
|
*/
|
||||||
void run();
|
void run();
|
||||||
|
|
||||||
static void registerCommand(std::unique_ptr<Commands::Command> command);
|
static void registerCommand(
|
||||||
|
std::unique_ptr<Commands::Command> command,
|
||||||
|
const std::optional<AtomicSessionIdType>& atomicSessionId
|
||||||
|
);
|
||||||
|
|
||||||
static std::optional<std::unique_ptr<Responses::Response>> waitForResponse(
|
static std::optional<std::unique_ptr<Responses::Response>> waitForResponse(
|
||||||
Commands::CommandIdType commandId,
|
Commands::CommandIdType commandId,
|
||||||
@@ -96,9 +103,15 @@ namespace Bloom::TargetController
|
|||||||
);
|
);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static inline SyncSafe<
|
static inline SyncSafe<std::queue<std::unique_ptr<Commands::Command>>> commandQueue;
|
||||||
std::queue<std::unique_ptr<Commands::Command>>
|
|
||||||
> commandQueue;
|
/**
|
||||||
|
* We have a dedicated queue for atomic sessions.
|
||||||
|
*
|
||||||
|
* During an atomic session, all commands for the session are placed into this dedicated queue.
|
||||||
|
* The TargetController will only serve commands from this dedicated queue, until the atomic session ends.
|
||||||
|
*/
|
||||||
|
static inline SyncSafe<std::queue<std::unique_ptr<Commands::Command>>> atomicSessionCommandQueue;
|
||||||
|
|
||||||
static inline SyncSafe<
|
static inline SyncSafe<
|
||||||
std::map<Commands::CommandIdType, std::unique_ptr<Responses::Response>>
|
std::map<Commands::CommandIdType, std::unique_ptr<Responses::Response>>
|
||||||
@@ -112,6 +125,8 @@ namespace Bloom::TargetController
|
|||||||
ProjectConfig projectConfig;
|
ProjectConfig projectConfig;
|
||||||
EnvironmentConfig environmentConfig;
|
EnvironmentConfig environmentConfig;
|
||||||
|
|
||||||
|
std::optional<AtomicSession> activeAtomicSession = std::nullopt;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The TargetController should be the sole owner of the target and debugTool. They are constructed and
|
* The TargetController should be the sole owner of the target and debugTool. They are constructed and
|
||||||
* destroyed within the TargetController. Under no circumstance should ownership of these resources be
|
* destroyed within the TargetController. Under no circumstance should ownership of these resources be
|
||||||
@@ -242,6 +257,10 @@ namespace Bloom::TargetController
|
|||||||
*/
|
*/
|
||||||
void releaseHardware();
|
void releaseHardware();
|
||||||
|
|
||||||
|
void startAtomicSession();
|
||||||
|
|
||||||
|
void endActiveAtomicSession();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Extracts address ranges and groups target register descriptors.
|
* Extracts address ranges and groups target register descriptors.
|
||||||
*/
|
*/
|
||||||
@@ -304,6 +323,8 @@ namespace Bloom::TargetController
|
|||||||
void onDebugSessionFinishedEvent(const Events::DebugSessionFinished& event);
|
void onDebugSessionFinishedEvent(const Events::DebugSessionFinished& event);
|
||||||
|
|
||||||
// Command handlers
|
// Command handlers
|
||||||
|
std::unique_ptr<Responses::AtomicSessionId> handleStartAtomicSession(Commands::StartAtomicSession& command);
|
||||||
|
std::unique_ptr<Responses::Response> handleEndAtomicSession(Commands::EndAtomicSession& command);
|
||||||
std::unique_ptr<Responses::Response> handleShutdown(Commands::Shutdown& command);
|
std::unique_ptr<Responses::Response> handleShutdown(Commands::Shutdown& command);
|
||||||
std::unique_ptr<Responses::TargetDescriptor> handleGetTargetDescriptor(Commands::GetTargetDescriptor& command);
|
std::unique_ptr<Responses::TargetDescriptor> handleGetTargetDescriptor(Commands::GetTargetDescriptor& command);
|
||||||
std::unique_ptr<Responses::TargetState> handleGetTargetState(Commands::GetTargetState& command);
|
std::unique_ptr<Responses::TargetState> handleGetTargetState(Commands::GetTargetState& command);
|
||||||
|
|||||||
Reference in New Issue
Block a user