unit Unit1;

interface
                                
uses
  SysUtils, WinTypes, WinProcs, Messages, Classes, Graphics, Controls,
  Forms, Dialogs, ExtCtrls, StdCtrls, Buttons, Spin, Mask, 
  ComPort, ComCtrls;

type
  TForm1 = class(TForm)
    Panel1: TPanel;
    Panel2: TPanel;
    btnClose: TBitBtn;
    ParamPanel: TPanel;
    rgPortIndex: TRadioGroup;
    GroupBox1: TGroupBox;
    btnOpenPort: TSpeedButton;
    btnClosePort: TSpeedButton;
    StatusBar: TStatusBar;
    lbTrace: TListBox;
    FPort: TComPort;
    Panel4: TPanel;
    bRead: TSpeedButton;
    btnClearLog: TSpeedButton;
    Panel3: TPanel;
    GroupBox2: TGroupBox;
    PnP_Rev: TLabeledEdit;
    EISA_ID: TLabeledEdit;
    Product_ID: TLabeledEdit;
    GroupBox3: TGroupBox;
    Serial_Number: TLabeledEdit;
    Driver_ID: TLabeledEdit;
    User_Name: TLabeledEdit;
    Class_Name: TComboBox;
    Label1: TLabel;
    procedure FormCreate(Sender: TObject);
    procedure btnCloseClick(Sender: TObject);
    procedure bReadClick(Sender: TObject);
    procedure btnOpenPortClick(Sender: TObject);
    procedure btnClosePortClick(Sender: TObject);
    procedure rgPortIndexClick(Sender: TObject);
    procedure btnClearLogClick(Sender: TObject);
    procedure FormCloseQuery(Sender: TObject; var CanClose: Boolean);
  private
    Function GetPnPRevison(RevN : String) : String;
    Function GetPnPCS(SID : String) : Byte;
  public
   function  MakePnP_ID : String;
   procedure SetEnabledControls;
  end;

var
  Form1: TForm1;

implementation

{$R *.DFM}

{ Создание компонента доступа к портам при создании формы }
procedure TForm1.FormCreate(Sender: TObject);
begin
 DecimalSeparator:= '.';
 SetEnabledControls;
end;

{Изменение номера порта}
procedure TForm1.rgPortIndexClick(Sender: TObject);
begin
 FPort.ComNumber:= rgPortIndex.ItemIndex+1;
end;

{Кнопка открытия порта}
procedure TForm1.btnOpenPortClick(Sender: TObject);
begin
 FPort.Close;
 FPort.ComNumber:= rgPortIndex.ItemIndex+1;
 FPort.Open;
 If FPort.Connected then
  StatusBar.Panels[0].Text:= 'Порт успешно открыт'
 Else
  StatusBar.Panels[0].Text:= 'Ошибка открытия порта';
 SetEnabledControls;
 If FPort.Connected then begin
  FPort.ToggleRTS(False);
  FPort.ToggleDTR(False);
 End;
end;

procedure TForm1.btnClosePortClick(Sender: TObject);
begin
 FPort.Close;
 StatusBar.Panels[0].Text:= '';
 SetEnabledControls;
 bRead.Down:= False;
end;

procedure TForm1.SetEnabledControls;
Var Active : Boolean;
begin
 Active:= FPort.Connected;
 btnClosePort.Enabled:= Active;
 rgPortIndex.Enabled := not Active;
 btnOpenPort.Enabled := not Active;
 bRead.Enabled       := Active;
end;

{Кнопка закрытия программы}
procedure TForm1.btnCloseClick(Sender: TObject);
begin
 Close;
end;

{ Получение контрольной суммы строки PnP идентификатора }
Function TForm1.GetPnPCS(SID : String) : Byte;
Var i : Integer;
Begin
 Result:= 0;
 SID:= '(' + SID + ')';
 {суммируем}
 For i:= 1 to Length(SID) do begin
  {$R-}
  Result:= Result + Byte(SID[i]);
  {$R+}
 End;
End;

{ Формирование поля PnP Revision }
Function TForm1.GetPnPRevison(RevN : String) : String;
Var iRev : Integer; iRevH, iRevL : Byte;
Begin
 { RevN = строковое значение, например, 1.0 }
 { Получаем iRev - цифровое значение }
 iRev:= Trunc(StrToFloatDef(RevN, 0)*100);
 { Выделяем старшие 6 бит и младшие 6 бит}
 iRevH:= (iRev shr 6) and $3F;
 iRevL:= iRev and $3F;
 { Создаем строку из двух символов}
 Result:= Char(iRevH)+Char(iRevL);
End;

{ Формирование PnP идентификатора}
Function TForm1.MakePnP_ID : String;
Begin
 {Внутреннее содержание PnP ID}
 Result:=
  Format('%s%3s%4s\%s\%s\%s\%s',[
    GetPnPRevison(PnP_Rev.Text),
    EISA_ID.Text,
    Product_ID.Text,
    Serial_Number.Text,
    Class_Name.Text,
    Driver_ID.Text,
    User_Name.Text
  ]);
{ Должно получиться что-то вроде строки: }
{ "#$01#$24'PVA0000\12345678\MULTIFUNCTION\BEER001, BEER002\Bottle Opener" }

 { Добавить BeginID, EndID и контрольную сумму }
 Result:= Format('(%s%s)',[Result, IntToHex(GetPnPCS(Result),2)]);
End;

{Запустить!}
procedure TForm1.bReadClick(Sender: TObject);
begin
 StatusBar.Panels[0].Text:=  MakePnP_ID;

 lbTrace.Items.Add('Пуск...');
 lbTrace.Items.Add('Настройка порта: 1200/7/NONE/1');
 FPort.ComProp.BaudRate:= br1200;
 FPort.ComProp.ByteSize:= bs7;
 FPort.ComProp.Parity  := ptNONE;
 FPort.ComProp.Stopbits:= sb1BITS;
 While FPort.Connected do begin
  lbTrace.Items.Add('Ждем появления DSR...');
  While (FPort.GetModemState and MS_DSR_ON) = 0 do
   Application.ProcessMessages;
  lbTrace.Items.Add('Устанавливаем в ответ DTR');
  FPort.ToggleDTR(True);
  lbTrace.Items.Add('Ждем установки CTS...');
  While (FPort.GetModemState and MS_CTS_ON) = 0 do
   Application.ProcessMessages;
  lbTrace.Items.Add('Передаем идентификатор');
  FPort.WriteString(MakePnP_ID);
 End;
 lbTrace.Items.Add('END');
end;

procedure TForm1.btnClearLogClick(Sender: TObject);
begin
 lbTrace.Items.Clear;
end;

procedure TForm1.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
 FPort.Close;
end;

end.
