program CFlash_Example1;
{Tento priklad zkopiruje obsah souboru File1.dat do souboru File2.dat nebo naopak,
 podle toho, ktery ze souboru je mensi (kopiruje mensi soubor do vetsiho).
 Soubory mohou mit velikost i nekolik MB.}

uses
  HwSyst,
  NumToStr,
 {$ifdef Kit188}
  Crt2Mem, {obsluhy Video a Keyboard BIOSu pro komunikaci na KitXxx}
  ChnVirt, {knihovna virtualniho komunikacniho kanalu}
  Chn188,  {knihovna vlastniho komunikacniho kanalu pro systemovy COM Kit188}
  ChnCrt,  {komunikacni protokol pro prenos Video a Keyboard}
  CrtComSl,{komunikacni automat pro prenos Video a Keyboard}
 {$endif}
  Crt,
  CFlash,
  FstTimer;

const
  cCopyBuffSize = 5*1024;
type
  pCopyBuff = ^tCopyBuff;
  tCopyBuff = array[1..cCopyBuffSize]of byte; {nejoptimalnejsi velikost pro kopirovani je velikost
                                  sektoru nebo vetsi v nasobcich sektoru}
const
  FileObj   : array[1..2]of
              tCFlash   = ((),());{objekt pro pristup k souborum na CF}
  SourFile  : 1..2      = 1;    {ktery soubor je zdrojovy}
  DestFile  : 1..2      = 2;    {ktery soubor je cilovy}
  CopyBuff  : pCopyBuff = nil;  {mezibuffer pro ctena/zapisovana data}
  AddrForRW : longint   = 0;    {linearni adresa pro cteni/zapis z/do CF}
  LenForRW  : word      = 0;    {delka prave ctenych/zapisovanych dat}
  NumPart   : longint   = 0;    {pocet ctenych/zapisovanych useku souboru}
  CopyTimer : tFstTimer = ();   {casovac pro mereni rychlosti kopirovani}
  Res       : word      = 0;    {pro navratovy kod chyby CF operaci}
  L         : longint   = 0;    {pomocna pro FOR cyklus}

const
 {popis chybovych kodu definovanych knihovnou CFlash}
  ResCF_Str : array[0..10] of string[15] =
        {123456789012345}
   ({ 0}'Ok',
    { 1}'NoCF       ',
    { 2}'FormatCFErr',
    { 3}'NoLinFile  ',
    { 4}'LinFileErr ',
    { 5}'RWOverflow ',
    { 6}'ReadErr    ',
    { 7}'WriteErr   ',
    { 8}'VerifyErr  ',
    { 9}'???',
    {10}'Busy');

function SizeToStr(Size:longint; Des:byte):string;
  {prevede velikost na retezec s koncovym B/KB/MB/GB s poctem Des desetinnych mist}
begin
  if Size<1024 then
    SizeToStr:=LongIntStrDec(Size,3)+'B'
  else
  if Size<1024*1024 then
    SizeToStr:=RealToStr(Size/1024,Des,tpFixedDes)+'KB'
  else
  if Size<1024*1024*1024 then
    SizeToStr:=RealToStr(Size/(1024*1024),Des,tpFixedDes)+'MB'
  else
    SizeToStr:=RealToStr(Size/(1024*1024*1024),Des,tpFixedDes)+'GB'
end;

var
  SaveExit:pointer;
procedure MyExitProc; far;
begin
  ExitProc:=SaveExit;
  if ExitCode<>0 then
  begin
    write('RunTime Error ',ExitCode,' on addr ',PtrToStr(ErrorAddr));
  end;
  repeat
   {$ifdef Kit188}
    CrtComMake;
   {$endif}
  until False;
end;

Begin
 {$ifdef Kit188}
  if InitCrtCom('NAM=CRT MAS=SLAVE LSB=400 '+
                'NAM=188 BD=115200 PAR=E STO=1 LRB=500') <> res_Ok then RunError(10);
 {$endif}

  SaveExit:=ExitProc;
  ExitProc:=@MyExitProc;

  ClrScr;
  writeln('                 * * *  Priklad na knihovnu CFlash  * * *');
  writeln('Compact Flash size: ',CFSize,'B = (',CFSize shr 20,'MB)');
  writeln;

  New(CopyBuff);

  Res:=FileObj[1].CFInit('File1.dat');
  if Res<>resCF_Ok then
  begin
    writeln('File1.dat Init Error: ',ResCF_Str[Res]);
    Halt;
  end
  else
    writeln('File1.dat Init Ok, Size=',SizeToStr(FileObj[1].CFGetFileSize,2));
  Res:=FileObj[2].CFInit('File2.dat');
  if Res<>resCF_Ok then
  begin
    writeln('File2.dat Init Error: ',ResCF_Str[Res]);
    Halt;
  end
  else
    writeln('File2.dat Init Ok, Size=',SizeToStr(FileObj[2].CFGetFileSize,2));
  if FileObj[1].CFGetFileSize>FileObj[2].CFGetFileSize then
  begin
    SourFile:=2;
    DestFile:=1;
  end;
  writeln;

  writeln('Copying ',FileObj[SourFile].CF_FileName,' to ',
                     FileObj[DestFile].CF_FileName,
                     '  (',SizeToStr(FileObj[SourFile].CFGetFileSize,2),')');

  {zjistime na kolik casti budeme kopirovat}
  NumPart:=FileObj[SourFile].CFGetFileSize div SizeOf(tCopyBuff);
  if FileObj[SourFile].CFGetFileSize mod SizeOf(tCopyBuff)<>0 then Inc(NumPart);

  CopyTimer.SaveTime;

  {kopirovaci cyklus}
  for L:=1 to NumPart do
  begin
    if FileObj[SourFile].CFGetFileSize<SizeOf(tCopyBuff)+AddrForRW then
      LenForRW:=FileObj[SourFile].CFGetFileSize-AddrForRW
    else
      LenForRW:=SizeOf(tCopyBuff);

    {nacteme data ze zdrojoveho souboru}
    Res:=FileObj[SourFile].CFRead(AddrForRW,CopyBuff,LenForRW);
    if Res<>resCF_Ok then
    begin
      writeln('SourFile Read Error: ',ResCF_Str[Res]);
      Halt;
    end;
    {zapiseme data do ciloveho souboru}
    Res:=FileObj[DestFile].CFWrite(CopyBuff,AddrForRW,LenForRW);
    if Res<>resCF_Ok then
    begin
      writeln('DestFile Write Error: ',ResCF_Str[Res]);
      Halt;
    end;
    Inc(AddrForRW,LenForRW);

    gotoxy(1,WhereY);
    write(RealToStr(AddrForRW/FileObj[SourFile].CFGetFileSize*100,1,tpFixedDes),'%');

   {$ifdef Kit188}
    CrtComMake;
   {$endif}
  end;
  L:=CopyTimer.ReadTime;
  writeln('  Ok  Time:',L,'ms  (',RealToStr(FileObj[SourFile].CFGetFileSize/1024/(L/1000),3,tpFixedDes),'KB/s)');

  Dispose(CopyBuff);
End.
