unit u_main;

// Purpose: Main form with control- status and data display functions

{$mode objfpc}{$H+}

// Collapse all procedures:  alt shift 1
// DeCollapse all procedures:  alt shift 0

interface

uses
  Classes, SysUtils, Forms, Controls, Graphics, Dialogs,
  ExtCtrls, StdCtrls, Buttons, ComCtrls, u_scope, u_compass;

type { TFrmMain }

  TFrmMain = class (TForm)
    ButtChangeParameters1: TButton;
    ButtChangeParameters: TButton;
    ButtClearCompass: TButton;
    ButtClearSelf: TButton;
    ButtClearMemo: TButton;
    Button1: TButton;
    ButtOtherHalf1: TButton;
    ButtOtherHalf4: TButton;
    ButtReSync1: TButton;
    ButtReSync4: TButton;
    ButtSaveCompass: TButton;
    ButtEnterComment: TButton;
    ButtNewFileName: TButton;
    ButtResetArduino: TButton;
    ButtRefreshTimeDisplay: TButton;
    ButtSaveLinGraph: TButton;
    ButtSetDefaultParameters1: TButton;
    ButtSetDefaultParameters4: TButton;
    CbxAutoZeroPositionData: TCheckBox;
    CbxEnableDrive: TCheckBox;
    CbxEnableDrive1: TCheckBox;
    CbxShowCenterPassBlip: TCheckBox;
    CbxShowFarestBlip: TCheckBox;
    CbxShowAveragedFarestBlip: TCheckBox;
    CbxForceMaximumDriveCurrent1: TCheckBox;
    CbxForceMinimumDriveCurrent1: TCheckBox;
    CbxLogPMS: TCheckBox;
    CbxShowAC_Mag: TCheckBox;
    CbxEnableDetectorCenterPass_Mag: TCheckBox;
    CbxEnableDetectorCenterPass_Cap: TCheckBox;
    CbxShowMajorAxis: TCheckBox;
    CbxShowFrmResonance1: TCheckBox;
    CbxShowFormLargeADC: TCheckBox;
    CbxPositionOnly: TCheckBox;
    CbxAutoSave: TCheckBox;
    CbxForceMaximumDriveCurrent: TCheckBox;
    CbxForceMinimumDriveCurrent: TCheckBox;
    CbxEnlarge: TCheckBox;
    CbxPersistence: TCheckBox;
    CbxShowAC_Cap: TCheckBox;
    CbxShowPendulumAmplitude: TCheckBox;
    CbxShowFormCorrections: TCheckBox;
    CbxShowPrecessionAngle: TCheckBox;
    CbxShowMinorAxis: TCheckBox;
    CbxShowHours: TCheckBox;
    CbxShowDriveStrength: TCheckBox;
    CbxShowCenterWidth_Cap: TCheckBox;
    CbxTalk: TCheckBox;
    CbxCalibratePMS: TCheckBox;
    GbxDriveParameters: TGroupBox;
    GbxParameters1: TGroupBox;
    GbxCenterParameters: TGroupBox;
    GbxRimParameters: TGroupBox;
    GbxAmplitudeControl: TGroupBox;
    GbxResonanceParameters: TGroupBox;
    GroupBox2: TGroupBox;
    GbxCommunication: TGroupBox;
    GbxPMS: TGroupBox;
    GbxStatus: TGroupBox;
    GbxGeneral: TGroupBox;
    GbxTimeDisplay: TGroupBox;
    GbxCompassDisplay: TGroupBox;
    GroupBox3: TGroupBox;
    GroupBox4: TGroupBox;
    GroupBox5: TGroupBox;
    GroupBox6: TGroupBox;
    GroupBox7: TGroupBox;
    Label100: TLabel;
    Label101: TLabel;
    Label102: TLabel;
    Label103: TLabel;
    Label104: TLabel;
    Label105: TLabel;
    Label106: TLabel;
    Label107: TLabel;
    Label108: TLabel;
    Label109: TLabel;
    Label110: TLabel;
    Label111: TLabel;
    Label112: TLabel;
    Label113: TLabel;
    Label114: TLabel;
    Label115: TLabel;
    Label116: TLabel;
    Label117: TLabel;
    Label118: TLabel;
    Label119: TLabel;
    Label120: TLabel;
    Label121: TLabel;
    Label122: TLabel;
    Label123: TLabel;
    Label124: TLabel;
    Label125: TLabel;
    Label128: TLabel;
    Label129: TLabel;
    Label130: TLabel;
    Label131: TLabel;
    Label132: TLabel;
    Label133: TLabel;
    Label134: TLabel;
    Label135: TLabel;
    Label136: TLabel;
    Label137: TLabel;
    Label138: TLabel;
    Label139: TLabel;
    Label14: TLabel;
    Label140: TLabel;
    Label141: TLabel;
    Label142: TLabel;
    Label143: TLabel;
    Label144: TLabel;
    Label145: TLabel;
    Label146: TLabel;
    Label147: TLabel;
    Label148: TLabel;
    Label149: TLabel;
    Label15: TLabel;
    Label150: TLabel;
    Label151: TLabel;
    Label152: TLabel;
    Label16: TLabel;
    Label17: TLabel;
    Label27: TLabel;
    Label39: TLabel;
    Label40: TLabel;
    Label41: TLabel;
    Label42: TLabel;
    Label43: TLabel;
    Label46: TLabel;
    Label47: TLabel;
    Label48: TLabel;
    Label49: TLabel;
    Label50: TLabel;
    Label51: TLabel;
    Label52: TLabel;
    Label53: TLabel;
    Label54: TLabel;
    Label55: TLabel;
    Label56: TLabel;
    Label57: TLabel;
    Label58: TLabel;
    Label59: TLabel;
    Label60: TLabel;
    Label61: TLabel;
    Label62: TLabel;
    Label63: TLabel;
    Label64: TLabel;
    Label65: TLabel;
    Label66: TLabel;
    Label67: TLabel;
    Label68: TLabel;
    Label69: TLabel;
    Label71: TLabel;
    Label72: TLabel;
    Label73: TLabel;
    Label74: TLabel;
    Label75: TLabel;
    Label76: TLabel;
    Label77: TLabel;
    Label78: TLabel;
    Label79: TLabel;
    Label80: TLabel;
    Label81: TLabel;
    Label82: TLabel;
    Label83: TLabel;
    Label84: TLabel;
    Label85: TLabel;
    Label86: TLabel;
    Label87: TLabel;
    Label88: TLabel;
    Label89: TLabel;
    Label90: TLabel;
    Label91: TLabel;
    Label92: TLabel;
    Label93: TLabel;
    Label96: TLabel;
    Label97: TLabel;
    Label98: TLabel;
    Label99: TLabel;
    LblDaysOfOperation: TLabel;
    Label94: TLabel;
    Label95: TLabel;
    LblStatusBit27: TLabel;
    LblStatusSeenRim2_Mag: TLabel;
    LblStatusBit22: TLabel;
    LblStatusBit23: TLabel;
    LblStatusBME280Error: TLabel;
    LblStatusBit26: TLabel;
    LblStatusBit28: TLabel;
    LblStatusMinDriveLevel: TLabel;
    LblStatusDidReSyncMySelf: TLabel;
    LblStatusGeneralError: TLabel;
    LblStatusBit20: TLabel;
    LblStatusBit21: TLabel;
    LblStatusHalfSwing: TLabel;
    LblStatusBit24: TLabel;
    LblStatusHaveSync: TLabel;
    LblStatusMaxDriveLevel: TLabel;
    LblStatusMissedRim2_Mag: TLabel;
    LblStatusBit14: TLabel;
    LblStatusBit25: TLabel;
    LblOverRangeCenter_Mag: TLabel;
    LblOverRangeRim2_Mag: TLabel;
    LblOverRangeCenter_Cap: TLabel;
    LblStatusSeenCenter_Mag: TLabel;
    LblStatusMissedcenter_Cap: TLabel;
    LblStatusSeenCenter_Cap: TLabel;
    LblStatusMissedCenter_Mag: TLabel;
    LblStatusDDS_FrequencyChanged: TLabel;
    LblStatusMissedRim1_Mag: TLabel;
    LblStatusCharron: TLabel;
    LblStatusSeenRim1_Mag: TLabel;
    LblStatusBit10: TLabel;
    LblOverRangeRim1_Mag: TLabel;
    RBMemoShowNone: TRadioButton;
    RBMemoShowTDiffCenter_Cap: TRadioButton;
    RBMemoShowADiffRim1_Mag: TRadioButton;
    RBMemoShowTDiffRim1_Mag: TRadioButton;
    RBMemoShowTDiffCenter_Mag: TRadioButton;
    RB10: TRadioButton;
    RBRimSyncByCenter_Cap: TRadioButton;
    RBRimSyncByNone: TRadioButton;
    RBSyncCapacitive1: TRadioButton;
    Rb5hour: TRadioButton;
    RB1hour: TRadioButton;
    RB1Quarter: TRadioButton;
    RB60: TRadioButton;
    RB300: TRadioButton;
    RBSyncResonance: TRadioButton;
    RBSyncMagnetic1: TRadioButton;
    RBRimSyncByCenter_Mag: TRadioButton;
    RBUseNoAmplitudeControl: TRadioButton;
    RBSyncCenter_Mag: TRadioButton;
    RBSyncCenter_Cap: TRadioButton;
    RBSyncCharron: TRadioButton;
    RBUseRimMagForAmplitudeControl: TRadioButton;
    RBUseCenterCapForAmplitudeControl: TRadioButton;
    TbxABaseCenter_Cap1: TEdit;
    TbxABaseCenter_Cap: TEdit;
    TbxAdcRim_Cap: TEdit;
    TbxAPeakRim1Diff_Mag: TEdit;
    TbxCalibrateEllipseAxis_mm: TEdit;
    TbxTargetGainCalibration: TEdit;
    TbxPeriodTime_ticks: TEdit;
    TbxTDiffRim1_Mag: TEdit;
    TbxWidthCenter_Cap: TEdit;
    TbxAdcCenter_Cap1: TEdit;
    TbxAdcCenter_Cap: TEdit;
    TbxAdcCenter_Mag1: TEdit;
    TbxAdcCenter_Mag: TEdit;
    TbxAdcRim_Mag: TEdit;
    TbxAmplitudeFromRim_mm1: TEdit;
    TbxAPeakCenter_Mag1: TEdit;
    TbxAMidCenter_Mag: TEdit;
    TbxCalFactor_Amplitude1: TEdit;
    TbxRimCoilRadius_mm: TEdit;
    TbxTargetAmplitudeRim_Mag_ticks: TEdit;
    TbxCenterElectrodeRadius_mm: TEdit;
    TbxTargetAmplitudeCenterWidth_Cap_ticks: TEdit;
    TbxControlFrequency: TEdit;
    TbxControlPeriod: TEdit;
    TbxDDS_FrequencyOut: TEdit;
    TbxDDS_FrequencyWord: TEdit;
    TbxDDS_XtalFrequency: TEdit;
    TbxDivider_Final: TEdit;
    TbxDivider_T5: TEdit;
    TbxDivider_T5_Out: TEdit;
    TbxDriveMaximalCurrent1: TEdit;
    TbxDrive_MinimalCurrent1: TEdit;
    TbxDrive_Position1: TEdit;
    TbxDrive_Width1: TEdit;
    TbxHalfHeightCenter_Cap1: TEdit;
    TbxTPasscenter_Cap: TEdit;
    TbxComment: TEdit;
    TbxCompassScale: TEdit;
    TbxDrive_Width: TEdit;
    TbxEllipseRatio_Percent: TEdit;
    TbxAutoZeroEW: TEdit;
    TbxAutoZeroNS: TEdit;
    TbxTPassCenter_Mag: TEdit;
    TbxTPassRim2_Mag: TEdit;
    TbxTPassRim1_Mag: TEdit;
    TbxPeakCenter_Cap1: TEdit;
    TbxHalfHeightCenter_Cap: TEdit;
    TbxAMidRim_Mag: TEdit;
    TbxSetPoint_Amplitude_mm1: TEdit;
    TbxSetPoint_Amplitude_mm: TEdit;
    TbxTMissedCenter1: TEdit;
    TbxTStartLookForCenter_Cap: TEdit;
    TbxTMissedCenter_Cap: TEdit;
    TbxTStartLookForRim2_Mag: TEdit;
    TbxTMissedRim2_Mag: TEdit;
    TbxTPassCenter_Cap1: TEdit;
    TbxAPeakCenter_Cap: TEdit;
    TbxPMSZeroAverageFactor: TEdit;
    TbxBME_Temperature: TEdit;
    TbxBME_Hygro: TEdit;
    TbxBME_Baro: TEdit;
    TbxDrive_MinimalCurrent: TEdit;
    TbxFarestNS: TEdit;
    TbxPrecessionAngle: TEdit;
    TbxFarestEW: TEdit;
    TbxArduinoIP: TEdit;
    TbxCurrentTime: TEdit;
    TbxEast: TEdit;
    TbxEllipseMajorAxis: TEdit;
    TbxEllipseMinorAxis: TEdit;
    TbxFirmwareBuildDate: TEdit;
    TbxInMessage: TEdit;
    TbxInMessageCount: TEdit;
    TbxInMessageLength: TEdit;
    TbxLastCleared: TEdit;
    TbxLogFileName: TEdit;
    TbxNorth: TEdit;
    TbxOutMessage: TEdit;
    TbxOutMessageCount: TEdit;
    TbxOutMessageLength: TEdit;
    TbxPosEW: TEdit;
    TbxPosNS: TEdit;
    TbxSouth: TEdit;
    Memo: TMemo;
    TbxAPeakRim2_Mag: TEdit;
    TbxTPassCenter_Mag1: TEdit;
    TbxAPeakCenter_Mag: TEdit;
    TbxDrive_Position: TEdit;
    TbxDrive_MaximalCurrent: TEdit;
    TbxAPeakRim1_Mag: TEdit;
    TbxTStartLookForCenter1: TEdit;
    TbxTStartLookForCenter_Mag: TEdit;
    TbxTMissedCenter_Mag: TEdit;
    TbxTStartLookForRim1_Mag: TEdit;
    TbxTMissedRim1_Mag: TEdit;
    TbxWest: TEdit;
    TbxWidthCenter_Cap1: TEdit;
    TimerSixMinutes: TTimer;
    TimerSend: TTimer;
    TimerScreenShot: TTimer;
    TimerDaysOfOperation: TTimer;
    UdDivider_T5: TUpDown;
    UdFrequencyWord: TUpDown;
    procedure ButtChangeParametersClick (Sender: TObject);
    procedure ButtClearCompassClick (Sender: TObject);
    procedure ButtClearSelfClick (Sender: TObject);
    procedure ButtClearMemoClick (Sender: TObject);
    procedure ButtEnterCommentClick (Sender: TObject);
    procedure ButtNewFileNameClick (Sender: TObject);
    procedure Button1Click(Sender: TObject);
    procedure ButtOtherHalfClick (Sender: TObject);
    procedure ButtRefreshTimeDisplayClick (Sender: TObject);
    procedure ButtResetArduinoClick (Sender: TObject);
    procedure ButtReSyncClick (Sender: TObject);
    procedure ButtSaveCompassClick (Sender: TObject);
    procedure ButtSaveLinGraphClick (Sender: TObject);
    procedure ButtSetDefaultParametersClick (Sender: TObject);
    procedure CbxAutoZeroPositionDataChange (Sender: TObject);
    procedure CbxEnableDetectorCenterPass_CapChange(Sender: TObject);
    procedure CbxEnableDetectorCenterPass_MagChange(Sender: TObject);
    procedure CbxLogPMSChange (Sender: TObject);
    procedure CbxPositionOnlyChange (Sender: TObject);
    procedure CbxCalibratePMSChange (Sender: TObject);
    procedure CbxEnableDriveChange (Sender: TObject);
    procedure CbxForceMaximumDriveCurrentChange (Sender: TObject);
    procedure CbxForceMinimumDriveCurrentChange (Sender: TObject);
    procedure CbxShowFormCorrectionsChange (Sender: TObject);
    procedure CbxShowFormLargeADCChange (Sender: TObject);
    procedure CbxTalkChange (Sender: TObject);
    procedure CbxEnlargeChange (Sender: TObject);
    procedure CbxPersistenceChange (Sender: TObject);
    procedure FormClick(Sender: TObject);
    procedure RBMemoShowNoneChange(Sender: TObject);
    procedure RBMemoShowTDiffRim1_MagChange(Sender: TObject);
    procedure RBMemoShowTDiffCenter_CapChange(Sender: TObject);
    procedure RBMemoShowADiffRim1_MagChange(Sender: TObject);
    procedure RBMemoShowTDiffCenter_MagChange(Sender: TObject);
    procedure RBRimSyncByCenter_CapChange(Sender: TObject);
    procedure RBRimSyncByNoneChange(Sender: TObject);
    procedure RBSyncCenter_CapChange(Sender: TObject);
    procedure RBSyncCenter_MagChange (Sender: TObject);
    procedure RBSyncResonanceChange(Sender: TObject);
    procedure RBSyncCharronChange(Sender: TObject);
    procedure RBRimSyncByCenter_MagChange(Sender: TObject);
    procedure RBUseNoAmplitudeControlChange (Sender: TObject);
    procedure RBUseRimMagForAmplitudeControlChange (Sender: TObject);
    procedure RBUseCenterCapForAmplitudeControlChange (Sender: TObject);
    procedure TbxCalibrateEllipseAxis_mmChange(Sender: TObject);
    procedure TimerDaysOfOperationTimer (Sender: TObject);
    procedure TimerScreenShotTimer (Sender: TObject);
    procedure TimerSendTimer (Sender: TObject);
    procedure FormDestroy (Sender: TObject);
    procedure FormCreate (Sender: TObject);
    procedure TimerSixMinutesTimer (Sender: TObject);
    procedure UdDivider_T5Click (Sender: TObject; Button: TUDBtnType);
    procedure UdFrequencyWordClick (Sender: TObject; Button: TUDBtnType);
  private
    { private declarations }
  public
    { public declarations }
  end;

const
  VERSIONSTRING ='v 2025-11-03';
  VERSIONNUMBER = 251103;
  TITLE = 'Logging Foucault Pendulum ';

  // Position of TimeDisplay
  TimeDisplay_Left = 6;
  TimeDisplay_Top = 6;
  TimeDisplay_Num_Xdivs = 10;
  TimeDisplay_Num_Ydivs = 8;
  TimeDisplay_Num_XpixPerDiv = 50;
  TimeDisplay_Num_YpixPerDiv = 40;
  TimeDisplay_GridColor = clWhite;
  // Position of Compass:
  Compass_Left = 513;
  Compass_Top = 2;
  Compass_Size = 330;

var
  // Form
  FrmMain: TFrmMain;
  TimeDisplay: tScope;
  Compass: tCompass;
  ParameterFilename: shortstring;
  MemoShowTDiffCenter_Mag,
  MemoShowTDiffCenter_Cap,
  MemoShowTDiffRim1_Mag,
  MemoShowADiffRim1_Mag,
  StoreInEEPROM, MadeCompassScreenShot,
  CompassIsInitialized, TimeDisplayIsInitialized: boolean;

  // GroupBox General
  OStype, Slash: shortstring;
  ForceReSync, ClearDidReSyncMyself: boolean;

  // GroupBox Communication
  Talk, ResetArduino: boolean;

  // GroupBox Status

  // GroupBox Time Display

  // GroupBox Compass Display
  Persistence, Enlarge: boolean;

  // Groupbox Drive Parameters
type tDrive_SyncMode =
  (Drive_SyncByCharronRing = 0, Drive_SyncByCenter_Mag, Drive_SyncByCenter_Cap, Drive_SyncByResonance);
var
  Drive_SyncMode, PrevDrive_SyncMode: tDrive_SyncMode;
  TempDrive_SyncMode: integer;
  ForceMinimalDriveCurrent, ForceMaximalDriveCurrent,
  UseMinimalDriveCurrent, UseMaximalDriveCurrent,
  EnableDrive : boolean;
  TStartLookForCenter, TMissedCenter,
  SetPoint_Amplitude_mm,
  Drive_Position, Drive_Width,
  Drive_MinimalCurrent, Drive_MaximalCurrent: word;

  // GroupBox CenterParameters
  TStartLookForCenter_Mag, TMissedCenter_Mag,
  TStartLookForCenter_Cap, TMissedCenter_Cap: word;
  EnableDetectorCenterPass_Mag, EnableDetectorCenterPass_Cap,
  InvertHalfSwing: boolean;

  // GroupBox RimParameters
type tRimSyncMode = (RimSyncByNone = 0, RimSyncByCenter_Mag, RimSyncByCenter_Cap, RimSyncByTBD);
var
  RimSyncMode, PrevRimSyncMode: tRimsyncMode;
  TempRimSyncMode: integer;
  TStartLookForRim1_Mag, TMissedRim1_Mag,
  TStartLookForRim2_Mag, TMissedRim2_Mag,
  RimCoilRadius_mm: word;
  EnableDetectorRimPass_Mag: boolean;

  // GroupBox AmplitudeControl
type tAmplitudeControlMode =
  (AmplitudeControlByNone = 0, AmplitudeControlByRim_Mag, AmplitudeControlByCenter_Cap, AmplitudeControlByTBD);
var
  AmplitudeControlMode, PrevAmplitudeControlMode: tAmplitudeControlMode;
  TempAmplitudeControlMode: integer;
  CenterTarget_Cap_ticks: word;
  CenterElectrodeRadius_mm,
  CalibrateEllipseAxis_mm: real;

  // GroupBox ResonanceParameters
  DDS_XtalFrequency, DDS_FrequencyWord: longword;
  DDS_FrequencyOut, Divider_T5_Out,
  ControlFrequency, ControlPeriod: extended;
  Divider_T5, Divider_Final: word;
  SendFrequencyWord: boolean;

  // GroupBox Position Measurement System
  CalibratePMS, LogPMS,
  PositionOnly, AutoZeroPositionData,
  ShowFormLargeADC: boolean;
  PMSZeroAverageFactor: real;
  CompassScale: word;

  // We list all functions and procedures in this unit
  // exept those in the form class
  // in the order they appear below.
  procedure Compass_Init;
  procedure MemoAdd (MemoString: shortstring);
  procedure WriteParametersToTextBoxes;
  procedure ReadParametersFromTextBoxes;
  procedure WriteParametersToFile;
  function  ReadParametersFromFile: boolean;
  function CheckParameters: boolean;

implementation
{$R *.lfm}

uses u_calc, u_large_adc, u_corrections, u_logging, u_timestrings, u_messages,
     u_timedisplay, u_numstrings;

// *** GroupBox Time Display **********

procedure TFrmMain.ButtRefreshTimeDisplayClick (Sender: TObject);
begin
  TimeDisplay_Init;
  TimeDisplay_Refresh;
end;

procedure TFrmMain.ButtSaveLinGraphClick(Sender: TObject);
begin
  if TimeDisplayIsInitialized then // prevent crash
    TimeDisplay.SaveImageToFile (LoggingPath + 'TimeDisplay_' + DateTimeStamp3);
end;

// *** GroupBox Compass **********

procedure TFrmMain.CbxPersistenceChange (Sender: TObject);
begin
  Persistence:= CbxPersistence.Checked;
  ButtClearCompassClick (Sender);
end;

procedure TFrmMain.CbxEnlargeChange (Sender: TObject);
begin
  Enlarge:= CbxEnlarge.checked;
end;

procedure TFrmMain.ButtClearCompassClick (Sender: TObject);
begin
  TbxLastCleared.text:= MyTime_hms;
  Compass_Init;
  AddToEventLog ('ClearCompass Click');
end;

procedure TFrmMain.ButtSaveCompassClick (Sender: TObject);
begin
  if CompassIsInitialized then // prevent crash
    Compass.SaveImageToFile (LoggingPath + 'Compass_' + DateTimeStamp3);
end;

procedure Compass_Init;
begin
  Compass.Init (FrmMain, Compass_Left, Compass_Top, Compass_Size);
  CompassIsInitialized:= true;
end;

// *** Memo **********

procedure MemoAdd (MemoString: shortstring);
begin
  with Frmmain.Memo do
  begin
    Lines.add (MemoString);
    SelStart:= length (Text); // autoscroll
  end;
end;

// *** GroupBox General **********

procedure TFrmMain.ButtEnterCommentClick (Sender: TObject);
begin
  AddToLog('** ' + TbxComment.Text);
  AddToEventLog (TbxComment.Text);
end;

procedure TFrmMain.ButtNewFileNameClick (Sender: TObject);
begin
  NewLogFileNames;
end;

procedure TFrmMain.ButtClearSelfClick(Sender: TObject);
begin
  ClearDidReSyncMyself:= true;
end;

procedure TFrmMain.ButtChangeParametersClick (Sender: TObject);
// To be used after a manual change in a textbox
begin
  ReadParametersFromTextBoxes;
  if not CheckParameters then
  begin
    ButtChangeParameters.font.color:= clRed;
    exit;
  end
  else ButtChangeParameters.font.color:= clBlack;
  WriteParametersToFile;
  RecalculateFrequencies;
  RecalculateAmplitudeSettings;
  StoreInEEPROM:= true;  // Signal to Arduino
  AddToLog ('** Changed Parameters');
  WriteParametersToEventLog;
end;

procedure TFrmMain.ButtSetDefaultParametersClick (Sender: TObject);
begin
  // Moste values here are from my 4 m pendulum
  // You should calculate values for your own pendulum
  // Drive Parameters
  Drive_Position:=                 650;
  Drive_Width:=                     40;
  Drive_MaximalCurrent:=           800;
  Drive_MinimalCurrent:=           200;
  // Center Parameters
  TStartLookForCenter_Mag:=      40000;
  TMissedCenter_Mag:=            45000; // > HalfPeriod Time
  TStartLookForCenter_Cap:=      14200;
  TMissedCenter_Cap:=            22000;
  // Rim Parameters
  TStartLookForRim1_Mag:=         8500;
  TMissedRim1_Mag:=              10000;
  TStartLookForRim2_Mag:=        30000;
  TMissedRim2_Mag:=              35000;
  // Amplitude Control
  SetPoint_Amplitude_mm:=          230;
  RimCoilRadius_mm:=               150;
  CenterElectrodeRadius_mm:=        35.0;
  CenterTarget_Cap_ticks:=          35;
  CalibrateEllipseAxis_mm:=       1000.0;
  // Resonance Parameters
  DDS_XtalFrequency:=         25000000; // 25 MHz
  DDS_FrequencyWord:=          4992905; // for 465 kHz
  Divider_T5:=                   46500; // for 0.5 Hz
  Divider_Final:=                   20; // for 0.5 Hz
  // PMS Parameters
  PMSZeroAverageFactor:=             0.1;
  CompassScale:=                   320;

  RecalculateFrequencies;
  RecalculateAmplitudeSettings;
  WriteParametersToTextBoxes;
  WriteParametersToFile;
  AddToEventLog ('Set Default Parameters');
  WriteParametersToEventLog;
end;

procedure WriteParametersToTextBoxes; // called after set Defaults and after Read from file
begin
  with FrmMain do
  begin
    // Drive Parameters
    case TDrive_SyncMode (TempDrive_SyncMode) of
      Drive_SyncByCenter_Mag: RBSyncCenter_Mag.checked:= true;
      Drive_SyncByCenter_Cap: RBSyncCenter_Cap.checked:= true;
      Drive_SyncByCharronRing: RBSyncCharron.checked:= true;
      Drive_SyncByResonance: RBSyncResonance.checked:= true;
    end;
    Drive_SyncMode:= TDrive_SyncMode (TempDrive_SyncMode);
    TbxDrive_Position.text:=           format ('%5d',[Drive_Position]);
    TbxDrive_Width.text:=              format ('%5d',[Drive_Width]);
    TbxDrive_MaximalCurrent.text:=     format ('%4d',[Drive_MaximalCurrent]);
    TbxDrive_MinimalCurrent.text:=     format ('%4d',[Drive_MinimalCurrent]);
    // Center Parameters
    TbxTStartLookForCenter_Mag.text:=  format ('%5d',[TStartLookForCenter_Mag]);
    TbxTMissedCenter_Mag.text:=        format ('%5d',[TMissedCenter_Mag]);
    TbxTStartLookForCenter_Cap.text:=  format ('%5d',[TStartLookForCenter_Cap]);
    TbxTMissedCenter_Cap.text:=        format ('%5d',[TMissedCenter_Cap]);
    // Rim Parameters
    case tRimSyncMode (TempRimSyncMode) of
      RimSyncByCenter_Mag: RBRimSyncByCenter_Mag.checked:= true;
      RimSyncByCenter_Cap: RBRimSyncByCenter_Cap.checked:= true;
      RimSyncByNone:       RBRimSyncByNone.checked:= true;
    end;
    RimSyncMode:= tRimSyncMode (TempRimSyncMode);
    TbxTStartLookForRim1_Mag.text:=    format ('%5d',[TStartLookForRim1_Mag]);
    TbxTMissedRim1_Mag.text:=          format ('%5d',[TMissedRim1_Mag]);
    TbxTStartLookForRim2_Mag.text:=    format ('%5d',[TStartLookForRim2_Mag]);
    TbxTMissedRim2_Mag.text:=          format ('%5d',[TMissedRim2_Mag]);
    // Amplitude Control
    case tAmplitudeControlMode (TempAmplitudeControlMode) of
      AmplitudeControlByRim_Mag:    RBUseRimMagForAmplitudeControl.checked:= true;
      AmplitudeControlByCenter_Cap: RBUseCenterCapForAmplitudeControl.checked:= true;
      AmplitudeControlByNone:       RBUseNoAmplitudeControl.checked:= true;
    end;
    AmplitudeControlMode:= tAmplitudeControlMode (TempAmplitudeControlMode);
    TbxSetPoint_Amplitude_mm.text:=    format ('%4d',[SetPoint_Amplitude_mm]);
    TbxRimCoilRadius_mm.text:=         format ('%4d',[RimCoilRadius_mm]);
    TbxCenterElectrodeRadius_mm.text:= format ('%5.2f',[CenterElectrodeRadius_mm]);
    TbxTargetAmplitudeCenterWidth_Cap_ticks.text:=  format ('%4d',[CenterTarget_Cap_ticks]);
    TbxCalibrateEllipseAxis_mm.text:=  format ('%7.2f', [CalibrateEllipseAxis_mm]);
    // Resonance Parameters
    TbxDDS_XtalFrequency.text:=        format ('%10d',[DDS_XtalFrequency]);
    TbxDDS_FrequencyWord.text:=        format ('%10d',[DDS_FrequencyWord]);
    TbxDivider_T5.text:=               format ('%5d',[Divider_T5]);
    TbxDivider_Final.text:=            format ('%5d',[Divider_Final]);
    // PMS
    TbxPMSZeroAverageFactor.text:=     format ('%4.2f',[PMSZeroAverageFactor]);
    TbxCompassScale.text:=             format ('%3d',[CompassScale])
  end;
end;

procedure ReadParametersFromTextBoxes;
begin
  with FrmMain do
  begin
    // Drive Parameters
    Drive_Position:=            Fival (TbxDrive_Position.text);
    Drive_Width:=               Fival (TbxDrive_Width.text);
    Drive_MaximalCurrent:=      Fival (TbxDrive_MaximalCurrent.text);
    Drive_MinimalCurrent:=      Fival (TbxDrive_MinimalCurrent.text);
    // Center Parameters
    TStartLookForCenter_Mag:=   Fival (TbxTStartLookForCenter_Mag.text);
    TMissedCenter_Mag:=         Fival (TbxTMissedCenter_Mag.text);
    TStartLookForCenter_Cap:=   Fival (TbxTStartLookForCenter_Cap.text);
    TStartLookForCenter_Cap:=   Fival (TbxTStartLookForCenter_Cap.text);
    // Rim Parameters
    TStartLookForRim1_Mag:=     Fival (TbxTStartLookForRim1_Mag.text);
    TMissedRim1_Mag:=           Fival (TbxTMissedRim1_Mag.text);
    TStartLookForRim2_Mag:=     Fival (TbxTStartLookForRim2_Mag.text);
    TMissedRim2_Mag:=           Fival (TbxTMissedRim2_Mag.text);
    // Amplitude Control
    SetPoint_Amplitude_mm:=     Fival (TbxSetPoint_Amplitude_mm.text);
    RimCoilRadius_mm:=          Fival (TbxRimCoilRadius_mm.text);
    CenterElectrodeRadius_mm:=  Frval (TbxCenterElectrodeRadius_mm.text);
    CenterTarget_Cap_ticks:=    Fival (TbxTargetAmplitudeCenterWidth_Cap_ticks.text);
    CalibrateEllipseAxis_mm:=   Frval (TbxCalibrateEllipseAxis_mm.text);
    // Resonance Parameters
    DDS_XtalFrequency:=         Fival (TbxDDS_XtalFrequency.text);
    Divider_T5:=                Fival (TbxDivider_T5.text);
    Divider_Final:=             Fival (TbxDivider_Final.text);
    // PMS
    PMSZeroAverageFactor:=      Frval (TbxPMSZeroAverageFactor.text);
    CompassScale:=              Fival (TbxCompassScale.text);
  end;
  RecalculateAmplitudeSettings;
  RecalculateFrequencies;
end;

procedure WriteParametersToFile;
var
  ParameterFile: text;
begin
  ReadParametersFromTextBoxes;
  assign (ParameterFile, ParameterFileName);
  rewrite (ParameterFile);
  // Drive Parameters
  writeln (ParameterFile, ord (Drive_SyncMode));
  writeln (ParameterFile, Drive_Position);
  writeln (ParameterFile, Drive_Width);
  writeln (ParameterFile, Drive_MaximalCurrent);
  writeln (ParameterFile, Drive_MinimalCurrent);
  // Center Parameters
  writeln (ParameterFile, EnableDetectorCenterPass_Mag);
  writeln (ParameterFile, EnableDetectorCenterPass_Cap);
  writeln (ParameterFile, TStartLookForCenter_Mag);
  writeln (ParameterFile, TMissedCenter_Mag);
  writeln (ParameterFile, TStartLookForCenter_Cap);
  writeln (ParameterFile, TMissedCenter_Cap);
  // Rim Parameters
  writeln (ParameterFile, ord (RimSyncMode));
  writeln (ParameterFile, TStartLookForRim1_Mag);
  writeln (ParameterFile, TMissedRim1_Mag);
  writeln (ParameterFile, TStartLookForRim2_Mag);
  writeln (ParameterFile, TMissedRim2_Mag);
  // Amplitude Control
  writeln (ParameterFile, ord (AmplitudeControlMode));
  writeln (ParameterFile, SetPoint_Amplitude_mm);
  writeln (ParameterFile, RimCoilRadius_mm);
  writeln (ParameterFile, CenterElectrodeRadius_mm);
  writeln (ParameterFile, CenterTarget_Cap_ticks);
  writeln (ParameterFile, CalibrateEllipseAxis_mm);
  // Resonance Parameters
  writeln (ParameterFile, DDS_XtalFrequency);
  writeln (ParameterFile, Divider_T5);
  writeln (ParameterFile, Divider_Final);
  // PMS Parameters
  writeln (ParameterFile, PMSZeroAverageFactor);
  writeln (ParameterFile, CompassScale );
  Close (ParameterFile);
end;

function ReadParametersFromFile : boolean;
var
  ParameterFile: text;
  Str: shortstring;
  Ival: integer;
begin
  if not FileExists (ParameterFileName) then exit (false);
  assign (ParameterFile, ParameterFileName);
  reset (ParameterFile);
  with FrmMain do
  begin
    // Drive Parameters
    readln (ParameterFile, TempDrive_SyncMode);
    readln (ParameterFile, Drive_Position);
    readln (ParameterFile, Drive_Width);
    readln (ParameterFile, Drive_MaximalCurrent);
    readln (ParameterFile, Drive_MinimalCurrent);
    // Center Parameters
    readln (ParameterFile, Str); CbxEnableDetectorCenterPass_Mag.checked:= (Str = 'TRUE');
    readln (ParameterFile, Str); CbxEnableDetectorCenterPass_Cap.checked:= (Str = 'TRUE');
    readln (ParameterFile, TStartLookForCenter_Mag);
    readln (ParameterFile, TMissedCenter_Mag);
    readln (ParameterFile, TStartLookForCenter_Cap);
    readln (ParameterFile, TMissedCenter_Cap);
    // Rim Parameters
    readln (ParameterFile, TempRimSyncMode);
    readln (ParameterFile, TStartLookForRim1_Mag);
    readln (ParameterFile, TMissedRim1_Mag);
    readln (ParameterFile, TStartLookForRim2_Mag);
    readln (ParameterFile, TMissedRim2_Mag);
    // Amplitude Control
    readln (ParameterFile, TempAmplitudeControlMode);
    readln (ParameterFile, SetPoint_Amplitude_mm);
    readln (ParameterFile, RimCoilRadius_mm);
    readln (ParameterFile, CenterElectrodeRadius_mm);
    readln (ParameterFile, CenterTarget_Cap_ticks);
    readln (ParameterFile, CalibrateEllipseAxis_mm);
    // Resonance Parameters
    readln (ParameterFile, DDS_XtalFrequency);
    readln (ParameterFile, Divider_T5);
    readln (ParameterFile, Divider_Final);
    // PMS Parameters
    readln (ParameterFile, PMSZeroAverageFactor);
    readln (ParameterFile, CompassScale );
  end;
  Close (ParameterFile);
  WriteParametersToTextBoxes;
  WriteParametersToEventLog;
  RecalculateFrequencies;
  RecalculateAmplitudeSettings;
end;

function CheckParameters: boolean;  // True = OK, false = error
begin
    // We do a few value checks
    Result:= true;
    if TMissedCenter_Mag <= TStartLookForCenter_Mag then
    begin
      MemoAdd ('Missed, Look Center_Mag');
      Result:= false;
    end;
    if TMissedCenter_Cap <= TStartLookForCenter_Cap then
    begin
      MemoAdd ('Missed, Look Center Cap');
      Result:= false;
    end;
    if Drive_MaximalCurrent <= Drive_MinimalCurrent then
    begin
      MemoAdd ('Min / Max Current');
      Result:= false;
    end;
    if (Drive_Width / 2) >= Drive_Position then
    begin
      MemoAdd ('Drive Mid / Width');
      Drive_Width:= 0; // prevent out of range crash
      Result:= false;
    end;
end;

// *** GroupBox Communication **********

procedure TFrmMain.CbxTalkChange (Sender: TObject);
begin
  Compass_Init;
  TimeDisplay_Init;
  TimeDisplayIsInitialized:= true;
  if CbxTalk.Checked then
    StartTalking
  else
    StopTalking;
end;

procedure TFrmMain.ButtResetArduinoClick (Sender: TObject);
begin
  ResetArduino:= true;
end;

//*****************  GroupBox Drive Parameters *******************8

procedure TFrmMain.CbxEnableDriveChange (Sender: TObject);
begin
  EnableDrive:= CbxEnableDrive.checked;
  if EnableDrive then
  begin
    AddToLog ('** Drive Enabled');
    AddtoEventLog ('Drive Enabled');
  end
  else
  begin
    AddToLog ('** Drive Disabled');
    AddtoEventLog ('Drive Disabled');
  end;
end;

procedure TFrmMain.CbxForceMaximumDriveCurrentChange (Sender: TObject);
begin
  ForceMaximalDriveCurrent:= (CbxForceMaximumDriveCurrent.checked);
  CbxForceMinimumDriveCurrent.checked:= false;
end;

procedure TFrmMain.CbxForceMinimumDriveCurrentChange (Sender: TObject);
begin
  ForceMinimalDriveCurrent:= (CbxForceMinimumDriveCurrent.checked);
  CbxForceMaximumDriveCurrent.checked:= false;
end;

// Sync mode determines which event will zero the PositionCounter
procedure TFrmMain.RBSyncCenter_MagChange (Sender: TObject);
begin
  Drive_SyncMode:= Drive_SyncByCenter_Mag;
end;

procedure TFrmMain.RBSyncCenter_CapChange (Sender: TObject);
begin
  Drive_SyncMode:= Drive_SyncByCenter_Cap;
end;

procedure TFrmMain.RBSyncCharronChange (Sender: TObject);
begin
  Drive_SyncMode:= Drive_SyncByCharronRing; // to be implemented
end;

procedure TFrmMain.RBSyncResonanceChange (Sender: TObject);
begin
  Drive_SyncMode:= Drive_SyncByResonance; // implementation to be completed
end;

procedure TFrmMain.ButtReSyncClick (Sender: TObject);
begin
  ForceResync:= true;
  AddToLog ('** ForceResync');
  AddToEventLog ('ForceResync');
end;

// *** GroupBox Center Parameters **********

procedure TFrmMain.ButtOtherHalfClick (Sender: TObject);
begin
  InvertHalfSwing:= true;
end;

// *** GroupBox Rim Parameters **********

procedure TFrmMain.RBRimSyncByCenter_MagChange (Sender: TObject);
begin
  RimSyncMode:= RimSyncByCenter_Mag;
  EnableDetectorRimPass_Mag:= true;
end;

procedure TFrmMain.RBRimSyncByCenter_CapChange (Sender: TObject);
begin
  RimSyncMode:= RimSyncByCenter_Cap;
  EnableDetectorRimPass_Mag:= true;
end;

procedure TFrmMain.RBRimSyncByNoneChange (Sender: TObject);
begin
  RimSyncMode:= RimSyncByNone;
  EnableDetectorRimPass_Mag:= false;
end;

// *** GroupBox Amplitude Control **********

procedure TFrmMain.RBUseRimMagForAmplitudeControlChange (Sender: TObject);
begin
  AmplitudeControlMode:= AmplitudeControlByRim_Mag;
end;

procedure TFrmMain.RBUseCenterCapForAmplitudeControlChange (Sender: TObject);
begin
  AmplitudeControlMode:= AmplitudeControlByCenter_Cap;
end;

procedure TFrmMain.TbxCalibrateEllipseAxis_mmChange(Sender: TObject);
begin

end;

procedure TFrmMain.RBUseNoAmplitudeControlChange (Sender: TObject);
begin
  AmplitudeControlMode:= AmplitudeControlByNone;
end;

// *** GroupBox Resonance Parameters **********

procedure TFrmMain.UdFrequencyWordClick (Sender: TObject; Button: TUDBtnType);
begin
  DDS_FrequencyWord:= fIval (TbxDDS_FrequencyWord.text);
  if Button = btNext then DDS_FrequencyWord += 70;
  if Button = btPrev then DDS_FrequencyWord -= 70;
  TbxDDS_FrequencyWord.text:= format ('%12d', [DDS_FrequencyWord]);
  RecalculateFrequencies;
end;

procedure TFrmmain.UdDivider_T5Click (Sender: TObject; Button: TUDBtnType);
begin
  Divider_T5:= fIval (TbxDivider_T5.text);
  if Button = btNext then Divider_T5 += 1;
  if Button = btPrev then Divider_T5 -= 1;
  TbxDivider_T5.text:= format ('%5d', [Divider_T5]);
  RecalculateFrequencies;
end;

// *** GroupBox Position Mesuring System **********

procedure TFrmMain.CbxCalibratePMSChange (Sender: TObject);
begin
  CalibratePMS:= CbxCalibratePMS.Checked;
end;

procedure TFrmMain.CbxAutoZeroPositionDataChange (Sender: TObject);
begin
  AutoZeroPositionData:= CbxAutoZeroPositionData.checked;
end;

procedure TFrmMain.CbxEnableDetectorCenterPass_CapChange(Sender: TObject);
begin
  EnableDetectorCenterPass_Cap:= CbxEnableDetectorCenterPass_Cap.checked;
end;

procedure TFrmMain.CbxEnableDetectorCenterPass_MagChange(Sender: TObject);
begin
  EnableDetectorCenterPass_Mag:= CbxEnableDetectorCenterPass_Mag.checked;
end;

procedure TFrmMain.CbxLogPMSChange (Sender: TObject);
begin
  LogPMS:= CbxLogPMS.checked;
end;

procedure TFrmMain.CbxPositionOnlyChange (Sender: TObject);
begin
  PositionOnly:= CbxPositionOnly.checked;
end;

procedure TFrmMain.CbxShowFormCorrectionsChange(Sender: TObject);
begin
 if CbxShowFormCorrections.checked then
   FrmCorrections.Show
 else
   FrmCorrections.Hide;
end;

procedure TFrmMain.CbxShowFormLargeADCChange (Sender: TObject);
begin
  ShowFormLargeADC:= CbxShowFormLargeADC.checked;
  if ShowFormLargeADC then
    FrmLargeADC.Show
  else
    FrmLargeADC.Hide;
end;

// *** GroupBox Status **********
// has no event handlers

// *** Timers **********

procedure TFrmMain.TimerSendTimer (Sender: TObject);  // 10 Hz
// Send a message to Arduino each 10th of a second
begin
  TbxCurrentTime.text:= MyTime_hms;
  SendAndReceiveMessage;
end;

procedure TFrmMain.TimerSixMinutesTimer (Sender: TObject); // called 1 Hertz
// update certain traces each so many minutes, such that the
// dispay scale is 5, 1, or 1/4 hours per division
const SixMinutesCounter: integer = -1;
  var MaxCounts: integer;
begin
  if Rb5hour.checked then MaxCounts:= 359;   // 5 hrs per div
  if Rb1hour.checked then MaxCounts:= 71;    // 1 hr per div
  if Rb1Quarter.checked then MaxCounts:= 17; // 1/4 hr per div
  inc (SixMinutesCounter);
  if SixMinutesCounter > MaxCounts then
  begin
    SixMinutesCounter:= 0;
    if TimeDisplayIsInitialized then TimeDisplay_Update_Slow;
  end;
end;

procedure TFrmMain.TimerScreenShotTimer (Sender: TObject); // 1 Hz
const
  Seconds: integer = 0;
  Minutes: integer = 0;
  StartSequence: boolean = false;
begin
  if not CompassIsInitialized then exit; // prevent crash
  Compass.TextLowerLeft (DateTimeStamp);
  if not CbxAutoSave.checked then exit;
  // repeatedly do screenshot of compass.
  inc (Seconds);
  if RB10.checked then
    if (Seconds mod 10) = 0 then  // 10 seconds
    begin
      StartSequence:= true;
      Seconds:= 0;
    end;
  if Seconds > 59 then // one minute
  begin
    Seconds:= 0;
    inc (Minutes);
    if RB60.checked then   // 1 minute
      StartSequence:= true;
    if RB300.checked then
      if (Minutes mod 5) = 0 then  // 5 minutes
        StartSequence:= true;
  end;

  if StartSequence then
  begin
    if Seconds = 1 then ButtClearCompassClick (Sender);
    // wait for >1 period of the pendulum to complete
    if Seconds = 6 then
    begin
      ButtSaveCompassClick (Sender);
      MadeCompassScreenShot:= true; // for logging
    end;
    if Seconds = 7 then StartSequence:= false;
  end;
end;

procedure TFrmMain.TimerDaysOfOperationTimer (Sender: TObject);
// we have noticed that this program stops working after some 13 days of
// continuous operation, for no known reason.
// This alert timer allows us to restart the program manually
// at a convenient moment, with minimal interruption
// of the data logging process.
// This timer has an interval of 1 day.
// 24 hour * 3600 sec = 86400 sec.
const DaysOfOperation: integer = 0;
begin
  inc (DaysOfOperation);
  // in GroupBox Communication
  LblDaysOfOperation.caption:= format ('%2d', [DaysOfOperation]);
end;

// *** Main Form  **********

procedure TFrmMain.FormClick (Sender: TObject);
begin
  // on some OSes clicking on the main form causes the graphs to disappear.
  // here we do a restore
  ButtRefreshTimeDisplayClick (Sender);
end;

procedure TFrmMain.RBMemoShowTDiffCenter_MagChange (Sender: TObject);
// this also shows the Diff plot on the Time Display
begin
  MemoShowTDiffCenter_Mag:= true;
  MemoShowTDiffCenter_Cap:= false;
  MemoShowTDiffRim1_Mag:= false;
  MemoShowADiffRim1_Mag:= false;
end;

procedure TFrmMain.RBMemoShowTDiffCenter_CapChange (Sender: TObject);
// this also shows the Diff plot on the Time Display
begin
  MemoShowTDiffCenter_Mag:= false;
  MemoShowTDiffCenter_Cap:= true;
  MemoShowTDiffRim1_Mag:= false;
  MemoShowADiffRim1_Mag:= false;
end;

procedure TFrmMain.RBMemoShowTDiffRim1_MagChange(Sender: TObject);
begin
  MemoShowTDiffCenter_Mag:= false;
  MemoShowTDiffCenter_Cap:= false;
  MemoShowTDiffRim1_Mag:= true;
  MemoShowADiffRim1_Mag:= false;
end;

procedure TFrmMain.RBMemoShowADiffRim1_MagChange (Sender: TObject);
// this also shows the Diff plot on the Time Display
begin
  MemoShowTDiffCenter_Mag:= false;
  MemoShowTDiffCenter_Cap:= false;
  MemoShowTDiffRim1_Mag:= false;
  MemoShowADiffRim1_Mag:= true;
end;

procedure TFrmMain.RBMemoShowNoneChange (Sender: TObject);
// this also shows the Diff plot on the Time Display
begin
  MemoShowTDiffCenter_Mag:= false;
  MemoShowTDiffCenter_Cap:= false;
  MemoShowTDiffRim1_Mag:= false;
  MemoShowADiffRim1_Mag:= false;
end;

procedure TFrmMain.ButtClearMemoClick (Sender: TObject);
begin
  Memo.clear;
end;

procedure TFrmMain.Button1Click(Sender: TObject);
begin
  // assign a function for diagnosis
end;

procedure TFrmMain.FormDestroy (Sender: TObject);
begin
  StopTalking;
  WriteParametersToFile;
end;

procedure TFrmMain.FormCreate (Sender: TObject);
begin
  // Find out on which platform we run
  {$IFDEF Linux}
    OSType:= 'Linux';
    Slash := '/';
  {$ELSE}
    {$IFDEF WINDOWS}
      OSType:= 'Windows'; // only previous versions have been tested on WXP and W7
      Slash := '\';
    {$ENDIF}
    {$IFDEF CPUARM}
      OSType:= 'RaspberryPi'; // running on RPI has not been tested. may need a very fast RPI
      Slash := '/';
    {$ENDIF}
     // t.b.d. Mac and/or other platforms
  {$ENDIF}

  // initialize the other forms
  Caption:= TITLE + VERSIONSTRING;
  Application.CreateForm (TFrmCorrections, FrmCorrections);
  Application.CreateForm (TFrmLargeADC, FrmLargeADC);
  FrmCorrections.hide;
  FrmLargeADC.hide;
  // create the display classes
  TimeDisplay:= tScope.create;
  Compass:= tCompass.create;
  // prevent problems regarding locale with ',' as decimal separator
  // so logfiles can be in comma separated format
  DefaultFormatSettings.DecimalSeparator:= '.';

  // Positions and Dimensions of the groupboxes
  with Frmmain do
  begin
    Height:= 710;
    Width:= 1278;
  end;

  with Memo do
  begin
    Left:= 844;
    Top:=  2;
    Width:= 186;
    Height:= 335;
  end;

  with GbxGeneral do
  begin
    Top:= 2;
    Left:= 1032;
    Height:= 160;
    Width:= 242;
  end;

  with GbxCommunication do
  begin
    Top:= 168;
    Left:= 1032;
    Height:= 137;
    Width:= 242;
  end;

  with GbxStatus do
  begin
    Top:= 312;
    Left:= 1095;
    Height:= 393;
    Width:= 177;
  end;

  with GbxTimeDisplay do
  begin
    Top:= 333;
    Left:= 2;
    Height:= 100;
    Width:= 510;
  end;

  with GbxCompassDisplay do
  begin
    Top:= 333;
    Left:= 513;
    Height:= 100;
    Width:= 330;
  end;

  with GbxDriveParameters do
  begin
    Top:= 435;
    Left:= 2;
    Height:= 270;
    Width:= 128;
  end;

  with GbxCenterParameters do
  begin
    Top:= 435;
    Left:= 132;
    Height:= 270;
    Width:= 166;
  end;

  with GbxRimParameters do
  begin
    Top:= 435;
    Left:= 299;
    Height:= 270;
    Width:= 168;
  end;

  with GbxAmplitudeControl do
  begin
    Top:= 435;
    Left:= 468;
    Height:= 270;
    Width:= 142;
  end;

  with GbxResonanceParameters do
  begin
    Top:= 435;
    Left:= 611;
    Height:= 270;
    Width:= 194;
  end;

  with GbxPMS do
  begin
    Top:= 435;
    Left:= 806;
    Height:= 270;
    Width:= 288;
  end;
  // Create the directory for the logfiles
  ExeDir:= Application.Location;
  if not DirectoryExists (ExeDir + 'LogFiles') then
    if not CreateDir (ExeDir + 'LogFiles') then MemoAdd ('Err Dir Logfiles');
  LoggingPath:= ExeDir + 'LogFiles' + Slash;
  NewLogFileNames;
  ParameterFilename:= LoggingPath + 'Parameters.txt';
  if not ReadParametersFromFile then
  begin
    MemoAdd ('Can''t Read Parameter File');
    MemoAdd ('Setting Defaults');
    ButtSetDefaultParametersClick (Sender);
  end;

  // we "click" several checkboxes to trigger their change event.
  CbxEnableDrive.checked:= true;
  CbxAutoZeroPositionData.checked:= true;
  Rb1Quarter.checked:= true; // Autosave Compass display
  RBMemoShowNoneChange (Sender); // to set the values correctly
  Persistence:= true;
  Init_Messages;
  //RBMemoShowNoneChange (Sender); // to set the values correctly
  FrmMain.show;
end;

begin
// no unit initialisation code
end.

