(*
*******************************************************************************
*         Copyright (C) SofCon 2002 All Rights Reserved                       *
*******************************************************************************
*
*    project:     vizualizace
*
*    title:       File1.pas
*
*******************************************************************************
*
*    description: priklad podpory pro dva soubory mensi nez paket
*
*    version:     1.02
*    language:    Borland Pascal
*
*    author:      Hvozdovic
*    history:     date      sign   remark
*                 8.02      hv     zacatek vyvoje
*                11.02      hv     prvni release
*                11.02      hv     zruseni odkazu na ChnPrt, ChnSofs2
*                                  kontrola alokace pameti(NIL) +
*                                       doplneno uvolnovani pameti
*****************************************************************************
*)
{$I sets.inc}

unit File1;
interface
uses
   Objects             { objekty }
  ,ChnVirt             { virtualni kanal }
  ,ChnSofT             { definice typu pro protokol SofCon }
  ,Xtking_1            { definice typu a konstant pro praci s vizualizaci }
  ,NumToStr            { prace s retezci }
  ,WTVirt              { virtualni predek vsech vizualizacnich objektu }
  ,WTFile;             { objekt s podporou prenosu souboru }

type
 { vyctovy typ popisujici banky souboru }
  tFileEnum =
  (
    file_FixData,      {kompletni FixData}
    file_FixData1      {kompletni FixData}
  );

  { definice uzivatelske struktury, ktera bude ctena a zapisovana
    do binarniho souboru }
  tFixData = record
    Version          : longint;       {verze programu}

    UserAppDscr      : string[20];    {uzivatelsky popis firmware}
    UnitId           : Byte;          {cislo stanice pri komunikaci}

    { dalsi data }
    var1             : Byte;
    var2             : Word;
    var3             : LongInt;

{ z duvodu zjednoduseni testu se nepouziva }
{    Crc              : word;          {kontrolni soucet  (musi byt na konci tohoto rekordu)}
  end;


  { objekt pracujici s soubory }
  PFile1 = ^TFile1;
  TFile1 = object(TWinTickFile)
    constructor Init;
    destructor Done; virtual;

   {$ifdef CONVERT_FILENO}
    function   fnConvertFileNo(bFileNo:Byte):Byte; virtual;
   {$endif}
    function   fnGetFileCnt:Byte; virtual;

    procedure  fnAbort; virtual;
    function   fnClose:Byte; virtual;
    procedure  fnGetBankListItem(var FileBankListItem:TFileDataHeader); virtual;
    function   fnGetBankDataOpen(var FileBankDataInfo:TFileBankDataInfo):Byte; virtual;
    function   fnGetBankDataBlock(var FileBankDataBlock:TDataBlockFile):Byte; virtual;
    function   fnPutBankDataOpen(var FileBankDataOpen :TPutFileBankDataOpen):Byte; virtual;
    function   fnPutBankDataBlock(var FileBankDataBlock:TDataBlockFile):Byte; virtual;
  end;


var
  { synchronizacni flag }
  fFileBankIsUsed:Boolean;
  { deskriptory souboru }
  pFileDescArray : array[tFileEnum] of ^TFileDataHeader;
  FixData, FixData1 : tFixData;


{ inicializuje pole struktur popisujicich jednotlive banky souboru
  a uzivatelska data}
procedure InitBankDescUserData;

{ procedura pro zobrazeni stavu - zobrazi se stiskem klavesy "1" }
procedure ShowState;


implementation
uses
  Kernel;       { rozhrani operacniho systemu }

{ inicializuje pole struktur popisujicich jednotlive banky souboru
  a uzivatelska data}
procedure InitBankDescUserData;
begin
  { nastaveni prvni banky souboru }
  New(pFileDescArray[file_FixData]);
  if pFileDescArray[file_FixData]=nil then RunError(255);
  with pFileDescArray[file_FixData]^ do
  begin
    NextHeaderFl := file_FixData<High(tFileEnum);  { priznak ne-posledniho prenaseneho header    }
   {$ifdef CONVERT_FILENO}
    FileBankNum  := 3;                             { cislo banky souboru - zakladni adresa banky }
   {$else}
    FileBankNum  := byte(file_FixData);            { cislo banky souboru - zakladni adresa banky }
   {$endif}
    FileBankName := 'FixData file';                { jmeno banky / jmeno typu banky / urceni banky }
    FileName     := 'FixData.bin';                 { jmeno souboru zavedeneho do banky }
    FileSize     := SizeOf(tFixData);              { velikost souboru v bance }
    FileDaTi     := GetPackTime;                   { datum a cas souboru DOS packed-format }
    FileAttr     := 0;                             { atributy souboru dle Delphi kodovani  }
  end;
  { nastaveni druhe banky souboru }
  New(pFileDescArray[file_FixData1]);
  if pFileDescArray[file_FixData1]=nil then RunError(255);
  with pFileDescArray[file_FixData1]^ do
  begin
    NextHeaderFl := file_FixData1<High(tFileEnum); { priznak ne-posledniho prenaseneho header    }
   {$ifdef CONVERT_FILENO}
    FileBankNum  := 7;                             { cislo banky souboru - zakladni adresa banky }
   {$else}
    FileBankNum  := byte(file_FixData1);           { cislo banky souboru - zakladni adresa banky }
   {$endif}
    FileBankName := 'FixData file1';               { jmeno banky / jmeno typu banky / urceni banky }
    FileName     := 'FixData1.bin';                { jmeno souboru zavedeneho do banky }
    FileSize     := SizeOf(tFixData);              { velikost souboru v bance }
    FileDaTi     := GetPackTime;                   { datum a cas souboru DOS packed-format }
    FileAttr     := 0;                             { atributy souboru dle Delphi kodovani  }
  end;

  { inicializace dat - data se budou cist a zapisovat do binarniho souboru}
  with FixData do
  begin
    Version:=1234;
    UserAppDscr:='2 jednoduche banky';
    UnitId:=2;
    var1:=30;
    var2:=40;
    var3:=50;
  end;
  { inicializace dat - data se budou cist a zapisovat do binarniho souboru}
  with FixData1 do
  begin
    Version:=2345;
    UserAppDscr:='2 jednoduche banky';
    UnitId:=2;
    var1:=130;
    var2:=140;
    var3:=150;
  end;
  fFileBankIsUsed:=False;
end;

procedure ShowState;
var
  fLock:Boolean;
begin
  if fFileBankIsUsed then
  begin
    Writeln('Banky souboru jsou pouzivany, proto nelze zobrazit jejich stav');
    exit;
  end;

  { synchronizace promennych - zamknuti jadra proti prepnuti
    procesu.
    Tato synchronizace je dostatecna pokud k promennym pristupuji
    ruzne procesy. V pripade pristupu k promennym z prerusovaci
    obsluhy by zde musela byt pouzito zakazani preruseni (pushf cli) }
  fLock:=ExLockKernel;
   { zobrazeni uzivatelskych dat}
   with FixData do
   begin
     writeln('FixData:');
     writeln('  Version: ', Version);
     writeln('  UserApp: ', UserAppDscr);
     writeln('  UnitId:  ', UnitId);
     writeln('  var1: ', var1);
     writeln('  var2: ', var2);
     writeln('  var3: ', var3);
   end;
   with FixData1 do
   begin
     writeln('FixData1:');
     writeln('  Version: ', Version);
     writeln('  UserApp: ', UserAppDscr);
     writeln('  UnitId:  ', UnitId);
     writeln('  var1: ', var1);
     writeln('  var2: ', var2);
     writeln('  var3: ', var3);
   end;
  { synchronizace promennych - odemknuti jadra, viz. vyse }
  if not fLock then UnLockKernel;
end;


constructor TFile1.Init;
begin
  inherited Init;

  { inicializace bank souboru a uzivatelskych dat }
  InitBankDescUserData;
end;

destructor TFile1.Done;
begin
  { uvolneni popisovace #1 }
  if pFileDescArray[file_FixData]<>nil then Dispose(pFileDescArray[file_FixData]);
  { uvolneni popisovace #2 }
  if pFileDescArray[file_FixData1]<>nil then Dispose(pFileDescArray[file_FixData1]);

  inherited Done;
end;

{$ifdef CONVERT_FILENO}
function   TFile1.fnConvertFileNo(bFileNo:Byte):Byte;
begin
  { konverze mezi oznacenim banky souboru a indexem banky souboru }
  case bFileNo of
    3: fnConvertFileNo:=0;
    7: fnConvertFileNo:=1;
  else
    fnConvertFileNo:=High(bFileNo);
  end;
end;
{$endif}

function   TFile1.fnGetFileCnt:Byte;
begin
  { vraci pocet bank souboru }
  fnGetFileCnt:=Byte(High(tFileEnum))+1;
end;

procedure  TFile1.fnAbort;
begin
  { zruseni prace s banky souboru }
  fFileBankIsUsed:=False;
end;

function   TFile1.fnClose:Byte;
begin
  { ukonceni prace s banky souboru }
  fFileBankIsUsed:=False;
  fnClose:=erc_file_OK;
end;

procedure  TFile1.fnGetBankListItem(var FileBankListItem:TFileDataHeader);
begin
  { nastaveni headeru popisujiciho pozadovanou banku souboru m_bFile
    Tato funkce slouzi pro ziskani informaci o jednotlivych bankach
    pri jejich zobrazeni ve vizualizaci. }
  FileBankListItem:=pFileDescArray[tFileEnum(m_bFile)]^;
  FileBankListItem.FileDaTi:=GetPackTime;
end;


function  TFile1.fnGetBankDataOpen(var FileBankDataInfo:TFileBankDataInfo):Byte;
begin
  { nastaveni headeru popisujici pozadovanou banku souboru m_bFile.
    Tato funkce se vola pred otevrenim banky pro cteni dat a odrazi
    aktualni stav banky souboru. Stavem banky se predevsim mysli
    aktualni velikost souboru.
    Pozn. v prikladech byly kvuli jednoduchosti pouzity soubory
          s pevnou delkou.
    Pozn. predek provede konverzi indexu banky podle predaneho oznaceni
          banku a nastavi promennou m_bFile }
  fnGetBankDataOpen:=erc_file_Ok;
  FileBankDataInfo:=pFileDescArray[tFileEnum(m_bFile)]^;
  FileBankDataInfo.FileDaTi:=GetPackTime;

  { zde by mel byt kod, ktery aplikaci zabrani v pristupu
    k vybrane bance souboru.
    Pokud by zde kod nebyl mohlo by dojit k rozsynchronizovani
    jednotlivych dat.}
  fFileBankIsUsed:=True;
end;

function  TFile1.fnGetBankDataBlock(var FileBankDataBlock:TDataBlockFile):Byte;
begin
  fnGetBankDataBlock:=erc_file_Ok;
  { vypocet kolik dat lze prenest v jednom datovem paketu
    a nastaveni priznaku prenosu dat ve vice paketech }
  FileBankDataBlock.DataFileOffs:=m_liFileOffs;
  if m_liFileOffs+SizeOf(TBinBlockFile)<=SizeOf(tFixData) then
  begin
    FileBankDataBlock.NextBlockFl:=True;
    FileBankDataBlock.BlockSize:= SizeOf(TBinBlockFile);
  end
  else
  begin
    FileBankDataBlock.NextBlockFl:=False;
    FileBankDataBlock.BlockSize:= SizeOf(tFixData)-m_liFileOffs;
  end;

  { nastaveni datoveho bufferu dle stavu komunikace a vybraneho banku
    souboru m_bFile }
  case tFileEnum(m_bFile) of
  file_FixData:  Move(PByteArray(Addr(FixData))^[m_liFileOffs], FileBankDataBlock.Block,
                             FileBankDataBlock.BlockSize);

  file_FixData1: Move(PByteArray(Addr(FixData1))^[m_liFileOffs], FileBankDataBlock.Block,
                             FileBankDataBlock.BlockSize);
  end;
  Inc(m_liFileOffs, FileBankDataBlock.BlockSize);
end;


function TFile1.fnPutBankDataOpen(var FileBankDataOpen :TPutFileBankDataOpen):Byte;
begin
  { Funkce se vola pred zapisem binarnich dat do pozadovaneho banku
    souboru. Ve vetsine pripadu zde postaci provest kontrolu, jestli
    zapisovana data lze do vybrane banky zapsat
    Pozn. predek provede konverzi indexu banky podle predaneho oznaceni
          banku a nastavi promennou m_bFile }
  fnPutBankDataOpen:=erc_file_Ok;
  if FileBankDataOpen.FileSize > sizeof(tFixData) then fnPutBankDataOpen:=erc_file_InsufficientMemory;

  { zde by mel byt kod, ktery aplikaci zabrani v pristupu
    k vybrane bance souboru.
    Pokud by zde kod nebyl mohlo by dojit k rozsynchronizovani
    jednotlivych dat.
    Pro zjednoduseni prikladu je pouzit flag zabranujici praci se vsemi
    banky. }
  fFileBankIsUsed:=True;
end;

function  TFile1.fnPutBankDataBlock(var FileBankDataBlock:TDataBlockFile):Byte;
begin
  fnPutBankDataBlock:=erc_file_Ok;
  with FileBankDataBlock do
  begin
    { nastaveni hodnot vybraneho banku souboru m_bFile podle stavu komunikace
      z datoveho bufferu ve strukture FileBankDataBlock }
    case tFileEnum(m_bFile) of
    file_FixData:  Move(Block, PByteArray(Addr(FixData))^[m_liFileOffs], BlockSize);
    file_FixData1: Move(Block, PByteArray(Addr(FixData1))^[m_liFileOffs], BlockSize);
    end;

   {$ifdef Deb}
    if DataFileOffs<>m_liFileOffs then RunError(255);
   {$endif}

    Inc(m_liFileOffs, BlockSize);
    if not NextBlockFl then
    begin
      pFileDescArray[tFileEnum(m_bFile)]^.FileSize:=m_liFileOffs;
    end;
  end;
end;

end.