Ignore:
Timestamp:
May 25, 2010, 1:51:46 PM (14 years ago)
Author:
george
Message:
  • Přidáno: Knihovna VectorObject pro vykreslování vektorových objektů.
  • Přidáno: Knihovna PersistentForm pro uchování stavu oken v registrech.
  • Přidáno: LastOpenedList pro uchování naposledy otevřených souborů.
  • Upraveno: Aktualizace různých knihoven.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • IntelHexFile/UIntelHexFile.pas

    r15 r26  
    44
    55uses
    6   UTextFileStream, SysUtils;
     6  Classes, UTextFileStream, SysUtils, Contnrs, UCommon, UMemoryStreamEx,
     7  DateUtils;
    78
    89type
    9   TArrayofByte = array of Byte;
    10 
    11   TIntelHexFile = class(TTextFileStream)
     10  EFileCorrupted = class(Exception);
     11  EChecksumError = class(Exception);
     12
     13  TIntelHexRecordType = (rtData, rtEndOfFile, rtSegmentAddress, rtExtendedAddress);
     14
     15  TMappedMemory = class(TMemoryStreamEx)
     16    BaseAddress: Integer;
     17  end;
     18
     19  { TIntelHexFile }
     20
     21  TIntelHexFile = class
     22  private
     23    function GetSize:Integer;
     24    procedure WriteBlock(Block: TMappedMemory; StringList:TStringList);
     25    function TwoComplement(Value: Byte): Byte;
    1226  public
    13     function ReadContent: TArrayOfByte;
     27    Blocks: TObjectList; // of TMappedMemory
     28    BytePerLine: Byte;
     29    procedure LoadFromFile(FileName: string);
     30    procedure SaveToFile(FileName: string);
     31    procedure LoadFromStringList(StringList:TStringList);
     32    procedure SaveToStringList(StringList:TStringList);
     33    procedure LoadFromBinFile(FileName: string);
     34    procedure SaveToBinFile(FileName: string);
     35    constructor Create;
     36    destructor Destroy; override;
     37    property Size: Integer read GetSize;
    1438  end;
    1539
     
    1943{ TIntelHexFile }
    2044
    21 function TIntelHexFile.ReadContent: TArrayOfByte;
     45function TIntelHexFile.GetSize:Integer;
     46var
     47  I: Integer;
     48begin
     49  Result := 0;
     50  for I := 0 to Blocks.Count - 1 do
     51    Result := Result + TMappedMemory(Blocks[I]).Size;
     52end;
     53
     54procedure TIntelHexFile.WriteBlock(Block:TMappedMemory; StringList:TStringList)
     55  ;
     56var
     57  I: Integer;
     58  L: Integer;
     59  CheckSum: Byte;
     60  OutputLine: string;
     61  Count: Integer;
     62  Line: TMemoryStreamEx;
     63begin
     64  Line := TMemoryStreamEx.Create;
     65  Block.Position := 0;
     66  for L := 0 to (Block.Size div BytePerLine) do begin
     67    Count := BytePerLine;
     68    if Count > (Block.Size - Block.Position) then
     69      Count := Block.Size - Block.Position;
     70    if Count > 0 then begin
     71      Line.Size := 4 + Count;
     72      Line.Position := 0;
     73      Line.WriteByte(Count);
     74      Line.WriteByte(((Block.Position + Block.BaseAddress) shr 8) and $ff);
     75      Line.WriteByte((Block.Position + Block.BaseAddress) and $ff);
     76      Line.WriteByte(Integer(rtData));
     77      Line.WriteStreamPart(TStream(Block), Count);
     78
     79      CheckSum := TwoComplement(Line.Sum);
     80      Line.WriteByte(CheckSum);
     81
     82      OutputLine := ':';
     83      Line.Position := 0;
     84      for I := 0 to Line.Size - 1 do
     85        OutputLine := OutputLine + IntToHex(Line.ReadByte, 2);
     86      StringList.Add(OutputLine);
     87    end;
     88  end;
     89  Line.Destroy;
     90end;
     91
     92function TIntelHexFile.TwoComplement(Value:Byte):Byte;
     93begin
     94  Result := (not Value + 1) and $ff;
     95end;
     96
     97procedure TIntelHexFile.LoadFromFile(FileName: string);
     98var
     99  StringList: TStringList;
     100begin
     101     StringList := TStringList.Create;
     102  StringList.LoadFromFile(UTF8Decode(FileName));
     103  LoadFromStringList(StringList);
     104  StringList.Destroy;
     105end;
     106
     107procedure TIntelHexFile.LoadFromStringList(StringList: TStringList);
    22108var
    23109  Row: string;
    24110  DataCount: Byte;
    25   RecordType: Byte;
    26   I: Integer;
    27   CRC: Byte;
    28   ComputedCRC: Byte;
    29   Address: Word;
     111  RecordType: TIntelHexRecordType;
     112  I: Integer;
     113  CheckSum: Byte;
     114  LastAddress: Integer;
     115  Address: Integer;
    30116  SegmentAddress: Word;
    31117  ExtendedAddress: Word;
    32   EndOfFile: Boolean;
    33 
    34 function SplitString(var Text: string; Count: Word): string;
    35 begin
    36   Result := Copy(Text, 1, Count);
    37   Delete(Text, 1, Count);
    38 end;
    39 
    40 begin
     118  Block: TMappedMemory;
     119  Line: TMemoryStreamEx;
     120begin
     121  Line := TMemoryStreamEx.Create;
     122  Blocks.Clear;
     123  Block := nil;
     124  LastAddress := -1;
    41125  ExtendedAddress := 0;
    42126  SegmentAddress := 0;
    43   EndOfFile := False;
    44   repeat
    45     ComputedCRC := 0;
    46     Row := ReadLn;
    47     if SplitString(Row, 1) <> ':' then raise Exception.Create('File corrupted');
    48     for I := 0 to (Length(Row) div 2) - 2 do
    49       ComputedCRC := ComputedCRC + StrToInt('$' + Row[I * 2 + 1] + Row[I * 2 + 2]);
    50     ComputedCRC := not (ComputedCRC ) + 1;
    51 
    52     DataCount := StrToInt('$' + SplitString(Row, 2));
    53     Address := StrToInt('$' + SplitString(Row, 4)) + (SegmentAddress shl 4) +
    54       (ExtendedAddress shl 16);
    55     RecordType := StrToInt('$' + SplitString(Row, 2));
     127  for I := 0 to StringList.Count - 1 do begin
     128    Row := Trim(StringList[I]);
     129    if SplitString(Row, 1) <> ':' then
     130      raise EFileCorrupted.Create('File corrupted');
     131
     132    Line.Position := 0;
     133    Line.Size := Length(Row) div 2;
     134    while Length(Row) > 0 do
     135      Line.WriteByte(StrToInt('$' + SplitString(Row, 2)));
     136
     137    // Read CheckSum
     138    Line.Position := Line.Size - 1;
     139    CheckSum := Line.ReadByte;
     140    Line.Size := Line.Size - 1;
     141    if CheckSum <> TwoComplement(Line.Sum) then
     142        raise EChecksumError.Create('Checksum error ' + Row);
     143
     144    Line.Position := 0;
     145    DataCount := Line.ReadByte;
     146    Address := ((Line.ReadByte shl 8) or Line.ReadByte) +
     147      + (SegmentAddress shl 4) + (ExtendedAddress shl 16);
     148
     149    if LastAddress <> Address then begin
     150      Block := TMappedMemory.Create;
     151      Block.BaseAddress := Address;
     152      Blocks.Add(Block);
     153    end;
     154    RecordType := TIntelHexRecordType(Line.ReadByte);
    56155    case RecordType of
    57       0: begin // Data
    58         if Length(Result) < (Address + DataCount) then
    59           SetLength(Result, Address + DataCount);
    60         for I := 0 to DataCount - 1 do begin
    61           Result[Address + I] := StrToInt('$' + SplitString(Row, 2));
    62         end;
    63       end;
    64       1: begin // End-of-file
    65         EndOfFile := True;
    66       end;
    67       2: begin // Segment address
    68         SegmentAddress := StrToInt('$' + SplitString(Row, 4));
     156      rtData: begin
     157        Block.WriteStreamPart(Line, Line.Size - Line.Position);
     158      end;
     159      rtEndOfFile: begin
     160        Break;
     161      end;
     162      rtSegmentAddress: begin
     163        SegmentAddress := (Line.ReadByte shl 8) or Line.ReadByte;
    69164        ExtendedAddress := 0;
    70165      end;
    71       4: begin // Linear extended address
    72         ExtendedAddress := StrToInt('$' + SplitString(Row, 4));
     166      rtExtendedAddress: begin
     167        ExtendedAddress := (Line.ReadByte shl 8) or Line.ReadByte;
    73168        SegmentAddress := 0;
    74169      end;
    75170    end;
    76     CRC := StrToInt('$' + SplitString(Row, 2));
    77     if CRC <> ComputedCRC then raise Exception.Create('Checksum error');
    78   until Eof or EndOfFile;
     171    LastAddress := Address + DataCount;
     172  end;
     173  Line.Destroy;
     174end;
     175
     176procedure TIntelHexFile.SaveToFile(FileName: string);
     177var
     178  StringList: TStringList;
     179begin
     180  StringList := TStringList.Create;
     181  SaveToStringList(StringList);
     182  StringList.SaveToFile(UTF8Decode(FileName));
     183  StringList.Destroy;
     184end;
     185
     186procedure TIntelHexFile.SaveToStringList(StringList: TStringList);
     187var
     188  I: Integer;
     189  Line: TMemoryStreamEx;
     190  OutputLine: string;
     191  CheckSum: Byte;
     192begin
     193  StringList.Clear;
     194
     195  for I := 0 to Blocks.Count - 1 do
     196    WriteBlock(TMappedMemory(Blocks[I]), StringList);
     197
     198  Line := TMemoryStreamEx.Create;
     199
     200  // Write EndOfFile
     201  Line.Size := 4;
     202  Line.WriteByte(0);
     203  Line.WriteByte(0);
     204  Line.WriteByte(0);
     205  Line.WriteByte(Integer(rtEndOfFile));
     206
     207  CheckSum := TwoComplement(Line.Sum);
     208
     209  Line.Position := 0;
     210  OutputLine := ':';
     211  for I := 0 to Line.Size - 1 do
     212    OutputLine := OutputLine + IntToHex(Line.ReadByte, 2);
     213  OutputLine := OutputLine + IntToHex(CheckSum, 2);
     214  StringList.Add(OutputLine);
     215
     216  Line.Destroy;
     217end;
     218
     219procedure TIntelHexFile.LoadFromBinFile(FileName:string);
     220var
     221  NewBlock: TMappedMemory;
     222begin
     223  // TODO: analyze empty areas with FF bytes and split them to blocks
     224  Blocks.Clear;
     225  NewBlock := TMappedMemory.Create;
     226  NewBlock.LoadFromFile(UTF8Decode(FileName));
     227end;
     228
     229procedure TIntelHexFile.SaveToBinFile(FileName:string);
     230var
     231  MergedMemory: TMemoryStreamEx;
     232  I: Integer;
     233begin
     234  MergedMemory := TMemoryStreamEx.Create;
     235
     236  // Fill unused space by unused data (FF)
     237  for I := 0 to Blocks.Count - 1 do
     238   if MergedMemory.Size < (TMappedMemory(Blocks[I]).BaseAddress + TMappedMemory(Blocks[I]).Size) then
     239     MergedMemory.Size := (TMappedMemory(Blocks[I]).BaseAddress + TMappedMemory(Blocks[I]).Size);
     240  MergedMemory.FillByte($ff, MergedMemory.Size);
     241
     242  // Write all memory blocks
     243  for I := 0 to Blocks.Count - 1 do begin
     244    MergedMemory.Position := TMappedMemory(Blocks[I]).BaseAddress;
     245    MergedMemory.WriteStream(TMappedMemory(Blocks[I]), TMappedMemory(Blocks[I]).Size);
     246  end;
     247  MergedMemory.SaveToFile(UTF8Decode(FileName));
     248  MergedMemory.Destroy;
     249end;
     250
     251constructor TIntelHexFile.Create;
     252begin
     253  Blocks := TObjectList.Create;
     254  BytePerLine := 16;
     255end;
     256
     257destructor TIntelHexFile.Destroy;
     258begin
     259  Blocks.Destroy;
     260  inherited Destroy;
    79261end;
    80262
Note: See TracChangeset for help on using the changeset viewer.