Files
BloomPatched/src/TargetController/TargetControllerConsole.hpp

244 lines
8.1 KiB
C++
Raw Normal View History

#pragma once
#include <cstdint>
#include <optional>
2021-05-30 16:52:32 +01:00
#include "TargetControllerState.hpp"
#include "src/EventManager/EventListener.hpp"
#include "src/EventManager/EventManager.hpp"
#include "src/Targets/TargetRegister.hpp"
#include "src/Targets/TargetMemory.hpp"
#include "src/Targets/TargetBreakpoint.hpp"
#include "src/Targets/TargetVariant.hpp"
#include "src/Targets/TargetState.hpp"
#include "src/Targets/TargetPinDescriptor.hpp"
2022-04-05 22:37:00 +01:00
#include "src/Exceptions/Exception.hpp"
namespace Bloom
{
/**
2021-10-10 23:18:06 +01:00
* The TargetControllerConsole provides an interface to the TargetController.
*/
class TargetControllerConsole
{
public:
TargetControllerConsole(EventListener& eventListener);
void setDefaultTimeout(std::chrono::milliseconds timeout) {
this->defaultTimeout = timeout;
}
2021-10-10 23:18:06 +01:00
/**
* Requests the current TargetController state from the TargetController. The TargetController should always
* respond to such a request, even when it's in a suspended state.
*
* To check if the TargetController is in an active state, isTargetControllerInService() can be used for
* convenience.
*
* @return
*/
2021-05-30 16:52:32 +01:00
TargetControllerState getTargetControllerState();
2021-10-10 23:18:06 +01:00
/**
* Retrieves the TargetController state and checks if it's currently active.
*
* @return
* True if the TargetController is currently in an active state, otherwise false.
*/
2021-05-30 16:52:32 +01:00
bool isTargetControllerInService() noexcept;
/**
* Requests the TargetDescriptor from the TargetController
*
* @return
*/
Targets::TargetDescriptor getTargetDescriptor();
/**
* Requests the TargetController to halt execution on the target.
*/
void stopTargetExecution();
/**
* Requests the TargetController to continue execution on the target.
*
* @param fromAddress
*/
void continueTargetExecution(std::optional<std::uint32_t> fromAddress);
/**
* Requests the TargetController to step execution on the target.
*
* @param fromAddress
*/
void stepTargetExecution(std::optional<std::uint32_t> fromAddress);
/**
* Requests the TargetController to read register values from the target.
*
* @param descriptors
* Descriptors of the registers to read.
*
* @return
*/
Targets::TargetRegisters readRegisters(const Targets::TargetRegisterDescriptors& descriptors);
/**
* Requests the TargetController to write register values to the target.
*
* @param registers
*/
void writeRegisters(const Targets::TargetRegisters& registers);
/**
* Requests the TargetController to read memory from the target.
*
* @param memoryType
* @param startAddress
* @param bytes
* @param excludedAddressRanges
* @return
*/
Targets::TargetMemoryBuffer readMemory(
Targets::TargetMemoryType memoryType,
std::uint32_t startAddress,
std::uint32_t bytes,
const std::set<Targets::TargetMemoryAddressRange>& excludedAddressRanges = {}
);
/**
* Requests the TargetController to write memory to the target.
*
* @param memoryType
* @param startAddress
* @param buffer
*/
void writeMemory(
Targets::TargetMemoryType memoryType,
std::uint32_t startAddress,
const Targets::TargetMemoryBuffer& buffer
);
/**
* Requests the TargetController to set a breakpoint on the target.
*
* @param breakpoint
*/
void setBreakpoint(Targets::TargetBreakpoint breakpoint);
/**
* Requests the TargetController to remove a breakpoint from the target.
*
* @param breakpoint
*/
void removeBreakpoint(Targets::TargetBreakpoint breakpoint);
/**
* Requests a pin state refresh from the TargetController, for a specific target variant.
*
* @param variantId
*/
void requestPinStates(int variantId);
/**
* Retrieves the pin states for a particular target variant.
*
* @param variantId
*/
Targets::TargetPinStateMappingType getPinStates(int variantId);
/**
* Updates the pin state on the target, for a specific pin.
*
* @param pinDescriptor
* @param pinState
*/
void setPinState(Targets::TargetPinDescriptor pinDescriptor, Targets::TargetPinState pinState);
/**
* Retrieves the current stack pointer value from the target.
*
* @return
*/
std::uint32_t getStackPointer();
/**
* Triggers a reset on the target. The target will be held in a stopped state.
*/
void resetTarget();
private:
EventListener& eventListener;
std::chrono::milliseconds defaultTimeout = std::chrono::milliseconds(20000);
/**
* Triggers an event for the TargetController and waits for a response.
*
* To use this method, the triggered event must define a 'TargetControllerResponseType' alias, which should
2021-10-10 23:18:06 +01:00
* specify the type of response expected from the TargetController.
* For an example of this, see the Events::ExtractTargetDescriptor class.
*
2021-10-10 23:18:06 +01:00
* If the TargetController fails to respond within the given time specified by the timeout argument, or it
* responds with an instance of Events::TargetControllerErrorOccurred, this function will throw an exception.
*
* @tparam TriggerEventType
*
* @param event
* Event to trigger.
*
* @param timeout
* The time, in milliseconds, to wait for the TargetController to respond to the event. If this is not
* supplied, this->defaultTimeout will be used.
*
* @return
*/
template<class TriggerEventType>
auto triggerTargetControllerEventAndWaitForResponse(
const Events::SharedEventPointerNonConst<TriggerEventType> event,
std::optional<std::chrono::milliseconds> timeout = {}
) {
using Bloom::Events::SharedEventPointer;
using Bloom::Events::TargetControllerErrorOccurred;
using ResponseEventType = typename TriggerEventType::TargetControllerResponseType;
bool deRegisterEventType = false;
if (!this->eventListener.isEventTypeRegistered<ResponseEventType>()) {
this->eventListener.registerEventType<ResponseEventType>();
deRegisterEventType = true;
}
2022-03-20 17:37:36 +00:00
EventManager::triggerEvent(event);
auto responseEvent = this->eventListener.waitForEvent<
ResponseEventType,
TargetControllerErrorOccurred
>(timeout.value_or(this->defaultTimeout), event->id);
if (deRegisterEventType) {
this->eventListener.deRegisterEventType<ResponseEventType>();
}
if (!responseEvent.has_value()) {
throw Bloom::Exceptions::Exception("Timed out waiting for response from TargetController.");
}
if (!std::holds_alternative<SharedEventPointer<ResponseEventType>>(responseEvent.value())) {
if (std::holds_alternative<SharedEventPointer<TargetControllerErrorOccurred>>(responseEvent.value())) {
auto& tcErrorEvent = std::get<SharedEventPointer<TargetControllerErrorOccurred>>(responseEvent.value());
throw Bloom::Exceptions::Exception(tcErrorEvent->errorMessage);
}
2021-12-22 23:11:18 +00:00
throw Bloom::Exceptions::Exception("Unexpected response from TargetController");
}
return std::get<SharedEventPointer<ResponseEventType>>(responseEvent.value());
}
};
}