unit Form_UartTerminal;

{$I _crw_sysdef}

{$IFDEF FPC}{$mode Delphi}{$ENDIF}{$H+}

{$WARN 5023 off : Unit "$1" not used in $2}

interface

uses
 _crw_sharemem, // NB: THIS UNIT MUST BE FIRST !!!
 {$IFDEF UNIX} cthreads, dl, {$ENDIF}
 {$IFDEF WINDOWS} windows, {$ENDIF}
 sysutils, classes, math, lclintf, lcltype, lmessages,
 graphics, controls, forms, dialogs, stdctrls, buttons, extctrls,
 comctrls, checklst, spin, process,
 _crw_alloc, _crw_rtc, _crw_ef, _crw_str, _crw_eldraw, _crw_fio,
 _crw_colors, _crw_appforms, _crw_apputils, _crw_apptools,
 _crw_uart, _crw_serio{, _crw_task};

type

  { TFormUartTerminal }

  TFormUartTerminal = class(TMasterForm)
    ButtonListComPorts: TButton;
    ButtonRunSercatGui: TButton;
    CheckListBoxDcbFlags: TCheckListBox;
    ComboBoxBaudRate: TComboBox;
    ComboBoxDataBits: TComboBox;
    PanelComPreset: TPanel;
    TimerScan: TTimer;
    GroupBoxComPreset: TGroupBox;
    LabelPortNum: TLabel;
    SpinEditPortNum: TSpinEdit;
    LabelDataBits: TLabel;
    LabelBaudRate: TLabel;
    LabelStopBits: TLabel;
    ComboBoxStopBits: TComboBox;
    LabelParity: TLabel;
    ComboBoxParity: TComboBox;
    LabelTimeOut: TLabel;
    SpinEditTimeOut: TSpinEdit;
    CheckBoxCheckSum: TCheckBox;
    GroupBoxRxTx: TGroupBox;
    LabelTx: TLabel;
    EditTx: TEdit;
    LabelRx: TLabel;
    EditRx: TEdit;
    GroupBoxCommands: TGroupBox;
    ButtonOpen: TButton;
    ButtonExit: TButton;
    ButtonClose: TButton;
    GroupBoxAdamUtils: TGroupBox;
    ButtonAdamScan: TButton;
    EditPrefix: TEdit;
    LabelAddr: TLabel;
    EditSuffix: TEdit;
    EditAdamAddr: TEdit;
    EditAdamTcj: TEdit;
    ButtonAdamZero: TButton;
    ButtonAdamTcj: TButton;
    GroupBoxHistory: TGroupBox;
    MemoHistory: TMemo;
    ButtonAdamWho: TButton;
    ButtonAdamAdc: TButton;
    ButtonAdamDio: TButton;
    ButtonAdamHelp: TButton;
    LabelAdamAddr: TLabel;
    LabelDcbFlags: TLabel;
    EditDcbFlags: TEdit;
    procedure FormCreate(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
    procedure FormClose(Sender: TObject; var Action: TCloseAction);
    procedure EditTxKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
    procedure FormDestroy(Sender: TObject);
    procedure TimerScanTimer(Sender: TObject);
    procedure ButtonOpenClick(Sender: TObject);
    procedure ButtonCloseClick(Sender: TObject);
    procedure ButtonExitClick(Sender: TObject);
    procedure ButtonAdamHelpClick(Sender: TObject);
    procedure ButtonAdamScanClick(Sender: TObject);
    procedure ButtonAdamWhoClick(Sender: TObject);
    procedure ButtonAdamAdcClick(Sender: TObject);
    procedure ButtonAdamDioClick(Sender: TObject);
    procedure ButtonAdamZeroClick(Sender: TObject);
    procedure ButtonAdamTcjClick(Sender: TObject);
    procedure ButtonListComPortsClick(Sender: TObject);
    procedure ButtonRunSercatGuiClick(Sender: TObject);
    procedure CheckListBoxDcbFlagsClickCheck(Sender: TObject);
  private
    { Private declarations }
    myPortNum  : Integer;
    myScanAddr : Byte;
    myColorTxOk : TColor;
    myColorRxOk : TColor;
    myColorRxEr : TColor;
    procedure UpdateState;
    procedure OpenComPort;
    procedure CloseComPort;
    procedure UpdateColors;
    procedure RecordHistory(const s:LongString);
    function  SendAndReceive(const aMessage:LongString; aSleep:Integer=0):LongString;
    procedure EnableScan(aEnabled:Boolean);
  public
    { Public declarations }
    function  ListParityTypes:LongString;
    function  ListBaudRates:LongString;
    function  ListStopBits:LongString;
    function  GetTimeOut:Integer;
    function  GetBaudRate:Integer;
    function  GetStopBits:Integer;
    function  GetDataBits:Integer;
    function  GetDcbFlags:Integer;
    function  GetXonXoff:Boolean;
    function  GetParity:Integer;
    function  GetBuffer:Integer;
    procedure UpdateDcbFlags;
  end;

procedure ExecuteUartTerminal(Pos:TPosition=poDesigned);

const
 UartTerminalHistory  : Integer = 1024;
 UartTerminalSysClose : Boolean = false;

implementation

{$R *.lfm}

const
 FormUartTerminal: TFormUartTerminal = nil;

procedure ExecuteUartTerminal;
begin
 if CanShowModal(FormUartTerminal) then
 try
  if not Assigned(FormUartTerminal) then begin
   Application.CreateForm(TFormUartTerminal, FormUartTerminal);
   FormUartTerminal.Master:=@FormUartTerminal;
  end;
  if Assigned(FormUartTerminal) then begin
   FormUartTerminal.UpdateState;
   if Pos in [poScreenCenter,poDesktopCenter]
   then LocateFormToCenterOfScreen(FormUartTerminal);
   mrVoice(FormUartTerminal.ShowModal);
  end;
 except
  on E:Exception do BugReport(E,nil,'ExecuteUartTerminal');
 end;
end;

procedure TFormUartTerminal.UpdateState;
var Opened:Boolean;
begin
 try
  EnableScan(false);
  Opened:=uart[myPortNum].Active;
  SetEnabledControls(Opened,[LabelTx,           EditTx,
                             LabelRx,           EditRx,
                             EditPrefix,        LabelAddr,     EditSuffix,
                             LabelAdamAddr,     EditAdamAddr,  EditAdamTcj,
                             ButtonAdamWho,     ButtonAdamAdc, ButtonAdamDio,
                             ButtonAdamZero,    ButtonAdamTcj,
                             ButtonClose,       ButtonAdamScan]);
  SetEnabledControls(not Opened,[LabelPortNum,     SpinEditPortNum,
                                 LabelBaudRate,    ComboBoxBaudRate,
                                 LabelParity,      ComboBoxParity,
                                 LabelDcbFlags,    EditDcbFlags,
                                                   CheckListBoxDcbFlags,
                                 LabelDataBits,    ComboBoxDataBits,
                                 LabelStopBits,    ComboBoxStopBits,
                                 LabelTimeOut,     SpinEditTimeOut,
                                 CheckBoxCheckSum, ButtonOpen]);
  if Opened then begin
   if EditTx.CanFocus then ActiveControl:=EditTx;
   Caption:=Format(RusEng('UART терминал [COM%d]','UART terminal [COM%d]'),[myPortNum]);
  end else begin
   Caption:=RusEng('UART терминал [закрыт]','UART terminal [closed]');
  end;
  UpdateColors;
 except
  on E:Exception do BugReport(E,Self,'UpdateState');
 end;
end;

procedure TFormUartTerminal.UpdateColors;
begin
 try
  if uart[myPortNum].Active then begin
   EditTx.Color:=myColorTxOk;
   if IsEmptyStr(EditTx.Text) or not IsEmptyStr(EditRx.Text)
   then EditRx.Color:=myColorRxOk
   else EditRx.Color:=myColorRxEr;
   EditPrefix.Color:=myColorTxOk;
   EditSuffix.Color:=myColorTxOk;
  end else begin
   EditTx.Color:=clBtnFace;
   EditRx.Color:=clBtnFace;
   EditPrefix.Color:=clBtnFace;
   EditSuffix.Color:=clBtnFace;
  end;
 except
  on E:Exception do BugReport(E,Self,'UpdateColor');
 end;
end;

procedure TFormUartTerminal.EnableScan(aEnabled:Boolean);
var Trigger:Boolean;
begin
 try
  Trigger:=(TimerScan.Enabled<>aEnabled);
  if EditTx.CanFocus then ActiveControl:=EditTx;
  TimerScan.Interval:=GetTimeOut*2;
  TimerScan.Enabled:=aEnabled;
  myScanAddr:=0;
  LabelAddr.Caption:=HexB(myScanAddr);
  EditTx.Text:='';
  EditRx.Text:='';
  if aEnabled
  then ButtonAdamScan.Caption:=RusEng('Остановка сканера','Stop Scan')
  else ButtonAdamScan.Caption:=RusEng('Сканировать адреса','Scan for addresses');
  if Trigger then begin
   if aEnabled
   then RecordHistory(RusEng('Сканер запущен','Start Scan'))
   else RecordHistory(RusEng('Сканер завершен','Stop Scan'));
  end;
 except
  on E:Exception do BugReport(E,Self,'EnableScan');
 end;
end;

procedure TFormUartTerminal.OpenComPort;
begin
 try
  if myPortNum=0 then begin
   EnableScan(false);
   if uart[SpinEditPortNum.Value].Active
   then RecordHistory(Format(RusEng('Порт COM%d уже открыт.','Port COM%d opened yet.'),[SpinEditPortNum.Value]))
   else if uart[SpinEditPortNum.Value].Open(GetBaudRate,GetParity,GetDataBits,GetStopBits,GetXonXoff,GetBuffer,GetDcbFlags)
   then myPortNum:=SpinEditPortNum.Value
   else RecordHistory(Format(RusEng('Порт COM%d недоступен.','Port COM%d is not accessible.'),[SpinEditPortNum.Value]));
   if (myPortNum>0) then RecordHistory(RusEng('Открыт','Opened')+Format(' COM%d %d %d %s %s $%x',[myPortNum,GetBaudRate,GetDataBits,ComboBoxParity.Text,ComboBoxStopBits.Text,GetDcbFlags]));
   UpdateState;
  end;
 except
  on E:Exception do BugReport(E,Self,'OpenComPort');
 end;
end;

procedure TFormUartTerminal.CloseComPort;
begin
 try
  if (myPortNum>0) then begin
   RecordHistory(RusEng('Закрыт','Closed')+Format(' COM%d',[myPortNum]));
   if uart[myPortNum].Active then uart[myPortNum].Close;
  end;
  myPortNum:=0;
  UpdateState;
 except
  on E:Exception do BugReport(E,Self,'CloseComPort');
 end;
end;

procedure TFormUartTerminal.RecordHistory(const s:LongString);
begin
 try
  while (MemoHistory.Lines.Count>UartTerminalHistory) do MemoHistory.Lines.Delete(0);
  MemoHistory.Lines.Add(s); MemoHistory.SelStart:=MaxInt;
 except
  on E:Exception do BugReport(E,Self,'RecordHistory');
 end;
end;

function TFormUartTerminal.SendAndReceive(const aMessage:LongString; aSleep:Integer=0):LongString;
var t:Int64;
begin
 Result:='';
 try
  if uart[myPortNum].Active then begin
   if Length(aMessage)>0 then EditTx.Text:=aMessage;
   Result:=EditTx.Text+ASCII_CR;
   if CheckBoxCheckSum.Checked then Result:=CatCheckSumCR(Result);
   t:=intmsecnow;
   Result:=uart[myPortNum].ModalAnswerRequest(Result,GetTimeOut);
   t:=intmsecnow-t;
   if CheckBoxCheckSum.Checked then Result:=TruncCheckSumCR(Result);
   EditRx.Text:=Result;
   RecordHistory(Format('Tx=%-12s Rx=%-12s t=%-3d',[EditTx.Text,EditRx.Text,t]));
   if (aSleep>0) then Sleep(aSleep);
  end;
  UpdateColors;
 except
  on E:Exception do BugReport(E,Self,'SendAndReceive');
 end;
end;

procedure TFormUartTerminal.FormCreate(Sender: TObject);
begin
 SetStandardFont(Self);
 MemoHistory.Font.Name:=Font.Name;
 LabelAdamAddr.Font.Name:=Font.Name;
 SetAllButtonsCursor(Self,crHandPoint);
 LabelAdamAddr.Font.Size:=16;
 LabelAdamAddr.Font.Style:=[fsBold];
 ButtonExit.Font.Color:=clMaroon;
 ButtonOpen.Font.Color:=clGreen;
 ButtonClose.Font.Color:=clNavy;
 ButtonExit.Font.Size:=11;
 ButtonOpen.Font.Size:=11;
 ButtonClose.Font.Size:=11;
 ButtonExit.Font.Style:=[fsBold];
 ButtonOpen.Font.Style:=[fsBold];
 ButtonClose.Font.Style:=[fsBold];
 myColorTxOk:=StringToColor('AliceBlue',clWindow);
 myColorRxOk:=StringToColor('PaleGreen',clInfoBk);
 myColorRxEr:=StringToColor('MistyRose',clInfoBk);
 GroupBoxComPreset.Caption:=RusEng('Параметры COM порта','COM port preset');
 GroupBoxCommands.Caption:=RusEng('Управление','Control');
 GroupBoxRxTx.Caption:=RusEng('Передача/Прием (Tx/Rx)','Transmit/Receive (Tx/Rx)');
 GroupBoxHistory.Caption:=RusEng('История Tx/Rx','History Tx/Rx');
 GroupBoxAdamUtils.Caption:=RusEng('Утилиты ADAM','ADAM utilites');
 LabelPortNum.Caption:=RusEng('COM порт','COM port');
 SpinEditPortNum.Hint:=RusEng('Номер COM порта.','COM port number.');
 LabelBaudRate.Caption:=RusEng('Скорость','BaudRate');
 ComboBoxBaudRate.Hint:=RusEng('Скорость приемо-передачи, бит/сек.','Transmit/Reseive baudrate, bit/sec. ');
 LabelParity.Caption:=RusEng('Четность','Parity');
 ComboBoxParity.Hint:=RusEng('Тип контроля четности.','Parity control type.');
 LabelDataBits.Caption:=RusEng('Бит/байт','DataBits');
 ComboBoxDataBits.Hint:=RusEng('Число битов в байте данных.','Number of bits per data byte.');
 LabelStopBits.Caption:=RusEng('Бит/стоп','StopBits');
 ComboBoxStopBits.Hint:=RusEng('Число стоповых битов.','Number of stop bits.');
 LabelTimeOut.Caption:=RusEng('Таймаут','Timeout');
 SpinEditTimeOut.Hint:=RusEng('Таймаут - время ожидания ответа, мс.','Timeout to wait response, ms. ');
 CheckBoxCheckSum.Caption:=RusEng('Контроль сумм','Use Check Sum');
 CheckBoxCheckSum.Hint:=RusEng('Использовать Контрольные Суммы.','Use check sum control.');
 EditDcbFlags.Hint:=RusEng('Флаги управления модемом','Modem control flags')+' DCB (Device Control Block).';
 CheckListBoxDcbFlags.Hint:=RusEng('Флаги управления модемом','Modem control flags')+' DCB (Device Control Block).';
 ButtonOpen.Caption:=RusEng('Открыть порт','Open port');
 ButtonOpen.Hint:=RusEng('Открыть выбранный COM порт.','Open selected COM port.');
 ButtonClose.Caption:=RusEng('Закрыть порт','Close port');
 ButtonClose.Hint:=RusEng('Закрыть COM порт.','Close COM port.');;
 ButtonExit.Caption:=RusEng('Выход','Exit');
 ButtonExit.Hint:=RusEng('Выйти из диалога UART терминал.','Exit from UART terminal dialog.');
 ButtonAdamHelp.Hint:=RusEng('Справка по командам ADAM.','Help on ADAM commands.');
 ButtonAdamScan.Hint:=RusEng('Сканивать адреса ADAM.','Scan for ADAM adresses.');
 ButtonAdamWho.Hint:=RusEng('Прочитать информацию о модуле.','Read module information.');
 ButtonAdamAdc.Hint:=RusEng('Прочитать каналы ADC модуля.','Read module ADC channels.');
 ButtonAdamDio.Hint:=RusEng('Прочитать каналы DIO модуля.','Read module DIO channels.');
 ButtonAdamZero.Hint:=RusEng('Калибровать ноль АЦП.','Calibrate ADC zero.');
 ButtonAdamTcj.Hint:=RusEng('Калибровать холодный спай.','Calibrate cold junction.');
 ButtonListComPorts.Caption:=RusEng('Список COM портов','List COM Ports');
 ButtonListComPorts.Hint:=RusEng('Получить список доступных COM портов.','List all available COM ports.');
 ButtonRunSercatGui.Caption:=RusEng('Пуск','Run')+' sercat GUI';
 ButtonRunSercatGui.Hint:=RusEng('Запуск терминала sercatgui.','Run terminal sercatgui.');
 EditPrefix.Hint:=RusEng('Префикс команды при сканировании.','Command prefix to scan.');
 EditSuffix.Hint:=RusEng('Суффикс команды при сканировании.','Command suffix to scan.');
 EditAdamTcj.Hint:=RusEng('Температура холодного спая, °C.','Cold junction temperature, °C.');
 ComboBoxParity.Items.Text:=ListParityTypes;
 ComboBoxParity.ItemIndex:=0;
 ComboBoxStopBits.Items.Text:=ListStopBits;
 ComboBoxStopBits.ItemIndex:=0;
 ComboBoxBaudRate.Items.Text:=ListBaudRates;
 ComboBoxBaudRate.ItemIndex:=ComboBoxBaudRate.Items.IndexOf('9600');
 CheckListBoxDcbFlags.Font.Size:=8;
 MemoHistory.Text:='';
 UpdateDcbFlags;
 myPortNum:=0;
 UpdateState;
end;

procedure TFormUartTerminal.FormDestroy(Sender: TObject);
begin
 CloseComPort;
end;

function TFormUartTerminal.GetTimeOut:Integer;
begin
 Result:=SpinEditTimeOut.Value;
end;

function TFormUartTerminal.GetBaudRate:Integer;
begin
 Result:=StrToIntDef(Trim(ComboBoxBaudRate.Text),0);
end;

function TFormUartTerminal.GetStopBits:Integer;
begin
 Result:=ComboBoxStopBits.ItemIndex;
end;
 
function TFormUartTerminal.GetDataBits:Integer;
begin
 Result:=StrToIntDef(Trim(ComboBoxDataBits.Text),0);
end;

function TFormUartTerminal.GetDcbFlags:Integer;
begin
 Result:=StrToIntDef(Trim(EditDcbFlags.Text),0);
end;

procedure TFormUartTerminal.UpdateDcbFlags;
var dcb,msk:Cardinal; i:Integer; s:LongString;
begin
 dcb:=GetDcbFlags;
 for i:=0 to CheckListBoxDcbFlags.Items.Count-1 do
 if CheckListBoxDcbFlags.Checked[i] then begin
  s:=CheckListBoxDcbFlags.Items[i];
  s:=ExtractWord(1,s,JustBlanks);
  msk:=StrToIntDef(s,0);
  if (msk=0) then dcb:=0;
  dcb:=dcb or msk;
 end;
 EditDcbFlags.Text:=Format('$%.4X',[dcb]);
end;

function TFormUartTerminal.GetXonXoff:Boolean;
const XonXoffFlags=dcb_OutX or dcb_InX;
begin
Result:=HasFlags(GetDcbFlags,XonXoffFlags);
end;

function TFormUartTerminal.GetParity:Integer;
begin
 Result:=ComboBoxParity.ItemIndex;
end;

function TFormUartTerminal.GetBuffer:Integer;
begin
 Result:=SerBuffSize;
end;

function TFormUartTerminal.ListBaudRates:LongString;
begin
 Result:=Trim(UpperCase(SerListValidBaudRate(EOL)));
 if (Result='') then Result:='9600'+EOL+'115200';
end;

function TFormUartTerminal.ListParityTypes:LongString;
begin
 Result:=Trim(UpperCase(SerListValidParity(EOL)));
 Result:=StringReplace(Result,'PARITY','',[rfReplaceAll,rfIgnoreCase]);
 if (Result='') then Result:='NO'+EOL+'ODD'+EOL+'EVEN'+EOL+'MARK'+EOL+'SPACE';
end;

function TFormUartTerminal.ListStopBits:LongString;
begin
 Result:=Trim(UpperCase(SerListValidStopBits(EOL)));
 if (Result='') then Result:='1'+EOL+'1.5'+EOL+'2';
end;

procedure TFormUartTerminal.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
 CanClose:=(myPortNum=0) or UartTerminalSysClose;
end;

procedure TFormUartTerminal.FormClose(Sender: TObject; var Action: TCloseAction);
begin
 CloseComPort;
end;

procedure TFormUartTerminal.EditTxKeyDown(Sender: TObject; var Key: Word;  Shift: TShiftState);
begin
 if Key=VK_RETURN then SendAndReceive(EditTx.Text);
end;

procedure TFormUartTerminal.TimerScanTimer(Sender: TObject);
const Entry:Integer=0;
begin
 try
  inc(Entry);
  try
   if (Entry=1) then begin
    if uart[myPortNum].Active then begin
     LabelAddr.Caption:=HexB(myScanAddr);
     SendAndReceive(EditPrefix.Text+HexB(myScanAddr)+EditSuffix.Text);
     if (Length(EditRx.Text)>0)
     then Echo(Format('ADDR:$%s  REQUEST: %-10s  ANSWER: %-10s',
                      [HexB(myScanAddr), EditTx.Text, EditRx.Text]));
     inc(myScanAddr);
    end else EnableScan(false);
   end;
  finally
   dec(Entry);
  end;
 except
  on E:Exception do BugReport(E,Self,'TimerScanTimer');
 end;
end;

procedure TFormUartTerminal.ButtonExitClick(Sender: TObject);
begin
 CloseComPort;
 Close;
end;

procedure TFormUartTerminal.ButtonCloseClick(Sender: TObject);
begin
 CloseComPort;
end;

procedure TFormUartTerminal.ButtonOpenClick(Sender: TObject);
begin
 OpenComPort;
end;

{$IFDEF SKIP_DRAFT}
{$ELSE}
function SmartExecute(cmd:LongString; sw:Integer; how:LongString):Boolean;
begin
 Result:=false;
end;
{$ENDIF ~SKIP_DRAFT}

procedure TFormUartTerminal.ButtonAdamHelpClick(Sender: TObject);
var s:ShortString;
begin
 try
  s:='';
  if ReadIniFilePath(SysIniFile,'[System]','AdamCommandsManual',HomeDir,s) and FileExists(s) then begin
   if not SmartExecute(s,SW_SHOWNORMAL,'open')
   then Echo(Format(RusEng('Не могу открыть "%s".','Could not open "%s".'),[s]));
  end else RecordHistory(RusEng('Не могу найти файл справки.','Could not find help file.'));
 except
  on E:Exception do BugReport(E,Self,'ButtonAdamHelpClick');
 end;
end;

procedure TFormUartTerminal.ButtonAdamScanClick(Sender: TObject);
begin
 try
  if TimerScan.Enabled
  then EnableScan(false)
  else begin
   if uart[myPortNum].Active
   then EnableScan(true)
   else RecordHistory(RusEng('Порт не открыт!','Port not active!'));
  end;
 except
  on E:Exception do BugReport(E,Self,'ButtonAdamScanClick');
 end;
end;

procedure TFormUartTerminal.ButtonAdamWhoClick(Sender: TObject);
var a:Integer;
begin
 try
  EnableScan(false);
  if uart[myPortNum].Active then
  if StrHex2Long(EditAdamAddr.Text,a) then begin
   RecordHistory(RusEng('Информация о модуле:','Module information:'));
   SendAndReceive('~'+hexb(a)+'1',GetTimeOut);
   SendAndReceive('$'+hexb(a)+'M',GetTimeOut);
   SendAndReceive('$'+hexb(a)+'F',GetTimeOut);
   SendAndReceive('$'+hexb(a)+'2',GetTimeOut);
   SendAndReceive('~'+hexb(a)+'0',GetTimeOut);
   SendAndReceive('~'+hexb(a)+'2',GetTimeOut);
  end;
 except
  on E:Exception do BugReport(E,Self,'ButtonAdamWhoClick');
 end;
end;

procedure TFormUartTerminal.ButtonAdamAdcClick(Sender: TObject);
var a:Integer;
begin
 try
  EnableScan(false);
  if uart[myPortNum].Active then
  if StrHex2Long(EditAdamAddr.Text,a) then begin
   RecordHistory(RusEng('Чтение АЦП:','Read ADC:'));
   SendAndReceive('~'+hexb(a)+'1',GetTimeOut);
   if SendAndReceive('$'+hexb(a)+'5FF',GetTimeOut)='!'+hexb(a) then begin
    SendAndReceive('#'+hexb(a)+'0',GetTimeOut);
    SendAndReceive('#'+hexb(a)+'1',GetTimeOut);
    SendAndReceive('#'+hexb(a)+'2',GetTimeOut);
    SendAndReceive('#'+hexb(a)+'3',GetTimeOut);
    SendAndReceive('#'+hexb(a)+'4',GetTimeOut);
    SendAndReceive('#'+hexb(a)+'5',GetTimeOut);
    SendAndReceive('#'+hexb(a)+'6',GetTimeOut);
    SendAndReceive('#'+hexb(a)+'7',GetTimeOut);
   end else begin
    SendAndReceive('#'+hexb(a),GetTimeOut);
   end;
  end;
 except
  on E:Exception do BugReport(E,Self,'ButtonAdamAdcClick');
 end;
end;

procedure TFormUartTerminal.ButtonAdamDioClick(Sender: TObject);
var
 a : Integer;
begin
 try
  EnableScan(false);
  if uart[myPortNum].Active then
  if StrHex2Long(EditAdamAddr.Text,a) then begin
   RecordHistory(RusEng('Чтение DIO:','Read DIO:'));
   SendAndReceive('~'+hexb(a)+'1',GetTimeOut);
   SendAndReceive('$'+hexb(a)+'6',GetTimeOut);
   SendAndReceive('@'+hexb(a),GetTimeOut);
  end;
 except
  on E:Exception do BugReport(E,Self,'ButtonAdamDioClick');
 end;
end;

procedure TFormUartTerminal.ButtonAdamZeroClick(Sender: TObject);
var
 a : Integer;
 f : boolean;
begin
 try
  EnableScan(false);
  if uart[myPortNum].Active then
  if StrHex2Long(EditAdamAddr.Text,a) then begin
   RecordHistory(RusEng('Калибровка нуля АЦП:','ADC zero calibration:'));
   SendAndReceive('~'+hexb(a)+'1',GetTimeOut);
   if SendAndReceive('$'+hexb(a)+'5FF',GetTimeOut)='!'+hexb(a)
   then SendAndReceive('#'+hexb(a)+'0',GetTimeOut)
   else SendAndReceive('#'+hexb(a),GetTimeOut);
   SendAndReceive('~'+hexb(a)+'E1',GetTimeOut);
   f:=SendAndReceive('$'+hexb(a)+'1',GetTimeOut)='!'+hexb(a);
   SendAndReceive('~'+hexb(a)+'E0',GetTimeOut);
   if SendAndReceive('$'+hexb(a)+'5FF',GetTimeOut)='!'+hexb(a)
   then SendAndReceive('#'+hexb(a)+'0',GetTimeOut)
   else SendAndReceive('#'+hexb(a),GetTimeOut);
   if f
   then RecordHistory(RusEng('Калибровка сделана.','Calibration done.'))
   else RecordHistory(RusEng('Ошибка калибровки!','Calibration error!'));
  end;
  EnableScan(false);
 except
  on E:Exception do BugReport(E,Self,'ButtonAdamZeroClick');
 end;
end;

procedure TFormUartTerminal.ButtonAdamTcjClick(Sender: TObject);
var a:Integer; f:Boolean; s:LongString; t1,t2:Double;
begin
 try
  EnableScan(false);
  if uart[myPortNum].Active then
  if StrHex2Long(EditAdamAddr.Text,a) then
  if Str2Real(EditAdamTcj.Text,t2) then begin
   RecordHistory(RusEng('Калибровка холодного спая:','Cold junction calibration:'));
   SendAndReceive('~'+hexb(a)+'1',GetTimeOut);
   SendAndReceive('$'+hexb(a)+'3',GetTimeOut);
   SendAndReceive('$'+hexb(a)+'9+0000',GetTimeOut*10);
   s:=SendAndReceive('$'+hexb(a)+'3',GetTimeOut);
   f:=false;
   if Str2Real(copy(s,2,length(s)-1),t1) then begin
    s:=hexw(round(abs(t2-t1)*GetTimeOut));
    if (t1>t2) then s:='-'+s else s:='+'+s;
    f:=SendAndReceive('$'+hexb(a)+'9'+s,GetTimeOut*10)='!'+hexb(a);
   end;
   SendAndReceive('$'+hexb(a)+'3',GetTimeOut);
   if f
   then RecordHistory(RusEng('Калибровка сделана.','Calibration done.'))
   else RecordHistory(RusEng('Ошибка калибровки!','Calibration error!'));
  end;
  EnableScan(false);
 except
  on E:Exception do BugReport(E,Self,'ButtonAdamTcjClick');
 end;
end;

procedure TFormUartTerminal.ButtonListComPortsClick(Sender: TObject);
begin
 try
  EnableScan(false);
  RecordHistory(RusEng('******************','******************'));
  RecordHistory(RusEng('Список COM портов:','List of COM ports:'));
  RecordHistory(RusEng('******************','******************'));
  if (SerPortMap.Count>0) then RecordHistory(Trim(SerPortMap.Table));
  RecordHistory(RusEng('******************','******************'));
  RecordHistory(RusEng('Найдено COM портов: ','COM ports found: ')
               +IntToStr(SerPortMap.Count)+EOL);
 except
  on E:Exception do BugReport(E,Self,'ButtonListComPortsClick');
 end;
end;

procedure TFormUartTerminal.ButtonRunSercatGuiClick(Sender: TObject);
var cmd,arg:LongString; ep:Integer;
begin
 try
  EnableScan(false);
  cmd:='unix';
  if IsWindows then cmd:=ForceExtension(cmd,'.exe');
  if IsWindows then arg:='grun' else arg:='';
  cmd:=file_which(cmd);
  if IsEmptyStr(cmd) then begin
   RecordHistory(RusEng('Команда не найдена.','The command is not found.'));
   Exit;
  end;
  if HasChars(cmd,JustBlanks)
  then cmd:=AnsiQuotedStr(cmd,QuoteMark);
  arg:=Trim(arg+' sercatgui');
  RecordHistory(cmd+' '+arg);
  ep:=ExecuteProcess(cmd,arg);
  if (ep=0) then RecordHistory(RusEng('Команда выполнена успешно.','Command executed successfully.'));
  if (ep<>0) then RecordHistory(RusEng('Команда выполена с кодом ошибки ','Command executed with code ')+IntToStr(ep));
 except
  on E:Exception do BugReport(E,Self,'ButtonRunSercatGuiClick');
 end;
end;

procedure TFormUartTerminal.CheckListBoxDcbFlagsClickCheck(Sender: TObject);
begin
 UpdateDcbFlags;
end;

end.
