unit UlanGlob;
{ global variables/parameters for Ulan program, for constant values/types see
  ulantype.pas }
{
  (C) 2000 - 2001 Jindrich Jindrich, Pavel Pisa, PiKRON Ltd.

  Originators of the CHROMuLAN project:

  Jindrich Jindrich - http://www.jindrich.com
                      http://orgchem.natur.cuni.cz/Chromulan/
                      software developer, project coordinator
  Pavel Pisa        - http://cmp.felk.cvut.cz/~pisa
                      embeded software developer
  PiKRON Ltd.       - http://www.pikron.com
                      project initiator, sponsor, instrument developer

  The CHROMuLAN project is distributed under the GNU General Public Licence.
  See file COPYING for details.

  Originators reserve the right to use and publish sources
  under different conditions too. If third party contributors
  do not accept this condition, they can delete this statement
  and only GNU license will apply.
}
interface
uses
  Windows, Classes, SysUtils, IniFiles,
  UtlType, PropUtl, UlanType, ULDrvTyp,
  ApexType, WinUtl;

{Exceptions}
type
  ENotImplemented = class(Exception);
    { The feature was not implemented yet }
  EInvalidParams = class(Exception);
    { Procedure called with invalid input parameters }
  EInvalidFileExt = class(Exception);
    { Filename with unsupported extension was tried to open }
  EOnlyULFSupported = class(Exception);
    { Trying to create analysis with file name with extension different from .ULF }
  EAcqAlreadyOpened = class(Exception);
    { Trying to opened new chromagram window (for acquisition), but it was
      already opened for current channel. }
  EImportAborted = class(Exception);
    { When importing TXT file, the chance to change import parameters is
      given to user, if he presses Cancel, this exception is raised. }
  EDataOpenFailed = class(Exception);
  {v0.66}
  ETemplateNotFound = class(Exception);
  {/v0.66}
{/Exception}

var
{ini.lst}
  DefPortName: shortstring = 'COM2';
    { what is the default port for communication }
  DefDeviceMode: TDeviceMode = dmUlan;
    { Set to dmUlan or dmApex, defines default type of
      communication with Pikron devices.
      dmUlan by default, if not running under NT/2000 get adjusted to
      dmApex after warning the user.
      Can be changed back in Setup|Options dialog.
      Copied to CurDeviceMode after reading from ini, CurDeviceMode
      is copied back to DefDeviceMode before writing to ini  }
  DefUVDetAddr:longint = 3;
    { What is the default address of UV detector in ulan network }
  {v1.05}
  DefFilterType: TFilterType =  ftNone;
    { what filtering scheme is beeing used to display the spectrum,
      see ulantype.ftXXXX }
  DefAvgPointCount: longint = 5;
    { what number of points is used for averaging if FilterType = ftAvg }
  DefFilter1: single = 0.5;
    { what is the value of cofficient used to display the spectrum if
      FilterType = ftFilter1 }
  {/v1.05}
  DefaultAnalysisName: shortstring = {v0.13}'DEFAULT.ULT';{/v0.13 'DEFANAL.ULF';}
  VerifyAbort: boolean = true;
    { Ask user if the abortion of the acquisition or discarding of
      acquired data is really what he wants to do if he trying to close the
      window with running acquisition or acquired but not saved data. }

  ToolsAllowed: boolean = false;
  DebugToolsAllowed: boolean = false;
  TestAllowed: boolean = false;

  {v0.22 moved to ULObju}
  {/v0.22
  UserMode: TUserMode = umUser;{umSysOp}
    { behavior of some procedures behaves according this param.
      see ulantype umXXXX }
  MaxULAddr: integer = 20;
    { How many ulan device addresses should be scanned during autodetect. }
  {v0.22 moved to ULBrowu}
  {/v0.22
  AutoSizeBrowseCols : boolean = true;}
  AutoConfigDriver: boolean = {v0.54}false{/v0.54 true};
    { Try to install ul_drv.sys automatically? Disable if makes troubles. }
  PCUlanAddr: integer = 2;

  {v0.50}
  IniDataDir: shortstring = '%EXEDIR%DATA\';
     // copied to DataDir expanded
  IniTemplateDir: shortstring = {v0.64}{v0.73}'%DATADIR%Templates\'{/v0.73 '%DATADIR%Templates'}{/v0.64 '%EXEDIR%Templates\'};
     // copied to TemplateDir expanded
  IniMethodDir: shortstring = '%DATADIR%Methods\';
  IniSequenceDir: shortstring = '%DATADIR%Sequences\';
  IniPrgDir: shortstring = '%DATADIR%Programs\';
  {/v0.50
  IniDataDir: shortstring = 'DATA\';
     // copied to DataDir expanded
  IniTemplateDir: shortstring = 'Templates\';
     // copied to TemplateDir expanded
  IniMethodDir: shortstring = 'DATA\Methods\';
  IniSequenceDir: shortstring = 'DATA\Sequences\';
  IniPrgDir: shortstring = 'DATA\Programs\';
  }

  ReportDir: shortstring = '';
  BaseSplittingAllowed: boolean = false;{true;{ create baseline allows splitting existing
    baseline, then size neighboring baseline sections together }
  UlanPointTimeInterval: single = 40;{ms}
    { sampling rate 25 Hz }
  {v0.11}{/v0.11 GHLabPointTimeInterval: single = 31.25;{ms}
  {v0.09}
  PeakOverlapAllowed: boolean = false;{true;}
  {/v0.09}

  {v0.14}
  DefAnalTemplate: shortstring = '';
    { Updated, loaded and saved from FileNewDlg; file name of the template
      to be used for the new analysis }
  {/v0.14}
  
  {v0.41}
  DefAnalSeq: shortstring = '';
  {/v0.41}

  {v0.18}
  MaxSpectrumFormCount: integer = 4;
    {max allowed number of spectrum windows}
  {/v0.18}
  {v0.24}
  DefaultApplication: shortstring = 'None';
    { can only have one of the values specified in DevSetFr.DefAppComboBox.Items:
      None
      AAA }
  {/v0.24}

  {v0.28}
  UseLanguage: boolean = false;
  LanguageName: shortstring = '';
  {/v0.28}
  {v0.29}
  RootUsrDir: shortstring = '';
    { root for all data, ini, etc., the dir where is the INI file }
  {/v0.29}
  {v0.45}
  AutofixData: boolean = false;
    { check every opened data ULF file for natural time sequence of data points }
  {/v0.45}
  {v0.53}
  SimulatingData: boolean = false;
    { can be set for acquisition debugging purposes if no device is available; }
  {/v0.53}
  {v0.54}
  ShouldUpdateMethodPeakFromDataPeak: boolean = false;
    { Default value of checkbox in PickMethodPeakFrm. If true, then after
      selection of method peak for current data peak, the method peak
      will be updated by the current peak's values. }
  {/v0.54}
  {v0.64}
  { Should the detection of connected modules be run once after program starts? }
  ShouldAutoScanForModules: boolean = true;
  {/v0.64}
  {v0.74}
  PropertyLogging: boolean = true;
  {/v0.74}
  { Send e-mail with error message for which the sequence run was aborted.
    Setup the e-mail parameters using Setup | e-mail }
  EmailOnAbort: boolean = false;
{/ini.lst}
  {v0.14}
  TemplateDir: shortstring = '';
  {/v0.14}

  {v0.41}
  MethodDir: shortstring = '';
  SequenceDir: shortstring = '';
  PrgDir: shortstring = '';
  {/v0.41}

  {v0.13}
  DataDir: shortstring = '';
  {/v0.13}
  PortAddr: {v0.11}integer {/v0.11 word} = $2f8;
    { default serial port address used to create ul_drv.req }
  PortIrq: {v0.11}integer{/v0.11 byte} = 3;
    { default irq used to create ul_drv.req }
  {v0.21}
  UlanBaudRate: integer = $2580;{=9600}
    { default baud rate to create ul_drv.req }
  {/v0.21}
  {v0.49}
  ULDrvStartType: TDevDrvStartType = {v0.50}stAuto{/v0.50 stSystem};{default value; runtime retrieved from registry}
  {/v0.49}
const
  MinXStep = 0.1; { in seconds }
  MinYStep = 0.0001;

  MinUserYStep = MinYStep;
    { Minimal allowed Y difference of two points, in user units (same
      as exp units - AU) }
  MinUserXStep = MinXStep / 60;
    { Minimal allowed X difference of two points, in user units (minutes) }
var
  CurFilterPars: TFilterPars = (
    FilterType : ftNone;
    AvgPointCount : 5;
    Filter1 : 0.5);
    { updated as default from OK click in FILTDLG.PAS,
      used as default in SPECTRUM.PAS apexpoints.create }

  CurDeviceMode: TDeviceMode = dmUnspecified;
    { set after reading ini file to DefDeviceMode or can be set by
      other objects to something else if the created specform
      should use another type of device;
     Used only in DevSetFr now (v0.14) }

  CurPortName:shortstring = 'COM2';
  CurUVDetAddr:longint = 3;

  CurUserViewLimit: TUserViewLimit = (
   Min:(X:0;Y:{v0.15}DefMinUsrYValue{/v0.15 -0.1});Max:(X:20;Y:{v0.13}DefMaxAcqYValue{/v0.13 2})
  );
  NewUserViewLimit: TUserViewLimit = (
   Min:(X:0;Y:{v0.15}DefMinUsrYValue{/v0.15 -0.1});Max:(X:20;Y:{v0.13}DefMaxAcqYValue{/v0.13 2})
  );

  OverlayMode: boolean = false;
    { Can change at runtime only. If set true, then next opened chromatogram
      file will be added to active chromatogram. }
  {v0.23}
  AAAAutoAssignDefNames: boolean = {v0.50}false{/v0.50 true};
  {/v0.23}


{ Runtime only (not from INI) }
{v0.41}
var
  AAAActive: boolean = false;
{/v0.41}
{v0.65}
  { Gets assigned in Main.FormCreate to RegisterWindowMessage('CHROMuLAN').
    Should be used by cooperating applications. }
  CHROMuLANMessage: integer = 0;
{/v0.65}
var
  OSVersion:OSVERSIONINFO;
    { initialized upon call to UlanConfigRead
      DWORD dwOSVersionInfoSize;
      DWORD dwMajorVersion;
      DWORD dwMinorVersion;
      DWORD dwBuildNumber;
      DWORD dwPlatformId;
          VER_PLATFORM_WIN32s	        Win32s on Windows 3.1.
          VER_PLATFORM_WIN32_WINDOWS	Win32 on Windows 95.
          VER_PLATFORM_WIN32_NT	        Win32 on Windows NT.
      TCHAR szCSDVersion[ 128 ];
    }

procedure UlanConfigReadWrite(rw:TReadWrite);

{v0.50}
procedure UpdateIniDirs;
  { should be called every time if some IniXXXXDir value changed }
{/v0.50}

{v0.53}
function GetOSVersion: string;
{/v0.53}

{v0.68}
var
  { Set True during executing call CuLDoCmdu .CuLDoCmd }
  FInCuLDoCmd: boolean = false;

function InCuLDoCmd: boolean;
{/v0.68}

implementation
{v0.22}
uses
  ULObju{v0.24}{/v0.24, ULBrowu};
{/v0.22}

{v0.50}
procedure UpdateIniDir(const AIniDir: string; var ADir: shortstring);
begin
  ADir := AbsoluteFileName(RootUsrDir, ReplaceEnvVars(AIniDir), '');
  CreateDir(ADir);
end;

procedure UpdateIniDirs;
begin
  UpdateIniDir(IniDataDir, DataDir);
  SetEnv('DataDir', DataDir);

  UpdateIniDir(IniTemplateDir, TemplateDir);
  UpdateIniDir(IniMethodDir, MethodDir);
  UpdateIniDir(IniSequenceDir, SequenceDir);
  UpdateIniDir(IniPrgDir, PrgDir);
end;
{/v0.50}

procedure UlanConfigReadWrite(rw:TReadWrite);
var f: TIniFile;
begin
  if rw = rwWrite then begin
    DefDeviceMode := CurDeviceMode;
    DefPortName := CurPortName;
    DefUVDetAddr := CurUVDetAddr;

    DefFilterType := CurFilterPars.FilterType;
    DefAvgPointCount := CurFilterPars.AvgPointCount;
    DefFilter1 := CurFilterPars.Filter1;
  end;
  {v0.29}
  RootUsrDir := ExtractFileDir(FindIniFile);{winutl}
  {/v0.29}
  f := TIniFile.Create(FindIniFile);
  try

    ConfigReadWriteValue(f, rw, DevSection, 'DefPortName', @DefPortName, ptString);
    ConfigReadWriteValue(f, rw, DevSection, 'DevMode', @DefDeviceMode, ptByte);
    ConfigReadWriteValue(f, rw, DevSection, 'UVDetAddr', @DefUVDetAddr, ptLongint);
    ConfigReadWriteValue(f, rw, DevSection, 'MaxULAddr', @MaxULAddr, ptLongint);
    {v0.21}
    ConfigReadWriteValue(f, rw, DevSection, 'AutoConfigDriver', @AutoConfigDriver, ptByte);
    {/v0.21}

    {v0.11 now values for ul_drv reading/writing only from/to Registry}
    {/v0.11
    ConfigReadWriteValue(f, rw, DevSection, 'PortAddr', @PortAddr, ptWord);
    ConfigReadWriteValue(f, rw, DevSection, 'PortIrq', @PortIrq, ptByte);
    ConfigReadWriteValue(f, rw, DevSection, 'PCUlanAddr', @PCUlanAddr, ptLongint);}

    ConfigReadWriteValue(f, rw, DevSection, 'UlanPointTimeInterval', @UlanPointTimeInterval, ptSingle);
    {v0.08}
    {v0.11}{/v0.11
    ConfigReadWriteValue(f, rw, DevSection, 'GHLabPointTimeInterval', @GHLabPointTimeInterval, ptSingle);}
    {/v0.08}
    ConfigReadWriteValue(f, rw, SpecSection, 'FilterType', @DefFilterType, ptByte);
    ConfigReadWriteValue(f, rw, SpecSection, 'AvgPointCount', @DefAvgPointCount, ptLongint);
    ConfigReadWriteValue(f, rw, SpecSection, 'Filter1', @DefFilter1, ptSingle);
    ConfigReadWriteValue(f, rw, SpecSection, 'IniDataDir', @IniDataDir, ptString);
    ConfigReadWriteValue(f, rw, SpecSection, 'IniTemplateDir', @IniTemplateDir, ptString);
    {v0.41}
    ConfigReadWriteValue(f, rw, SpecSection, 'IniMethodDir', @IniMethodDir, ptString);
    ConfigReadWriteValue(f, rw, SpecSection, 'IniSequenceDir', @IniSequenceDir, ptString);
    ConfigReadWriteValue(f, rw, SpecSection, 'IniPrgDir', @IniPrgDir, ptString);
    {/v0.41}

    ConfigReadWriteValue(f, rw, SpecSection, 'MinX', @CurUserViewLimit.Min.X, ptSingle);
    ConfigReadWriteValue(f, rw, SpecSection, 'MaxX', @CurUserViewLimit.Max.X, ptSingle);
    ConfigReadWriteValue(f, rw, SpecSection, 'MinY', @CurUserViewLimit.Min.Y, ptSingle);
    ConfigReadWriteValue(f, rw, SpecSection, 'MaxY', @CurUserViewLimit.Max.Y, ptSingle);
    ConfigReadWriteValue(f, rw, SpecSection, 'DefaultAnal', @DefaultAnalysisName, ptString);
    {v0.18}
    ConfigReadWriteValue(f, rw, SpecSection, 'MaxSpectrumFormCount', @MaxSpectrumFormCount, ptLongint);
    {/v0.18}


    ConfigReadWriteValue(f, rw, EnvSectionName, 'ToolsAllowed', @ToolsAllowed, ptByte);
    ConfigReadWriteValue(f, rw, EnvSectionName, 'DebugToolsAllowed', @DebugToolsAllowed, ptByte);
    ConfigReadWriteValue(f, rw, EnvSectionName, 'TestAllowed', @TestAllowed, ptByte);
    ConfigReadWriteValue(f, rw, EnvSectionName, 'UserMode', @UserMode, ptByte);
    {v0.65}
    ConfigReadWriteValue(f, rw, EnvSectionName, 'ULObjFileVersion', @ULObjFileVersion, ptLongint);
    {/v0.65}
    {v0.24}
    ConfigReadWriteValue(f, rw, EnvSectionName, 'DefaultApplication', @DefaultApplication, ptString);
    {/v0.24
      ConfigReadWriteValue(f, rw, EnvSectionName, 'AutoSizeBrowCols', @AutoSizeBrowseCols, ptByte);}
    {v0.41}
    {v0.50}{/v0.50
    ConfigReadWriteValue(f, rw, EnvSectionName, 'AAAAutoAssignDefNames', @AAAAutoAssignDefNames, ptByte);}
    {/v0.41}
    {v0.45}
    ConfigReadWriteValue(f, rw, EnvSectionName, 'AutofixData', @AutofixData, ptByte);
    {/v0.45}

    {v0.53}
    ConfigReadWriteValue(f, rw, EnvSectionName, 'SimulatingData', @SimulatingData, ptByte);
    {/v0.53}
    {v0.54}
    ConfigReadWriteValue(f, rw, EnvSectionName, 'ShouldUpdateMethodPeakFromDataPeak', @ShouldUpdateMethodPeakFromDataPeak, ptByte);
    {/v0.54}
    {v0.64}
    ConfigReadWriteValue(f, rw, EnvSectionName, 'ShouldAutoScanForModules', @ShouldAutoScanForModules, ptByte);
    {/v0.64}
    {v0.74}
    ConfigReadWriteValue(f, rw, EnvSectionName, 'PropertyLogging', @PropertyLogging, ptByte);
    {/v0.74}
    {v0.76}
    ConfigReadWriteValue(f, rw, EnvSectionName, 'DebugLogging', @DebugLogging, ptByte);
    {/v0.76}

    ConfigReadWriteValue(f, rw, EnvSectionName, 'UseRelToRootFileNames', @UseRelToRootFileNames, ptByte);
    ConfigReadWriteValue(f, rw, EnvSectionName, 'EmailOnAbort', @EMailOnAbort, ptByte);

    {v0.28}
    {ConfigReadWriteValue(f, rw, EnvSectionName, 'UseLanguage', @UseLanguage, ptByte);
    ConfigReadWriteValue(f, rw, EnvSectionName, 'LanguageName', @LanguageName, ptString);}
    {/v0.28}

    if rw = rwRead then begin
      CurDeviceMode := DefDeviceMode;
      CurPortName := DefPortName;
      CurUVDetAddr := DefUVDetAddr;

      CurFilterPars.FilterType := DefFilterType;
      CurFilterPars.AvgPointCount := DefAvgPointCount;
      CurFilterPars.Filter1 := DefFilter1;

      {v0.68 moved to initialization section}
      {/v0.68
      OSVersion.dwOSVersionInfoSize := sizeof(OSVersion);
      GetVersionEx(OSVersion);}
        { checking for OSVersion in UlanModeAllowedByOS }

      {v0.50}
      UpdateIniDirs;
      {/v0.50
      DataDir := AbsoluteFileName(RootUsrDir, IniDataDir,'');
      CreateDir(DataDir);

      TemplateDir := AbsoluteFileName(RootUsrDir, IniTemplateDir,'');
      CreateDir(TemplateDir);

      MethodDir := AbsoluteFileName(RootUsrDir, IniMethodDir, '');
      CreateDir(MethodDir);

      SequenceDir := AbsoluteFileName(RootUsrDir, IniSequenceDir, '');
      CreateDir(SequenceDir);

      PrgDir := AbsoluteFileName(RootUsrDir, IniPrgDir, '');
      CreateDir(PrgDir);
      }
    end;

  finally
    f.Free;
  end;
end;


{v0.53}
const testi: integer = 0;

function GetOSVersion: string;
begin
  if OSVersion.dwPlatformID = VER_PLATFORM_WIN32_NT then
    Result := 'WinNT '
  else if OSVersion.dwPlatformID = VER_PLATFORM_WIN32s then
    Result := 'Win32s '
  else if OSVersion.dwPlatformID = VER_PLATFORM_WIN32_WINDOWS then begin
    Result := 'Win32 ';
  end else
    Result := 'Unknown ';
  Result := Result + IntToStr(OSVersion.dwMajorVersion) + '.' +
    IntToStr(OSVersion.dwMinorVersion) + ' Build:' +
    IntToStr(OSVersion.dwBuildNumber) +
    ' ' + StrPas(@OSVersion.szCSDVersion);
end;

{/v0.53}

{v0.68}
function InCuLDoCmd: boolean;
begin
  Result := FInCuLDoCmd;
end;
{/v0.68}

initialization
  {ConfigSetGlobals(nil, 0);}
  {v0.68}
  OSVersion.dwOSVersionInfoSize := sizeof(OSVersion);
  GetVersionEx(OSVersion);
  {/v0.68}

  if ReportDir = '' then
    ReportDir := ExtractFilePath(Paramstr(0));
  DecimalSeparator := '.';
end.
