Skip to content

Commit

Permalink
utils: add intel hex parser
Browse files Browse the repository at this point in the history
  • Loading branch information
RubBra authored Sep 9, 2024
1 parent 86fa92f commit 150dd2e
Show file tree
Hide file tree
Showing 7 changed files with 242 additions and 0 deletions.
1 change: 1 addition & 0 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ add_library(mwr STATIC
${src}/mwr/utils/modules.cpp
${src}/mwr/utils/options.cpp
${src}/mwr/utils/srec.cpp
${src}/mwr/utils/ihex.cpp
${src}/mwr/utils/terminal.cpp
${src}/mwr/utils/uimage.cpp)

Expand Down
1 change: 1 addition & 0 deletions include/mwr.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@
#include "mwr/utils/options.h"
#include "mwr/utils/socket.h"
#include "mwr/utils/srec.h"
#include "mwr/utils/ihex.h"
#include "mwr/utils/terminal.h"
#include "mwr/utils/uimage.h"

Expand Down
45 changes: 45 additions & 0 deletions include/mwr/utils/ihex.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/******************************************************************************
* *
* Copyright (C) 2024 MachineWare GmbH *
* All Rights Reserved *
* *
* This is work is licensed under the terms described in the LICENSE file *
* found in the root directory of this source tree. *
* *
******************************************************************************/

#ifndef MWR_UTILS_IHEX_H
#define MWR_UTILS_IHEX_H

#include "mwr/core/types.h"
#include "mwr/core/report.h"

#include "mwr/stl/strings.h"
#include "mwr/stl/containers.h"

namespace mwr {

class ihex
{
public:
struct record {
u64 addr;
vector<u8> data;
};

u64 start_addr() const { return m_start_addr; }
const vector<record>& records() const { return m_records; }

ihex(const string& filename);
~ihex() = default;

ihex(const ihex&) = delete;

private:
u64 m_start_addr;
vector<record> m_records;
};

} // namespace mwr

#endif
141 changes: 141 additions & 0 deletions src/mwr/utils/ihex.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,141 @@
/******************************************************************************
* *
* Copyright (C) 2024 MachineWare GmbH *
* All Rights Reserved *
* *
* This is work is licensed under the terms described in the LICENSE file *
* Found in the root directory of this source tree. *
* *
******************************************************************************/

#include "mwr/utils/ihex.h"

namespace mwr {

enum record_type : u8 {
IHEX_DATA = 0x00,
IHEX_EOF = 0x01,
IHEX_EX_SEG = 0x02,
IHEX_START_SEG = 0x03,
IHEX_EX_LIN_ADDR = 0x04,
IHEX_START_LIN_ADDR = 0x05,
INVALID_LINE_FORMAT,
INVALID_LINE_LEN,
INVALID_TYPE,
INVALID_DESCRIPTOR,
INVALID_CHECKSUM,
};

struct ihex_record {
record_type type;
u64 addr;
vector<u8> data;
};

static inline u8 ihex_byte(const string& line, size_t off) {
MWR_ERROR_ON(off + 1 >= line.size(), "reading beyond srec line");
return from_hex_ascii(line[off]) << 4 | from_hex_ascii(line[off + 1]);
}

template <typename T>
static inline u64 vec_to(const std::vector<u8>& vec) {
constexpr size_t num_bytes = sizeof(T);
MWR_ERROR_ON(num_bytes > vec.size(), "reading beyond given vector");
T result = 0;
for (size_t i = 0; i < num_bytes; ++i)
result = (result << 8) | vec[i];
return result;
}

static inline ihex_record process_line(const string& line) {
const size_t delim = 1;
const size_t data_start = 9;
const size_t check_bytes = 1;
const size_t min_line_len = data_start + check_bytes * 2;

if (line.size() < min_line_len || line[0] != ':')
return { INVALID_LINE_FORMAT, 0, { 0 } };

const u32 nr_bytes = ihex_byte(line, 1);
const u16 addr = ihex_byte(line, 3) << 8 | ihex_byte(line, 5);
const record_type r_type = static_cast<record_type>(ihex_byte(line, 7));
const size_t line_len = min_line_len + nr_bytes * 2;

if (line.size() < line_len)
return { INVALID_LINE_LEN, 0, { 0 } };

u8 check_sum = 0;
for (size_t pos = delim; pos < line_len; pos += 2)
check_sum += ihex_byte(line, pos);
if (check_sum != 0x00)
return { INVALID_CHECKSUM, 0, {} };

switch (r_type) {
case IHEX_DATA:
break;
case IHEX_EOF:
if (nr_bytes != 0x00 || addr != 0x0000)
return { INVALID_DESCRIPTOR, 0, {} };
return { IHEX_EOF, 0, {} };
case IHEX_EX_SEG:
case IHEX_EX_LIN_ADDR:
if (nr_bytes != 0x02 || addr != 0x0000)
return { INVALID_DESCRIPTOR, 0, {} };
break;
case IHEX_START_SEG:
case IHEX_START_LIN_ADDR:
if (nr_bytes != 0x04 || addr != 0x0000)
return { INVALID_DESCRIPTOR, 0, {} };
break;
default:
return { INVALID_TYPE, 0, {} };
}

vector<u8> data;
data.reserve(nr_bytes);
for (size_t pos = data_start; pos < data_start + nr_bytes * 2; pos += 2)
data.push_back(ihex_byte(line, pos));
return { r_type, addr, std::move(data) };
}

ihex::ihex(const string& filename): m_start_addr(), m_records() {
ifstream file(filename);
MWR_ERROR_ON(!file, "Cannot open ihex file '%s'", filename.c_str());

u64 seg_offset = 0;
u64 linear_offset = 0;
string line;
while (getline(file, line)) {
line = trim(line);
ihex_record ihex_rec = process_line(line);

switch (ihex_rec.type) {
case IHEX_DATA: {
record rec = {};
rec.addr = ihex_rec.addr + seg_offset + linear_offset;
rec.data = std::move(ihex_rec.data);
m_records.push_back(std::move(rec));
break;
};
case IHEX_EOF:
return;
case IHEX_EX_SEG:
seg_offset = vec_to<u16>(ihex_rec.data) << 4;
break;
case IHEX_START_SEG:
case IHEX_START_LIN_ADDR:
m_start_addr = vec_to<u32>(ihex_rec.data);
break;
case IHEX_EX_LIN_ADDR:
linear_offset = vec_to<u16>(ihex_rec.data) << 16;
break;
default:
break;
}
}
MWR_REPORT_ON(m_records.size() == 0,
"File '%s' does not seem to be in Intel hex format",
filename.c_str());
}

} // namespace mwr
9 changes: 9 additions & 0 deletions test/resources/sample.ihex
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
:04000005000000CD2A //start address = 0x000000CD
:10010000214601360121470136007EFE09D2190140
:100110002146017E17C20001FF5F16002148011928
:020000040800F2//extended linear address by 0x800 << 16
:10012000194E79234623965778239EDA3F01B2CAA7
:0200000200001FA//extended linear address by 0x1 << 4
:100130003F0156702B5E712B722B732146013421C7
:100130003F0156702B5E712B722B732146013421C6 //broken checksum -> should not appear as line in test
:00000001FF//eof
1 change: 1 addition & 0 deletions test/utils/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -29,5 +29,6 @@ util_test(modules)
util_test(options)
util_test(socket)
util_test(srec)
util_test(ihex)
util_test(terminal)
util_test(uimage)
44 changes: 44 additions & 0 deletions test/utils/ihex.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/******************************************************************************
* *
* Copyright (C) 2024 MachineWare GmbH *
* All Rights Reserved *
* *
* This is work is licensed under the terms described in the LICENSE file *
* found in the root directory of this source tree. *
* *
******************************************************************************/

#include "testing.h"

#include "mwr.h"

using namespace mwr;

const vector<u8> V1 = { 0x21, 0x46, 0x01, 0x36, 0x01, 0x21, 0x47, 0x01,
0x36, 0x00, 0x7E, 0xFE, 0x09, 0xD2, 0x19, 0x01 };

const vector<u8> V2 = { 0x21, 0x46, 0x01, 0x7E, 0x17, 0xC2, 0x00, 0x01,
0xFF, 0x5F, 0x16, 0x00, 0x21, 0x48, 0x01, 0x19 };

const vector<u8> V3 = { 0x19, 0x4E, 0x79, 0x23, 0x46, 0x23, 0x96, 0x57,
0x78, 0x23, 0x9E, 0xDA, 0x3F, 0x01, 0xB2, 0xCA };

const vector<u8> V4 = { 0x3F, 0x01, 0x56, 0x70, 0x2B, 0x5E, 0x71, 0x2B,
0x72, 0x2B, 0x73, 0x21, 0x46, 0x01, 0x34, 0x21 };

TEST(ihex, load) {
ihex reader(get_resource_path("sample.ihex"));

EXPECT_EQ(reader.start_addr(), 0xcd);
ASSERT_EQ(reader.records().size(), 4);

EXPECT_EQ(reader.records()[0].addr, 0x0100);
EXPECT_EQ(reader.records()[1].addr, 0x0110);
EXPECT_EQ(reader.records()[2].addr, 0x0120 | 0x800 << 16);
EXPECT_EQ(reader.records()[3].addr, 0x0130 | 0x800 << 16 | 0x1 << 4);

EXPECT_EQ(reader.records()[0].data, V1);
EXPECT_EQ(reader.records()[1].data, V2);
EXPECT_EQ(reader.records()[2].data, V3);
EXPECT_EQ(reader.records()[3].data, V4);
}

0 comments on commit 150dd2e

Please sign in to comment.