114 lines
4.3 KiB
C++
114 lines
4.3 KiB
C++
#include "EepromFill.hpp"
|
|
|
|
#include <QByteArray>
|
|
#include <algorithm>
|
|
#include <stdexcept>
|
|
|
|
#include "src/DebugServer/Gdb/ResponsePackets/ResponsePacket.hpp"
|
|
#include "src/DebugServer/Gdb/ResponsePackets/ErrorResponsePacket.hpp"
|
|
|
|
#include "src/Services/StringService.hpp"
|
|
#include "src/Logger/Logger.hpp"
|
|
|
|
#include "src/DebugServer/Gdb/Exceptions/InvalidCommandOption.hpp"
|
|
#include "src/Exceptions/Exception.hpp"
|
|
|
|
namespace DebugServer::Gdb::AvrGdb::CommandPackets
|
|
{
|
|
using Services::TargetControllerService;
|
|
|
|
using ResponsePackets::ResponsePacket;
|
|
using ResponsePackets::ErrorResponsePacket;
|
|
|
|
using ::Exceptions::Exception;
|
|
using Exceptions::InvalidCommandOption;
|
|
|
|
EepromFill::EepromFill(Gdb::CommandPackets::Monitor&& monitorPacket)
|
|
: Gdb::CommandPackets::Monitor(std::move(monitorPacket))
|
|
, rawFillValue(this->commandArguments.size() >= 3 ? this->commandArguments[2] : std::string{})
|
|
{}
|
|
|
|
void EepromFill::handle(
|
|
DebugSession& debugSession,
|
|
const AvrGdbTargetDescriptor& gdbTargetDescriptor,
|
|
const Targets::TargetDescriptor& targetDescriptor,
|
|
TargetControllerService& targetControllerService
|
|
) {
|
|
Logger::info("Handling EepromFill packet");
|
|
|
|
try {
|
|
if (this->rawFillValue.empty()) {
|
|
throw InvalidCommandOption{"Fill value required"};
|
|
}
|
|
|
|
const auto eepromSize = gdbTargetDescriptor.eepromMemorySegmentDescriptor.size();
|
|
|
|
const auto fillValue = Services::StringService::dataFromHex(
|
|
this->rawFillValue.size() >= 3 && this->rawFillValue[0] == '0'
|
|
&& (this->rawFillValue[1] == 'X' || this->rawFillValue[1] == 'x')
|
|
? this->rawFillValue.substr(2)
|
|
: this->rawFillValue
|
|
);
|
|
const auto fillValueSize = fillValue.size();
|
|
|
|
if (fillValueSize > eepromSize) {
|
|
throw InvalidCommandOption{
|
|
"Fill value size (" + std::to_string(fillValueSize) + " bytes) exceeds EEPROM size ("
|
|
+ std::to_string(eepromSize) + " bytes)"
|
|
};
|
|
}
|
|
|
|
if ((eepromSize % fillValueSize) != 0) {
|
|
Logger::warning(
|
|
"The fill value size (" + std::to_string(fillValueSize) + " bytes) is not a multiple of the EEPROM "
|
|
"size (" + std::to_string(eepromSize) + " bytes) - the fill value will be truncated"
|
|
);
|
|
}
|
|
|
|
Logger::warning("Filling " + std::to_string(eepromSize) + " bytes of EEPROM");
|
|
|
|
auto data = Targets::TargetMemoryBuffer{};
|
|
data.reserve(eepromSize);
|
|
|
|
// Repeat fillValue until we've filled `data`
|
|
while (data.size() < eepromSize) {
|
|
data.insert(
|
|
data.end(),
|
|
fillValue.begin(),
|
|
fillValue.begin() + static_cast<std::int32_t>(
|
|
std::min(fillValueSize, (eepromSize - data.size()))
|
|
)
|
|
);
|
|
}
|
|
|
|
const auto hexValues = Services::StringService::toHex(data);
|
|
Logger::debug("Filling EEPROM with values: " + hexValues);
|
|
|
|
targetControllerService.writeMemory(
|
|
gdbTargetDescriptor.eepromAddressSpaceDescriptor,
|
|
gdbTargetDescriptor.eepromMemorySegmentDescriptor,
|
|
gdbTargetDescriptor.eepromMemorySegmentDescriptor.addressRange.startAddress,
|
|
std::move(data)
|
|
);
|
|
|
|
debugSession.connection.writePacket(ResponsePacket{Services::StringService::toHex(
|
|
"Filled " + std::to_string(eepromSize) + " bytes of EEPROM, with values: " + hexValues + "\n"
|
|
)});
|
|
|
|
} catch (const InvalidCommandOption& exception) {
|
|
debugSession.connection.writePacket(
|
|
ResponsePacket{Services::StringService::toHex(exception.getMessage() + "\n")}
|
|
);
|
|
|
|
} catch (const std::invalid_argument& exception) {
|
|
debugSession.connection.writePacket(
|
|
ResponsePacket{Services::StringService::toHex("Invalid fill value\n")}
|
|
);
|
|
|
|
} catch (const Exception& exception) {
|
|
Logger::error("Failed to fill EEPROM - " + exception.getMessage());
|
|
debugSession.connection.writePacket(ErrorResponsePacket{});
|
|
}
|
|
}
|
|
}
|