unit u_main;

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

{$mode objfpc}{$H+}
// Collapse all procedures:  alt shift 1

interface

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

type { TFrmMain }

  TFrmMain = class(TForm)
    ButtChangeParameters: TButton;
    ButtClearCompass: TButton;
    ButtClearMemo: TButton;
    ButtSaveCompass: TButton;
    ButtClearDidResetMyself: TButton;
    ButtEnterComment: TButton;
    ButtNewFileName: TButton;
    ButtOtherHalf: TButton;
    ButtResetArduino: TButton;
    ButtRefresh: TButton;
    ButtReSync: TButton;
    ButtSaveLinGraph: TButton;
    ButtSetDefaultParameters: TButton;
    CbxAutoSaveFast: TCheckBox;
    CbxAutoZero: TCheckBox;
    CbxHallOnly: TCheckBox;
    CbxLogRaw: TCheckBox;
    CbxAutoSave: TCheckBox;
    CbxMemo: TCheckBox;
    CbxPlotRim_1: TCheckBox;
    CbxPlotRim_2: TCheckBox;
    CbxForceMaximumDriveWidth: TCheckBox;
    CbxForceMinimumDriveWidth: TCheckBox;
    CbxEnableDrive: TCheckBox;
    CbxEnlarge: TCheckBox;
    CbxPersistence: TCheckBox;
    CbxShowAC: TCheckBox;
    CbxShowARim: TCheckBox;
    CbxShowPrecessionAngle: TCheckBox;
    CbxShowMinorAxis: TCheckBox;
    CbxShowTdiff: TCheckBox;
    CbxShowWidthDrive: TCheckBox;
    CbxTalk: TCheckBox;
    CbxCalibrateHallSensors: TCheckBox;
    GbxParameters: TGroupBox;
    GroupBox2: TGroupBox;
    GbxCommunication: TGroupBox;
    GbxHallSensors: TGroupBox;
    GbxStatus: TGroupBox;
    GbxGeneral: TGroupBox;
    GbxTimeDisplay: TGroupBox;
    GbxCompass: TGroupBox;
    Label104: TLabel;
    Label14: TLabel;
    Label17: TLabel;
    Label18: TLabel;
    Label19: TLabel;
    Label27: TLabel;
    Label39: TLabel;
    Label40: TLabel;
    Label41: TLabel;
    Label42: TLabel;
    Label43: TLabel;
    Label44: TLabel;
    Label45: TLabel;
    Label46: TLabel;
    Label48: TLabel;
    Label49: TLabel;
    Label50: TLabel;
    Label52: TLabel;
    Label53: TLabel;
    Label54: TLabel;
    Label55: TLabel;
    Label59: TLabel;
    Label60: TLabel;
    Label62: TLabel;
    Label65: TLabel;
    Label67: TLabel;
    Label68: TLabel;
    Label69: TLabel;
    Label70: 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;
    Label84: TLabel;
    Label85: TLabel;
    Label86: TLabel;
    Label87: TLabel;
    Label88: TLabel;
    Label89: TLabel;
    Label90: TLabel;
    Label91: TLabel;
    Label92: TLabel;
    Label93: TLabel;
    Label94: TLabel;
    Label95: TLabel;
    LblStatusSeenRim_2: TLabel;
    LblStatusDidReSyncMySelf: TLabel;
    LblStatusMaxDriveLevel: TLabel;
    LblStatusMinDriveLevel: TLabel;
    LblStatusDidResetMyself: TLabel;
    LblStatusMissedRim_2: TLabel;
    LblStatusBit14: TLabel;
    LblStatusHalfSwing: TLabel;
    LblStatusCenterMissed: TLabel;
    LblStatusCenterSeen: TLabel;
    LblStatusHaveSync: TLabel;
    LblStatusGeneralError: TLabel;
    LblStatusMissedRim_1: TLabel;
    LblStatusBit11: TLabel;
    LblStatusSeenRim_1: TLabel;
    LblStatusBit10: TLabel;
    LblTenDaysAlert: TLabel;
    LinGraph: TPaintBox;
    TbxAdcCenter: TEdit;
    TbxAdcRim: TEdit;
    TbxAmplitudeFromRim_mm: TEdit;
    TbxComment: TEdit;
    TbxCompassScale: TEdit;
    TbxEllipseRatio_Percent: TEdit;
    TbxAutoZeroEW: TEdit;
    TbxAutoZeroNS: TEdit;
    TbxPeakRim_2: TEdit;
    TbxHallZeroAverageFactor: TEdit;
    TbxSetPoint_Amplitude_mm: TEdit;
    TbxTemperatureTop: TEdit;
    TbxTemperatureBME: TEdit;
    TbxHygroBME: TEdit;
    TbxBaroBME: TEdit;
    TbxRimCoilRadius_mm: TEdit;
    TbxTMinDriveWidth: TEdit;
    TbxFarestNS: TEdit;
    TbxPrecessionAngle: TEdit;
    TbxFarestEW: TEdit;
    TbxArduinoIP: TEdit;
    TbxCurrentTime: TEdit;
    TbxEast: TEdit;
    TbxEllipseLongAxis: TEdit;
    TbxEllipseShortAxis: TEdit;
    TbxFirmwareVersion: TEdit;
    TbxInMessage: TEdit;
    TbxInMessageCount: TEdit;
    TbxInMessageLength: TEdit;
    TbxLastCleared: TEdit;
    TbxLogFileName: TEdit;
    TbxNorth: TEdit;
    TbxOutMessage: TEdit;
    TbxOutMessageCount: TEdit;
    TbxOutMessageLength: TEdit;
    TbxPeakCenter: TEdit;
    TbxPeakRim_1: TEdit;
    TbxPosEW: TEdit;
    TbxPosNS: TEdit;
    TbxSouth: TEdit;
    TbxTMissedRim_2: TEdit;
    TbxTPassRim_2: TEdit;
    TbxTStartLookForRim_1: TEdit;
    Memo: TMemo;
    TbxTStartLookForCenter: TEdit;
    TbxTDrivePosition: TEdit;
    TbxTMissedCenter: TEdit;
    TbxTMissedRim_1: TEdit;
    TbxTPassCenter: TEdit;
    TbxTPassRim_1: TEdit;
    TbxMaxDriveWidth: TEdit;
    TbxTStartLookForRim_2: TEdit;
    TbxWest: TEdit;
    TimerCheckHeap: TTimer;
    TimerBlink: TTimer;
    TimerSixMinutes: TTimer;
    TimerSend: TTimer;
    TimerScreenShot: TTimer;
    TimerTenDays: TTimer;
    procedure ButtChangeParametersClick (Sender: TObject);
    procedure ButtClearCompassClick (Sender: TObject);
    procedure ButtClearDidResetMyselfClick (Sender: TObject);
    procedure ButtClearMemoClick (Sender: TObject);
    procedure ButtEnterCommentClick (Sender: TObject);
    procedure ButtNewFileNameClick (Sender: TObject);
    procedure ButtOtherHalfClick (Sender: TObject);
    procedure ButtRefreshClick (Sender: TObject);
    procedure ButtResetArduinoClick (Sender: TObject);
    procedure ButtReSyncClick (Sender: TObject);
    procedure ButtSaveCompassClick (Sender: TObject);
    procedure ButtSaveLinGraphClick (Sender: TObject);
    procedure ButtSetDefaultParametersClick (Sender: TObject);
    procedure CbxAutoZeroChange (Sender: TObject);
    procedure CbxHallOnlyChange (Sender: TObject);
    procedure CbxLogRawChange (Sender: TObject);
    procedure CbxCalibrateHallSensorsChange (Sender: TObject);
    procedure CbxEnableDriveChange (Sender: TObject);
    procedure CbxForceMaximumDriveWidthChange (Sender: TObject);
    procedure CbxForceMinimumDriveWidthChange (Sender: TObject);
    procedure CbxPlotRim_1Change (Sender: TObject);
    procedure CbxPlotRim_2Change (Sender: TObject);
    procedure CbxMemoChange (Sender: TObject);
    procedure CbxTalkChange (Sender: TObject);
    procedure CbxEnlargeChange (Sender: TObject);
    procedure CbxPersistenceChange (Sender: TObject);
    procedure TimerBlinkTimer (Sender: TObject);
    procedure TimerCheckHeapTimer (Sender: TObject);
    procedure TimerTenDaysTimer (Sender: TObject);
    procedure TimerScreenShotTimer(Sender: TObject);
    procedure TimerSendTimer (Sender: TObject);
    procedure FormDestroy (Sender: TObject);
    procedure FormCreate (Sender: TObject);
    procedure TimerSixMinutesTimer (Sender: TObject);
  private
    { private declarations }
  public
    { public declarations }
  end;

const
  VERSIONSTRING ='v 2024-08-08';
  VERSIONNUMBER = 240808;
  TITLE = 'Logging Foucault Pendulum ';
  // position of Compass:
  CompassLeft = 512;
  CompassTop = 3;
  CompassSize = 330;

var
  ParameterFilename: string;
  FrmMain: TFrmMain;
  Talk, ForceReSync, InvertHalfSwing, PlotRim_1, PlotRim_2,
  ForceMinimalDriveWidth, ForceMaximalDriveWidth,
  UseMinimalDriveWidth, UseMaximalDriveWidth,
  Persistence, Enlarge, CalibrateHallSensors,
  HoldPower, ChargeBattery, ResetArduino,
  StoreInEEPROM, ClearDidResetMyself, ShowOnMemo, MadeCompassScreenShot: boolean;
  TStartLookForCenter,
  TMissedCenter,
  TStartLookForRim_1,
  TMissedRim_1,
  TStartLookForRim_2,
  TMissedRim_2,
  RimCoilRadius_mm,
  SetPoint_Amplitude_mm,
  TMidDrive: word;
  TMaxDriveWidth, TMinDriveWidth: byte;
  V24Cal: real;
  Blink, TenDaysAlert, LogRaw, HallOnly, AutoZeroHallData,
  CompassIsInitialized: boolean;
  HeapStatus, PrevHeapStatus: tFpcHeapStatus;

// forwards
  procedure MemoAdd (MemoString: shortstring);

implementation
{$R *.lfm}

uses u_logging, u_timestrings, u_messages, u_lingraph, u_numstrings, u_compass;

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

procedure WriteParametersToTextBoxes;
begin
  with Frmmain do
  begin
    TbxTStartLookForCenter.text:=   format ('%5d',[TStartLookForCenter]);
    TbxTMissedCenter.text:=         format ('%5d',[TMissedCenter]);
    TbxTStartLookForRim_1.text:=    format ('%5d',[TStartLookForRim_1]);
    TbxTMissedRim_1.text:=          format ('%5d',[TMissedRim_1]);
    TbxTStartLookForRim_2.text:=    format ('%5d',[TStartLookForRim_2]);
    TbxTMissedRim_2.text:=          format ('%5d',[TMissedRim_2]);
    TbxTMinDriveWidth.text:=        format ('%4d',[TMinDriveWidth]);
    TbxMaxDriveWidth.text:=         format ('%4d',[TmaxDriveWidth]);
    TbxTDrivePosition.text:=        format ('%5d',[TMidDrive]);
    TbxRimCoilRadius_mm.text:=      format ('%4d',[RimCoilRadius_mm]);
    TbxSetPoint_Amplitude_mm.text:= format ('%4d',[SetPoint_Amplitude_mm]);
  end;
end;

procedure ReadParametersFromTextBoxes;
begin
  with FrmMain do
  begin
    TStartLookForCenter:=   Fival (TbxTStartLookForCenter.text);
    TMissedCenter:=         Fival (TbxTMissedCenter.text);
    TStartLookForRim_1:=    Fival (TbxTStartLookForRim_1.text);
    TMissedRim_1:=          Fival (TbxTMissedRim_1.text);
    TStartLookForRim_2:=    Fival (TbxTStartLookForRim_2.text);
    TMissedRim_2:=          Fival (TbxTMissedRim_2.text);
    TMinDriveWidth:=        FIval (TbxTMinDriveWidth.text);
    TMaxDriveWidth:=        FIval (TbxMaxDriveWidth.text);
    TMidDrive:=             Fival (TbxTDrivePosition.text);
    RimCoilRadius_mm:=      FIval (TbxRimCoilRadius_mm.text);
    SetPoint_Amplitude_mm:= FIval (TbxSetPoint_Amplitude_mm.text);
  end;
end;

procedure WriteParametersToFile;
var
  ParameterFile: text;
begin
  assign (ParameterFile, ParameterFileName);
  rewrite (ParameterFile);
  writeln (ParameterFile, TStartLookForCenter);
  writeln (ParameterFile, TMissedCenter);
  writeln (ParameterFile, TStartLookForRim_1);
  writeln (ParameterFile, TMissedRim_1);
  writeln (ParameterFile, TStartLookForRim_2);
  writeln (ParameterFile, TMissedRim_2);
  writeln (ParameterFile, TMinDriveWidth);
  writeln (ParameterFile, TMaxDriveWidth);
  writeln (ParameterFile, TMidDrive);
  writeln (ParameterFile, RimCoilRadius_mm);
  writeln (ParameterFile, SetPoint_Amplitude_mm);
  Close (ParameterFile);
end;

procedure ReadParametersFromFile;
var
  ParameterFile: text;
begin
  if not FileExists (ParameterFileName) then exit;
  assign (ParameterFile, ParameterFileName);
  reset (ParameterFile);
  with FrmMain do
  begin
    readln (ParameterFile, TStartLookForCenter);
    readln (ParameterFile, TMissedCenter);
    readln (ParameterFile, TStartLookForRim_1);
    readln (ParameterFile, TMissedRim_1);
    readln (ParameterFile, TStartLookForRim_2);
    readln (ParameterFile, TMissedRim_2);
    readln (ParameterFile, TMinDriveWidth);
    readln (ParameterFile, TMaxDriveWidth);
    readln (ParameterFile, TMidDrive);
    readln (ParameterFile, RimCoilRadius_mm);
    readln (ParameterFile, SetPoint_Amplitude_mm);
  end;
  Close (ParameterFile);
  WriteParametersToTextBoxes;
end;

procedure TFrmMain.ButtSetDefaultParametersClick (Sender: TObject);
begin
  TStartLookForCenter:= 18000;
  TMissedCenter:=       22000;
  TStartLookForRim_1:=   4000;
  TMissedRim_1:=         5500;
  TStartLookForRim_2:=  15000;
  TMissedRim_2:=        17000;
  TMinDriveWidth:=          5;
  TMaxDriveWidth:=        180;
  TMidDrive:=             650;
  RimCoilRadius_mm:=      150;
  SetPoint_Amplitude_mm:= 230;
  WriteParametersToTextBoxes;
  WriteParametersToFile;
end;

procedure TFrmMain.CbxForceMaximumDriveWidthChange (Sender: TObject);
begin
  ForceMaximalDriveWidth:= (CbxForceMaximumDriveWidth.checked);
  CbxForceMinimumDriveWidth.checked:= false;
end;

procedure TFrmMain.CbxForceMinimumDriveWidthChange (Sender: TObject);
begin
  ForceMinimalDriveWidth:= (CbxForceMinimumDriveWidth.checked);
  CbxForceMaximumDriveWidth.checked:= false;
end;

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

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

procedure TFrmMain.ButtChangeParametersClick (Sender: TObject);
// Used after a manual change in a textbox
begin
  ReadParametersFromTextBoxes;
  WriteParametersToFile;
  StoreInEEPROM:= true;  // Signal to Arduino
  AddToLog ('** Changed Parameters');
  WriteParametersToEventLog;
end;

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

procedure TFrmMain.CbxPlotRim_1Change(Sender: TObject);
begin
  PlotRim_1:= CbxPlotRim_1.checked;
end;

procedure TFrmMain.CbxPlotRim_2Change(Sender: TObject);
begin
  PlotRim_2:= CbxPlotRim_2.checked;
end;

// *** GroupBox Status **********

procedure TFrmMain.ButtClearDidResetMyselfClick(Sender: TObject);
begin
  ClearDidResetMyself:= true;
end;

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

procedure TFrmMain.ButtRefreshClick (Sender: TObject);
begin
  LinGraph_Init;
  LinGraph_Refresh;
end;

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

procedure Compass_Init;
begin
  Compass.Init (FrmMain, CompassLeft, CompassTop, CompassSize);
end;

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

procedure TFrmMain.ButtSaveCompassClick (Sender: TObject);
begin
  Compass.SaveImageToFile ('Compass '+ DateTimeStamp3);
end;

procedure TFrmMain.ButtSaveLinGraphClick(Sender: TObject);
begin
  LinGraph_SaveImageToFile ('LinGraph ' + DateTimeStamp2);
end;

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

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

// *** GroupBox Hall Sensors **********

procedure TFrmMain.CbxCalibrateHallSensorsChange (Sender: TObject);
begin
  CalibrateHallSensors:= CbxCalibrateHallSensors.Checked;
end;

procedure TFrmMain.CbxLogRawChange(Sender: TObject);
begin
   LogRaw:= CbxLogRaw.checked; // processed in TimerSixMinutesTimer event handler
end;

procedure TFrmMain.CbxAutoZeroChange (Sender: TObject);
begin
  AutoZeroHallData:= CbxAutoZero.checked;
end;

procedure TFrmMain.CbxHallOnlyChange(Sender: TObject);
begin
  HallOnly:= CbxHallOnly.checked;
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 MemoAdd (MemoString: shortstring);
begin
  with Frmmain.Memo do
  begin
    Lines.add (MemoString);
    SelStart:= length (Text); // autoscroll
  end;
end;

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

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

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

// *** 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.TimerBlinkTimer (Sender: TObject);
begin
  Blink:= not Blink;
  if TenDaysAlert then if Blink then
    LblTenDaysAlert.Color:= clRed else LblTenDaysAlert.Color:= clLime;
end;

procedure TFrmMain.TimerSixMinutesTimer (Sender: TObject); // called 1 Hertz
// update the FP and Minor Axis trace each 6 minutes, such that the
// dispay of 500 px width covers 50 hours
const SixMinutesCounter: integer = -1;
begin
  if LogRaw then LogRawHallData; // in u_logging
  inc (SixMinutesCounter);
  if SixMinutesCounter > 359 then
  begin
    SixMinutesCounter:= 0;
    LinGraph_Update_FP;
  end;
end;

procedure TFrmMain.TimerScreenShotTimer (Sender: TObject); // 1 Hz
const
  Seconds: integer = 0;
  Minutes: integer = 0;
  StartSequence: boolean = false;
begin
  if CompassIsInitialized then Compass.TextLowerLeft (DateTimeStamp);
  // we do a screenshot of the compass each 5 minutes.
  inc (Seconds);
  if CbxAutoSaveFast.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 CbxAutoSave.checked then
      if (Minutes mod 5) = 0 then  // 5 minutes
      begin
        StartSequence:= true;
        Seconds:= 0;
      end;
  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.TimerTenDaysTimer (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.
// 10 day * 24 hour * 3600 sec = 864000 sec.
// This timer has an interval of 1 second.
const TenDaysCounter: longint = -1;
begin
  inc (TenDaysCounter);
  if TenDaysCounter > 864000 then
  begin
    TenDaysCounter:= 0;
    TenDaysAlert:= true;
  end;
end;

procedure TFrmMain.TimerCheckHeapTimer (Sender: TObject);
// We had a suspicion that the above mentioned stopping of the program
// had something to do with stack- or heap overflow, so we did a regular chack.
begin
  HeapStatus:= GetFPCHeapstatus;
  if (HeapStatus.MaxHeapSize  <> PrevHeapStatus.MaxHeapSize) or
     (HeapStatus.MaxHeapUsed  <> PrevHeapStatus.MaxHeapUsed) or
     (HeapStatus.CurrHeapSize <> PrevHeapStatus.CurrHeapSize) or
     (HeapStatus.CurrHeapUsed <> PrevHeapStatus.CurrHeapUsed) or
     (HeapStatus.CurrHeapFree <> PrevHeapStatus.CurrHeapFree)
  then
  begin
    AddToEventLog ('Change found in Heap properties:');
    AddToEventLog (format ('MaxHeapSize  was: %10d diff: %6d', [PrevHeapStatus.MaxHeapSize,  PrevHeapStatus.MaxHeapSize - HeapStatus.MaxHeapSize]));
    AddToEventLog (format ('MaxHeapUsed  was: %10d diff: %6d', [PrevHeapStatus.MaxHeapUsed,  PrevHeapStatus.MaxHeapUsed - HeapStatus.MaxHeapUsed]));
    AddToEventLog (format ('CurrHeapSize was: %10d diff: %6d', [PrevHeapStatus.CurrHeapSize, PrevHeapStatus.CurrHeapSize - PrevHeapStatus.CurrHeapSize]));
    AddToEventLog (format ('CurrHeapUsed was: %10d diff: %6d', [PrevHeapStatus.CurrHeapUsed, PrevHeapStatus.CurrHeapUsed - HeapStatus.CurrHeapUsed]));
    AddToEventLog (format ('CurrHeapFree was: %10d diff: %6d', [PrevHeapStatus.CurrHeapFree, PrevHeapStatus.CurrHeapFree - HeapStatus.CurrHeapFree]));
    PrevHeapStatus:= HeapStatus;
  end;
end;

// *** Form  **********

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

procedure TFrmMain.CbxMemoChange (Sender: TObject);
begin
 ShowOnMemo:= CbxMemo.Checked;
end;

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

procedure TFrmMain.FormCreate (Sender: TObject);
begin
  // prevent problems regarding locale with ',' as decimal separator
  // so logfiles can be in comma separated format
  DefaultFormatSettings.DecimalSeparator:= '.';
  ExeDir:= Application.Location;
  Caption:= TITLE + VERSIONSTRING;
  ParameterFileName:= ExeDir + 'Parameters.txt';
  ReadParametersFromFile;
  NewLogFileNames;
  TbxArduinoIP.text:= ARDUINOIP;
  Compass:= tCompass.create;
  Persistence:= true;
  AutoZeroHallData:= true;
end;

begin
// no initialisation code
end.

