(*
*******************************************************************************
*         Copyright (C) SofCon 2002 All Rights Reserved                       *
*******************************************************************************
*
*    project:     vizualizace
*
*    title:       AppDesc.pas
*
*******************************************************************************
*
*    description: definice typu, konstant a promennych pouzivanych v aplikaci
*                 Pri inicializaci se pouzivaji konstanty (xDesc) popisujici
*                 sdileny pametovy prostor mezi aplikaci a LOADER.
*
*    version:     1.00
*    language:    Borland Pascal
*
*    author:      Jan Hvozdovic
*    history:     date      sign   remark
*                 9.02      hv     start of development
*****************************************************************************
*)
unit AppDesc;
{$i sets.inc}

interface
uses
   xDesc               { jednotka definujici konstanty a typy pouzivane
                         jak v aplikaci tak v LOADER
                         (castecne definuje rozlozeni pameti) }
  ,ATypes              { definice typu pro praci s archivy }
  ,uCrc16;             { prace s CRC }

const
  { verze struktury xDesc.tAppRstDesc (ErrDescArray), ktera je pouzivana soucasnou
    aplikaci; verze se muze v budoucnu pri zmene aplikace zmenit vcetne upravy
    pouzivani teto struktury v ramci zminenych omezeni viz. zapis do struktury 
    ErrDescArray
    LOADER tuto konstantu nepouziva !!!}
  cErrDescArrayVer    = $0100;              { VYZADOVANO }
  cAppVer             = $0100;              { VYZADOVANO }



{ konstanty a typy popisujici archivy pouzivane v prikladu vizualizace }
const
  cMaxArchive2Str = 20;

  cArchive1MaxItem = 50;
  cArchive2MaxItem = 30;
  cGraf1MaxItem = 80;

type
  pArchive1Item = ^tArchive1Item;
  tArchive1Item = record
    dwPackDate : LongInt;
    wCode      : Word;
    bActive    : Byte;
  end;

  pArchive2Item = ^tArchive2Item;
  tArchive2Item = record
    dwPackDate : LongInt;
    str        : String[cMaxArchive2Str];
    bActive    : Byte;
  end;

  pGraf1Item = ^tGraf1Item;
  tGraf1Item = record
    dwPackDate  : LongInt;
    wTemp       : Word;
    wCurrent    : Word;
    wOutputs    : Word;
  end;


const
  {-------------------------------------------------------------------------}
  {-------------------------------------------------------------------------}
  { hodnoty se vyplni pri alokaci pameti }
  { adresa struktury AppRstDesc - restart struktura, pocitadla Pfi atd. }
  laAppRstDesc   :LongInt    = 0;            { VYZADOVANO }
  { adresa struktury LdrDesc - pouziva LOADER pri spousteni aplikace,
           dale je mozne pomoci bParForApp, bParForLdr predavat ruzne flag }
  laLdrDesc      :LongInt    = 0;            { VYZADOVANO }


  { definice adres dalsich struktur }
  laArchive1           : LongInt = 0;
  laArchive2           : LongInt = 0;
  laGraf1              : LongInt = 0;
  laArchive1AStruct    : LongInt = 0;
  laArchive2AStruct    : LongInt = 0;
  laGraf1AStruct       : LongInt = 0;

  {-------------------------------------------------------------------------}
  {-------------------------------------------------------------------------}
  { ukazatel na prostor tAppRstDesc }
  gpAppRstDesc : pAppRstDesc  = nil;         { VYZADOVANO }

  { ukazatel na prostor tLdrDesc }
  gpLdrDesc : pLdrDesc = nil;                { VYZADOVANO }


  { ukazatele na dalsi struktury }
  gpArchive1           : Pointer = nil;
  gpArchive2           : Pointer = nil;
  gpGraf1              : Pointer = nil;
  gpArchive1AStruct    : Pointer = nil;
  gpArchive2AStruct    : Pointer = nil;
  gpGraf1AStruct       : Pointer = nil;

  {-------------------------------------------------------------------------}
  {-------------------------------------------------------------------------}

  _laArchive1         = _laLdrDesc - cArchive1MaxItem*sizeof(tArchive1Item);
  _laArchive2         = _laArchive1 - cArchive2MaxItem*sizeof(tArchive2Item);
  _laGraf1            = _laArchive2 - cGraf1MaxItem*sizeof(tGraf1Item);
  _laArchive1AStruct  = _laGraf1 - sizeof(tArchiveStruct);
  _laArchive2AStruct  = _laArchive1AStruct - sizeof(tArchiveStruct);
  _laGraf1AStruct     = _laArchive2AStruct - sizeof(tArchiveStruct);

  {-------------------------------------------------------------------------}
  {-------------------------------------------------------------------------}
  { identifikacni retezec ve vizualizacnim programu - Query LOADER }
  strAppName: String[30] = 'Invalid';        { VYZADOVANO }
  { cislo verze Loaderu }
  strAppVer : Word = 0;                      { VYZADOVANO }



{ Funkce provede inicializaci promennych popisujici rozlozeni
  pameti. Pri inicializaci se pouzivaji konstanty ze souboru xDesc.
  Po nastaveni rozlozeni pameti se provede kontrola verzi RstDescArray,
  viz. pozn. o kodovani a pouzivani RstDescArray. Dale se provede validace
  struktury LdrDesc, pri jejim poskozeni se provede inicializace.
  Vraci:
    True  - vse OK
    False - poskozena struktur LdrDesc. Doslo k jeji inicializaci. }
function fnAppInit:Boolean;

implementation
uses
  Kernel,              { jadro os ReTOS }
  numToStr,            { prace s retezci }
  Xtking_1;            { definice typu a konstant pro praci s vizualizaci }

var
  SaveExit:Pointer;


procedure MyExitProc;far; forward;




{ funkce se vola po spusteni LOADER a umoznuje signalizovat stav
  na sbernici, napr. PBUS }
procedure ShowLoaderStartUp;
{$ifdef Deb}
const
 {$ifdef VerMC}
  PBusAddr  = $D210; { bazova adresa PBusu na Kit386 }
  IOBusAddr = $2300; { bazova adresa IOBusu na Kit386 }
 {$else}
  PBusAddr  = $0220; { bazova adresa PBusu na PC-Kit }
  IOBusAddr = $0300; { bazova adresa IOBusu na PC-Kit }
 {$endif}

begin
 {$ifNdef SimPC}
  { signalizace spusteni LOADER - LED "Run" }
  asm Pushf; Cli end;
  port[PBusAddr+$0]:=$01; port[PBusAddr+$3]:=$00; { brana A }
  port[PBusAddr+$1]:=$00; port[PBusAddr+$5]:=$00; { brana B }
  port[PBusAddr+$2]:=$00; port[PBusAddr+$7]:=$00; { brana C }
  asm Popf end;
 {$endif}
end;

{$else}
begin
  { kod pro signalizaci behu LOADER }
end;
{$endif}

{ Funkce provede inicializaci promennych popisujici rozlozeni
  pameti. Pri inicializaci se pouzivaji konstanty ze souboru xDesc.
  Po nastaveni rozlozeni pameti se provede kontrola verzi RstDescArray,
  viz. pozn. o kodovani a pouzivani RstDescArray. Dale se provede validace
  struktury LdrDesc, pri jejim poskozeni se provede inicializace.
  Vraci:
    True  - vse OK
    False - poskozena struktur LdrDesc. Doslo k jeji inicializaci. }
function fnAppInit:Boolean;
begin
  fnAppInit:=True;

 { nastaveni posledni obsluhy ExitProc, aby se MyExitProc volala jako prvni }
  SaveExit:=ExitProc;
  ExitProc:=@MyExitProc;

 {$ifNdef VerMC}
  { alokace prostoru pro struktury aplikace a LOADER }
  GetMem(gpAppRstDesc, sizeof(tAppRstDesc));
    FillChar(gpAppRstDesc^, sizeof(tAppRstDesc), 0);
    laAppRstDesc:=(LongInt(Seg(gpAppRstDesc^)) shl 4) + Ofs(gpAppRstDesc^);

  GetMem(gpLdrDesc, sizeof(tLdrDesc));
    FillChar(gpLdrDesc^, sizeof(tLdrDesc), 0);
    laLdrDesc:=(LongInt(Seg(gpLdrDesc^)) shl 4) + Ofs(gpLdrDesc^);

 { alokace a nastaveni dalsich struktur pro verzi na PC }
   { alokace dalsich struktur aplikace }
  GetMem(gpArchive1, sizeof(tArchive1Item)*cArchive1MaxItem);
    FillChar(gpArchive1^, sizeof(tArchive1Item)*cArchive1MaxItem, 0);
    laArchive1:=(LongInt(Seg(gpArchive1^)) shl 4) + Ofs(gpArchive1^);

  GetMem(gpArchive2, sizeof(tArchive2Item)*cArchive2MaxItem);
    FillChar(gpArchive2^, sizeof(tArchive2Item)*cArchive2MaxItem, 0);
    laArchive2:=(LongInt(Seg(gpArchive2^)) shl 4) + Ofs(gpArchive2^);

  GetMem(gpGraf1, sizeof(tGraf1Item)*cGraf1MaxItem);
    FillChar(gpGraf1^, sizeof(tGraf1Item)*cGraf1MaxItem, 0);
    laGraf1:=(LongInt(Seg(gpGraf1^)) shl 4) + Ofs(gpGraf1^);

  GetMem(gpArchive1AStruct, sizeof(tArchiveStruct));
    FillChar(gpArchive1AStruct^, sizeof(tArchiveStruct), 0);
    laArchive1AStruct:=(LongInt(Seg(gpArchive1AStruct)) shl 4) + Ofs(gpArchive1AStruct);

  GetMem(gpArchive2AStruct, sizeof(tArchiveStruct));
    FillChar(gpArchive2AStruct^, sizeof(tArchiveStruct), 0);
    laArchive2AStruct:=(LongInt(Seg(gpArchive2AStruct)) shl 4) + Ofs(gpArchive2AStruct);

  GetMem(gpGraf1AStruct, sizeof(tArchiveStruct));
    FillChar(gpGraf1AStruct^, sizeof(tArchiveStruct), 0);
    laGraf1AStruct:=(LongInt(Seg(gpGraf1AStruct)) shl 4) + Ofs(gpGraf1AStruct);

   { nahrani dalsich struktur aplikace }
   if LoadAppRstDesc(gpAppRstDesc)<>0 then InitAppRstDesc(gpAppRstDesc);
   if LoadLdrDesc(gpLdrDesc)<>0 then InitLdrDesc(gpLdrDesc);

 {$else}
   { nastaveni linearnich adres dle rozlozeni pameti }
   laAppRstDesc:=_laAppRstDesc;
   laLdrDesc:=_laLdrDesc;

   {--}
   { nastaveni ukazovatelu na struktury aplikace a LOADER }
   gpAppRstDesc:=Ptr(laAppRstDesc shr 4, laAppRstDesc and $F);
   gpLdrDesc:=Ptr(laLdrDesc shr 4, laLdrDesc and $F);
   {--}

   { alokace a nastaveni dalsich struktur pro verzi na MC }
   laArchive1:=_laArchive1;
   laArchive2:=_laArchive2;
   laGraf1:=_laGraf1;
   laArchive1AStruct:=_laArchive1AStruct;
   laArchive2AStruct:=_laArchive2AStruct;
   laGraf1AStruct:=_laGraf1AStruct;

   gpArchive1:=Ptr(laArchive1 shr 4, laArchive1 and $F);
   gpArchive2:=Ptr(laArchive2 shr 4, laArchive2 and $F);
   gpGraf1:=Ptr(laGraf1 shr 4, laGraf1 and $F);
   gpArchive1AStruct:=Ptr(laArchive1AStruct shr 4, laArchive1AStruct and $F);
   gpArchive2AStruct:=Ptr(laArchive2AStruct shr 4, laArchive2AStruct and $F);
   gpGraf1AStruct:=Ptr(laGraf1AStruct shr 4, laGraf1AStruct and $F);
 {$endif}

   {otestovani verze restart struktury}
   fUseErrDescArray := Hi(gpAppRstDesc^.wVer) = Hi(cLdrErrDescArrayVer);

   { kontrola prekryvu jednotlivych pametovych oblasti }
   if ((_laAppRstDesc + sizeof(tAppRstDesc)) <= laMaxFixedMemory) and
      ((_laLdrDesc + sizeof(tLdrDesc)) <= _laAppRstDesc) and

      { kontroly struktur definovanych v aplikaci }
      ((_laArchive1 + (sizeof(tArchive1Item)*cArchive1MaxItem)) <= _laLdrDesc) and
      ((_laArchive2 + (sizeof(tArchive2Item)*cArchive2MaxItem)) <= _laArchive1) and
      ((_laGraf1 + (sizeof(tGraf1Item)*cGraf1MaxItem)) <= _laArchive2) and
      ((_laArchive1AStruct + sizeof(tArchiveStruct)) <= _laGraf1) and
      ((_laArchive2AStruct + sizeof(tArchiveStruct)) <= _laArchive1AStruct) and

      (laMinFixedMemory <= _laArchive2AStruct) and
      { kontrola nastaveni RTD - !!! lze pouze pro VerMC !!!
        v pripade teto chyby se musi zkontrolovat nebo smazat
        laRamModule, cRamModuleSize a nastaveni RTD u RAM modulu }
      ((_laGraf1AStruct + sizeof(tArchiveStruct)) <= _laArchive2AStruct) and
{$ifNdef VerMC}
      (TRUE) then
{$else}
      (((LongInt(Seg(HeapEnd^)) shl 4) + (Ofs(HeapEnd^) and $F)) <= laMinFixedMemory) then
{$endif}
   begin
     { vse OK }
     { kontrola platnosti struktury LdrDesc - CRC }
     if gpLdrDesc^.wCrc<>theCrc.CalculateCrc(gpLdrDesc,
             cLdrDescCrcSize, cResidue) then
     begin
       InitLdrDesc(gpLdrDesc);
       fnAppInit:=False;
     end;
   end
   else
   begin
     { chybne rozlozeni pameti }
     fnSetLastError(err_Alloc);
     fnAppInit:=False;
   end;
end;


{****************************************************************************}
{$S-}
procedure MyExitProc;
begin
  ExitProc:=SaveExit;

  if ((ExitCode<>0) or (ErrorAddr<>nil)) and (gpAppRstDesc<>nil) then
  begin
    with gpAppRstDesc^ do
    begin
      { zvyseni poctu zachycenych RunError }
      if wRunErrCnt<High(wRunErrCnt) then Inc(wRunErrCnt);

      wVer:=cErrDescArrayVer;    { verze ErrDescArray }
      wAppVer:=cAppVer;          { verze App }
      { zalozeni nove chyby }
      Inc(bIxWrittenAt); if bIxWrittenAt>MaxRst then bIxWrittenAt:=0;
      with ErrDescArray[bIxWrittenAt] do
      begin
        rErr := ExitCode;
        rAddr:= ErrorAddr;
        rPckTime:=GetPackTime;
        if TestKernel then rStr:=RunningProcess;
      end;
    end;
  end;

{$ifNdef VerMC}
  SaveAppRstDesc(gpAppRstDesc);
  SaveLdrDesc(gpLdrDesc);
{$endif}
end;
{$S+}

{****************************************************************************}
{ funkce pro nastaveni posledni chyby }
procedure uSetLastError(ldrerr:Word); far;
begin
  if ldrerr<>err_Ok then
  begin
    RunError(ldrerr);
  end;
end;

{****************************************************************************}

begin
  { nastaveni vlastni obsluhy nastavovani posledni chyby }
  fnSetLastError:=uSetLastError;

  { inicializace posledni chyby }
  fnSetLastError(err_Ok);
end.
