-
Notifications
You must be signed in to change notification settings - Fork 0
/
ihex.c
318 lines (300 loc) · 9.31 KB
/
ihex.c
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
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
#include <stdio.h>
#include <string.h>
#include "ihex.h"
logger_t ihexlogger=defaultlogger;
/*!\brief Default logger callback
* \param level Severity of message
* \param msg Message to print
*/
void defaultlogger(loglevel_t level,char *msg,...){
if(level>LL_DEBUG){
va_list arg;
va_start(arg,msg);
vprintf(msg,arg);
printf("\r\n");
}
}
/*!\brief Parses and converts n bytes of a hex string to an integer
* \param data String with hexadecimal codes
* \param length Number of bytes to convert
* \return Integer value
*/
int parse_hex(char *data,unsigned int length){
char d[length+1];
memcpy(d,data,length);
d[length]=0;
return strtol(d,0,16);
}
/*!\brief Parses a hex file
* \param filename Path to the file to be processed
* \param memory Memory object to be populated
* \return Number of records processed
*/
int parse_file(char *filename,memory_t *memory){
FILE *fd=fopen(filename,"rb");
if(fd){
fseek(fd,0,SEEK_END);
int l=ftell(fd);
fseek(fd,0,SEEK_SET);
char buffer[l+1];
fread(buffer,l,1,fd);
fclose(fd);
return parse_string(buffer,l,memory);
}
else{
ihexlogger(LL_ERROR,"Could not open %s",filename);
return -1;
}
}
/*!\brief Parses a string of intelhex data
* \param data String to process, must be in intelhex format
* \param length Number of bytes in string
* \param memory Memory object to be processed
* \return Number of records processed
*/
int parse_string(char *data,unsigned int length,memory_t *memory){
unsigned long base=0;
unsigned int line=0;
unsigned int p=0;
int eof=0;
int r=0;
while(p<length){
uint8_t c=data[p++];
if(c==':' && length-p>8){
uint8_t bytecount=parse_hex(data+p,2);
uint16_t address=parse_hex(data+p+2,4);
uint8_t rectype=parse_hex(data+p+6,2);
line++;
p+=8;
if(length-p>=bytecount*2+2){
if(eof){
ihexlogger(LL_WARNING,"Record after EOF in line #%d",line);
}
segment_t segment;
segment_init(&segment,base+address,bytecount);
uint8_t checksum=bytecount;
checksum+=address>>8;
checksum+=address&0xff;
checksum+=rectype;
for(uint8_t i=0;i<bytecount;i++){
segment_set(&segment,i,parse_hex(data+p,2));
checksum+=segment_get(&segment,i);
p+=2;
}
if((uint8_t)((~checksum)+1)==parse_hex(data+p,2)){
if(rectype==0){
// Normal data record
memory_add(memory,&segment);
}
else if(rectype==1){
// EOF record
eof=1;
}
else if(rectype==2){
// Extended segment address record
base=segment_get(&segment,0)<<12;
base+=segment_get(&segment,1)<<4;
}
else if(rectype==3){
// Start segment address record
memory->start=segment_get(&segment,0)<<8;
memory->start+=segment_get(&segment,1);
}
else if(rectype==4){
// Extended linear address record
base=(segment.buffer[0]<<24)+(segment.buffer[1]<<16);
}
else if(rectype==5){
// Start linear address record
memory->start=segment_get(&segment,0)<<24;
memory->start+=segment_get(&segment,1)<<16;
memory->start+=segment_get(&segment,2)<<8;
memory->start+=segment_get(&segment,3);
}
else{
ihexlogger(LL_ERROR,"Unsupported record in line #%d: %d",line,rectype);
segment_free(&segment);
return -1;
}
p+=2;
r++;
}
else{
ihexlogger(LL_ERROR,"Corrupted data in line #%d",line);
segment_free(&segment);
return -1;
}
segment_free(&segment);
}
else{
ihexlogger(LL_ERROR,"Incomplete data in line #%d",line);
return -1;
}
}
else if(c!='\r' && c!='\n' && c!=' ' && c!='\t' && c!=0){
ihexlogger(LL_WARNING,"Unexpected character %c in line #%d",c,line);
}
}
memory_consilidate(memory);
#ifdef REQUIRE_EOF
ihexlogger(LL_WARNING,"No EOF record in data");
return -1;
#endif
return r;
}
/*!\brief Initializes memory structure
* \param memory Structure to initialize
*/
void memory_init(memory_t *memory){
memset(memory,0,sizeof(memory_t));
}
/*!\brief Deallocates memory structure recursively
* \param memory Memory structure to deallocate
*
* Note: Top-level object is not deallocated as this is typically created
* on the stack. If you have allocated this on the heap you have to call
* free on the top object after calling this method.
*/
void memory_free(struct memory_t *memory){
memory_t *head=memory;
while(head){
if(head->segment){
segment_free(head->segment);
free(head->segment);
head->segment=0;
}
head=head->next;
}
if(memory){
head=memory->next;
while(head){
memory_t *tmp=head;
head=head->next;
free(tmp);
}
}
}
/*!\brief Counts segments in memory structure
* \param memory Structure to iterate
*/
unsigned int memory_count(memory_t *memory){
unsigned int r=0;
memory_t *head=memory;
while(head){
if(head->segment){
r++;
}
head=head->next;
}
return r;
}
/*!\brief Finds number of bytes in all segments held in memory
* \param memory Memory structure to iterate
* \return Number of bytes held in memory structure
*/
unsigned int memory_size(memory_t *memory){
unsigned int r=0;
memory_t *head=memory;
while(head){
if(head->segment){
r+=head->segment->size;
}
head=head->next;
}
return r;
}
/*!\brief Consilidates memory segment which align
* \param memory Memory structure to iterate
*/
void memory_consilidate(memory_t *memory){
memory_t *head=memory;
while(head){
if(head->segment && head->next && head->next->segment){
segment_t *s1=head->segment;
segment_t *s2=head->next->segment;
if(s1->address+s1->size == s2->address){
// Consilidate the two segments
ihexlogger(LL_DEBUG,"Merging segments at 0x%X and 0x%X",s1->address,s2->address);
segment_t *ns=(segment_t*)malloc(sizeof(segment_t));
segment_init(ns,s1->address,s1->size+s2->size);
memcpy(ns->buffer,s1->buffer,s1->size);
memcpy(ns->buffer+s1->size,s2->buffer,s2->size);
segment_free(s1);
segment_free(s2);
free(s1);
free(s2);
head->segment=ns;
// Drop segment from memory
memory_t *next=head->next;
head->next=next->next;
free(next);
continue;
}
}
head=head->next;
}
}
/*!\brief Adds a segment to memory object
* \param memory Memory object to add the the segment to
* \param segment Segment to add to memory object
*/
void memory_add(memory_t *memory,segment_t *segment){
// Create a copy of the segment
segment_t *ns=(segment_t*)malloc(sizeof(segment_t));
segment_init(ns,segment->address,segment->size);
memcpy(ns->buffer,segment->buffer,segment->size);
// Add segment to the stack
if(memory->segment==0){
memory->segment=ns;
}
else{
memory_t *head=memory;
while(head->next){
head=head->next;
}
head->next=(memory_t*)malloc(sizeof(memory_t));
head=head->next;
memory_init(head);
head->segment=ns;
}
}
/*!\brief Initialize segment
* \param segment Segment to initialize
* \param address Starting address of this segment
* \param size Size of this segment
*/
void segment_init(segment_t *segment,uint32_t address,uint32_t size){
segment->address=address;
segment->size=size;
if(size){
segment->buffer=(uint8_t*)malloc(size);
}
else{
segment->buffer=0;
}
if(!segment->buffer){
segment->size=0;
}
}
/*!\brief Free data from segment
*
* Note: The segment object itself is not freed. Only the buffer within.
*/
void segment_free(segment_t *segment){
free(segment->buffer);
segment->buffer=0;
segment->size=0;
}
void segment_set(segment_t *segment,uint32_t index,uint8_t value){
if(index<segment->size){
segment->buffer[index]=value;
}
}
uint8_t segment_get(segment_t *segment,uint32_t index){
if(index<segment->size){
return segment->buffer[index];
}
else{
return 0;
}
}