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/Command.cpp
src/DebugToolDrivers/Protocols/CMSIS-DAP/Response.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/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/CommandFrames/AVR8Generic/ReadMemory.cpp
src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrResponse.cpp src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/AvrResponse.cpp
src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/AVR/ResponseFrames/AvrResponseFrame.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 class AvrCommand: public Command
{ {
public: 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); this->setCommandId(0x80);
} }
@@ -25,26 +33,14 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
return this->fragmentNumber; return this->fragmentNumber;
} }
void setFragmentNumber(std::size_t fragmentNumber) {
this->fragmentNumber = fragmentNumber;
}
[[nodiscard]] std::size_t getFragmentCount() const { [[nodiscard]] std::size_t getFragmentCount() const {
return this->fragmentCount; return this->fragmentCount;
} }
void setFragmentCount(std::size_t fragmentCount) {
this->fragmentCount = fragmentCount;
}
[[nodiscard]] const std::vector<unsigned char>& getCommandPacket() const { [[nodiscard]] const std::vector<unsigned char>& getCommandPacket() const {
return this->commandPacket; return this->commandPacket;
} }
void setCommandPacket(const std::vector<unsigned char>& commandPacket) {
this->commandPacket = commandPacket;
}
private: private:
std::size_t fragmentNumber = 1; std::size_t fragmentNumber = 1;
std::size_t fragmentCount = 1; std::size_t fragmentCount = 1;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -5,7 +5,12 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic 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: * 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) * 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) * 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). * 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); this->payload = std::vector<unsigned char>(11, 0x00);
output[0] = this->excludedAddresses.empty() ? 0x21 : 0x22; this->payload[0] = excludedAddresses.empty() ? 0x21 : 0x22;
output[1] = 0x00; this->payload[1] = 0x00;
output[2] = static_cast<unsigned char>(this->type); this->payload[2] = static_cast<unsigned char>(type);
output[3] = static_cast<unsigned char>(this->address); this->payload[3] = static_cast<unsigned char>(address);
output[4] = static_cast<unsigned char>(this->address >> 8); this->payload[4] = static_cast<unsigned char>(address >> 8);
output[5] = static_cast<unsigned char>(this->address >> 16); this->payload[5] = static_cast<unsigned char>(address >> 16);
output[6] = static_cast<unsigned char>(this->address >> 24); this->payload[6] = static_cast<unsigned char>(address >> 24);
output[7] = static_cast<unsigned char>(this->bytes); this->payload[7] = static_cast<unsigned char>(bytes);
output[8] = static_cast<unsigned char>(this->bytes >> 8); this->payload[8] = static_cast<unsigned char>(bytes >> 8);
output[9] = static_cast<unsigned char>(this->bytes >> 16); this->payload[9] = static_cast<unsigned char>(bytes >> 16);
output[10] = static_cast<unsigned char>(this->bytes >> 24); this->payload[10] = static_cast<unsigned char>(bytes >> 24);
if (!this->excludedAddresses.empty()) { if (!excludedAddresses.empty()) {
const auto endAddress = this->address + (this->bytes - 1); const auto endAddress = address + (bytes - 1);
constexpr auto byteBitSize = std::numeric_limits<unsigned char>::digits; constexpr auto byteBitSize = std::numeric_limits<unsigned char>::digits;
auto byteBitset = std::bitset<byteBitSize>(); auto byteBitset = std::bitset<byteBitSize>();
byteBitset.reset(); byteBitset.reset();
for (std::uint32_t address = this->address; address <= endAddress; address++) { for (std::uint32_t address = address; address <= endAddress; address++) {
auto addressIndex = address - this->address; auto addressIndex = address - address;
auto bitIndex = static_cast<std::size_t>( auto bitIndex = static_cast<std::size_t>(
addressIndex - (std::floor(addressIndex / byteBitSize) * byteBitSize) addressIndex - (std::floor(addressIndex / byteBitSize) * byteBitSize)
); );
if (!this->excludedAddresses.contains(address)) { if (!excludedAddresses.contains(address)) {
byteBitset[bitIndex] = 1; byteBitset[bitIndex] = true;
} }
if (address > 0 && (bitIndex == 7 || address == endAddress)) { if (address > 0 && (bitIndex == 7 || address == endAddress)) {
output.emplace_back(byteBitset.to_ulong()); this->payload.emplace_back(byteBitset.to_ulong());
byteBitset.reset(); byteBitset.reset();
} }
} }
} }
return output;
} }
} }

View File

@@ -8,35 +8,16 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{ {
class ReadMemory: public Avr8GenericCommandFrame class ReadMemory: public Avr8GenericCommandFrame<std::vector<unsigned char>>
{ {
public: public:
using ResponseFrameType = ResponseFrames::Avr8Generic::ReadMemory; using ResponseFrameType = ResponseFrames::Avr8Generic::ReadMemory;
ReadMemory() = default; ReadMemory(
const Avr8MemoryType& type,
void setType(const Avr8MemoryType& type) { std::uint32_t address,
this->type = type; std::uint32_t bytes,
} const std::set<std::uint32_t>& excludedAddresses = {}
);
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;
}; };
} }

View File

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

View File

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

View File

@@ -6,18 +6,10 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{ {
class RunTo: public Avr8GenericCommandFrame class RunTo: public Avr8GenericCommandFrame<std::array<unsigned char, 6>>
{ {
public: public:
RunTo() = default; explicit RunTo(const std::uint32_t& address) {
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 {
/* /*
* The run-to command consists of 6 bytes: * The run-to command consists of 6 bytes:
* *
@@ -25,21 +17,18 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames
* 2. Version (0x00) * 2. Version (0x00)
* 3. Address to run to (4 bytes) * 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. // The address to run to needs to be the 16-bit word address, not the byte address.
auto wordAddress = this->address / 2; const auto wordAddress = 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));
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 namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{ {
class SetParameter: public Avr8GenericCommandFrame class SetParameter: public Avr8GenericCommandFrame<std::vector<unsigned char>>
{ {
public: public:
SetParameter() = default; SetParameter(const Avr8EdbgParameter& parameter, const std::vector<unsigned char>& value) {
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 {
/* /*
* The set param command consists of this->value.size() + 5 bytes. The first five bytes consist of: * The set param command consists of this->value.size() + 5 bytes. The first five bytes consist of:
* 1. Command ID (0x01) * 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 * 5. Param value length (this->value.size()) - this is only one byte in size, so its value should
* never exceed 255. * never exceed 255.
*/ */
auto output = std::vector<unsigned char>(this->value.size() + 5, 0x00); this->payload = std::vector<unsigned char>(value.size() + 5, 0x00);
output[0] = 0x01; this->payload[0] = 0x01;
output[1] = 0x00; this->payload[1] = 0x00;
output[2] = static_cast<unsigned char>(this->parameter.context); this->payload[2] = static_cast<unsigned char>(parameter.context);
output[3] = static_cast<unsigned char>(this->parameter.id); this->payload[3] = static_cast<unsigned char>(parameter.id);
output[4] = static_cast<unsigned char>(this->value.size()); this->payload[4] = static_cast<unsigned char>(value.size());
output.insert(output.begin() + 5, this->value.begin(), this->value.end()); this->payload.insert(this->payload.begin() + 5, value.begin(), value.end());
return output;
} }
private:
Avr8EdbgParameter parameter;
std::vector<unsigned char> value;
}; };
} }

View File

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

View File

@@ -7,18 +7,10 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{ {
class SetSoftwareBreakpoints: public Avr8GenericCommandFrame class SetSoftwareBreakpoints: public Avr8GenericCommandFrame<std::vector<unsigned char>>
{ {
public: public:
SetSoftwareBreakpoints() = default; explicit SetSoftwareBreakpoints(const std::vector<std::uint32_t>& addresses) {
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 {
/* /*
* The set software breakpoint command consists of 2 bytes + 4*n bytes, where n is the number * The set software breakpoint command consists of 2 bytes + 4*n bytes, where n is the number
* of breakpoints to set: * of breakpoints to set:
@@ -27,21 +19,17 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames
* 2. Version (0x00) * 2. Version (0x00)
* ... addresses * ... addresses
*/ */
auto output = std::vector<unsigned char>(2, 0x00); this->payload = {
output[0] = 0x43; 0x43,
output[1] = 0x00; 0x00,
};
for (const auto& address : this->addresses) { for (const auto& address : addresses) {
output.push_back(static_cast<unsigned char>(address)); this->payload.emplace_back(static_cast<unsigned char>(address));
output.push_back(static_cast<unsigned char>(address >> 8)); this->payload.emplace_back(static_cast<unsigned char>(address >> 8));
output.push_back(static_cast<unsigned char>(address >> 16)); this->payload.emplace_back(static_cast<unsigned char>(address >> 16));
output.push_back(static_cast<unsigned char>(address >> 24)); 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 namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{ {
class SetXmegaSoftwareBreakpoint: public Avr8GenericCommandFrame class SetXmegaSoftwareBreakpoint: public Avr8GenericCommandFrame<std::array<unsigned char, 15>>
{ {
public: public:
SetXmegaSoftwareBreakpoint() = default; explicit SetXmegaSoftwareBreakpoint(std::uint32_t address) {
this->payload = {
explicit SetXmegaSoftwareBreakpoint(std::uint32_t address): address(address) {} 0x42,
0x00,
void setAddress(std::uint32_t address) { static_cast<unsigned char>(address),
this->address = 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 namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{ {
class Step: public Avr8GenericCommandFrame class Step: public Avr8GenericCommandFrame<std::array<unsigned char, 4>>
{ {
public: public:
Step() = default; Step() {
[[nodiscard]] std::vector<unsigned char> getPayload() const override {
/* /*
* The step command consists of 4 bytes: * The step command consists of 4 bytes:
* 1. Command ID (0x34) * 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) * 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) * 4. Mode (0x00 for step over, 0x01 for step into, 0x02 for step out)
*/ */
auto output = std::vector<unsigned char>(4, 0x00); this->payload = {
output[0] = 0x34; 0x34,
output[1] = 0x00; 0x00,
output[2] = 0x01; 0x01,
output[3] = 0x01; 0x01,
};
return output;
} }
}; };
} }

View File

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

View File

@@ -7,24 +7,10 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr::CommandFrames::Avr8Generic
{ {
class WriteMemory: public Avr8GenericCommandFrame class WriteMemory: public Avr8GenericCommandFrame<std::vector<unsigned char>>
{ {
public: public:
WriteMemory() = default; WriteMemory(const Avr8MemoryType& type, std::uint32_t address, const Targets::TargetMemoryBuffer& buffer) {
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 {
/* /*
* The write memory command consists of 12 bytes + the buffer size: * The write memory command consists of 12 bytes + the buffer size:
* 1. Command ID (0x23) * 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") * 6. Asynchronous flag (0x00 for "write first, then reply" and 0x01 for "reply first, then write")
* 7. Buffer * 7. Buffer
*/ */
auto output = std::vector<unsigned char>(12, 0x00); this->payload = std::vector<unsigned char>(12 + buffer.size(), 0x00);
output[0] = 0x23; this->payload[0] = 0x23;
output[1] = 0x00; this->payload[1] = 0x00;
output[2] = static_cast<unsigned char>(this->type); this->payload[2] = static_cast<unsigned char>(type);
output[3] = static_cast<unsigned char>(this->address); this->payload[3] = static_cast<unsigned char>(address);
output[4] = static_cast<unsigned char>(this->address >> 8); this->payload[4] = static_cast<unsigned char>(address >> 8);
output[5] = static_cast<unsigned char>(this->address >> 16); this->payload[5] = static_cast<unsigned char>(address >> 16);
output[6] = static_cast<unsigned char>(this->address >> 24); this->payload[6] = static_cast<unsigned char>(address >> 24);
auto bytesToWrite = static_cast<std::uint32_t>(this->buffer.size()); auto bytesToWrite = static_cast<std::uint32_t>(buffer.size());
output[7] = static_cast<unsigned char>(bytesToWrite); this->payload[7] = static_cast<unsigned char>(bytesToWrite);
output[8] = static_cast<unsigned char>(bytesToWrite >> 8); this->payload[8] = static_cast<unsigned char>(bytesToWrite >> 8);
output[9] = static_cast<unsigned char>(bytesToWrite >> 16); this->payload[9] = static_cast<unsigned char>(bytesToWrite >> 16);
output[10] = static_cast<unsigned char>(bytesToWrite >> 24); this->payload[10] = static_cast<unsigned char>(bytesToWrite >> 24);
// We always set the async flag to 0x00 ("write first, then reply") // 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()); this->payload.insert(this->payload.begin() + 12, buffer.begin(), buffer.end());
return output;
} }
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 <vector>
#include <memory> #include <memory>
#include <limits> #include <limits>
#include <cmath>
#include <atomic>
#include <array>
#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/Command.hpp" #include "src/DebugToolDrivers/Protocols/CMSIS-DAP/Command.hpp"
#include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/Edbg.hpp" #include "src/DebugToolDrivers/Protocols/CMSIS-DAP/VendorSpecific/EDBG/Edbg.hpp"
@@ -12,27 +15,59 @@
namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr 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 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: public:
using ResponseFrameType = AvrResponseFrame; using ResponseFrameType = AvrResponseFrame;
AvrCommandFrame() { AvrCommandFrame() {
if (AvrCommandFrame::lastSequenceId < std::numeric_limits<decltype(AvrCommandFrame::lastSequenceId)>::max()) { if (LAST_SEQUENCE_ID < std::numeric_limits<decltype(LAST_SEQUENCE_ID)>::max()) {
this->sequenceId = ++(AvrCommandFrame::lastSequenceId); this->sequenceId = ++(LAST_SEQUENCE_ID);
} else { } else {
this->sequenceId = 0; this->sequenceId = 0;
AvrCommandFrame::lastSequenceId = 0; LAST_SEQUENCE_ID = 0;
} }
}; };
virtual ~AvrCommandFrame() = default; virtual ~AvrCommandFrame() = default;
AvrCommandFrame(const AvrCommandFrame& other) = default; AvrCommandFrame(const AvrCommandFrame& other) = default;
AvrCommandFrame(AvrCommandFrame&& other) = default; AvrCommandFrame(AvrCommandFrame&& other) noexcept = default;
AvrCommandFrame& operator = (const AvrCommandFrame& other) = default; AvrCommandFrame& operator = (const AvrCommandFrame& other) = default;
AvrCommandFrame& operator = (AvrCommandFrame&& other) = default; AvrCommandFrame& operator = (AvrCommandFrame&& other) noexcept = default;
[[nodiscard]] unsigned char getProtocolVersion() const { [[nodiscard]] unsigned char getProtocolVersion() const {
return this->protocolVersion; return this->protocolVersion;
@@ -58,12 +93,38 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
this->protocolHandlerID = static_cast<ProtocolHandlerId>(protocolHandlerId); this->protocolHandlerID = static_cast<ProtocolHandlerId>(protocolHandlerId);
} }
[[nodiscard]] virtual std::vector<unsigned char> getPayload() const { [[nodiscard]] virtual const PayloadContainerType& getPayload() const {
return this->payload; 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 * @return
* A vector of sequenced AVRCommands, each containing a segment of the AvrCommandFrame. * 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();
/** std::size_t commandFrameSize = rawCommandFrame.size();
* Converts instance of a CMSIS Command to an unsigned char, for sending to the Atmel ICE device. auto commandsRequired = static_cast<std::size_t>(
* std::ceil(static_cast<float>(commandFrameSize) / static_cast<float>(maximumCommandPacketSize))
* @return );
*/
explicit virtual operator std::vector<unsigned char> () const; 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: private:
unsigned char SOF = 0x0E; unsigned char SOF = 0x0E;
@@ -101,14 +185,11 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg::Avr
* Incrementing from 0x00 * Incrementing from 0x00
*/ */
std::uint16_t sequenceId = 0; std::uint16_t sequenceId = 0;
inline static std::uint16_t lastSequenceId = 0;
/** /**
* Destination sub-protocol handler ID * Destination sub-protocol handler ID
*/ */
ProtocolHandlerId protocolHandlerID = ProtocolHandlerId::DISCOVERY; 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; return static_cast<unsigned char>(id) != rawId;
} }
class DiscoveryCommandFrame: public AvrCommandFrame template<class PayloadContainerType>
class DiscoveryCommandFrame: public AvrCommandFrame<PayloadContainerType>
{ {
public: public:
using ResponseFrameType = ResponseFrames::DiscoveryResponseFrame; 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 * 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. * 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: public:
Query(): DiscoveryCommandFrame() {} explicit Query(QueryContext context) {
explicit Query(QueryContext context): DiscoveryCommandFrame() {
this->setContext(context);
}
void setContext(QueryContext context) {
this->context = context;
}
[[nodiscard]] std::vector<unsigned char> getPayload() const override {
/* /*
* The payload for the Query command consists of three bytes. A command ID (0x00), version (0x00) and a * The payload for the Query command consists of three bytes. A command ID (0x00), version (0x00) and a
* query context. * query context.
*/ */
auto output = std::vector<unsigned char>(3, 0x00); this->payload = {
output[2] = static_cast<unsigned char>(this->context); 0x00,
0x00,
return output; 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. * 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: public:
EndSession(): HouseKeepingCommandFrame() { EndSession() {
this->init();
}
private:
void init() {
/* /*
* The payload for the End Session command consists of three bytes. A command ID byte (0x11), a * 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). * version byte (0x00) and a reset flag (0x00 for no reset, 0x01 for tool reset).
*/ */
auto payload = std::vector<unsigned char>(3); this->payload = {
payload[0] = 0x11; 0x11,
payload[1] = 0x00; 0x00,
payload[2] = 0x00; 0x00
this->setPayload(payload); };
} }
}; };
} }

View File

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

View File

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

View File

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

View File

@@ -8,18 +8,10 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg
{ {
using namespace Bloom::Exceptions; using namespace Bloom::Exceptions;
Protocols::CmsisDap::Response EdbgInterface::sendAvrCommandFrameAndWaitForResponse( Protocols::CmsisDap::Response EdbgInterface::sendAvrCommandsAndWaitForResponse(
const Protocols::CmsisDap::Edbg::Avr::AvrCommandFrame& avrCommandFrame const std::vector<Avr::AvrCommand>& avrCommands
) { ) {
// An AVR command frame can be split into multiple CMSIS-DAP commands. Each command for (const auto& avrCommand : avrCommands) {
// 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) {
// Send command to device // Send command to device
auto response = this->sendCommandAndWaitForResponse(avrCommand); auto response = this->sendCommandAndWaitForResponse(avrCommand);

View File

@@ -33,8 +33,19 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg
* @param avrCommandFrame * @param avrCommandFrame
* @return * @return
*/ */
virtual Protocols::CmsisDap::Response sendAvrCommandFrameAndWaitForResponse( template <class PayloadContainerType>
const Protocols::CmsisDap::Edbg::Avr::AvrCommandFrame& avrCommandFrame 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(); Protocols::CmsisDap::Edbg::Avr::AvrResponse getAvrResponse();
@@ -44,12 +55,10 @@ namespace Bloom::DebugToolDrivers::Protocols::CmsisDap::Edbg
const CommandFrameType& avrCommandFrame const CommandFrameType& avrCommandFrame
) { ) {
static_assert( static_assert(
std::is_base_of<Protocols::CmsisDap::Edbg::Avr::AvrCommandFrame, CommandFrameType>::value, std::is_base_of<
"AVR Command must be base of AvrCommandFrame." Protocols::CmsisDap::Edbg::Avr::AvrResponseFrame,
); typename CommandFrameType::ResponseFrameType
>::value,
static_assert(
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." "AVR Command must specify a valid response frame type, derived from AvrResponseFrame."
); );