unit DlgRemote;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  StdCtrls, ExtCtrls, Mask, Spin, ComCtrls, FileCtrl,
  Buttons, Inifiles, AppEvnts, Registry,
  ThreadMessage, CamRemote, CamDefines;

const REMOTE_SUBKEY         = 'RemoteTemplate'; //Key used when reading writing to registry
      THUMBNAIL_FILENAME    = '\thumbnail.jpg'; //Thumbnail name
      LOG_FILE_NAME         = '\log.txt';       //Log-file name
      MAX_LOG_SIZE          = 65000;            //Max size of log-file
      START_REMOTE_TXT      = '&Start taking pictures remote';
      STOP_REMOTE_TXT       = '&Stop taking pictures remote';
      START_REMOTE_PROC_TXT = '&Start remote process';
      STOP_REMOTE_PROC_TXT  = '&Stop remote process';

//List all supported cameras, which is sused to separatelu define supported
//parameters per camera. This function is however done by CamRemote when
//starting the remote process.
type AvailRemoteCamerasType =
       (
         AllParameters,
         ConnectedCameraParameters
       );

//String corresponding type to AvailRemoteCamerasType
const RemoteCamerasStringType : array[AvailRemoteCamerasType] of string =
       ( 'All parameters',
         'Connected camera parameters'
       );

//A record of supported remote parameters
type CameraRemoteParamType =
           record
             CompQuality         : array of RemoteFormatQualityType;
             ImageSize           : array of RemoteFormatSizeType;
             StrobeSetting       : array of RemoteFormatFlashType;
             StrobeCompSetting   : array of RemoteFormatFlashCompType;
             ImageMode           : array of RemoteFormatShootingModeType;
             MLWeiMode           : array of RemoteFormatMLWeiType;
             AFDistance          : array of RemoteFormatAFDistType;
             WhiteBalanceSetting : array of RemoteFormatWBType;
             Contrast            : array of RemoteFormatLevelType;
             ColorGain           : array of RemoteFormatLevelType;
             Sharpness           : array of RemoteFormatLevelType;
             ISO                 : array of RemoteFormatISOType;
             ExposureComp        : array of RemoteFormatExposureCompType;
             AV                  : array of RemoteFormatAVType;
             TV                  : array of RemoteFormatTVType;
             PhotoEffect         : array of RemoteFormatPhotoEffectType;
             Beep                : array of RemoteFormatBeepType;
           end;

//------------------------------------------------------------------------------
//- Global variables including texts used in the comboboxes when handling
//- remote paramters
//------------------------------------------------------------------------------
var gCompQualArrayText : array[low(RemoteFormatQualityType)..high(RemoteFormatQualityType)] of string =
  ('-', 'Economy', 'Normal', 'Fine', 'Super Fine','RAW');

var gImageSizeArrayText : array[low(RemoteFormatSizeType)..high(RemoteFormatSizeType)] of string =
  ('-', 'Large', 'Medium',  'Small', 'Medium1', 'Medium2', 'Medium3');

var gStrobeSettingArrayText : array[low(RemoteFormatFlashType)..high(RemoteFormatFlashType)] of string =
  ('-', 'Off', 'Auto', 'On', 'auto+red eye', 'auto+slow sync', 'auto+red eye', 'on+red eye');

var gStrobeCompSettingArrayText : array[low(RemoteFormatFlashCompType)..high(RemoteFormatFlashCompType)] of string =
  ('-', '+2.00', '+1.66', '+1.33', '+1.00', '+0.66', '+0.33', '0',
   '-0.33', '-0.66', '-1.00', '-1.33', '-1.66', '-2.00');

var gImageModeArrayText : array[low(RemoteFormatShootingModeType)..high(RemoteFormatShootingModeType)] of string =
 ('-',            'Auto',          'Manual mode',     'Far Scene',      'Fast Shutter',
  'Slow Shutter', 'Night Scene',   'Gray Scene',      'Sepia',          'Portrait',
  'Sport',        'Macro',         'Black and White', 'Pan Focus',      'Vivid',
  'Neutral',      'Program',       'TV',              'AV',             'ADep',
  'MDep',         'Bulb',          'Manual2',         'Flash Off',      'Long Shutter',
  'Super Macro',  'Foliage',       'Indoor',          'Fireworks',      'Beach',
  'Underwater',   'Snow',          'Kids and pets',   'Night snapshot', 'Ditigal macro',
  'My colors',    'Photo in movie'
  );

var gMLWeiModeArrayText : array[low(RemoteFormatMLWeiType)..high(RemoteFormatMLWeiType)] of string =
  ('-', 'Center-weighted', 'Spot', 'Averaging', 'Evaluative', 'Partial',
   'Center-weighted averaging');

var gAFDistanceArrayText : array[low(RemoteFormatAFDistType)..high(RemoteFormatAFDistType)] of string =
  ('-', 'Manual', 'Auto', 'Unknown', 'Zone Focus(Close up)',
   'Zone Focus(The shortest distance)', 'Zone Focus(Short distance)',
   'Zone Focus(Medium distance)',       'Zone Focus(Far distance)',
   'Pan Focus', 'Super Macro', 'Infinity', 'Super Macro OCM' 
  );

var gWhiteBalanceSetArrayText : array[low(RemoteFormatWBType)..high(RemoteFormatWBType)] of string =
  ('-', 'Auto', 'Daylight', 'Cloudy', 'Tungsten', 'Fluorscent', 'Flash',
   'Fluorescent light', 'Custom', 'Custom1', 'Custom2', 'BW', 'Shade',
   'Kelvin', 'PCSet1', 'PCSet2', 'PCSet3');

var gContrastArrayText : array[low(RemoteFormatLevelType)..high(RemoteFormatLevelType)] of string =
  ('-', 'Low', 'Default', 'High');

var gColorGainArrayText : array[low(RemoteFormatLevelType)..high(RemoteFormatLevelType)] of string =
  ('-', 'Low', 'Default', 'High');

var gSharpnessArrayText : array[low(RemoteFormatLevelType)..high(RemoteFormatLevelType)] of string =
  ('-', 'Low', 'Default', 'High');

var gIsoArrayText : array[low(RemoteFormatISOType)..high(RemoteFormatISOType)] of string =
  ('-', 'Auto', '50', '100', '200', '400', '800', '1600', '3200');

var gExposureCompArrayText : array[low(RemoteFormatExposureCompType)..high(RemoteFormatExposureCompType)] of string =
  ('-', '+2.00', '+1.66', '+1.33', '+1.00', '+0.66', '+0.33', '0',
   '-0.33', '-0.66', '-1.00', '-1.33', '-1.66', '-2.00');

var gAvArrayText : array[low(RemoteFormatAVType)..high(RemoteFormatAVType)] of string =
  ('-', '1.0', '1.4', '2.0', '2.8', '4.0', '5.6', '8.0', '11', '16', '22', '32', '45', '64', '91');

var gTvArrayText : array[low(RemoteFormatTVType)..high(RemoteFormatTVType)] of string =
  ('-', '30"', '15"', '8"', '4"', '2"', '1"', '1/2', '1/4', '1/8',
   '1/15', '1/30', '1/60', '1/125', '1/250', '1/500', '1/1000',
   '1/2000', '1/4000', '1/8000', '1/16000');

var gPhotoEffectArrayText : array[low(RemoteFormatPhotoEffectType)..high(RemoteFormatPhotoEffectType)] of string =
  ('-', 'Off', 'Vivid', 'Neutral', 'Low Sharpening', 'Sepia', 'Black and White');

var gBeepArrayText : array[low(RemoteFormatBeepType)..high(RemoteFormatBeepType)] of string =
  ('-', 'Off', 'On');

//Remote form type
type
  TFormRemote = class(TForm)
    StatusBar: TStatusBar;
    PageControl: TPageControl;
    TabSheetRemote: TTabSheet;
    LabelComputerDir: TLabel;
    Image: TImage;
    LabelPreview: TLabel;
    ButtonTakePic: TButton;
    BitBtnClose: TBitBtn;
    ButtonStartRemoteProcess: TButton;
    TabSheetRelParams: TTabSheet;
    LabelTV: TLabel;
    LabelAv: TLabel;
    ComboBoxTv: TComboBox;
    ComboBoxAv: TComboBox;
    LabelExpComp: TLabel;
    ComboBoxExpComp: TComboBox;
    LabelFlash: TLabel;
    ComboBoxFlash: TComboBox;
    LabelFlashComp: TLabel;
    ComboBoxFlashComp: TComboBox;
    LabelSize: TLabel;
    LabelQuality: TLabel;
    ComboBoxSize: TComboBox;
    ComboBoxQuality: TComboBox;
    LabelWhiteBalance: TLabel;
    ComboBoxWhiteBalance: TComboBox;
    LabelISO: TLabel;
    ComboBoxISO: TComboBox;
    CheckBoxBeep: TCheckBox;
    LabelImageMode: TLabel;
    ComboBoxImageMode: TComboBox;
    LabelMeteringMode: TLabel;
    ComboBoxMeteringMode: TComboBox;
    LabelAFDistance: TLabel;
    ComboBoxAFDistance: TComboBox;
    LabelContrast: TLabel;
    ComboBoxContrast: TComboBox;
    LabelColorGain: TLabel;
    ComboBoxColorGain: TComboBox;
    LabelSharpness: TLabel;
    ComboBoxSharpness: TComboBox;
    ButtonGetCamSet: TButton;
    LabelZoom: TLabel;
    TrackBarZoom: TTrackBar;
    ButtonViewFinder: TButton;
    ButtonSetCameraSettings: TButton;
    ProgressBar: TProgressBar;
    LabelPhotoEffect: TLabel;
    ComboBoxPhotoEffect: TComboBox;
    LabelZoomPos: TLabel;
    ApplicationEvents1: TApplicationEvents;
    TabSheetAbout: TTabSheet;
    CheckBoxDebug: TCheckBox;
    LabelVersion: TLabel;
    CamRemote: TCamRemote;
    ComboBoxTransferMode: TComboBox;
    LabelTransfer: TLabel;
    CheckBoxActiveMode: TCheckBox;
    CheckBoxOnlySupportedParam: TCheckBox;
    EditPCDirectory: TEdit;
    TimerTakePicture: TTimer;
    procedure FormCreate(Sender: TObject);
    procedure ButtonTakePicClick(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
    procedure ButtonStartRemoteProcessClick(Sender: TObject);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure ButtonGetCamSetClick(Sender: TObject);
    procedure TrackBarZoomChange(Sender: TObject);
    procedure ButtonViewFinderClick(Sender: TObject);
    procedure ButtonSetCameraSettingsClick(Sender: TObject);
    procedure CheckBoxDebugClick(Sender: TObject);
    procedure FormShow(Sender: TObject);
    procedure CamRemoteEvent(Event: EventCallbackType);
    procedure CamRemoteViewfinderEvent(Jpegdata: TMemoryStream);
    procedure CamRemoteRemoteGetPictureEvent(PercentageDone: Integer);
    procedure CamRemoteRemoteTakePictureEvent(PercentageDone: Integer);
    procedure CamRemoteRemoteEvent(Event: RemoteEventCallbackType);
    procedure TimerTakePictureTimer(Sender: TObject);
  private
    mReleaseProcessActive  : boolean;                //Is true when the releasestart proc has been called
    mCameraIsActive        : boolean;                //Is true if the camera is ready to take a picture
    mViewFinderEnabled     : boolean;                //Is true when viewfinder functions are on
    mCameraRemoteParam     : CameraRemoteParamType;  //Contains remote parameters possible to set for current camera
    mCurrentCamera         : AvailRemoteCamerasType; //Current connected camera
    mPictureReqTime        : TDateTime;              //The time when the request for taking a picture
    mIniFile               : TRegistryIniFile;       //The registry entry
    mLogFile               : TFileStream;            //The log-file
    mConnToCamera          : boolean;                //Is true during connection to camera
    mMessageThread         : TMessageThread;         //Thread to handle event messages from the camera
    mCameraInfo            : ConnectInfoType;        //Info about the camera received when connecting
    mCameraCapability      : RemoteFuncType;         //Remote capability of the connected camera
    mReleaseMode           : ReleaseModeType;        //The selected transfer mode in "Transfer mode"

    procedure Initvar;
    procedure StartReleasePic;
    procedure StopReleasePic;
    procedure TakePicture;
    procedure TakeThePictures;
    procedure SetRemoteParameters(inParam : RemoteReleaseParametersType);
    function  GetRemoteParameters : RemoteReleaseParametersType;
    procedure LogRemoteParameters(RemoteParameters : RemoteReleaseParametersType);
    procedure PictureTaken;
    procedure EnableButtons(Active : boolean);
    function  Versiontext : string;
    function  GetLogFileName : string;
    procedure AppException(Sender: TObject; E: Exception);
    procedure WriteVerToLog;
    procedure DisconnectFromCamera;
    procedure ConnectToCamera;
    procedure UpdateRemoteParamVCL;
  public
    { Public declarations }
    property  ViewFinderEnabled  : boolean          read mViewFinderEnabled  write mViewFinderEnabled;
    property  MessageThread      : TMessageThread   read mMessageThread      write mMessageThread;
    procedure Log(Text : string);
  end;

var
  FormRemote: TFormRemote;

implementation

uses DlgViewFinder, Jpeg;

{$R *.DFM}

//Takes a picture remotely and gets the picture data if the remote transfer
//mode is active and not passive
procedure TFormRemote.TakeThePictures;
begin
  TakePicture;
  if (CheckBoxActiveMode.Checked) then
  begin
    PictureTaken;
  end;
end;

//Form create procedure
procedure TFormRemote.FormCreate(Sender: TObject);
begin
  //Set the application exception handler
  Application.OnException := AppException;
  //Create the registry ini-file
  mIniFile := TRegistryIniFile.Create('Software');
  CheckBoxDebug.Checked := mIniFile.ReadBool(REMOTE_SUBKEY,
                                             CheckBoxDebug.Name,
                                             false);
  //Create the debug file if the checkbox is set
  if (CheckBoxDebug.Checked) then
  begin
    if FileExists(GetLogFileName) then
    begin
      mLogFile := TFileStream.Create(GetLogFileName,
                                     (fmOpenReadWrite or fmShareDenyWrite));
      mLogFile.Seek(0, soFromEnd);
      //Check if size is exceeded
      if (mLogFile.Size > MAX_LOG_SIZE) then
      begin
        mLogFile.Free;
        //Create the new file
        mLogFile := TFileStream.Create(GetLogFileName,
                                       (fmCreate or fmShareDenyWrite));
      end;
    end else
    begin
      mLogFile := TFileStream.Create(GetLogFileName,(fmCreate or fmShareDenyWrite));
    end;
  end;
  Log('');
  Log('');
  Log('Remote template version ' + Versiontext + ' started');
  Log('Date and time=' + DateTimeToStr(Now));
  //Write OS version in LOG
  WriteVerToLog;
  //Initialize
  mConnToCamera        := false;
  StatusBar.SimpleText := '';
  //Set the global time variable format
  TimeSeparator   := ':';
  LongTimeFormat  := 'HH:mm:ss';
  //Creates the message thread. The message thread is started immidiately.
  mMessageThread  := TMessageThread.Create(false);
  mCameraIsActive := false;
  //Read data stored in the registry
  EditPCDirectory.Text := mIniFile.ReadString(REMOTE_SUBKEY,
                                              EditPCDirectory.Name,
                                              GetCurrentDir);
  CheckBoxDebug.Checked := mIniFile.ReadBool(REMOTE_SUBKEY,
                                             CheckBoxDebug.Name,
                                             CheckBoxDebug.Checked);
  ComboBoxTransferMode.ItemIndex := mIniFile.ReadInteger(REMOTE_SUBKEY,
                                                         ComboBoxTransferMode.Name,
                                                         ComboBoxTransferMode.ItemIndex);
  CheckBoxActiveMode.Checked := mIniFile.ReadBool(REMOTE_SUBKEY,
                                                  CheckBoxActiveMode.Name,
                                                  CheckBoxActiveMode.Checked);
  CheckBoxOnlySupportedParam.Checked := mIniFile.ReadBool(REMOTE_SUBKEY,
                                                          CheckBoxOnlySupportedParam.Name,
                                                          CheckBoxOnlySupportedParam.Checked);
  Initvar;
  //Deaktivate buttons since the remote process not started
  EnableButtons(false);
  PageControl.ActivePageIndex := 0;
  //Set about version text
  LabelVersion.Caption := 'Remote version ' + Versiontext;
  inherited;
end;

//Procedure for the "Take a picture" button
procedure TFormRemote.ButtonTakePicClick(Sender: TObject);
begin
  //Takes the picture(s) manually triggered
  Log('Enters ButtonTakePicClick');
  //Check if destination directory exists
  if not DirectoryExists(EditPCDirectory.Text) then
  begin
    raise EInOutError.Create('Destination directory does not exist');
  end;
  try
    Initvar;
    EnableButtons(false);
    StatusBar.SimpleText := 'Taking the picture';
    TakeThePictures;
    EnableButtons(true);
  except
    on E:exception do
      begin
        Log('Button_TakePicClick Exception=' + E.Message);
        Initvar;
        StopReleasePic;
        StatusBar.SimpleText := 'Remote process stopped';
        raise;
      end;
  end;
end;

//Gets the thumbnail and picture when a picture has been taken
procedure TFormRemote.PictureTaken;
var thumb_file_name   : string;
    pic_file_name     : string;
    time_string       : string;
begin
  //Is called when the event for a remote picture is sent
  Log('Enters PictureTaken');
  try
    if ((mReleaseProcessActive) and
        (mReleaseMode <> ReleaseModeOnlyToCamera)) then
    begin
      //First get the thumbnail
      thumb_file_name := extractFileDir(ParamStr(0)) + THUMBNAIL_FILENAME;
      Log('Remote: Thumbnail receive request. Time = ' +
          floattostr((Now - mPictureReqTime) * 24* 3600));
      CamRemote.RemoteGetPicture(thumb_file_name);
      Log('Remote: Thumbnail received. Time = ' +
          floattostr((Now - mPictureReqTime) * 24* 3600));
      Image.Picture.LoadFromFile(thumb_file_name);
      DateTimeToString(time_string, 'yymmddhhnnss', Now);
      pic_file_name := Format('%s%s.jpg', [EditPCDirectory.Text + '\',
                                           time_string]);
      //Get the picure
      Log('Remote: Picture receive request. Time = ' +
          floattostr((Now - mPictureReqTime) * 24* 3600));
      CamRemote.RemoteGetPicture(pic_file_name);
      Log('Remote: Picture received. Time = ' +
          floattostr((Now - mPictureReqTime) * 24* 3600));
    end else begin
      Log('Exception, nearly. mReleaseProcessActive');
    end;
    ProgressBar.Position := 0;
  except
    on E:Exception do
       begin
         Log('Exception=' + E.Message);
         Initvar;
         StopReleasePic;
         StatusBar.SimpleText := 'Remote process stopped';
         raise;
       end;
  end;
end;

procedure TFormRemote.Initvar;
begin
  Log('Enters Initvar');
  if (ButtonStartRemoteProcess.Caption = STOP_REMOTE_PROC_TXT) then
  begin
    ButtonTakePic.Enabled := true;
  end;
  ButtonTakePic.Enabled;
end;

//Procedure used when starting the remote process
procedure TFormRemote.StartReleasePic;
var i              : integer;
    temp_tab_sheet : TTabSheet;
begin
  Log('Enters StartReleasePic');
  Log('Checks if the camera supports remote');
  if (not CamRemote.RemoteSupported) then
  begin
    ECamException.Create('The connected camera does not support remote mode');
  end;
  StatusBar.SimpleText := 'Starts remote process and probes remote parameters';
  //Starts the remote mode
  Log('Opens remote mode');
  mCameraCapability := CamRemote.RemoteStart(mReleaseMode,
                                             ReleaseDataKingTakeBothThumbAndPic,
                                             true); //Always probe remote parameters
{$IFNDEF VER130} //Not supported by Delphi 5
  Log('Remote capabaility DoSupportZoom = '                + BoolToStr(mCameraCapability.DoSupportZoom));
  Log('Remote capabaility DoSupportShootingPara = '        + BoolToStr(mCameraCapability.DoSupportShootingPara));
  Log('Remote capabaility DoSupportViewfinder = '          + BoolToStr(mCameraCapability.DoSupportViewfinder));
  Log('Remote capabaility ReqViewfinderOffWhenShooting = ' + BoolToStr(mCameraCapability.ReqViewfinderOffWhenShooting));
  Log('Remote capabaility DoSupportAfLockUnlock = '        + BoolToStr(mCameraCapability.DoSupportAfLockUnlock));
{$ENDIF}  
  mCameraIsActive       := true;
  mReleaseProcessActive := true;
  //Disable not supported VCL
  if (not mCameraCapability.DoSupportViewfinder) then
  begin
    ButtonViewFinder.Visible := false;
    Log('ViewFinder is not allowed');
  end else begin
    ButtonViewFinder.Enabled := true;
    Log('ViewFinder is allowed');
  end;
  if (not mCameraCapability.DoSupportZoom) then
  begin
    LabelZoom.Visible    := false;
    TrackBarZoom.Visible := false;
  end;
  if (not mCameraCapability.DoSupportShootingPara) then
  begin
    //Disable the parameters tab
    for i := 0 to PageControl.PageCount - 1 do
    begin
       temp_tab_sheet := PageControl.Pages[i];
       if (temp_tab_sheet.Name = 'TabSheetRelParams') then
       begin
         temp_tab_sheet.TabVisible := false;
       end;
    end;
  end;
  EnableButtons(true);
  StatusBar.SimpleText := 'Remote process is opened';
end;

//Procedure used when stopping the remote process
procedure TFormRemote.StopReleasePic;
begin
  //Ends the release process
  Log('Enters StopReleasePic');
  if (mReleaseProcessActive) then
  begin
    EnableButtons(false);
    ButtonStartRemoteProcess.Caption := START_REMOTE_PROC_TXT;
    CamRemote.RemoteEnd;
    mCameraIsActive := false;
    Log('StopReleasePic, ReleaseEnd');
    mReleaseProcessActive := false;
  end;
  StatusBar.SimpleText := 'Remote process stopped';
  Initvar;
end;

//Procedure used when taking a picture remotely
procedure TFormRemote.TakePicture;
var remote_parameters : RemoteReleaseParametersType;
begin
  //Takes one picture
  Log('Enters TakePicture');
  mPictureReqTime := Now();
  Log('Remote: Request to take a picture. Time = ' +
      floattostr((Now - mPictureReqTime) * 24* 3600));
  if (mCameraCapability.DoSupportShootingPara) then
  begin
    //Gets release parameters from the Parameters tab
    remote_parameters := GetRemoteParameters;
    Log('Sets remote parameters');
    CamRemote.RemoteSetRemoteParams(remote_parameters);
    Log('Remote: Remote parameters set. Time = ' +
        floattostr((Now - mPictureReqTime) * 24* 3600));
  end;
  Log('Takes a remote pic. Zoom = ' + inttostr(TrackBarZoom.Position)+
      ', maxZoom = ' + inttostr(TrackBarZoom.Max));
  //Check if Viewfinder must be closed before taking the picture
  if (FormViewFinder.Showing) and (mCameraCapability.ReqViewfinderOffWhenShooting) then
  begin
    FormViewFinder.Close;
  end;
  CamRemote.RemoteTakePicture(CheckBoxActiveMode.Checked);
  Log('Remote: Request for taking picture done. Time = ' +
      floattostr((Now - mPictureReqTime) * 24* 3600));
end;

//Procedure called when exiting the application and the form is freed.
procedure TFormRemote.FormDestroy(Sender: TObject);
begin
  Log('Enters TForm_Remote.FormDestroy');
  //Stores data in the registry
  mIniFile.WriteInteger(REMOTE_SUBKEY, 'RemoteWidth',                   FormRemote.Width);
  mIniFile.WriteInteger(REMOTE_SUBKEY, 'RemoteHeight',                  FormRemote.Height);
  mIniFile.WriteString (REMOTE_SUBKEY, EditPCDirectory.Name,            EditPCDirectory.Text);
  mIniFile.WriteBool   (REMOTE_SUBKEY, CheckBoxDebug.Name,              CheckBoxDebug.Checked);
  mIniFile.WriteInteger(REMOTE_SUBKEY, ComboBoxTransferMode.Name,       ComboBoxTransferMode.ItemIndex);
  mIniFile.WriteBool   (REMOTE_SUBKEY, CheckBoxActiveMode.Name,         CheckBoxActiveMode.Checked);
  mIniFile.WriteBool   (REMOTE_SUBKEY, CheckBoxOnlySupportedParam.Name, CheckBoxOnlySupportedParam.Checked);
  mIniFile.Free;
  if (CheckBoxDebug.Checked) then
  begin
    mLogFile.Free;
  end;
  //Close the message thread
  mMessageThread.Terminate;
  mMessageThread.WaitFor;
  mMessageThread.free;
end;

//EnableButtons enables or disables buttons that only can be used when remote
//process has been started or stopped.
procedure TFormRemote.EnableButtons(Active : boolean);
begin
  Log('Enters TFormRemote.EnableButtons');
  ButtonTakePic.Enabled           := Active;
  ButtonGetCamSet.Enabled         := Active;
  ButtonSetCameraSettings.Enabled := Active;
  ButtonViewFinder.Enabled        := Active;
end;

procedure TFormRemote.ButtonStartRemoteProcessClick(Sender: TObject);
begin
  //Starts the remote process
  Log('Enters TForm_Remote.Button_StartRemoteProcessClick');
  if (ButtonStartRemoteProcess.Caption = START_REMOTE_PROC_TXT) then
  begin
    //Connects to the camera and starts the remote mode
    if (ComboBoxTransferMode.ItemIndex <> -1) then
    begin
      mReleaseMode := ReleaseModeType(ComboBoxTransferMode.ItemIndex);
    end;
    ButtonStartRemoteProcess.Caption   := STOP_REMOTE_PROC_TXT;
    ComboBoxTransferMode.Enabled       := false;
    CheckBoxActiveMode.Enabled         := false;
    CheckBoxOnlySupportedParam.Enabled := false;
    ConnectToCamera;
    if (CheckBoxOnlySupportedParam.Checked) then
    begin
      mCurrentCamera := ConnectedCameraParameters;
    end else begin
      mCurrentCamera := AllParameters;
    end;
    StartReleasePic;
    UpdateRemoteParamVCL;
  end else
  begin
    //Closes the viewfinder, if opened, then stops the remote mode and
    //disconnects from the camera
    if (FormViewFinder.Visible) then
    begin
      FormViewFinder.Close;
    end;
    //Disconnects from the camera
    ButtonStartRemoteProcess.Caption   := START_REMOTE_PROC_TXT;
    ComboBoxTransferMode.Enabled       := true;
    CheckBoxActiveMode.Enabled         := true;
    CheckBoxOnlySupportedParam.Enabled := true;
    try
      StopReleasePic;
    finally
      DisconnectFromCamera;
    end;
  end;
end;

procedure TFormRemote.FormClose(Sender: TObject;
  var Action: TCloseAction);
begin
  //Closes the viewfinder, if opened, then stops the remote mode and
  //disconnects from the camera
  Log('Enters TForm_Remote.FormClose');
  if (FormViewFinder.Visible) then
  begin
    FormViewFinder.Close;
  end;
  if mCameraIsActive then
  begin
    StopReleasePic;
    DisconnectFromCamera;
  end;
end;

procedure TFormRemote.ButtonGetCamSetClick(Sender: TObject);
var remote_param    : RemoteReleaseParametersType;
    zoom_capability : RemoteZoomCapabilityType;
begin
  //Gets remote parameters from the camera and sets the VCL components
  remote_param := CamRemote.RemoteGetRemoteParams;
  Log('Sets remote parameters to dialogue');
  LogRemoteParameters(remote_param);
  SetRemoteParameters(remote_param);
  if (mCameraCapability.DoSupportZoom) then begin
    //Get zoom position
    zoom_capability        := CamRemote.RemoteGetZoomPos;
    TrackBarZoom.Max       := zoom_capability.MaxOpticalZoomPos;
    TrackBarZoom.Position  := zoom_capability.CurrentZoomPos;
    LabelZoomPos.Caption   := IntToStr(TrackBarZoom.Position);
    TrackBarZoom.Frequency := TrackBarZoom.Max DIV 10;
  end;
end;

procedure TFormRemote.FormShow(Sender: TObject);
begin
  //Resize dialogue
  FormRemote.Width  := mIniFile.ReadInteger(REMOTE_SUBKEY, 'RemoteWidth',  FormRemote.Width);
  FormRemote.Height := mIniFile.ReadInteger(REMOTE_SUBKEY, 'RemoteHeight', FormRemote.Height);
  //Set current camera
  Initvar;
end;

//Updates the comboboxes in the remote tab
procedure TFormRemote.UpdateRemoteParamVCL;
var i                           : integer;
    quality_counter             : RemoteFormatQualityType;
    imagesize_counter           : RemoteFormatSizeType;
    strobesetting_counter       : RemoteFormatFlashType;
    imagemode_counter           : RemoteFormatShootingModeType;
    mlweimode_counter           : RemoteFormatMLWeiType;
    afdistance_counter          : RemoteFormatAFDistType;
    whitebalancesetting_counter : RemoteFormatWBType;
    iso_counter                 : RemoteFormatISOType;
    expcomp_counter             : RemoteFormatExposureCompType;
    av_counter                  : RemoteFormatAVType;
    tv_counter                  : RemoteFormatTVType;
    photoeffect_counter         : RemoteFormatPhotoEffectType;
    strobecomp_counter          : RemoteFormatFlashCompType;
    level_counter               : RemoteFormatLevelType;
    beep_counter                : RemoteFormatBeepType;
begin
  //Assign camera parameters possible to set
  //CompQuality
  i := 0;
  SetLength(mCameraRemoteParam.CompQuality, 0);
  for quality_counter := Succ(Low(RemoteFormatQualityType)) to High(RemoteFormatQualityType) do
  begin
    if (((mCurrentCamera = ConnectedCameraParameters) and (mCameraCapability.RemoteParamSupported.CompQuality[quality_counter] = true)) or
        (mCurrentCamera = AllParameters)) then
    begin
      SetLength(mCameraRemoteParam.CompQuality, i + 1);
      mCameraRemoteParam.CompQuality[i] := quality_counter;
      i := i + 1;
    end;
  end;

  //Image size
  i := 0;
  SetLength(mCameraRemoteParam.ImageSize, 0);
  for imagesize_counter := Succ(Low(RemoteFormatSizeType)) to High(RemoteFormatSizeType) do
  begin
    if (((mCurrentCamera = ConnectedCameraParameters) and (mCameraCapability.RemoteParamSupported.ImageSize[imagesize_counter])) or
        (mCurrentCamera = AllParameters)) then
    begin
       SetLength(mCameraRemoteParam.ImageSize, i + 1);
       mCameraRemoteParam.ImageSize[i] := imagesize_counter;
       i := i + 1;
    end;
  end;

  //StrobeSetting
  i := 0;
  SetLength(mCameraRemoteParam.StrobeSetting, 0);
  for strobesetting_counter := Succ(Low(RemoteFormatFlashType)) to High(RemoteFormatFlashType) do
  begin
    if (((mCurrentCamera = ConnectedCameraParameters) and (mCameraCapability.RemoteParamSupported.StrobeSetting[strobesetting_counter])) or
        (mCurrentCamera = AllParameters)) then
    begin
       SetLength(mCameraRemoteParam.StrobeSetting, i + 1);
       mCameraRemoteParam.StrobeSetting[i] := strobesetting_counter;
       i := i + 1;
    end;
  end;

  //StrobeCompSetting
  i := 0;
  SetLength(mCameraRemoteParam.StrobeCompSetting, 0);
  for strobecomp_counter := Succ(Low(RemoteFormatFlashCompType)) to High(RemoteFormatFlashCompType) do
  begin
    if (((mCurrentCamera = ConnectedCameraParameters) and (mCameraCapability.RemoteParamSupported.StrobeCompSetting[strobecomp_counter])) or
        (mCurrentCamera = AllParameters)) then
    begin
       SetLength(mCameraRemoteParam.StrobeCompSetting, i + 1);
       mCameraRemoteParam.StrobeCompSetting[i] := strobecomp_counter;
       i := i + 1;
    end;
  end;

  //ImageMode
  i := 0;
  SetLength(mCameraRemoteParam.ImageMode, 0);
  for imagemode_counter := Succ(Low(RemoteFormatShootingModeType)) to High(RemoteFormatShootingModeType) do
  begin
    if (((mCurrentCamera = ConnectedCameraParameters) and (mCameraCapability.RemoteParamSupported.ImageMode[imagemode_counter])) or
        (mCurrentCamera = AllParameters)) then
    begin
       SetLength(mCameraRemoteParam.ImageMode, i + 1);
       mCameraRemoteParam.ImageMode[i] := imagemode_counter;
       i := i + 1;
    end;
  end;

  //MLWeiMode
  i := 0;
  SetLength(mCameraRemoteParam.MLWeiMode, ord(high(RemoteFormatMLWeiType)) + 1);
  for mlweimode_counter := Succ(Low(RemoteFormatMLWeiType)) to High(RemoteFormatMLWeiType) do
  begin
    if (((mCurrentCamera = ConnectedCameraParameters) and (mCameraCapability.RemoteParamSupported.MLWeiMode[mlweimode_counter])) or
        (mCurrentCamera = AllParameters)) then
    begin
       SetLength(mCameraRemoteParam.MLWeiMode, i + 1);
       mCameraRemoteParam.MLWeiMode[i] := mlweimode_counter;
       i := i + 1;
    end;
  end;

  //AFDistance
  i := 0;
  SetLength(mCameraRemoteParam.AFDistance, 0);
  for afdistance_counter := Succ(Low(RemoteFormatAFDistType)) to High(RemoteFormatAFDistType) do
  begin
    if (((mCurrentCamera = ConnectedCameraParameters) and (mCameraCapability.RemoteParamSupported.AFDistance[afdistance_counter])) or
        (mCurrentCamera = AllParameters)) then
    begin
       SetLength(mCameraRemoteParam.AFDistance, i + 1);
       mCameraRemoteParam.AFDistance[i] := afdistance_counter;
       i := i + 1;
    end;
  end;

  //WhiteBalanceSetting
  i := 0;
  SetLength(mCameraRemoteParam.WhiteBalanceSetting, 0);
  for whitebalancesetting_counter := Succ(Low(RemoteFormatWBType)) to High(RemoteFormatWBType) do
  begin
    if (((mCurrentCamera = ConnectedCameraParameters) and (mCameraCapability.RemoteParamSupported.WhiteBalanceSetting[whitebalancesetting_counter])) or
        (mCurrentCamera = AllParameters)) then
    begin
       SetLength(mCameraRemoteParam.WhiteBalanceSetting, i + 1);
       mCameraRemoteParam.WhiteBalanceSetting[i] := whitebalancesetting_counter;
       i := i + 1;
    end;
  end;

  //Contrast
  i := 0;
  SetLength(mCameraRemoteParam.Contrast, 0);
  for level_counter := Succ(Low(RemoteFormatLevelType)) to High(RemoteFormatLevelType) do
  begin
    if (((mCurrentCamera = ConnectedCameraParameters) and (mCameraCapability.RemoteParamSupported.Contrast[level_counter])) or
        (mCurrentCamera = AllParameters)) then
    begin
       SetLength(mCameraRemoteParam.Contrast, i + 1);
       mCameraRemoteParam.Contrast[i] := level_counter;
       i := i + 1;
    end;
  end;

  //ColorGain
  i := 0;
  SetLength(mCameraRemoteParam.ColorGain, 0);
  for level_counter := Succ(Low(RemoteFormatLevelType)) to High(RemoteFormatLevelType) do
  begin
    if (((mCurrentCamera = ConnectedCameraParameters) and (mCameraCapability.RemoteParamSupported.ColorGain[level_counter])) or
        (mCurrentCamera = AllParameters)) then
    begin
       SetLength(mCameraRemoteParam.ColorGain, i + 1);
       mCameraRemoteParam.ColorGain[i] := level_counter;
       i := i + 1;
    end;
  end;

  //Sharpness
  i := 0;
  SetLength(mCameraRemoteParam.Sharpness, 0);
  for level_counter := Succ(Low(RemoteFormatLevelType)) to High(RemoteFormatLevelType) do
  begin
    if (((mCurrentCamera = ConnectedCameraParameters) and (mCameraCapability.RemoteParamSupported.Sharpness[level_counter])) or
        (mCurrentCamera = AllParameters)) then
    begin
       SetLength(mCameraRemoteParam.Sharpness, i + 1);
       mCameraRemoteParam.Sharpness[i] := level_counter;
       i := i + 1;
    end;
  end;

  //ISO
  i := 0;
  SetLength(mCameraRemoteParam.ISO, 0);
  for iso_counter := Succ(Low(RemoteFormatISOType)) to High(RemoteFormatISOType) do
  begin
    if (((mCurrentCamera = ConnectedCameraParameters) and (mCameraCapability.RemoteParamSupported.ISO[iso_counter])) or
        (mCurrentCamera = AllParameters)) then
    begin
       SetLength(mCameraRemoteParam.ISO, i + 1);
       mCameraRemoteParam.ISO[i] := iso_counter;
       i := i + 1;
    end;
  end;

  //ExposureComp
  i := 0;
  SetLength(mCameraRemoteParam.ExposureComp, 0);
  for expcomp_counter := Succ(Low(RemoteFormatExposureCompType)) to High(RemoteFormatExposureCompType) do
  begin
    if (((mCurrentCamera = ConnectedCameraParameters) and (mCameraCapability.RemoteParamSupported.ExposureCompensation[expcomp_counter])) or
        (mCurrentCamera = AllParameters)) then
    begin
       SetLength(mCameraRemoteParam.ExposureComp, i + 1);
       mCameraRemoteParam.ExposureComp[i] := expcomp_counter;
       i := i + 1;
    end;
  end;

  //AV
  i := 0;
  SetLength(mCameraRemoteParam.AV, 0);
  for AV_counter := Succ(Low(RemoteFormatAVType)) to High(RemoteFormatAVType) do
  begin
    if (((mCurrentCamera = ConnectedCameraParameters) and (mCameraCapability.RemoteParamSupported.Av[AV_counter])) or
        (mCurrentCamera = AllParameters)) then
    begin
       SetLength(mCameraRemoteParam.AV, i + 1);
       mCameraRemoteParam.AV[i] := AV_counter;
       i := i + 1;
    end;
  end;

  //TV
  i := 0;
  SetLength(mCameraRemoteParam.TV, 0);
  for TV_counter := Succ(Low(RemoteFormatTVType)) to High(RemoteFormatTVType) do
  begin
    if (((mCurrentCamera = ConnectedCameraParameters) and (mCameraCapability.RemoteParamSupported.Tv[TV_counter])) or
        (mCurrentCamera = AllParameters)) then
    begin
       SetLength(mCameraRemoteParam.TV, i + 1);
       mCameraRemoteParam.TV[i] := TV_counter;
       i := i + 1;
    end;
  end;

  //PhotoEffect
  i := 0;
  SetLength(mCameraRemoteParam.PhotoEffect, 0);
  for photoeffect_counter := Succ(Low(RemoteFormatPhotoEffectType)) to High(RemoteFormatPhotoEffectType) do
  begin
    if (((mCurrentCamera = ConnectedCameraParameters) and (mCameraCapability.RemoteParamSupported.PhotoEffect[photoeffect_counter])) or
        (mCurrentCamera = AllParameters)) then
    begin
       SetLength(mCameraRemoteParam.PhotoEffect, i + 1);
       mCameraRemoteParam.PhotoEffect[i] := photoeffect_counter;
       i := i + 1;
    end;
  end;

  //Beep
  i := 0;
  SetLength(mCameraRemoteParam.Beep, 0);
  for beep_counter := Succ(Low(RemoteFormatBeepType)) to High(RemoteFormatBeepType) do
  begin
    if (((mCurrentCamera = ConnectedCameraParameters) and (mCameraCapability.RemoteParamSupported.Beep[beep_counter])) or
        (mCurrentCamera = AllParameters)) then
    begin
       SetLength(mCameraRemoteParam.Beep, i + 1);
       mCameraRemoteParam.Beep[i] := beep_counter;
       i := i + 1;
    end;
  end;

  //Get the items in the parameters comboboxes
  //Compression quality combobox
  ComboBoxQuality.Enabled := false;
  ComboBoxQuality.Items.Clear;
  for i := 0 to high(mCameraRemoteParam.CompQuality) do begin
    ComboBoxQuality.Enabled := true;
    ComboBoxQuality.Items.Add(gCompQualArrayText[mCameraRemoteParam.CompQuality[i]]);
  end;

  //ImageSize combobox
  ComboBoxSize.Enabled := false;
  ComboBoxSize.Items.Clear;
  for i := 0 to high(mCameraRemoteParam.ImageSize) do begin
    ComboBoxSize.Enabled := true;
    ComboBoxSize.Items.Add(gImageSizeArrayText[mCameraRemoteParam.ImageSize[i]]);
  end;

  //StrobeSetting combobox
  ComboBoxFlash.Enabled := false;
  ComboBoxFlash.Items.Clear;
  for i := 0 to high(mCameraRemoteParam.StrobeSetting) do begin
    ComboBoxFlash.Enabled := true;
    ComboBoxFlash.Items.Add(gStrobeSettingArrayText[mCameraRemoteParam.StrobeSetting[i]]);
  end;

  //StrobeCompSetting combobox
  ComboBoxFlashComp.Enabled := false;
  ComboBoxFlashComp.Items.Clear;
  for i := 0 to high(mCameraRemoteParam.StrobeCompSetting) do begin
    ComboBoxFlashComp.Enabled := true;
    ComboBoxFlashComp.Items.Add(gStrobeCompSettingArrayText[mCameraRemoteParam.StrobeCompSetting[i]]);
  end;

  //ImageMode combobox
  ComboBoxImageMode.Enabled := false;
  ComboBoxImageMode.Items.Clear;
  for i := 0 to high(mCameraRemoteParam.ImageMode) do begin
    ComboBoxImageMode.Enabled := true;
    ComboBoxImageMode.Items.Add(gImageModeArrayText[mCameraRemoteParam.ImageMode[i]]);
  end;

  //MLWeiMode combobox
  ComboBoxMeteringMode.Enabled := false;
  ComboBoxMeteringMode.Items.Clear;
  for i := 0 to high(mCameraRemoteParam.MLWeiMode) do begin
    ComboBoxMeteringMode.Enabled := true;
    ComboBoxMeteringMode.Items.Add(gMLWeiModeArrayText[mCameraRemoteParam.MLWeiMode[i]]);
  end;

  //AFDistance combobox
  ComboBoxAFDistance.Enabled := false;
  ComboBoxAFDistance.Items.Clear;
  for i := 0 to high(mCameraRemoteParam.AFDistance) do begin
    ComboBoxAFDistance.Enabled := true;
    ComboBoxAFDistance.Items.Add(gAFDistanceArrayText[mCameraRemoteParam.AFDistance[i]]);
  end;

  //WhiteBalanceSetting combobox
  ComboBoxWhiteBalance.Enabled := false;
  ComboBoxWhiteBalance.Items.Clear;
  for i := 0 to high(mCameraRemoteParam.WhiteBalanceSetting) do begin
    ComboBoxWhiteBalance.Enabled := true;
    ComboBoxWhiteBalance.Items.Add(gWhiteBalanceSetArrayText[mCameraRemoteParam.WhiteBalanceSetting[i]]);
  end;

  //Photo Effect combobox
  ComboBoxPhotoEffect.Enabled := false;
  ComboBoxPhotoEffect.Items.Clear;
  for i := 0 to high(mCameraRemoteParam.PhotoEffect) do begin
    ComboBoxPhotoEffect.Enabled := true;
    ComboBoxPhotoEffect.Items.Add(gPhotoEffectArrayText[mCameraRemoteParam.PhotoEffect[i]]);
  end;

  //Contrast combobox
  ComboBoxContrast.Enabled := false;
  ComboBoxContrast.Items.Clear;
  for i := 0 to high(mCameraRemoteParam.Contrast) do begin
    ComboBoxContrast.Enabled := true;
    ComboBoxContrast.Items.Add(gContrastArrayText[mCameraRemoteParam.Contrast[i]]);
  end;

  //Colorgain combobox
  ComboBoxColorGain.Enabled := false;
  ComboBoxColorGain.Items.Clear;
  for i := 0 to high(mCameraRemoteParam.Colorgain) do begin
    ComboBoxColorGain.Enabled := true;
    ComboBoxColorGain.Items.Add(gColorGainArrayText[mCameraRemoteParam.Colorgain[i]]);
  end;

  //Sharpness combobox
  ComboBoxSharpness.Enabled := false;
  ComboBoxSharpness.Items.Clear;
  for i := 0 to high(mCameraRemoteParam.Sharpness) do begin
    ComboBoxSharpness.Enabled := true;
    ComboBoxSharpness.Items.Add(gSharpnessArrayText[mCameraRemoteParam.Sharpness[i]]);
  end;

  //ISO combobox
  ComboBoxISO.Enabled := false;
  ComboBoxISO.Items.Clear;
  for i := 0 to high(mCameraRemoteParam.ISO) do begin
    ComboBoxISO.Enabled := true;
    ComboBoxISO.Items.Add(gISOArrayText[mCameraRemoteParam.ISO[i]]);
  end;

  //ExposureCompensation combobox
  ComboBoxExpComp.Enabled := false;
  ComboBoxExpComp.Items.Clear;
  for i := 0 to high(mCameraRemoteParam.ExposureComp) do begin
    ComboBoxExpComp.Enabled := true;
    ComboBoxExpComp.Items.Add(gExposureCompArrayText[mCameraRemoteParam.ExposureComp[i]]);
  end;

  //AV combobox
  ComboBoxAv.Enabled := false;
  ComboBoxAv.Items.Clear;
  for i := 0 to high(mCameraRemoteParam.AV) do begin
    ComboBoxAv.Enabled := true;
    ComboBoxAv.Items.Add(gAvArrayText[mCameraRemoteParam.AV[i]]);
  end;

  //TV combobox
  ComboBoxTv.Enabled := false;
  ComboBoxTv.Items.Clear;
  for i := 0 to high(mCameraRemoteParam.TV) do begin
    ComboBoxTv.Enabled := true;
    ComboBoxTv.Items.Add(gTvArrayText[mCameraRemoteParam.TV[i]]);
  end;

  //Beep checkbox
  CheckBoxBeep.Enabled := false;
  if (high(mCameraRemoteParam.Beep) > 0) then begin
    CheckBoxBeep.Enabled := true;
  end;
end;

//Sets new remote parameters in the VCLs in the parameters tab
procedure TFormRemote.SetRemoteParameters(inParam : RemoteReleaseParametersType);
begin
  ComboBoxQuality.ItemIndex      := ComboBoxQuality.Items.IndexOf(gCompQualArrayText[inParam.CompQuality]);
  ComboBoxSize.ItemIndex         := ComboBoxSize.Items.IndexOf(gImageSizeArrayText[inParam.ImageSize]);
  ComboBoxFlash.ItemIndex        := ComboBoxFlash.Items.IndexOf(gStrobeSettingArrayText[inParam.StrobeSetting]);
  ComboBoxFlashComp.ItemIndex    := ComboBoxFlashComp.Items.IndexOf(gStrobeCompSettingArrayText[inParam.StrobeCompSetting]);
  ComboBoxImageMode.ItemIndex    := ComboBoxImageMode.Items.IndexOf(gImageModeArrayText[inParam.ImageMode]);
  ComboBoxMeteringMode.ItemIndex := ComboBoxMeteringMode.Items.IndexOf(gMLWeiModeArrayText[inParam.MLWeiMode]);
  ComboBoxAFDistance.ItemIndex   := ComboBoxAFDistance.Items.IndexOf(gAFDistanceArrayText[inParam.AFDistance]);
  ComboBoxWhiteBalance.ItemIndex := ComboBoxWhiteBalance.Items.IndexOf(gWhiteBalanceSetArrayText[inParam.WhiteBalanceSetting]);
  ComboBoxPhotoEffect.ItemIndex  := ComboBoxPhotoEffect.Items.IndexOf(gPhotoEffectArrayText[inParam.PhotoEffect]);
  ComboBoxContrast.ItemIndex     := ComboBoxContrast.Items.IndexOf(gContrastArrayText[inParam.Contrast]);
  ComboBoxColorGain.ItemIndex    := ComboBoxColorGain.Items.IndexOf(gColorGainArrayText[inParam.ColorGain]);
  ComboBoxSharpness.ItemIndex    := ComboBoxSharpness.Items.IndexOf(gSharpnessArrayText[inParam.Sharpness]);
  ComboBoxISO.ItemIndex          := ComboBoxISO.Items.IndexOf(gISOArrayText[inParam.ISO]);
  ComboBoxAv.ItemIndex           := ComboBoxAv.Items.IndexOf(gAVArrayText[inParam.AV]);
  ComboBoxTv.ItemIndex           := ComboBoxTv.Items.IndexOf(gTVArrayText[inParam.TV]);
  ComboBoxExpComp.ItemIndex      := ComboBoxExpComp.Items.IndexOf(gExposureCompArrayText[inParam.ExposureCompensation]);
  CheckBoxBeep.Checked := false;
  if (inParam.Beep = RemoteFormatBeepOn) then
  begin
    CheckBoxBeep.Checked := true;
  end;
end;

//Event when changing the zoom trackbar
procedure TFormRemote.TrackBarZoomChange(Sender: TObject);
begin
  LabelZoomPos.Caption := IntToStr(TrackBarZoom.Position);
  if ((mReleaseProcessActive) and (mCameraCapability.DoSupportZoom)) then
  begin
    //Turn of Viewfinder temporarily when changing zoom. May not be necessary.
    if mViewFinderEnabled then begin
      CamRemote.RemoteStopViewfinder;
      sleep(1000);
    end;
    CamRemote.RemoteSetZoomPos(TrackBarZoom.Position);
    if mViewFinderEnabled then begin
      sleep(1000);
      CamRemote.RemoteStartViewfinder;
    end;
  end;
end;

procedure TFormRemote.ButtonViewFinderClick(Sender: TObject);
begin
  mViewFinderEnabled := true;
  FormViewFinder.Show;
end;

procedure TFormRemote.ButtonSetCameraSettingsClick(Sender: TObject);
var remote_parameters : RemoteReleaseParametersType;
begin
  //Sets release parameters
  remote_parameters := GetRemoteParameters;
  Log('Sets remote parameters');
  LogRemoteParameters(remote_parameters);
  CamRemote.RemoteSetRemoteParams(remote_parameters);
end;

//Gets remote parameters from the VCL in the remote tab
function TFormRemote.GetRemoteParameters : RemoteReleaseParametersType;
begin
  if (ComboBoxQuality.Enabled) then
    result.CompQuality  := mCameraRemoteParam.CompQuality[ComboBoxQuality.ItemIndex]
  else
    result.CompQuality := RemoteFormatQualityNotUsed;

  if (ComboBoxSize.Enabled) then
    result.ImageSize := mCameraRemoteParam.ImageSize[ComboBoxSize.ItemIndex]
  else
    result.ImageSize := RemoteFormatSizeNotUsed;

  if (ComboBoxFlash.Enabled) then
    result.StrobeSetting := mCameraRemoteParam.StrobeSetting[ComboBoxFlash.ItemIndex]
  else
    result.StrobeSetting := RemoteFormatFlashNotUsed;

  if (ComboBoxFlashComp.Enabled) then
    result.StrobeCompSetting := mCameraRemoteParam.StrobeCompSetting[ComboBoxFlashComp.ItemIndex]
  else
    result.StrobeCompSetting := RemoteFormatFlashCompNotUsed;

  if (ComboBoxImageMode.Enabled) then
    result.ImageMode := mCameraRemoteParam.ImageMode[ComboBoxImageMode.ItemIndex]
  else
    result.ImageMode := RemoteFormatShootingModeNotUsed;

  if (ComboBoxMeteringMode.Enabled) then
    result.MLWeiMode := mCameraRemoteParam.MLWeiMode[ComboBoxMeteringMode.ItemIndex]
  else
    result.MLWeiMode := RemoteFormatMLWeiNotUsed;

  if (ComboBoxAFDistance.Enabled) then
    result.AFDistance := mCameraRemoteParam.AFDistance[ComboBoxAFDistance.ItemIndex]
  else
    result.AFDistance := RemoteFormatAFDistNotUsed;

  if (ComboBoxWhiteBalance.Enabled) then
    result.WhiteBalanceSetting  := mCameraRemoteParam.WhiteBalanceSetting[ComboBoxWhiteBalance.ItemIndex]
  else
    result.WhiteBalanceSetting  := RemoteFormatWBNotUsed;

  if (ComboBoxPhotoEffect.Enabled) then
    result.PhotoEffect := mCameraRemoteParam.PhotoEffect[ComboBoxPhotoEffect.ItemIndex]
  else
    result.PhotoEffect := RemoteFormatPhotoEffectNotUsed;

  if (ComboBoxContrast.Enabled) then
    result.Contrast := mCameraRemoteParam.Contrast[ComboBoxContrast.ItemIndex]
  else
    result.Contrast := RemoteFormatLevelNotUsed;

  if (ComboBoxColorGain.Enabled) then
    result.ColorGain := mCameraRemoteParam.ColorGain[ComboBoxColorGain.ItemIndex]
  else
    result.ColorGain := RemoteFormatLevelNotUsed;

  if (ComboBoxSharpness.Enabled) then
    result.Sharpness := mCameraRemoteParam.Sharpness[ComboBoxSharpness.ItemIndex]
  else
    result.Sharpness := RemoteFormatLevelNotUsed;

  if (ComboBoxISO.Enabled) then
    result.ISO := mCameraRemoteParam.ISO[ComboBoxISO.ItemIndex]
  else
    result.ISO := RemoteFormatISONotUsed;

  if (ComboBoxAV.Enabled) then
    result.AV := mCameraRemoteParam.AV[ComboBoxAv.ItemIndex]
  else
    result.AV := RemoteFormatAVNotUsed;

  if (ComboBoxTV.Enabled) then
    result.TV := mCameraRemoteParam.TV[ComboBoxTv.ItemIndex]
  else
    result.TV := RemoteFormatTVNotUsed;

  if (ComboBoxExpComp.Enabled) then
    result.ExposureCompensation := mCameraRemoteParam.ExposureComp[ComboBoxExpComp.ItemIndex]
  else
    result.ExposureCompensation := RemoteFormatExposureCompNotUsed;

  if (CheckBoxBeep.Enabled) then
  begin
    if (CheckBoxBeep.Checked) then
    begin
      result.Beep := RemoteFormatBeepOn;
    end else begin
      result.Beep := RemoteFormatBeepOff;
    end;
  end else begin
    result.Beep := RemoteFormatBeepNotUsed;
  end;
end;

procedure TFormRemote.LogRemoteParameters(RemoteParameters : RemoteReleaseParametersType);
begin
  //Log remote properties
  Log('Logs remote parameters');
  Log('CompQuality          = ' + inttostr(ord(RemoteParameters.CompQuality)));
  Log('ImageSize            = ' + inttostr(ord(RemoteParameters.ImageSize)));
  Log('StrobeSetting        = ' + inttostr(ord(RemoteParameters.StrobeSetting)));
  Log('StrobeCompSetting    = ' + inttostr(ord(RemoteParameters.StrobeCompSetting)));
  Log('ImageMode            = ' + inttostr(ord(RemoteParameters.ImageMode)));
  Log('MLWeiMode            = ' + inttostr(ord(RemoteParameters.MLWeiMode)));
  Log('AFDistance           = ' + inttostr(ord(RemoteParameters.AFDistance)));
  Log('WhiteBalanceSetting  = ' + inttostr(ord(RemoteParameters.WhiteBalanceSetting)));
  Log('PhotoEffect          = ' + inttostr(ord(RemoteParameters.PhotoEffect)));
  Log('Contrast             = ' + inttostr(ord(RemoteParameters.Contrast)));
  Log('ColorGain            = ' + inttostr(ord(RemoteParameters.ColorGain)));
  Log('Sharpness            = ' + inttostr(ord(RemoteParameters.Sharpness)));
  Log('ISO                  = ' + inttostr(ord(RemoteParameters.ISO)));
  Log('Av                   = ' + inttostr(ord(RemoteParameters.Av)));
  Log('Tv                   = ' + inttostr(ord(RemoteParameters.Tv)));
  Log('ExposureCompensation = ' + inttostr(ord(RemoteParameters.ExposureCompensation)));
  Log('Beep                 = ' + inttostr(ord(RemoteParameters.Beep)));
end;

//Gets application version text
function TFormRemote.Versiontext : string;
var
  size  : DWord;
  size2 : DWord;
  pt    : Pointer;
  pt2   : Pointer;
begin
  //Get the version of application
  result := '';
  size   := GetFileVersionInfoSize(PChar(ParamStr(0)), size2);
  if (size > 0) then
  begin
    GetMem(pt, size);
    try
       GetFileVersionInfo(PChar(ParamStr(0)), 0, size, pt);
       // show the fixed information
       VerQueryValue(pt, '\', pt2, size2);
       with TVSFixedFileInfo(pt2^) do
       begin
         result := result + IntToStr(HiWord(dwFileVersionMS)) + '.';
         result := result + IntToStr(LoWord(dwFileVersionMS)) + '.';
         result := result + IntToStr(HiWord(dwFileVersionLS));
         result := result + ' Build:' + IntToStr(LoWord(dwFileVersionLS));
       end;
    finally
      FreeMem(pt);
    end;
  end;
end;

//Separate application exception handler, making it possible to log
//all exceptions.
procedure TFormRemote.AppException(Sender: TObject; E: Exception);
begin
  log('AppException. Exception=' + E.Message);
  Application.ShowException(E);
end;

//Function to get the filename of the log-file
function TFormRemote.GetLogFileName : string;
var file_dir : string;
begin
  file_dir := ParamStr(0);
  file_dir := extractFileDir(file_dir);
  result   := file_dir + LOG_FILE_NAME;
end;

//Write OS information to log
procedure TFormRemote.WriteVerToLog;
var
  ver_info : TOSVERSIONINFO;
  str      : String;
  i        : Word;
begin
  ver_info.dwOSVersionInfoSize := SizeOf(TOSVersionInfo);
  if GetVersionEx(ver_info) then begin
    Log('Size of OS-version text:' + IntToStr(ver_info.dwOSVersionInfoSize));
    Log('Major OS-version:'        + IntToStr(ver_info.dwMajorVersion));
    Log('Minor OS-version:'        + IntToStr(ver_info.dwMinorVersion));
    Log('Build of OS-version:'     + IntToStr(ver_info.dwBuildNumber));
    case ver_info.dwPlatformId of
      VER_PLATFORM_WIN32s         : Log('Win16 running Win32s');
      VER_PLATFORM_WIN32_WINDOWS  : Log('Win32 Windows, probably Win95');
      VER_PLATFORM_WIN32_NT       : Log('WinNT, full 32-bit');
    end;
    str := '';
    for i := 0 to 127 do
    begin
      str := str + ver_info.szCSDVersion[i];
    end;
    Log('Additional OS data:' + str);
  end;
end;

//Procedure for writing a string to the log
procedure TFormRemote.Log(Text : string);
var buffer : array[1..512] of char;
    i      : integer;
begin
  if (CheckBoxDebug.Checked) then
  begin
    Text := DateTimeToStr(now) + ':' + Text;
    for i := 1 to length(Text) do
    begin
      buffer[i] := Text[i];
    end;
    buffer[length(Text) + 1] := #13;
    buffer[length(Text) + 2] := #10;
    mLogFile.Write(buffer, length(Text) + 2);
  end;
end;

//Procedure to connect to a camera
procedure TFormRemote.ConnectToCamera;
begin
  //See if already conected
  if (not mConnToCamera) then
  begin
    try
      mCameraInfo := CamRemote.Connect;
      StatusBar.SimpleText := 'Camera is connected';
      mConnToCamera := true;
      Log('Camera model='        + mCameraInfo.CameraModelName);
      Log('Camera name='         + mCameraInfo.OwnerName);
      Log('Camera connected');
    except
      on E:exception do
        begin
          log('Connect_to_powershot. Exception=' + E.Message);
          StatusBar.SimpleText := 'Connection to camera failed';
          mConnToCamera        := false;
          raise;
        end;
    end;
  end;
end;

//Procedure to disconnect from a camera
procedure TFormRemote.DisconnectFromCamera;
begin
  //See if not connected
  if (mConnToCamera) then
  begin
    try
      mConnToCamera := false;
      CamRemote.Disconnect;
      StatusBar.SimpleText := 'Camera is disconnected';
      Log('Camera is disconnected');
    except
      on E:exception do
        begin
          log('Disconnect_from_powershot. Exception=' + E.Message);
          StatusBar.SimpleText := 'Camera communication error';
          raise;
        end;
    end;
  end else begin
    StatusBar.SimpleText := 'Camera already disconnected';
  end;
end;

procedure TFormRemote.CheckBoxDebugClick(Sender: TObject);
var default_string : string;
begin
  if FormRemote.Visible then
  begin
    if (not CheckBoxDebug.Checked) then
    begin
      default_string := Format('Debug is disabled. The logfile (%s) will be removed',
                               [GetLogFileName]);
      MessageDlg(default_string, mtInformation, [mbYes], 0);
      mLogFile.Free;
      DeleteFile(GetLogFileName);
    end else begin
      default_string := Format('Debug is enabled. The logfile (%s) will be created',
                               [GetLogFileName]);
      MessageDlg(default_string, mtInformation, [mbYes], 0);
      mLogFile := TFileStream.Create(GetLogFileName, (fmCreate or fmShareDenyWrite));
    end;
  end;
end;

//Camera event handler
procedure TFormRemote.CamRemoteEvent(Event: EventCallbackType);
var camera_text   : string;
    text_message  : string;
    message_out   : MessageQueueElementType;
begin
  FormRemote.Log('Callback Severity=' + inttostr(Ord(Event.Severity)) +
                 'Event =' + inttostr(Ord(Event.Event)));
  //Do not handle information message, not of interest
  if (Event.Severity = EventSeverityInfo) then
    exit;
  camera_text := 'Camera event-';
  case Event.Severity of
    EventSeverityWarning : text_message := 'Camera warning event';
    EventSeverityClosing : text_message := 'Camera shutdown event';
  end;
  case Event.Event of
    EventBatteryLevelNormal :     camera_text := camera_text + 'Battery level normal';
    EventBatteryLevelWeak :       camera_text := camera_text + 'Battery level weak';
    EventBatteryLevelSafetyLow :  camera_text := camera_text + 'Battery level safety low';
    EventBatteryLevelLB :         camera_text := camera_text + 'Battery level LB';
    EventDialChanged :            camera_text := camera_text + 'Dial changed';
    EventCFGateOpened :           camera_text := camera_text + 'CF gate opened';
    EventBatteryCoverOpened :     camera_text := camera_text + 'Battery cover opened';
    EventConnectionDisappeared :  camera_text := camera_text + 'Camera connection disappeared';
    EventUnrecoverableError :     camera_text := camera_text + 'Unrecoverable error';
    EventUnkonwnCommandReceived : camera_text := camera_text + 'Unknown command received';
    EventRemoteParamterChanged :  camera_text := camera_text + 'Remote parameter changed';
  end;
  //Send the event text to the message thread
  message_out.MessageText   := text_message;
  message_out.Caption       := camera_text;
  message_out.Style         := MB_OK or MB_ICONWARNING;
  message_out.Critical      := false;
  FormRemote.MessageThread.AddMessage(message_out);
end;

//Viewfinder event handler.
procedure TFormRemote.CamRemoteViewfinderEvent(Jpegdata: TMemoryStream);
var jpg : TJpegImage;
begin
  jpg := TJpegImage.Create;
  //Get the 320x240 picture and update the image on the dialogue
  try
    jpg.LoadFromStream(Jpegdata);
    FormViewFinder.Image.Picture.Assign(jpg);
  finally
    jpg.Free;
  end;
end;

//Get picture after taking a picture event handler
procedure TFormRemote.CamRemoteRemoteGetPictureEvent(
  PercentageDone: Integer);
begin
  FormRemote.StatusBar.SimpleText := 'Receiving the picture to disc';
  FormRemote.ProgressBar.Position := PercentageDone;
end;

//Receiving picture event handler when taking a picture
procedure TFormRemote.CamRemoteRemoteTakePictureEvent(
  PercentageDone: Integer);
begin
  FormRemote.StatusBar.SimpleText := 'Handles the picture';
  FormRemote.ProgressBar.Position := PercentageDone;
end;

//Remote process event handler
procedure TFormRemote.CamRemoteRemoteEvent(Event: RemoteEventCallbackType);
begin
  FormRemote.Log('Remote callback event=' + inttostr(Ord(Event)));
  //Check if the release button was pressed on the camera.
  //This applies to PowerShot cameras. EOS cameras do not generate
  //this event when pressing the shutter butten. Instead the EOS camera
  //takes the picture and generates a RemoteEventCallbackReleaseStart event.
  if (Event = RemoteEventCallbackCamReleaseOn) then
  begin
    TimerTakePicture.Enabled := true;
  end;
  if (not FormRemote.CheckBoxActiveMode.Checked) then
  begin
    if (Event = RemoteEventCallbackReleaseComplete) then
    begin
      FormRemote.PictureTaken;
    end;
  end;
end;

procedure TFormRemote.TimerTakePictureTimer(Sender: TObject);
begin
   TimerTakePicture.Enabled := false;
   ButtonTakePicClick(Application);
end;

end.
