diff options
| author | ejka <ejka@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2007-03-18 09:33:39 +0000 | 
|---|---|---|
| committer | ejka <ejka@3c298f89-4303-0410-b956-a3cf2f4a3e73> | 2007-03-18 09:33:39 +0000 | 
| commit | 865cfde1ef9a81d05ce7512d9e2bef05d4270732 (patch) | |
| tree | c7ebde29c1cfd9428bba666914c8a7eb96a90654 /tools/firmware-utils/src | |
| parent | 01d129a6a2f7837aa409988ba7a9aa57d0efd0c3 (diff) | |
Add srec2bin to firmware-utils
git-svn-id: svn://svn.openwrt.org/openwrt/trunk@6599 3c298f89-4303-0410-b956-a3cf2f4a3e73
Diffstat (limited to 'tools/firmware-utils/src')
| -rw-r--r-- | tools/firmware-utils/src/srec2bin.c | 523 | 
1 files changed, 523 insertions, 0 deletions
diff --git a/tools/firmware-utils/src/srec2bin.c b/tools/firmware-utils/src/srec2bin.c new file mode 100644 index 000000000..0eb8b2023 --- /dev/null +++ b/tools/firmware-utils/src/srec2bin.c @@ -0,0 +1,523 @@ +#include <stdio.h> +#include <ctype.h> + +//Rev 0.1 Original +// 8 Jan 2001  MJH  Added code to write data to Binary file +//                  note: outputfile is name.bin, where name is first part +//                  of input file.  ie tmp.rec -> tmp.bin +// +//   srec2bin <input SREC file> <Output Binary File> <If Present, Big Endian> +// +//   TAG    +//        bit32u TAG_BIG     = 0xDEADBE42; +//        bit32u TAG_LITTLE  = 0xFEEDFA42; +// +//  File Structure +// +//  TAG    :   32 Bits +//  [DATA RECORDS] +// +//  Data Records Structure +// +//  LENGTH  :  32 Bits    <- Length of DATA, excludes ADDRESS and CHECKSUM +//  ADDRESS :  32 Bits +//  DATA    :  8 Bits * LENGTH +//  CHECKSUM:  32 Bits    <-  0 - (Sum of Length --> End of Data) +// +//  Note : If Length == 0, Address will be Program Start +// +// +//   +// +// + +#define MajRevNum 0 +#define MinRevNum 2 + + +#define EndianSwitch(x) ((x >> 24) | (x << 24) | ((x << 8) & (0x00FF0000)) | ((x >> 8) & (0x0000FF00)) ) + +typedef unsigned char bit8u; +typedef unsigned int bit32u; +typedef int bit32; + +#define FALSE 0 +#define TRUE (!FALSE) + + +bit32u CheckSum; +int RecStart; +int debug; +int verbose; + +FILE *OpenOutputFile( char *Name ); +FILE *fOut; +bit32u RecLength=0; + +bit32u AddressCurrent; + +bit32u gh(char *cp,int nibs); + +int BigEndian; + +int inputline; + +// char buf[16*1024]; + +char buffer[2048]; +char *cur_ptr; +int cur_line=0; +int cur_len=0; + +int s1s2s3_total=0; + +bit32u PBVal; +int    PBValid; +bit32u PBAdr; + + +void dumpfTell(char *s, bit32u Value) +{ +    int Length; +    Length = (int) RecLength; +    if (debug) +          printf("[%s  ] ftell()[0x%08lX] Length[0x%4X] Length[%4d] Value[0x%08x]\n", +                s, ftell(fOut), Length, Length, Value); +} + +void DispHex(bit32u Hex) +{ +//    printf("%X", Hex); +} + +void WaitDisplay(void) +{ +   static int Count=0; +   static int Index=0; +   char iline[]={"-\\|/"}; + +   Count++; +   if ((Count % 32)==0) +   { +     if (verbose) +        printf("%c%c",iline[Index++],8); +     Index &= 3; +   } +} + + +void binOut32 ( bit32u Data ) +{ +// On UNIX machine all 32bit writes need ENDIAN switched +//    Data = EndianSwitch(Data); +//    fwrite( &Data, sizeof(bit32u), 1, fOut); + +   char sdat[4]; +   int i; + +   for(i=0;i<4;i++) +    sdat[i]=(char)(Data>>(i*8)); +   fwrite( sdat, 1, 4, fOut); +   dumpfTell("Out32" , Data); +} + +// Only update RecLength on Byte Writes +// All 32 bit writes will be for Length etc + +void binOut8 ( bit8u Data ) +{ +    int n; +    dumpfTell("B4Data" , (bit32u) (Data & 0xFF) ); +    n = fwrite( &Data, sizeof(bit8u), 1, fOut); +    if (n != 1) +        printf("Error in writing %X for Address 0x%8X\n", Data, AddressCurrent); +    RecLength += 1; +} + +//  Currently ONLY used for outputting Program Start + +void binRecStart(bit32u Address) +{ +    RecLength      = 0; +    CheckSum       = Address; +    RecStart       = TRUE; + +    if (debug) +          printf("[RecStart] CheckSum[0x%08X] Length[%4d] Address[0x%08X]\n", +                CheckSum, RecLength, Address); + + +    dumpfTell("RecLength", RecLength); +    binOut32( RecLength ); +    dumpfTell("Address", Address); +    binOut32( Address ); +} + +void binRecEnd(void) +{ +    long RecEnd; + +    if (!RecStart)   //  if no record started, do not end it +    { +        return; +    } + +    RecStart = FALSE; + + +    RecEnd = ftell(fOut);         // Save Current position + +    if (debug) +          printf("[RecEnd  ] CheckSum[0x%08X] Length[%4d] Length[0x%X] RecEnd[0x%08lX]\n", +                CheckSum, RecLength, RecLength, RecEnd); + +    fseek( fOut, -((long) RecLength), SEEK_CUR);  // move back Start Of Data + +    dumpfTell("Data   ", -1); + +    fseek( fOut, -4, SEEK_CUR);  // move back Start Of Address + +    dumpfTell("Address   ", -1); + +    fseek( fOut, -4, SEEK_CUR);  // move back Start Of Length + +    dumpfTell("Length   ", -1); + +    binOut32( RecLength ); + +    fseek( fOut, RecEnd, SEEK_SET);  // move to end of Record + +    CheckSum += RecLength; + +    CheckSum =  ~CheckSum + 1;  // Two's complement + +    binOut32( CheckSum ); + +    if (verbose) +        printf("[Created Record of %d Bytes with CheckSum [0x%8X]\n", RecLength, CheckSum); +} + +void binRecOutProgramStart(bit32u Address) +{ +    if (Address != (AddressCurrent+1)) +    { +        binRecEnd(); +        binRecStart(Address); +    } +    AddressCurrent = Address; +} +void binRecOutByte(bit32u Address, bit8u Data) +{ +    //  If Address is one after Current Address, output Byte +    //  If not, close out last record, update Length, write checksum +    //  Then Start New Record, updating Current Address + +    if (Address != (AddressCurrent+1)) +    { +        binRecEnd(); +        binRecStart(Address); +    } +    AddressCurrent = Address; +    CheckSum += Data; +    binOut8( Data ); +} + +//============================================================================= +//       SUPPORT FUNCTIONS +//============================================================================= +int readline(FILE *fil,char *buf,int len) +{ +    int rlen; +     +    rlen=0; +    if (len==0)  return(0); +    while(1) +    { +      if (cur_len==0) +      { +        cur_len=fread(buffer, 1, sizeof(buffer), fil); +        if (cur_len==0) +        { +          if (rlen) +          { +            *buf=0; +            return(rlen); +          } +          return(-1); +        } +        cur_ptr=buffer; +      } +      if (cur_len) +      { +        if (*cur_ptr=='\n') +        { +          *buf=0; +          cur_ptr++; +          cur_len--; +          return(rlen); +        } +         else +         { +           if ((len>1)&&(*cur_ptr!='\r')) +           { +             *buf++=*cur_ptr++; +             len--; +           } +           else +             cur_ptr++; + +           rlen++; +           cur_len--; +         } +      } +      else +      { +        *buf=0; +        cur_ptr++; +        cur_len--; +        return(rlen); +      } +    } +} + + +int SRLerrorout(char *c1,char *c2) +{ +  printf("\nERROR: %s - '%s'.",c1,c2); +  return(FALSE); +} + + +int checksum(char *cp,int count) +{ +  char *scp; +  int cksum; +  int dum; + +  scp=cp; +  while(*scp) +  { +    if (!isxdigit(*scp++)) +      return(SRLerrorout("Invalid hex digits",cp)); +  } +  scp=cp; + +  cksum=count; + +  while(count) +  { +    cksum += gh(scp,2); +    if (count == 2) +        dum = ~cksum; +    scp += 2; +    count--; +  } +  cksum&=0x0ff;  +  //  printf("\nCk:%02x",cksum); +  return(cksum==0x0ff); +} + +bit32u gh(char *cp,int nibs) +{ +  int i; +  bit32u j; + +  j=0; + +  for(i=0;i<nibs;i++) +  { +    j<<=4; +    if ((*cp>='a')&&(*cp<='z')) *cp &= 0x5f; +    if ((*cp>='0')&&(*cp<='9'))  +      j += (*cp-0x30); +     else +      if ((*cp>='A')&&(*cp<='F')) +        j += (*cp-0x37); +       else +        SRLerrorout("Bad Hex char", cp); +    cp++; +  } +  return(j); +} + + +//============================================================================= +//       PROCESS SREC LINE +//============================================================================= + +int srecLine(char *pSrecLine) +{ +    char *scp,ch; +    int  itmp,count,dat; +    bit32u adr; +    static bit32u RecordCounter=0; + +    cur_line++; +    scp=pSrecLine; +   +    if (*pSrecLine!='S') +      return(SRLerrorout("Not an Srecord file",scp)); +    pSrecLine++; +    if (strlen(pSrecLine)<4) +      return(SRLerrorout("Srecord too short",scp)); +   +    ch=*pSrecLine++; +   +    count=gh(pSrecLine,2); +   +    pSrecLine += 2; +   +  //  if(debug) +  //        printf("count %d, strlen(pSrecLine) = %d, pSrecLine =[%s]\n", count, strlen(pSrecLine), pSrecLine); +     RecordCounter++; +     DispHex(RecordCounter); +   +    if ((count*2) != strlen(pSrecLine)) return(SRLerrorout("Count field larger than record",scp)); +   +    if (!checksum(pSrecLine, count)) return(SRLerrorout("Bad Checksum",scp)); +   +    switch(ch) +    { +        case '0': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp)); +                  itmp=gh(pSrecLine,4); pSrecLine+=4; count-=2; +                  if (itmp) return(SRLerrorout("Srecord 1 address not zero",scp)); +        break; +        case '1': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp)); +                  return(SRLerrorout("Srecord Not valid for MIPS",scp)); +        break; +        case '2': if (count<4) return(SRLerrorout("Invalid Srecord count field",scp)); +                  return(SRLerrorout("Srecord Not valid for MIPS",scp)); +        break; +        case '3': if (count<5) return(SRLerrorout("Invalid Srecord count field",scp)); +                  adr=gh(pSrecLine,8); pSrecLine+=8; count-=4; +                  count--; +                  while(count) +                  { +                    dat=gh(pSrecLine,2); pSrecLine+=2; count--; +                    binRecOutByte(adr, (char) (dat & 0xFF)); +                    adr++; +                  } +                  s1s2s3_total++; +        break; +        case '4': return(SRLerrorout("Invalid Srecord type",scp)); +        break; +        case '5': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp)); +                  itmp=gh(pSrecLine,4); pSrecLine+=4; count-=2; +                  if (itmp|=s1s2s3_total) return(SRLerrorout("Incorrect number of S3 Record processed",scp)); +        break; +        case '6': return(SRLerrorout("Invalid Srecord type",scp)); +        break; +        case '7': // PROGRAM START +                  if (count<5) return(SRLerrorout("Invalid Srecord count field",scp)); +                  adr=gh(pSrecLine,8); pSrecLine+=8; count-=4; +                  if (count!=1) return(SRLerrorout("Invalid Srecord count field",scp)); +                  binRecOutProgramStart(adr); +        break; +        case '8': if (count<4) return(SRLerrorout("Invalid Srecord count field",scp)); +                  return(SRLerrorout("Srecord Not valid for MIPS",scp)); +        break; +        case '9': if (count<3) return(SRLerrorout("Invalid Srecord count field",scp)); +                  return(SRLerrorout("Srecord Not valid for MIPS",scp)); +        break; +        default: +        break; +    } +    return(TRUE); +} +  + +//============================================================================= +//       MAIN LOGIC, READS IN LINE AND OUTPUTS BINARY +//============================================================================= + +int srec2bin(int argc,char *argv[],int verbose) +{ +    int i,rlen,sts; +    FILE *fp; +    char ac; +    char buff[256]; +    bit32u TAG_BIG     = 0xDEADBE42; +    bit32u TAG_LITTLE  = 0xFEEDFA42; + +    bit32u Tag; + +   +    if(argc < 3) +    { +      printf("\nError: <srec2bin <srec input file> <bin output file>\n\n"); +      return(0); +    } +   +    if (argc > 3) BigEndian=TRUE; else BigEndian=FALSE; + +    if (BigEndian) +        Tag = TAG_BIG; +    else +        Tag = TAG_LITTLE; + +    if (verbose) +       printf("\nEndian: %s, Tag is 0x%8X\n",(BigEndian)?"BIG":"LITTLE", Tag); + +    fp = fopen(argv[1],"rt"); + +    if (fp==NULL) +    { +      printf("\nError: Opening input file, %s.", argv[1]); +      return(0); +    } +   +    fOut = fopen( argv[2], "wb"); +     +    if (fOut==NULL) +    { +      printf("\nError: Opening Output file, %s.", argv[2]); +      if(fp) fclose(fp); +      return(0); +    } +  +    RecStart = FALSE; + +    AddressCurrent = 0xFFFFFFFFL; + +    // Setup Tag  +   +    dumpfTell("Tag", Tag); + +    binOut32(Tag); + +   +    inputline=0; +    sts=TRUE; + +    rlen = readline(fp,buff,sizeof buff); + +    while( (sts) && (rlen != -1)) +    { +        if (strlen(buff)) +        { +            sts &= srecLine(buff); +            WaitDisplay(); +        } +       rlen = readline(fp,buff,sizeof buff); +    } + +   +  //  printf("PC: 0x%08X, Length 0x%08X, Tag 0x%08X\n", ProgramStart, RecLength, TAG_LITTLE); +   +    binRecEnd(); + +    if(fp) fclose(fp); +    if(fOut) fclose(fOut); + +    return(1); +} + +main(int argc, char *argv[]) +{ +    debug = TRUE; +    debug = FALSE; +    verbose = FALSE; +    srec2bin(argc,argv,verbose); +    return 0; +} +  | 
