15 #include "fletchgen/srec/srec.h"
16 #include <fletcher/common.h>
22 namespace fletchgen::srec {
25 : type_(type), size_(size), address_(address) {
28 throw std::domain_error(
"SREC Record size cannot exceed " + std::to_string(
MAX_DATA_BYTES) +
" bytes.");
32 data_ =
static_cast<uint8_t *
>(calloc(1, size_));
45 auto str = header_str.substr(0, std::max(
MAX_DATA_BYTES, header_str.size()));
46 return Record(Record::HEADER,
address, (
const uint8_t *) (str.c_str()), str.size());
49 uint8_t Record::byte_count() {
50 return address_width() + size_ + 1;
53 int Record::address_width() {
55 case DATA24:
return 3;
56 case COUNT24:
return 3;
57 case TERM24:
return 3;
58 case DATA32:
return 4;
59 case TERM32:
return 4;
64 uint8_t Record::checksum() {
69 if (address_width() > 3) sum += (address_ & 0xFF000000u) >> 24u;
70 if (address_width() > 2) sum += (address_ & 0x00FF0000u) >> 16u;
71 sum += (address_ & 0x0000FF00u) >> 8u;
72 sum += (address_ & 0x000000FFu);
74 for (
size_t i = 0; i < size_; i++)
77 auto ret =
static_cast<uint8_t
>(sum & 0xFFu);
86 std::stringstream output;
88 output <<
'S' << std::to_string(type_);
90 PutHex(output, byte_count());
92 PutHex(output, address_, 2 * address_width());
94 for (
size_t i = 0; i < size_; i++) {
95 PutHex(output, data_[i]);
98 PutHex(output, checksum());
109 Record ret(RESERVED, 0,
nullptr, 0);
112 if (line.substr(offset, 1) !=
"S") {
118 uint64_t t = std::stoul(line.substr(offset, 1),
nullptr, 16);
122 ret.type_ =
static_cast<Type>(t);
126 ret.size_ = std::stoul(line.substr(offset, 2),
nullptr, 16) - ret.address_width() - 1;
134 for (
int i = ret.address_width() - 1; i >= 0; i--) {
135 uint8_t
byte =
static_cast<uint8_t
>(std::stoul(line.substr(offset, 2),
nullptr, 16));
136 addr |=
static_cast<uint32_t
>(byte) << (8u * i);
142 ret.data_ =
static_cast<uint8_t *
>(calloc(ret.size_,
sizeof(uint8_t)));
145 for (
size_t i = 0; i < ret.size_; i++) {
146 auto byte =
static_cast<uint8_t
>(std::stoul(line.substr(offset, 2),
nullptr, 16));
152 uint8_t sum =
static_cast<uint8_t
>(std::stoul(line.substr(offset, 2),
nullptr, 16));
153 if (ret.checksum() != sum) {
160 File::File(uint32_t start_address,
const uint8_t *
data,
size_t size,
const std::string &header_str) {
175 auto rec = Record::Data<32>(
static_cast<uint32_t
>(start_address + pos), &
data[pos], rec_size);
178 pos = pos + rec_size;
183 if (output->good()) {
185 (*output) << r.ToString(
true);
188 FLETCHER_LOG(ERROR,
"Could not write SREC file to output stream.");
192 File::File(std::istream *input) {
193 for (std::string line; std::getline(*input, line);) {
198 throw std::runtime_error(
"Could not parse SREC file.");
205 uint32_t top_addr = 0;
206 const Record *top_rec =
nullptr;
207 for (
const auto &r :
records) {
208 if (r.address() > top_addr) {
214 if (top_rec !=
nullptr) {
215 *size = top_addr + top_rec->
size();
216 *buf =
static_cast<uint8_t *
>(calloc(*size,
sizeof(uint8_t)));
224 for (
const auto &r :
records) {
225 std::memcpy(*buf + r.address(), r.data(), r.size());
Structure to build up a single Record of an SREC file.
static Record Header(const std::string &header_str="HDR", uint16_t address=0)
Create an SREC header Record.
Type
The SREC Record type.
static constexpr size_t MAX_DATA_BYTES
Maximum number of data bytes per Record.
Record(const Record &rec)
SREC Record copy constructor.
size_t size() const
Return the size in bytes of this record.
uint32_t address() const
Return the address of this record.
uint8_t * data() const
Return the data source pointer of this record.
std::string ToString(bool line_feed=false)
Return the SREC Record string.
~Record()
Record destructor.
static std::optional< Record > FromString(const std::string &line)
Attempt to construct a Record from a string.
std::shared_ptr< Type > data(int width)
Fletcher data.
void ToBuffer(uint8_t **buffer, size_t *size)
Convert an SREC file to a raw buffer.
std::vector< Record > records
SREC records in this file.
void write(std::ostream *output)
Write the SREC file to an output stream.