28enum record_type_e { DATA, END_OF_FILE, EXTENDED_SEGMENT_ADDRESS, START_SEGMENT_ADDRESS, EXTENDED_LINEAR_ADDRESS, START_LINEAR_ADDRESS };
35uint8_t hex2dec(uint8_t h) {
36 if(h >=
'0' && h <=
'9')
38 else if(h >=
'A' && h <=
'F')
40 else if(h >=
'a' && h <=
'z')
43 return INVALID_HEX_CHAR;
46static uint8_t ihex_checksum(
const std::vector<uint8_t>& bytes) {
49 for(uint8_t b : bytes)
51 return static_cast<uint8_t
>(0u -
static_cast<uint8_t
>(sum));
54static void write_record(std::ostream& os, uint8_t len, uint16_t addr, uint8_t type,
const uint8_t* data) {
55 std::vector<uint8_t> payload;
56 payload.reserve(4 + len);
57 payload.push_back(len);
58 payload.push_back(
static_cast<uint8_t
>((addr >> 8) & 0xFF));
59 payload.push_back(
static_cast<uint8_t
>(addr & 0xFF));
60 payload.push_back(type);
61 for(uint8_t i = 0; i < len; ++i)
62 payload.push_back(data[i]);
64 uint8_t csum = ihex_checksum(payload);
66 os << ':' << std::uppercase << std::hex << std::setfill('0') << std::setw(2) << static_cast<int>(len) << std::setw(4)
67 <<
static_cast<int>(addr) << std::setw(2) <<
static_cast<int>(type);
69 for(uint8_t i = 0; i < len; ++i) {
70 os << std::setw(2) << static_cast<int>(data[i]);
73 os << std::setw(2) << static_cast<int>(csum) <<
"\n";
78bool parse(std::istream& is, std::function<
bool(uint64_t, uint64_t,
const uint8_t*)> cb) {
82 uint16_t address_lo{0};
83 uint16_t address_hi{0};
84 std::array<uint8_t, IHEX_DATA_SIZE> data;
85 unsigned data_size_in_nibble{0};
86 uint8_t byte_count{0};
87 uint8_t record_type{DATA};
88 uint8_t calculated_cs{0};
89 uint8_t saved_high_nibble{0};
90 bool save_high_nibble{
true};
91 bool ex_segment_addr_mode{
false};
97 if((i = hex2dec(c)) == INVALID_HEX_CHAR)
99 if(state <= CHECKSUM_1_STATE) {
101 saved_high_nibble = i;
103 calculated_cs += (saved_high_nibble << 4) | i;
104 save_high_nibble = !save_high_nibble;
108 case START_CODE_STATE:
109 calculated_cs = 0x00;
110 save_high_nibble =
true;
111 if(c ==
'\r' || c ==
'\n') {
113 }
else if(c ==
':') {
117 memset(data.data(), 0, data.size());
118 data_size_in_nibble = 0;
124 case BYTE_COUNT_0_STATE:
125 case BYTE_COUNT_1_STATE:
126 byte_count = (byte_count << 4) | i;
133 address_lo = ((address_lo << 4) | i);
136 case RECORD_TYPE_0_STATE:
141 case RECORD_TYPE_1_STATE:
142 if(i > START_LINEAR_ADDRESS)
145 if(byte_count == 0) {
146 state = CHECKSUM_0_STATE;
147 }
else if(byte_count >
sizeof(data))
153 uint8_t b_index = data_size_in_nibble / 2;
154 data[b_index] = (data[b_index] << 4) | i;
156 ++data_size_in_nibble;
157 if((data_size_in_nibble / 2) >= byte_count)
161 case CHECKSUM_0_STATE:
164 case CHECKSUM_1_STATE:
165 if((byte_count << 1) != data_size_in_nibble)
167 if(calculated_cs != 0x00)
169 if(record_type == EXTENDED_SEGMENT_ADDRESS) {
170 address_hi = ((uint16_t)data[0] << 8) | (data[1]);
171 ex_segment_addr_mode =
true;
172 }
else if(record_type == EXTENDED_LINEAR_ADDRESS) {
173 address_hi = ((uint16_t)data[0] << 8) | (data[1]);
174 ex_segment_addr_mode =
false;
175 }
else if(record_type == DATA && cb) {
176 uint64_t address = ex_segment_addr_mode ? (
static_cast<uint32_t
>(address_hi) << 4) +
static_cast<uint32_t
>(address_lo)
177 : (
static_cast<uint32_t
>(address_hi) << 16) |
static_cast<uint32_t
>(address_lo);
178 if(!cb(address, data_size_in_nibble >> 1, data.data()))
181 state = START_CODE_STATE;
190void dump(std::ostream& os, nonstd::span<uint8_t>
const& bytes, uint32_t base_address, uint32_t record_len) {
191 if(record_len == 0 || record_len > 255) {
192 throw std::invalid_argument(
"record_len must be 1..255");
195 uint32_t addr = base_address;
196 uint32_t upper = 0xFFFFFFFFu;
199 while(i < bytes.size()) {
200 uint32_t new_upper = (addr >> 16) & 0xFFFF;
203 if(new_upper != upper) {
205 uint8_t ext[2] = {
static_cast<uint8_t
>((upper >> 8) & 0xFF),
static_cast<uint8_t
>(upper & 0xFF)};
206 write_record(os, 2, 0x0000, 0x04, ext);
209 uint16_t low =
static_cast<uint16_t
>(addr & 0xFFFF);
212 size_t max_before_boundary = 0x10000u - low;
213 size_t chunk = record_len;
214 if(chunk > bytes.size() - i)
215 chunk = bytes.size() - i;
216 if(chunk > max_before_boundary)
217 chunk = max_before_boundary;
220 std::vector<uint8_t> buf(chunk);
221 for(
size_t k = 0; k < chunk; ++k)
222 buf[k] =
static_cast<uint8_t
>(bytes[i + k]);
224 write_record(os,
static_cast<uint8_t
>(chunk), low, 0x00, buf.data());
227 addr +=
static_cast<uint32_t
>(chunk);
231 write_record(os, 0, 0x0000, 0x01,
nullptr);
bool parse(std::istream &is, std::function< bool(uint64_t, uint64_t, const uint8_t *)> cb)
Parses an IHEX file from the given input stream and invokes a callback function for each data record ...