Add srec2bin to firmware-utils
[openwrt.git] / tools / firmware-utils / src / srec2bin.c
1 #include <stdio.h>
2 #include <ctype.h>
3
4 //Rev 0.1 Original
5 // 8 Jan 2001 MJH Added code to write data to Binary file
6 // note: outputfile is name.bin, where name is first part
7 // of input file. ie tmp.rec -> tmp.bin
8 //
9 // srec2bin <input SREC file> <Output Binary File> <If Present, Big Endian>
10 //
11 // TAG
12 // bit32u TAG_BIG = 0xDEADBE42;
13 // bit32u TAG_LITTLE = 0xFEEDFA42;
14 //
15 // File Structure
16 //
17 // TAG : 32 Bits
18 // [DATA RECORDS]
19 //
20 // Data Records Structure
21 //
22 // LENGTH : 32 Bits <- Length of DATA, excludes ADDRESS and CHECKSUM
23 // ADDRESS : 32 Bits
24 // DATA : 8 Bits * LENGTH
25 // CHECKSUM: 32 Bits <- 0 - (Sum of Length --> End of Data)
26 //
27 // Note : If Length == 0, Address will be Program Start
28 //
29 //
30 //
31 //
32 //
33
34 #define MajRevNum 0
35 #define MinRevNum 2
36
37
38 #define EndianSwitch(x) ((x >> 24) | (x << 24) | ((x << 8) & (0x00FF0000)) | ((x >> 8) & (0x0000FF00)) )
39
40 typedef unsigned char bit8u;
41 typedef unsigned int bit32u;
42 typedef int bit32;
43
44 #define FALSE 0
45 #define TRUE (!FALSE)
46
47
48 bit32u CheckSum;
49 int RecStart;
50 int debug;
51 int verbose;
52
53 FILE *OpenOutputFile( char *Name );
54 FILE *fOut;
55 bit32u RecLength=0;
56
57 bit32u AddressCurrent;
58
59 bit32u gh(char *cp,int nibs);
60
61 int BigEndian;
62
63 int inputline;
64
65 // char buf[16*1024];
66
67 char buffer[2048];
68 char *cur_ptr;
69 int cur_line=0;
70 int cur_len=0;
71
72 int s1s2s3_total=0;
73
74 bit32u PBVal;
75 int PBValid;
76 bit32u PBAdr;
77
78
79 void dumpfTell(char *s, bit32u Value)
80 {
81 int Length;
82 Length = (int) RecLength;
83 if (debug)
84 printf("[%s ] ftell()[0x%08lX] Length[0x%4X] Length[%4d] Value[0x%08x]\n",
85 s, ftell(fOut), Length, Length, Value);
86 }
87
88 void DispHex(bit32u Hex)
89 {
90 // printf("%X", Hex);
91 }
92
93 void WaitDisplay(void)
94 {
95 static int Count=0;
96 static int Index=0;
97 char iline[]={"-\\|/"};
98
99 Count++;
100 if ((Count % 32)==0)
101 {
102 if (verbose)
103 printf("%c%c",iline[Index++],8);
104 Index &= 3;
105 }
106 }
107
108
109 void binOut32 ( bit32u Data )
110 {
111 // On UNIX machine all 32bit writes need ENDIAN switched
112 // Data = EndianSwitch(Data);
113 // fwrite( &Data, sizeof(bit32u), 1, fOut);
114
115 char sdat[4];
116 int i;
117
118 for(i=0;i<4;i++)
119 sdat[i]=(char)(Data>>(i*8));
120 fwrite( sdat, 1, 4, fOut);
121 dumpfTell("Out32" , Data);
122 }
123
124 // Only update RecLength on Byte Writes
125 // All 32 bit writes will be for Length etc
126
127 void binOut8 ( bit8u Data )
128 {
129 int n;
130 dumpfTell("B4Data" , (bit32u) (Data & 0xFF) );
131 n = fwrite( &Data, sizeof(bit8u), 1, fOut);
132 if (n != 1)
133 printf("Error in writing %X for Address 0x%8X\n", Data, AddressCurrent);
134 RecLength += 1;
135 }
136
137 // Currently ONLY used for outputting Program Start
138
139 void binRecStart(bit32u Address)
140 {
141 RecLength = 0;
142 CheckSum = Address;
143 RecStart = TRUE;
144
145 if (debug)
146 printf("[RecStart] CheckSum[0x%08X] Length[%4d] Address[0x%08X]\n",
147 CheckSum, RecLength, Address);
148
149
150 dumpfTell("RecLength", RecLength);
151 binOut32( RecLength );
152 dumpfTell("Address", Address);
153 binOut32( Address );
154 }
155
156 void binRecEnd(void)
157 {
158 long RecEnd;
159
160 if (!RecStart) // if no record started, do not end it
161 {
162 return;
163 }
164
165 RecStart = FALSE;
166
167
168 RecEnd = ftell(fOut); // Save Current position
169
170 if (debug)
171 printf("[RecEnd ] CheckSum[0x%08X] Length[%4d] Length[0x%X] RecEnd[0x%08lX]\n",
172 CheckSum, RecLength, RecLength, RecEnd);
173
174 fseek( fOut, -((long) RecLength), SEEK_CUR); // move back Start Of Data
175
176 dumpfTell("Data ", -1);
177
178 fseek( fOut, -4, SEEK_CUR); // move back Start Of Address
179
180 dumpfTell("Address ", -1);
181
182 fseek( fOut, -4, SEEK_CUR); // move back Start Of Length
183
184 dumpfTell("Length ", -1);
185
186 binOut32( RecLength );
187
188 fseek( fOut, RecEnd, SEEK_SET); // move to end of Record
189
190 CheckSum += RecLength;
191
192 CheckSum = ~CheckSum + 1; // Two's complement
193
194 binOut32( CheckSum );
195
196 if (verbose)
197 printf("[Created Record of %d Bytes with CheckSum [0x%8X]\n", RecLength, CheckSum);
198 }
199
200 void binRecOutProgramStart(bit32u Address)
201 {
202 if (Address != (AddressCurrent+1))
203 {
204 binRecEnd();
205 binRecStart(Address);
206 }
207 AddressCurrent = Address;
208 }
209 void binRecOutByte(bit32u Address, bit8u Data)
210 {
211 // If Address is one after Current Address, output Byte
212 // If not, close out last record, update Length, write checksum
213 // Then Start New Record, updating Current Address
214
215 if (Address != (AddressCurrent+1))
216 {
217 binRecEnd();
218 binRecStart(Address);
219 }
220 AddressCurrent = Address;
221 CheckSum += Data;
222 binOut8( Data );
223 }
224
225 //=============================================================================
226 // SUPPORT FUNCTIONS
227 //=============================================================================
228 int readline(FILE *fil,char *buf,int len)
229 {
230 int rlen;
231
232 rlen=0;
233 if (len==0) return(0);
234 while(1)
235 {
236 if (cur_len==0)
237 {
238 cur_len=fread(buffer, 1, sizeof(buffer), fil);
239 if (cur_len==0)
240 {
241 if (rlen)
242 {
243 *buf=0;
244 return(rlen);
245 }
246 return(-1);
247 }
248 cur_ptr=buffer;
249 }
250 if (cur_len)
251 {
252 if (*cur_ptr=='\n')
253 {
254 *buf=0;
255 cur_ptr++;
256 cur_len--;
257 return(rlen);
258 }
259 else
260 {
261 if ((len>1)&&(*cur_ptr!='\r'))
262 {
263 *buf++=*cur_ptr++;
264 len--;
265 }
266 else
267 cur_ptr++;
268
269 rlen++;
270 cur_len--;
271 }
272 }
273 else
274 {
275 *buf=0;
276 cur_ptr++;
277 cur_len--;
278 return(rlen);
279 }
280 }
281 }
282
283
284 int SRLerrorout(char *c1,char *c2)
285 {
286 printf("\nERROR: %s - '%s'.",c1,c2);
287 return(FALSE);
288 }
289
290
291 int checksum(char *cp,int count)
292 {
293 char *scp;
294 int cksum;
295 int dum;
296
297 scp=cp;
298 while(*scp)
299 {
300 if (!isxdigit(*scp++))
301 return(SRLerrorout("Invalid hex digits",cp));
302 }
303 scp=cp;
304
305 cksum=count;
306
307 while(count)
308 {
309 cksum += gh(scp,2);
310 if (count == 2)
311 dum = ~cksum;
312 scp += 2;
313 count--;
314 }
315 cksum&=0x0ff;
316 // printf("\nCk:%02x",cksum);
317 return(cksum==0x0ff);
318 }
319
320 bit32u gh(char *cp,int nibs)
321 {
322 int i;
323 bit32u j;
324
325 j=0;
326
327 for(i=0;i<nibs;i++)
328 {
329 j<<=4;
330 if ((*cp>='a')&&(*cp<='z')) *cp &= 0x5f;
331 if ((*cp>='0')&&(*cp<='9'))
332 j += (*cp-0x30);
333 else
334 if ((*cp>='A')&&(*cp<='F'))
335 j += (*cp-0x37);
336 else
337 SRLerrorout("Bad Hex char", cp);
338 cp++;
339 }
340 return(j);
341 }
342
343
344 //=============================================================================
345 // PROCESS SREC LINE
346 //=============================================================================
347
348 int srecLine(char *pSrecLine)
349 {
350 char *scp,ch;
351 int itmp,count,dat;
352 bit32u adr;
353 static bit32u RecordCounter=0;
354
355 cur_line++;
356 scp=pSrecLine;
357
358 if (*pSrecLine!='S')
359 return(SRLerrorout("Not an Srecord file",scp));
360 pSrecLine++;
361 if (strlen(pSrecLine)<4)
362 return(SRLerrorout("Srecord too short",scp));
363
364 ch=*pSrecLine++;
365
366 count=gh(pSrecLine,2);
367
368 pSrecLine += 2;
369
370 // if(debug)
371 // printf("count %d, strlen(pSrecLine) = %d, pSrecLine =[%s]\n", count, strlen(pSrecLine), pSrecLine);
372 RecordCounter++;
373 DispHex(RecordCounter);
374
375 if ((count*2) != strlen(pSrecLine)) return(SRLerrorout("Count field larger than record",scp));
376
377 if (!checksum(pSrecLine, count)) return(SRLerrorout("Bad Checksum",scp));
378
379 switch(ch)
380 {
381 case '0': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
382 itmp=gh(pSrecLine,4); pSrecLine+=4; count-=2;
383 if (itmp) return(SRLerrorout("Srecord 1 address not zero",scp));
384 break;
385 case '1': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
386 return(SRLerrorout("Srecord Not valid for MIPS",scp));
387 break;
388 case '2': if (count<4) return(SRLerrorout("Invalid Srecord count field",scp));
389 return(SRLerrorout("Srecord Not valid for MIPS",scp));
390 break;
391 case '3': if (count<5) return(SRLerrorout("Invalid Srecord count field",scp));
392 adr=gh(pSrecLine,8); pSrecLine+=8; count-=4;
393 count--;
394 while(count)
395 {
396 dat=gh(pSrecLine,2); pSrecLine+=2; count--;
397 binRecOutByte(adr, (char) (dat & 0xFF));
398 adr++;
399 }
400 s1s2s3_total++;
401 break;
402 case '4': return(SRLerrorout("Invalid Srecord type",scp));
403 break;
404 case '5': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
405 itmp=gh(pSrecLine,4); pSrecLine+=4; count-=2;
406 if (itmp|=s1s2s3_total) return(SRLerrorout("Incorrect number of S3 Record processed",scp));
407 break;
408 case '6': return(SRLerrorout("Invalid Srecord type",scp));
409 break;
410 case '7': // PROGRAM START
411 if (count<5) return(SRLerrorout("Invalid Srecord count field",scp));
412 adr=gh(pSrecLine,8); pSrecLine+=8; count-=4;
413 if (count!=1) return(SRLerrorout("Invalid Srecord count field",scp));
414 binRecOutProgramStart(adr);
415 break;
416 case '8': if (count<4) return(SRLerrorout("Invalid Srecord count field",scp));
417 return(SRLerrorout("Srecord Not valid for MIPS",scp));
418 break;
419 case '9': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp));
420 return(SRLerrorout("Srecord Not valid for MIPS",scp));
421 break;
422 default:
423 break;
424 }
425 return(TRUE);
426 }
427
428
429 //=============================================================================
430 // MAIN LOGIC, READS IN LINE AND OUTPUTS BINARY
431 //=============================================================================
432
433 int srec2bin(int argc,char *argv[],int verbose)
434 {
435 int i,rlen,sts;
436 FILE *fp;
437 char ac;
438 char buff[256];
439 bit32u TAG_BIG = 0xDEADBE42;
440 bit32u TAG_LITTLE = 0xFEEDFA42;
441
442 bit32u Tag;
443
444
445 if(argc < 3)
446 {
447 printf("\nError: <srec2bin <srec input file> <bin output file>\n\n");
448 return(0);
449 }
450
451 if (argc > 3) BigEndian=TRUE; else BigEndian=FALSE;
452
453 if (BigEndian)
454 Tag = TAG_BIG;
455 else
456 Tag = TAG_LITTLE;
457
458 if (verbose)
459 printf("\nEndian: %s, Tag is 0x%8X\n",(BigEndian)?"BIG":"LITTLE", Tag);
460
461 fp = fopen(argv[1],"rt");
462
463 if (fp==NULL)
464 {
465 printf("\nError: Opening input file, %s.", argv[1]);
466 return(0);
467 }
468
469 fOut = fopen( argv[2], "wb");
470
471 if (fOut==NULL)
472 {
473 printf("\nError: Opening Output file, %s.", argv[2]);
474 if(fp) fclose(fp);
475 return(0);
476 }
477
478 RecStart = FALSE;
479
480 AddressCurrent = 0xFFFFFFFFL;
481
482 // Setup Tag
483
484 dumpfTell("Tag", Tag);
485
486 binOut32(Tag);
487
488
489 inputline=0;
490 sts=TRUE;
491
492 rlen = readline(fp,buff,sizeof buff);
493
494 while( (sts) && (rlen != -1))
495 {
496 if (strlen(buff))
497 {
498 sts &= srecLine(buff);
499 WaitDisplay();
500 }
501 rlen = readline(fp,buff,sizeof buff);
502 }
503
504
505 // printf("PC: 0x%08X, Length 0x%08X, Tag 0x%08X\n", ProgramStart, RecLength, TAG_LITTLE);
506
507 binRecEnd();
508
509 if(fp) fclose(fp);
510 if(fOut) fclose(fOut);
511
512 return(1);
513 }
514
515 main(int argc, char *argv[])
516 {
517 debug = TRUE;
518 debug = FALSE;
519 verbose = FALSE;
520 srec2bin(argc,argv,verbose);
521 return 0;
522 }
523
This page took 0.076945 seconds and 5 git commands to generate.