unit uCompartment;

interface

uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, StdCtrls, Buttons, ExtCtrls, SDL_rchart, _GClass, AbVSlide,
  JvExControls, JvxSlider, Vcl.Menus, SDL_NumLab,
  AbLED, JvExStdCtrls, JvShapedButton, AbNumEdit, AbSwitch, JvExExtCtrls,
  JvExtComponent, JvRollOut, JvSlider,
  JvComponentBase, JvWavePlayer, JvSoundControl, Bass, Vcl.ComCtrls,
  JvExComCtrls, JvStatusBar,
  SDL_sdlbase, MkRangeSlider, AbGearDial, JvDialButton, JvCheckBox, JvPanel,
  JvRadioGroup, IniFiles, Vcl.Imaging.jpeg,
  math, JvToolEdit, JvBaseEdits, Vcl.Mask, JvExMask, JvSpin, JvLabel, JvShape;

type
  TfrmCompartment = class(TForm)
    rollStatus: TJvRollOut;
    pnlStatusRollout: TPanel;
    gbMouse: TGroupBox;
    nlMouseMembrain: TNumLab;
    gbConstants: TGroupBox;
    gbStatus: TGroupBox;
    pnlMain: TPanel;
    Chart: TRChart;
    pnlControl: TPanel;
    btnResume: TBitBtn;
    btnStop: TBitBtn;
    btnStart: TBitBtn;
    tmrSim: TTimer;
    mnuMain: TMainMenu;
    mnuFile: TMenuItem;
    mnuOptions: TMenuItem;
    nlMembrain: TNumLab;
    nlCurrentIn: TNumLab;
    nlMouseCurrent: TNumLab;
    lblCap: TLabel;
    lblVr: TLabel;
    lblVt: TLabel;
    lblK: TLabel;
    lbla: TLabel;
    lblb: TLabel;
    lblc: TLabel;
    lbld: TLabel;
    mnuRS: TMenuItem;
    None1: TMenuItem;
    sbCap: TScrollBar;
    sbVr: TScrollBar;
    sbVt: TScrollBar;
    sbK: TScrollBar;
    sbA: TScrollBar;
    sbB: TScrollBar;
    sbc: TScrollBar;
    sbD: TScrollBar;
    sbSimTimeMs: TScrollBar;
    lblSimTime: TLabel;
    mnuIB: TMenuItem;
    mnuCH: TMenuItem;
    mnuLTS: TMenuItem;
    mnuFS: TMenuItem;
    mnuLS: TMenuItem;
    Thalamus: TMenuItem;
    mnuOtherGroups: TMenuItem;
    mnuHelp: TMenuItem;
    mnuAbout: TMenuItem;
    mnuHippocampal: TMenuItem;
    mnuSpiny: TMenuItem;
    mnuMesencephalic: TMenuItem;
    mnuEntorhinalCortex: TMenuItem;
    mnuOlfactoryBulb: TMenuItem;
    mnuHints: TMenuItem;
    mnuSound: TMenuItem;
    sbStatus: TJvStatusBar;
    mnuThalamocortical: TMenuItem;
    mnuReticularThalamic: TMenuItem;
    spbtnVt: TSpeedButton;
    spbtnReset: TSpeedButton;
    Cortexexcitatory1: TMenuItem;
    mnuNAC: TMenuItem;
    rollNeuron: TJvRollOut;
    Panel1: TPanel;
    rollDendrite: TJvRollOut;
    JvPanel1: TJvPanel;
    pnlP1: TJvPanel;
    nsP1Start: TAbNumSpin;
    nsP1Stop: TAbNumSpin;
    nsP1Vpost: TAbNumSpin;
    ckP1: TJvCheckBox;
    lblStart: TLabel;
    lblStop: TLabel;
    lblAmp: TLabel;
    JvPanel2: TJvPanel;
    nsP2Start: TAbNumSpin;
    nsP2Stop: TAbNumSpin;
    nsP2Vpost: TAbNumSpin;
    ckP2: TJvCheckBox;
    lblResistance: TJvLabel;
    lblCapacatance: TJvLabel;
    nsResistance: TAbNumSpin;
    nsCapacatance: TAbNumSpin;
    Panel2: TPanel;
    JvShape1: TJvShape;
    JvShape2: TJvShape;
    JvShape3: TJvShape;
    JvShape4: TJvShape;

    procedure btnStartClick(Sender: TObject);

    procedure btnExitClick(Sender: TObject);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
    procedure FormCreate(Sender: TObject);

    procedure tmrSimTimer(Sender: TObject);
    procedure btnStopClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure btnResumeClick(Sender: TObject);
    procedure mnuAboutClick(Sender: TObject);
    procedure ChartMouseMoveInChart(Sender: TObject; InChart: Boolean; Shift: TShiftState; rMousePosX, rMousePosY: Double);
    procedure nlMembrainClick(Sender: TObject);
    procedure nlCurrentInClick(Sender: TObject);
    procedure mnuHintsClick(Sender: TObject);
    procedure btnResetClick(Sender: TObject);
    procedure sbVrChange(Sender: TObject);
    procedure rollStatusExpand(Sender: TObject);
    procedure rollStatusCollapse(Sender: TObject);
    procedure sbVtChange(Sender: TObject);
    procedure sbKChange(Sender: TObject);
    procedure sbBChange(Sender: TObject);
    procedure sbcChange(Sender: TObject);
    procedure sbDChange(Sender: TObject);
    procedure sbCapChange(Sender: TObject);
    procedure sbAChange(Sender: TObject);
    procedure sbSimTimeMsChange(Sender: TObject);
    procedure mnuRSClick(Sender: TObject);
    procedure mnuIBClick(Sender: TObject);
    procedure mnuCHClick(Sender: TObject);
    procedure mnuLTSClick(Sender: TObject);
    procedure mnuFSClick(Sender: TObject);
    procedure mnuLSClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure mnuSoundClick(Sender: TObject);
    procedure mnuThalamocorticalClick(Sender: TObject);
    procedure mnuReticularThalamicClick(Sender: TObject);
    procedure mnuHippocampalClick(Sender: TObject);
    procedure mnuSpinyClick(Sender: TObject);
    procedure mnuMesencephalicClick(Sender: TObject);
    procedure mnuEntorhinalCortexClick(Sender: TObject);
    procedure mnuOlfactoryBulbClick(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure spbtnVtClick(Sender: TObject);
    procedure spbtnResetClick(Sender: TObject);
    procedure mnuNACClick(Sender: TObject);
    procedure Cortexexcitatory1Click(Sender: TObject);
    procedure mnuOptionsClick(Sender: TObject);
    procedure rollDendriteCollapse(Sender: TObject);
    procedure rollDendriteExpand(Sender: TObject);
    procedure rollNeuronCollapse(Sender: TObject);
    procedure rollNeuronExpand(Sender: TObject);
    procedure btnLoadClick(Sender: TObject);
    procedure ckP1Click(Sender: TObject);
    procedure ckP2Click(Sender: TObject);
    procedure nsP2StartChange(Sender: TObject);
    procedure nsP1VpostValueChanged(Sender: TObject);
    procedure nsP1StartValueChanged(Sender: TObject);
    procedure nsP1StopValueChanged(Sender: TObject);
    procedure nsP2StartValueChanged(Sender: TObject);
    procedure nsP2StopValueChanged(Sender: TObject);
    procedure nsP2VpostValueChanged(Sender: TObject);

  private
    arrayPulse: Array [1 .. 5] of Array [1 .. 4] of Integer; // Holds the pulse data (Start, Stop, Ampl, Enable)
    VmMax: Single; // Voltage of the membrain Maximum [mVolt]
    VmMin: Single; // Voltage of the membrain Minimul [mVolt]
    VmRest: Single; // Resting potential of the membrain
    Vpsp: Single; // Post Synaptic Potential)[Volt]
    LastVpsp: Single;
    Vo: Single; // Initial conditions;
    fileINI: TIniFile;
    StreamHandle: HSTREAM;
    ClickFired: Boolean;
    FMaxCurrent: Single;
    FMinCurrent: Single;
    DataCnt: Double;
    PulseOnTime: Integer;
    mSec: int64;
    v: Single; // Membraine potential (mV)
    u: Single; // recovery current (pA)
    // inputResistance: Single; // INput resistance [mOhm]
    // rheobase: Single; // input current necessare to fire [pA]
    Cap: Single; // Membraine capacitance
    Vr: Single; // resting membrane potential (mV) usually -60 mV
    Vt: Single; // Instantaneous Firing threshold for this neuron
    k: Single; // k=0.7 for v <= Vt and k = 7.0 for v > Vt (Page 49)
    a: Single; // Recovery time constant
    b: Single; // u=amplifying (b<0) or resonate (b>0)
    c: Single; // After spike resetting point
    d: Single;
    // Total of outward minus inward currents activated during the spike
    vpeak, // Spike cutoff
    I: Single; // Pulse of input DC current (pA)
    tau: Single; // Time span and step (mS)
    SimTimeMsec: Single; // number of simulation time [mSec]
    spbtnVtDown: Boolean;
    spbtnResetDown: Boolean;

    LastVs: Single;
    LastVf, NextVf: Single;
    NextV, NextU: Single;
    LastV, LastU: Single;
    procedure DisplayHint(Sender: TObject);
    procedure setMaxCurrent(Value: Single);
    procedure setMinCurrent(Value: Single);
    function Dendrite(Vo, Vs: Single; OnTime: Integer; Resistance, Capacitance: Single): Single;
    procedure Soma(var Vin, Uin, Iin: Single; var Vout, Uout: Single);
    procedure UpdateStatus;
    procedure setTime(Value: Integer);
    procedure ConstantReset;
    procedure Start;
    procedure Stop;
    procedure Pause;
    property MaxCurrent: Single read FMaxCurrent write setMaxCurrent;
    property MinCurrent: Single read FMinCurrent write setMinCurrent;

  public
    { Public declarations }
  end;

var
  frmCompartment: TfrmCompartment;

implementation

{$R *.DFM}

uses uAbout, MMSystem;
{$REGION ' C R E A T E '}

Const
  CCaption = 'Stick Ball Model: ';
  CVmRest = -65; // Resting potential of membrain [mVolt]
  CVmMax = +40; // Maxim membrain potintial
  CVmMin = -70; // Minimum membrain potintial

procedure TfrmCompartment.FormCreate(Sender: TObject);

begin
  SimTimeMsec := 175; // Simulation Time [Sec]
  LastV := v;
  LastU := u;

  mSec := 1;
  // Step := 0.1; // 0.08;

  Caption := CCaption + ' (' + IntToStr(SizeOf(Pointer) * 8) + ' Bit)';
{$IF Defined(EUREKALOG)}
  Caption := Caption + (' + EurekaLog ');
{$IFEND}
  rollStatus.Collapsed := true;
  Chart.JointLayers.L02xControlledBy := 1;
  Chart.JointLayers.L03xControlledBy := 1;

  setTime(175);

  if BASS_Init(-1, 44100, 0, Handle, nil) then
    StreamHandle := BASS_StreamCreateFile(false, PChar('Click.wav'), 0, 0, 0
{$IFDEF UNICODE} or BASS_UNICODE {$ENDIF});
  spbtnVt.glyph := CreateMarkAsBitmap(48, clBlue, ClBtnFace, 2);
  spbtnReset.glyph := CreateMarkAsBitmap(48, clBlue, ClBtnFace, 2);
  mnuHints.Checked := true;

  fileINI := TIniFile.Create(ChangeFileExt(Application.ExeName, '.INI'));
  try
    With fileINI do
    begin
      // res := ini.ReadString('Section_Name', 'Key_Name', 'default value');

      arrayPulse[1, 1] := ReadInteger('Pulse 1', 'Start', 1);
      arrayPulse[1, 2] := ReadInteger('Pulse 1', 'Stop', 1);
      arrayPulse[1, 3] := ReadInteger('Pulse 1', 'Amp', 1);
      arrayPulse[1, 4] := ReadInteger('Pulse 1', 'Enable', 6661);

      arrayPulse[2, 1] := ReadInteger('Pulse 2', 'Start', 2);
      arrayPulse[2, 2] := ReadInteger('Pulse 2', 'Stop', 2);
      arrayPulse[2, 3] := ReadInteger('Pulse 2', 'Amp', 2);
      arrayPulse[2, 4] := ReadInteger('Pulse 2', 'Enable', 6662);

      arrayPulse[3, 1] := ReadInteger('Pulse 3', 'Start', 3);
      arrayPulse[3, 2] := ReadInteger('Pulse 3', 'Stop', 3);
      arrayPulse[3, 3] := ReadInteger('Pulse 3', 'Amp', 3);
      arrayPulse[3, 4] := ReadInteger('Pulse 3', 'Enable', 6663);

      arrayPulse[4, 1] := ReadInteger('Pulse 4', 'Start', 4);
      arrayPulse[4, 2] := ReadInteger('Pulse 4', 'Stop', 4);
      arrayPulse[4, 3] := ReadInteger('Pulse 4', 'Amp', 4);
      arrayPulse[4, 4] := ReadInteger('Pulse 4', 'Enable', 6664);

      arrayPulse[5, 1] := ReadInteger('Pulse 5', 'Start', 5);
      arrayPulse[5, 2] := ReadInteger('Pulse 5', 'Stop', 5);
      arrayPulse[5, 3] := ReadInteger('Pulse 5', 'Amp', 5);
      arrayPulse[5, 4] := ReadInteger('Pulse 5', 'Enable', 6665);
    end;

  finally
    fileINI.Free;
  end;
  nsP1Start.ValueAsInt := arrayPulse[1, 1];
  nsP1Stop.ValueAsInt := arrayPulse[1, 2];
  nsP1Vpost.ValueAsInt := arrayPulse[1, 3];
  If arrayPulse[1, 4] = 0 then
    ckP1.Checked := false
  else
    ckP1.Checked := true;

  nsP2Start.ValueAsInt := arrayPulse[2, 1];
  nsP2Stop.ValueAsInt := arrayPulse[2, 2];
  nsP2Vpost.ValueAsInt := arrayPulse[2, 3];
  If arrayPulse[2, 4] = 0 then
    ckP2.Checked := false
  else
    ckP2.Checked := true;

  VmMax := CVmMax;
  VmMin := CVmMin;
  VmRest := CVmRest;
  Left := 1300;
  Chart.Scale1Y.RangeHigh := VmMin;
  Chart.Scale1Y.RangeHigh := VmMax;
  Chart.Scale2Y.RangeHigh := VmMin;
  Chart.Scale2Y.RangeHigh := VmMax;
  // Chart.AutoRangeYOnly(2, 5);
  // Chart.AutoRangeYOnly(1, 5);
  mnuRSClick(Self); // Always start up with a RS
end;

(* S T A T U S *)
procedure TfrmCompartment.UpdateStatus;

begin
  nlMembrain.Value := LastV;
  nlCurrentIn.Value := I;

  if mnuSound.Checked then
  begin
    if (LastV > Vt) then
      if (NOT ClickFired) then
      begin
        BASS_ChannelPlay(StreamHandle, true);
        ClickFired := true;
      end;
    if (LastV <= Vt) then
      ClickFired := false;
  end;

  if (spbtnVtDown = true) then
  begin
    if LastV > Vt then
    begin
      if (spbtnVt.Tag = 0) then // if not fired
      begin
        Chart.MarkAt(DataCnt, NextV, 36);
        spbtnVt.Tag := 1; // mark reset
      end;
    end;
    if (LastV < c) then
      spbtnVt.Tag := 0;
  end;
  if (spbtnResetDown = true) then
  begin
    if LastV < c then
    begin
      if (spbtnReset.Tag = 0) then // if not fired
      begin
        Chart.MarkAt(DataCnt, NextV, 33);
        spbtnReset.Tag := 1; // mark reset
      end;
    end;
    if (LastV > c) then
      spbtnReset.Tag := 0;
  end;

end;

procedure TfrmCompartment.spbtnResetClick(Sender: TObject);
begin
  spbtnResetDown := NOT spbtnResetDown;
  spbtnReset.Down := spbtnResetDown;
  if spbtnResetDown then
    spbtnReset.glyph := CreateMarkAsBitmap(33, clBlue, ClBtnFace, 2)
  else
    spbtnReset.glyph := CreateMarkAsBitmap(48, clBlue, ClBtnFace, 2);
end;

procedure TfrmCompartment.spbtnVtClick(Sender: TObject);
begin
  spbtnVtDown := NOT spbtnVtDown;
  spbtnVt.Down := spbtnVtDown;
  if spbtnVtDown then
    spbtnVt.glyph := CreateMarkAsBitmap(36, clBlue, ClBtnFace, 2)
  else
    spbtnVt.glyph := CreateMarkAsBitmap(48, clBlue, ClBtnFace, 2);
end;

procedure TfrmCompartment.FormDestroy(Sender: TObject);
begin
  BASS_StreamFree(StreamHandle);
  BASS_Free;
end;

procedure TfrmCompartment.ConstantReset;
begin

  sbCap.Position := round(Cap);
  sbVr.Position := sbVr.Max - round(-Vr);
  sbVt.Position := sbVt.Max - round(-Vt);
  sbK.Position := round(k * 100);
  sbA.Position := round(a * 100);
  sbB.Position := round(b);
  sbc.Position := sbc.Max - round(-c);
  sbD.Position := round(d);
  sbSimTimeMs.Position := round(SimTimeMsec);

  u := v; // Recovery variable [pA]
end;

procedure TfrmCompartment.Cortexexcitatory1Click(Sender: TObject);
begin

end;

{$ENDREGION}
//
{$REGION ' G e t t e r s  /  S e t t e r s '}

procedure TfrmCompartment.setMaxCurrent(Value: Single);
begin
  FMaxCurrent := Value; // Max current for  Neuron.

  Chart.Scale3Y.RangeHigh := MaxCurrent; //
  Chart.Scale3Y.RangeLow := MinCurrent; //
end;

procedure TfrmCompartment.setMinCurrent(Value: Single);
begin
  FMinCurrent := Value; // Mincurrent for  Neuron.

  Chart.Scale3Y.RangeHigh := MaxCurrent; //
  Chart.Scale3Y.RangeLow := MinCurrent; //
end;

{$ENDREGION}
//
{$REGION ' T i m e r    '}

procedure TfrmCompartment.tmrSimTimer(Sender: TObject);

begin
  Chart.SuppressPaint := true;

  { Vfilter - The output of the Dendrite (after the TC filter }
  Chart.ActiveLayer := 2;
  Chart.DataColor := clBlue;
  Chart.LineWidth := 1;
  if (arrayPulse[1, 4] <> 0) then
  begin

    If (DataCnt > arrayPulse[1, 1]) AND (DataCnt < arrayPulse[1, 2]) then
    begin
      Vpsp := arrayPulse[1, 3];
      PulseOnTime := PulseOnTime + 1;
      NextVf := Dendrite(LastVf, Vpsp, PulseOnTime, nsResistance.Value, nsCapacatance.Value);
      Chart.ActiveLayer := 1;
      Chart.DataColor := clRed;
      Chart.LineWidth := 1;

    end
    else
    begin
      PulseOnTime := 0;
      Vpsp := VmRest;
      PulseOnTime := PulseOnTime + 1;
      NextVf := Dendrite(LastVf, Vpsp, PulseOnTime, nsResistance.Value, nsCapacatance.Value);
    end;
    Chart.MoveTo(DataCnt - tau, LastVf);
    Chart.DrawTo(DataCnt, NextVf);
    LastVf := NextVf;
    // Layer 1 is last so that the mouse can be adjusted correctly - Don't reorder
    begin // Vs - Step input to the dendrite (Post Synaptic Potential

      Chart.MoveTo(DataCnt - tau, LastVpsp);
      Chart.DrawTo(DataCnt, Vpsp);
    end;

  end;

  if (arrayPulse[2, 4] <> 0) then
  begin

    If (DataCnt > arrayPulse[2, 1]) AND (DataCnt < arrayPulse[2, 2]) then
    begin
      Vpsp := arrayPulse[2, 3];
      PulseOnTime := PulseOnTime + 1;
      NextVf := Dendrite(LastVf, Vpsp, PulseOnTime, nsResistance.Value, nsCapacatance.Value);
      Chart.ActiveLayer := 1;
      Chart.DataColor := clRed;
      Chart.LineWidth := 1;

    end
    else
    begin
      PulseOnTime := 0;
      Vpsp := VmRest;
      PulseOnTime := PulseOnTime + 1;
      NextVf := Dendrite(LastVf, Vpsp, PulseOnTime, nsResistance.Value, nsCapacatance.Value);
    end;
    Chart.MoveTo(DataCnt - tau, LastVf);
    Chart.DrawTo(DataCnt, NextVf);
    LastVf := NextVf;
    // Layer 1 is last so that the mouse can be adjusted correctly - Don't reorder
    begin // Vs - Step input to the dendrite (Post Synaptic Potential
      // Soma(LastV, LastU, I, NextV, NextU); // Run the neuron
      // Chart.ActiveLayer := 1;
      // Chart.DataColor := clRed;
      // Chart.LineWidth := 1;

      Chart.MoveTo(DataCnt - tau, LastVpsp);
      Chart.DrawTo(DataCnt, Vpsp);
    end;

  end;

  if DataCnt > SimTimeMsec then
  begin // End of Simulation run
    Chart.ClearGraf;
    DataCnt := 0;

    LastV := Vr; // Start off at rest
    LastU := u;
    Vpsp := VmRest; // Set the PSP up for no input
    Vo := VmRest; // Initial conditions
    LastVf := VmRest;
  end
  else
  begin
    DataCnt := DataCnt + tau;
    LastU := NextU;
    LastV := NextV;
    LastVpsp := Vpsp;

  end;

  UpdateStatus;
  Chart.SuppressPaint := false;

end;
{$ENDREGION}
//
{$REGION ' D E N D R I T E  and   N E U R O N '}

function TfrmCompartment.Dendrite(Vo, Vs: Single; OnTime: Integer; Resistance, Capacitance: Single): Single; {
  Where:
  e = 2.718281828459045
  Vo = current Vmembrain[volts]
  Vs = Step Voltage [volts]
  Resistance = Axial Resistange [ohms]
  Capacitance = Capacatance of dendrite membrain [frads]
  OnTime = Milliseconds of pulse on time
}
const
  e = 2.718281828459045;
var
  RC: Single;
  t: Single;
begin
  t := OnTime / 1000; // Convert mSec to Seconds
  RC := Resistance * Capacitance * 0.000000001;
  Result := Vs + (Vo - Vs) * (Power(e, -t / RC))
end;

procedure TfrmCompartment.Soma(var Vin, Uin, Iin: Single; var Vout, Uout: Single);
begin
  Vout := Vin + tau * (k * (Vin - Vr) * (Vin - Vt) - Uin + I) / Cap;
  Uout := Uin + tau * a * (b * (Vout - Vr) - Uin);
  if Vout >= vpeak then
  begin
    Vout := c;
    // Vin := vpeak; // Reset the membrane
    Uout := Uout + d; // Reset the recovery variable
  end;

end;
{$ENDREGION}
//
{$REGION '  C O N T R O L S   }

procedure TfrmCompartment.Pause;
begin
  btnStop.Enabled := true;
  if tmrSim.Enabled then
  begin
    tmrSim.Enabled := false;
    btnResume.Caption := 'Resume'
  end
  else
  begin
    tmrSim.Enabled := true;
    btnResume.Caption := 'Pause'
  end
end;

procedure TfrmCompartment.Start;
begin
  Chart.ClearGraf;
  // Chart.SetRange(1, 0, Chart.Scale1Y.RangeLow, SimTimeMsec, Chart.Scale1Y.RangeHigh);
  DataCnt := 0;
  btnStart.Enabled := false;
  btnStop.Enabled := true;
  btnResume.Enabled := true;
  btnResume.Caption := 'Pause';
  LastV := Vr;
  // Start off at rest
  LastU := u;
  LastVs := VmRest;
  LastVf := VmRest;
  tmrSim.Enabled := true;
end;

procedure TfrmCompartment.Stop;
begin
  tmrSim.Enabled := false;
  btnStart.Caption := 'ReStart';
  btnStart.Enabled := true;
  btnStop.Enabled := false;
  btnResume.Enabled := true;
  btnResume.Caption := 'Paused';
end;

procedure TfrmCompartment.setTime(Value: Integer);

begin
  SimTimeMsec := sbSimTimeMs.Position;
  lblSimTime.Caption := 'T:' + IntToStr(sbSimTimeMs.Position) + ' mSec';
  Chart.Scale1X.RangeHigh := SimTimeMsec;
  // rngInput.Max := sbT.Position;
  // rngInput.maxPosition := rngInput.Max - 10;
  // rngInput.MinPosition := rngInput.min + 10;
end;

procedure TfrmCompartment.nlCurrentInClick(Sender: TObject);
begin
  Chart.LayerVisible[2] := NOT Chart.LayerVisible[2];
  if Chart.LayerVisible[2] = false then
    nlCurrentIn.RightText := 'OFF'
  else
    nlCurrentIn.RightText := 'pA';
  Chart.Scale2Y.Visible := Chart.LayerVisible[2];
end;

procedure TfrmCompartment.nlMembrainClick(Sender: TObject);
begin
  Chart.LayerVisible[1] := NOT Chart.LayerVisible[1];
  if Chart.LayerVisible[1] = false then
    nlMembrain.RightText := 'OFF'
  else
    nlMembrain.RightText := 'mV';
  Chart.Scale1Y.Visible := Chart.LayerVisible[1];
end;

procedure TfrmCompartment.nsP1VpostValueChanged(Sender: TObject);
begin
  arrayPulse[1, 3] := nsP1Vpost.ValueAsInt;
end;

procedure TfrmCompartment.nsP1StartValueChanged(Sender: TObject);
begin
  arrayPulse[1, 1] := nsP1Start.ValueAsInt;
end;

procedure TfrmCompartment.nsP1StopValueChanged(Sender: TObject);
begin
  arrayPulse[1, 2] := nsP1Stop.ValueAsInt;
end;

procedure TfrmCompartment.nsP2VpostValueChanged(Sender: TObject);
begin
  arrayPulse[2, 3] := nsP2Vpost.ValueAsInt;
end;

procedure TfrmCompartment.nsP2StartChange(Sender: TObject);
begin
  arrayPulse[2, 1] := nsP2Start.ValueAsInt;
end;

procedure TfrmCompartment.nsP2StartValueChanged(Sender: TObject);
begin
  arrayPulse[2, 1] := nsP2Start.ValueAsInt;
end;

procedure TfrmCompartment.nsP2StopValueChanged(Sender: TObject);
begin
  arrayPulse[2, 2] := nsP2Stop.ValueAsInt;
end;

procedure TfrmCompartment.rollDendriteCollapse(Sender: TObject);
begin
  frmCompartment.Width := frmCompartment.Width + pnlStatusRollout.Width;
end;

procedure TfrmCompartment.rollDendriteExpand(Sender: TObject);
begin
  frmCompartment.Width := frmCompartment.Width + pnlStatusRollout.Width;
end;

procedure TfrmCompartment.rollNeuronCollapse(Sender: TObject);
begin
  frmCompartment.Width := frmCompartment.Width - pnlStatusRollout.Width;
end;

procedure TfrmCompartment.rollNeuronExpand(Sender: TObject);
begin
  frmCompartment.Width := frmCompartment.Width + pnlStatusRollout.Width;
end;

procedure TfrmCompartment.rollStatusCollapse(Sender: TObject);
begin
  frmCompartment.Width := frmCompartment.Width - pnlStatusRollout.Width;
end;

procedure TfrmCompartment.rollStatusExpand(Sender: TObject);
begin
  frmCompartment.Width := frmCompartment.Width + pnlStatusRollout.Width;

end;

procedure TfrmCompartment.sbAChange(Sender: TObject);
begin
  a := sbA.Position / 100;
  lbla.Caption := 'a: ' + FloatToStr(sbA.Position / 100)
end;

procedure TfrmCompartment.sbBChange(Sender: TObject);
begin
  b := sbB.Position;
  lblb.Caption := 'b: ' + IntToStr(sbB.Position);
end;

procedure TfrmCompartment.sbCapChange(Sender: TObject);
begin
  Cap := sbCap.Position;
  lblCap.Caption := 'Cap: ' + IntToStr(sbCap.Position);
end;

procedure TfrmCompartment.sbDChange(Sender: TObject);
begin
  d := sbD.Position;
  lbld.Caption := 'd: ' + IntToStr(sbD.Position);
end;

procedure TfrmCompartment.sbKChange(Sender: TObject);
begin
  k := sbK.Position / 100;
  lblK.Caption := 'k: ' + FloatToStr(sbK.Position / 100)
end;

procedure TfrmCompartment.sbSimTimeMsChange(Sender: TObject);
begin
  setTime(sbSimTimeMs.Position);
end;

procedure TfrmCompartment.sbVrChange(Sender: TObject);
begin
  Vr := -(sbVr.Max - sbVr.Position);
  lblVr.Caption := 'vr: -' + IntToStr(sbVr.Max - sbVr.Position);
end;

procedure TfrmCompartment.sbVtChange(Sender: TObject);
begin
  Vt := -(sbVt.Max - sbVt.Position);
  lblVt.Caption := 'vt: -' + IntToStr(sbVt.Max - sbVt.Position);
end;

procedure TfrmCompartment.sbcChange(Sender: TObject);
begin
  c := -(sbc.Max - sbc.Position);
  lblc.Caption := 'c: -' + IntToStr(sbc.Max - sbc.Position);
end;

(* S T A R T *)
procedure TfrmCompartment.btnLoadClick(Sender: TObject);
begin
  // nsP1Start.ValueAsInt := arrayPulse[1, 1];
  // nsP1Stop.ValueAsInt := arrayPulse[1, 2];
  // nsP1Amp.ValueAsInt := arrayPulse[1, 3];
  // If arrayPulse[1, 4] = 0 then
  // ckP1.Checked := false
  // else
  // ckP1.Checked := true;
  //
  // nsP2Start.ValueAsInt := arrayPulse[2, 1];
  // nsP2Stop.ValueAsInt := arrayPulse[2, 2];
  // nsP2Amp.ValueAsInt := arrayPulse[2, 3];
  // If arrayPulse[2, 4] = 0 then
  // ckP2.Checked := false
  // else
  // ckP2.Checked := true;
end;

procedure TfrmCompartment.btnResetClick(Sender: TObject);
begin
  ConstantReset;
end;

procedure TfrmCompartment.btnResumeClick(Sender: TObject);
begin
  Pause;
end;

procedure TfrmCompartment.btnStartClick(Sender: TObject);
begin
  Start;
end;

procedure TfrmCompartment.btnStopClick(Sender: TObject);
begin
  Stop;
end;

procedure TfrmCompartment.ChartMouseMoveInChart(Sender: TObject; InChart: Boolean; Shift: TShiftState; rMousePosX, rMousePosY: Double);

begin
  nlMouseMembrain.Value := rMousePosY;
  nlMouseCurrent.Value := (abs(Chart.Scale1Y.RangeLow) + rMousePosY) *
    (MaxCurrent / (abs(Chart.Scale1Y.RangeLow) + abs(Chart.Scale1Y.RangeHigh)));
end;

procedure TfrmCompartment.ckP1Click(Sender: TObject);
begin
  if ckP1.Checked then
    arrayPulse[1, 4] := 1
  else
    arrayPulse[1, 4] := 0;
end;

procedure TfrmCompartment.ckP2Click(Sender: TObject);
begin
  if ckP2.Checked then
    arrayPulse[2, 4] := 1
  else
    arrayPulse[2, 4] := 0;
end;

(* E X I T *)
procedure TfrmCompartment.btnExitClick(Sender: TObject);
begin
  close;
end;

(* M O U S E   M O V E *)
procedure TfrmCompartment.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
begin
  Screen.cursor := crDefault;
end;

procedure TfrmCompartment.mnuAboutClick(Sender: TObject);
begin
  frmAbout.ShowVersion;
end;

procedure TfrmCompartment.mnuHintsClick(Sender: TObject);
begin
  if mnuHints.Checked then
  begin
    frmCompartment.ShowHint := mnuHints.Checked;
    Application.ShowHint := mnuHints.Checked;
  end
  else
  begin
    frmCompartment.ShowHint := false;
  end;
end;

procedure TfrmCompartment.mnuSoundClick(Sender: TObject);
begin
  mnuSound.Checked := NOT mnuSound.Checked;
end;

(* S L I D E R   C U R R E N T   I N *)
procedure TfrmCompartment.DisplayHint(Sender: TObject);
begin
  sbStatus.Panels[1].Text := GetLongHint(Application.Hint);
end;
{$ENDREGION}
//
{$REGION '  C o n s t a n t s '}

// [ R S ]
procedure TfrmCompartment.mnuRSClick(Sender: TObject);
begin
  Stop;
  Caption := frmCompartment.Caption + ' - Regular Spiking [RS]';
  MaxCurrent := 300; // Max current for Regular Spiking Neuron.
  MinCurrent := 0; // Minimum current for RS

  vpeak := 35; // Spike cutoff

  Cap := 100; // Membrane capacitance [pF=pA.ms.mV^-1]
  Vr := -60; // Resting membrane potential [mV]
  Vt := -40; // instataneous threshold potential [mV]
  k := 0.7; // Parameters used for RS
  a := 0.03; // Recovery time constant [ms^-1]
  b := -2.0; // Constant [(1/R )  [pA.mV^-1 (10^-9 ohm^-1]
  c := -50; // Membrane voltage reset
  d := 100; // neocortical pyramidal neuron

  tau := 1.0; // Time span and step

  With Chart do // Set the Phase portrait up
  begin
    Scale3Y.RangeHigh := MaxCurrent; // Recovery constant [u]
    Scale3Y.RangeLow := -40;

    Scale4X.RangeLow := -65;
    Scale4X.RangeHigh := 40;

    Scale4Y.RangeLow := -60;
    Scale4Y.RangeHigh := MaxCurrent;
  end;
  ConstantReset;
  Start;
end;

// [ I B ]
procedure TfrmCompartment.mnuIBClick(Sender: TObject);
begin
  Stop;
  Caption := frmCompartment.Caption + '- Intrinsically Bursting [IB]';
  MaxCurrent := 800; // Max current for [IB] .
  MinCurrent := 0; // Minimum current for [IB]

  vpeak := 50; // Spike cutoff

  Cap := 150; // Membrane capacitance [pF=pA.ms.mV^-1]
  Vr := -75; // Resting membrane potential [mV]
  Vt := -45; // instataneous threshold potential [mV]
  k := 1.2; // Parameters used for RS
  a := 0.01; // Recovery time constant [ms^-1]
  b := 5; // Constant [(1/R )  [pA.mV^-1 (10^-9 ohm^-1]
  c := -56; // Membrane voltage reset
  d := 130; // neocortical pyramidal neuron

  tau := 1; // Time span and step

  With Chart do // Set the Phase portrait up
  begin
    Scale3Y.RangeHigh := 800; // Recovery constant [u]
    Scale3Y.RangeLow := -40;
    Scale4X.RangeLow := -85;
    Scale4X.RangeHigh := 10;
    Scale4Y.RangeLow := -10;
    Scale4Y.RangeHigh := 500;
  end;
  ConstantReset;
  Start;
end;

// [ C H ]
procedure TfrmCompartment.mnuCHClick(Sender: TObject);
begin
  Stop;
  Caption := frmCompartment.Caption + ' - Chattering [CH] ';
  MaxCurrent := 600; // Max current for Regular Spiking Neuron.
  MinCurrent := 0; // Minimum current for RS

  vpeak := 35; // Spike cutoff

  // Cap := 100; // Membrane capacitance [pF=pA.ms.mV^-1]
  Cap := 50;
  Vr := -60; // Resting membrane potential [mV]
  Vt := -40; // instataneous threshold potential [mV]
  k := 0.7; // Parameters used for RS

  a := 0.03; // Recovery time constant [ms^-1]
  b := -2; // Constant [(1/R )  [pA.mV^-1 (10^-9 ohm^-1]

  c := -40; // Membrane voltage reset
  d := 100; // neocortical pyramidal neuron

  tau := 1; // Time span and step

  With Chart do // Set the Phase portrait up
  begin
    Scale3Y.RangeHigh := MaxCurrent; // Recovery constant [u]
    Scale3Y.RangeLow := -40;

    Scale4X.RangeLow := -65;
    Scale4X.RangeHigh := 40;

    Scale4Y.RangeLow := -60;
    Scale4Y.RangeHigh := MaxCurrent;
  end;

  ConstantReset;
  Start;
end;

// F S  Paragraph 8.2.6]
procedure TfrmCompartment.mnuFSClick(Sender: TObject);
begin
  Stop;
  Caption := frmCompartment.Caption + ' - Fast Spiking [FS]';
  MaxCurrent := 450; // Max current
  MinCurrent := 0; // Minimum current

  vpeak := 35; // Spike cutoff

  Cap := 100; // Membrane capacitance [pF=pA.ms.mV^-1]
  Vr := -55; // Resting membrane potential [mV]
  Vt := -40; // instataneous threshold potential [mV]
  k := 0.7; // Parameters used for RS
  a := 0.03; // Recovery time constant [ms^-1]
  b := -2; // Constant [(1/R )  [pA.mV^-1 (10^-9 ohm^-1]
  c := -50; // Membrane voltage reset
  d := 100; // neocortical pyramidal neuron

  tau := 1; // Time span and step

  With Chart do // Set the Phase portrait up
  begin
    Scale3Y.RangeHigh := 450; // Recovery constant [u]
    Scale3Y.RangeLow := -40;

    Scale4X.RangeLow := -60;
    Scale4X.RangeHigh := 45;
    Scale4Y.RangeLow := -10;
    Scale4Y.RangeHigh := 55;
  end;

  ConstantReset;
  Start;
end;

// [ L T S  Paragraph 8.2.5 ]

procedure TfrmCompartment.mnuLTSClick(Sender: TObject);
begin
  Stop;
  Caption := frmCompartment.Caption + ' - Low-Threshold Spiking [LTS]';
  MaxCurrent := 350; // Max current for [LTS]
  MinCurrent := 0; // Minimum current

  vpeak := 50; // Spike cutoff

  Cap := 150; // Membrane capacitance [pF=pA.ms.mV^-1]
  Vr := -56; // Resting membrane potential [mV]
  Vt := -42; // instataneous threshold potential [mV]
  k := 1.0; // Parameters used for
  a := 0.01; // Recovery time constant [ms^-1]
  b := 8; // Constant [(1/R )  [pA.mV^-1 (10^-9 ohm^-1]
  c := -56; // Membrane voltage reset
  d := 130; // neocortical pyramidal neuron

  tau := 1; // Time span and step

  With Chart do // Set the Phase portrait up
  begin
    Scale3Y.RangeHigh := 350; // Recovery constant [u]
    Scale3Y.RangeLow := -40;
    Scale4X.RangeLow := -65;
    Scale4X.RangeHigh := 45;
    Scale4Y.RangeLow := -10;
    Scale4Y.RangeHigh := 350;
  end;

  ConstantReset;
  Start;
end;

// [L S ]
procedure TfrmCompartment.mnuLSClick(Sender: TObject);
begin
  Stop;
  Caption := frmCompartment.Caption + ' - LateSpiking [LS]';
  MaxCurrent := 300; // Max current for [LTS]
  MinCurrent := 50; // Minimum current

  vpeak := 35; // Spike cutoff

  Cap := 100; // Membrane capacitance [pF=pA.ms.mV^-1]
  Vr := -60; // Resting membrane potential [mV]
  Vt := -40; // instataneous threshold potential [mV]
  k := 0.7; // Parameters used for RS
  a := 0.03; // Recovery time constant [ms^-1]
  b := -2; // Constant [(1/R )  [pA.mV^-1 (10^-9 ohm^-1]
  c := -50; // Membrane voltage reset
  d := 100; // neocortical pyramidal neuron

  tau := 1; // Time span and step
  With Chart do // Set the Phase portrait up
  begin
    Scale4X.RangeLow := -65;
    Scale4X.RangeHigh := 40;
    Scale4Y.RangeLow := -60;
    Scale4Y.RangeHigh := 60;
  end;

  ConstantReset;
  Start;
end;

// [ T C ]
procedure TfrmCompartment.mnuThalamocorticalClick(Sender: TObject);
begin
  Stop;
  Caption := frmCompartment.Caption + ' - Thalamocortical (TC) Relay';
  MaxCurrent := 100; // Max current for TC.
  MinCurrent := -100; // Minimum current for TC

  vpeak := 35; // Spike cutoff

  Cap := 200; // Membrane capacitance [pF=pA.ms.mV^-1]
  Vr := -60; // Resting membrane potential [mV]
  Vt := -50; // instataneous threshold potential [mV]
  k := 0.7; // Parameters used for RS
  a := 0.03; // Recovery time constant [ms^-1]
  b := 0; // Constant [(1/R )  [pA.mV^-1 (10^-9 ohm^-1]
  c := -35; // Membrane voltage reset
  d := 100; // neocortical pyramidal neuron

  tau := 1; // Time span and step

  With Chart do // Set the Phase portrait up
  begin
    Scale4X.RangeLow := -90;
    Scale4X.RangeHigh := 45;
    Scale4Y.RangeLow := -250;
    Scale4Y.RangeHigh := 110;
  end;
  ConstantReset;
  Start;
end;

// [ R T N ]
procedure TfrmCompartment.mnuReticularThalamicClick(Sender: TObject);
begin
  Stop;
  Caption := frmCompartment.Caption + ' - Reticular Thalamic Nucleus (RTN)';
  MaxCurrent := 120; // Max current for RTN
  MinCurrent := -100; // Minimum current for RTN

  vpeak := 35; // Spike cutoff

  Cap := 100; // Membrane capacitance [pF=pA.ms.mV^-1]
  Vr := -60; // Resting membrane potential [mV]
  Vt := -40; // instataneous threshold potential [mV]
  k := 0.7; // Parameters used for RS
  a := 0.03; // Recovery time constant [ms^-1]
  b := 1; // Constant [(1/R )  [pA.mV^-1 (10^-9 ohm^-1]
  c := -50; // Membrane voltage reset
  d := 100; // neocortical pyramidal neuron

  tau := 1; // Time span and step

  With Chart do // Set the Phase portrait up
  begin
    Scale4X.RangeLow := -65;
    Scale4X.RangeHigh := 40;
    Scale4Y.RangeLow := -60;
    Scale4Y.RangeHigh := 60;
  end;
  ConstantReset;
  Start;
end;

// [N A C]
procedure TfrmCompartment.mnuNACClick(Sender: TObject);
begin
  Stop;
  Caption := frmCompartment.Caption + ' - Non-accommodating [NAC] ';
  MaxCurrent := 600; // Max current for Regular Spiking Neuron.
  MinCurrent := 0; // Minimum current

  vpeak := 35; // Spike cutoff

  Cap := 100; // Membrane capacitance [pF=pA.ms.mV^-1]
  Vr := -60; // Resting membrane potential [mV]
  Vt := -40; // instataneous threshold potential [mV]
  k := 1.0; // Parameters
  a := 0.03; // Recovery time constant [ms^-1]
  b := -2; // Constant [(1/R )  [pA.mV^-1 (10^-9 ohm^-1]
  c := -50; // Membrane voltage reset
  d := 100; // neocortical pyramidal neuron

  tau := 1; // Time span and step

  With Chart do // Set the Phase portrait up
  begin
    Scale3Y.RangeHigh := 600; // Recovery constant [u]
    Scale3Y.RangeLow := -40;

    Scale4X.RangeLow := -65;
    Scale4X.RangeHigh := 40;

    Scale4Y.RangeLow := -60;
    Scale4Y.RangeHigh := 600;
  end;
  ConstantReset;
  Start;
end;

// [C A 1]
procedure TfrmCompartment.mnuHippocampalClick(Sender: TObject);
begin
  Stop;
  Caption := frmCompartment.Caption + ' - Hippocampal';
  MaxCurrent := 600; // Max current for Regular Spiking Neuron.
  MinCurrent := 0; // Minimum current

  vpeak := 35; // Spike cutoff

  Cap := 100; // Membrane capacitance [pF=pA.ms.mV^-1]
  Vr := -60; // Resting membrane potential [mV]
  Vt := -40; // instataneous threshold potential [mV]
  k := 0.7; // Parameters used for RS
  a := 0.03; // Recovery time constant [ms^-1]
  b := -2; // Constant [(1/R )  [pA.mV^-1 (10^-9 ohm^-1]
  c := -50; // Membrane voltage reset
  d := 100; // neocortical pyramidal neuron

  tau := 1; // Time span and step

  With Chart do // Set the Phase portrait up
  begin
    Scale3Y.RangeHigh := 600; // Recovery constant [u]
    Scale3Y.RangeLow := -40;

    Scale4X.RangeLow := -65;
    Scale4X.RangeHigh := 40;

    Scale4Y.RangeLow := -60;
    Scale4Y.RangeHigh := 600;
  end;
  ConstantReset;
  Start;
end;

procedure TfrmCompartment.mnuSpinyClick(Sender: TObject);
begin
  Stop;
  Caption := frmCompartment.Caption + '- Spiny Projection';

  MaxCurrent := 700; // Max current for Regular Spiking Neuron.
  MinCurrent := 0; // Minimum current

  vpeak := 40; // Spike cutoff

  Cap := 100; // Membrane capacitance [pF=pA.ms.mV^-1]
  Vr := -80; // Resting membrane potential [mV]
  Vt := -25; // instataneous threshold potential [mV]
  k := 0.7; // Parameters used for RS
  a := 0.01; // Recovery time constant [ms^-1]
  b := -20; // Constant [(1/R )  [pA.mV^-1 (10^-9 ohm^-1]
  c := -55; // Membrane voltage reset
  d := 150; // neocortical pyramidal neuron
  tau := 1; // Time span and step

  With Chart do // Set the Phase portrait up
  begin
    Scale3Y.RangeHigh := 700; // Recovery constant [u]
    Scale3Y.RangeLow := -40;

    Scale4X.RangeLow := -65;
    Scale4X.RangeHigh := 40;

    Scale4Y.RangeLow := -60;
    Scale4Y.RangeHigh := 600;
  end;
  ConstantReset;
  Start;

end;

procedure TfrmCompartment.mnuMesencephalicClick(Sender: TObject);
begin
  Stop;
  Caption := frmCompartment.Caption + '- Mesencephalic is TBD';
  MaxCurrent := 850; // Max current
  MinCurrent := 0; // Minimum current

  vpeak := 35; // Spike cutoff

  Cap := 100; // Membrane capacitance [pF=pA.ms.mV^-1]
  Vr := -55; // Resting membrane potential [mV]
  Vt := -40; // instataneous threshold potential [mV]
  k := 0.7; // Parameters used for RS
  a := 0.03; // Recovery time constant [ms^-1]
  b := -2; // Constant [(1/R )  [pA.mV^-1 (10^-9 ohm^-1]
  c := -50; // Membrane voltage reset
  d := 100; // neocortical pyramidal neuron

  tau := 1; // Time span and step

  With Chart do // Set the Phase portrait up
  begin
    Scale3Y.RangeHigh := 850; // Recovery constant [u]
    Scale3Y.RangeLow := -40;

    Scale4X.RangeLow := -60;
    Scale4X.RangeHigh := 45;
    Scale4Y.RangeLow := -10;
    Scale4Y.RangeHigh := 55;
  end;

  ConstantReset;
  Start;

end;

procedure TfrmCompartment.mnuEntorhinalCortexClick(Sender: TObject);
begin
  Caption := frmCompartment.Caption + '- Entorhinal Cortex is TBD';
end;

procedure TfrmCompartment.mnuOlfactoryBulbClick(Sender: TObject);
begin
  Caption := frmCompartment.Caption + '- Olfactory Bulb is TBD';
end;

procedure TfrmCompartment.mnuOptionsClick(Sender: TObject);
begin

end;

{$ENDREGION  ' C O N S T A N T S }
//
{$REGION '  C L O S E   }

procedure TfrmCompartment.FormActivate(Sender: TObject);
begin
  Application.OnHint := DisplayHint;
end;

procedure TfrmCompartment.FormClose(Sender: TObject; var Action: TCloseAction);
begin

  tmrSim.Enabled := false;
  btnStart.Enabled := true;
  btnStop.Enabled := false;
  fileINI := TIniFile.Create(ChangeFileExt(Application.ExeName, '.INI'));
  try
    With fileINI do
    begin

      WriteInteger('Pulse 1', 'Start', arrayPulse[1, 1]);
      WriteInteger('Pulse 1', 'Stop', arrayPulse[1, 2]);
      WriteInteger('Pulse 1', 'Amp', arrayPulse[1, 3]);
      WriteInteger('Pulse 1', 'Enable', arrayPulse[1, 4]);

      WriteInteger('Pulse 2', 'Start', arrayPulse[2, 1]);
      WriteInteger('Pulse 2', 'Stop', arrayPulse[2, 2]);
      WriteInteger('Pulse 2', 'Amp', arrayPulse[2, 3]);
      WriteInteger('Pulse 2', 'Enable', arrayPulse[2, 4]);

      WriteInteger('Pulse 3', 'Start', arrayPulse[3, 1]);
      WriteInteger('Pulse 3', 'Stop', arrayPulse[3, 2]);
      WriteInteger('Pulse 3', 'Amp', arrayPulse[3, 3]);
      WriteInteger('Pulse 3', 'Enable', arrayPulse[3, 4]);

      WriteInteger('Pulse 4', 'Start', arrayPulse[4, 1]);
      WriteInteger('Pulse 4', 'Stop', arrayPulse[4, 2]);
      WriteInteger('Pulse 4', 'Amp', arrayPulse[4, 3]);
      WriteInteger('Pulse 4', 'Enable', arrayPulse[4, 4]);

      WriteInteger('Pulse 5', 'Start', arrayPulse[5, 1]);
      WriteInteger('Pulse 5', 'Stop', arrayPulse[5, 2]);
      WriteInteger('Pulse 5', 'Amp', arrayPulse[5, 3]);
      WriteInteger('Pulse 5', 'Enable', arrayPulse[5, 4]);
    end;

  finally
    fileINI.Free;
  end;
end;
{$ENDREGION}

end.
