unit KYasPar;
{
   Parameters for Yaskawa inverter

   Author:  Vesa Lappalainen
   Date:    31.12.1996
   Changes: 05.04.1997
              + reset ottaa kaikki RunParametrin biti pois päältä aluksi
              (jos run-päällä tai Ext.error, ei muuten resetoi).
   Changes: 23.07.2001
     + modbusslave not a pointer any more (no use)
   Changes: 06.10.2001
     + StoreRamRegister + EEPROM
   Changes: 26.12.2003
     + SendRunParams ja RefreshRunParams käsittely ei peräkkäisille rekistereille.
   Changes: 31.01.2004
     +


  One example hierarcy
  =====================
                  0-n
     TParamValue -----<> TParamList                                  IniPara.pas
          |                  ^
          |           1      |                                      ------------
          |         |----TKParamList
          |         |
          ^         |    TComponent
          |         |        ^
          |         ---<>TParams                                     KParams.pas
          |                  ^                                      ------------
          |                  |
     YasParamValue       TYasParams                                  KYasPar.pas
           *
           |
TModBus ---
}

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  IniPara,KModbus,kparams;

const NotInUseSlave = -33;

type
  TYasParamValue = class(TParamValue)
  private
    ModBusSlave:TModBusSlave;
    StoreRamRegister : integer;
    StoreEEPROMRegister : integer;
    StoreEEPROMSequence : string;

  protected
  public
    function WriteFunction(d: double;noread:boolean): string; override;
    function ReadFunction: string; override;
    procedure StoreEEPROM; override;
    procedure StoreRAM; override;
  published
  end;

type
  TYasParams = class(TParams)
  private
    FYasForm : TForm;
    FModbusSlave:TModBusSlave;
    thz : Double;  // Temp for demos, where no modbus active

    FDirection : integer;
    FRun       : boolean;

    RunParam,
    ReverseParam,
    DirectionParam,
    ResetParam,
    HzParam : TParamValue;

    FNameRun,
    FNameReverse,
    FNameDirection,
    FNameReset,
    FNameHz,
    FNameMaxHz, //   = 'n012';
    FNameMinHz, //   = 'n017';
    FNameAccTime, // = 'n019';
    FNameDecTime, // = 'n020';
    FNameInvStatus : string; // = 'r044';
    FcInvFault : integer;
    FNameOutRead: string;
    FNameInRead: string;
    FNameOutWrite: string;
    FNameReadV: string;
    FNameFreqRef: string;
    FNameMaxV: string;
    FNameReadHz: string;
    FNameInWrite: string;
    FNameReadA: string;
    FNameMaxA: string;
    FcResetBitValue: integer;
    FcInCount: integer;
    FcInWriteStart: integer;
    FcOutReadShift: integer;
    FcOutCount: integer;
    FcOutWriteShift: integer;
    FcInReadShift: integer;
    FcInWriteShift: integer;
    FInputNames: string;
    FOutputNames: string;
    FcStoreRamRegister: integer;
    FcStoreEEPROMRegister: integer;
    FStoreEEPROMSequence : string;
    FResetSequence : string;
    FcForwardRun: integer;
    FcReverseRun: integer; // = $4000;
    FcRunBit : integer;
    FcDirectionBit : integer;
    FcRunMask : integer;
    FcDirectionMask : integer;
    FcRunMaskOr : integer;
    FcDirectionMaskOr : integer;
    function GetEnabled: boolean;
    procedure SetEnabled(const Value: boolean);
    function ReadNames: boolean;

  protected
    procedure SetDirection(d:integer); virtual;
    function GetDirection:integer; virtual;
    function FindParams:boolean; virtual;
    procedure RefreshRunParams; virtual;
    procedure SendRunParams; virtual;

    function GetSlave:integer;  virtual;
    procedure SetSlave(s:integer); virtual;
    function GetModbus : TModbus;
    procedure SetModbus(mb:TModbus);

    procedure DoSequence(var Sequence:string);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    function CreateList: string; override;
    procedure WriteHz(hz:double); virtual;
    procedure WriteRunHz(hz:double); virtual;
    function ReadHz:double; virtual;
    function ReadMaxHz:double; virtual;
    function ReadMinHz:double; virtual;
    function WriteReadHz(hz:double):double; virtual;
    function AccAHz:double; virtual;
    function DecAHz:double; virtual;
    function InvOK : boolean; virtual;
    procedure Stop; virtual;
    function Reset : boolean; virtual;
    function NewParam(const name:string):TParamValue; override;
    procedure DoShowControl(modal:boolean);
    procedure ShowControl; virtual;
    procedure ShowControlModal; virtual;
    procedure ShowErrors; virtual;
    function GetLastError:string; virtual;
    procedure StoreEEPROM; override;
    procedure StoreRAM; override;
  published
    property ModbusSlave:TModBusSlave read FModbusSlave;
    property Modbus:TModBus read GetModBus write SetModbus;
    property Direction:integer read GetDirection write SetDirection;
    property Slave : integer read GetSlave write SetSlave;
    property Enabled : boolean read GetEnabled write SetEnabled;
//    property LastError : string; read GetLastError;
    property NameRun:string read FNameRun;
    property NameReverse:string read FNameReverse;
    property NameReset:string read FNameReset;
    property NameDirection:string read FNameDirection;
    property NameHz:string read FNameHz;
    property NameMaxHz:string read FNameMaxHz;
    property NameMinHz:string read FNameMinHz;
    property NameAccTime:string read FNameAccTime;
    property NameDecTime:string read FNameDecTime;
    property NameInvStatus:string read FNameInvStatus;
    property NameInRead:string read FNameInRead;
    property NameOutRead:string read FNameOutRead;
    property NameOutWrite:string read FNameOutWrite;
    property NameInWrite:string read FNameInWrite;
    property NameReadHz:string read FNameReadHz;
    property NameMaxA:string read FNameMaxA;
    property NameReadA:string read FNameReadA;
    property NameMaxV:string read FNameMaxV;
    property NameReadV:string read FNameReadV;
    property NameFreqRef:string read FNameFreqRef;
    property cInvFault:integer read FcInvFault;
    property ResetBitValue:integer read FcResetBitValue;
    property InCount:integer read FcInCount;
    property OutCount:integer read FcOutCount;
    property InReadShift:integer read FcInReadShift;
    property InWriteShift:integer read FcInWriteShift;
    property InWriteStart:integer read FcInWriteStart;
    property OutReadShift:integer read FcOutReadShift;
    property OutWriteShift:integer read FcOutWriteShift;
    property InputNames : string read FInputNames;
    property OutputNames : string read FOutputNames;
    property StoreRamRegister : integer read FcStoreRamRegister;
    property StoreEEPROMRegister : integer read FcStoreEEPROMRegister;
    property StoreEEPROMSequence : string read FStoreEEPROMSequence;
    property ResetSequence : string read FResetSequence;
    property cForwardRun : integer read FcForwardRun;
    property cReverseRun : integer read FcReverseRun;
    property cRunBit : integer read FcRunBit;
    property cDirectionBit : integer read FcDirectionBit;
    property cRunMask : integer read FcRunMask;
    property cDirectionMask : integer read FcDirectionMask;
    property cRunMaskOr : integer read FcRunMaskOr;
    property cDirectionMaskOr : integer read FcDirectionMaskOr;
  end;

procedure Register;

implementation

uses YasForm,inifiles,kErrors;
var
  ceYasParamDebug : TCommError;


procedure TYasParamValue.StoreEEPROM;
begin
  if ( StoreEEPROMRegister <> 0 ) then begin
    ModbusSlave.SetReg(StoreEEPROMRegister,0);
    ceYasParamDebug.Add('Yaskawa: Write to EEPROM - '+Name+'='+AsString);
  end;

end;

procedure TYasParamValue.StoreRAM;
begin
  if ( StoreRAMRegister <> 0 ) then ModbusSlave.SetReg(StoreRAMRegister,0);
end;


{------------------------------------------------------------------------------}
{ Write value to the fysical device if one exist and change value to d         }
{ if success                                                                   }
{ Return error message as text.                                                }
function TYasParamValue.WriteFunction(d: double;noread:boolean): string;
var i:integer; oldvalue : double; err:string;
begin
  oldvalue := value;
  value := d;
  Result := 'No slave';
  if ( not ModbusSlave.ok ) then exit;
  ModbusSlave.SetReg(Ind,AsInteger);
  Result := ModbusSlave.LastError;
  if ( noread ) then exit;
  if ( ModbusSlave.ReadReg(Ind,i) ) then begin
    AsInteger := i;
    StoreRam;
  end
  else begin
    err := ModbusSlave.LastError;
    value := oldvalue;
    if ( Result = '' ) and ( err <> '' ) then Result := err;
  end;  
end;

{------------------------------------------------------------------------------}
{ Read value from fysical device and change the value if success               }
{ Return error message as text.                                                }
function TYasParamValue.ReadFunction: string;
var i:integer;
begin
  Result := 'No slave';
  if ( not ModbusSlave.ok ) then exit;
  if ( ModbusSlave.ReadReg(Ind,i) ) then begin
    AsInteger := i;
    Result := '';
  end
  else
    Result := ModbusSlave.LastError;
end;

{------------------------------------------------------------------------------}
{ Overdriven virtual to create right params for this Params-list               }
function TYasParams.NewParam(const name:string):TParamValue;
var p : TYasParamValue;
begin
  p := TYasParamValue.Create;
  p.ModbusSlave := ModbusSlave;
  Result := p;
  if ( Name <> '' ) and ( UpperCase(Name[1]) <> 'R' ) then begin
    p.StoreRamRegister := FcStoreRamRegister;
    p.StoreEEPROMRegister := FcStoreEEPROMRegister;
    p.StoreEEPROMSequence := FStoreEEPROMSequence;
  end;
end;

{------------------------------------------------------------------------------}
{ TYasParam -------------------------------------------------------------------}
{------------------------------------------------------------------------------}

{------------------------------------------------------------------------------}
function TYasParams.GetModbus : TModbus;
begin
  Result := ModbusSlave.Modbus;
end;

{------------------------------------------------------------------------------}
procedure TYasParams.SetModbus(mb:TModbus);
begin
  ModbusSlave.Modbus := mb;
end;

{------------------------------------------------------------------------------}
procedure TYasParams.SendRunParams;
var r,ihz,dir : integer;
begin
  if ( not ModbusSlave.ok ) then exit;
  if RunParam.Ind = ReverseParam.Ind then begin  // same run command for both direction
    r   := RunParam.AsInteger;
    ihz := abs(HzParam.AsInteger);
    if ( RunParam.Ind+1 = HzParam.Ind ) and ( RunParam.Ind = DirectionParam.Ind ) then begin
      // Use single write, if Hz is immediately after run.
      ModbusSlave.SetReg2(RunParam.Ind,r,ihz);
    end else begin
      if ( RunParam.Ind <> DirectionParam.Ind ) then begin
        dir := DirectionParam.AsInteger;
        ModbusSlave.SetReg(DirectionParam.Ind,dir);
      end;
      ModbusSlave.SetReg(HzParam.Ind,ihz);
      ModbusSlave.SetReg(RunParam.Ind,r);
    end;
  end else begin
    // This is not perfect. Expects that forwar/reverse will be controlled by
    // single bit so that e.g RunParam.AsInteger=0, when not forward run.

    // UniDrive SP sekosi, jos laittoi parkkausohjelmalla hertsit pieneksi
    if ( RunParam.AsInteger<>0 ) or ( ReverseParam.AsInteger<>0 ) then begin
      ihz := abs(HzParam.AsInteger);
      if ( ihz<>0 ) then begin
        ModbusSlave.SetReg(HzParam.Ind,ihz);
      end else begin  // Hertsit nollassa, asetetaan vain run:=0
        RunParam.AsInteger:=0;
        ReverseParam.AsInteger:=0;
      end;
    end;

    if RunParam.AsInteger=0 then begin
      ModbusSlave.SetReg(RunParam.Ind,0);
      r := ReverseParam.AsInteger;
      ModbusSlave.SetReg(ReverseParam.Ind,r);
    end else begin
      ModbusSlave.SetReg(ReverseParam.Ind,0);
      r := RunParam.AsInteger;
      ModbusSlave.SetReg(RunParam.Ind,r);
    end;
  end;
end;

{------------------------------------------------------------------------------}
procedure TYasParams.RefreshRunParams;
var r,ihz : integer;
begin
  if ( not ModbusSlave.ok ) then exit;
  if RunParam.Ind = ReverseParam.Ind then begin  // same run command for both direction
    if ( RunParam.Ind+1 = HzParam.Ind ) then begin
      // Use single write, if Hz is immediately after run.
      if ( ModbusSlave.ReadReg2(RunParam.Ind,r,ihz) ) then begin
        RunParam.AsInteger := r;
        HzParam.AsInteger := ihz;
      end;
    end else begin
      if ( ModbusSlave.ReadReg(RunParam.Ind,r) ) then RunParam.AsInteger := r;
      if ( ModbusSlave.ReadReg(HzParam.Ind,ihz) ) then HzParam.AsInteger := ihz;
    end
  end else begin
    if ( ModbusSlave.ReadReg(RunParam.Ind,r) ) then RunParam.AsInteger := r;
    if ( ModbusSlave.ReadReg(ReverseParam.Ind,r) ) then ReverseParam.AsInteger := r;
    if ( ModbusSlave.ReadReg(HzParam.Ind,ihz) ) then HzParam.AsInteger := ihz;
  end;
end;

{------------------------------------------------------------------------------}
function TYasParams.FindParams:boolean;
begin
  RunParam       := FindParam(NameRun);
  ReverseParam   := FindParam(NameReverse);
  ResetParam     := FindParam(NameReset);
  DirectionParam := FindParam(NameDirection);
  HzParam        := FindParam(NameHz);
  Result := (RunParam<>NIL) and (HzParam<>NIL);
end;

{------------------------------------------------------------------------------}
procedure TYasParams.SetDirection(d:integer);
begin
  Fdirection := d;
  if ( Frun ) then begin
    if RunParam.Ind = ReverseParam.Ind then begin  // same run command for both direction
      RunParam.SetBitMask(cRunBit,1,cRunMask,cRunMaskOr);
      if Fdirection < 0 then begin
        DirectionParam.SetBitMask(cDirectionBit,cReverseRun,cDirectionMask,cDirectionMaskOr)
      end else begin
        DirectionParam.SetBitMask(cDirectionBit,cForwardRun,cDirectionMask,cDirectionMaskOr)
      end
    end else begin
      if Fdirection < 0 then begin
        RunParam.SetBitMask(cForwardRun,0,cRunMask,cRunMaskOr);
        ReverseParam.SetBitMask(cReverseRun,1,cRunMask,cRunMaskOr);
      end else begin
        ReverseParam.SetBitMask(cReverseRun,0,cRunMask,cRunMaskOr);
        RunParam.SetBitMask(cForwardRun,1,cRunMask,cRunMaskOr);
      end
    end;
  end else begin
    if RunParam.Ind = ReverseParam.Ind then begin  // same run command for both direction
      RunParam.SetBitMask(cRunBit,0,cRunMask,cRunMaskOr);
    end else begin
      ReverseParam.SetBitMask(cReverseRun,0,cRunMask,cRunMaskOr);
      RunParam.SetBitMask(cForwardRun   ,0,cRunMask,cRunMaskOr);
    end
  end
end;

{------------------------------------------------------------------------------}
function TYasParams.GetDirection:integer;
begin
//  Result := 1;
//  if ( RunParam.GetBit(1) )  then Result := -1;
  Result := fDirection;
end;

{------------------------------------------------------------------------------}
function TYasParams.ReadHz:double;
var hz:double;
begin
  Result := thz;
  if ( not ModbusSlave.Ok ) then exit;
  RefreshRunParams;
  hz := HzParam.Value;
  if ( direction = -1 ) then Hz := -Hz;
  Result := Hz;
  thz := hz;
end;

{------------------------------------------------------------------------------}
function TYasParams.ReadMaxHz:double;
begin
  if ( not ModbusSlave.Ok ) then Result := 60
  else Result := ReadValueByName(NameMaxHz);
end;

{------------------------------------------------------------------------------}
function TYasParams.ReadMinHz:double;
begin
  if ( not ModbusSlave.Ok ) then Result := 0
  else Result := ReadValueByName(NameMinHz);
end;

{------------------------------------------------------------------------------}
procedure TYasParams.WriteHz(hz:double);
begin
  thz := hz;
  if ( hz < 0 ) then direction := -1 else direction := 1;
  HzParam.Value := abs(hz);
  SendRunParams;
end;

{------------------------------------------------------------------------------}
procedure TYasParams.WriteRunHz(hz:double);
begin
  FRun := abs(hz)>0.01;
  WriteHz(hz);
end;

{------------------------------------------------------------------------------}
function TYasParams.WriteReadHz(hz:double):double;
begin
  WriteRunHz(hz);
  Result := ReadHz;
end;

{------------------------------------------------------------------------------}
function TYasParams.AccAHz:double;
var t : double;
begin
  t := ReadValueByName(NameAccTime);
  if ( t = 0 ) then t := 1;
  Result := ReadMaxHz/t;
end;

{------------------------------------------------------------------------------}
function TYasParams.DecAHz:double;
var t : double;
begin
  t := ReadValueByName(NameDecTime);
  if ( t = 0 ) then t := 1;
  Result := ReadMaxHz/t;
end;

{------------------------------------------------------------------------------}
procedure TYasParams.Stop;
begin
  FRun := false;
  if RunParam.Ind = ReverseParam.Ind then begin  // same run command for both direction
    RunParam.WriteBitMask(cRunBit,0,cRunMask,cRunMaskOr);
  end else begin
    ReverseParam.SetBitMask(cReverseRun,0,cRunMask,cRunMaskOr);
    RunParam.SetBitMask(cForwardRun,0,cRunMask,cRunMaskOr);
  end;
end;

{------------------------------------------------------------------------------}
function TYasParams.Reset : boolean;
begin
  Result := true;
  FRun := false;
  if ( not ModbusSlave.OK ) then exit;
  Result := false;

  if ( ResetSequence<>'' ) then begin
    DoSequence(FResetSequence);
    ceYasParamDebug.Add('Reset');
  end else begin
    RunParam.WriteValue(0);
    ReverseParam.WriteValue(0);

    if ( ModbusSlave.LastError <> '' ) then exit;
  //  RunParam.WriteBit(3,true);
    ResetParam.WriteBitMask(0,ResetBitValue,$ffff,0);
    if ( ModbusSlave.LastError <> '' ) then exit;
    ResetParam.WriteValue(0);
    ReverseParam.WriteValue(0);
    RunParam.WriteValue(0);
  //  RunParam.WriteBitMask(0,0,$ffff);
  //  RunParam.WriteBit(3,false);
  end;
  Result := ModbusSlave.LastError = '';
end;

{------------------------------------------------------------------------------}
function TYasParams.ReadNames : boolean;
var ini : TIniFile;
begin
  ini := nil;
  Result := true;
  try
    ini := TIniFile.Create(TypeIniName);
    FNameRun       := ini.ReadString('Names','NameRun','r001');
    FNameReverse   := ini.ReadString('Names','NameReverse',FNameRun);
    FNameReset     := ini.ReadString('Names','NameReset',FNameRun);
    FNameDirection := ini.ReadString('Names','NameDirection',FNameRun);

    FNameHz        := ini.ReadString('Names','NameHz','r002');
    FNameMaxHz     := ini.ReadString('Names','NameMaxHz','n012');
    FNameMinHz     := ini.ReadString('Names','NameMinHz','n017');
    FNameAccTime   := ini.ReadString('Names','NameAccTime','n019');
    FNameDecTime   := ini.ReadString('Names','NameDecTime','n020');
    FNameOutWrite  := ini.ReadString('Names','NameOutWrite','r009');
    FNameOutRead   := ini.ReadString('Names','NameOutRead','r032');
    FNameInRead    := ini.ReadString('Names','NameInRead','r043');
    FNameInWrite   := ini.ReadString('Names','NameInWrite','r001');
    FNameInvStatus := ini.ReadString('Names','NameInvStatus','r044');
    FNameReadHz    := ini.ReadString('Names','NameReadHz','r036');
    FNameMaxA      := ini.ReadString('Names','NameMaxA','n032');
    FNameReadA     := ini.ReadString('Names','NameReadA','r039');
    FNameMaxV      := ini.ReadString('Names','NameMaxV','n013');
    FNameReadV     := ini.ReadString('Names','NameReadV','r040');
    FNameFreqRef   := ini.ReadString('Names','NameFreqRef','r035');

    FInputNames   := ini.ReadString('Names','InputNames','S1,S2,S3,S4,S5,S6');
    FOutputNames   := ini.ReadString('Names','OutputNames','MA-MC,M1-M2');

    FcInvFault := ini.ReadInteger('Names','cInvFault',$4000);
    FcResetBitValue := ini.ReadInteger('Names','cResetBitValue',$0008);
    FcInCount := ini.ReadInteger('Names','cInCount',6);
    FcInReadShift := ini.ReadInteger('Names','cInReadShift',0);
    FcInWriteShift := ini.ReadInteger('Names','cInWriteShift',4);
    FcInWriteStart := ini.ReadInteger('Names','cInWriteStart',2);
    FcOutCount := ini.ReadInteger('Names','cOutCount',2);
    FcOutReadShift := ini.ReadInteger('Names','cOutReadShift',5);
    FcOutWriteShift := ini.ReadInteger('Names','cOutWriteShift',0);
    FcStoreRamRegister := ini.ReadInteger('Names','cStoreRAMRegister',0);
    FcStoreEEPROMRegister := ini.ReadInteger('Names','cStoreEEPROMRegister',0);
    FStoreEEPROMSequence := ini.ReadString('Names','StoreEEPROMSequence','');
    FResetSequence := ini.ReadString('Names','ResetSequence','');
    FcForwardRun := ini.ReadInteger('Names','cForwardRun',$1);
    FcReverseRun := ini.ReadInteger('Names','cReverseRun',$3);
    FcRunBit := ini.ReadInteger('Names','cRunBit',0);
    FcDirectionBit := ini.ReadInteger('Names','cRunBit',FcRunBit);
    FcRunMask := ini.ReadInteger('Names','cRunMask',$3);
    FcDirectionMask := ini.ReadInteger('Names','cDirectionMask',FcRunMask);
    FcRunMaskOr := ini.ReadInteger('Names','cRunMaskOr',$0);
    FcDirectionMaskOr := ini.ReadInteger('Names','cDirectionMaskOr',FcRunMaskOr);
  finally
    ini.Free;
  end;
end;

{------------------------------------------------------------------------------}
function TYasParams.CreateList: string;
begin
  ReadNames;
  Result := Inherited CreateList;
  if ( Result = '' ) and ( Not FindParams ) then Result := 'Param error';
end;

{------------------------------------------------------------------------------}
constructor TYasParams.Create(AOwner: TComponent);
begin
  FYasForm := NIL;
  FmodbusSlave := TModbusSlave.Create;
  FModbusSlave.slave := 1;
  thz := 0;
end;

{------------------------------------------------------------------------------}
procedure TYasParams.DoShowControl(modal:boolean);
//var os : integer;
begin
//  os := slave;
  if ( FYasForm = NIL ) then begin
    FYasForm := TFormYas.Create2(@FYasForm,Self);
    if ( FYasForm = NIL ) then exit;
{
    if ( os < 0 ) then begin
      (FYasForm as TFormYas).ParamSlave.Value := os;
      (FYasForm as TFormYas).ParamSlave.SaveToIni;
      Slave := os;
    end;
}
  end;
  if modal then FYasForm.ShowModal else FYasForm.Show;
end;

{------------------------------------------------------------------------------}
destructor TYasParams.Destroy;
begin
  If ( FYasForm <> nil ) then
    FYasForm.Free;
  inherited;
end;

{------------------------------------------------------------------------------}
procedure TYasParams.ShowControl;
begin
  DoShowControl(false);
end;

{------------------------------------------------------------------------------}
procedure TYasParams.ShowControlModal;
begin
  DoShowControl(true);
end;

{------------------------------------------------------------------------------}
procedure TYasParams.ShowErrors;
begin
  ModbusSlave.ShowErrors;
end;

{------------------------------------------------------------------------------}
function TYasParams.GetSlave:integer;
begin
  Result := ModbusSlave.Slave;
end;

{------------------------------------------------------------------------------}
procedure TYasParams.SetSlave(s:integer);
begin
  ModbusSlave.Slave := s;
end;


{------------------------------------------------------------------------------}
function TYasParams.InvOK : boolean;
var i : integer;
begin
  // ceYasParamDebug.Add('Before inv ok');
  Result := false;
  if ( not ModbusSlave.Ok ) then exit;
  // ceYasParamDebug.Add('MBok');
  i := Trunc(ReadValueByName(NameInvStatus));
  // ceYasParamDebug.Add(Format('Status: %s = %d',[NameInvStatus,i]));
  if ( ModbusSlave.LastError <> '' ) then exit;
  // ceYasParamDebug.Add(Format('Result: %d',[i and cInvFault]));
  Result := ( i and cInvFault ) = 0;
end;

{------------------------------------------------------------------------------}
function TYasParams.GetLastError:string;
begin
  Result := 'No slave';
  if ( not ModbusSlave.Ok ) then exit;
  Result := ModbusSlave.LastError;
end;

function TYasParams.GetEnabled: boolean;
begin
  Result := ModbusSlave.Enabled;
end;

procedure TYasParams.SetEnabled(const Value: boolean);
begin
  ModbusSlave.Enabled := Value;
end;

// Finds first delimiter from string starting from pos.
// Return delimiter position or pos>Length(S), if not found.
function FirstDelimiter(const Delimiters,S:string; pos:integer):Integer;
var
  Found:Boolean;
begin
  Found:=false;

  while (pos<=Length(S)) and not Found do begin
    Found:=IsDelimiter(Delimiters,S,pos);
    if not Found then pos:=pos+1;
  end;

  Result:=pos;
end;

// Takes parameter name from given string stating from pos.
// Pos will be udated to point to delimiter position.
function GetNameFromSequence(var Sequence:string; var pos:integer): string;
var
  Start:Integer;
begin
  Start:=pos;
  pos:=FirstDelimiter('#&|',Sequence,pos);
  Result:=Copy(Sequence,Start,pos-Start);
end;

// Takes parameter name from given string stating from pos.
// Pos will be udated to point to delimiter position.
function GetValueFromSequence(var Sequence:string; var pos:integer): Integer;
var
  Start:Integer;
  I, Code: Integer;
begin
  Start:=pos;
  pos:=FirstDelimiter('#&|;',Sequence,pos);

  Val(Copy(Sequence,Start,pos-Start),I,Code);
  Result:=I;
end;

procedure TYasParams.DoSequence(var Sequence:string);
var
  pos:Integer;
  Param:TParamValue;
  ParamName:string;
  value:Integer;
  Command:char;
begin
  pos:=0;
  repeat
    pos:=pos+1;
    ParamName:=GetNameFromSequence(Sequence,pos);
    if (ParamName='') or (pos>Length(Sequence)) then Exit;
    Param := FindParam(ParamName);
    repeat
      Command:=Sequence[pos];
      pos:=pos+1;
      value:=GetValueFromSequence(Sequence,pos);
      case Command of
        '#': Param.AsInteger:=value;
      end;
    until (pos>Length(Sequence)) or (Sequence[pos]=';');
    Param.WriteValueNoSave(Param.AsInteger,true);
  until ( pos>Length(Sequence) ) or ( ModbusSlave.LastError <> '' );
end;

procedure TYasParams.StoreEEPROM;
begin
  if ( FStoreEEPROMSequence<>'' ) then begin
    DoSequence(FStoreEEPROMSequence);
    ceYasParamDebug.Add('Write to EEPROM');
  end else if ( FcStoreEEPROMRegister <> 0 ) then begin
    ModbusSlave.SetReg(FcStoreEEPROMRegister,0);
    ceYasParamDebug.Add('Yaskawa: Write to EEPROM');
  end;
end;

procedure TYasParams.StoreRAM;
begin
  if ( FcStoreRamRegister <> 0 ) then ModbusSlave.SetReg(FcStoreRamRegister,0);
end;


procedure Register;
begin
end;



initialization begin
  RegisterError(ceYasParamDebug ,'yd', 'Yaskawa debug'           ,True);
end;

end.
