not working
unit Sequenceru;
interface
uses
  Messages, SysUtils, FileCtrl, Classes, TypInfo, Forms, Controls, Dialogs,
  Graphics,
  Fifou, Timer, Stru, Msgu, ShowMsg,
  PropUtl, UtlType, WinUtl, ExeLogu,
  UlanType, UlanGlob,
  ULRecTyp, ULRecUtl, ULObju, ULFObju, ULObjUsru,
  ModuType, Modulu, ModuUtl,

  Timersu,
  ULADType, ULADObju,

  ULDRType, ULDRObju,
  ULDPType, ULDPObju,

  ULIType, ULIObju, Instrumentu,
  ULMType, ULMObju, Methodu,
  {AAPLType, AAPLObju,
  AAPGType, AAPGObju, AAPrgu, // Sequencer program }

  ULSRType, ULSRObju, { Sequence record=sample }
  ULSQType, ULSQObju, Sequenceu, { Sequencer sequence }

  SequencerType, SequencerObju{, SequencerUtl - in ModuUtl}, AAFatalFrm,
  Spectrum, AcqInfou, SpecForm{v0.25}, DebugFrm{/v0.25}
  {v0.28}, Language{/v0.28};

const
  MaxHistCount = 4;
  AbortingInterval = -2*60*1000;{ms, = 2 min}
type
  TSequencerResult = integer;

{arXXXX}
const
  ar0 = 12000;
  arInvalidStateRequest = ar0 + 1;
  arNoSamples = ar0 + 2;
  arInvalidProgramNoEquil = ar0 + 3;
  arFilesMissing = ar0 + 4;
{/arXXXX}

type
  TULObjFldAutoCon = class(TULObjField);

type
  TSequencer = class(TULObjUsr) {Sequencertype}
  private
    FDefPrg: TAAPrg;{default prg for sequence/seqSamples}
    FDefMethod: TUlanMethod; { loaded from AO.MethodFileName }
    FDefInstrument: TInstrument;{ autocreated }
    FSequence: TSequence; { loaded from AO.SeqFileName }
    {FCurPrg: TAAPrg;
    FBrowsingCurPrg: TAAPrg; // non nil, if for FCurPrg was called ShowRunning }
      { pointer to currently running program (of FSequence.CurSample) }
    FAcqInfo: TAcqInfo;
    FAcqData: TAcqData;

    {FHistCount: integer;
    FHists:array[0..MaxHistCount-1] of TTechHistory;

    FP1PressHistory: TTechHistory;
    FP2PressHistory: TTechHistory;
    FColumnTempHistory: TTechHistory;
    FReactTempHistory: TTechHistory;
    }
    FIsInTimer: boolean;

    FIK_ON: TULObjFldAutoCon;
    FIK_OFF: TULObjFldAutoCon;
    FIK_STATUS: TULObjFldAutoCon;{uld.asc}
    FIK_WDG: TULObjFldAutoCon;

    FP1_STATUS: TULObjFldAutoCon;
    FP1_FLOW: TULObjFldAutoCon;
    FP1_PRESS: TULObjFldAutoCon;
    FP1_PRESS_L: TULObjFldAutoCon;
    FP1_PRESS_H: TULObjFldAutoCon;
    FP1_AUXVALV: TULObjFldAutoCon;{ 1 - 8 ... buffer valves 1 - 8,
      if = 0 ... unconnected wire }
    FP1_STOP: TULObjFldAutoCon;
    FP1_START: TULObjFldAutoCon;
    FP1_ERRCLR: TULObjFldAutoCon;{ Clear error status field in device }

    FP2_STATUS: TULObjFldAutoCon;
    FP2_FLOW: TULObjFldAutoCon;
    FP2_PRESS: TULObjFldAutoCon;
    FP2_PRESS_L: TULObjFldAutoCon;
    FP2_PRESS_H: TULObjFldAutoCon;
    FP2_GRADDIR: TULObjFldAutoCon; { Switch gradient valves, 0 .. H2O, 1 .. NHD }
    FP2_GRAD_B: TULObjFldAutoCon;  { <> 0 -> NHD, = 0 -> H2O }
    FP2_ERRCLR: TULObjFldAutoCon;
    FP2_STOP: TULObjFldAutoCon;
    FP2_START: TULObjFldAutoCon;

    FAS_OFF: TULObjFldAutoCon;
    FAS_TEMP_OFF: TULObjFldAutoCon;
    FAS_STATUS: TULObjFldAutoCon;
    FAS_TEMP1: TULObjFldAutoCon; { Column temperature (read/write) }
    FAS_TEMP1RQ: TULObjFldAutoCon;
    FAS_CALLPS: TULObjFldAutoCon; { Get autosampler ready (flushing, sensors calibration) }
    FAS_ERRCLR: TULObjFldAutoCon;
    FAS_SAMPNUM: TULObjFldAutoCon; { Number of the next sample to be prepared }
    FAS_PREPSAMP: TULObjFldAutoCon; { Prepare sample sample for inject (select position, load) }
    FAS_INJECT: TULObjFldAutoCon; { Turn inject valve - inject sample }
    FAS_TEMP_ST: TULObjFldAutoCon;

    FDET_TEMP1: TULObjFldAutoCon;
    FDET_TEMP_ST: TULObjFldAutoCon;
    FDET_ERRCLR: TULObjFldAutoCon;
    FDET_CHA: TULObjFldAutoCon; { Absorbance on channel A }
    FDET_CHB: TULObjFldAutoCon; { Absorbance on channel B }
    FDET_ZERO: TULObjFldAutoCon; { Set zero absorbance}
    FDET_ON: TULObjFldAutoCon;   { switch the lamp on }
    FDET_OFF: TULObjFldAutoCon; { switch the lamp off }
    FDET_TEMP_OFF: TULObjFldAutoCon; { switch react.termostat off }
    FDET_STATUS: TULObjFldAutoCon;

    FP1: TULDRObj;
    FP2: TULDRObj;
    FAS: TULDRObj;
    FIK: TULDRObj;
    FDET: TULDRObj;

    FSubState: integer;
    FStateStartTime: integer;
    FStateTime: integer;
    FUsrStateTimeOffset: integer;
    FLogActive:boolean;

    {states of devices, can be changed only by assigning to corresponing property }
    FIKState: TDevState;

    FP1State: TDevState;
    FP2State: TDevState;
    FDetState: TDevState;
    FColState: TDevState;
    FReactState: TDevState;

    FASState: TASState;{moduutl}
    {/states}

    {states of devices, current variables used for getting state from devices
      (passed as var parameters) in DoTimer-DoTechControl method. Assigned
      to corresponding properties at DoTimer end }
    FcIKState: TDevState;

    FcP1State: TDevState;
    FcP2State: TDevState;
    FcDetState: TDevState;
    FcColState: TDevState;
    FcReactState: TDevState;

    FcASState: TASState;{moduutl}
    {/states}
    FDevStatesOK: boolean;
    FcDevStatesOK: boolean;
      { set true if all FxxxState values are OK }
    FFatalForm: TAAFatalForm;
    FFatalCancelTime: integer;
    FAlarmCancelTime: integer;
    FSimulationOn: boolean;
    FSkipCalibration: boolean;

    {FindULDP: TULDPObj;
      { set true if just testing software without presence of the Sequencer device }
    FSequencerTemplateFileName: string;
    FSeqFileOpenDlg: TOpenDialog;
    FAcqDebugStartTime: integer;
    FDebLogAcq: boolean;
      { log acquired values from Channel A,B to DebLog? }
    {v0.25}
    FDebErrorDlg: boolean;
    FCHAProp: TModuleProp;
    FCHBProp: TModuleProp;
{    FNextSampleEnabled: boolean;}
      { set flag false if some error (loading next sample) failed during the
        run, will cause stopping the analysis }
    FLogHead: string;
      { string prepended to Log parameter }
    {/v0.25}
    function GetDataRootDir: string;
  protected
    function GetRecID: TULRecID; override;
    function GetSequencerObj: TSequencerObj;
    procedure ClassFieldsCreate;override;
    procedure ClassFieldsDestroy;override;
    function GetULDP(const SequencerObjPropName: string; var AULDP:TULDPObj): boolean;
      { find uldp object that corresponds to property name of TSequencerObj
        (i.e. to what ULDPObj should be assigned initial values)
        Syntax of SequencerObjPropName: DeviceName_PropDesc }
    function FindULDP(const SequencerObjPropName: string): TULDPObj;
      { as GeTULDP but raises exception if not found }
    procedure FindULDRs;
    function FindULDR(const SequencerObjPropName: string): TULDRObj;

    procedure CopySequencerToULD;
      { copy values from SequencerObj to ULDR.ULDP objects (e.g. to devices)
        using SequencerObj property names }

      procedure GetULField(const SequencerPropName: string; var AField: TULObjFldAutoCon);

    procedure Log(const msg:string);
    {v0.29}
    procedure LogState(const msg: string);
      { log error status to logfile, eventually to the current sample}
      procedure SampleLog(const msg: string);
        { called from logstate, if cursample <> nil then
          adds message to its Protocol }
    {/v0.29
    procedure LogState;
    }
    procedure AlarmActivate;
      { start alarm (PC speaker), user can cancel, then ignore alarms for 3-5 min }
    procedure AlarmDeactivate;
    procedure FatalActivate;
      { in 10 seconds will start switch off devices (if user won't correct the error) }
    function SetSequencerState(SequencerAState: TSequencerState): TSequencerResult;
      { tries to set specified state, returns error if not possible }
      procedure StateStart(aas: TSequencerState; AUsrTimeOffset: integer);
        { no checking - set specified state and starts its time }

    procedure DoTechControl;
      procedure ClearParams;
      procedure DoTechStarting;
      procedure DoTechStoppingFinishing;
      {v0.25}
      {procedure DoTechStopRunning;}
      {/v0.25}
      procedure DoTechAborting;
      procedure DoTechRunningStopRunning;

    procedure DoTimer(Sender: TObject);
    function GetSequencerState: TSequencerState;

    procedure GetULFields;
    procedure UpdateUpdateIntervals;
    function GetP1StateMsg: string;
    function GetP2StateMsg: string;
    function GetDetStateMsg: string;
    function GetColStateMsg: string;
    function GetReactStateMsg: string;
    function GetASStateMsg: string;

    {set devices states}
    procedure SetIKState(dst: TDevState);
    procedure SetP1State(dst: TDevState);
    procedure SetP2State(dst: TDevState);
    procedure SetDetState(dst: TDevState);
    procedure SetColState(dst: TDevState);
    procedure SetReactState(dst: TDevState);

    procedure SetASState(ast: TASState);
    {/set devices states}
    function GetUsrStateTimeStr: string;
      { time of current SequencerState in minutes }
    procedure SetUsrStateTimeStr(const AValue: string);

    function FirstSampleRun: TSequencerResult;
    function GetErrorActive: boolean;
      { true if fatal or alarm active }
    function GetFatalActive: boolean;
    function GetAlarmActive: boolean;
    function ShouldIgnoreError: boolean;
    function GetASTempMin: TTemperature;
    function GetASTempMax: TTemperature;
    function GetDetTempMin: TTemperature;
    function GetDetTempMax: TTemperature;
    function ChildCreate(AChildObj: TULObj):TULObjUsr;override;
    procedure WMAppMessage(var Msg: TMessage);message WM_APPMESSAGE;
    procedure SequenceUpdateDefaults(AULSQ: TULSQObj);
    function AcqStart: boolean;
      { start acquisition of data for current sample }
    procedure AcqDoTimer;
      { called every sec. acquire the data, append to FAcqData }
    procedure AcqStop;
    function AcqEquilStart: boolean;
      { as AcqStart but with file name set to PrgName_Equilibration }
    procedure AcqEquilStop;
      { just calls AcqStop }
      { stop the acquisition }
    function GetCurSample: TSeqSample;
    function CheckSequenceFilesPresence: boolean;
    procedure AcqDataUpdateViewLimit;
      { reflect CurPrg.Time of last line to X max limit of SpecForm view limit }

    {v0.25}
    function GetCurPrgName: string;{ for status wnd }
    function GetCurSampleName: string;{ for status wnd }
    function GetCurSampleStateName: string; { ulsrtype }

    procedure CurSampleStateChanged;
      {call when current sample program/name/state changed}
    procedure DoCurSampleSelected;
      { called after Sequence.First or Sequence.Next, i.e. when CurSample
        pointer changed; loads params from prg, method files }
    function IsInFatalCancelTime: boolean;
    function IsInAlarmCancelTime: boolean;
    procedure DefMethodSetDefaults;
    {/v0.25}
    function CheckCurSample: boolean; {ulsrtype}
      { returns true if Sequence has CurSample (selected by First or Next call,
        ready to run) }
    procedure CheckDefTemplate;
    procedure UpdateDefDirs;override;
      { Update DefDir properties of ULObjs and ULObjFields according to
        current AO.SeqsDir, AO.MethodsDir, AO.PrgsDir values }
    procedure DoAfterSettingsEdit;
    function GetNewSequenceName: string;
      { returns name of new (non existing) directory (yymmdd-n), subdirectory
        of AO.SeqsDir }
    function GetMethodFullFileName: string;
      { creates full filename from AO MethodsDir and MethodFileName fields }
    function GetSeqFullFileName: string;
      { creates full filename from AO SeqsDir and SeqFileName fields }
    function GetCurSequenceName: string;
      { returns name of current sequence for displaying }

    function GetPrgFullFileName: string;
    procedure SequenceCheckDir;
      { makes sure that directory for currently selected sequence exists }
    procedure SequenceFileNew;
      { non interactive creation of new sequence (used just during the first
        program start, or if SeqFileName cleared ) }
    {v0.29}
    procedure DefPrgCreateDefault;
    {/v0.29}
    {v0.38}
    procedure SetCurPrg(APrg: TAAPrg);
    procedure SetDefPrg(APrg: TAAPrg);{not public method accessible through property!!}
    procedure DefPrgNameChanged;
    procedure SetLogActive(OnOff: boolean);
    {/v0.38}
  public
    constructor Load(const AFileName: string); reintroduce;
    {constructor Create(const AFileName: string);}
    destructor Destroy;override;
    procedure ErrorCanceled;{from FatalForm}
    procedure ErrorConfirmed;{from FatalForm}
    procedure AutoSaveAll;
      { called upon every ended acquisition to save all opened files }


    {usr methods}
    function SettingsEdit: integer;
    procedure SequenceBrowse;
    procedure SequenceOpen;
    procedure SequenceNew;
    procedure SeqFileOpen;
      { File Open Dialog for files of current sequence }
    procedure DefPrgBrowse;
    {v0.38}
    procedure ShowRunningPrg;
    {/v0.38}
    procedure DefPrgOpen;
    procedure DefPrgNew;
    procedure DefMethodEdit;
    procedure DefMethodOpen;
    procedure DefMethodNew;

    function UsrSetSequencerState(SequencerAState: TSequencerState): TSequencerResult;
    procedure UsrRequestOnOff;
    procedure AcqShow;
     { show window for current acquisition }

    {/usr methods}
    {debug methods}
    procedure AcqDebugStart;
    procedure AcqDebugStop;

    property LogHead: string read FLogHead write FLogHead;
    procedure DebugAlarmActivate;
    procedure DebugFatalActivate;
    {/debug}
    {debug properties}
    property DebLogAcq: boolean read FDebLogAcq write FDebLogAcq;
    {/debug properties}
    property ULDP[const SequencerObjPropName: string]: TULDPObj read FindULDP;{ulobju}
    property AO:TSequencerObj read GetSequencerObj;

    property DefPrg: TAAPrg read FDefPrg;
    property DefMethod: TUlanMethod read FDefMethod;
    property DefInstrument: TInstrument read FDefInstrument;
    property Sequence: TSequence read FSequence;
    property CurSample: TSeqSample read GetCurSample;
    property StateTime: integer read FStateTime;
    property StateStartTime: integer read FStateStartTime;

    property State: TSequencerState read GetSequencerState;

    {dev states write only props (read xxxStateMsg) }
    property IKState: TDevState write SetIKState;
    property P1State: TDevState write SetP1State;
    property P2State: TDevState write SetP2State;
    property DetState: TDevState write SetDetState;
    property ColState: TDevState write SetColState;
    property ReactState: TDevState write SetReactState;
    property ASState: TASState write SetASState;
    {/dev states}
    property DevStatesOK: boolean read FDevStatesOK write FDevStatesOK;
    property FatalActive: boolean read GetFatalActive;
    property ErrorActive: boolean read GetErrorActive;
    property AlarmActive: boolean read GetAlarmActive;
    property DataRootDir: string read GetDataRootDir;
    property SequencerTemplateFileName: string read FSequencerTemplateFileName;
    {v0.38}
    property CurPrg: TAAPrg read FCurPrg write SetCurPrg;{aaprgu}
    property LogActive: boolean read FLogActive write SetLogActive;
    {/v0.38}
  published
    property DP1: TULDRObj read FP1 write FP1;
    property DP2: TULDRObj read FP2 write FP2;
    property DAS: TULDRObj read FAS write FAS;
    property DDET: TULDRObj read FDET write FDET;
    property DIK: TULDRObj read FIK write FIK;

    property IK_ON: TULObjFldAutoCon read FIK_ON write FIK_ON;
    property IK_OFF: TULObjFldAutoCon read FIK_OFF write FIK_OFF;
    property IK_STATUS: TULObjFldAutoCon read FIK_STATUS write FIK_STATUS;
    property IK_WDG: TULObjFldAutoCon read FIK_WDG write FIK_WDG;

    property P1_STATUS: TULObjFldAutoCon read FP1_STATUS write FP1_STATUS;
    property P1_FLOW: TULObjFldAutoCon read FP1_FLOW write FP1_FLOW;
    property P1_PRESS: TULObjFldAutoCon read FP1_PRESS write FP1_PRESS;
    property P1_PRESS_L: TULObjFldAutoCon read FP1_PRESS_L write FP1_PRESS_L;
    property P1_PRESS_H: TULObjFldAutoCon read FP1_PRESS_H write FP1_PRESS_H;
    property P1_AUXVALV: TULObjFldAutoCon read FP1_AUXVALV write FP1_AUXVALV;
    property P1_STOP: TULObjFldAutoCon read FP1_STOP write FP1_STOP;
    property P1_START: TULObjFldAutoCon read FP1_START write FP1_START;
    property P1_ERRCLR: TULObjFldAutoCon read FP1_ERRCLR write FP1_ERRCLR;

    property P2_STATUS: TULObjFldAutoCon read FP2_STATUS write FP2_STATUS;
    property P2_FLOW: TULObjFldAutoCon read FP2_FLOW write FP2_FLOW;
    property P2_PRESS: TULObjFldAutoCon read FP2_PRESS write FP2_PRESS;
    property P2_PRESS_L: TULObjFldAutoCon read FP2_PRESS_L write FP2_PRESS_L;
    property P2_PRESS_H: TULObjFldAutoCon read FP2_PRESS_H write FP2_PRESS_H;
    property P2_GRADDIR: TULObjFldAutoCon read FP2_GRADDIR write FP2_GRADDIR;
    property P2_GRAD_B: TULObjFldAutoCon read FP2_GRAD_B write FP2_GRAD_B;
    property P2_STOP: TULObjFldAutoCon read FP2_STOP write FP2_STOP;
    property P2_START: TULObjFldAutoCon read FP2_START write FP2_START;
    property P2_ERRCLR: TULObjFldAutoCon read FP2_ERRCLR write FP2_ERRCLR;

    property AS_OFF: TULObjFldAutoCon read FAS_OFF write FAS_OFF;
    property AS_TEMP_OFF: TULObjFldAutoCon read FAS_TEMP_OFF write FAS_TEMP_OFF;
    property AS_STATUS: TULObjFldAutoCon read FAS_STATUS write FAS_STATUS;
    property AS_TEMP1: TULObjFldAutoCon read FAS_TEMP1 write FAS_TEMP1;
    property AS_TEMP1RQ: TULObjFldAutoCon read FAS_TEMP1RQ write FAS_TEMP1RQ;
    property AS_CALLPS: TULObjFldAutoCon read FAS_CALLPS write FAS_CALLPS;
    property AS_ERRCLR: TULObjFldAutoCon read FAS_ERRCLR write FAS_ERRCLR;
    property AS_SAMPNUM: TULObjFldAutoCon read FAS_SAMPNUM write FAS_SAMPNUM;
    {property AS_ASPREPARE: TULObjFldAutoCon read FAS_ASPREPARE write FAS_ASPREPARE;}
    property AS_INJECT: TULObjFldAutoCon read FAS_INJECT write FAS_INJECT;
    property AS_TEMP_ST: TULObjFldAutoCon read FAS_TEMP_ST write FAS_TEMP_ST;
    property AS_PREPSAMP: TULObjFldAutoCon read FAS_PREPSAMP write FAS_PREPSAMP;

    property DET_TEMP1: TULObjFldAutoCon read FDET_TEMP1 write FDET_TEMP1;
    property DET_TEMP_ST: TULObjFldAutoCon read FDET_TEMP_ST write FDET_TEMP_ST;
    property DET_ERRCLR: TULObjFldAutoCon read FDET_ERRCLR write FDET_ERRCLR;
    property DET_CHA: TULObjFldAutoCon read FDET_CHA write FDET_CHA;
    property DET_CHB: TULObjFldAutoCon read FDET_CHB write FDET_CHB;
    property DET_ZERO : TULObjFldAutoCon read FDET_ZERO  write FDET_ZERO;
    property DET_ON : TULObjFldAutoCon read FDET_ON  write FDET_ON;
    property DET_OFF : TULObjFldAutoCon read FDET_OFF  write FDET_OFF;
    property DET_TEMP_OFF : TULObjFldAutoCon read FDET_TEMP_OFF  write FDET_TEMP_OFF;
    property DET_STATUS : TULObjFldAutoCon read FDET_STATUS  write FDET_STATUS;

    property P1StateMsg: string read GetP1StateMsg;
    property P2StateMsg: string read GetP2StateMsg;
    property DetStateMsg: string read GetDetStateMsg;
    property ColStateMsg: string read GetColStateMsg;
    property ReactStateMsg: string read GetReactStateMsg;
    property ASStateMsg: string read GetASStateMsg;

    property UsrStateTimeStr: string read GetUsrStateTimeStr write SetUsrStateTimeStr;
    property SimulationOn: boolean read FSimulationOn write FSimulationOn;
    property SkipCalibration: boolean read FSkipCalibration write FSkipCalibration;
    property ASTempMin: TTemperature read GetASTempMin;
    property ASTempMax: TTemperature read GetASTempMax;
    property DetTempMin: TTemperature read GetDetTempMin;
    property DetTempMax: TTemperature read GetDetTempMax;

    property CurSampleName: string read GetCurSampleName;
    property CurPrgName: string read GetCurPrgName;
    property CurSampleStateName: string read GetCurSampleStateName;
    property CurSequenceName: string read GetCurSequenceName;
  end;

function Sequencer: TSequencer;
procedure SequencerFree;

implementation

const
  FSequencer: TSequencer = nil;

function SequencerCfgName: string;
begin
  Result := DataDir + SequencerCfgBaseName;
end;

function Sequencer: TSequencer;
begin
  if FSequencer = nil then begin
    FSequencer := TSequencer.Load(SequencerCfgName);
  end;
  Result := FSequencer;
end;

{TSequencer}
function TSequencer.GetRecID: TULRecID;
begin
  Result := SequencerID;
end;

constructor TSequencer.Load(const AFileName: string);
const
  DefHistorySlotCount = 6;
{var
  d: string;}
begin{ulobjusru}
  inherited; {Load{Create(nil, nil, SequencerID); ulanrecs.lst aapgtype}
{  if (AFileName <> '') and (AFileName <> FileName) then begin
    if FileExists(AFileName) then begin
      LoadFromFile(AFileName);
    end else begin
      FileName := AFileName;
    end;
  end;}
  {v0.24}
  {v0.38}
  LogActive := true;
  {/v0.38
  FLogActive := true;
  }
  AO.SequencerName := 'Sequencer';
  AO.SequencerState := aasDisconnected;
  {/v0.24}
  {techhistory}
  FP1PressHistory := TTechHistory.Create(DefHistorySlotCount);
  FP2PressHistory := TTechHistory.Create(DefHistorySlotCount);
  FColumnTempHistory := TTechHistory.Create(DefHistorySlotCount);
  FReactTempHistory := TTechHistory.Create(DefHistorySlotCount);
  FHistCount:= MaxHistCount;
  FHists[0] := FP1PressHistory;
  FHists[1] := FP2PressHistory;
  FHists[2] := FColumnTempHistory;
  FHists[3] := FReactTempHistory;
  {/techhistory}
  GetULFields;
  {v0.24}
  UpdateUpdateIntervals;
  FindULDRs;
  ClearParams;
  CheckDefTemplate;

  Timers.AddTimerProc(DoTimer, 1000);{timersu}
  {/v0.24}
end;

procedure TSequencer.ClassFieldsDestroy;
begin

  {if FDefPrg <> nil then
    AO.PrgFileName := RelativeFileName(FDefPrg.FileName;}
  {v0.38}
  SetDefPrg(nil);
  {/v0.38
  FDefPrg.Free;
  FDefPrg := nil;}

  {if FSequence <> nil then
    AO.SeqFileName := FSequence.FileName;}
  FSequence.Free;
  FSequence := nil;

  {if FDefMethod <> nil then
    AO.MethodFileName := FDefMethod.FileName;}
  FDefMethod.Free;
  FDefMethod := nil;

  inherited;
end;

{v0.25}
procedure TSequencer.DefMethodSetDefaults;
begin
  FDefMethod.ULM.NoUnknownPeaks := true;
  {v0.29}
  FDefMethod.Save;
  {/v0.29}
end;
{/v0.25}

{v0.29}
procedure TSequencer.DefPrgCreateDefault;

  procedure AddLine0(l: TAAPLObj);
  begin
    l.PrgTime := 0;
    l.Temperature := 50;
    l.BufferNr := bn1;
    l.Command := acInject;
    l.Note := 'Start by injecting the sample on the column (acqusition starts)';
  end;

  procedure AddLine1(l: TAAPLObj);
  begin
    l.PrgTime := 60;
    l.Temperature := 50;
    l.BufferNr := bn1;
    l.Command := acNHD;
    l.Note := 'Ninhydrin should be switched on for poscolumn detection';
  end;

  procedure AddLine2(l: TAAPLObj);
  begin
    l.PrgTime := 120;
    l.Temperature := 50;
    l.BufferNr := bn1;
    l.Command := acZero;
    l.Note := 'Eventually zero the detector';
  end;

  procedure AddLine3(l: TAAPLObj);
  begin
    l.PrgTime := 180;
    l.Temperature := 50;
    l.BufferNr := bn1;
    l.Command := acLoad;
    l.Note := 'Load next sample to injector loop';
  end;

  procedure AddLine4(l: TAAPLObj);
  begin
    l.PrgTime := 240;
    l.Temperature := 50;
    l.BufferNr := bn1;
    l.Command := acAcqStop;
    l.Note := 'Acquisition can be stopped before program ends';
  end;

  procedure AddLine5(l: TAAPLObj);
  begin
    l.PrgTime := 300;
    l.Temperature := 50;
    l.BufferNr := bn1;
    l.Command := acStartEquil;
    l.Note := 'Start equilibrating the columnn for next sample';
  end;

  procedure AddLine6(l: TAAPLObj);
  begin
    l.PrgTime := 360;
    l.Temperature := 50;
    l.BufferNr := bn1;
    l.Command := acNone;
    l.Note := 'Just waiting for the end (of equilibration)';
  end;

var
  pl: TAAPrgLine;
  i: integer;

begin
  for i := 0 to 6 do begin
    pl := TAAPrgLine(FDefPrg.ChildAdd(nil, AAPLID, ''));{ulobjusru}
    case i of
      0: AddLine0(pl.AAPL);
      1: AddLine1(pl.AAPL);
      2: AddLine2(pl.AAPL);
      3: AddLine3(pl.AAPL);
      4: AddLine4(pl.AAPL);
      5: AddLine5(pl.AAPL);
      6: AddLine6(pl.AAPL);
    end;
  end;
  FDefPrg.Save;
end;
{/v0.29}

procedure TSequencer.ClassFieldsCreate;
{var d: string;}
begin
  inherited;

  if AO.SeqsDir = '' then begin
    AO.SeqsDir := DataRootDir + 'Sequences\';
    CreateDir(AO.SeqsDir);
  end;

  if ExtractFilePath(AO.SeqFileName) = '' then begin
    if AO.SeqFileName = '' then begin
      AO.SeqFileName  := '';{GetNewSequenceName;{ULRecDefFileName(ULSQID);}
    end;
  end;

  if AO.MethodsDir = '' then begin
    AO.MethodsDir := DataRootDir + 'Methods\';
    CreateDir(AO.MethodsDir);
  end;
  if ExtractFilePath(AO.MethodFileName) = '' then begin
    if AO.MethodFileName = '' then
      AO.MethodFileName  := ULRecDefFileName(ULMID);
  end;

  if AO.PrgsDir = '' then begin
    AO.PrgsDir := DataRootDir + 'Programs\';
    CreateDir(AO.PrgsDir);
  end;
  if ExtractFilePath(AO.PrgFileName) = '' then begin
    if AO.PrgFileName = '' then
      AO.PrgFileName  := ULRecDefFileName(AAPGID);
  end;

  if FDefInstrument = nil then
    FDefInstrument := TInstrument(ChildFindOrAdd(ULIID, ''));{ulobjusru}

  if FDefMethod = nil then begin
    FDefMethod := TUlanMethod.Load(GetMethodFullFileName); {ulobju extractfilename }
    {v0.25}
    if not FileExists(GetMethodFullFileName) then begin
      DefMethodSetDefaults;
    end;
    {/v0.25}
  end;

  if FDefPrg = nil then begin
    {v0.38}
    SetDefPrg(TAAPrg.Load(GetPrgFullFileName));
    {/v0.38
    FDefPrg := TAAPrg.Load(GetPrgFullFileName);}
    {v0.25}
    FDefPrg.Obj.SetFlag(rfAskForSave, true);{ulobju}
    {/v0.25}
    {v0.29}
    if not FileExists(GetPrgFullFileName) then begin
      DefPrgCreateDefault;
    end;
    {/v0.29}
  end;

  if FSequence = nil then begin
    if AO.SeqFileName = '' then begin
      FSequence := TSequence.Load('');
      {v0.25}
      FSequence.Obj.SetFlag(rfAskForSave, false);
      {/v0.25}
      SequenceFileNew;
    end else begin
      FSequence := TSequence.Load(GetSeqFullFileName);
      {v0.25}
      FSequence.Obj.SetFlag(rfAskForSave, false);
      {/v0.25}
    end;
  end;

  SequenceUpdateDefaults(FSequence.ULSQ);
  UpdateDefDirs;

  {!!! just for testing:}
  {FCurPrg := FDefPrg;}
end;

function TSequencer.GetMethodFullFileName: string;
begin
  Result := AbsoluteFileName(AO.MethodsDir, AO.MethodFileName{v0.36}, ULMExt{/v0.36});
end;

function TSequencer.GetCurSequenceName: string;
begin
  Result := ExtractFileName(ChangeFileExt(AO.SeqFileName, ''));
end;

function TSequencer.GetSeqFullFileName: string;
begin
  Result := AbsoluteFileName(AO.SeqsDir, AO.SeqFileName {v0.36}, ULSExt{/v0.36});
end;

function TSequencer.GetPrgFullFileName: string;
begin
  Result := AbsoluteFileName(AO.PrgsDir, AO.PrgFileName{v0.36}, AAPGExt{/v0.36});
end;

function TSequencer.GetSequencerObj: TSequencerObj;
begin
  Result := TSequencerObj(Obj);
end;

procedure TSequencer.SequenceBrowse;
begin
  FSequence.Browse;
end;

procedure TSequencer.SequenceOpen;
begin
  if Sequence.FileOpen then begin
    {v0.25}
    Sequence.Obj.SetFlag(rfAskForSave, false);
    AO.SeqFileName := Sequence.ULSQ.SequenceName + ULRecDefFileExt(ULSQID);
    AO.DoChange;
    {/v0.25}
    SequenceBrowse;
  end;
end;

procedure TSequencer.SeqFileOpen;
 { File Open Dialog for files of current sequence }
begin
  if FSeqFileOpenDlg = nil then begin
    FSeqFileOpenDlg := TOpenDialog.Create(Self);
  end;
  FSeqFileOpenDlg.FileName := '';
  FSeqFileOpenDlg.InitialDir := Sequence.DirName;
  FSeqFileOpenDlg.Filter := GetTxt({#}'Data file (*.ULF)|*.ULF');
  if FSeqFileOpenDlg.Execute then begin
    CreateSpectrumForm(FSeqFileOpenDlg.FileName, omRead);{ulantype}
  end;{main}
end;

procedure TSequencer.SequenceCheckDir;
begin
  CreateDir(AO.SeqsDir + Sequence.ULSQ.SequenceName);
  {v0.29}
  if not FileExists(Sequence.FileName) then
    Sequence.Save;
  {/v0.29}
end;

procedure TSequencer.SequenceFileNew;
begin
  Sequence.FileNew;
  SequenceUpdateDefaults(Sequence.ULSQ);
  AO.SeqFileName := Sequence.ULSQ.SequenceName + ULRecDefFileExt(ULSQID);
  AO.DoChange;
  Sequence.FileName := GetSeqFullFileName;
  Sequence.ClassFieldsUpdate;
  SequenceCheckDir;
end;

procedure TSequencer.SequenceNew;
var
  f: TULFObj;
  s: TULSQObj;
begin
  { vybrat z analsetup form }
  f := TULFObj.Create(nil);
  try
    s := TULSQObj(f.FindOrAdd(ULSQID, ''));
    SequenceUpdateDefaults(s);
    if s.EditModal = mrOK then begin
      Sequence.FileNew;
      Sequence.ULSQ.Assign(s);
      
      AO.SeqFileName := Sequence.ULSQ.SequenceName + ULRecDefFileExt(ULSQID);
      AO.DoChange;

      Sequence.FileName := GetSeqFullFileName;
      Sequence.ClassFieldsUpdate;
      SequenceCheckDir;
      SequenceBrowse;
    end;
  finally
    f.Free;
  end;
end;

function TSequencer.GetNewSequenceName: string;
var
  d: string;
  n: string;
  i: integer;
begin
  n := FormatDateTime('yymmdd', Now);
  i := 1;
  repeat {ulsqtype}
    d := n + '-' + IntToStr(i);
    if not DirectoryExists(AO.SeqsDir + d) then begin
      break;
    end;
    inc(i);
  until false;
  Result := d;
end;

procedure TSequencer.SequenceUpdateDefaults(AULSQ: TULSQObj);
begin
  if AULSQ.PrgFileName = '' then begin
    AULSQ.PrgFileName := AO.PrgFileName;
  end;

  if AULSQ.MethodFileName = '' then begin
    AULSQ.MethodFileName := AO.MethodFileName;
  end;

  if AULSQ.SequenceName = '' then begin
    AULSQ.SequenceName := GetNewSequenceName;
    AULSQ.MethodFileName := AO.MethodFileName;
    AULSQ.PrgFileName := AO.PrgFileName;
  end;
  {ulsqtype}
end;

procedure TSequencer.DefPrgBrowse;
begin
  FDefPrg.Browse;
end;

{v0.38}
procedure TSequencer.ShowRunningPrg;
begin
  if FCurPrg <> nil then begin
    FBrowsingCurPrg := FCurPrg;
    FCurPrg.Browse;
  end else begin
    FBrowsingCurPrg := nil;
  end;
end;
{/v0.38}

procedure TSequencer.DefPrgOpen;
begin
  if DefPrg.FileOpen then begin {ulobjusru ulmtype}
    {v0.25}
    DefPrg.Obj.SetFlag(rfAskForSave, true);{ulobju}
    {/v0.25}
    {v0.38}
    DefPrgNameChanged;
    {/v0.38
    AO.PrgFileName := RelativeFileName(AO.PrgsDir, DefPrg.FileName
      , AAPGExt);}
    DefPrgBrowse;
  end;
end;

{v0.38}
procedure TSequencer.DefPrgNameChanged;
begin
  AO.PrgFileName := RelativeFileName(AO.PrgsDir, DefPrg.FileName, AAPGExt);
end;
{/v0.38}

procedure TSequencer.DefPrgNew;
begin
  DefPrg.FileNew;
  AO.PrgFileName := ExtractFileName(DefPrg.FileName);
  DefPrg.FileName := GetPrgFullFileName;
  DefPrg.ClassFieldsUpdate;
  DefPrgBrowse;
end;

procedure TSequencer.DefMethodEdit;
begin
  {v0.26}
  if DefMethod.EditModal = mrOK then begin
    {v0.37}
    DefMethod.Obj.DoFileSave;
    AO.MethodFileName := RelativeFileName(AO.MethodsDir, DefMethod.FileName,
      ULMExt);
    {/v0.37
    DefMethod.Save;}
  end;
  {/v0.26 ulobjusru
    DefMethod.EditModal; }
end;

procedure TSequencer.DefMethodOpen;
begin
  if DefMethod.FileOpen then begin
    AO.MethodFileName := RelativeFileName(AO.MethodsDir, DefMethod.FileName
      {v0.36}, ULMExt{/v0.36});
    DefMethodEdit;
  end;
end;

procedure TSequencer.DefMethodNew;
begin
  DefMethod.FileNew;
  AO.MethodFileName := {v0.36}RelativeFileName(AO.MethodsDir, DefMethod.FileName, ULMExt);{/v0.36
    ExtractFileName(DefMethod.FileName);}
  DefMethod.FileName := GetMethodFullFileName;
  DefMethod.ClassFieldsUpdate;
  DefMethodSetDefaults;
  DefMethodEdit;
end;

function TSequencer.SettingsEdit: integer;
begin
  Result := EditModal; {ulobjusru}
  if Result = mrOK then begin
    DoAfterSettingsEdit;
    {CopySequencerToULD;}
  end;
end;

function TSequencer.GetULDP(const SequencerObjPropName: string; var AULDP:TULDPObj): boolean;
{ find uldp object that corresponds to property name of TSequencerObj
 (i.e. to what uldpobj should be assigned these initial values }
var
  dn, pn: string;
  o: TULObj;
  i: integer;
begin
  Result := false;
  i := pos('_', SequencerObjPropName);
  if i > 0 then begin
    dn := copy(SequencerObjPropName, 1, i - 1);
    pn := copy(SequencerObjPropName, i + 1, length(SequencerObjPropName));
    if ULFKeeper.FindByULObjPath(dn + '.' + pn, 0, o) then begin
      if o is TULDPObj then begin
        AULDP := TULDPObj(o);
        Result := true;
        exit;
      end;
    end;
  end;
end;

function TSequencer.FindULDR(const SequencerObjPropName: string): TULDRObj;
var o: TULObj;
begin
  if ULFKeeper.FindByULObjPath(SequencerObjPropName, 0, o) and
    (o is TULDRObj)
  then begin
    Result := TULDRObj(o);
  end else begin
    raise Exception.Create('Sequencer ' + SequencerObjPropName + ' not found.');
  end;
end;

procedure TSequencer.FindULDRs;
{v0.25}
var m: TModule;
{/v0.25}
begin
  FP1 := FindULDR('P1');
  FP2 := FindULDR('P2');
  FAS := FindULDR('AS');
  FIK := FindULDR('IK');
  FDET := FindULDR('DET');

  {v0.25}
  if not Modules.FindModuleWithPropVal(piDeviceName, 'DET', m) then
    raise Exception.Create('Module DeviceName=DET not found in Modules');

  if not m.FindPropByDesc('CHA', FCHAProp) then
    raise  Exception.Create('Property CHA not found in Module DET');
  if not m.FindPropByDesc('CHB', FCHBProp) then
    raise  Exception.Create('Property CHB not found in Module DET');
  {/v0.25}
end;

function TSequencer.FindULDP(const SequencerObjPropName: string): TULDPObj;
{ as GeTULDP but raises exception if not found }
var o:TULDPObj;
begin
  if not GetULDP(SequencerObjPropName, o) then
    raise Exception.Create('Sequencer ' + SequencerObjPropName + ' not found.');
  Result := o;
end;

procedure TSequencer.CopySequencerToULD;
var
  up: TULDPObj;
  i: integer;
  s: string;
begin
  for i := 0 to AO.FieldCount - 1 do begin
    if GetULDP(AO.Fields[i].FldDesc.Name, up) then begin
      if (up.TypeID <> ptCommand) and ((up.PropFlags and pfWrite) <> 0) then begin

        if up.PropDesc = 'PRESS_L' then begin
          s := '0';
        end else if up.PropDesc = 'PRESS_H' then begin
          s := IntToStr(StrToInt(AO.Fields[i].AsString) + 10);
        end else begin
          s := AO.Fields[i].AsString;
        end;

        up.ValueInPC := s;
        Log('Sequencer->ULD ' + AO.Fields[i].FldDesc.Name + '=' + s);
      end;{uldptype}
    end;
  end;
end;

procedure TSequencer.UpdateUpdateIntervals;
var
  up: TULDPObj;
  i: integer;
  n: shortstring;
  v: AnsiString;
  pi: PPropInfo;
begin
  {proputl}
  i := 0;
  while ClassGetPropNameAndValue(Self, i, n, v) do begin
    if ClassGetPropInfo(Self, n, pi) then begin
      if pi^.PropType^^.Name = 'TULObjFldAutoCon' then begin
        if GetULDP(n, up) then begin
          if (up.TypeID <> ptCommand) and ((up.PropFlags and pfRead) <> 0) then begin
            up.UpdateInterval := 1000;
            Log('Sequencer->ULD UpdateTime ' + n + ' 1000 ms');
          end;
        end;
      end;
    end;
    inc(i);
  end;
end;

procedure TSequencer.GetULFields;
var
  i: integer;
  n: shortstring;
  value: ansistring;
  f: TULObjFldAutoCon;
  pi: PPropInfo;
begin
  i := 0;
  while ClassGetPropNameAndValue(Self, i, n, value) do begin
    if ClassGetPropInfo(Self, n, pi) then begin
      if pi^.PropType^^.Name = 'TULObjFldAutoCon' then begin
      {if pos('_', n) > 0 then begin}
        GetULField(n, f);
        SetOrdProp(Self, pi, integer(f));
      end;
    end;
    inc(i);
  end;
end;

procedure TSequencer.GetULField(const SequencerPropName: string; var AField: TULObjFldAutoCon);
begin
  AField := TULObjFldAutoCon(FindULDP(SequencerPropName).FindField(pvValueInPC));
end;

destructor TSequencer.Destroy;
begin
  {v0.38}
  LogActive := false;
  {/v0.38}

  AcqStop;
  {FAcqInfo.Free;
  FAcqData.Free;}
  Timers.DeleteTimerProc(DoTimer);
  FP1PressHistory.Free;
  FP2PressHistory.Free;
  FColumnTempHistory.Free;
  FReactTempHistory.Free;
  inherited Destroy;
end;

procedure TSequencer.DoTimer(Sender: TObject);
begin
  if FIsInTimer then
    exit;
  FIsInTimer := true;
  try
    DoTechControl;{sleep}
  finally
    FIsInTimer := false;
  end;
end;

procedure TSequencer.AlarmDeactivate;
begin
  if not AlarmActive then
    exit;
  if FFatalForm <> nil then begin
    FFatalForm.Free;
    FFatalForm := nil;
    FAlarmCancelTime := 0;
  end;{ulobjusru}
end;

{v0.25}
procedure TSequencer.DebugAlarmActivate;
begin
  FDebErrorDlg := true;
  try
    AlarmActivate;
  finally
    FDebErrorDlg := false;
  end;
end;

procedure TSequencer.DebugFatalActivate;
begin
  FDebErrorDlg := true;
  try
    FatalActivate;
  finally
    FDebErrorDlg := false;
  end;
end;
{/v0.25}

procedure TSequencer.AlarmActivate;
begin
  {see beeper unit}
  {v0.25}
  if FDebErrorDlg then begin
    if FFatalForm <> nil then
      exit;
  end else
  {/v0.25}
  begin
    if ShouldIgnoreError then
      exit;
    if ErrorActive then
      exit;
    if SimulationOn then
      exit;
  end;
  FFatalForm := TAAFatalForm.Create(Application.MainForm);
  FFatalForm.Text := GetTxt({#}'Error conditions. Shut down Sequencer?');
  FFatalForm.Timeout := 5*60*1000;
  FFatalForm.IsAlarm := true;
  FFatalForm.Show;

  {v0.29}
  LogState('ALARM WARNING');
  {/v0.29
  Log('ALARM WARNING');
  LogState;}
end;

procedure TSequencer.ErrorCanceled;
begin
  if FFatalForm = nil then
    exit;
  if FFatalForm.IsAlarm then begin
    FAlarmCancelTime := mstime;
    FFatalCancelTime := 0;
  end else begin
    FAlarmCancelTime := 0;
    FFatalCancelTime := mstime;
  end;
  FFatalForm := nil;
end;

procedure TSequencer.ErrorConfirmed;
begin
  FFatalForm := nil;
  FFatalCancelTime := 0;
  FAlarmCancelTime := 0;
  SetSequencerState(aasAborting);
end;

function TSequencer.ShouldIgnoreError: boolean;
begin
  Result := (State = aasAborting) or (State <= aasOff);
end;

function TSequencer.GetASTempMin: TTemperature;
begin
  Result := {AO.AS_TEMP1RQ}AS_TEMP1RQ.AsFloat - AO.ASTempMinDif;
end;

function TSequencer.GetASTempMax: TTemperature;
begin
  Result := {AO.AS_TEMP1RQ}AS_TEMP1RQ.AsFloat + AO.ASTempMaxDif;
end;

function TSequencer.GetDetTempMin: TTemperature;
begin
  Result := AO.DET_TEMP1RQ - AO.DetTempMinDif;
end;

function TSequencer.GetDetTempMax: TTemperature;
begin
  Result := AO.DET_TEMP1RQ + AO.DetTempMaxDif;
end;


function TSequencer.IsInFatalCancelTime: boolean;
begin
  Result := false;
  if FFatalCancelTime <> 0 then begin
    if (mstime - FFatalCancelTime) < 2*60*1000 then
      Result := true
    else
      FFatalCancelTime := 0;
  end;
end;

function TSequencer.IsInAlarmCancelTime: boolean;
begin
  Result := false;
  if FAlarmCancelTime <> 0 then begin
    if (mstime - FAlarmCancelTime) < 2*60*1000 then
      Result := true
    else
      FAlarmCancelTime := 0;
  end;
end;


function TSequencer.GetFatalActive:boolean;
begin
{  Result := false;}
  if (FFatalForm <> nil) and (not FFatalForm.IsAlarm) then begin
    Result := true;
  end else begin
    Result := IsInFatalCancelTime;
    {if (FFatalCancelTime <> 0) and ((mstime - FFatalCancelTime) < 2*60*1000) then begin
      Result := true;
    end;}
  end;
end;

function TSequencer.GetAlarmActive:boolean;
begin
{  Result := false;}
  if (FFatalForm <> nil) and FFatalForm.IsAlarm then begin
    Result := true;
  end else begin
    Result := IsInAlarmCancelTime;
    {if (FAlarmCancelTime <> 0) and ((mstime - FAlarmCancelTime) < 2*60*1000) then begin
      Result := true;
    end;}
  end;
end;

function TSequencer.GetErrorActive: boolean;
begin
  Result := (FFatalForm <> nil) or IsInFatalCancelTime or IsInAlarmCancelTime;
end;

procedure TSequencer.FatalActivate;
begin
  {v0.25}
  if FDebErrorDlg then begin
    if FFatalForm <> nil then
      exit;
  end else
  {/v0.25}
  begin
    if SimulationOn then
      exit;
    if ShouldIgnoreError then
      exit;
    if FatalActive then
      exit;
  end;

  if AlarmActive then
    AlarmDeactivate;
  FFatalForm := TAAFatalForm.Create(Application.MainForm);
  FFatalForm.Show;
  {v0.29}
  LogState('FATAL ERROR');
  {/v0.29
  Log('FATAL ERROR ');
  LogState;}
end;

procedure TSequencer.LogState{v0.29}(const msg: string){/v0.29};
begin
  {v0.29}
  Log(msg);
  {/v0.29}
{  Log('IK    ' + IKStateMsg);}
  Log('AS    ' + ASStateMsg);
  Log('P1    ' + P1StateMsg);
  Log('P2    ' + P2StateMsg);
  Log('Det   ' + DetStateMsg);
  Log('Col   ' + ColStateMsg);
  Log('React ' + ReactStateMsg);
  {v0.29}
  SampleLog(msg);
  SampleLog('AS    ' + ASStateMsg);
  SampleLog('P1    ' + P1StateMsg);
  SampleLog('P2    ' + P2StateMsg);
  SampleLog('Det   ' + DetStateMsg);
  SampleLog('Col   ' + ColStateMsg);
  SampleLog('React ' + ReactStateMsg);
  {/v0.29}
end;

procedure TSequencer.Log(const msg: string);
var s:string;
begin {ulobju}
  if not FLogActive then
    exit;
  s := IntToString(FStateTime, 6) + ' '  +
       Pad(AO.FindField('SequencerState').AsString, 20) + ' ' +
       IntToString(FSubState, 3);{logfrm}
  {v0.38}
  if SimulationOn then begin
    s := '[SIMUL]' + s;
  end;
  {/v0.38}
  ExeLog.Log(s + ' ' + LogHead + msg);
end;

{v0.29}
procedure TSequencer.SampleLog(const msg: string);
var
  s:string;
  cs: TSeqSample;
begin
  cs := CurSample;
  if cs = nil then
    exit;
  s := FloatToStrF(FStateTime/60000, ffFixed, 6, 2) + ' '  + msg;
  cs.ULSR.Protocol := cs.ULSR.Protocol + s + #13#10;
  {ExeLog.Log(s + ' ' + LogHead + msg);}
  {v0.31}
  {v0.36}{/v0.36
  cs.ULSR.SampleState := sasError;}
  {/v0.31}
end;
{/v0.29}

procedure TSequencer.DoTechStarting;
begin
  case FSubState of

    0: begin

      DIK.DetectState := dsUnknown;
      IK_ON.AsInteger := 1;
      IK_ON.UpdateNow;

      Log('IK_ON');
      inc(FSubState);
    end;

    1: begin
      if FStateTime < 8000 then
        exit;

      DP1.DetectState := dsUnknown;
      DP2.DetectState := dsUnknown;
      DAS.DetectState := dsUnknown;
      DDET.DetectState := dsUnknown;

      Log('P1,P2,AS,DET - DetectState set to Unknown');
      inc(FSubState);
    end;

    2: begin
      if FStateTime < 10000 then
        exit;

      CopySequencerToULD;

      P1_STOP.AsInteger := 1;
      P2_STOP.AsInteger := 1;
      DET_OFF.AsInteger := 1;

      {AS_TEMP_OFF.AsInteger := 1;
      DET_TEMP_OFF.AsInteger := 1;
        .. dont call - will clear TEMP set by CopySequencerToULD }

      Log('Sequencer -> ULD');
      inc(FSubState);
    end;

    3: begin
      if FStateTime < 15000 then
        exit;

      P1_ERRCLR.AsInteger := 1;
      P1_AUXVALV.AsInteger := 1;

      P2_ERRCLR.AsInteger := 1;
      P2_GRADDIR.AsInteger := 1;

      DET_ERRCLR.AsInteger := 1;
      DET_ON.AsInteger := 1;

      AS_OFF.AsInteger := 1;
      AS_OFF.UpdateNow;
      AS_ERRCLR.AsInteger := 1;
      AS_OFF.UpdateNow;
      if not SkipCalibration then
        AS_CALLPS.AsInteger := 1;
      {SendCommand(IID_POD,I_ERRCLR);}

      Log('P1.AUXVALV=1 P2.GRADDIR=NHD DET.ON AS.CALLPS');
      FSubState := 10;
    end;

    10: begin
      if FStateTime < 2*60*1000 then
        exit;
      DET_ZERO.AsInteger := 1;
      Log('DET_ZERO ');
      inc(FSubState);
    end;

    11: begin
      if (FStateTime < 18*60*1000) and (not DevStatesOK) then
        exit;
      SetSequencerState(aasReady);
    end;

{  - start reactor temp.
  - start column temp.
  - if column temp. > 45 (see below) start P1
  - if P1.Press > P1.Press_L start P2

  - wait max.20 min for OK, then Alarm
  - if OK earlier swith to Ready
}
  end;

end;

procedure TSequencer.DoTechStoppingFinishing;
begin
  case FSubState of
    0: begin

      AS_CALLPS.AsInteger := 1;

      DET_TEMP_OFF.AsInteger := 1;
      DET_OFF.AsInteger := 1;

      P1_AUXVALV.AsInteger := 1;
      P2_GRADDIR.AsInteger := 0;

      Log('AS_CALLPS DET-TEMP-OFF DET-OFF P1-AUXVALV=1 P2-GRADDIR=H2O');
      inc(FSubState);
    end;

    1: begin
      if FStateTime < 19*60*1000 then
        exit;

      AS_TEMP_OFF.AsInteger := 1;

      AS_OFF.AsInteger := 1;
      P1_STOP.AsInteger := 1;
      P2_STOP.AsInteger := 1;

      Log('AS-TEMP-OFF AS-OFF P1,P2-STOP');
      FSubState := 10;
    end;

    10: begin
      if FStateTime < 20*60*1000 then
        exit;

      IK_OFF.AsInteger := 1;

      Log('IK-OFF');
      inc(FSubState);
    end;

    11: begin
      if State = aasFinishing then
        SetSequencerState(aasFinished)
      else
        SetSequencerState(aasStandby);
    end;

  end;
end;

{v0.25}
{procedure TSequencer.DoTechStopRunning;
begin
  case FSubState
end;            }
{/v0.25}

procedure TSequencer.DoTechAborting;
begin
  case FSubState of
    0: begin

      {AS_CALLPS.AsInteger := 1;}

      DET_TEMP_OFF.AsInteger := 1;
      DET_OFF.AsInteger := 1;

      P1_AUXVALV.AsInteger := 1;
      P2_GRADDIR.AsInteger := 0;

      Log('DET-TEMP-OFF DET-OFF P1-AUXVALV=1 P2-GRADDIR=H2O');
      inc(FSubState);
    end;

    1: begin
      if FStateTime < 1*60*1000 then
        exit;

      AS_TEMP_OFF.AsInteger := 1;

      AS_OFF.AsInteger := 1;
      P1_STOP.AsInteger := 1;
      P2_STOP.AsInteger := 1;

      Log('AS-TEMP-OFF AS-OFF P1,P2-STOP');
      FSubState := 10;
    end;

    10: begin
      if FStateTime < 2*60*1000 then
        exit;

      IK_OFF.AsInteger := 1;

      Log('IK-OFF');
      inc(FSubState);
    end;

    11: begin
      SetSequencerState(aasAborted);
    end;

  end;
end;

procedure TSequencer.DoTechRunningStopRunning;
var
  pl: TAAPrgLine;
{  dr: TExpPoint;}
  timedif: integer;
{v0.25}

  procedure DoBuffer;
  var
     bnr: integer;
  begin
    {buffer}
    bnr := ord(pl.AAPL.BufferNr);
    if bnr <> 0 then begin
      P1_AUXVALV.AsInteger := bnr;
      Log('BUFFER=' + IntToStr(bnr));
    end;
    {/buffer} {ulvotype}
  end;

  procedure DoColumnTemp;
  var
    ot: extended;
    nt: extended;
  begin
    {column temp.}
    ot := StrToFloat(AS_TEMP1RQ.AsUsrString);
    nt := pl.AAPL.Temperature;
    if abs(ot - nt) > 1 then begin
      FColumnTempHistory.ChangedCounter := 5*60;
    end;
    AS_TEMP1.AsUsrString := FloatToStr(nt);
    Log('TEMP=' + IntToStr(round(nt)));
    {/column temp.}
  end;

  function DoInject: boolean;
  var vnr: integer;
  begin
    Result := true;
    {v0.38}
    if SimulationOn then begin
      {v0.38}
      if not FCurPrg.Equil then begin
        FASState := astPrepared;
        {AS_SAMPNUM.AsInteger := CurSample.ULSR.VialNr; already set in Load }
      end;
    end;
    {/v0.38}

    if (FASState <> astPrepared) {v0.24}{v0.38}{/v0.38 and (not SimulationOn) }{/v0.24} then
    begin
      { AS Not prepared: }
      if FCurPrg.Equil then begin
        Log('INJECT - Sample not prepared - Ignored (equilibrating)');
      end else begin
        Result := false;
        LogState('INJECT - AS NOT READY');
      end;
    end else begin
      { AS Prepared: }
      vnr := AS_SAMPNUM.AsInteger;
      if (CurSample.ULSR.VialNr = vnr) then begin
        { Prepared vial position is ok: }
        if (CurSample.ULSR.SampleState <> sasInLoop) then
        begin
          if FCurPrg.Equil then begin
            Log('INJECT - Ignored (equilibrating), VialNr:' + IntToStr(vnr));
          end else begin
            LogState('INJECT - Sample NOT LOADED!, VialNr:' + IntToStr(vnr));
          end;
        end else begin
          AS_Inject.AsInteger := 1;
          Log('INJECTED VialNr: ' + IntToStr(vnr));
          AcqStart;
          CurSample.ULSR.SampleState := sasRunning;{ulsrtype}
          CurSampleStateChanged;
        end;
      end else begin
        LogState('INJECTED - Dif.Cur.Sample VialNr(' +
          IntToStr(CurSample.ULSR.VialNr) + ') and Prepared VialNr(' + IntToStr(vnr));
        Result := false;
      end;

    end;

    if not Result then begin
      LogState('INJECT FAILED, ABORTING. Sample=' + CurSample.ULSR.FileName);
      {v0.36}{/v0.36
      CurSample.ULSR.SampleState := sasError;
      CurSampleStateChanged;}
      SetSequencerState(aasAborting);
    end;

  end;

  function DoLoad: boolean;
  var
    vnr: integer;
  begin
    Result := true;
    vnr := 0;

    if CurSample.ULSR.SampleState = sasWaiting then begin
      vnr := CurSample.ULSR.VialNr;
      CurSample.ULSR.SampleState := sasInLoop;
      Log('LOAD - loading current sample');
    end else if Sequence.NextSample <> nil then begin
      if CurSample.ULSR.PrgFileName <> Sequence.NextSample.ULSR.PrgFileName then begin
        Log('LOAD - ignored (next sample has dif.program)');
      end else begin
        vnr := Sequence.NextSample.ULSR.VialNr;
        Sequence.NextSample.ULSR.SampleState := sasInLoop;
        Sequence.NextSample.Obj.SetFlag(rfCantDelete, true);
        CurSampleStateChanged;
        Log('PRG LINE: LOAD - loading next sample');
      end;
    end else begin
      Log('LOAD - no more samples');
    end;

    if vnr <> 0 then begin

      if (FDetState <> dstOK) {v0.25} and (not SimulationOn){/v0.25} then begin
        {v0.29}
        LogState('Before LOAD - DETECTOR FAILURE(' + GetDetStateMsg +
          ') detected, STOPPING before ' + CurSample.ULSR.FileName);
        {/v0.29
        Log('before LOAD - DETECTOR FAILURE(' + GetDetStateMsg +
          ') detected, STOPPING before ' + CurSample.ULSR.FileName);}
        {v0.36}{/v0.36
        CurSample.ULSR.SampleState := sasError;}
        SetSequencerState(aasAborting);
        Result := false;

      end else  begin

        AS_PREPSAMP.AsInteger := vnr;
        Log('AS_PREPSAMP=' + IntToStr(vnr));

        if SimulationOn then begin
          AS_SAMPNUM.AsInteger := vnr;
        end;

      end;

    end;

  end;
{/v0.25}


begin
{  if FCurPrg = nil then
    exit;}
  {aaprgu}
  if FCurPrg.LineReady(pl, FStateStartTime) then begin

    if FCurPrg.Equil then
      LogHead := 'EQUIL:PRG_LINE: '
    else
      LogHead := 'PRG_LINE: ';

    try
      Log('START');

      DoBuffer;
      DoColumnTemp;

      {command}
      case pl.AAPL.Command of

        acInject: begin
          if not DoInject then
            exit;
        end;

        acZero: begin
          DET_ZERO.AsInteger := 1;
          Log('DET_ZERO');
        end;

        acH2O: begin
          P2_GRADDIR.AsInteger := 0;
          Log('P2_GRADDIR=H2O(0)');
        end;

        acNHD: begin
          P2_GRADDIR.AsInteger := 1;
          Log('P2_GRADDIR=NHD(1)');
        end;

        acAcqStop: begin
          if not FCurPrg.Equil then begin
            AcqStop;
            CurSample.ULSR.SampleState := sasCompleting;{ulsrtype}
            Log('ACQ STOP');
          end else begin
            {AcqEquilStop;}
            Log('ACQ STOP - ignored (equilibrating)');
          end;
        end;

        acStartEquil:;

        acLoad: begin
          if not DoLoad then
            exit;
        end;

      end;
      {/command}

    finally
      Log('END');
      LogHead := '';
      Log('');
      {v0.38}
      pl.AAPL.State := plsDone;
      {/v0.38}
    end;
  end;

  if not FCurPrg.Running then begin
    { CurPrg finished (no more lines): }
    {v0.25}
    if FCurPrg.Equil then begin
      AcqEquilStop
    end else begin
      AcqStop;{just to be sure the acq is stopped (if AcqStop command was not in program)}
    end;
    if State = aasStopRunning then begin
      Log('SEQUENCE STOPPED BY USER REQUEST DURING LAST SAMPLE RUN');
      SetSequencerState(aasReady);
    end else
    {/v0.25}
    begin
      if FCurPrg.Equil then begin
        { was equilibrating: }{v0.38}CurPrg := FCurPrg;{/v0.38}{ reselect/reactivate the same prg }
        FCurPrg.Start;
        StateStart(aasRunning, 0);
        Log('PRG ' + FCurPrg.FileName + ' STARTED (AFTER EQUIL) Sample ' +
          IntToStr(CurSample.ULSR.VialNr) + ' ' + CurSample.ULSR.FileName);
      end else begin
        {CurSample finihed}
        CurSample.ULSR.SampleState := sasDone;
        Log('SAMPLE DONE: Sample='+ IntToStr(CurSample.ULSR.VialNr));

        if Sequence.Next then begin

          {v0.25}
          DoCurSampleSelected;
          {/v0.25
          CurSample.Prg.LoadFromFile(AbsoluteFileName(AO.PrgsDir, CurSample.ULSR.PrgFileName));}
          Log('SAMPLE NEXT: Sample='+ IntToStr(CurSample.ULSR.VialNr) + ' PRG LOADED=' + CurSample.ULSR.PrgFileName);
          {v0.38}CurPrg{/v0.38 FCurPrg} := CurSample.Prg;
          {aaprgu}

          if Sequence.LastSample.ULSR.PrgFileName <> Sequence.CurSample.ULSR.PrgFilename then
          begin
            FCurPrg.StartEquil(timedif);
            {v0.25}
            AcqEquilStart;
            {/v0.25}
            StateStart(aasRunning, timedif);
            Log('PRG ' + FCurPrg.FileName + ' EQUIL STARTED');
          end else begin
            FCurPrg.Start;
            StateStart(aasRunning, 0);
            Log('PRG ' + FCurPrg.FileName + ' STARTED');
          end;

        end else begin

          {v0.38}
          CurPrg := nil;
          {/v0.38}

          SetSequencerState(aasFinishing);

        end;

      end;
    end;

  end else begin
    { CurPrg is runnning }
    if FAcqInfo <> nil then begin
      AcqDoTimer; {acqinfou}
    end;

  end;

end;

function GetDebugAbsorbance(ADataIndex: integer; ATimeSec: single): single;
const
  MaxTime = 20 * 60;{20 min}
  PeakTime = 1 * 60;
  PeakHeight = 1;
  PeakCount = 10;
{var
  n: integer;}
begin
  result := (sin((ATimeSec/PeakTime) * 2 * pi) + 1) * PeakHeight * ((1 + ADataIndex)/2);
{  Result := (ATimeSec - (n * PeakTime) / PeakTime) * PeakHeight;}
end;

procedure TSequencer.AcqDoTimer;
var
  dr: TExpPoint;
  y: single;
begin
  if FAcqInfo = nil then
    exit;
  if FAcqDebugStartTime <> 0 then begin
    dr.X := (mstime - FAcqDebugStartTime) / 1000;
  end else begin
    dr.X := (FCurPrg.Time {v0.25}+ FCurPrg.EquilOffset{/v0.25})/ 1000;{ aaprgu }
  end;
  if dr.X >= 0 then begin
    FAcqInfo.PointsAddStart;

    if SimulationOn then begin
      dr.Y := GetDebugAbsorbance(0, dr.X);
      FAcqInfo.PointsAddAdd(0, dr);
      dr.Y := GetDebugAbsorbance(1, dr.X);
      FAcqInfo.PointsAddAdd(1, dr);
    end else begin
      dr.Y := FDET_CHB.AsFloat;
      FAcqInfo.PointsAddAdd(0, dr);
      {v0.25}
      y := dr.Y;
      {/v0.25}{ulsqtype}
      dr.Y := FDET_CHA.AsFloat;
      FAcqInfo.PointsAddAdd(1, dr);
      {v0.25}
      if DebLogAcq then begin
        DebLog(IntToString(mstime, 10) + ' Sequencer.AcqDoTimer: Time=' + FloatToStrF(dr.x, ffFixed, 6, 2) +
          ' G=' + FloatToStrF(y, ffFixed, 6, 4) + ' B=' + FloatToStrF(y, ffFixed, 6, 4));
      end;
      FCHAProp.RequestRead;{SetState(psReadRequested, true);}
      FCHBProp.RequestRead;{SetState(psReadRequested, true);}
      {FCHAProp.SetFlag(pfNeedUpdateFromDevice, true);
      FCHBProp.SetFlag(pfNeedUpdateFromDevice, true);}
      {/v0.25}
    end;

    FAcqInfo.PointsAddStop;
  end;
  {specform}
end;

{procedure TSequencer.SetDevProp(ULDR: TULDRObj; ULDP: TULDPObj; AValue: single; const msg: string);
  SetDevProp(P1, P1_FLOW, 1, 'protoze chci');}

procedure TSequencer.DoTechControl;
var
{  v: TTechValue;}
  ok: boolean;
  chn: boolean;

  procedure CheckHardwareRanges;
  var ok:boolean;
  begin
    ok := true;
    if not FColumnTempHistory.CheckHardLimits(0, 900, FcColState) then
      ok := false;

    if not FReactTempHistory.CheckHardLimits(0, 1500, FcReactState) then
      ok := false;

    if (AO.SequencerState >= aasReady) then begin
      if not FP1PressHistory.CheckHardLimits(AO.P1_PRESS_L, AO.P1_PRESS_H, FcP1State) then
        ok := false;
      if not FP2PressHistory.CheckHardLimits(AO.P2_PRESS_L, AO.P2_PRESS_H, FcP2State) then
        ok := false;
    end else begin
      if not FP1PressHistory.CheckHardLimits(0, AO.P1_PRESS_H, FcP1State) then
        ok := false;
      if not FP2PressHistory.CheckHardLimits(0, AO.P2_PRESS_H, FcP2State) then
        ok := false;
    end;

    if (DevStatToInt(P1_STATUS.AsInteger) < 0) then begin
      FcP1State := dstDeviceError;
      ok := false;
    end;

    if (DevStatToInt(P2_STATUS.AsInteger) < 0)  then begin
      FcP2State := dstDeviceError;
      ok := false;
    end;


    if not ok then begin
      if not FatalActive then begin
        if not ShouldIgnoreError then begin
          {v0.25}
          if not SimulationOn then
          {/v0.25}
          begin
            {v0.29}
            LogState('FATAL - OOR');
            {/v0.29
            Log('FATAL - OOR');}
          end;
        end;
        FatalActivate;
      end;
    end;

  end;

  procedure CheckDevicesPresence;
  var
    ok: boolean;
    dst: TDevState;
  begin
    ok := true;
    if DIK.DetectState <> dsPresent then begin
      FcIKState := dstCommunicationError;
      ok := false;
    end else begin
      dst := DevStatToInt(IK_STATUS.AsInteger);
      if dst < 0 then
        FcIKState := dstDeviceError
      else if dst = 0 then
        FcIKState := dstOK;{dstOff;{moduutl}
    end;

    if DAS.DetectState <> dsPresent then begin
      FcASState := astCommunicationError;
      FcColState := dstCommunicationError;
      ok := false;
    end else begin
      FcASState := AS_STATUS_Decode(AS_STATUS.AsInteger);
      dst := DevStatToInt(AS_TEMP_ST.AsInteger);
      if dst < 0 then
        FcColState := dstDeviceError
      else if dst = 0 then
        FcColState := dstOff;
    end;

    if DP1.DetectState <> dsPresent then begin
      FcP1State := dstCommunicationError;
      ok := false;
    end else begin
      dst := DevStatToInt(P1_STATUS.AsInteger);
      if dst < 0 then
        FcP1State := dstDeviceError
      else if dst = 0 then
        FcP1State := dstOff;
    end;

    if DP2.DetectState <> dsPresent then begin
      FcP2State := dstCommunicationError;
      ok := false;
    end else begin
      dst := DevStatToInt(P2_STATUS.AsInteger);
      if dst < 0 then
        FcP2State := dstDeviceError
      else if dst = 0 then
        FcP2State := dstOff;
    end;

    if DDET.DetectState <> dsPresent then begin
      FcDetState := dstCommunicationError;
      FcReactState := dstCommunicationError;
      ok := false;
    end else begin
      dst := DevStatToInt(DET_STATUS.AsInteger);
      if dst < 0 then
        FcDetState := dstDeviceError
      else if dst = 0 then
        FcDetState := dstOff;

      dst := DevStatToInt(DET_TEMP_ST.AsInteger);
      if dst < 0 then
        FcReactState := dstDeviceError
      else if dst = 0 then
        FcReactState := dstOff;

    end;

    if not OK then begin
      if not FatalActive then begin
        if not ShouldIgnoreError then begin
          if not SimulationOn then begin
            {v0.29}
            LogState('FATAL - Communication Error');
            {/v0.29
            Log('FATAL - Communication Error');}
          end;
        end;
        FatalActivate;
      end;
    end;
  end;

  procedure CheckReady;
  begin
    if not DevStatesOK then begin
      if not ShouldIgnoreError then begin
        if (State <> aasStarting) and (State <> aasStopping) and (State <> aasFinishing) then
          AlarmActivate;
      end;
      {case State of
        aasStarting: begin
          SetSequencerState(aasReady);
        end;
      end;}
    end else begin
      if AlarmActive then
        AlarmDeactivate;
    end;
  end;

  procedure AcqDebugDoTimer;
  begin
    if FAcqDebugStartTime = 0 then
      exit;
    AcqDoTimer;
  end;

begin
  {v0.24}
  AcqDebugDoTimer;
  {/v0.24}
  AO.DoChangeLock; { prevent sending cmULObjUpdate messages during this method }
  try
    if AO.SequencerState <= aasOff then begin
      {switch off alarms...}
      FStateTime := 0;
      FUsrStateTimeOffset := 0;
      exit;
    end;

    {v0.25}
    IK_WDG.AsInteger := 1;
    {/v0.25}
    {update state time}
    FStateTime := mstime - FStateStartTime;{Sequencertype}
    AO.DoChange;
    {/update state time}

    case AO.SequencerState of
      aasStarting: begin
        DoTechStarting;
        if FSubState < 10 then
          exit;
      end;

      aasRunning, aasStopRunning: begin
        DoTechRunningStopRunning;
      end;

      aasFinishing, aasStopping: begin
        DoTechStoppingFinishing;
        if FSubState >= 10 then
          exit;
      end;

      aasAborting: begin
        DoTechAborting;
        if FSubState >= 10 then
          exit;
      end;

    end;

    {v0.36}
    if AO.SequencerState <= aasOff then begin
      FStateTime := 0;
      FUsrStateTimeOffset := 0;
      exit;
    end;
    {/v0.36}

    {clear FcXXState}
    FcP1State := dstOK;
    FcP2State := dstOK;
    FcDetState := dstOK;
    FcColState := dstOK;
    FcReactState := dstOK;
    FcIKState := dstOK;

    FcASState := astOK;
    {/clear FcXXState}

    FP1PressHistory.PutVal(P1_PRESS.AsFloat);
    FP2PressHistory.PutVal(P2_PRESS.AsFloat);
    FColumnTempHistory.PutVal(AS_TEMP1.AsFloat);
    FReactTempHistory.PutVal(DET_TEMP1.AsFloat);

    FP1PressHistory.CheckDeviation(1, AO.P1PressDev, FcP1State);
    FP1PressHistory.CheckLimits(AO.P1_PRESS_L, AO.P1_PRESS_H, FcP1State);

    FP2PressHistory.CheckDeviation(1, AO.P2PressDev, FcP2State);
    FP2PressHistory.CheckLimits(AO.P2_PRESS_L, AO.P2_PRESS_H, FcP2State);

    FColumnTempHistory.CheckDeviation(10, AO.AsTempDev, FcColState);
    FColumnTempHistory.CheckLimits(AsTempMin, AsTempMax, FcColState);

    FReactTempHistory.CheckDeviation(10, AO.DetTempDev, FcReactState);
    FReactTempHistory.CheckLimits(DetTempMin, DetTempMax, FcReactState);

    ok := true;

    if AO.SequencerState >= aasReady then begin

      if not FP1PressHistory.IsOK(chn) then begin
        if chn then begin
          Log('P1 Deviation Too High');
        end;
        ok := false;
      end;

      if not ok then begin
        AlarmActivate;
      end else begin

      end;

    end;

    CheckHardwareRanges;

    CheckDevicesPresence;

    {
    if (FColumnTempHistory.Avg > 90) or (FReactTempHistory.Avg > 150) or
       (FP1PressHistory.Avg > AO.P1_PRESS_H) or
       (FP2PressHistory.Avg > AO.P2_PRESS_H) or
       (DevStatToInt(P1_STATUS.AsInteger) < 0) or
       (DevStatToInt(P2_STATUS.AsInteger) < 0) or
       ( (AO.SequencerState >= aasReady) and ( FP1PressHistory.Avg < AO.P1_PRESS_L ) ) or
       ( (AO.SequencerState >= aasReady) and ( FP2PressHistory.Avg < AO.P2_PRESS_L ) ) then
    begin
      Log('FATAL - OOR');
      FatalActivate;
    end;
    }

    if (FP1PressHistory.Avg < AO.P1_PRESS_L) or (DevStatToInt(P1_STATUS.AsInteger) <= 0)then
    begin
      if DevStatToInt(P2_STATUS.AsInteger) > 0 then begin
        {PumpCheckState(2, false);}
        P2_STOP.AsInteger := 1;
        {v0.29}
        LogState('P2_STOP, reason: P1 OOR or ERROR');
        {/v0.29
        Log('P2_STOP, reason: P1 OOR or ERROR');
        LogState;}
      end;
    end else begin
      if P2_STATUS.AsInteger = 0 then begin
        P2_START.AsInteger := 1;
        {v0.25}
        if not SimulationOn then
        {/v0.25}
          Log('P2_START');
      end;
    end;

    if FColumnTempHistory.Avg < 40*10 then begin
      if DevStatToInt(P1_STATUS.AsInteger) > 0 then begin
        P1_STOP.AsInteger := 1; {ulobju}
        P2_STOP.AsInteger := 1;
        {v0.29}
        LogState('P1,P2_STOP, reason: Column Temp.');
        {/v0.29
        Log('P1,P2_STOP, reason: Column Temp.');
        LogState;}
      end;
    end else begin
      if P1_STATUS.AsInteger = 0 then begin
        P1_START.AsInteger := 1;
        {v0.25}
        if not SimulationOn then
        {/v0.25}
          Log('P1_START');
      end;
    end;

  finally
    {update dev state properties}
    FcDevStatesOK := true;
      { following state setting commands will set this false, if any state <> OK }
    IKState := FcIKState;

    P1State := FcP1State;
    P2State := FcP2State;
    DetState := FcDetState;
    ColState := FcColState;
    ReactState := FcReactState;
    DetState := FcDetState;

    ASState := FcASState;
    {/update dev state properties}
        { assigning to these properties (will) send update message to AO users
          (especially TULObjCtrl), necessary if they use Sequencer object properties
          (i.e. Sequencer is AO usr) }
    if SimulationOn then begin
      FcDevStatesOK := true;
    end;
    DevStatesOK := FcDevStatesOK;


    CheckReady;
      { check the DevStatesOK and behave accordingly }
    AO.DoChangeUnlock;
  end;
end;

{v0.25}
function TSequencer.CheckSequenceFilesPresence: boolean;
var
  i : integer;
  s: string;
  ss: TSeqSample;
  fn: string;
{  cnt: integer;}
begin
  Result := true;
  s := '';
  for i := 0 to Sequence.ChildCount - 1 do begin
    ss := TSeqSample(Sequence.Childs[i]);
    if ss.Obj.RecID = ULSRID then begin
      fn := AbsoluteFileName(AO.PrgsDir, ss.ULSR.PrgFileName
        {v0.36}, AAPGExt{/v0.36});
      if not FileExists(fn) then
        s := s + ' ' + fn;
      fn := AbsoluteFileName(AO.MethodsDir, ss.ULSR.MethodFileName
        {v0.36}, ULMExt{/v0.36});
      if not FileExists(fn) then
        s := s + ' ' + fn;
    end;
  end;
  if s <> '' then begin
    ShowMessage(GetTxt({#}'Program or Method Files Missing:') + ' ' + s, smError, 0);
    Result := false;
  end;
end;
{/v0.25}
function TSequencer.UsrSetSequencerState(SequencerAState: TSequencerState): TSequencerResult;
begin
{  case SequencerAState of
    aasDisconnected,
    aasAborted,
    aasFinished,
    aasStandby,
    aasOff,
    aasStarting,
    aasStopping,
    aasAborting,
    aasReady,
    aasRunning
  end;}
  {v0.25}
  if SequencerAState = aasRunning then begin
    if not CheckSequenceFilesPresence then begin
      Result := arFilesMissing;
      exit;
    end;
  end;

  Result := SetSequencerState(SequencerAState);
end;

procedure TSequencer.ClearParams;
var i: integer;
begin
  for i := 0 to FHistCount - 1 do
    FHists[i].Clear;
  FcIKState := dstUnknownState;

  FcP1State := dstUnknownState;
  FcP2State := dstUnknownState;
  FcDetState := dstUnknownState;
  FcColState := dstUnknownState;
  FcReactState := dstUnknownState;

  FcASState := astUnknownState;{moduutl}

  FcDevStatesOK := false;
end;

function TSequencer.FirstSampleRun: TSequencerResult;
var timedif:integer;
begin
  {!!! set to prg from sequence.cursample
  if FCurPrg = nil then begin
    result := -1;
    exit;
  end;}
  if Sequence.First then begin{sequenceu}
    {v0.25}
    DoCurSampleSelected;
    {/v0.25
    CurSample.Prg.LoadFromFile(AbsoluteFileName(AO.PrgsDir, CurSample.ULSR.PrgFileName));}
    Log('PRG FIRST LOADED ' + CurSample.ULSR.PrgFileName);
    {v0.38}CurPrg{/v0.38 FCurPrg}:= CurSample.Prg;
    {
    FSubState := 0;
    AO.SequencerState := aasRunning;
    FUsrStateTimeOffset := 0;
    FStateStartTime := mstime;
    FStateTime := 0;}

    if FCurPrg.StartEquil(timedif) then begin
      {v0.25}
      AcqEquilStart;
      {/v0.25}
      StateStart(aasRunning, timedif);
      Log('PRG ' + FCurPrg.FileName + ' EQUIL START');
      Result := 0;
    end else begin
      {v0.29}
      LogState('PRQ EQUIL START FAILED');
      {/v0.29
      Log('PRQ EQUIL START FAILED');}
      Result := arInvalidProgramNoEquil;
    end;
    {v0.25}
    CurSampleStateChanged;
    {/v0.25}
  end else begin
    {v0.38}
    CurPrg := nil;
    {/v0.38 FCurPrg}
    Result := arNoSamples;
    Log('RUN: NO SAMPLES IN SEQUENCE');
  end;
end;

procedure TSequencer.StateStart(aas: TSequencerState; AUsrTimeOffset: integer);
begin
  FSubState := 0;
  AO.SequencerState := aas;
  FUsrStateTimeOffset := AUsrTimeOffset;
  FStateStartTime := mstime;
  FStateTime := 0;
end;

function TSequencer.SetSequencerState(SequencerAState: TSequencerState): TSequencerResult;

  function DoStarting: TSequencerResult;
  begin
    Result := 0;
    ClearParams;
    StateStart(aasStarting, -18*60*1000);
  end;

  function DoStopping: TSequencerResult;
  begin
    Result := 0;
    StateStart(aasStopping, -20*60*1000);
  end;

  function DoFinishing:TSequencerResult;
  begin
    Result := 0;
    StateStart(aasFinishing, -20*60*1000);
  end;

  function DoReady: TSequencerResult;
  begin
    Result := 0;
    StateStart(aasReady, 0);
  end;

  function DoFinished: TSequencerResult;
  begin
    Result := 0;
    StateStart(aasFinished, 0);
  end;

  function DoStandby: TSequencerResult;
  begin
    Result := 0;
    StateStart(aasStandby, 0);
  end;

  function DoAborting: TSequencerResult;
  {v0.36}
  var cs: TSeqSample;
  {/v0.36}
  begin
    Result := 0;
    {v0.36}
    cs := CurSample;
    if cs <> nil then begin
      case cs.ULSR.SampleState of
        sasRunning, sasInLoop: begin
          cs.ULSR.SampleState := sasError;{ulsrtype}
        end;
        sasWaiting: begin
          if (FCurPrg <> nil) and (FCurPrg.Equil) then begin
            cs.ULSR.SampleState := sasError;{ulsrtype}
          end;
        end;
      end;
      Sequence.NoSample;
      CurSampleStateChanged;
    end;
    {/v0.36}
    {v0.38}
    CurPrg := nil;
    {/v0.38}
    StateStart(aasAborting, AbortingInterval);
    {v0.25}
    {AcqEquilStop;}
    AcqStop;
    {/v0.25}
  end;

  function DoAborted: TSequencerResult;
  begin
    Result := 0;
    StateStart(aasAborted, 0);
  end;

  function DoRunning: TSequencerResult;
  begin
    Result := FirstSampleRun;
    if Result <> 0 then
      exit;
    {
    FSubState := 0;
    AO.SequencerState := aasRunning;



    FUsrStateTimeOffset := 0;
    FStateStartTime := mstime;
    FStateTime := 0;}
  end;

  {v0.25}
  function RequestStopRunning: TSequencerResult;
  begin
    Result := 0;
    case ShowMessage(GetTxt({#}'Stop after current sample completed? (No for ABORT)'), smYesNoCancel, 0) of
      cmYes: begin
        {StateStart(aasStopRunning, 0); .. do not reset time:}
        AO.SequencerState := aasStopRunning;
      end;
      cmNo: {v0.36}DoAborting{/v0.36 StateStart(aasAborting, AbortingInterval);}
    end;
  end;
  {/v0.25}

begin
  Result := -1;
  case SequencerAState of

    aasStandby: begin

      case AO.SequencerState of

        aasStandby: begin
          Result := 0;
        end;

        aasDisconnected: begin
          AO.SequencerState := aasStandby;
          Result := 0;
        end;

        aasStopping: begin
          Result := DoStandby;
        end;

      else
        Result := arInvalidStateRequest;
      end;
    end;

    aasStarting: begin

      if (State <= aasOff) or (State = aasStopping) or (State = aasAborting) then begin
        Result := DoStarting;
      end else begin
        Result := arInvalidStateRequest;
      end;

    end;

    aasStopping: begin
      if State <= aasOff then begin
        Result := arInvalidStateRequest;
      end else begin
        Result := DoStopping;
      end;
    end;

    aasFinishing: begin
      if (State <> aasRunning) {v0.25} and (State <> aasStopRunning) {/v0.25} then begin
        Result := arInvalidStateRequest;
      end else begin
        Result := DoFinishing;
      end;
    end;

    aasDisconnected: begin
      case State of
        aasStopping, aasAborting: begin
          AO.SequencerState := aasDisconnected;
          Result := 0;
        end;
      else
        Result := arInvalidStateRequest;
      end;
    end;

    aasReady: begin
      if (State = aasStarting) {v0.25} or (State = aasStopRunning){/v0.25} then begin
        Result := DoReady;
      end else {v0.25} if State = aasRunning then begin
        Result := RequestStopRunning;
      end else {/v0.25} begin
        Result := arInvalidStateRequest;
      end;
    end;

    {v0.25}
    aasStopRunning: begin
      if State <> aasRunning then begin
        Result := arInvalidStateRequest;
      end else begin
        Result := RequestStopRunning;
      end;
    end;
    {/v0.25}

    aasRunning: begin
      if State = aasReady then begin
        Result := DoRunning;
      end else{v0.25} if State = aasStopRunning then begin
        AO.SequencerState := aasRunning;
      end else{/v0.25} begin
        Result := arInvalidStateRequest;
      end;
    end;

    aasFinished: begin
      if (State = aasFinishing) then begin
        Result := DoFinished;
      end else begin
        Result := arInvalidStateRequest;
      end;
    end;

    aasAborting: begin
      {if (State = aasAborting) then begin
        Result := DoAborted;
      end else begin
        Result := arInvalidStateRequest;
      end;}
      Result := DoAborting;
    end;

    aasAborted: begin
      if (State = aasAborting) then begin
        Result := DoAborted;
      end else begin
        Result := arInvalidStateRequest;
      end;
    end;

  end;{/case SequencerAState}         {proputl}
  Log('SetSequencerState=' + IntToStr(integer(SequencerAState)) + ' Result:' + IntToStr(Result));
end;

function TSequencer.GetSequencerState: TSequencerState;
begin
  Result := AO.SequencerState;
end;

function TSequencer.GetP1StateMsg: string;
begin
  Result := DevStateToString(FP1State);
end;

function TSequencer.GetP2StateMsg: string;
begin
  Result := DevStateToString(FP2State);
end;

function TSequencer.GetDetStateMsg: string;
begin
  Result := DevStateToString(FDetState);
end;

function TSequencer.GetColStateMsg: string;
begin
  Result := DevStateToString(FColState);
end;

function TSequencer.GetReactStateMsg: string;
begin
  Result := DevStateToString(FReactState);
end;

function TSequencer.GetASStateMsg: string;
begin
  Result := ASStateToString(FASState);
end;

{set devices states}
procedure TSequencer.SetIKState(dst: TDevState);
begin
  if dst <> FIKState then begin
    FIKState := dst;
    AO.DoChange;
  end;
  if FIKState <> dstOK then
    FcDevStatesOK := false;
end;

procedure TSequencer.SetP1State(dst: TDevState);
begin
  if dst <> FP1State then begin
    FP1State := dst;
    AO.DoChange;
  end;
  if FP1State <> dstOK then
    FcDevStatesOK := false;
end;

procedure TSequencer.SetP2State(dst: TDevState);
begin
  if dst <> FP2State then begin
    FP2State := dst;
    AO.DoChange;
  end;
  if FP2State <> dstOK then
    FcDevStatesOK := false;
end;

procedure TSequencer.SetDetState(dst: TDevState);
begin
  if dst <> FDetState then begin
    FDetState := dst;
    AO.DoChange;
  end;
{v0.25}{/v0.25 if FDetState <> dstOK then
    FcDevStatesOK := false;}
end;

procedure TSequencer.SetColState(dst: TDevState);
begin
  if dst <> FColState then begin
    FColState := dst;
    AO.DoChange;
  end;
  if FColState <> dstOK then
    FcDevStatesOK := false;
end;

procedure TSequencer.SetReactState(dst: TDevState);
begin
  if dst <> FReactState then begin
    FReactState := dst;
    AO.DoChange;
  end;
  if FReactState <> dstOK then
    FcDevStatesOK := false;
end;


procedure TSequencer.SetASState(ast: TASState);
begin
  if ast <> FASState then begin
    FASState := ast;
    AO.DoChange;
  end;
  if FASState <> astOK then begin
    {DebLog('SetASState ' + IntToStr(ast));}
    if FASState >= astError then
      FcDevStatesOK := false;
  end;
end;
{/set devices states}

function TSequencer.GetUsrStateTimeStr: string;
  { time of current SequencerState in minutes }
begin
  Result := FloatToStrF((FStateTime + FUsrStateTimeOffset)/ 1000 / 60, ffFixed, 6, 2);
end;

procedure TSequencer.SetUsrStateTimeStr(const AValue: string);
var i: integer;
begin
  if UserMode <> umSysOp then
    exit;
  i := round(StrToFloat(AValue) * 60 * 1000) - FUsrStateTimeOffset;
  FStateStartTime := mstime - i;
end;

procedure TSequencer.UsrRequestOnOff;
begin
  if State <= aasOff then begin
    UsrSetSequencerState(aasStarting);
  end else begin
    if (State = aasRunning){v0.25} or (State = aasStopRunning) {/v0.25} then begin
      ShowMessage(GetTxt({#}'Can not switch off. Stop the sequence first.'), smError, 0);
    end else begin
      {v0.25}
      if (State = aasStopping) or (State = aasAborting) then begin
         UsrSetSequencerState(aasStarting);
      end else
      {/v0.25}
      begin
        if ShowMessage(GetTxt({#}'Really switch the Sequencer off?'), smNoYes, 0) <> cmYes then
          exit;
        UsrSetSequencerState(aasStopping);
      end;
    end;
  end;
end;

function TSequencer.ChildCreate(AChildObj: TULObj):TULObjUsr;
var id: TULRecID;
begin
  if AChildObj = nil then begin
    id := ULIID;
  end else begin
    id := AChildObj.RecID;
  end;

  case id of
    ULIID: begin
      if FDefInstrument = nil then begin
        FDefInstrument := TInstrument.Create(Self, AChildObj, id);
        if FDefInstrument.ULI.ChannelName = '' then begin
          FDefInstrument.ULI.ChannelName := pvUlanDefaultChannel;
        end;
        Result := FDefInstrument;
      end else
        Result := nil;
    end;
  else
    Result := nil;
  end;
end;

procedure TSequencer.UpdateDefDirs;{sequenceu ulobjdes}
begin
  Obj.FindField('PrgFileName').FldDesc.DefDir := AO.PrgsDir;
  Obj.FindField('MethodFileName').FldDesc.DefDir := AO.MethodsDir;
  Obj.FindField('SeqFileName').FldDesc.DefDir := AO.SeqsDir;

  DefMethod.Obj.ObjDesc.DefDir := AO.MethodsDir;{ulmtype}
  DefMethod.UpdateDefDirs; { methodu }

  DefPrg.Obj.ObjDesc.DefDir := AO.PrgsDir;{aapgtype}

  Sequence.Obj.ObjDesc.DefDir := AO.SeqsDir;{ulsqtype}
  Sequence.UpdateDefDirs;
end;

procedure TSequencer.DoAfterSettingsEdit;
begin
  if DefPrg.FileName <> GetPrgFullFileName then
    DefPrg.LoadFromFile(GetPrgFullFileName);
  if DefMethod.FileName <> GetMethodFullFileName then
    DefMethod.LoadFromFile(GetMethodFullFileName);
  if Sequence.FileName <> GetSeqFullFileName then begin
    Sequence.LoadFromFile(GetSeqFullFileName);
    SequenceUpdateDefaults(Sequence.ULSQ);
  end;
  UpdateDefDirs;
  if State <> aasRunning then
    CopySequencerToULD; {Sequencertype}
  {v0.36}
  Sequencer.Save;
  {/v0.36}
end;

procedure TSequencer.WMAppMessage(var Msg: TMessage);
var o: TULObj;
begin
  o := TULObj(Msg.lParam);
  if o = AO then begin
    case Msg.wParam of
      cmULObjAfterEdit: begin
        {DoAfterSettingsEdit;}
      end;
    end;
  end{v0.38} else begin
    if (FDefPrg <> nil) and (o = FDefPrg.Obj) then begin
      case Msg.WParam of
        cmULObjFileNameChanged: DefPrgNameChanged;
      end;
    end;
    if (FCurPrg <> nil) and (o = FCurPrg.Obj) then begin
      case Msg.WParam of
        cmULObjUpdated: begin
          if FCurPrg.Active then begin
          end;
        end;
      end;
    end;
  end{/v0.38};
end;

function TSequencer.GetDataRootDir: string;
begin
  { directory where .Sequencer config file located, used as default root
    directory for all other files or subdirectories } {ulsrtype ulatype}
  Result := AO.RootFileDir;
end;

procedure TSequencer.AcqDebugStart;
begin
  if not CheckCurSample then begin
    if not Sequence.First then
      exit;
    DoCurSampleSelected;
    {v0.38}CurPrg{/v0.38 FCurPrg} := CurSample.Prg;
  end;
  if AcqStart then
    FAcqDebugStartTime := mstime;
end;

procedure TSequencer.AcqDebugStop;
begin
  FAcqDebugStartTime := 0;
  AcqStop;
end;

{v0.25}
procedure TSequencer.AutoSaveAll;
begin
  Sequence.Save;
  DefPrg.Save;
  DefMethod.Save;{ulobjusru}
end;
{/v0.25}

procedure TSequencer.AcqShow;
begin
  if (FAcqInfo <> nil) and (FAcqData <> nil) then begin
    if FAcqInfo.SpecForm <> nil then
      FAcqInfo.SpecForm.BringToFront
    else
      SpectrumFormOpenForAcqData(FAcqData, FAcqInfo);
  end;
end;

{v0.25}
procedure TSequencer.AcqDataUpdateViewLimit;
begin
  {v0.26}
  if (CurSample <> nil) and (FAcqData <> nil) then
    FAcqData.ULVL.MaxX := CurSample.Prg.TotalSecTime / 60;
  {/v0.26}
end;
{/v0.25}

function TSequencer.AcqEquilStart: boolean;
var
  pn: string;
begin
  Result := false;
  if FAcqInfo <> nil then begin
    Log('AcqEquilStart - acquisition is already running');
    exit;
  end;

  if CheckCurSample then begin {sequenceu}
    FAcqData := TAcqData.Create(SequencerTemplateFileName, omCreate);
    pn := ChangeFileExt(ExtractFileName(CurSample.ULSR.PrgFileName),'');
    pn := Sequence.DirName + pn + '_Equilibration.ULF';
    FAcqData.ChangeFileName(pn);
    {v0.25}
    AcqDataUpdateViewLimit;
    {/v0.25}

    FAcqInfo := TAcqInfo.Create(FAcqData);
    try
      SpectrumFormOpenForAcqData(FAcqData, FAcqInfo);
      FAcqInfo.Start;
      Log('AcqEquil Started ' + pn);
    except
      FAcqInfo.Free;
      FAcqInfo := nil;
      FAcqData.Free;
      FAcqData := nil;
    end;
    Result := true;
  end;
end;

procedure TSequencer.AcqEquilStop;
begin
  if FAcqInfo <> nil then begin
    Log('AcqEquil Stopping..');
    AcqStop;
  end;
end;

function TSequencer.AcqStart: boolean;
begin
  {acqinfou}
  Result := false;
  if FAcqInfo <> nil then begin
    Log('AcqStart - acquisition is already running');
    exit;
  end;

  if CheckCurSample then begin {sequenceu}
    FAcqData := TAcqData.Create(SequencerTemplateFileName, omCreate);
    FAcqData.ChangeFileName(Sequence.DirName + CurSample.ULSR.FileName);
    {v0.25}
    if CurSample.ULSR.SampleName = '' then
      CurSample.ULSR.SampleName := CurSample.ULSR.FileName;{ulsrtype}

    FAcqData.ULA.AssignClass(CurSample.ULSR);
      { copy just header (class published fields, not childs) }

    FAcqData.ULM.Assign(CurSample.Method.ULM);
    FAcqData.CheckULMRecords;

    FAcqData.ULM.MethodTemplate := CurSample.ULSR.MethodFileName;
      {ulsrtype ulitype ulmtype aapgtype}
    {FAcqData.ULI.InstrumentTemplate := CurSample.ULSR.}

    AcqDataUpdateViewLimit;

    {FAcqData.ULI.Assign(FDefInstrument.ULI);}
    {/v0.25}

    FAcqInfo := TAcqInfo.Create(FAcqData);
    {specform}
    SpectrumFormOpenForAcqData(FAcqData, FAcqInfo);

    FAcqInfo.Start;
    Result := true;

  end;
end;

procedure TSequencer.AcqStop; { ulsrtype }
var
  ai: TAcqInfo;
  ad: TAcqData;
begin
  ai := FAcqInfo;
  FAcqInfo := nil;{disables timer calls}
  ad := FAcqData;
  FAcqData := nil;

  if ai <> nil then begin
    {v0.28}
    if ad <> nil then
      ad.ULA.AutodetectLater := true;
    {/v0.28}
    ai.Stop;
    ai.Free;
    Log('AcqStopped');
  end;

  if ad <> nil then begin {acqinfou}
    ad.Free;
  end;

  {v0.25}
  AutoSaveAll;
  {/v0.25}
end;

function TSequencer.GetCurSample: TSeqSample;
begin
  Result := Sequence.CurSample;
end;

{v0.25}
function TSequencer.GetCurPrgName: string;{ for status wnd }
var s: TSeqSample;
begin
  Result := '';
  s := CurSample;
  if s <> nil then begin
    {v0.36}
    Result := ChangeFileExt(ExtractFileName(CurSample.ULSR.PrgFileName), '');
    {Result := CurSample.ULSR.FindField('PrgFileName').AsUsrString;}
    {/v0.36
    Result := ChangeFileExt(CurSample.ULSR.PrgFileName, '');}
  end;
end;

function TSequencer.GetCurSampleName: string;{ for status wnd }
var
  s: TSeqSample;
begin
  Result := '';
  s := CurSample;
  if s <> nil then begin
    {v0.36}
    Result := ChangeFileExt(ExtractFileName(CurSample.ULSR.FileName), '');
    {Result := CurSample.ULSR.FindField('FileName').AsUsrString;}
    {/v0.36
    Result := CurSample.ULSR.FileName;}
  end;
end;

function TSequencer.GetCurSampleStateName: string; { ulsrtype }
var
  s: TSeqSample;
  n: string;
  i: integer;
begin
  Result := '';
  s := CurSample;
  if s <> nil then begin
    n := CurSample.Obj.FindField('SampleState').AsUsrString;
    i := pos('sas',n);
    if i = 1 then
      n := copy(n, 4, length(n));
    Result := n;
  end;
end;

procedure TSequencer.CurSampleStateChanged;
begin
  AO.DoChange;
end;

{/v0.25}



function TSequencer.CheckCurSample: boolean;
begin
  if CurSample = nil then begin
    Log('CurSample=nil');
    Result := false;
  end else begin
    Result := true;
  end;
end;

procedure TSequencer.CheckDefTemplate;
var
  d: TAcqData;
  ad: TULADObj;
  cnt, i: integer;
  o: TULObj;
  ul: TUserViewLimit;
begin
  if FSequencerTemplateFileName = '' then begin
    FSequencerTemplateFileName := AO.SeqsDir + 'SequencerTemplate' + ULTExt;
    d := TAcqData.Create(FSequencerTemplateFileName, omCreateTemplate);
    try
      d.ULI.Assign(DefInstrument.ULI);
      cnt := 0;
      i := 0;
      while i < d.ULA.ChildCount do begin
        o := d.ULA.Childs[i];
        inc(i);
        if o is TULADObj then begin
          inc(cnt);
          if cnt = 1 then begin
            TULADObj(o).Color := clGreen;
          end else if cnt = 2 then begin
            TULADObj(o).Color := clBlue;
            TULADObj(o).DataName := 'B';
          end else begin
            o.Free;
            dec(i);
          end;
        end;
      end;

      if cnt = 0 then begin
        ad := TULADObj(d.ULA.Add(ULADID));
        inc(cnt);
      end;

      if cnt = 1 then begin
        ad := TULADObj(d.ULA.Add(ULADID));
        ad.DataName := 'B';
        ad.Color := clBlue;
      end;
      d.ULAD.Update;
      ul := NewUserViewLimit;
      d.ULVL.MinX := ul.Min.X;
      d.ULVL.MinY := ul.Min.Y;
      d.ULVL.MaxX := 120;
      d.ULVL.MaxY := ul.Max.Y;
    finally
      d.ULF.SaveToFile('');
      d.ULF.SaveToFile(ChangeFileExt(d.ULF.FileName, ASCExt));
      d.Free;
    end;
  end;
end;

procedure TSequencer.DoCurSampleSelected;
begin
{  CurSample.Prg.LoadFromFile(AbsoluteFileName(AO.PrgsDir, CurSample.ULSR.PrgFileName
    , AAPGExt));}
  CurSample.Method.LoadFromFile(AbsoluteFileName(AO.MethodsDir, CurSample.ULSR.MethodFileName
    , ULMExt));
end;

{
procedure TSequencer.SetCurPrg(APrg: TAAPrg);
begin
  if FCurPrg <> nil then begin
    FCurPrg.Active := false;
  end;

  if (FBrowsingCurPrg <> nil) then begin
    if (FBrowsingCurPrg = FCurPrg) then begin
      FCurPrg.Obj.UsersNotify(cmULObjCloseViews);
    end else begin
      FBrowsingCurPrg := nil;
    end;
  end;

  FCurPrg := APrg;

  if FCurPrg <> nil then begin
    FCurPrg.Active := true;
  end;

  if FBrowsingCurPrg <> nil then begin
    // was watching the current prog, open the view again if running:
    if FCurPrg <> nil then
      ShowRunningPrg
    else
      FBrowsingCurPrg := nil;
  end;
end;

procedure TSequencer.SetDefPrg(APrg: TAAPrg);
begin
  if FDefPrg <> nil then begin
    FDefPrg.Obj.UserUnregister(Self);
    if APrg = nil then
      FDefPrg.Free;
  end;
  FDefPrg := APrg;
  if FDefPrg <> nil then begin
    FDefPrg.Obj.UserRegister(Self);
  end;
end; }

procedure TSequencer.SetLogActive(OnOff: boolean);
begin
  if FLogActive <> OnOff then
    exit;
  if FLogActive then begin
    Log('Sequencer Destroyed.');{ulantype}
  end;
  FLogActive := OnOff;
  if FLogActive then begin
    Log('Sequencer Created. Chromulan version ' + uLanVersion);{ulantype}
  end;
end;
{/TSequencer}

procedure SequencerFree;
begin
  FSequencer.Free;
  FSequencer := nil;
end;

initialization
  RegisterClass(TSequencer);
finalization
end.
