Switched to automatic storage for EDBG AVR command frame payloads that are fixed in size, in the EDBG driver.

This means we don't have to keep allocating space (using std::vector) for each command payload, when the payload is fixed in size.
Also, some general tidying of the EDBG AVR command frames.
This commit is contained in:
Nav
2022-02-27 20:29:26 +00:00
parent f28ec0f162
commit 16e20b89b6
36 changed files with 379 additions and 628 deletions

View File

@@ -97,7 +97,6 @@ add_executable(Bloom
src/DebugToolDrivers/Protocols/CMSIS-DAP/Command.cpp
src/DebugToolDrivers/Protocols/CMSIS-DAP/Response.cpp
src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrCommand.cpp
src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AvrCommandFrame.cpp
src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/CommandFrames/AVR8Generic/ReadMemory.cpp
src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrResponse.cpp
src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/ResponseFrames/AvrResponseFrame.cpp

View File

@@ -10,7 +10,15 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
class AvrCommand: public Command
{
public:
AvrCommand() {
AvrCommand(
std::size_t fragmentCount,
std::size_t fragmentNumber,
std::vector<unsigned char> commandPacket
)
: fragmentCount(fragmentCount)
, fragmentNumber(fragmentNumber)
, commandPacket(std::move(commandPacket))
{
this->setCommandId(0x80);
}
@@ -25,26 +33,14 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
return this->fragmentNumber;
}
void setFragmentNumber(std::size_t fragmentNumber) {
this->fragmentNumber = fragmentNumber;
}
[[nodiscard]] std::size_t getFragmentCount() const {
return this->fragmentCount;
}
void setFragmentCount(std::size_t fragmentCount) {
this->fragmentCount = fragmentCount;
}
[[nodiscard]] const std::vector<unsigned char>& getCommandPacket() const {
return this->commandPacket;
}
void setCommandPacket(const std::vector<unsigned char>& commandPacket) {
this->commandPacket = commandPacket;
}
private:
std::size_t fragmentNumber = 1;
std::size_t fragmentCount = 1;

View File

@@ -4,33 +4,22 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class ActivatePhysical: public Avr8GenericCommandFrame
class ActivatePhysical: public Avr8GenericCommandFrame<std::array<unsigned char, 3>>
{
public:
ActivatePhysical() = default;
explicit ActivatePhysical(bool reset): reset(reset) {};
void setReset(bool reset) {
this->reset = reset;
}
[[nodiscard]] std::vector<unsigned char> getPayload() const override {
explicit ActivatePhysical(bool reset) {
/*
* The activate physical command consists of 3 bytes:
* 1. Command ID (0x10)
* 2. Version (0x00)
* 3. Reset flag (to apply external reset)
*/
auto output = std::vector<unsigned char>(3, 0x00);
output[0] = 0x10;
output[1] = 0x00;
output[2] = static_cast<unsigned char>(this->reset);
return output;
this->payload = {
0x10,
0x00,
static_cast<unsigned char>(reset)
};
}
private:
bool reset = false;
};
}

View File

@@ -4,33 +4,21 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class Attach: public Avr8GenericCommandFrame
class Attach: public Avr8GenericCommandFrame<std::array<unsigned char, 3>>
{
public:
Attach() = default;
explicit Attach(bool breakAfterAttach): breakAfterAttach(breakAfterAttach) {};
void setBreadAfterAttach(bool breakAfterAttach) {
this->breakAfterAttach = breakAfterAttach;
}
[[nodiscard]] std::vector<unsigned char> getPayload() const override {
explicit Attach(bool breakAfterAttach) {
/*
* The attach command consists of 3 bytes:
* 1. Command ID (0x13)
* 2. Version (0x00)
* 3. Break (stop) after attach flag
*/
auto output = std::vector<unsigned char>(3, 0x00);
output[0] = 0x13;
output[1] = 0x00;
output[2] = static_cast<unsigned char>(this->breakAfterAttach);
return output;
this->payload = {
0x13,
0x00,
static_cast<unsigned char>(breakAfterAttach)
};
}
private:
bool breakAfterAttach = false;
};
}

View File

@@ -7,7 +7,8 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class Avr8GenericCommandFrame: public AvrCommandFrame
template<class PayloadContainerType>
class Avr8GenericCommandFrame: public AvrCommandFrame<PayloadContainerType>
{
public:
using ResponseFrameType = ResponseFrames::Avr8Generic::Avr8GenericResponseFrame;

View File

@@ -4,24 +4,19 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class ClearAllSoftwareBreakpoints: public Avr8GenericCommandFrame
class ClearAllSoftwareBreakpoints: public Avr8GenericCommandFrame<std::array<unsigned char, 2>>
{
public:
ClearAllSoftwareBreakpoints() {
init();
};
private:
void init() {
/*
* The clear all software breakpoints command consists of 2 bytes:
* 1. Command ID (0x45)
* 2. Version (0x00)
*/
auto payload = std::vector<unsigned char>(2);
payload[0] = 0x45;
payload[1] = 0x00;
this->setPayload(payload);
this->payload = {
0x45,
0x00,
};
}
};
}

View File

@@ -7,18 +7,10 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class ClearSoftwareBreakpoints: public Avr8GenericCommandFrame
class ClearSoftwareBreakpoints: public Avr8GenericCommandFrame<std::vector<unsigned char>>
{
public:
ClearSoftwareBreakpoints() = default;
explicit ClearSoftwareBreakpoints(std::vector<std::uint32_t> addresses): addresses(std::move(addresses)) {}
void setAddresses(const std::vector<std::uint32_t>& addresses) {
this->addresses = addresses;
}
[[nodiscard]] std::vector<unsigned char> getPayload() const override {
explicit ClearSoftwareBreakpoints(const std::vector<std::uint32_t>& addresses) {
/*
* The clear software breakpoints command consists of 2 bytes + 4*n bytes, where n is the number
* of breakpoints to clear:
@@ -27,21 +19,17 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames
* 2. Version (0x00)
* ... addresses
*/
auto output = std::vector<unsigned char>(2, 0x00);
output[0] = 0x44;
output[1] = 0x00;
this->payload = {
0x44,
0x00,
};
for (const auto& address : this->addresses) {
output.push_back(static_cast<unsigned char>(address));
output.push_back(static_cast<unsigned char>(address >> 8));
output.push_back(static_cast<unsigned char>(address >> 16));
output.push_back(static_cast<unsigned char>(address >> 24));
for (const auto& address : addresses) {
this->payload.emplace_back(static_cast<unsigned char>(address));
this->payload.emplace_back(static_cast<unsigned char>(address >> 8));
this->payload.emplace_back(static_cast<unsigned char>(address >> 16));
this->payload.emplace_back(static_cast<unsigned char>(address >> 24));
}
return output;
}
private:
std::vector<std::uint32_t> addresses;
};
}

View File

@@ -4,24 +4,19 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class DeactivatePhysical: public Avr8GenericCommandFrame
class DeactivatePhysical: public Avr8GenericCommandFrame<std::array<unsigned char, 2>>
{
public:
DeactivatePhysical() {
init();
};
private:
void init() {
/*
* The deactivate physical command consists of 2 bytes:
* 1. Command ID (0x11)
* 2. Version (0x00)
*/
auto payload = std::vector<unsigned char>(2);
payload[0] = 0x11;
payload[1] = 0x00;
this->setPayload(payload);
this->payload = {
0x11,
0x00
};
}
};
}

View File

@@ -4,24 +4,19 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class Detach: public Avr8GenericCommandFrame
class Detach: public Avr8GenericCommandFrame<std::array<unsigned char, 2>>
{
public:
Detach() {
init();
};
private:
void init() {
/*
* The detach command consists of 2 bytes:
* 1. Command ID (0x11)
* 1. Command ID (0x14)
* 2. Version (0x00)
*/
auto payload = std::vector<unsigned char>(2);
payload[0] = 0x11;
payload[1] = 0x00;
this->setPayload(payload);
this->payload = {
0x14,
0x00
};
}
};
}

View File

@@ -4,24 +4,19 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class DisableDebugWire: public Avr8GenericCommandFrame
class DisableDebugWire: public Avr8GenericCommandFrame<std::array<unsigned char, 2>>
{
public:
DisableDebugWire() {
init();
};
private:
void init() {
/*
* The disable debugWire command consists of 2 bytes:
* 1. Command ID (0x17)
* 2. Version (0x00)
*/
auto payload = std::vector<unsigned char>(2);
payload[0] = 0x17;
payload[1] = 0x00;
this->setPayload(payload);
this->payload = {
0x17,
0x00
};
}
};
}

View File

@@ -5,26 +5,21 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class GetDeviceId: public Avr8GenericCommandFrame
class GetDeviceId: public Avr8GenericCommandFrame<std::array<unsigned char, 2>>
{
public:
using ResponseFrameType = ResponseFrames::Avr8Generic::GetDeviceId;
GetDeviceId() {
init();
};
private:
void init() {
/*
* The get device ID command consists of 2 bytes:
* 1. Command ID (0x12)
* 2. Version (0x00)
*/
auto payload = std::vector<unsigned char>(2);
payload[0] = 0x12;
payload[1] = 0x00;
this->setPayload(payload);
this->payload = {
0x12,
0x00
};
}
};
}

View File

@@ -6,28 +6,10 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class GetParameter: public Avr8GenericCommandFrame
class GetParameter: public Avr8GenericCommandFrame<std::array<unsigned char, 5>>
{
public:
GetParameter() = default;
explicit GetParameter(const Avr8EdbgParameter& parameter) {
this->setParameter(parameter);
}
GetParameter(const Avr8EdbgParameter& parameter, std::uint8_t size): GetParameter(parameter) {
this->setSize(size);
}
void setParameter(const Avr8EdbgParameter& parameter) {
this->parameter = parameter;
}
void setSize(std::uint8_t size) {
this->size = size;
}
[[nodiscard]] std::vector<unsigned char> getPayload() const override {
GetParameter(const Avr8EdbgParameter& parameter, std::uint8_t size) {
/*
* The get param command consists of 5 bytes:
* 1. Command ID (0x02)
@@ -36,18 +18,13 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames
* 4. Param ID (Avr8Parameter::id)
* 5. Param value length (this->size)
*/
auto output = std::vector<unsigned char>(5, 0x00);
output[0] = 0x02;
output[1] = 0x00;
output[2] = static_cast<unsigned char>(this->parameter.context);
output[3] = static_cast<unsigned char>(this->parameter.id);
output[4] = static_cast<unsigned char>(this->size);
return output;
this->payload = {
0x02,
0x00,
static_cast<unsigned char>(parameter.context),
static_cast<unsigned char>(parameter.id),
static_cast<unsigned char>(size)
};
}
private:
Avr8EdbgParameter parameter;
std::uint8_t size = 0;
};
}

View File

@@ -5,26 +5,21 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class GetProgramCounter: public Avr8GenericCommandFrame
class GetProgramCounter: public Avr8GenericCommandFrame<std::array<unsigned char, 2>>
{
public:
using ResponseFrameType = ResponseFrames::Avr8Generic::GetProgramCounter;
GetProgramCounter() {
init();
};
private:
void init() {
/*
* The PC Read command consists of 2 bytes:
* 1. Command ID (0x35)
* 2. Version (0x00)
*/
auto payload = std::vector<unsigned char>(2);
payload[0] = 0x35;
payload[1] = 0x00;
this->setPayload(payload);
this->payload = {
0x35,
0x00,
};
}
};
}

View File

@@ -5,7 +5,12 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
std::vector<unsigned char> ReadMemory::getPayload() const {
ReadMemory::ReadMemory(
const Avr8MemoryType& type,
std::uint32_t address,
std::uint32_t bytes,
const std::set<std::uint32_t>& excludedAddresses
) {
/*
* The read memory command consists of 11/11 + (this->bytes / 8) bytes:
* 1. Command ID (0x21 for the general read memory command, 0x22 for reading with a mask)
@@ -15,43 +20,41 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames
* 5. Number of bytes to read (4 bytes)
* 6. Mask to apply (this->bytes / 8) - only required if we're using the masked read command (command ID 0x22).
*/
auto output = std::vector<unsigned char>(11, 0x00);
output[0] = this->excludedAddresses.empty() ? 0x21 : 0x22;
output[1] = 0x00;
output[2] = static_cast<unsigned char>(this->type);
output[3] = static_cast<unsigned char>(this->address);
output[4] = static_cast<unsigned char>(this->address >> 8);
output[5] = static_cast<unsigned char>(this->address >> 16);
output[6] = static_cast<unsigned char>(this->address >> 24);
output[7] = static_cast<unsigned char>(this->bytes);
output[8] = static_cast<unsigned char>(this->bytes >> 8);
output[9] = static_cast<unsigned char>(this->bytes >> 16);
output[10] = static_cast<unsigned char>(this->bytes >> 24);
this->payload = std::vector<unsigned char>(11, 0x00);
this->payload[0] = excludedAddresses.empty() ? 0x21 : 0x22;
this->payload[1] = 0x00;
this->payload[2] = static_cast<unsigned char>(type);
this->payload[3] = static_cast<unsigned char>(address);
this->payload[4] = static_cast<unsigned char>(address >> 8);
this->payload[5] = static_cast<unsigned char>(address >> 16);
this->payload[6] = static_cast<unsigned char>(address >> 24);
this->payload[7] = static_cast<unsigned char>(bytes);
this->payload[8] = static_cast<unsigned char>(bytes >> 8);
this->payload[9] = static_cast<unsigned char>(bytes >> 16);
this->payload[10] = static_cast<unsigned char>(bytes >> 24);
if (!this->excludedAddresses.empty()) {
const auto endAddress = this->address + (this->bytes - 1);
if (!excludedAddresses.empty()) {
const auto endAddress = address + (bytes - 1);
constexpr auto byteBitSize = std::numeric_limits<unsigned char>::digits;
auto byteBitset = std::bitset<byteBitSize>();
byteBitset.reset();
for (std::uint32_t address = this->address; address <= endAddress; address++) {
auto addressIndex = address - this->address;
for (std::uint32_t address = address; address <= endAddress; address++) {
auto addressIndex = address - address;
auto bitIndex = static_cast<std::size_t>(
addressIndex - (std::floor(addressIndex / byteBitSize) * byteBitSize)
);
if (!this->excludedAddresses.contains(address)) {
byteBitset[bitIndex] = 1;
if (!excludedAddresses.contains(address)) {
byteBitset[bitIndex] = true;
}
if (address > 0 && (bitIndex == 7 || address == endAddress)) {
output.emplace_back(byteBitset.to_ulong());
this->payload.emplace_back(byteBitset.to_ulong());
byteBitset.reset();
}
}
}
return output;
}
}

View File

@@ -8,35 +8,16 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class ReadMemory: public Avr8GenericCommandFrame
class ReadMemory: public Avr8GenericCommandFrame<std::vector<unsigned char>>
{
public:
using ResponseFrameType = ResponseFrames::Avr8Generic::ReadMemory;
ReadMemory() = default;
void setType(const Avr8MemoryType& type) {
this->type = type;
}
void setAddress(std::uint32_t address) {
this->address = address;
}
void setBytes(std::uint32_t bytes) {
this->bytes = bytes;
}
void setExcludedAddresses(const std::set<std::uint32_t>& excludedAddresses) {
this->excludedAddresses = excludedAddresses;
}
[[nodiscard]] std::vector<unsigned char> getPayload() const override;
private:
Avr8MemoryType type = Avr8MemoryType::SRAM;
std::uint32_t address = 0;
std::uint32_t bytes = 0;
std::set<std::uint32_t> excludedAddresses;
ReadMemory(
const Avr8MemoryType& type,
std::uint32_t address,
std::uint32_t bytes,
const std::set<std::uint32_t>& excludedAddresses = {}
);
};
}

View File

@@ -4,32 +4,21 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class Reset: public Avr8GenericCommandFrame
class Reset: public Avr8GenericCommandFrame<std::array<unsigned char, 3>>
{
public:
Reset() = default;
explicit Reset(bool stopAtMainAddress): stopAtMainAddress(stopAtMainAddress) {};
void setStopAtMainAddress(bool stopAtMainAddress) {
this->stopAtMainAddress = stopAtMainAddress;
}
[[nodiscard]] std::vector<unsigned char> getPayload() const override {
explicit Reset(bool stopAtMainAddress = false) {
/*
* The reset command consists of 3 bytes:
* 1. Command ID (0x30)
* 2. Version (0x00)
* 3. "Level" (0x01 to stop at boot reset vector or 0x02 to stop at main address)
*/
auto output = std::vector<unsigned char>(3, 0x00);
output[0] = 0x30;
output[1] = 0x00;
output[2] = this->stopAtMainAddress ? 0x02 : 0x01;
return output;
this->payload = {
0x30,
0x00,
static_cast<unsigned char>(stopAtMainAddress ? 0x02 : 0x01),
};
}
private:
bool stopAtMainAddress = false;
};
}

View File

@@ -4,24 +4,19 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class Run: public Avr8GenericCommandFrame
class Run: public Avr8GenericCommandFrame<std::array<unsigned char, 2>>
{
public:
Run() {
init();
};
private:
void init() {
/*
* The run command consists of 2 bytes:
* 1. Command ID (0x32)
* 2. Version (0x00)
*/
auto payload = std::vector<unsigned char>(2);
payload[0] = 0x32;
payload[1] = 0x00;
this->setPayload(payload);
this->payload = {
0x32,
0x00,
};
}
};
}

View File

@@ -6,18 +6,10 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class RunTo: public Avr8GenericCommandFrame
class RunTo: public Avr8GenericCommandFrame<std::array<unsigned char, 6>>
{
public:
RunTo() = default;
explicit RunTo(const std::uint32_t& address): address(address) {}
void setAddress(const std::uint32_t& address) {
this->address = address;
}
[[nodiscard]] std::vector<unsigned char> getPayload() const override {
explicit RunTo(const std::uint32_t& address) {
/*
* The run-to command consists of 6 bytes:
*
@@ -25,21 +17,18 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames
* 2. Version (0x00)
* 3. Address to run to (4 bytes)
*/
auto output = std::vector<unsigned char>(6, 0x00);
output[0] = 0x33;
output[1] = 0x00;
// The address to run to needs to be the 16-bit word address, not the byte address.
auto wordAddress = this->address / 2;
output[2] = (static_cast<unsigned char>(wordAddress));
output[3] = (static_cast<unsigned char>(wordAddress >> 8));
output[4] = (static_cast<unsigned char>(wordAddress >> 16));
output[5] = (static_cast<unsigned char>(wordAddress >> 24));
const auto wordAddress = address / 2;
return output;
this->payload = {
0x33,
0x00,
static_cast<unsigned char>(wordAddress),
static_cast<unsigned char>(wordAddress >> 8),
static_cast<unsigned char>(wordAddress >> 16),
static_cast<unsigned char>(wordAddress >> 24),
};
}
private:
std::uint32_t address = 0;
};
}

View File

@@ -4,36 +4,10 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class SetParameter: public Avr8GenericCommandFrame
class SetParameter: public Avr8GenericCommandFrame<std::vector<unsigned char>>
{
public:
SetParameter() = default;
explicit SetParameter(const Avr8EdbgParameter& parameter) {
this->setParameter(parameter);
}
SetParameter(const Avr8EdbgParameter& parameter, const std::vector<unsigned char>& value): SetParameter(parameter) {
this->setValue(value);
}
SetParameter(const Avr8EdbgParameter& parameter, unsigned char value): SetParameter(parameter) {
this->setValue(value);
}
void setParameter(const Avr8EdbgParameter& parameter) {
this->parameter = parameter;
}
void setValue(const std::vector<unsigned char>& value) {
this->value = value;
}
void setValue(unsigned char value) {
this->value.resize(1, value);
}
[[nodiscard]] std::vector<unsigned char> getPayload() const override {
SetParameter(const Avr8EdbgParameter& parameter, const std::vector<unsigned char>& value) {
/*
* The set param command consists of this->value.size() + 5 bytes. The first five bytes consist of:
* 1. Command ID (0x01)
@@ -43,19 +17,13 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames
* 5. Param value length (this->value.size()) - this is only one byte in size, so its value should
* never exceed 255.
*/
auto output = std::vector<unsigned char>(this->value.size() + 5, 0x00);
output[0] = 0x01;
output[1] = 0x00;
output[2] = static_cast<unsigned char>(this->parameter.context);
output[3] = static_cast<unsigned char>(this->parameter.id);
output[4] = static_cast<unsigned char>(this->value.size());
output.insert(output.begin() + 5, this->value.begin(), this->value.end());
return output;
this->payload = std::vector<unsigned char>(value.size() + 5, 0x00);
this->payload[0] = 0x01;
this->payload[1] = 0x00;
this->payload[2] = static_cast<unsigned char>(parameter.context);
this->payload[3] = static_cast<unsigned char>(parameter.id);
this->payload[4] = static_cast<unsigned char>(value.size());
this->payload.insert(this->payload.begin() + 5, value.begin(), value.end());
}
private:
Avr8EdbgParameter parameter;
std::vector<unsigned char> value;
};
}

View File

@@ -6,30 +6,24 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class SetProgramCounter: public Avr8GenericCommandFrame
class SetProgramCounter: public Avr8GenericCommandFrame<std::array<unsigned char, 6>>
{
public:
explicit SetProgramCounter(std::uint32_t programCounter): programCounter(programCounter) {}
[[nodiscard]] std::vector<unsigned char> getPayload() const override {
explicit SetProgramCounter(std::uint32_t programCounter) {
/*
* The PC write command consists of 6 bytes:
* 1. Command ID (0x01)
* 1. Command ID (0x36)
* 2. Version (0x00)
* 3. PC (4 bytes, LSB)
*/
auto output = std::vector<unsigned char>(6, 0x00);
output[0] = 0x36;
output[1] = 0x00;
output[2] = static_cast<unsigned char>(this->programCounter);
output[3] = static_cast<unsigned char>(this->programCounter >> 8);
output[4] = static_cast<unsigned char>(this->programCounter >> 16);
output[5] = static_cast<unsigned char>(this->programCounter >> 24);
return output;
this->payload = {
0x36,
0x00,
static_cast<unsigned char>(programCounter),
static_cast<unsigned char>(programCounter >> 8),
static_cast<unsigned char>(programCounter >> 16),
static_cast<unsigned char>(programCounter >> 24),
};
}
private:
std::uint32_t programCounter = 0;
};
}

View File

@@ -7,18 +7,10 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class SetSoftwareBreakpoints: public Avr8GenericCommandFrame
class SetSoftwareBreakpoints: public Avr8GenericCommandFrame<std::vector<unsigned char>>
{
public:
SetSoftwareBreakpoints() = default;
explicit SetSoftwareBreakpoints(std::vector<std::uint32_t> addresses): addresses(std::move(addresses)) {}
void setAddresses(const std::vector<std::uint32_t>& addresses) {
this->addresses = addresses;
}
[[nodiscard]] std::vector<unsigned char> getPayload() const override {
explicit SetSoftwareBreakpoints(const std::vector<std::uint32_t>& addresses) {
/*
* The set software breakpoint command consists of 2 bytes + 4*n bytes, where n is the number
* of breakpoints to set:
@@ -27,21 +19,17 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames
* 2. Version (0x00)
* ... addresses
*/
auto output = std::vector<unsigned char>(2, 0x00);
output[0] = 0x43;
output[1] = 0x00;
this->payload = {
0x43,
0x00,
};
for (const auto& address : this->addresses) {
output.push_back(static_cast<unsigned char>(address));
output.push_back(static_cast<unsigned char>(address >> 8));
output.push_back(static_cast<unsigned char>(address >> 16));
output.push_back(static_cast<unsigned char>(address >> 24));
for (const auto& address : addresses) {
this->payload.emplace_back(static_cast<unsigned char>(address));
this->payload.emplace_back(static_cast<unsigned char>(address >> 8));
this->payload.emplace_back(static_cast<unsigned char>(address >> 16));
this->payload.emplace_back(static_cast<unsigned char>(address >> 24));
}
return output;
}
private:
std::vector<std::uint32_t> addresses;
};
}

View File

@@ -6,39 +6,27 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class SetXmegaSoftwareBreakpoint: public Avr8GenericCommandFrame
class SetXmegaSoftwareBreakpoint: public Avr8GenericCommandFrame<std::array<unsigned char, 15>>
{
public:
SetXmegaSoftwareBreakpoint() = default;
explicit SetXmegaSoftwareBreakpoint(std::uint32_t address): address(address) {}
void setAddress(std::uint32_t address) {
this->address = address;
explicit SetXmegaSoftwareBreakpoint(std::uint32_t address) {
this->payload = {
0x42,
0x00,
static_cast<unsigned char>(address),
static_cast<unsigned char>(address >> 8),
static_cast<unsigned char>(address >> 16),
static_cast<unsigned char>(address >> 24),
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x00,
0x01,
0x00,
};
}
[[nodiscard]] std::vector<unsigned char> getPayload() const override {
/*
* The set software breakpoint command consists of 6 bytes bytes
*
* 1. Command ID (0x42)
* 2. Version (0x00)
* 3. Address (4 bytes)
*/
auto output = std::vector<unsigned char>(15, 0x00);
output[0] = 0x42;
output[1] = 0x00;
output[2] = static_cast<unsigned char>(address);
output[3] = static_cast<unsigned char>(address >> 8);
output[4] = static_cast<unsigned char>(address >> 16);
output[5] = static_cast<unsigned char>(address >> 24);
output[13] = 0x01; // One breakpoint
output[14] = 0x00;
return output;
}
private:
std::uint32_t address = 0;
};
}

View File

@@ -4,12 +4,10 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class Step: public Avr8GenericCommandFrame
class Step: public Avr8GenericCommandFrame<std::array<unsigned char, 4>>
{
public:
Step() = default;
[[nodiscard]] std::vector<unsigned char> getPayload() const override {
Step() {
/*
* The step command consists of 4 bytes:
* 1. Command ID (0x34)
@@ -17,13 +15,12 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames
* 3. Level (0x01 for instruction level step, 0x02 for statement level step)
* 4. Mode (0x00 for step over, 0x01 for step into, 0x02 for step out)
*/
auto output = std::vector<unsigned char>(4, 0x00);
output[0] = 0x34;
output[1] = 0x00;
output[2] = 0x01;
output[3] = 0x01;
return output;
this->payload = {
0x34,
0x00,
0x01,
0x01,
};
}
};
}

View File

@@ -4,32 +4,21 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class Stop: public Avr8GenericCommandFrame
class Stop: public Avr8GenericCommandFrame<std::array<unsigned char, 3>>
{
public:
Stop() = default;
explicit Stop(bool stopImmediately): stopImmediately(stopImmediately) {};
void setStopImmediately(bool stopImmediately) {
this->stopImmediately = stopImmediately;
}
[[nodiscard]] std::vector<unsigned char> getPayload() const override {
explicit Stop(bool stopImmediately = true) {
/*
* The stop command consists of 3 bytes:
* 1. Command ID (0x31)
* 2. Version (0x00)
* 3. Stop immediately (0x01 to stop immediately or 0x02 to stop at the next symbol)
*/
auto output = std::vector<unsigned char>(3, 0x00);
output[0] = 0x31;
output[1] = 0x00;
output[2] = this->stopImmediately ? 0x01 : 0x02;
return output;
this->payload = {
0x31,
0x00,
static_cast<unsigned char>(stopImmediately ? 0x01 : 0x02),
};
}
private:
bool stopImmediately = true;
};
}

View File

@@ -7,24 +7,10 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{
class WriteMemory: public Avr8GenericCommandFrame
class WriteMemory: public Avr8GenericCommandFrame<std::vector<unsigned char>>
{
public:
WriteMemory() = default;
void setType(const Avr8MemoryType& type) {
this->type = type;
}
void setAddress(std::uint32_t address) {
this->address = address;
}
void setBuffer(const Targets::TargetMemoryBuffer& buffer) {
this->buffer = buffer;
}
[[nodiscard]] std::vector<unsigned char> getPayload() const override {
WriteMemory(const Avr8MemoryType& type, std::uint32_t address, const Targets::TargetMemoryBuffer& buffer) {
/*
* The write memory command consists of 12 bytes + the buffer size:
* 1. Command ID (0x23)
@@ -35,32 +21,25 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames
* 6. Asynchronous flag (0x00 for "write first, then reply" and 0x01 for "reply first, then write")
* 7. Buffer
*/
auto output = std::vector<unsigned char>(12, 0x00);
output[0] = 0x23;
output[1] = 0x00;
output[2] = static_cast<unsigned char>(this->type);
output[3] = static_cast<unsigned char>(this->address);
output[4] = static_cast<unsigned char>(this->address >> 8);
output[5] = static_cast<unsigned char>(this->address >> 16);
output[6] = static_cast<unsigned char>(this->address >> 24);
this->payload = std::vector<unsigned char>(12 + buffer.size(), 0x00);
this->payload[0] = 0x23;
this->payload[1] = 0x00;
this->payload[2] = static_cast<unsigned char>(type);
this->payload[3] = static_cast<unsigned char>(address);
this->payload[4] = static_cast<unsigned char>(address >> 8);
this->payload[5] = static_cast<unsigned char>(address >> 16);
this->payload[6] = static_cast<unsigned char>(address >> 24);
auto bytesToWrite = static_cast<std::uint32_t>(this->buffer.size());
output[7] = static_cast<unsigned char>(bytesToWrite);
output[8] = static_cast<unsigned char>(bytesToWrite >> 8);
output[9] = static_cast<unsigned char>(bytesToWrite >> 16);
output[10] = static_cast<unsigned char>(bytesToWrite >> 24);
auto bytesToWrite = static_cast<std::uint32_t>(buffer.size());
this->payload[7] = static_cast<unsigned char>(bytesToWrite);
this->payload[8] = static_cast<unsigned char>(bytesToWrite >> 8);
this->payload[9] = static_cast<unsigned char>(bytesToWrite >> 16);
this->payload[10] = static_cast<unsigned char>(bytesToWrite >> 24);
// We always set the async flag to 0x00 ("write first, then reply")
output[11] = 0x00;
this->payload[11] = 0x00;
output.insert(output.end(), this->buffer.begin(), this->buffer.end());
return output;
this->payload.insert(this->payload.begin() + 12, buffer.begin(), buffer.end());
}
private:
Avr8MemoryType type = Avr8MemoryType::SRAM;
std::uint32_t address = 0;
Targets::TargetMemoryBuffer buffer;
};
}

View File

@@ -1,64 +0,0 @@
#include "AvrCommandFrame.hpp"
#include <math.h>
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
{
std::vector<AvrCommand> AvrCommandFrame::generateAvrCommands(std::size_t maximumCommandPacketSize) const {
auto rawCommandFrame = static_cast<std::vector<unsigned char>>(*this);
std::size_t commandFrameSize = rawCommandFrame.size();
auto commandsRequired = static_cast<std::size_t>(
ceil(static_cast<float>(commandFrameSize) / static_cast<float>(maximumCommandPacketSize))
);
std::vector<AvrCommand> avrCommands;
std::size_t copiedPacketSize = 0;
for (std::size_t i = 0; i < commandsRequired; i++) {
AvrCommand avrCommand;
avrCommand.setFragmentCount(commandsRequired);
avrCommand.setFragmentNumber(i + 1);
auto commandPacket = avrCommand.getCommandPacket();
// If we're on the last packet, the packet size will be what ever is left of the AvrCommandFrame
std::size_t commandPacketSize = ((i + 1) != commandsRequired) ? maximumCommandPacketSize
: (commandFrameSize - (maximumCommandPacketSize * i));
commandPacket.insert(
commandPacket.end(),
rawCommandFrame.begin() + static_cast<long>(copiedPacketSize),
rawCommandFrame.begin() + static_cast<long>(copiedPacketSize + commandPacketSize)
);
avrCommand.setCommandPacket(commandPacket);
avrCommands.push_back(avrCommand);
copiedPacketSize += commandPacketSize;
}
return avrCommands;
}
AvrCommandFrame::operator std::vector<unsigned char>() const {
auto data = this->getPayload();
auto dataSize = data.size();
auto rawCommand = std::vector<unsigned char>(5);
rawCommand[0] = this->SOF;
rawCommand[1] = this->getProtocolVersion();
rawCommand[2] = static_cast<unsigned char>(this->getSequenceId());
rawCommand[3] = static_cast<unsigned char>(this->getSequenceId() >> 8);
rawCommand[4] = static_cast<unsigned char>(this->getProtocolHandlerId());
if (dataSize > 0) {
rawCommand.insert(
rawCommand.end(),
data.begin(),
data.end()
);
}
return rawCommand;
}
}

View File

@@ -4,6 +4,9 @@
#include <vector>
#include <memory>
#include <limits>
#include <cmath>
#include <atomic>
#include <array>
#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/Command.hpp"
#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/Edbg.hpp"
@@ -12,27 +15,59 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
{
static inline std::atomic<std::uint16_t> LAST_SEQUENCE_ID = 0;
template <class PayloadContainerType = std::vector<unsigned char>>
class AvrCommandFrame
{
/*
* Every AVR command frame contains a payload. For many commands, the payload size is fixed, meaning we can
* use automatic storage. In other cases, the size of the payload is determined at runtime, requiring the use
* of dynamic storage.
*
* For example, consider the Get Device ID command from the AVR8 Generic Protocol. The size of the payload
* for this command is fixed at 2 bytes. So there is no need to use dynamic storage duration for the payload.
*
* Now consider the Write Memory command from the same protocol. The payload size for that command depends
* on the size of memory we wish to write, which is not known at compile time. For this command, the payload
* would have dynamic storage.
*
* For the above reason, the AvrCommandFrame class is a template class in which the payload container type can
* be specified for individual commands.
*
* For now, we only permit two payload container types:
* - std::array<unsigned char> for payloads with automatic storage duration.
* - std::vector<unsigned char> for payloads with dynamic storage duration.
*/
static_assert(
(
std::is_same_v<PayloadContainerType, std::vector<unsigned char>>
|| std::is_same_v<typename PayloadContainerType::value_type, unsigned char>
),
"Invalid payload container type - must be an std::array<unsigned char, X> or an std::vector<unsigned char>"
);
public:
using ResponseFrameType = AvrResponseFrame;
AvrCommandFrame() {
if (AvrCommandFrame::lastSequenceId < std::numeric_limits<decltype(AvrCommandFrame::lastSequenceId)>::max()) {
this->sequenceId = ++(AvrCommandFrame::lastSequenceId);
if (LAST_SEQUENCE_ID < std::numeric_limits<decltype(LAST_SEQUENCE_ID)>::max()) {
this->sequenceId = ++(LAST_SEQUENCE_ID);
} else {
this->sequenceId = 0;
AvrCommandFrame::lastSequenceId = 0;
LAST_SEQUENCE_ID = 0;
}
};
virtual ~AvrCommandFrame() = default;
AvrCommandFrame(const AvrCommandFrame& other) = default;
AvrCommandFrame(AvrCommandFrame&& other) = default;
AvrCommandFrame(AvrCommandFrame&& other) noexcept = default;
AvrCommandFrame& operator = (const AvrCommandFrame& other) = default;
AvrCommandFrame& operator = (AvrCommandFrame&& other) = default;
AvrCommandFrame& operator = (AvrCommandFrame&& other) noexcept = default;
[[nodiscard]] unsigned char getProtocolVersion() const {
return this->protocolVersion;
@@ -58,12 +93,38 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
this->protocolHandlerID = static_cast<ProtocolHandlerId>(protocolHandlerId);
}
[[nodiscard]] virtual std::vector<unsigned char> getPayload() const {
[[nodiscard]] virtual const PayloadContainerType& getPayload() const {
return this->payload;
}
};
void setPayload(const std::vector<unsigned char>& payload) {
this->payload = payload;
/**
* Converts the command frame into a container of unsigned char - a raw buffer to send to the EDBG device.
*
* @return
*/
[[nodiscard]] auto getRawCommandFrame() const {
auto data = this->getPayload();
const auto dataSize = data.size();
auto rawCommand = std::vector<unsigned char>(5);
rawCommand[0] = this->SOF;
rawCommand[1] = this->getProtocolVersion();
rawCommand[2] = static_cast<unsigned char>(this->getSequenceId());
rawCommand[3] = static_cast<unsigned char>(this->getSequenceId() >> 8);
rawCommand[4] = static_cast<unsigned char>(this->getProtocolHandlerId());
if (dataSize > 0) {
rawCommand.insert(
rawCommand.end(),
data.begin(),
data.end()
);
}
return rawCommand;
}
/**
@@ -83,14 +144,37 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
* @return
* A vector of sequenced AVRCommands, each containing a segment of the AvrCommandFrame.
*/
[[nodiscard]] std::vector<AvrCommand> generateAvrCommands(std::size_t maximumCommandPacketSize) const;
[[nodiscard]] std::vector<AvrCommand> generateAvrCommands(std::size_t maximumCommandPacketSize) const {
auto rawCommandFrame = this->getRawCommandFrame();
/**
* Converts instance of a CMSIS Command to an unsigned char, for sending to the Atmel ICE device.
*
* @return
*/
explicit virtual operator std::vector<unsigned char> () const;
std::size_t commandFrameSize = rawCommandFrame.size();
auto commandsRequired = static_cast<std::size_t>(
std::ceil(static_cast<float>(commandFrameSize) / static_cast<float>(maximumCommandPacketSize))
);
std::vector<AvrCommand> avrCommands;
std::size_t copiedPacketSize = 0;
for (std::size_t i = 0; i < commandsRequired; i++) {
// If we're on the last packet, the packet size will be what ever is left of the AvrCommandFrame
std::size_t commandPacketSize = ((i + 1) != commandsRequired) ? maximumCommandPacketSize
: (commandFrameSize - (maximumCommandPacketSize * i));
avrCommands.emplace_back(AvrCommand(
commandsRequired,
i + 1,
std::vector<unsigned char>(
rawCommandFrame.begin() + static_cast<std::int64_t>(copiedPacketSize),
rawCommandFrame.begin() + static_cast<std::int64_t>(copiedPacketSize + commandPacketSize)
)
));
copiedPacketSize += commandPacketSize;
}
return avrCommands;
}
protected:
PayloadContainerType payload;
private:
unsigned char SOF = 0x0E;
@@ -101,14 +185,11 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
* Incrementing from 0x00
*/
std::uint16_t sequenceId = 0;
inline static std::uint16_t lastSequenceId = 0;
/**
* Destination sub-protocol handler ID
*/
ProtocolHandlerId protocolHandlerID = ProtocolHandlerId::DISCOVERY;
std::vector<unsigned char> payload;
};
}

View File

@@ -34,7 +34,8 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames
return static_cast<unsigned char>(id) != rawId;
}
class DiscoveryCommandFrame: public AvrCommandFrame
template<class PayloadContainerType>
class DiscoveryCommandFrame: public AvrCommandFrame<PayloadContainerType>
{
public:
using ResponseFrameType = ResponseFrames::DiscoveryResponseFrame;

View File

@@ -19,31 +19,19 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames
* The Discovery protocol handler only supports one command; the Query command. This command is used to
* query information from the device, such as device capabilities, manufacture date, serial number, etc.
*/
class Query: public DiscoveryCommandFrame
class Query: public DiscoveryCommandFrame<std::array<unsigned char, 3>>
{
public:
Query(): DiscoveryCommandFrame() {}
explicit Query(QueryContext context): DiscoveryCommandFrame() {
this->setContext(context);
}
void setContext(QueryContext context) {
this->context = context;
}
[[nodiscard]] std::vector<unsigned char> getPayload() const override {
explicit Query(QueryContext context) {
/*
* The payload for the Query command consists of three bytes. A command ID (0x00), version (0x00) and a
* query context.
*/
auto output = std::vector<unsigned char>(3, 0x00);
output[2] = static_cast<unsigned char>(this->context);
return output;
this->payload = {
0x00,
0x00,
static_cast<unsigned char>(context)
};
}
private:
QueryContext context = QueryContext::COMMAND_HANDLERS;
};
}

View File

@@ -7,24 +7,19 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames
/**
* The End Session command ends the active session with the tool.
*/
class EndSession: public HouseKeepingCommandFrame
class EndSession: public HouseKeepingCommandFrame<std::array<unsigned char, 3>>
{
public:
EndSession(): HouseKeepingCommandFrame() {
this->init();
}
private:
void init() {
EndSession() {
/*
* The payload for the End Session command consists of three bytes. A command ID byte (0x11), a
* version byte (0x00) and a reset flag (0x00 for no reset, 0x01 for tool reset).
*/
auto payload = std::vector<unsigned char>(3);
payload[0] = 0x11;
payload[1] = 0x00;
payload[2] = 0x00;
this->setPayload(payload);
this->payload = {
0x11,
0x00,
0x00
};
}
};
}

View File

@@ -7,24 +7,10 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::HouseKeeping
{
class GetParameter: public HouseKeepingCommandFrame
class GetParameter: public HouseKeepingCommandFrame<std::array<unsigned char, 5>>
{
public:
explicit GetParameter(const Parameter& parameter): parameter(parameter) {}
GetParameter(const Parameter& parameter, std::uint8_t size): GetParameter(parameter) {
this->setSize(size);
}
void setParameter(const Parameter& parameter) {
this->parameter = parameter;
}
void setSize(std::uint8_t size) {
this->size = size;
}
[[nodiscard]] std::vector<unsigned char> getPayload() const override {
explicit GetParameter(const Parameter& parameter, std::uint8_t size) {
/*
* The get param command consists of 5 bytes:
* 1. Command ID (0x02)
@@ -33,18 +19,13 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames
* 4. Param ID (Parameter::id)
* 5. Param value length (this->size)
*/
auto output = std::vector<unsigned char>(5, 0x00);
output[0] = 0x02;
output[1] = 0x00;
output[2] = static_cast<unsigned char>(this->parameter.context);
output[3] = static_cast<unsigned char>(this->parameter.id);
output[4] = static_cast<unsigned char>(this->size);
return output;
this->payload = {
0x02,
0x00,
static_cast<unsigned char>(parameter.context),
static_cast<unsigned char>(parameter.id),
static_cast<unsigned char>(size)
};
}
private:
Parameter parameter;
std::uint8_t size = 0;
};
}

View File

@@ -21,7 +21,8 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames
return rawId == id;
}
class HouseKeepingCommandFrame: public AvrCommandFrame
template<class PayloadContainerType>
class HouseKeepingCommandFrame: public AvrCommandFrame<PayloadContainerType>
{
public:
HouseKeepingCommandFrame() {

View File

@@ -1,5 +1,7 @@
#pragma once
#include <array>
#include "HouseKeepingCommandFrame.hpp"
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::HouseKeeping
@@ -7,23 +9,18 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames
/**
* The Start Session command begins a session with the tool.
*/
class StartSession: public HouseKeepingCommandFrame
class StartSession: public HouseKeepingCommandFrame<std::array<unsigned char, 2>>
{
public:
StartSession(): HouseKeepingCommandFrame() {
this->init();
}
private:
void init() {
StartSession() {
/*
* The payload for the Start Session command consists of two bytes. A command ID byte (0x10) and a
* version byte (0x00).
*/
auto payload = std::vector<unsigned char>(2);
payload[0] = 0x10;
payload[1] = 0x00;
this->setPayload(payload);
this->payload = {
0x10,
0x00
};
}
};
}

View File

@@ -1459,11 +1459,12 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
}
}
auto commandFrame = CommandFrames::Avr8Generic::ReadMemory();
commandFrame.setType(type);
commandFrame.setAddress(startAddress);
commandFrame.setBytes(bytes);
commandFrame.setExcludedAddresses(excludedAddresses);
auto commandFrame = CommandFrames::Avr8Generic::ReadMemory(
type,
startAddress,
bytes,
excludedAddresses
);
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame);
if (response.getResponseId() == Avr8ResponseId::FAILED) {
@@ -1479,10 +1480,11 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
throw Exception("Writing to flash memory is not supported.");
}
auto commandFrame = CommandFrames::Avr8Generic::WriteMemory();
commandFrame.setType(type);
commandFrame.setAddress(address);
commandFrame.setBuffer(buffer);
auto commandFrame = CommandFrames::Avr8Generic::WriteMemory(
type,
address,
buffer
);
auto response = this->edbgInterface.sendAvrCommandFrameAndWaitForResponseFrame(commandFrame);
if (response.getResponseId() == Avr8ResponseId::FAILED) {

View File

@@ -8,18 +8,10 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg
{
using namespace Bloom::Exceptions;
Protocols::CmsisDap::Response EdbgInterface::sendAvrCommandFrameAndWaitForResponse(
const Protocols::CmsisDap::Edbg::Avr::AvrCommandFrame& avrCommandFrame
Protocols::CmsisDap::Response EdbgInterface::sendAvrCommandsAndWaitForResponse(
const std::vector<Avr::AvrCommand>& avrCommands
) {
// An AVR command frame can be split into multiple CMSIS-DAP commands. Each command
// containing a fragment of the AvrCommandFrame.
// Minus 3 to accommodate AVR command meta data
std::size_t maximumCommandPacketSize = (this->getUsbHidInputReportSize() - 3);
auto avrCommands = avrCommandFrame.generateAvrCommands(maximumCommandPacketSize);
for (auto& avrCommand : avrCommands) {
for (const auto& avrCommand : avrCommands) {
// Send command to device
auto response = this->sendCommandAndWaitForResponse(avrCommand);

View File

@@ -33,8 +33,19 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg
* @param avrCommandFrame
* @return
*/
virtual Protocols::CmsisDap::Response sendAvrCommandFrameAndWaitForResponse(
const Protocols::CmsisDap::Edbg::Avr::AvrCommandFrame& avrCommandFrame
template <class PayloadContainerType>
Protocols::CmsisDap::Response sendAvrCommandFrameAndWaitForResponse(
const Protocols::CmsisDap::Edbg::Avr::AvrCommandFrame<PayloadContainerType>& avrCommandFrame
) {
// An AVR command frame can be split into multiple CMSIS-DAP commands. Each command
// containing a fragment of the AvrCommandFrame.
return this->sendAvrCommandsAndWaitForResponse(avrCommandFrame.generateAvrCommands(
this->getUsbHidInputReportSize() - 3 // Minus 3 to accommodate AVR command bytes
));
}
virtual Protocols::CmsisDap::Response sendAvrCommandsAndWaitForResponse(
const std::vector<Avr::AvrCommand>& avrCommands
);
Protocols::CmsisDap::Edbg::Avr::AvrResponse getAvrResponse();
@@ -44,12 +55,10 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg
const CommandFrameType& avrCommandFrame
) {
static_assert(
std::is_base_of<Protocols::CmsisDap::Edbg::Avr::AvrCommandFrame, CommandFrameType>::value,
"AVR Command must be base of AvrCommandFrame."
);
static_assert(
std::is_base_of<Protocols::CmsisDap::Edbg::Avr::AvrResponseFrame, typename CommandFrameType::ResponseFrameType>::value,
std::is_base_of<
Protocols::CmsisDap::Edbg::Avr::AvrResponseFrame,
typename CommandFrameType::ResponseFrameType
>::value,
"AVR Command must specify a valid response frame type, derived from AvrResponseFrame."
);