unit tp_TestCable;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, Spin, ExtCtrls, IdIOHandlerStack,IdTCPClient,
  rtm_types;

type
  TReceiveData = procedure ( ATelegram : ttelegram ) of object;
  TTimerTick = procedure (Sender: TObject) of object;

  TDirection = (dRec, dSend);

type TSVGCableTest = class (Tobject)
  wifibuffer    : ttelegram; // pracovni buffer prichozich bytu
  fHost         : string;
  fPort         : integer;
  fOpenData     : ttelegram; // 13 bytu
  fByte41Data   : ttelegram;
  fInittelegram : ttelegram; // init telegram do jednotky
  fTimeBeforeInitTel : integer;
  fCableAnswer  : ttelegram;
  fCableNum     : word;
  fResetByte    : byte;
  fSafeFWNum    : word;
  fPublicFWNum  : word;
  fbegintime    : tdatetime;

  fReceiveData  : TReceiveData ;
  fResetReceiveData   : TReceiveData ;
  fBytes41ReceiveData : TReceiveData ;
  fAnswerReceiveData  : TReceiveData ;

  fTimer      : ttimer;
  fReceiveTimer : ttimer;
  fTestRuns   : boolean;
  fTestResult : boolean;
  fLogQueue   : ttelegrams;
  fTelsToSend : ttelegrams;
  fTelsToSendIndex : integer;

  IdTCPClient1: TIdTCPClient;
  IdIOHandlerStack1: TIdIOHandlerStack;

  fDoNotTestBytesInAsnwer : boolean;
  constructor Create (AOwner : tobject);
  destructor Destroy; override;
  function DoTest ( AHost: string; APortNum : integer ) : boolean;
  procedure DoResetReceiveData ( ATelegram : ttelegram );
  procedure DoReceive41Bytes ( ATelegram : ttelegram );
  procedure DoReceiveAnswer ( ATelegram : ttelegram );
  procedure WifiConnect;
  procedure WifiDisconnect;

  procedure ResettimerTick (sender : tobject);
  procedure Receive41ByteTimerTick (sender : tobject);
  procedure ReceiveAnswerTimerTick (sender : tobject);

  procedure AddToLog (ADirection : TDirection; ATelegram : ttelegram);
  procedure SaveLogAndClear ( AHeader : string; AUspech, AKO : integer);

  property TestRuns : boolean read fTestRuns write fTestRuns ;
  property TestResult : boolean read fTestResult write fTestResult ;
  property OpenData     : ttelegram read fopendata write fopendata;
  property Inittelegram : ttelegram read fInittelegram write fInittelegram ; // init telegram do jednotky
  property TimeBeforeInitTel : integer read fTimeBeforeInitTel write fTimeBeforeInitTel;
  property begintime    : tdatetime read fbegintime write fbegintime;
  property CableNum     : word read fCableNum write fCableNum;
  property SafeFWNum    : word read fSafeFWNum write fSafeFWNum;
  property PublicFWNum  : word read fPublicFWNum write fPublicFWNum;
  property TelsToSend   : ttelegrams read  fTelsToSend write fTelsToSend ;
  property DoNotTestBytesInAsnwer  : boolean read fDoNotTestBytesInAsnwer write fDoNotTestBytesInAsnwer ;
  function SendTelegram (ATel : ttelegram):boolean;
  private
    procedure ReceiveDataTimerTick(sender: tobject);
end;

implementation

uses
  tp_createcodecab, main;

{$LONGSTRINGS OFF}
function TSVGCableTest.SendTelegram (ATel : ttelegram):boolean;
var i : integer;
begin
  wifibuffer.Empty; // vyprazdnime si doposud prijate byty
  // novy telegram posilame, cekame odpoved od zacatku
  AddToLog(dSend, atel);
  begin
    for i := 0 to atel.Size -1 do
    begin
        IdIOHandlerStack1.Write(ATel.value[i]);
    end;
    sleep(300); // delsi prodleva uz neni potreba
  end
end;

procedure TSVGCableTest.WifiConnect;
begin
  // vytvori komponenty TCP a timer pro prijem bytu
  IdTCPClient1 := TIdTCPClient.create;
  IdIOHandlerStack1 := TIdIOHandlerStack.create;

  IdIOHandlerStack1.Destination:=  fHost + ':' + inttostr(fPort);//  '168.2.199:2000';
  IdIOHandlerStack1.Host :=  fhost; // '192.168.2.199';
  IdIOHandlerStack1.port := fPort;

  IdTCPClient1.Port := fPort; // aportnum;
  IdTCPClient1.Host := fhost; // '192.168.2.199';
  IdTCPClient1.IOHandler := IdIOHandlerStack1;

  fReceiveTimer := ttimer.Create(nil);
  fReceiveTimer.Interval := 100;
  fReceiveTimer.Enabled := true;
  freceivetimer.OnTimer := ReceiveDataTimerTick;

  fReceiveData := DoResetReceiveData;

  IdTCPClient1.Connect;
end;

procedure TSVGCableTest.WifiDisconnect;
begin
  // prichozi buffer
  wifibuffer.empty;

  // timer pro prijem bytu od wifi
  freceivetimer.Enabled := false;
  fReceivetimer.Free;

  // uvolnime komponenty
   IdTCPClient1.Disconnect;
   IdTCPClient1.free;

   IdIOHandlerStack1.DiscardAll;
   IdIOHandlerStack1.Free;
end;

procedure TSVGCableTest.DoReceive41Bytes( ATelegram : ttelegram );
var a: ttelegram;
    s: ttelegram;
begin
 fByte41Data :=  fByte41Data + atelegram;

 if fByte41Data.size = 41 then
 begin
    AddToLog(dRec, fByte41Data);
    fTimer.enabled := false;
    fReceiveData := DoReceiveAnswer;
    fCableNum    := fByte41Data.GetWordFromPos(1);
    fSafeFWNum   := fByte41Data.GetWordFromPos(29);
    fPublicFWNum := fByte41Data.GetWordFromPos(31);

    s := CodeCab ( fByte41Data.copy(16,13) );

    fCableAnswer.empty;
    sendtelegram( s ); //
    fTimer.OnTimer := ReceiveAnswerTimerTick;
    if fInittelegram.size > 0 then
    begin
      sleep(fTimeBeforeInitTel);
      sendtelegram(fInittelegram); // fsvport.SendData( @fInittelegram.value[0], finittelegram.size );
    end;
    fTimer.enabled := true;
 end;
end;

procedure TSVGCableTest.DoReceiveAnswer ( ATelegram : ttelegram );
var a:ttelegram;
    bo:boolean;
begin
  fCableAnswer := fCableAnswer + atelegram;
  AddToLog(dRec, atelegram);
  if fTelsToSendIndex >= fTelsToSend.count then exit;
  if fcableanswer.size =  fTelsToSend.Value[fTelsToSendIndex]^.size then
  begin
    bo := fCableAnswer = ( fTelsToSend.Value[fTelsToSendIndex]^ );
    if bo or fDoNotTestBytesInAsnwer then // prisla správná odpověď nebo netestuj byty v odpovedi
    begin
      fTimer.enabled := false; // resetuje timer
      fTelsToSendIndex := ftelsToSendIndex + 1;
      fCableAnswer.empty;
      if fTelsToSendIndex < fTelsToSend.count then // ma se jeste neco poslat?
      begin
        SendTelegram (ftelstoSend.value[fTelsToSendIndex]^); // fSVPort.senddata( @(ftelstoSend.value[fTelsToSendIndex]^.value[0]), ftelstoSend.value[fTelsToSendIndex].size );
        fTelsToSendIndex := fTelsToSendIndex + 1;
      end;

      if fTelsToSendIndex >= fTelsToSend.count then
      begin
        fReceiveData := nil; // neprijimej zadne byty
        sleep(300); // cas na odeslani telegramu
        wifiDisconnect;
        fTestResult := true;
        ftestresult := bo;
        fTestRuns   := false;
        exit;
      end;

      fTimer.enabled := true; // resetuje timer
    end;
  end;
//  if fCableAnswer.pos([255,13])>-1
//    then ReceiveAnswerTimerTick(nil); // ukonci krok testu ...
end;

{ TSVGCableTest }

destructor TSVGCableTest.Destroy;
begin
  inherited;
//  fWifiPort.free;  // wifi se rusi pri disconnectu, tady ne ...
  fTimer.Free;
end;

procedure TSVGCableTest.AddToLog(ADirection: TDirection; ATelegram: ttelegram);
begin
  if ADirection = drec
    then Form1.Memo2.lines.add( 'R: '+atelegram.asdecstring )
    else Form1.Memo2.lines.add( 'S: '+atelegram.asdecstring );
  if ADirection = dRec then
    ATelegram := 0 + ATelegram
    else ATelegram := 1 + ATelegram;
  fLogQueue.Append( ATelegram );
end;

constructor TSVGCableTest.Create(AOwner: tobject);
begin
  fInittelegram.empty;

  fTimer  := ttimer.create(nil);
  fTimer.interval := 3500;
  fTelsToSendIndex := 0;

  fDoNotTestBytesInAsnwer := true;

  fResetReceiveData := Doresetreceivedata;
  fBytes41ReceiveData := DoReceive41Bytes;
  fAnswerReceiveData  := DoReceiveAnswer;
end;

procedure TSVGCableTest.DoResetReceiveData ( Atelegram : ttelegram);
begin
  if ATelegram.Pos('*HELLO*')=0 then // ohlasilo se wifi
    ATelegram.Delete(0,7);
  if ATelegram.Size=0 then exit;

  AddToLog(dRec, ATelegram);

  if ATelegram.Size=1 then // zbyl jeden byte, tak je to resetbyte
  begin
    fReceiveData := DoReceive41Bytes;
    fResetByte   := ATelegram.value[0];

    fByte41Data.empty;
    fTimer.OnTimer := Receive41ByteTimerTick;
    fTimer.enabled := true;
    SendTelegram(fopendata);
  end;
end;

function TSVGCableTest.DoTest(AHost: string; APortNum: integer): boolean;
begin
  // nastavi parametry
  fHost := AHost;
  fPort := APortNum;
  Wificonnect; // vytvori wifi komponenty a vytvori spojeni ...

  // hlidaci timer
  fTimer.OnTimer := ResettimerTick;
  fTestResult := false;
  fTelsToSendIndex := 0;
  fTestRuns := true;
  fTimer.enabled := true;
end;

// zde se prijimaji byty od wifi, timer to hlida kazdou
procedure TSVGCableTest.ReceiveDataTimerTick(sender: tobject);
var I :integer;
begin
    if IdIOHandlerStack1.CheckForDataOnSource(400) then
    begin
      if not IdIOHandlerStack1.InputBufferIsEmpty then
      begin
        for I := 0 to IdIOHandlerStack1.InputBuffer.Size-1 do
        begin
          wifibuffer := wifibuffer + IdIOHandlerStack1.InputBuffer.ExtractToByte(i);
        end;
        IdIOHandlerStack1.InputBuffer.Clear; // vyprazdnime odebrane byty
        if assigned(fResetReceiveData) then
          fReceiveData(wifibuffer);
      end;
    end;
end;

procedure TSVGCableTest.Receive41ByteTimerTick(sender: tobject);
begin
  fTimer.enabled := false;
  WifiDisconnect;
  fTestRuns := false;
  sleep(1000);
end;

procedure TSVGCableTest.ReceiveAnswerTimerTick(sender: tobject);
begin
  fTimer.enabled := false;
  WifiDisconnect;
  fTestResult := false;
  fTestRuns := false;
end;

procedure TSVGCableTest.ResettimerTick(sender: tobject);
begin
  fTimer.enabled := false;
  WifiDisconnect;

  fTestRuns := false;
end;

procedure TSVGCableTest.SaveLogAndClear ( AHeader : string; AUspech, AKO : integer);
var konstname : string;
    i : integer;
    f : textfile;
    t : ttelegram;
    b : byte;
    LFilename : string;
begin
  konstname := inttostr(fcablenum)+'-'+inttostr(AUspech)+'x'+inttostr(ako);
  if fileexists(konstname) then
  begin
    i :=  1;
    while fileexists(konstname+inttostr(i)+'.txt') do
    begin
      inc(i);
      if i> 1000000 then
        exit;
    end;
    LFilename := konstname+inttostr(i)+'.txt';
  end
  else LFilename := konstname+'.txt';

  assignfile(f,Lfilename);
  rewrite(f);
  writeln(f,'zacatek testu: '+datetimetostr(fbegintime));
  writeln(f,'konec testu: '+datetimetostr(now));
  writeln(f,'kabel cislo: '+inttostr(fCableNum));
  writeln(f,'reset byte : '+inttostr(fResetByte));
  writeln(f,'firmware   : '+inttostr(fSafeFWNum) +'/'+ inttostr(fPublicFWNum));
  writeln(f,'prodleva : '+inttostr(fTimeBeforeInitTel));
  writeln(f,'počet pokusů    : ' + inttostr(AUspech+AKO) );
  writeln(f,'kousnuté pokusy : ' + inttostr(AKO) );
  writeln(f,'úspěšné pokusy  : ' + inttostr(AUspech) );

  if AHeader <> '' then
    writeln(f, AHeader );
  for i := 0 to fLogQueue.Count - 1 do
  begin
    t.assign(fLogQueue.Value[i]^);
    b := t.value[0];
    t.delete(0,1);
    if b=0 then
      writeln(f, 'R ' + t.AsDECString)
      else writeln(f, 'S ' + t.AsDECString);
  end;
  fLogQueue.Clear;
  closefile (f);
end;

end.
