finally move buildroot-ng to trunk
[openwrt.git] / target / image / ar7 / 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