-
Notifications
You must be signed in to change notification settings - Fork 36
/
kk_ihex.h
191 lines (174 loc) · 7.29 KB
/
kk_ihex.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
/*
* kk_ihex.h: A simple library for reading and writing the Intel HEX
* or IHEX format. Intended mainly for embedded systems, and thus
* somewhat optimised for size at the expense of error handling and
* generality.
*
* USAGE
* -----
*
* The library has been split into read and write parts, which use a
* common data structure (`struct ihex_state`), but each can be used
* independently. Include the header `kk_ihex_read.h` for reading, and/or
* the header `kk_ihex_write.h` for writing (and link with their respective
* object files). Both can be used simultaneously - this header defines
* the shared data structures and definitions.
*
*
* READING INTEL HEX DATA
* ----------------------
*
* To read data in the Intel HEX format, you must perform the actual reading
* of bytes using other means (e.g., stdio). The bytes read must then be
* passed to `ihex_read_byte` and/or `ihex_read_bytes`. The reading functions
* will then call `ihex_data_read`, at which stage the `struct ihex_state`
* structure will contain the data along with its address. See the header
* `kk_ihex_read.h` for details and example implementation of `ihex_data_read`.
*
* The sequence to read data in IHEX format is:
* struct ihex_state ihex;
* ihex_begin_read(&ihex);
* ihex_read_bytes(&ihex, my_input_bytes, length_of_my_input_bytes);
* ihex_end_read(&ihex);
*
*
* WRITING BINARY DATA AS INTEL HEX
* --------------------------------
*
* In order to write out data, the `ihex_write_at_address` or
* `ihex_write_at_segment` functions are used to set the data location,
* and then the binary bytes are written with `ihex_write_byte` and/or
* `ihex_write_bytes`. The writing functions will then call the function
* `ihex_flush_buffer` whenever the internal write buffer needs to be
* cleared - it is up to the caller to provide an implementation of
* `ihex_flush_buffer` to do the actual writing. See the header
* `kk_ihex_write.h` for details and an example implementation.
*
* See the declaration further down for an example implementation.
*
* The sequence to write data in IHEX format is:
* struct ihex_state ihex;
* ihex_init(&ihex);
* ihex_write_at_address(&ihex, 0);
* ihex_write_bytes(&ihex, my_data, length_of_my_data);
* ihex_end_write(&ihex);
*
* For outputs larger than 64KiB, 32-bit linear addresses are output. Normally
* the initial linear extended address record of zero is NOT written - it can
* be forced by setting `ihex->flags |= IHEX_FLAG_ADDRESS_OVERFLOW` before
* writing the first byte.
*
* Gaps in the data may be created by calling `ihex_write_at_address` with the
* new starting address without calling `ihex_end_write` in between.
*
*
* The same `struct ihex_state` may be used either for reading or writing,
* but NOT both at the same time. Furthermore, a global output buffer is
* used for writing, i.e., multiple threads must not write simultaneously
* (but multiple writes may be interleaved).
*
*
* CONSERVING MEMORY
* -----------------
*
* For memory-critical use, you can save additional memory by defining
* `IHEX_LINE_MAX_LENGTH` as something less than 255. Note, however, that
* this limit affects both reading and writing, so the resulting library
* will be unable to read lines with more than this number of data bytes.
* That said, I haven't encountered any IHEX files with more than 32
* data bytes per line. For write only there is no reason to define the
* maximum as greater than the line length you'll actually be writing,
* e.g., 32 or 16.
*
* If the write functionality is only occasionally used, you can provide
* your own buffer for the duration by defining `IHEX_EXTERNAL_WRITE_BUFFER`
* and providing a `char *ihex_write_buffer` which points to valid storage
* for at least `IHEX_WRITE_BUFFER_LENGTH` characters from before the first
* call to any IHEX write function to until after the last.
*
* If you are doing both reading and writing, you can define the maximum
* output length separately as `IHEX_MAX_OUTPUT_LINE_LENGTH` - this will
* decrease the write buffer size, but `struct ihex_state` will still
* use the larger `IHEX_LINE_MAX_LENGTH` for its data storage.
*
* You can also save a few additional bytes by disabling support for
* segmented addresses, by defining `IHEX_DISABLE_SEGMENTS`. Both the
* read and write modules need to be build with the same option, as the
* resulting data structures will not be compatible otherwise. To be honest,
* this is a fairly pointless optimisation.
*
*
* Copyright (c) 2013-2019 Kimmo Kulovesi, https://arkku.com/
* Provided with absolutely no warranty, use at your own risk only.
* Use and distribute freely, mark modified copies as such.
*/
#ifndef KK_IHEX_H
#define KK_IHEX_H
#define KK_IHEX_VERSION "2019-08-07"
#include <stdint.h>
#ifdef IHEX_USE_STDBOOL
#include <stdbool.h>
typedef bool ihex_bool_t;
#else
typedef uint_fast8_t ihex_bool_t;
#endif
typedef uint_least32_t ihex_address_t;
typedef uint_least16_t ihex_segment_t;
typedef int ihex_count_t;
// Maximum number of data bytes per line (applies to both reading and
// writing!); specify 255 to support reading all possible lengths. Less
// can be used to limit memory footprint on embedded systems, e.g.,
// most programs with IHEX output use 32.
#ifndef IHEX_LINE_MAX_LENGTH
#define IHEX_LINE_MAX_LENGTH 255
#endif
enum ihex_flags {
IHEX_FLAG_ADDRESS_OVERFLOW = 0x80 // 16-bit address overflow
};
typedef uint8_t ihex_flags_t;
typedef struct ihex_state {
ihex_address_t address;
#ifndef IHEX_DISABLE_SEGMENTS
ihex_segment_t segment;
#endif
ihex_flags_t flags;
uint8_t line_length;
uint8_t length;
uint8_t data[IHEX_LINE_MAX_LENGTH + 1];
} kk_ihex_t;
enum ihex_record_type {
IHEX_DATA_RECORD,
IHEX_END_OF_FILE_RECORD,
IHEX_EXTENDED_SEGMENT_ADDRESS_RECORD,
IHEX_START_SEGMENT_ADDRESS_RECORD,
IHEX_EXTENDED_LINEAR_ADDRESS_RECORD,
IHEX_START_LINEAR_ADDRESS_RECORD
};
typedef uint8_t ihex_record_type_t;
#ifndef IHEX_DISABLE_SEGMENTS
// Resolve segmented address (if any). It is the author's recommendation that
// segmented addressing not be used (and indeed the write function of this
// library uses linear 32-bit addressing unless manually overridden).
//
#define IHEX_LINEAR_ADDRESS(ihex) ((ihex)->address + (((ihex_address_t)((ihex)->segment)) << 4))
//
// Note that segmented addressing with the above macro is not strictly adherent
// to the IHEX specification, which mandates that the lowest 16 bits of the
// address and the index of the data byte must be added modulo 64K (i.e.,
// at 16 bits precision with wraparound) and the segment address only added
// afterwards.
//
// To implement fully correct segmented addressing, compute the address
// of _each byte_ with its index in `data` as follows:
//
#define IHEX_BYTE_ADDRESS(ihex, byte_index) ((((ihex)->address + (byte_index)) & 0xFFFFU) + (((ihex_address_t)((ihex)->segment)) << 4))
#else // IHEX_DISABLE_SEGMENTS:
#define IHEX_LINEAR_ADDRESS(ihex) ((ihex)->address)
#define IHEX_BYTE_ADDRESS(ihex, byte_index) ((ihex)->address + (byte_index))
#endif
// The newline string (appended to every output line, e.g., "\r\n")
#ifndef IHEX_NEWLINE_STRING
#define IHEX_NEWLINE_STRING "\n"
#endif
// See kk_ihex_read.h and kk_ihex_write.h for function declarations!
#endif // !KK_IHEX_H