unit PumpFrm;
{
  (C) 2000 - 2001 Jindrich Jindrich, Pavel Pisa, PiKRON Ltd.

  Originators of the CHROMuLAN project:

  Jindrich Jindrich - http://www.jindrich.com
                      http://orgchem.natur.cuni.cz/Chromulan/
                      software developer, project coordinator
  Pavel Pisa        - http://cmp.felk.cvut.cz/~pisa
                      embeded software developer
  PiKRON Ltd.       - http://www.pikron.com
                      project initiator, sponsor, instrument developer

  The CHROMuLAN project is distributed under the GNU General Public Licence.
  See file COPYING for details.

  Originators reserve the right to use and publish sources
  under different conditions too. If third party contributors
  do not accept this condition, they can delete this statement
  and only GNU license will apply.
}
{$I define.pas}
interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  RackCtls, ExtCtrls, UlanType, {v0.22}ULRecTyp, {/v0.22}
  ModuType,
  {$IFDEF USEDLL}
  ModuProc,
  {$ELSE}
  Modulu,
  {$ENDIF}
  ULDRObju, StdCtrls, Spin,
  UtlType, PBSpinEdit, PBNumEdit;{msgu}

type
  TPumpForm = class(TForm)
    ScrewPanel: TScrewPanel;
    RunBtn: TLEDButton;
    HoldBtn: TLEDButton;
    EndBtn: TLEDButton;
    StartBtn: TLEDButton;
    PurgeBtn: TLEDButton;
    StopBtn: TLEDButton;
    ABtn: TLEDButton;
    BBtn: TLEDButton;
    CBtn: TLEDButton;
    Label1: TLabel;
    Label2: TLabel;
    PressureLEDDisplay: TLEDDisplay;
    Label3: TLabel;
    Label4: TLabel;
    AEdit: TSpinEdit;
    BEdit: TSpinEdit;
    CEdit: TSpinEdit;
    Label5: TLabel;
    Label6: TLabel;
    Label7: TLabel;
    Label8: TLabel;
    Label9: TLabel;
    SolventHintPanel: TPanel;
    Label10: TLabel;
    XEdit: TEdit;
    Label11: TLabel;
    FlowEdit: TPBNumEdit;
    Press_LEdit: TPBNumEdit;
    Press_HEdit: TPBNumEdit;
    procedure StartBtnClick(Sender: TObject);
    procedure FormCreate(Sender: TObject);
    procedure Press_LEditChange(Sender: TObject);
    procedure BEditChange(Sender: TObject);
    procedure ABtnClick(Sender: TObject);
    procedure BBtnClick(Sender: TObject);
    procedure CBtnClick(Sender: TObject);
    procedure XEditChange(Sender: TObject);
    procedure FlowEditChange(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
  private
    { Private declarations }
    FModule: TModule;
    IsInXChange: boolean;
    IsInBCChange: boolean;
    {$IFDEF USEDLL}
    FGrad_B: TModuleProp;
    FGrad_C: TModuleProp;
    FPress: TModuleProp;
    FGradDir, FStart, FStop, FPurge, FPress_H, FPress_L, FFlow: TModuleProp;
    {$ENDIF}
  protected
    procedure SetModule(AModule: TModule);
  public
    { Public declarations }
    procedure UpdateGradValues(upload:boolean);
    property Module: TModule read FModule write SetModule;
    procedure WMAppMessage(var Msg:TMessage);message WM_APPMESSAGE;
    procedure GradModuleToEdits;
    procedure PressModuleToEdit;
  end;

var
  PumpForm: TPumpForm;

function PumpFrmEdit(AModule: pointer): integer;

implementation

{$R *.DFM}

const
  AConc = 100;
  BConc = 50;
  CConc = 0;

function XToBC(x: integer; var b: integer; var c: integer):boolean;
  { if the content of solvent X in resulting two component mixture
    should be x (%), and the three components of gradient contain:
    A = 100% X, B = 50% X, C = 0% X, this function returns how much
    of B, C (and A - calculated to 100%) should be mixed.
    Returns false if x is in invalid range. }
var
  a: integer;
begin
  Result := false;
  if (x < 0) or (x > 100) then
    exit;
  if x < BConc then begin
    b := 100 * x div (CConc + BConc);
    c := 100 * (BConc - x) div (CConc + BConc);
  end else begin
    a := 100 * (x - BConc) div (AConc - BConc);
    b := 100 * (AConc - x) div (AConc - BConc);
    c := 100 - (a + b);
  end;
  Result := true;
end;

function BCToX(b, c: integer; var x: integer): boolean;
var a: integer;
begin
  Result := false;
  a := 100 - b - c;
  if (b < 0) or (b > 100) or (c < 0) or (c > 100) or (a < 0) then
    exit;
  x := (a * AConc + b * BConc + c * CConc) div (a + b + c);
  Result := true;
end;

function PumpFrmEdit(AModule: pointer): integer;
var p: TPumpForm;
begin
{  TModule(AModule).DownloadPropVals;}
  p := TPumpForm.Create(Application);
  {PumpForm.Module := AModule;}
  p.Module := AModule;
  p.Show;
  Result := mrOK;
{  Result := PumpForm.ShowModal;}
end;

procedure TPumpForm.StartBtnClick(Sender: TObject);
begin
  if Sender is TLedButton then begin
    with Sender as TLedButton do begin
      case Tag of
        piStart, piStop, piPurge: begin
          {$IFDEF USEDLL}
          ModuleDoAction(Module, mdaDoCommand, @Tag, sizeof(Tag));
          {$ELSE}
          Module.DoCommand(Tag);
          {$ENDIF}
        end;
      end;
    end;
  end;
end;

procedure TPumpForm.SetModule(AModule: TModule);

  procedure SetUpdates(OnOff:boolean);
  var
    {$IFDEF USEDLL}
    i: integer;
    {$ELSE}
    p: TModuleProp;
    {$ENDIF}
  begin
    {$IFDEF USEDLL}
    if OnOff then i := 500 else i := 0;
    if ModuleHasProp(FModule, mpPropIDStr, IntToStr(piPress), FPress) then
      ModulePropSetPropInt(FPress, mpUpdateInterval, i);
    if ModuleHasProp(FModule, mpPropIDStr, IntToStr(piGrad_B), FGrad_B) then
      ModulePropSetPropInt(FGrad_B, mpUpdateInterval, i);
    if ModuleHasProp(FModule, mpPropIDStr, IntToStr(piGrad_C), FGrad_C) then
      ModulePropSetPropInt(FGrad_C, mpUpdateInterval, i);

    ModuleHasProp(FModule, mpPropIDStr, IntToStr(piPress_H), FPress_H);
    ModuleHasProp(FModule, mpPropIDStr, IntToStr(piPress_L), FPress_L);
    ModuleHasProp(FModule, mpPropIDStr, IntToStr(piFlow), FFlow);
    ModuleHasProp(FModule, mpPropIDStr, IntToStr(piStart), FStart);
    ModuleHasProp(FModule, mpPropIDStr, IntToStr(piPurge), FPurge);
    ModuleHasProp(FModule, mpPropIDStr, IntToStr(piStop), FStop);
    ModuleHasProp(FModule, mpPropIDStr, IntToStr(piGradDir), FGradDir);

    StartBtn.Tag := integer(FStart);
    PurgeBtn.Tag := integer(FPurge);
    StopBtn.Tag := integer(FStop);
    Press_HEdit.Tag := integer(FPress_H);
    Press_LEdit.Tag := integer(FPress_L);

    {$ELSE}
    if FModule.FindProp(piPress, p) then begin
      if OnOff then
        p.UpdateInterval := 500
      else
        p.UpdateInterval := 0;
    end;
    if FModule.FindProp(piGrad_B, p) then begin
      if OnOff then
        p.UpdateInterval := 500
      else
        p.UpdateInterval := 0;
    end;
    if FModule.FindProp(piGrad_C, p) then begin
      if OnOff then
        p.UpdateInterval := 500
      else
        p.UpdateInterval := 0;
    end;
    {$ENDIF}
  end;

begin
  if FModule <> nil then begin
    {$IFDEF USEDLL}
    ModuleDoAction(FModule, mdaUserUnregister, @Self, sizeof(Self));
    {$ELSE}
    FModule.ULDR.UserUnregister(Self);
    {$ENDIF}
    SetUpdates(false);
    FModule := nil;
  end;
  if AModule <> nil then begin
    FModule := AModule;
    {$IFDEF USEDLL}
    SetUpdates(true);
    Press_HEdit.Value := StrToFloat(ModulePropAsUsrStr(FPress_H));
    Press_LEdit.Value := StrToFloat(ModulePropAsUsrStr(FPress_L));
    FlowEdit.Value := StrToFloat(ModulePropAsUsrStr(FFlow));
    GradModuleToEdits;
    PressModuleToEdit;
    ModuleDoAction(FModule, mdaUserRegister, @Self, sizeof(Self));
    {$ELSE}
    Press_HEdit.Value := StrToFloat(Module.UserValStr[piPress_H]);
    Press_LEdit.Value := StrToFloat(Module.UserValStr[piPress_L]);
    FlowEdit.Value := StrToFloat(Module.UserValStr[piFlow]);
    GradModuleToEdits;
    PressModuleToEdit;
    SetUpdates(true);
    FModule.ULDR.UserRegister(Self);
    {$ENDIF}
  end;
end;

procedure TPumpForm.PressModuleToEdit;
begin
  {$IFDEF USEDLL}
  PressureLEDDisplay.Value := StrToFloat(ModulePropAsUsrStr(FPress));
  {$ELSE}
  PressureLEDDisplay.Value := {round}(StrToFloat(Module.UserValStr[piPress]))
  {$ENDIF}
end;

procedure TPumpForm.GradModuleToEdits;
begin
  IsInBCChange := true;
  try
    {$IFDEF USEDLL}
    BEdit.Value := ModulePropAsUsrInt(FGrad_B);
    CEdit.Value := ModulePropAsUsrInt(FGrad_C);

    {$ELSE}
    BEdit.Value := Module.UserValInt[piGrad_B];
    CEdit.Value := Module.UserValInt[piGrad_C];
    {$ENDIF}
    UpdateGradValues(false);
  finally
    IsInBCChange := false;
  end;
end;

procedure TPumpForm.UpdateGradValues(upload:boolean);
var x: integer;
begin
  AEdit.Value := 100 - BEdit.Value - CEdit.Value;
  BEdit.MaxValue := 100 - CEdit.Value;
  CEdit.MaxValue := 100 - BEdit.Value;
  if IsInBCChange then begin
    if BCToX(BEdit.Value, CEdit.Value, x) then
      XEdit.Text := IntToStr(x);
  end;
  if upload then begin
  {$IFDEF USEDLL}
    ModulePropSetUsrInt(FGrad_B, BEdit.Value);
    ModulePropSetUsrInt(FGrad_C, CEdit.Value);
  {$ELSE}
    Module.UserValInt[piGrad_B] := BEdit.Value;
    Module.UserValInt[piGrad_C] := CEdit.Value;
  {$ENDIF}
  end;
end;

procedure TPumpForm.FormCreate(Sender: TObject);
begin
  {$IFDEF USEDLL}
  {$ELSE}
  StartBtn.Tag := piStart;
  PurgeBtn.Tag := piPurge;
  StopBtn.Tag := piStop;
  Press_HEdit.Tag := piPress_H;
  Press_LEdit.Tag := piPress_L;
  {$ENDIF}
end;

procedure TPumpForm.Press_LEditChange(Sender: TObject);
begin
  if Sender is TSpinEdit then begin
    with Sender as TSpinEdit do begin
      {$IFDEF USEDLL}
      ModulePropSetUsrInt(TModuleProp(Tag), Value);
      {$ELSE}
      Module.UserValInt[Tag] := Value;
      {$ENDIF}
    end;
  end;
end;

procedure TPumpForm.BEditChange(Sender: TObject);
begin
  if IsInXChange then
    exit;
  if IsInBCChange then
    exit;
  IsInBCChange := true;
  try
    UpdateGradValues(true);
  finally
    IsInBCChange := false;
  end;
end;

procedure TPumpForm.ABtnClick(Sender: TObject);
begin
  {$IFDEF USEDLL}
  ModulePropSetUsrStr(FGradDir, '0');
  {$ELSE}
  Module.UserValStr[piGradDir] := '0';
  {$ENDIF}
end;

procedure TPumpForm.BBtnClick(Sender: TObject);
begin
  {$IFDEF USEDLL}
  ModulePropSetUsrStr(FGradDir, '1');
  {$ELSE}
  Module.UserValStr[piGradDir] := '1';
  {$ENDIF}
end;

procedure TPumpForm.CBtnClick(Sender: TObject);
begin
  {$IFDEF USEDLL}
  ModulePropSetUsrStr(FGradDir, '2');
  {$ELSE}
  Module.UserValStr[piGradDir] := '2';
  {$ENDIF}
end;

procedure TPumpForm.XEditChange(Sender: TObject);
var code, x, b, c:integer;
begin
  if IsInXChange then
    exit;
  if IsInBCChange then
    exit;
  IsInXChange := true;
  try
    val(XEdit.Text, x, code);
    if code = 0 then begin
      if not XToBC(x, b, c) then
        exit;
      BEdit.MaxValue := b;
      BEdit.Value := b;
      CEdit.MaxValue := c;
      CEdit.Value := c;
      UpdateGradValues(true);
    end;
  finally
    IsInXChange := false;
  end;
end;

procedure TPumpForm.WMAppMessage(var Msg:TMessage);
begin
  case Msg.wParam of
    cmULObjUpdated: begin
      {$IFDEF USEDLL}
      if Msg.lParam = ModuleGetPropInt(FModule, mpULDR) then begin
        GradModuleToEdits;
        PressModuleToEdit;
      end;
      {$ELSE}
      if TULDRObj(Msg.lParam) = FModule.ULDR then begin
        GradModuleToEdits;
        PressModuleToEdit;
      end;
      {$ENDIF}
    end;
  end;
end;


procedure TPumpForm.FlowEditChange(Sender: TObject);
begin
  if Module <> nil then
    {$IFDEF USEDLL}
    ModulePropSetUsrStr(FFlow, FloatToStr(FlowEdit.Value));
    {$ELSE}
    Module.UserValStr[piFlow] := FloatToStr(FlowEdit.Value);
    {$ENDIF}
end;

procedure TPumpForm.FormDestroy(Sender: TObject);
begin
  Module := nil;
end;

end.
