unit Setup;
{ ====================================================================
  WinWCP : Digital recording parameters setup dialog.
  (c) J. Dempster, University of Strathclyde 1996, All Rights Reserved
  ====================================================================}
interface

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

type
  TSetupDlg = class(TForm)
    GroupBox1: TGroupBox;
    EdNumSamples: TEdit;
    SpNumSamples: TSpinButton;
    lNumChannels: TLabel;
    EdNumChannels: TEdit;
    spNumChannels: TSpinButton;
    Label1: TLabel;
    EdSamplingInterval: TEdit;
    spRecordDuration: TSpinButton;
    lNumSamples: TLabel;
    EdRecordDuration: TEdit;
    Label4: TLabel;
    Channels: TGroupBox;
    Label5: TLabel;
    ChannelTable: TStringGrid;
    Label6: TLabel;
    cbADCVoltageRange: TComboBox;
    ColorBox: TPanel;
    ColorLabel: TLabel;
    ColorDialog1: TColorDialog;
    Label2: TLabel;
    bOK: TButton;
    bCancel: TButton;
    GroupBox2: TGroupBox;
    cbLabInterface: TComboBox;
    TUnitsGrp: TGroupBox;
    rbTmsecs: TRadioButton;
    rbTSecs: TRadioButton;
    grp1902: TGroupBox;
    ckCED1902InUse: TCheckBox;
    PortsGrp: TGroupBox;
    lbIOPort: TLabel;
    edIOPort: TEdit;
    lbIRQ: TLabel;
    EdIRQ: TEdit;
    Label8: TLabel;
    EdDMA: TEdit;
    ckNIDisableDMA: TCheckBox;
    procedure spRecordDurationDownClick(Sender: TObject);
    procedure spRecordDurationUpClick(Sender: TObject);
    procedure SpNumSamplesDownClick(Sender: TObject);
    procedure SpNumSamplesUpClick(Sender: TObject);
    procedure spNumChannelsDownClick(Sender: TObject);
    procedure spNumChannelsUpClick(Sender: TObject);
    procedure ColorBoxClick(Sender: TObject);
    procedure ColorBoxDblClick(Sender: TObject);
    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);
  private
    { Private declarations }
    procedure ShowSamplingInterval ;
    procedure DisplayRecordDuration ;
    function SamplingIntervalValid : boolean ;
  public
    { Public declarations }
  end;

const
     ChNum = 0 ;
     ChName = 1 ;
     ChCal = 2 ;
     ChAmp = 3 ;
     ChUnits = 4 ;
type
    TRecordDuration = record
                 Index : LongInt ;
                 List : Array[0..69] of double ;
                 end ;
var
  SetupDlg: TSetupDlg;
  NumChannels : LongInt ;
  NumSamples : LongInt ;
  RecordDurations : TRecordDuration ;
  UpdateOK : boolean ;
  OKorCancelButtonClicked : boolean ;

implementation

{$R *.DFM}
Uses Zoom ;

procedure TSetupDlg.FormShow(Sender: TObject);
{ --------------------------------------------------------------------------
  Initialise setup's combo lists and tables with current recording parameters
  --------------------------------------------------------------------------}
var
   ch,i,NumOptions,Err : Integer ;
   RangeOptions : array[1..10] of TADCRange ;
   Buf : array[0..20] of char ;
   x,dx : Double ;
   Diff,MinDiff,CurrentDuration : single ;
   n : LongInt ;
   List : TStringList ;
begin


     cbLabInterface.Clear ;
     try
        List := TStringList.Create ;
        GetLabInterfaceList( List ) ;
        cbLabInterface.Items := List ;
        cbLabInterface.ItemIndex := Settings.LaboratoryInterface ;
        SelectLaboratoryInterface( Settings.LaboratoryInterface ) ;

        if TLaboratoryInterface(Settings.LaboratoryInterface) = DD then begin
           { If using Axon Digidata 1200 interface, show the port settings }
           PortsGrp.Visible := True ;
           edIoPort.text := format(' %xh', [Settings.DD1200IOPort] ) ;
           edIRQ.text := format( ' %d ', [Settings.DD1200IRQ] ) ;
           edDMA.text := format( ' %d ', [Settings.DD1200DMA] ) ;
           ckNIDisableDMA.visible := False ;
           end
        else if TLaboratoryInterface(Settings.LaboratoryInterface) = NI then begin
           PortsGrp.Visible := False ;
           ckNIDisableDMA.visible := True ;
           ckNIDisableDMA.Checked := Settings.NIDisableDMA ;
           end
        else begin
           PortsGrp.Visible := False ;
           ckNIDisableDMA.visible := False ;
           end ;

     finally
          List.Free ;
          end ;

     { Allow changes to no. of channels and/or samples/channel
       if the data file is empty }
     if RawfH.NumRecords > 0 then begin
        spNumChannels.enabled := False ;
        spNumSamples.enabled := False ;
        EdNumSamples.enabled := False ;
        EdNumChannels.enabled := False ;
        end
     else begin
        spNumChannels.enabled := True ;
        spNumSamples.enabled := True ;
        EdNumSamples.enabled := True ;
        EdNumChannels.enabled := True ;
        end ;

     { Create lists of available values for }
     { Record durations }
     dx := 0.001 ;
     x := dx ;
     for i := 0 to High(RecordDurations.List) do begin
         RecordDurations.List[i] := x ;
         x := x + dx ;
         if x > 9*dx then begin
            dx := dx*10. ;
            x := dx ;
            end ;
         end ;

     { Find nearest recording duration }
     MinDiff := 1E30 ;
     CurrentDuration := RawFH.dt*RawFH.NumSamples ;
     for i := 0 to High(RecordDurations.List) do begin
         Diff := Abs(RecordDurations.List[i] - CurrentDuration) ;
         if Diff < MinDiff then begin
            MinDiff := Diff ;
            RecordDurations.Index := i ;
            end ;
         end ;
     DisplayRecordDuration ;

     { Number of channels }
     NumChannels := RawFH.NumChannels ;
     EdNumChannels.text := format( '%d', [NumChannels] ) ;
     { Number of samples per channel }
     NumSamples := RawFH.NumSamples ;
     EdNumSamples.text := format( '%d', [NumSamples] ) ;

     { If a CED 1902 programmable amplifier is available and
       in use ... set Channel 0 amplification factor to the gain of
       the CEd 1902 }
     if Settings.CED1902.InUse then begin
        ckCED1902InUse.checked := True ;
        Channel[0].ADCAmplifierGain := Settings.CED1902.GainValue ;
        end
     else ckCED1902InUse.checked := False ;


     { 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[ChAmp,0] := 'Amp. Gain' ;
     ChannelTable.colwidths[ChAmp] := (5*ChannelTable.DefaultColWidth) div 4 ;
     ChannelTable.cells[ChUnits,0] := 'Units' ;
     ChannelTable.colwidths[ChUnits] := ChannelTable.DefaultColWidth ;
     ChannelTable.RowCount := NumChannels + 1;
     ChannelTable.options := [goEditing,goHorzLine,goVertLine] ;

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


     { Set trace colour box }
     ColorBox.color := Channel[0].color ;

     { Set up A/D Converter voltage range selection box }
     GetADCVoltageRangeOptions( RangeOptions, NumOptions ) ;
     cbADCVoltageRange.clear ;
     for i := 1 to NumOptions do cbADCVoltageRange.items.add( RangeOptions[i] ) ;

     GetSamplingIntervalRange( Settings.MinSamplingInterval,
                               Settings.MaxSamplingInterval ) ;

     { Select the current A/D converter range in use }
     MinDiff := 1E30 ;
     for i := 1 to NumOptions do begin
         Diff := Abs(RawfH.ADCVoltageRange-ExtractFloat(RangeOptions[i],1. )) ;
         if MinDiff >= Diff then begin
            MinDiff := Diff ;
            cbADCVoltageRange.ItemIndex := i-1
            end ;
         end ;

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

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


procedure TSetupDlg.ShowSamplingInterval ;
var
   SamplingInterval : single ;
begin
     SamplingInterval := RecordDurations.List[RecordDurations.Index]/
                         (NumSamples*RawFH.NumChannels) ;
     CheckSamplingInterval( SamplingInterval ) ;
     edSamplingInterval.text := Format( '%.3f ms',
                                [SamplingInterval*RawFH.NumChannels*SecsToms]);
     end ;


procedure TSetupDlg.spRecordDurationDownClick(Sender: TObject);
begin
     RecordDurations.Index := MaxInt([0,RecordDurations.Index-1]);
     DisplayRecordDuration ;
     { Prevent sampling interval falling below lower limit }
     if not SamplingIntervalValid then Inc(RecordDurations.Index) ;
     ShowSamplingInterval ;
     end;

procedure TSetupDlg.spRecordDurationUpClick(Sender: TObject);
begin
     RecordDurations.Index := MinInt([High(RecordDurations.List),
                                     RecordDurations.Index+1]);
     DisplayRecordDuration ;
     ShowSamplingInterval ;
     end;


procedure TSetupDlg.SpNumSamplesDownClick(Sender: TObject);
{ --------------------------------
  Decrement no. of samples/channel
  --------------------------------}
begin
   NumSamples := NumSamples - 256 ;
   if NumSamples < 256 then NumSamples := 256 ;
   edNumSamples.text := format( '%d ',[NumSamples] ) ;
   ShowSamplingInterval ;
   end;


procedure TSetupDlg.SpNumSamplesUpClick(Sender: TObject);
{ --------------------------------
  Increment no. of samples/channel
  --------------------------------}
begin
   NumSamples := NumSamples + 256 ;
   { Prevent A/D sample buffer begin exceeded }
   if (NumSamples*NumChannels) > (MaxTBuf+1) then begin
      NumSamples := NumSamples - 256 ;
      MessageDlg(' Not allowed! Too many sample points. ',
                         mtWarning, [mbOK], 0 ) ;
      end
   { Prevent sampling interval falling below lower limit }
   else if not SamplingIntervalValid then NumSamples := NumSamples - 256 ;

   edNumSamples.text := format( '%d ',[NumSamples] ) ;
   ShowSamplingInterval ;
   end;


procedure TSetupDlg.spNumChannelsDownClick(Sender: TObject);
{ ----------------------------------
  Decrement no. of channels / record
  ----------------------------------}
begin
   Dec(NumChannels) ;
   if NumChannels < 1 then NumChannels := 1 ;
   edNumChannels.text := format( '%d ',[NumChannels] ) ;
   ShowSamplingInterval ;
   ChannelTable.RowCount := NumChannels + 1;
   end;


procedure TSetupDlg.spNumChannelsUpClick(Sender: TObject);
{ ----------------------------------
  Increment no. of channels / record
  ----------------------------------}
var
   ch : Integer ;
begin
   Inc(NumChannels) ;
   if NumChannels > (ChannelLimit+1) then NumChannels := ChannelLimit+1 ;
   { Prevent A/D sample buffer begin exceeded }
   if (NumChannels*NumSamples) > (MaxTBuf+1) then begin
      MessageDlg(' Not allowed! Too many sample points. ',
                         mtWarning, [mbOK], 0 ) ;
      Dec(NumChannels) ;
      end
   { Prevent sampling interval falling below lower limit }
   else if not SamplingIntervalValid then Dec(NumChannels) ;

   edNumChannels.text := format( '%d ',[NumChannels] ) ;
   ShowSamplingInterval ;

   { Add details for new channel to table }
   ChannelTable.RowCount := NumChannels + 1;
   ch := NumChannels - 1;
   ChannelTable.cells[ChNum,ch+1] := IntToStr(ch) ;
   ChannelTable.cells[ChName,ch+1] := Channel[ch].ADCName ;
   ChannelTable.cells[ChCal,ch+1] := Format( '%5.4g',[Channel[ch].ADCCalibrationFactor] ) ;
   ChannelTable.cells[ChAmp,ch+1] := Format( '%5.4g',[Channel[ch].ADCAmplifierGain] ) ;
   ChannelTable.cells[ChUnits,ch+1] := Channel[ch].ADCUnits ;
   Channel[ch].InUse := True ;

   end ;


procedure TSetupDlg.ColorBoxClick(Sender: TObject);
begin
     ColorDialog1.execute ;
     ColorBox.color := ColorDialog1.color ;
     end;


procedure TSetupDlg.ColorBoxDblClick(Sender: TObject);
begin
     ColorDialog1.execute ;
     ColorBox.color := ColorDialog1.color ;
     end;


procedure TSetupDlg.DisplayRecordDuration  ;
begin
     edRecordDuration.text := format( '%.5g %s',[Settings.TScale*
                              RecordDurations.List[RecordDurations.Index],
                              Settings.TUnits] )
     end ;

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

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


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


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


procedure TSetupDlg.FormClose(Sender: TObject; var Action: TCloseAction);
{ ---------------------------------------------
  Update values in file header (RawFH) and Exit
  ---------------------------------------------}
var
   ch : LongInt ;
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
        { Update file header block with new settings }

        Settings.LaboratoryInterface := cbLabInterface.ItemIndex ;

        { Use I/O port settings if the interface is a Digidata 1200 }
        if TLaboratoryInterface(Settings.LaboratoryInterface) = DD then begin
           if Contains( '100', edIOPort.text ) then Settings.DD1200IOPort := $100 ;
           if Contains( '120', edIOPort.text ) then Settings.DD1200IOPort := $120 ;
           if Contains( '140', edIOPort.text ) then Settings.DD1200IOPort := $140 ;
           if Contains( '160', edIOPort.text ) then Settings.DD1200IOPort := $160 ;
           if Contains( '180', edIOPort.text ) then Settings.DD1200IOPort := $180 ;
           if Contains( '1A0', edIOPort.text ) then Settings.DD1200IOPort := $1A0 ;
           if Contains( '1C0', edIOPort.text ) then Settings.DD1200IOPort := $1C0 ;
           if Contains( '1E0', edIOPort.text ) then Settings.DD1200IOPort := $1E0 ;
           if Contains( '200', edIOPort.text ) then Settings.DD1200IOPort := $200 ;
           if Contains( '220', edIOPort.text ) then Settings.DD1200IOPort := $220 ;
           if Contains( '240', edIOPort.text ) then Settings.DD1200IOPort := $240 ;
           if Contains( '300', edIOPort.text ) then Settings.DD1200IOPort := $300 ;
           if Contains( '320', edIOPort.text ) then Settings.DD1200IOPort := $320 ;
           if Contains( '340', edIOPort.text ) then Settings.DD1200IOPort := $340 ;
           Settings.DD1200IRQ := ExtractInt( edIRQ.text ) ;
           Settings.DD1200DMA := ExtractInt( edDMA.text ) ;
           end
        else if TLaboratoryInterface(Settings.LaboratoryInterface) = NI then begin
           Settings.NIDisableDMA := ckNIDisableDMA.Checked ;
           end ;

        { Recording parameters }

        RawFH.dt := RecordDurations.List[RecordDurations.Index]/NumSamples ;
        RawFH.NumChannels := NumChannels ;
        { If no. of samples has changed ... zoom out }
        if RawFH.NumSamples <> NumSamples then ZoomFrm.ZoomOut ;
        RawFH.NumSamples :=  NumSamples ;
        RawFH.NumSamplesPerRecord := RawFH.NumSamples*RawFH.NumChannels ;
        RawFH.NumDataBytesPerRecord := RawFH.NumSamplesPerRecord*2 ;
        RawFH.NumBytesPerRecord := RawFH.NumDataBytesPerRecord + 512 ;
        RawFH.NumBytesInHeader := 512 ;

        { Channel calibration }

        RawFH.ADCVoltageRange := ExtractFloat(
                           cbADCVoltageRange.items[cbADCVoltageRange.ItemIndex],
                           RawFH.ADCVoltageRange ) ;

        for ch := 0 to RawFH.NumChannels-1 do begin
            Channel[ch].ADCName := ChannelTable.cells[ChName,ch+1] ;
            Channel[ch].ADCCalibrationFactor := ExtractFloat(
                                             ChannelTable.cells[ChCal,ch+1],
                                             Channel[ch].ADCCalibrationFactor);
            Channel[ch].ADCAmplifierGain := ExtractFloat(
                                         ChannelTable.cells[ChAmp,ch+1],
                                         Channel[ch].ADCAmplifierGain);
            Channel[ch].ADCUnits := ChannelTable.cells[ChUnits,ch+1] ;
            end ;

        { Set channel colours }
        for ch := 0 to ChannelLimit do Channel[ch].color := ColorBox.color ;

        { Update CED 1902 amplifier settings }
        if ckCED1902InUse.checked then begin
           Channel[ch].ADCAmplifierGain := Settings.CED1902.GainValue ;
           Settings.CED1902.InUse := True ;
           end
        else Settings.CED1902.InUse := False ;

        { Save data to file header }
        SaveHeader( RawFH ) ;
        FH := RawFH ;
        end ;
     end ;

function TSetupDlg.SamplingIntervalValid : boolean ;
begin
     if (RecordDurations.List[RecordDurations.Index]/
        (NumChannels*NumSamples)) < Settings.MinSamplingInterval then begin
             MessageDlg(' Not allowed! Sampling interval too small. ',
                         mtWarning, [mbOK], 0 ) ;
             Result := False ;
             end
     else Result := True ;
     end ;

procedure TSetupDlg.cbLabInterfaceChange(Sender: TObject);
var
   i,NumOptions : Integer ;
   RangeOptions : array[1..10] of TADCRange ;
begin
     SelectLaboratoryInterface( cbLabInterface.ItemIndex ) ;
     GetADCVoltageRangeOptions( RangeOptions, NumOptions ) ;
     cbADCVoltageRange.clear ;
     for i := 1 to NumOptions do cbADCVoltageRange.items.add( RangeOptions[i] ) ;
     cbADCVoltageRange.ItemIndex := 0 ;

     if TLaboratoryInterface(cbLabInterface.ItemIndex) = DD then begin
        PortsGrp.Visible := True ;
        edIoPort.text := format(' %xh', [Settings.DD1200IOPort] ) ;
        edIRQ.text := format( ' %d ', [Settings.DD1200IRQ] ) ;
        edDMA.text := format( ' %d ', [Settings.DD1200DMA] ) ;
        end
     else PortsGrp.Visible := False ;
     end;

end.
