{Copyright or © or Copr. :

CNRS - Laboratoire Mouvement & Perception
franck.buloup@univmed.fr

This software is a computer program whose purpose is to highly simplify  
the use of ADwinPro realtime systems when you develop experimental
protocols  on life's sciences area.

This software is governed by the CeCILL  license under French law and
abiding by the rules of distribution of free software.  You can  use, 
modify and/ or redistribute the software under the terms of the CeCILL
license as circulated by CEA, CNRS and INRIA at the following URL
"http://www.cecill.info". 

As a counterpart to the access to the source code and  rights to copy,
modify and redistribute granted by the license, users are provided only
with a limited warranty  and the software's author,  the holder of the
economic rights,  and the successive licensors  have only  limited
liability. 

In this respect, the user's attention is drawn to the risks associated
with loading,  using,  modifying and/or developing or reproducing the
software by the user in light of its specific status of free software,
that may mean  that it is complicated to manipulate,  and  that  also
therefore means  that it is reserved for developers  and  experienced
professionals having in-depth computer knowledge. Users are therefore
encouraged to load and test the software's suitability as regards their
requirements in conditions enabling the security of their systems and/or 
data to be ensured and,  more generally, to use and operate it in the 
same conditions as regards security. 

The fact that you are presently reading this means that you have had
knowledge of the CeCILL license and that you accept its terms.}
unit USimulThread;

interface

uses Classes, Windows, SysUtils, XMLClasses, Dialogs, Forms, Controls;

const RLS_STOPPED = -1;
      RLS_READY = 0;
      RLS_INIT = 0;
      RLS_EVENT = 1;
      RLS_FINISH = 2;
      RLS_PAUSED = 3;
      NMAX = 1024;

type
  TTAB_DATA_PARAM  = array[1..NMAX] of DOUBLE;
  TSegProc   = PROCEDURE (VAR pIndex : integer;
                          VAR pTAB_DATA : TTAB_DATA_PARAM;
                          VAR pTAB_PARAM : TTAB_DATA_PARAM;
                          VAR pREALTIME_LOOP_STATE : integer);
  TSimulThread = class(TThread)
  private
    { Déclarations privées }
    INIT   : TSegProc;
    EVENT  : TSegProc;
    FINISH : TSegProc;
    InfoCanaux : TInfoCanaux;
  protected
    procedure Execute; override;
  public
    REALTIME_LOOP_STATE : integer;
    INDEX : integer;
    TEMPS : double;
    FEG : double;
    TAB_DATA  : TTAB_DATA_PARAM;
    TAB_PARAM : TTAB_DATA_PARAM;
    Library_Name : string;
    constructor Create(pFEG : double;pLibrary_Name : string);
    function Initialize:string;
    procedure DoSimul;
    procedure MAJValueList;
  end;

implementation

uses UDocometre, UGrapheSimulFrame, USimulFrame, GeneratorClass, UGrapheTabSimulForm;

{ Important : les méthodes et propriétés des objets de la VCL peuvent uniquement
  être utilisés dans une méthode appelée en utilisant Synchronize, comme :

      Synchronize(UpdateCaption);

  où UpdateCaption serait de la forme 

    procedure TSimulThread.UpdateCaption;
    begin
      Form1.Caption := 'Mis à jour dans un thread';
    end; }

{ TSimulThread }

constructor TSimulThread.Create(pFEG : double;pLibrary_Name : string);
begin
  inherited Create(true);
  //(tpIdle, tpLowest, tpLower, tpNormal, tpHigher, tpHighest, tpTimeCritical);
  Priority := tpHighest;
  FreeOnTerminate := true;
  OnTerminate := DocoForm.SimulFrame.OnTerminateSimulThread;
  REALTIME_LOOP_STATE := RLS_STOPPED;
  INDEX := 1;
  TEMPS := 0;
  FEG := pFEG;
  Library_Name := pLibrary_Name;
end;

function TSimulThread.Initialize:string;
begin
  DocoForm.SimulFrame.Library_Handle := LoadLibrary(PChar(Library_Name));
  if DocoForm.SimulFrame.Library_Handle <> 0 then
  begin
    @INIT   := GetProcAddress(DocoForm.SimulFrame.Library_Handle,'INIT');
    @EVENT  := GetProcAddress(DocoForm.SimulFrame.Library_Handle,'EVENT');
    @FINISH := GetProcAddress(DocoForm.SimulFrame.Library_Handle,'FINISH');
    if (@INIT <> nil) and (@EVENT <> nil) and (@FINISH <> nil) then
    begin
      if InfoCanaux <> nil then InfoCanaux.Free;
      InfoCanaux := DocDOCOMETRE.RendreListeInfoCanaux;
      REALTIME_LOOP_STATE := RLS_READY;
      INDEX := 1;
      TEMPS := 0;
      result := 'Simulateur prêt';
    end else result := 'Impossible de Charger : "INIT", "EVENT" ou "FINISH"';
  end else result := 'Impossible de Charger : ' + Library_Name;
  if result <> 'Simulateur prêt' then Terminate;
end;

procedure TSimulThread.DoSimul;
var i,j,rep : integer;
    AGrapheSimulFrame : TGrapheSimulFrame;
    AGrapheTabSimulForm : TGrapheTabSimulForm;
    valeur : double;
    Nom : string;
    DataIndex : integer;
    Generator : TGenerator;
begin
  DocoForm.SimulFrame.SimulStatusBar.Panels[1].Text := sTEMPS + floattostr(TEMPS);

  //pour toutes les entrees
  for i := 0 to DocoForm.SimulFrame.GraphCheckListBox.Count - 1 do
  begin
    Nom := DocoForm.SimulFrame.GraphCheckListBox.Items[i];
    if (InfoCanaux.inORoutORcanint[InfoCanaux.Nom.IndexOf(Nom)] = 'in') or
       ((InfoCanaux.inORoutORcanint[InfoCanaux.Nom.IndexOf(Nom)] = 'canint') and
        (InfoCanaux.purORparam[InfoCanaux.Nom.IndexOf(Nom)] = 'PARAM')) then
    begin
      if DocoForm.SimulFrame.GraphCheckListBox.Items.Objects[i] <> nil then
      begin
        Generator := DocoForm.SimulFrame.GraphCheckListBox.Items.Objects[i] as TGenerator;
        if Generator.Used then
        begin
          valeur := Generator.GetValue(INDEX);
        end else valeur :=
                 strtofloat(DocoForm.SimulFrame.CanauxValueListEditor.Values[Nom]);
      end else valeur :=
               strtofloat(DocoForm.SimulFrame.CanauxValueListEditor.Values[Nom]);

      if (InfoCanaux.inORoutORcanint[InfoCanaux.Nom.IndexOf(Nom)] = 'in')
      then TAB_DATA[strtoint(InfoCanaux.NumCanal[InfoCanaux.Nom.IndexOf(Nom)])] := valeur
      else TAB_PARAM[strtoint(InfoCanaux.NumCanal[InfoCanaux.Nom.IndexOf(Nom)])] := valeur;

      if DocoForm.SimulFrame.GraphCheckListBox.Checked[i] then
      begin
        for j := 0 to DocoForm.SimulFrame.GraphScrollBox.ControlCount - 1 do
        begin
          AGrapheSimulFrame := (DocoForm.SimulFrame.GraphScrollBox.Controls[j] as TGrapheSimulFrame);
          if AGrapheSimulFrame.NomCanalChartPanel.Caption = Nom
          then if AGrapheSimulFrame.NeedNewValue(INDEX)
               then AGrapheSimulFrame.AddNewValue(TEMPS,valeur);
        end;
      end;
    end;
  end;

  if REALTIME_LOOP_STATE = RLS_INIT then
  begin
    DocoForm.SimulFrame.SimulStatusBar.Panels[0].Text := sETAT + 'INIT';
    try
       INIT(INDEX,TAB_DATA,TAB_PARAM,REALTIME_LOOP_STATE);
    except
       on e : Exception do
       begin
          rep := messageDLG('Erreur dans le segment INIT : ' + e.Message, mtError,[mbAbort, mbRetry],e.HelpContext) ;
          if(rep=mrAbort) then REALTIME_LOOP_STATE := RLS_FINISH;
       end;
    end;

  end;

  if REALTIME_LOOP_STATE = RLS_EVENT then
  begin
    DocoForm.SimulFrame.SimulStatusBar.Panels[0].Text := sETAT + 'EVENT';
    try
       EVENT(INDEX,TAB_DATA,TAB_PARAM,REALTIME_LOOP_STATE);
    except
       on e : Exception do
       begin
          rep := messageDLG('Erreur dans le segment EVENT : ' + e.Message, mtError,[mbAbort, mbRetry],e.HelpContext) ;
          if(rep=mrAbort) then REALTIME_LOOP_STATE := RLS_FINISH;
       end;
    end;
  end;

  if REALTIME_LOOP_STATE = RLS_FINISH then
  begin
    DocoForm.SimulFrame.SimulStatusBar.Panels[0].Text := sETAT + 'FINISH';
    try
       FINISH(INDEX,TAB_DATA,TAB_PARAM,REALTIME_LOOP_STATE);
    except
       on e : Exception do
       begin
          messageDLG('Erreur dans le segment FINISH : ' + e.Message, mtInformation,[mbOK],e.HelpContext) ;
       end;
    end;

    //if not FreeLibrary(DocoForm.SimulFrame.Library_Handle)
    //then showmessage('PBME libération DLL ...');
    REALTIME_LOOP_STATE := RLS_STOPPED;
  end;

  //GESTION DES SORTIES
  for i := 0 to DocoForm.SimulFrame.GraphCheckListBox.Count - 1 do
  begin
    Nom := DocoForm.SimulFrame.GraphCheckListBox.Items[i];
    if (InfoCanaux.inORoutORcanint[InfoCanaux.Nom.IndexOf(Nom)] = 'out') or
       (InfoCanaux.inORoutORcanint[InfoCanaux.Nom.IndexOf(Nom)] = 'canint') then
    begin
      DataIndex := strtoint(InfoCanaux.NumCanal[InfoCanaux.Nom.IndexOf(Nom)]);
      //DocoForm.SimulFrame.CanauxValueListEditor.Values[Nom] :=
      //                                       floattostr(TAB_DATA[DataIndex]);
      if DocoForm.SimulFrame.GraphCheckListBox.Checked[i] then
      begin
        for j := 0 to DocoForm.SimulFrame.GraphScrollBox.ControlCount - 1 do
        begin
          AGrapheSimulFrame := (DocoForm.SimulFrame.GraphScrollBox.Controls[j] as TGrapheSimulFrame);
          if AGrapheSimulFrame.NomCanalChartPanel.Caption = Nom then
          begin
            if AGrapheSimulFrame.NeedNewValue(INDEX) then
            begin
              AGrapheSimulFrame.AddNewValue(TEMPS,TAB_DATA[DataIndex]);
            end;
            break;
          end;
        end;

        if DocoForm.SimulFrame.ListeGrapheTabSimulForm <> nil
        then for j := 0 to DocoForm.SimulFrame.ListeGrapheTabSimulForm.Count - 1 do
             begin
               AGrapheTabSimulForm := DocoForm.SimulFrame.ListeGrapheTabSimulForm[j];
               if AGrapheTabSimulForm.GetNom = Nom then
               begin
                  if AGrapheTabSimulForm.NeedNewValues(INDEX) then
                  begin
                     AGrapheTabSimulForm.AddTabValues(TAB_DATA);
                 end;
                 break;
               end;
             end;

      end;
    end;
  end;

  if REALTIME_LOOP_STATE = RLS_STOPPED then
  begin
    for i := 0 to DocoForm.SimulFrame.GraphScrollBox.ControlCount - 1 do
    begin
      AGrapheSimulFrame := (DocoForm.SimulFrame.GraphScrollBox.Controls[i] as TGrapheSimulFrame);
      AGrapheSimulFrame.FlushGraph;
    end;
    MAJValueList;
    Terminate;
  end;
end;

procedure TSimulThread.MAJValueList;
var i : integer;
    Nom : string;
    DataIndex : integer;
begin
  for i := 0 to DocoForm.SimulFrame.GraphCheckListBox.Count - 1 do
  begin
    Nom := DocoForm.SimulFrame.GraphCheckListBox.Items[i];
    if InfoCanaux.purORparam[InfoCanaux.Nom.IndexOf(Nom)] <> 'PARAM' then
    begin
      DataIndex := strtoint(InfoCanaux.NumCanal[InfoCanaux.Nom.IndexOf(Nom)]);
      DocoForm.SimulFrame.CanauxValueListEditor.Values[Nom] :=
                                             floattostr(TAB_DATA[DataIndex]);
    end;
  end;
end;

procedure TSimulThread.Execute;
begin
  { Placez le code du thread ici }
  while not Terminated do
  begin
    TEMPS := (INDEX-1)/FEG;
    Synchronize(DoSimul);
    Application.ProcessMessages;
    DocoForm.SimulFrame.SimulStatusBar.Repaint;
    if REALTIME_LOOP_STATE > RLS_INIT
    then inc(INDEX);
  end;
  if Terminated then
  begin
    MAJValueList;
    if InfoCanaux <> nil then InfoCanaux.Free;
  end;
end;

end.
