unit Setup;
{ ====================================================================
  WinWCP : Digital recording parameters setup dialog.
  (c) J. Dempster, University of Strathclyde 1996, All Rights Reserved
  ====================================================================
  10/9/99 12/16 bit switch added
  7/3/01 Now an MDI form to ensure that FormActivate/Deactivate of
         other MDI forms work (required by SealTest and Record).
  23/10/01 Sampling interval now updated correctly upon first
           opening of Setup dialog box
  22/1/02  Record duration now updated with values consistent with valid sampling intervals
  29.2.02  Settings now saved to WCP file header when OK selected
  24.06.03 No. of horizontal & vertical grid lines added
  18.03.04 MaxADCValue no longer set to SESLabIO.ADCMaxValue
  13.04.04 Channel settings fixed when using VP500 interface
  06.08.04 Channels settings now automatically configured
           when patch clamp amplifier is chosen
  29.07.05 A/D Input mode combo box list added
  25.07.06 Recording channel settings now stored in RecChannel (global.pas)
                  }
interface

uses WinTypes, WinProcs, Classes, Graphics, Forms, Controls, Buttons,
  StdCtrls, Spin, ExtCtrls, shared, sysUtils, Grids, Dialogs, Global, FileIo,
  maths, ValEdit, ValidatedEdit, math ;

type
  TSetupDlg = class(TForm)
    GroupBox1: TGroupBox;
    lNumChannels: TLabel;
    Label1: TLabel;
    lNumSamples: TLabel;
    Label4: TLabel;
    Channels: TGroupBox;
    ChannelTable: TStringGrid;
    Label2: TLabel;
    bOK: TButton;
    bCancel: TButton;
    GroupBox2: TGroupBox;
    cbLabInterface: TComboBox;
    TUnitsGrp: TGroupBox;
    rbTmsecs: TRadioButton;
    rbTSecs: TRadioButton;
    grp1902: TGroupBox;
    edRecordDuration: TValidatedEdit;
    edNumChannels: TValidatedEdit;
    edNumSamples: TValidatedEdit;
    edSamplingInterval: TValidatedEdit;
    cbAmplifier1: TComboBox;
    cbADCVoltageRange: TComboBox;
    Label5: TLabel;
    GroupBox3: TGroupBox;
    edNumHorizontalGridLines: TValidatedEdit;
    Label6: TLabel;
    Label7: TLabel;
    edNumVerticalGridLines: TValidatedEdit;
    cbAmplifier2: TComboBox;
    Label8: TLabel;
    Label9: TLabel;
    cbADCInputMode: TComboBox;
    Label3: TLabel;
    GainTelegraphPanel2: TPanel;
    Label10: TLabel;
    edGainTelegraphChannel2: TValidatedEdit;
    ModeTelegraphPanel1: TPanel;
    Label11: TLabel;
    edModeTelegraphChannel1: TValidatedEdit;
    ModeTelegraphPanel2: TPanel;
    Label12: TLabel;
    edModeTelegraphChannel2: TValidatedEdit;
    GainTelegraphPanel1: TPanel;
    lbTelegraphChannel1: TLabel;
    edGainTelegraphChannel1: TValidatedEdit;
    procedure bOKClick(Sender: TObject);
    procedure rbTmsecsClick(Sender: TObject);
    procedure rbTSecsClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure bCancelClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure cbLabInterfaceChange(Sender: TObject);
    procedure edNumChannelsKeyPress(Sender: TObject; var Key: Char);
    procedure edNumSamplesKeyPress(Sender: TObject; var Key: Char);
    procedure cbADCVoltageRangeChange(Sender: TObject);
    procedure edRecordDurationKeyPress(Sender: TObject; var Key: Char);
    procedure cbAmplifier1Change(Sender: TObject);
  private
    { Private declarations }
    procedure UpdateSamplingInterval ;
    procedure UpdateNumSamples ;
    procedure UpdateNumChannels ;
    procedure UpdateAmplifierSettings ;

  public
    { Public declarations }
  end;

const
     ChNum = 0 ;
     ChName = 1 ;
     ChCal = 2 ;
     ChUnits = 3 ;

var
  SetupDlg: TSetupDlg;
  UpdateOK : boolean ;
  OKorCancelButtonClicked : boolean ;
   OldResolution16Bit : Boolean ;

implementation

uses Mdiform, AmpModule, seslabio ;

{$R *.DFM}



procedure TSetupDlg.FormShow(Sender: TObject);
{ --------------------------------------------------------------------------
  Initialise setup's combo lists and tables with current recording parameters
  --------------------------------------------------------------------------}
var
   ch,i : Integer ;
begin

     { Stop laboratory interface activity }
     if Main.SESLabIO.ADCActive then Main.SESLabIO.ADCStop ;
     if Main.SESLabIO.DACActive then Main.SESLabIO.DACStop ;

     // Laboratory interface card
     Main.SESLabIO.GetLabInterfaceTypes( cbLabInterface.Items ) ;
     cbLabInterface.ItemIndex := Settings.LaboratoryInterface ;
     Main.SESLabIO.LabInterfaceType := Settings.LaboratoryInterface ;

     // A/D channel input mode
     Main.SESLABIO.GetADCInputModes( cbADCInputMode.Items ) ;
     cbADCInputMode.ItemIndex := Min(Main.SESLABIO.ADCInputMode,cbADCInputMode.Items.Count-1) ;

     edNumChannels.Value := Settings.NumChannels ;
     Main.SESLabIO.ADCNumChannels := Round(edNumChannels.Value) ;

     edNumSamples.HiLimit := MaxADCSamples ;
     edNumSamples.Value := Settings.NumSamples ;
     Main.SESLabIO.ADCNumSamples := Settings.NumSamples ;

     edRecordDuration.Units := Settings.TUnits ;
     edRecordDuration.Scale := Settings.TScale ;
     edRecordDuration.Value := Settings.RecordDuration ;
     edSamplingInterval.Scale := Settings.TScale ;
     edSamplingInterval.Units := Settings.TUnits ;

     { Set channel calibration table }
     ChannelTable.cells[ChNum,0] := 'Ch.' ;
     ChannelTable.colwidths[ChNum] := ChannelTable.DefaultColWidth div 2 ;
     ChannelTable.cells[ChName,0] := 'Name' ;
     ChannelTable.colwidths[ChName] := ChannelTable.DefaultColWidth ;
     ChannelTable.cells[ChCal,0] := 'V/Units' ;
     ChannelTable.colwidths[ChCal] := (5*ChannelTable.DefaultColWidth) div 4 ;
     ChannelTable.cells[ChUnits,0] := 'Units' ;
     ChannelTable.colwidths[ChUnits] := ChannelTable.DefaultColWidth ;
     ChannelTable.RowCount := Settings.NumChannels + 1;
     ChannelTable.options := [goEditing,goHorzLine,goVertLine] ;

     for ch := 0 to Settings.NumChannels-1 do begin
         ChannelTable.cells[ChNum,ch+1] := IntToStr(ch) ;
         ChannelTable.cells[ChName,ch+1] := RecChannel[ch].ADCName ;
         ChannelTable.cells[ChCal,ch+1] := Format( '%5.4g',[RecChannel[ch].ADCCalibrationFactor] ) ;
         ChannelTable.cells[ChUnits,ch+1] := RecChannel[ch].ADCUnits ;
         end ;

     { Set up A/D Converter voltage range selection box }
     cbADCVoltageRange.clear ;
     for i := 0 to Main.SESLabIO.ADCNumVoltageRanges-1 do begin
         Main.SESLabIO.ADCVoltageRangeIndex := i ;
         cbADCVoltageRange.items.add(
           format(' +/- %.3g V ',[Main.SESLabIO.ADCVoltageRange] )) ;
         end ;

     Settings.MinSamplingInterval := Main.SESLabIO.ADCMinSamplingInterval ;
     Settings.MaxSamplingInterval := Main.SESLabIO.ADCMaxSamplingInterval ;

     { Select the current A/D converter range in use }
     Main.SESLabIO.ADCVoltageRangeIndex := Min( Settings.ADCVoltageRangeIndex,
                                                Main.SESLabIO.ADCNumVoltageRanges-1) ;
     cbADCVoltageRange.ItemIndex := Main.SESLabIO.ADCVoltageRangeIndex ;

     { Set time units radio buttons }
     if Settings.TUnits = 's' then rbTSecs.checked := true
                              else rbTmsecs.checked := true ;

     // Amplifier #1
     Amplifier.GetList( cbAmplifier1.Items ) ;
     cbAmplifier1.ItemIndex := cbAmplifier1.Items.IndexofObject(TObject(Amplifier.AmplifierType[1])) ;
     edGainTelegraphChannel1.Value := Amplifier.GainTelegraphChannel[1] ;
     edModeTelegraphChannel1.Value := Amplifier.ModeTelegraphChannel[1] ;
     GainTelegraphPanel1.Visible := Amplifier.NeedsGainTelegraphChannel[1] ;
     ModeTelegraphPanel1.Visible := Amplifier.NeedsModeTelegraphChannel[1] ;

     // Amplifier #2
     Amplifier.GetList( cbAmplifier2.Items ) ;
     cbAmplifier2.ItemIndex := cbAmplifier2.Items.IndexofObject(TObject(Amplifier.AmplifierType[2])) ;
     edGainTelegraphChannel2.Value := Amplifier.GainTelegraphChannel[2] ;
     edModeTelegraphChannel2.Value := Amplifier.ModeTelegraphChannel[2] ;
     GainTelegraphPanel2.Visible := Amplifier.NeedsGainTelegraphChannel[2] ;
     ModeTelegraphPanel2.Visible := Amplifier.NeedsModeTelegraphChannel[2] ;

     // No. of horizontal and vertical grid lines on displays
     edNumVerticalGridLines.Value := Settings.NumVerticalGridLines ;
     edNumHorizontalGridLines.Value := Settings.NumHorizontalGridLines ;

     UpdateSamplingInterval ;
     UpDateOK := True ;
     OKorCancelButtonClicked := False ;
     end;


procedure TSetupDlg.rbTmsecsClick(Sender: TObject);
begin
     Settings.TUnits := 'ms' ;
     Settings.TScale := SecsToms ;
     Settings.TUnscale := MsToSecs ;
     edRecordDuration.Units := Settings.TUnits ;
     edRecordDuration.Scale := Settings.TScale ;
     edSamplingInterval.Units := Settings.TUnits ;
     edSamplingInterval.Scale := Settings.TScale ;
     end;

procedure TSetupDlg.rbTSecsClick(Sender: TObject);
begin
     Settings.TUnits := 's' ;
     Settings.TScale := 1. ;
     Settings.TUnscale := 1. ;
     edRecordDuration.Units := Settings.TUnits ;
     edRecordDuration.Scale := Settings.TScale ;
     edSamplingInterval.Units := Settings.TUnits ;
     edSamplingInterval.Scale := Settings.TScale ;
     end;


procedure TSetupDlg.bOKClick(Sender: TObject);
{ ---------------------------------
  Exit setup dialog and update file
  ---------------------------------}
begin
     UpdateOK := True ;
     OKorCancelButtonClicked := True ;
     Close ;
     end ;


procedure TSetupDlg.bCancelClick(Sender: TObject);
{ ---------------------------------------
  Exit setup dialog but don't update file
  ---------------------------------------}
begin
     UpdateOK := False ;
     OKorCancelButtonClicked := True ;
     Close ;
     end;


procedure TSetupDlg.FormClose(Sender: TObject; var Action: TCloseAction);
{ ---------------------------------------------
  Update values in file header (RawFH) and Exit
  ---------------------------------------------}
var
   ch : Integer ;
begin

     if not OKorCancelButtonClicked then begin
        if MessageDlg( 'Save changes! Are you Sure? ', mtConfirmation,
           [mbYes,mbNo], 0 ) = mrYes then UpdateOK := True
                                     else UpdateOK := False ;
           end ;

     if UpdateOK then begin

        UpdateNumChannels ;
        UpdateNumSamples ;

        { Update file header block with new settings }

        Settings.LaboratoryInterface := Main.SESLabIO.LabInterfaceType ;

        // A/D channel input mode
        Main.SESLABIO.ADCInputMode := cbADCInputMode.ItemIndex ;
        Settings.ADCInputMode := Main.SESLABIO.ADCInputMode ;

        Settings.NumChannels := Round(edNumChannels.Value) ;
        Settings.NumSamples := Round(edNumSamples.Value) ;
        Settings.RecordDuration := edRecordDuration.Value ;

        Settings.ADCVoltageRangeIndex := cbADCVoltageRange.ItemIndex ;
        Main.SESLabIO.ADCVoltageRangeIndex := cbADCVoltageRange.ItemIndex ;

        { Channel calibration }
        for ch := 0 to Settings.NumChannels-1 do begin
            RecChannel[ch].ADCName := ChannelTable.cells[ChName,ch+1] ;
            RecChannel[ch].ADCCalibrationFactor := ExtractFloat(
                                             ChannelTable.cells[ChCal,ch+1],
                                             RecChannel[ch].ADCCalibrationFactor);
            RecChannel[ch].ADCUnits := ChannelTable.cells[ChUnits,ch+1] ;
            end ;

        // No. of horizontal and vertical grid lines on displays
        Settings.NumVerticalGridLines := Round(edNumVerticalGridLines.Value) ;
        Settings.NumHorizontalGridLines := Round(edNumHorizontalGridLines.Value) ;

        // Update amplifier settings
        Amplifier.AmplifierType[1] := Integer(cbAmplifier1.Items.Objects[cbAmplifier1.ItemIndex]) ;
        Amplifier.GainTelegraphChannel[1] := Round(edGainTelegraphChannel1.Value) ;
        Amplifier.ModeTelegraphChannel[1] := Round(edModeTelegraphChannel1.Value) ;
        Amplifier.AmplifierType[2] := Integer(cbAmplifier2.Items.Objects[cbAmplifier2.ItemIndex]) ;
        Amplifier.GainTelegraphChannel[2] := Round(edGainTelegraphChannel2.Value) ;
        Amplifier.ModeTelegraphChannel[2] := Round(edModeTelegraphChannel2.Value) ;

        if Amplifier.AmplifierType[1] = amTriton then begin
            for ch := 0 to Settings.NumChannels-1 do begin
                   Amplifier.GetChannelSettings( ch,
                                                 RecChannel[ch].ADCName,
                                                 RecChannel[ch].ADCUnits,
                                                 RecChannel[ch].ADCCalibrationFactor,
                                                 RecChannel[ch].ADCAmplifierGain ) ;
                   end ;
            end ;

        // Add Names of channels to list
        ChannelNames.Clear ;
        for ch := 0 to Settings.NumChannels-1 do
            ChannelNames.Add( format('Ch.%d %s',[ch,RecChannel[ch].ADCName]) ) ;

        // Initialise channel display settings to minimum magnification
        for ch := 0 to WCPChannelLimit do begin
            RecChannel[ch].Cursor0 := 0 ;
            RecChannel[ch].Cursor1 := Settings.NumSamples div 2 ;
            RecChannel[ch].xMin := 0. ;
            RecChannel[ch].xMax := Settings.NumSamples-1 ;
            RecChannel[ch].yMin := Main.SESLabIO.ADCMinValue ;
            RecChannel[ch].yMax := Main.SESLabIO.ADCMaxValue ;
            end ;

        Main.NewFileUpdate ;
        end
     else begin
        { Restore old settings }
        Main.SESLabIO.LabInterfaceType := Settings.LaboratoryInterface ;
        Main.SESLabIO.ADCNumChannels := Settings.NumChannels ;
        Main.SESLabIO.ADCNumSamples := Settings.NumSamples ;
        end ;

     // If using VP500 as interface, amplifier must also be VP500
     if Main.SESLabIO.LabInterfaceType = vp500 then begin
        cbAmplifier1.ItemIndex := cbAmplifier1.Items.IndexOfObject(TObject(amVP500)) ;
        UpdateAmplifierSettings ;
        end ;

     // If using VP500 as interface, amplifier must also be VP500
     if Main.SESLabIO.LabInterfaceType = Triton then begin
        cbAmplifier1.ItemIndex := cbAmplifier1.Items.IndexOfObject(TObject(amTriton)) ;
        cbAmplifier2.ItemIndex := cbAmplifier2.Items.IndexOfObject(TObject(amNone)) ;
        UpdateAmplifierSettings ;
        end ;


     Action := caFree ;
     end ;


procedure TSetupDlg.cbLabInterfaceChange(Sender: TObject);
var
   i : Integer ;
begin

     Main.SESLabIO.LabInterfaceType := cbLabInterface.ItemIndex ;

     // A/D channel input mode
     Main.SESLABIO.GetADCInputModes( cbADCInputMode.Items ) ;
     cbADCInputMode.ItemIndex := Min(Main.SESLABIO.ADCInputMode,cbADCInputMode.Items.Count-1) ;

     cbADCVoltageRange.clear ;
     for i := 0 to Main.SESLabIO.ADCNumVoltageRanges-1 do begin
         Main.SESLabIO.ADCVoltageRangeIndex := i ;
         cbADCVoltageRange.items.add(
           format(' +/-%.3g V ',[Main.SESLabIO.ADCVoltageRange] )) ;
         end ;
     cbADCVoltageRange.ItemIndex := 0 ;

    // Initialise channel display settings to minimum magnification
    Main.mnZoomOutAll.Click ;

     // If using VP500 as interface, amplifier must also be VP500
     if Main.SESLabIO.LabInterfaceType = vp500 then begin
        cbAmplifier1.ItemIndex := cbAmplifier1.Items.IndexOfObject(TObject(amVP500)) ;
        UpdateAmplifierSettings ;
        end ;

     // If using VP500 as interface, amplifier must also be VP500
     if Main.SESLabIO.LabInterfaceType = Triton then begin
        cbAmplifier1.ItemIndex := cbAmplifier1.Items.IndexOfObject(TObject(amTriton)) ;
        cbAmplifier2.ItemIndex := cbAmplifier2.Items.IndexOfObject(TObject(amNone)) ;
        UpdateAmplifierSettings ;
        end ;

     end;


procedure TSetupDlg.edNumChannelsKeyPress(Sender: TObject; var Key: Char);
{ --------------------------------
  Set number of A/D input channels
  -------------------------------- }
begin

     if key = #13 then begin
        if (edNumChannels.Value < 1) or (edNumChannels.Value > (WCPChannelLimit+1)) then begin
           ShowMessage( format('Out of range (1-%d)!',[WCPChannelLimit+1])) ;
           edNumChannels.Value := Main.SESLabIO.ADCNumChannels ;
           end
        else UpdateNumChannels ;

        // Update number of samples/channel
        // to take account of change
        UpdateNumSamples ;

        end ;
     end ;


procedure TSetupDlg.UpdateNumChannels ;
{ --------------------------
  Update no. of A/D channels
  -------------------------- }
var
   OldCount,Row,ch : Integer ;
begin


     // VP500 has fixed channel settings
     if Main.SESLabIO.LabInterfaceType = vp500 then begin ;
          Main.SESLabIO.ADCNumChannels := Min( Round(edNumChannels.Value),2) ;
          edNumChannels.Value := Main.SESLabIO.ADCNumChannels ;
          ChannelTable.RowCount := Main.SESLabIO.ADCNumChannels + 1 ;
          end ;

     OldCount := ChannelTable.RowCount ;
     Main.SESLabIO.ADCNumChannels := Round(edNumChannels.Value) ;
     UpdateSamplingInterval ;
     ChannelTable.RowCount := Main.SESLabIO.ADCNumChannels + 1 ;
     { Add details for new channels to table }
     if ChannelTable.RowCount > OldCount then begin
        for Row := OldCount to ChannelTable.RowCount-1 do begin
            ch := Row-1 ;
            ChannelTable.cells[ChNum,Row] := format('%d',[ch]) ;
            ChannelTable.cells[ChName,Row] := RecChannel[ch].ADCName ;
            if RecChannel[ch].ADCCalibrationFactor = 0.0 then
               RecChannel[ch].ADCCalibrationFactor := 1E-3 ;
            ChannelTable.cells[ChCal,Row] := Format(
                                            '%5.4g',[RecChannel[ch].ADCCalibrationFactor] ) ;
            ChannelTable.cells[ChUnits,Row] := RecChannel[ch].ADCUnits ;
            RecChannel[ch].InUse := True ;
            end ;
        end ;
     end ;


procedure TSetupDlg.edNumSamplesKeyPress(Sender: TObject; var Key: Char);
{ --------------------------------------------
  Set number of samples per A/D input channels
  -------------------------------------------- }
const
     nMin = 256 ;
var
   n,nMax : Integer ;
begin

    if key = #13 then begin
       // Update number of channels first
       // (in case user has entered a new no. of channels but not pressed return)
       UpdateNumChannels ;
       nMax := Main.SESLabIO.ADCBufferLimit div Main.SESLabIO.ADCNumChannels ;

       n := Round(edNumSamples.Value) ;
       if (n < nMin) or (n > nMax) then
          ShowMessage(format('No. Samples/ch. Valid range (%d-%d)!',[nMin,nMax])) ;
       UpdateNumSamples ;
       end ;

    end ;


procedure TSetupDlg.UpdateNumSamples ;
{ -------------------------------------
  Update no. of A/D samples per channel
  ------------------------------------- }
const
     nMin = 256 ;
var
   n,nMax : Integer ;
begin
    nMax := Main.SESLabIO.ADCBufferLimit div Main.SESLabIO.ADCNumChannels ;
    n := Round(edNumSamples.Value) ;
    n := Min(Max(n,nMin),nMax) ;
    { Make a multiple of nMim }
    n := (n div nMin)*nMin ;
    edNumSamples.Value := n ;
    Main.SESLabIO.ADCNumSamples := n ;
    UpdateSamplingInterval ;
    end ;


procedure TSetupDlg.cbADCVoltageRangeChange(Sender: TObject);
{ ----------------------------------------------------
  Update A/D converter voltage range when list changes
  ---------------------------------------------------- }
begin
     Main.SESLabIO.ADCVoltageRangeIndex := cbADCVoltageRange.ItemIndex ;
     end;


procedure TSetupDlg.UpdateSamplingInterval ;
{ ----------------------------
  Update A/D sampling interval
  ---------------------------- }
begin
     // Compute sampling interval
     Main.SESLabIO.ADCSamplingInterval := edRecordDuration.Value /
                                          Main.SESLabIO.ADCNumSamples ;
     // Get validated in interval back from interface
     edSamplingInterval.Value := Main.SESLabIO.ADCSamplingInterval ;
     // Update record interval with valid value
     edRecordDuration.Value := edSamplingInterval.Value*Main.SESLabIO.ADCNumSamples ;
     end ;


procedure TSetupDlg.edRecordDurationKeyPress(Sender: TObject;
  var Key: Char);
begin
     if key = #13 then begin
        UpdateSamplingInterval ;
        end ;
     end;


procedure TSetupDlg.cbAmplifier1Change(Sender: TObject);
// ----------------------
// Amplifier type changed
// ----------------------
begin
     UpdateAmplifierSettings ;
     end ;


procedure TSetupDlg.UpdateAmplifierSettings ;
// ----------------------------------------------
// Update channel settings when amplifier changed
// ----------------------------------------------
var
    i,ch : Integer ;

begin

     // Amplifier #1
     Amplifier.AmplifierType[1] := Integer(cbAmplifier1.Items.Objects[cbAmplifier1.ItemIndex]) ;
     GainTelegraphPanel1.Visible := Amplifier.NeedsGainTelegraphChannel[1] ;
     ModeTelegraphPanel1.Visible := Amplifier.NeedsModeTelegraphChannel[1] ;

     // Amplifier #2
     Amplifier.AmplifierType[2] := cbAmplifier2.ItemIndex ;
     Amplifier.AmplifierType[2] := Integer(cbAmplifier2.Items.Objects[cbAmplifier2.ItemIndex]) ;
     GainTelegraphPanel2.Visible := Amplifier.NeedsGainTelegraphChannel[2] ;
     ModeTelegraphPanel2.Visible := Amplifier.NeedsModeTelegraphChannel[2] ;

     // Update ADC channels
     // Chs. 0 & 1 connected to amplifier #1
     // Chs. 2 & 3 connected to amplifier #2
     for i := 0 to 3 do begin
         Amplifier.GetChannelSettings( i,
                                   RecChannel[i].ADCName,
                                   RecChannel[i].ADCUnits,
                                   RecChannel[i].ADCCalibrationFactor,
                                   RecChannel[i].ADCAmplifierGain ) ;
         end ;

     // Update table
     for ch := 0 to 1 do begin
         ChannelTable.cells[ChNum,ch+1] := IntToStr(ch) ;
         ChannelTable.cells[ChName,ch+1] := RecChannel[ch].ADCName ;
         ChannelTable.cells[ChCal,ch+1] := Format( '%5.4g',[RecChannel[ch].ADCCalibrationFactor] ) ;
         ChannelTable.cells[ChUnits,ch+1] := RecChannel[ch].ADCUnits ;
         end ;

     // Set patch clamp command voltage divide factors
     for i := 1 to 2 do begin
         if Amplifier.AmplifierType[i] <> amNone then
            Settings.DAC[i-1].DivideFactor := Amplifier.CommandVoltageDivideFactor[i] ;
         end ;

     end ;

end.
