unit wdog;
{
   Component to do watch dog jobs for inverters

   Author:  Vesa Lappalainen
   Date:    27.05.1997
   Changes:
             + prioriteetti
   Problems:
}


interface

uses
  Windows,Classes,kconcomp,kparams,kinvts,graphics,kparam,WDogS;

type
  TWatchDog = class(TWatchDogS)
  private
    { Private declarations }
    Invts : TInvts;
    WDogNr : Integer;
    NextWDogNr : integer;
    ErrorHwnd : integer;
    ErrorMsg  : integer;
    ParamPrio : TkParam;
    ParamTime : TkParam;
    WaitResetEvent : THandle;
    ForceNextWatch : boolean;
    MyWname : string;
    procedure DoNextWatch;
  protected
{$ifdef TEST}
    vika : boolean; s:string;
    function Hex(i:integer):string;
{$endif}
    procedure Execute; override;
  public
    constructor Create5(invs:TInvts;eh,em:integer;p,pri:TkParam);
    destructor Destroy; override;
    procedure StartFrom(inv:TObject); override;
    procedure Reset;                  override;
    procedure Continue;               override;
    procedure Pause;                  override;
  end;

implementation

uses KYasPar,SysUtils,Dialogs,kErrors;

//                                01234567890
var Wname:Array[0..20] of char = 'ResetEvent0' + #0;
var WCount : integer;

var
  ceWatchDogDebug : TCommError;

constructor TWatchDog.Create5(invs:TInvts;eh,em:integer;p,pri:TkParam);
begin
  Invts := invs;
  WDogNr := 0;
  NextWDogNr := -1;
  ErrorHwnd := eh;
  ErrorMsg  := em;
  ParamTime := p;
  Wname[10] := char(WCount+ord('0'));
  WaitResetEvent := CreateEvent(Nil,FALSE,FALSE,Wname);
  MyWname := WName;
  inc(WCount);
  ParamPrio := pri;
  Assert(ParamPrio <> nil,'ParamPrio nil in WDog Create5!');
  if (ParamPrio = nil) then ShowMessage('ParamPrio nil in WDog Create5!');
  inherited Create(false);
//  Priority := tpLowest;
  ceWatchDogDebug.Add('Create '+MyWName);

end;

procedure TWatchDog.Reset;
begin
//  Resume;
  SetEvent(WaitResetEvent);
  ceWatchDogDebug.Add('Reset '+MyWName);
end;

procedure TWatchDog.Continue;
var i:integer;
begin
  for i:= 0 to 5 do Resume;
  ForceNextWatch := true;
  SetEvent(WaitResetEvent);
  ceWatchDogDebug.Add('Continue '+MyWName);
end;

procedure TWatchDog.Pause;
begin
//  SetEvent(WaitResetEvent);
  Suspend;
  ceWatchDogDebug.Add('Pause '+MyWName);
end;

destructor TWatchDog.Destroy;
begin
  Continue;
  inherited;
end;

{ Important: Methods and properties of objects in VCL can only be used in a
  method called using Synchronize, for example,

      Synchronize(UpdateCaption);

  and UpdateCaption could look like,

    procedure TWatchDog.UpdateCaption;
    begin
      Form1.Caption := 'Updated in a thread';
    end; }

{ TWatchDog }

procedure TWatchDog.StartFrom(inv:TObject);
var i : integer;
begin
  for i:=0 to Invts.Cnt-1 do
    if ( inv = Invts.invts[i].inv ) then begin
      NextWDogNr := i;
      exit;
    end;
end;

{$ifdef TEST}
function TWatchDog.Hex(i:integer):string;
begin
  Result := IntToHex(i,8);
end;
{$endif}

procedure TWatchDog.DoNextWatch;
var err : boolean; inv : TcInverter;  i : integer;
begin
{$ifdef TEST}
  asm mov i,ebx; end;
  s := Hex(i);
  asm mov eax,[ebx+$9c-4]; mov i,eax; end;
  s := s + ' ' +Hex(i);
  asm mov eax,[ebx+$9c]; mov i,eax; end;
  s := s + ' ' +Hex(i);
  asm mov eax,[ebx+$9c+4]; mov i,eax; end;
  s := s + ' ' +Hex(i);
  s := s + ' ' + IntToStr(Invts.invts[0].inv.Params.Slave);
  s := s + ' ' + IntToStr(WDogNr);
//  Assert(ParamPrio <> nil,'ParamPrio nil in WDog1n!'+Format('%x',[i]));
//  Assert(ParamPrio <> nil,'ParamPrio nil in WDog1n! '+s);
  if ( ParamPrio = nil ) then begin
    ShowMessage(s);
    vika := true;
    Exit;
  end;
{$endif}
  if ( NextWDogNr >= 0 ) then begin
    WDogNr := NextWDogNr;
    NextWDogNr := -1;
  end;
  if ( ceWatchDogDebug.need ) then
    ceWatchDogDebug.Add('DoNextWatch '+MyWName + Format(' %d %d ',[Invts.Cnt,WDogNr]));
  Assert(ParamPrio <> nil,'ParamPrio nil in WDog2!');
  if ( WDogNr < Invts.Cnt ) then begin
    inv := Invts.invts[WDogNr].inv;
    if ( not inv.InError ) then begin
      err := not inv.Params.InvOK;
      if ( inv.InError <> err ) and ( inv.Params.ModbusSlave.OK ) then begin
        PostMessage(ErrorHwnd,ErrorMsg,inv.Tag,integer(err));
      end;
    end;
  end;

  Assert(ParamPrio <> nil,'ParamPrio nil in WDog!');
  Priority := TThreadPriority(ParamPrio.AsInteger);
  i := 0; // To prevent endless loop if NO inverters
  repeat
    inc(i);
    inc(WDogNr); if ( WDogNr >= Invts.Cnt ) then WDogNr := 0;
    inv := Invts.invts[WDogNr].inv;
  until ( (not inv.InError ) and ( inv.Params.ModbusSlave.OK ) ) or ( i > Invts.Cnt );
end;


procedure TWatchDog.Execute;
var ret : integer;
begin
  { Place thread code here }
  DoNextWatch;
  while not terminated do begin
    Assert(ParamPrio <> nil,'ParamPrio nil in WDog Execute!');
    ret := WaitForSingleObject(WaitResetEvent,trunc(ParamTime.Value*1000));
    if ( ret = WAIT_TIMEOUT ) or ForceNextWatch  then begin
      Assert(ParamPrio <> nil,'ParamPrio nil in WDog Execute2!');
      DoNextWatch;
{$ifdef TEST}
      if vika then begin end;
      ShowMessage(s);
//      vika := false; end;
{$endif}
    end;
    ForceNextWatch := false;
  end;
  CloseHandle(WaitResetEvent);
end;

initialization begin
  RegisterError(ceWatchDogDebug ,'wd', 'WatchDog debug'           ,false);
end;

end.
