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