2023-04-02 23:41:04 +01:00
|
|
|
#include "WriteTargetMemory.hpp"
|
|
|
|
|
|
|
|
|
|
#include <cmath>
|
2024-12-24 18:27:59 +00:00
|
|
|
#include <QLocale>
|
2023-04-02 23:41:04 +01:00
|
|
|
#include <algorithm>
|
2023-04-08 14:09:25 +01:00
|
|
|
#include <numeric>
|
2023-04-02 23:41:04 +01:00
|
|
|
|
2023-05-03 23:13:22 +01:00
|
|
|
#include "src/Exceptions/Exception.hpp"
|
|
|
|
|
|
2023-08-13 15:47:51 +01:00
|
|
|
using Services::TargetControllerService;
|
2024-12-24 18:27:59 +00:00
|
|
|
using Targets::TargetMemorySize;
|
2023-04-02 23:41:04 +01:00
|
|
|
|
2024-12-24 18:27:59 +00:00
|
|
|
WriteTargetMemory::WriteTargetMemory(
|
|
|
|
|
const Targets::TargetAddressSpaceDescriptor& addressSpaceDescriptor,
|
|
|
|
|
const Targets::TargetMemorySegmentDescriptor& memorySegmentDescriptor,
|
|
|
|
|
std::vector<Block>&& blocks
|
|
|
|
|
)
|
|
|
|
|
: addressSpaceDescriptor(addressSpaceDescriptor)
|
|
|
|
|
, memorySegmentDescriptor(memorySegmentDescriptor)
|
|
|
|
|
, blocks(std::move(blocks))
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
WriteTargetMemory::WriteTargetMemory(
|
|
|
|
|
const Targets::TargetAddressSpaceDescriptor& addressSpaceDescriptor,
|
|
|
|
|
const Targets::TargetMemorySegmentDescriptor& memorySegmentDescriptor,
|
|
|
|
|
Targets::TargetMemoryAddress startAddress,
|
|
|
|
|
const Targets::TargetMemoryBuffer& data
|
|
|
|
|
)
|
|
|
|
|
: WriteTargetMemory(
|
|
|
|
|
addressSpaceDescriptor,
|
|
|
|
|
memorySegmentDescriptor,
|
|
|
|
|
std::vector<Block>{{startAddress, data}}
|
|
|
|
|
)
|
|
|
|
|
{}
|
|
|
|
|
|
|
|
|
|
QString WriteTargetMemory::brief() const {
|
|
|
|
|
return "Writing " + QLocale{QLocale::English}.toString(this->totalSize()) + " byte(s) to \""
|
|
|
|
|
+ QString::fromStdString(this->memorySegmentDescriptor.name) + "\"";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
TaskGroups WriteTargetMemory::taskGroups() const {
|
|
|
|
|
return {
|
|
|
|
|
TaskGroup::USES_TARGET_CONTROLLER,
|
|
|
|
|
};
|
|
|
|
|
}
|
2023-04-02 23:41:04 +01:00
|
|
|
|
2024-12-24 18:27:59 +00:00
|
|
|
void WriteTargetMemory::run(TargetControllerService& targetControllerService) {
|
|
|
|
|
if (!this->memorySegmentDescriptor.debugModeAccess.writeable) {
|
|
|
|
|
throw Exceptions::Exception{"Invalid request - cannot write to this memory segment during a debug session."};
|
2023-08-13 15:47:51 +01:00
|
|
|
}
|
2023-05-03 23:13:22 +01:00
|
|
|
|
2023-08-13 15:47:51 +01:00
|
|
|
/*
|
|
|
|
|
* To prevent locking up the TargetController for too long, we split the write operation into numerous
|
|
|
|
|
* operations.
|
|
|
|
|
*
|
|
|
|
|
* This allows the TargetController to service other commands in-between reads, reducing the likelihood of
|
|
|
|
|
* command timeouts when we're writing lots of data.
|
|
|
|
|
*/
|
|
|
|
|
const auto maxBlockSize = std::max(
|
2024-12-24 18:27:59 +00:00
|
|
|
TargetMemorySize{256},
|
|
|
|
|
this->memorySegmentDescriptor.pageSize.value_or(TargetMemorySize{0})
|
2023-08-13 15:47:51 +01:00
|
|
|
);
|
2023-04-08 14:09:25 +01:00
|
|
|
|
2024-12-24 18:27:59 +00:00
|
|
|
const auto writeSize = this->totalSize();
|
|
|
|
|
auto totalBytesWritten = TargetMemorySize{0};
|
2023-04-08 14:09:25 +01:00
|
|
|
|
2023-08-13 15:47:51 +01:00
|
|
|
for (const auto& block : this->blocks) {
|
|
|
|
|
const auto totalBytes = block.data.size();
|
2023-04-08 14:09:25 +01:00
|
|
|
|
2023-08-13 15:47:51 +01:00
|
|
|
TargetMemorySize bytesWritten = 0;
|
2023-04-08 14:09:25 +01:00
|
|
|
|
2023-08-13 15:47:51 +01:00
|
|
|
while (bytesWritten < totalBytes) {
|
|
|
|
|
const auto bytesToWrite = std::min(
|
|
|
|
|
maxBlockSize,
|
|
|
|
|
static_cast<decltype(maxBlockSize)>(totalBytes - bytesWritten)
|
|
|
|
|
);
|
2023-04-08 14:09:25 +01:00
|
|
|
|
2023-08-13 15:47:51 +01:00
|
|
|
targetControllerService.writeMemory(
|
2024-12-24 18:27:59 +00:00
|
|
|
this->addressSpaceDescriptor,
|
|
|
|
|
this->memorySegmentDescriptor,
|
2023-08-13 15:47:51 +01:00
|
|
|
block.startAddress + bytesWritten,
|
2024-12-24 18:27:59 +00:00
|
|
|
Targets::TargetMemoryBuffer{
|
2023-08-13 15:47:51 +01:00
|
|
|
block.data.begin() + bytesWritten,
|
|
|
|
|
block.data.begin() + bytesWritten + bytesToWrite
|
2024-12-24 18:27:59 +00:00
|
|
|
}
|
2023-08-13 15:47:51 +01:00
|
|
|
);
|
2023-04-08 14:09:25 +01:00
|
|
|
|
2023-08-13 15:47:51 +01:00
|
|
|
bytesWritten += bytesToWrite;
|
|
|
|
|
totalBytesWritten += bytesToWrite;
|
2023-04-08 14:09:25 +01:00
|
|
|
|
2023-08-13 15:47:51 +01:00
|
|
|
this->setProgressPercentage(static_cast<std::uint8_t>(
|
2024-12-24 18:27:59 +00:00
|
|
|
(static_cast<float>(totalBytesWritten) + 1) / (static_cast<float>(writeSize) / 100)
|
2023-08-13 15:47:51 +01:00
|
|
|
));
|
2023-04-02 23:41:04 +01:00
|
|
|
}
|
|
|
|
|
}
|
2023-08-13 15:47:51 +01:00
|
|
|
|
|
|
|
|
emit this->targetMemoryWritten(totalBytesWritten);
|
2023-04-02 23:41:04 +01:00
|
|
|
}
|
2024-12-24 18:27:59 +00:00
|
|
|
|
|
|
|
|
TargetMemorySize WriteTargetMemory::totalSize() const {
|
|
|
|
|
return std::accumulate(
|
|
|
|
|
this->blocks.begin(),
|
|
|
|
|
this->blocks.end(),
|
|
|
|
|
TargetMemorySize{0},
|
|
|
|
|
[] (TargetMemorySize bytes, const Block& block) {
|
|
|
|
|
return bytes + block.data.size();
|
|
|
|
|
}
|
|
|
|
|
);
|
|
|
|
|
}
|