unit Wavrun;
{ =============================================
  WinWCP -Analogue & Digital Waveform Generator
  12/12/97 DAC update interval can now go down to 0.1 ms
  13/4/98 Bug which caused -10411 NIDAQ errors fixed
          by using faster DAC update intervals
  =============================================}
interface

uses     global,shared,stdctrls,labio, dialogs, sysutils, fileio, maths ;

{ Public declarations }
procedure CreateWaveform( var wfm : TWaveform ;
                              var Buf,DigBuf : Array of Integer ) ;
procedure CreateLeakWaveform( var wfm : TWaveform ;
                                  var Buf : Array of Integer ) ;
procedure CreateVProgramList( var cbList : TComboBox ) ;
procedure LoadVProgramFromFile( const FileName : string ;
                                    var VProgram : TWaveform ) ;
procedure ProtocolDuration( const Wfm : TWaveform ;
                             var TMin,Total : single ) ;
procedure FillDACBuf( Chan, NumChannels : LongInt ;
                      NumPoints, DACValue : Single ;
                      var Bufpointer : LongInt ;
                      var Buf : Array of Integer ) ;
procedure FillDigBuf( NumPoints : single ;
                      BitMask : Integer ;
                      var BPointer : LongInt ;
                      var Buf : Array of Integer ) ;
procedure SetBits( Inverted:boolean ; Bit:Integer ; var OnBit,OffBit:Integer) ;
procedure FindSectorWriteTime ;
const
     VComm = 0 ;
     Sync = 1 ;
     DigShapes = 10 ; { First digital waveform shape }
     WaveformCreationTime = 0.05 ;

implementation


procedure CreateWaveform( var wfm : TWaveform ;
                          var Buf,DigBuf : Array of Integer ) ;
{ -----------------------------------------------------
  Create command voltage waveforms defined by protocol
  ----------------------------------------------------}

var
   Total,V,dV,DACScale,SyncScale,NumPoints,DACValue,TSmallestPulse : Single ;
   BufPointer,DACEnd,NumRamp,i,j,Shape,NumExtra,iEnd,iStep : LongInt ;
   iDACValue,OnBit,OffBit : Integer ;
   DigPointer : LongInt ;
   MaxDACVolts,TrgOnVolts,TrgOffVolts : single ;
begin

     MaxDACVolts := GetMaxDACVolts ;

     { Calculate total duration of voltage protocol (Total)
       and smallest pulse duration within protocol (TSmallestPulse) }
     ProtocolDuration( Wfm, TSmallestPulse, Total ) ;

     if Total > Wfm.RecordInterval then begin
        Wfm.RecordInterval := Total ;
        Wfm.RecordIntervalChanged := True ;
        end ;

     { Find limits of voltage pulses within protocol }
     Wfm.VMax := Wfm.HoldingVoltage ;
     Wfm.VMin := Wfm.HoldingVoltage ;
     NumExtra := Wfm.NumSteps - 1 ;
     for i := 0 to High(Wfm.Shape) do begin
         case Wfm.Shape[i] of
              wvStep0 : begin
                      Wfm.VMin := MinFlt( [Wfm.VMin,Wfm.Amplitude[i]] ) ;
                      Wfm.VMax := MaxFlt( [Wfm.VMax,Wfm.Amplitude[i]] ) ;
                      end ;
              wvStep1 : begin
                      Wfm.VMin := MinFlt( [Wfm.VMin,Wfm.Amplitude[i],
                                  Wfm.Amplitude[i]+Wfm.Increment[i]*NumExtra ] ) ;
                      Wfm.VMax := MaxFlt( [Wfm.VMax,Wfm.Amplitude[i],
                                  Wfm.Amplitude[i]+Wfm.Increment[i]*NumExtra ] ) ;
                      end ;
              wvStep2 : begin
                      Wfm.VMin := MinFlt( [Wfm.VMin,Wfm.Amplitude[i]] ) ;
                      Wfm.VMax := MaxFlt( [Wfm.VMax,Wfm.Amplitude[i]] ) ;
                      end ;
              wvRamp : begin
                      Wfm.VMin := MinFlt( [Wfm.VMin,Wfm.RampStart[i],Wfm.RampEnd[i]] ) ;
                      Wfm.VMax := MaxFlt( [Wfm.VMax,Wfm.RampStart[i],Wfm.RampEnd[i]] ) ;
                      end ;
              wvPTrain : Begin
                      Wfm.VMin := MinFlt( [Wfm.VMin,Wfm.Amplitude[i]] ) ;
                      Wfm.VMax := MaxFlt( [Wfm.VMax,Wfm.Amplitude[i]] ) ;
                      end ;
              end ;
         end ;

     { Choose the smallest D/A update interval which will allow
       the waveform to be held within the D/A waveform buffer
       (starting off with an interval at least 1/100th of smallest
       pulse and no larger than 5ms) }

     i := MinInt( [Trunc(TSmallestPulse/(100.0*Settings.MinDACInterval)),
                   Trunc(0.005/Settings.MinDACInterval)]) ;
     Wfm.DACdt := i*Settings.MinDACInterval ;
     repeat
       Wfm.DACdt := Wfm.DACdt + Settings.MinDACInterval ;
       until (Wfm.RecordInterval / Wfm.DACdt) < (MaxTBuf/2) ;

     { If an externally defined waveform is in use ... its DAC update
       interval over-rides the internal setting }
     for i := 0 to High(Wfm.Shape) do if Wfm.Shape[i] = wvWave then
         Wfm.DACdt := MaxFlt([Wfm.ExtDACdt,Settings.MinDACInterval]) ;

     Wfm.EndofInterval := Trunc( wfm.RecordInterval / Wfm.DACdt ) ;
     Wfm.EndofProtocol := Trunc( Total / Wfm.DACdt ) ;
     if Settings.VCommand.DivideFactor <= 0. then
        Settings.VCommand.DivideFactor := 1. ;
     DACScale := (MaxDACValue*Settings.VCommand.DivideFactor) / MaxDACVolts ;
     SyncScale := MaxDACValue / MaxDACVolts ;

     { Create a digital D/A waveform from protocol list }

     { Leave time at start to load waveform }
     BufPointer := 0 ;
     DACValue := DACScale * wfm.HoldingVoltage ;
     NumPoints := WaveformCreationTime / Wfm.DACdt ;
     FillDACBuf( VComm, NumDACChannels, NumPoints, DACValue, BufPointer,Buf) ;
     { Clear digital port buffer }
     Wfm.DigitalInUse := False ;
     for i := 0 to High(DigBuf) do DigBuf[i] := 0 ;

     for Shape := 0 to High(wfm.Shape) do begin
         case wfm.Shape[Shape] of
              wvStep0 : Begin
                  { Fixed size step }
                  FillDACBuf( VComm, NumDACChannels, wfm.Delay[Shape]/Wfm.DACdt,
                              DACScale*wfm.HoldingVoltage,BufPointer,Buf) ;
                  FillDACBuf( VComm, NumDACChannels, wfm.Duration[Shape]/Wfm.DACdt,
                              DACScale*(wfm.Amplitude[Shape]+wfm.HoldingVoltage),
                              BufPointer,Buf) ;
                  end ;
              wvStep1 : Begin
                  { Family of steps incrementing in amplitude }
                  FillDACBuf( VComm, NumDACChannels, wfm.Delay[Shape]/Wfm.DACdt,
                              DACScale*wfm.HoldingVoltage,BufPointer,Buf) ;
                  DACValue := DACScale * (wfm.Amplitude[Shape]+wfm.HoldingVoltage
                              + wfm.Increment[Shape]*Wfm.StepCounter );
                  FillDACBuf( VComm, NumDACChannels, wfm.Duration[Shape]/Wfm.DACdt,
                              DACValue,BufPointer, Buf) ;
                  end ;
              wvStep2 : Begin
                  { Family of steps incrementing in duration }
                  FillDACBuf( VComm, NumDACChannels, wfm.Delay[Shape]/Wfm.DACdt,
                              DACScale*wfm.HoldingVoltage,BufPointer, Buf) ;
                  FillDACBuf( VComm, NumDACChannels,
                              (wfm.Duration[Shape]
                              + wfm.Increment[Shape]*Wfm.StepCounter )/Wfm.DACdt,
                              DACScale*(wfm.Amplitude[Shape]+wfm.HoldingVoltage),
                              BufPointer, Buf) ;
                  end ;
              wvRamp : Begin
                  { Voltage ramp }
                  FillDACBuf( VComm, NumDACChannels, wfm.Delay[Shape]/Wfm.DACdt,
                              DACScale*wfm.HoldingVoltage, BufPointer, Buf) ;

                  NumRamp := Trunc( Wfm.Duration[Shape] / Wfm.DACdt ) ;
                  dV := (wfm.RampEnd[Shape] - wfm.RampStart[Shape] ) /(NumRamp) ;
                  V := wfm.RampStart[Shape] + wfm.HoldingVoltage ;
                  for i := 1 to NumRamp do begin
                      FillDACBuf( VComm, NumDACChannels, 1,
                                  DACScale*V,BufPointer, Buf) ;
                      V := V + dV ;
                      end ;
                  end ;
              wvPTrain : Begin
                  { Pulse train }
                  FillDACBuf( VComm, NumDACChannels, wfm.Delay[Shape]/Wfm.DACdt,
                              DACScale*wfm.HoldingVoltage, BufPointer, Buf) ;
                  for i := 1 to wfm.NumPulses[Shape] do begin
                      { Pulse duration }
                      FillDACBuf( VComm, NumDACChannels, wfm.Duration[Shape]/Wfm.DACdt,
                                  DACScale*(wfm.Amplitude[Shape] + wfm.HoldingVoltage),
                                  BufPointer, Buf) ;
                      { Inter pulse interval }
                      NumPoints := (wfm.PulseInterval[Shape] - wfm.Duration[Shape])
                                   /Wfm.DACdt ;
                      { Note ... Train ends at last pulse }
                      if i = wfm.NumPulses[Shape] then NumPoints := 1. ;
                      NumPoints := MaxFlt( [NumPoints, 1.] ) ;
                      FillDACBuf( VComm, NumDACChannels, NumPoints,
                                  DACScale * wfm.HoldingVoltage, BufPointer, Buf) ;
                      end ;
                  end ;

              wvWave : Begin
                  { Waveform defined from an external file }
                  FillDACBuf( VComm, NumDACChannels, wfm.Delay[Shape]/Wfm.DACdt,
                              DACScale*wfm.HoldingVoltage, BufPointer, Buf) ;
                  for i := 0 to Wfm.ExtEndofData do
                      FillDACBuf( VComm, NumDACChannels, 1,
                                  DACScale*(Wfm.ExtWaveData[i] + wfm.HoldingVoltage),
                                  BufPointer, Buf) ;
                  end ;

              wvDigStep0 : Begin
                  { Digital pulse }
                  SetBits(Wfm.Invert[Shape],Shape-DigShapes,OnBit,OffBit) ;
                  DigPointer := 0 ;
                  FillDIGBuf(WaveformCreationTime/Wfm.DACdt,OffBit,DigPointer,DigBuf) ;
                  FillDigBuf( ( wfm.Delay[Shape] +
                               (wfm.Increment[Shape]*Wfm.StepCounter) )/Wfm.DACdt,
                               OffBit,DigPointer,DigBuf) ;
                  FillDigBuf( wfm.Duration[Shape]/Wfm.DACdt,OnBit,DigPointer,DigBuf) ;
                  FillDigBuf( Wfm.EndofInterval-DigPointer,OffBit, DigPointer,DigBuf) ;
                  Wfm.DigitalInUse := True ;
                  end ;
              wvDigStep1 : Begin
                  { Digital pulse (incrementing width)}
                  SetBits( Wfm.Invert[Shape],Shape-DigShapes,OnBit,OffBit ) ;
                  DigPointer := 0 ;
                  FillDIGBuf(WaveformCreationTime/Wfm.DACdt, OffBit,DigPointer,DigBuf) ;
                  FillDigBuf((wfm.Delay[Shape])/Wfm.DACdt, OffBit,DigPointer,DigBuf) ;
                  FillDigBuf( (wfm.Duration[Shape] +
                              (wfm.Increment[Shape]*Wfm.StepCounter))/Wfm.DACdt,
                              OnBit,DigPointer,DigBuf) ;
                  FillDigBuf( Wfm.EndofInterval-DigPointer,OffBit, DigPointer,DigBuf) ;
                  Wfm.DigitalInUse := True ;
                  end ;
              wvDigTrain : begin
                  { Pulse train }
                  SetBits( Wfm.Invert[Shape],Shape-DigShapes,OnBit,OffBit ) ;
                  DigPointer := 0 ;
                  FillDIGBuf(WaveformCreationTime/Wfm.DACdt, OffBit,DigPointer,DigBuf) ;
                  FillDigBuf( (wfm.Delay[Shape])/Wfm.DACdt, OffBit,DigPointer,DigBuf) ;
                  for i := 1 to wfm.NumPulses[Shape] do begin
                      { Pulse duration }
                      FillDigBuf( wfm.Duration[Shape]/Wfm.DACdt,
                                  OnBit,DigPointer, DigBuf) ;
                      { Inter pulse interval }
                      NumPoints := (wfm.PulseInterval[Shape] -
                                    wfm.Duration[Shape])/Wfm.DACdt ;
                      { Note ... Train ends at last pulse }
                      if i = wfm.NumPulses[Shape] then NumPoints := 1 ;
                      NumPoints := MaxFlt( [NumPoints, 1.] ) ;
                      FillDigBuf( NumPoints, OffBit, DigPointer, DigBuf) ;
                      end ;
                  FillDigBuf( Wfm.EndofInterval-DigPointer,OffBit,DigPointer,DigBuf) ;
                  Wfm.DigitalInUse := True ;
                  end ;
              end ;
         end ;

     { Fill up to end of waveform with holding voltage }
     DACValue := DACScale * wfm.HoldingVoltage ;
     FillDACBuf( VComm, NumDACChannels, Wfm.EndofInterval-BufPointer, DACValue,
                 BufPointer, Buf) ;

     {Set default value for digital ports }
     if Wfm.DigitalInUse then Wfm.DigitalPortValue := DigBuf[0]
                         else Wfm.DigitalPortValue := 0 ;

     { *** Create Sync. pulse channel ***
       ... a series of on/off pulses the first of which triggers the
       A/D recording sweep. The rest provide the timing for the digital
       output pattern }

     { Get the voltage levels which signify trigger ON and OFF for
       the laboratory interface in use }
     GetSyncPulseLevels( TrgOnVolts, TrgOffVolts ) ;

     { Fill Sync. channel of D/A buffer with OFF levels }
     BufPointer := 0 ;
     FillDACBuf( Sync, NumDACChannels, Wfm.EndOfInterval, SyncScale*TrgOffVolts,
                 BufPointer, Buf) ;

     { Add a train of ON/OFF pulses where record is to be }
     Wfm.RecordingStart := Trunc(WaveformCreationTime/Wfm.DacDT) +
                           Trunc(Wfm.RecordDelay/Wfm.DacDT) +
                           Trunc((Wfm.RecordDelayIncrement*Wfm.StepCounter )/Wfm.DacDT) ;
     i := Wfm.RecordingStart ;
     iEnd := i + Trunc(Wfm.RecordDuration/Wfm.DACdt) - 3 ;
     iDACValue := Trunc(TrgOnVolts*SyncScale) ;

     case TLaboratoryInterface(Settings.LaboratoryInterface) of
          CED : iStep := 1 ;
          DD : iStep := iEnd + 1 ;
          else iStep := 2 ;
          end ;

     Buf[((i+2)*NumDACChannels)+Sync] := iDACValue ;
     while i < iEnd do begin
           Buf[(i*NumDACChannels)+Sync] := iDACValue ;
           i := i + iStep ;
           end ;
   {  Buf[((Wfm.RecordingStart+4)*NumDACChannels)+Sync] := Trunc(TrgOffVolts*SyncScale)}
     end ;


procedure CreateLeakWaveform( var wfm : TWaveform ;
                              var Buf : Array of Integer ) ;
{ -------------------------------------------------------------------------
  Create leak pulse waveform by dividing down test waveform by wfm.NumLeaks
  -------------------------------------------------------------------------}
var
   i,j : longint ;
   iHold : Integer ;
   VScale : single ;
begin
     if wfm.NumLeaks <> 0 then begin
        iHold := Buf[0] ;
        if wfm.LeakScale <> 0 then VScale := 1. / wfm.LeakScale
                              else VScale := 1 ;
        j := VComm ;
        for i := 0 to Wfm.EndofProtocol do begin
            Buf[j] := Trunc((Buf[j] - iHold)*VScale) + iHold ;
            j := j + 2 ;
            end ;
        end ;
   end ;



procedure FillDACBuf( Chan, NumChannels : LongInt ;
                      NumPoints, DACValue : Single ;
                      var Bufpointer : LongInt ;
                      var Buf : Array of Integer ) ;
{ -------------------------------------------------------------
  Copy a series of NumPoints D/A values of amplitude Value into
  channel Chan of a D/A output buffer Buf, starting at point BufPointer
  ---------------------------------------------------------------------}
var
   i,j : Longint ;
   IntValue : Integer ;
   Num : LongInt ;
begin
     Num := MaxInt( [Trunc(NumPoints),0] ) ;
     j := BufPointer*NumChannels + Chan ;
     if (Bufpointer+Num)*NumChannels < High(Buf) then begin
        IntValue := Trunc( DACValue ) ;
        for i := 1 to Num do begin
            Buf[j] := IntValue ;
            j := j + NumChannels ;
            end ;
        end
     else MessageDlg( ' DAC Buffer Overflow ', mtWarning, [mbOK], 0 ) ;
     BufPointer := BufPointer + Num ;
     end ;


procedure FillDigBuf( NumPoints : single ;
                      BitMask : Integer ;
                      var BPointer : LongInt ;
                      var Buf : Array of Integer ) ;
{ -------------------------------------------------------------
  Set or clear the bit defined by "BitMask" in the series of "NumPoints"
  16 bit integer in the array "Buf", starting at "BPointer"
  Note. If a bit-set operation is required, BitMask should have that bit
  set to 1 (all others 0). For bit-clear operations, the required bit is
  set to 0, (all other bits to 1).
  ---------------------------------------------------------------------}
var
   i : Longint ;
   AndMask,Bit : Integer ;
   Num : LongInt ;
   SetBit : Boolean ;
begin
     { If more than one bit is set in BitMask, a bit clear operation is required }
     SetBit := False ;
     Bit := 1 ;
     for i := 0 to 7 do begin
         if BitMask = Bit then SetBit := True ;
         Bit := Bit shl 1 ;
         end ;

     Num := MaxInt( [Trunc(NumPoints),0] ) ;
     if (BPointer+Num) < High(Buf) then begin
        if SetBit then begin
           { Set the bit defined by BitMask }
           for i := 1 to Num do begin
               Buf[BPointer] := Buf[BPointer] or BitMask ;
               Inc(BPointer) ;
               end ;
           end
        else begin
           { Clear the bit defined by BitMask, all other bits left untouched }
           for i := 1 to Num do begin
               Buf[BPointer] := Buf[BPointer] and BitMask ;
               Inc(BPointer) ;
               end ;
           end ;
        end
     else MessageDlg( ' Digital Buffer Overflow ', mtWarning, [mbOK], 0 ) ;
     end ;


procedure LoadVProgramFromFile( const FileName : string ;
                                var VProgram : TWaveform ) ;
{ --------------------------------
  Load a voltage program from file
  --------------------------------}
var
   FileHandle : Integer ;
begin
        VProgram.FileName := ReplaceFileEnding( FileName, '.vpr' ) ;
        FileHandle := FileOpen(  VProgram.FileName, fmOpenReadWrite ) ;
        if Sizeof(VProgram) <> FileRead(FileHandle,VProgram,Sizeof(VProgram))then
           MessageDlg(' LoadVProgramFromFile : File Read - Failed ',
                        mtWarning, [mbOK], 0 ) ;
        FileClose( FileHandle ) ;

        VProgram.Saved := True ;
        VProgram.RecordIntervalChanged := False ;
        end ;


procedure CreateVProgramList( var cbList : TComboBox ) ;
{ --------------------------------------------
  Compile a list of protocol files in the directory \winwcp\vprot
  and put the file names into a combo box
  --------------------------------------------------------------}
var
   SearchRec : TSearchRec ;
   First : Boolean ;
   Err : Integer ;
begin
     First := True ;
     cbList.Clear ;
     cbList.items.add( '' ) ;
     repeat
           if First then
                Err := FindFirst( Settings.VProtDirectory + '*.vpr',
                       faAnyFile, SearchRec )
           else Err := FindNext( SearchRec ) ;
           if Err = 0 then
                  { Add file name (no extension or path) to list }
                  cbList.items.Add( ExtractFileNameOnly( SearchRec.Name ) );
           First := False ;
           Until Err < 0 ;
     end ;


procedure ProtocolDuration( const Wfm : TWaveform ;
                             var TMin,Total : single ) ;
{ --------------------------------------------
  Calculate total duration of voltage protocol
  Returns TMin = Smallest pulse duration
          Total = Total protocol duration
  --------------------------------------------}

var
   i,NumExtra : Integer ;
   DigTotal,TotalRecordingTime,WriteToFileTime : Single ;
begin

     { Add up time taken by all active waveform shapes }
     Total := WaveformCreationTime ;
     DigTotal := WaveformCreationTime ;
     NumExtra := Wfm.NumSteps - 1 ;
     TMin := 1E30 ;
     for i := 0 to High(Wfm.Shape) do begin
            case Wfm.Shape[i] of
                 { Analogue voltage waveforms. Occur one after the other
                   on DAC O/P channel 0) }
                 wvStep0 :   begin
                         Total := Total + Wfm.Duration[i] + Wfm.Delay[i] ;
                         TMin := MinFlt([Wfm.Duration[i],TMin]) ;
                         end ;
                 wvStep1 : begin
                         Total := Total + Wfm.Duration[i] + Wfm.Delay[i] ;
                         TMin := MinFlt([Wfm.Duration[i],TMin]) ;
                         end ;
                 wvStep2 : begin
                         Total := Total + Wfm.Duration[i] + Wfm.Delay[i]
                                  + MaxFlt([Wfm.Increment[i]*NumExtra,0. ]) ;
                         TMin := MinFlt([Wfm.Duration[i],TMin]) ;
                         end ;
                 wvRamp : begin
                         Total := Total + Wfm.Duration[i] + Wfm.Delay[i] ;
                         TMin := MinFlt([Wfm.Duration[i],TMin]) ;
                         end ;
                 wvPTrain : begin
                         Total := Total + (Wfm.Delay[i] +
                                  + Wfm.NumPulses[i]*Wfm.PulseInterval[i]) ;
                         TMin := MinFlt([Wfm.Duration[i],TMin]) ;
                         end ;
                 wvWave : begin
                         Total := Total + (Wfm.ExtEndOfData+1)*Wfm.DACdt ;
                         TMin := Wfm.DACdt ;
                         end ;

                 { Digital waveforms. Each waveform output simultaneously (on bits 0..7) }
                 wvDigStep0 : begin
                         DigTotal := MaxFlt([DigTotal,
                                             Wfm.Delay[i] + Wfm.Duration[i] ]) ;
                         TMin := MinFlt([Wfm.Duration[i],TMin]) ;
                         end ;
                 wvDigStep1 : begin
                         DigTotal := MaxFlt([DigTotal,
                                          Wfm.Delay[i] + Wfm.Duration[i],
                                         (Wfm.Delay[i] + Wfm.Duration[i] +
                                          Wfm.Increment[i]*NumExtra) ] ) ;
                         TMin := MinFlt([Wfm.Duration[i],TMin]) ;
                         end ;
                 wvDigTrain : begin
                         DigTotal := MaxFlt([DigTotal,
                                          (Wfm.Delay[i] +
                                          Wfm.NumPulses[i]*Wfm.PulseInterval[i])]) ;
                         TMin := MinFlt([Wfm.Duration[i],TMin]) ;
                         end ;
                 end ;
         end ;

     { Calculate total duration of stimulus waveform
       (Note. digital pulse waveforms taken into account) }
     DigTotal := DigTotal*1.1 ;
     Total := MaxFlt( [Total*1.1,DigTotal] ) ;

     { Estimated time taken to write record to file }
     if Settings.SectorWriteTime <= 0. then FindSectorWriteTime ;
     WriteToFileTime := (RawFH.NumBytesPerRecord div 512)
                        *Settings.SectorWriteTime*1.25 + 0.06 ;

     { If he recording sweep time is greater than the
       total waveform protocol time ... use it for the total }
     TotalRecordingTime := Wfm.RecordDuration + Wfm.RecordDelay
                           + (Wfm.RecordDelayIncrement*NumExtra)
                           + WriteToFileTime ;

     if Total < TotalRecordingTime then Total := TotalRecordingTime ;
     { Ensure Tmin does not exceed total duration }
     TMin := MinFlt([Total,TMin]) ;

     end ;


procedure SetBits( Inverted : boolean ; Bit : Integer ;
                   var OnBit,OffBit : Integer ) ;
var
   BitSet : Array[0..7] of Integer ;
   BitClear : Array[0..7] of Integer ;
   BitPos,i : Integer ;
begin
     BitPos := 1 ;
     for i := 0 to High(BitSet) do begin
         BitSet[i] := BitPos ;
         BitClear[i] := not BitSet[i] ;
         BitPos := BitPos shl 1 ;
         end ;

     if Inverted then begin
        OffBit := BitSet[Bit] ;
        OnBit := BitClear[Bit] ;
        end
     else begin
        OffBit := BitClear[Bit] ;
        OnBit := BitSet[Bit] ;
        end ;
     end ;

procedure FindSectorWriteTime ;
{ -------------------------------------------------------------
  Find out how long it takes to write a 512 byte sector to disk
  -------------------------------------------------------------}
const
     NumRecords = 100 ;
var
   Buf : ^TIntArray ; { Temp Buffer }
   i,NumSectors : LongInt ;
   TimeStart,TimeEnd : LongInt ;
   TempFH : TFileHeader ;
   rh : TRecHeader ;
begin
     try
        New(Buf) ;
        {Open a temporary file }
        TempFH := RawFH ;
        TempFH.FileName := Settings.ProgDirectory + 'wcpAXTRE.tmp' ;
        TempFH.FileHandle := FileCreate( TempFH.FileName ) ;
        NumSectors := TempFH.NumBytesPerRecord div 512 ;
        TimeStart := TimeInMilliseconds ;
        { Write a block of records to see how long it takes }
        for i := 1 to NumRecords do PutRecord( TempFH, rh, i, Buf^ ) ;
        TimeEnd := TimeInMilliseconds ;
        Settings.SectorWriteTime := MsToSecs * (TimeEnd - TimeStart)/
                                   (NumSectors*NumRecords) ;

        WriteToLogFile( format(' Sector write time = %.1f ms',
                        [Settings.SectorWriteTime*SecsToms]) );
        { Close and remove the file }
        FileClose( TempFH.FileHandle ) ;
        DeleteFile( TempFH.Filename ) ;
     finally
            Dispose(Buf) ;
            end ;
     end ;

end.
