unit DevicePhilips89;

interface

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
  ComCtrls, Buttons, ExtCtrls, StdCtrls, Mask, ToolEdit,
  ComboDigEdit,CommInt,VCLUtils, MessageForm, Device_template, HexGrid;

type
  TfrmDevicePhilips89 = class(TfrmDevice)
    Panel2: TPanel;
    sbReset: TSpeedButton;
    PageControl1: TPageControl;
    TabSheet1: TTabSheet;
    Misc: TTabSheet;
    Panel5: TPanel;
    sbSetSecurityLevel: TSpeedButton;
    Label2: TLabel;
    Label3: TLabel;
    Label4: TLabel;
    cbBit1: TCheckBox;
    cbBit2: TCheckBox;
    cbBit3: TCheckBox;
    Panel4: TPanel;
    Label5: TLabel;
    Label6: TLabel;
    Label8: TLabel;
    edManufId: TEdit;
    edDevId1: TEdit;
    edDevId2: TEdit;
    Panel6: TPanel;
    Label9: TLabel;
    Label10: TLabel;
    edStatusByte: TEdit;
    edBootVector: TEdit;
    sbProgrStatus: TSpeedButton;
    Panel7: TPanel;
    edOscFreq: TEdit;
    Label11: TLabel;
    Label12: TLabel;
    rgSecurityLevel: TRadioGroup;
    Label14: TLabel;
    cbDevice: TComboBox;
    Label15: TLabel;
    sbMiscRead: TSpeedButton;
    procedure sbResetClick(Sender: TObject);
    procedure sbMiscReadClick(Sender: TObject);
    procedure rgSecurityLevelClick(Sender: TObject);
    procedure cbDeviceChange(Sender: TObject);
    procedure sbProgrStatusClick(Sender: TObject);
    procedure sbSetSecurityLevelClick(Sender: TObject);
  private
    SecurityLevel:Byte;
    StatusByte:Byte;
    BootVector:Byte;
    ManufId:byte;
    DevId1:byte;
    DevId2:byte;

    procedure UpdateMisc;
    function  CheckDeviceSelection:boolean;

    procedure ReadData;
    procedure VerifyData;
    procedure WriteData;
    procedure BlankCheck;
    function  CheckDevice:boolean;
    function  ReadMisc(strCmd:string):byte;
    function  WriteCmd(strCmd,strAnsw:string):boolean;
    procedure ResetLoader;
    procedure Reset;
    procedure ReadSecurityLevel;
    procedure ProgrStatus;
    procedure ProgrSecurity;
    procedure FreeSendThread;
    function  GetCRCfromString(str:string):string;
  public
    procedure DoRead;override;
    procedure DoProgr;override;
    procedure DoStop;override;
    procedure DoVerify;override;
    procedure DoBlankCheck;override;
    Constructor Create(AOwner:TComponent);override;
  end;

var
  frmDevicePhilips89: TfrmDevicePhilips89;
  frmMessage:TfrmMessage;

implementation

uses MainForm, RUtilites, SendThread;

{$R *.DFM}

Constructor TfrmDevicePhilips89.Create(AOwner:TComponent);
begin
  inherited;
  Self.edChipTo.MaxValue:=$FFFF;
  CommPort.FlowControl:=fcNone;

  Grid.DataCount:=$10000;
  Grid.DataSize:=dsByte;
  CodeWordSize:=1;
  frmMain.UpdateToolBarExecute(Self);
  frmMain.UpdateStatusBar;

end;



procedure TfrmDevicePhilips89.DoRead;
begin
  if not checkDeviceSelection then exit;
  CheckSendThread;
  FSendThread.OnExecuteProcess:=ReadData;
  FSendThread.OnEndProcess:=FreeSendThread;
  FSendThread.Resume;
end;

procedure TfrmDevicePhilips89.DoVerify;
begin
  if not checkDeviceSelection then exit;
  CheckSendThread;
  FSendThread.OnExecuteProcess:=VerifyData;
  FSendThread.OnEndProcess:=FreeSendThread;
  FSendThread.Resume;
end;

procedure TfrmDevicePhilips89.DoProgr;
begin
  if not checkDeviceSelection then exit;
  CheckSendThread;
  FSendThread.OnExecuteProcess:=WriteData;
  FSendThread.OnEndProcess:=FreeSendThread;
  FSendThread.Resume;
end;

procedure TfrmDevicePhilips89.DoStop;
begin
  if FSendThread<>Nil then FSendThread.Terminate;
end;

procedure TfrmDevicePhilips89.DoBlankCheck;
begin
  if not checkDeviceSelection then exit;
  CheckSendThread;
  FSendThread.OnExecuteProcess:=BlankCheck;
  FSendThread.OnEndProcess:=FreeSendThread;
  FSendThread.Resume;
end;

procedure TfrmDevicePhilips89.sbResetClick(Sender: TObject);
begin
  inherited;
  CheckSendThread;
  FSendThread.OnExecuteProcess:=ResetLoader;
  FSendThread.OnEndProcess:=FreeSendThread;
  FSendThread.Resume;
end;

procedure TfrmDevicePhilips89.sbMiscReadClick(Sender: TObject);
begin
  inherited;
  CheckSendThread;
  FSendThread.OnExecuteProcess:=ReadSecurityLevel;
  FSendThread.OnEndProcess:=FreeSendThread;
  FSendThread.Resume;
end;

procedure TfrmDevicePhilips89.sbProgrStatusClick(Sender: TObject);
begin
  inherited;
  if not checkDeviceSelection then exit;
  CheckSendThread;
  FSendThread.OnExecuteProcess:=ProgrStatus;
  FSendThread.OnEndProcess:=FreeSendThread;
  FSendThread.Resume;
end;

procedure TfrmDevicePhilips89.sbSetSecurityLevelClick(Sender: TObject);
begin
  inherited;
  if not checkDeviceSelection then exit;
  CheckSendThread;
  FSendThread.OnExecuteProcess:=ProgrSecurity;
  FSendThread.OnEndProcess:=FreeSendThread;
  FSendThread.Resume;
end;


function TfrmDevicePhilips89.checkDeviceSelection:boolean;
begin
  result:=true;
  if cbDevice.Text='' then
  begin
    MessageDlg('Device not selected!',mtError,[mbOK],0);
    cbDevice.SetFocus;
    result:=false;
  end;

  try
    StrToInt('$'+edOscFreq.text);
  except
    MessageDlg('Failure oscillator frequency setting!',mtError,[mbOK],0);
    edOscFreq.SetFocus;
    result:=false;
  end;

  try
    StrToInt('$'+edStatusByte.text);
  except
    MessageDlg('Failure status byte setting!',mtError,[mbOK],0);
    edStatusByte.SetFocus;
    result:=false;
  end;

  try
    StrToInt('$'+edBootVector.text);
  except
    MessageDlg('Failure boot vector setting!',mtError,[mbOK],0);
    edBootVector.SetFocus;
    result:=false;
  end;


end;


procedure TfrmDevicePhilips89.UpdateMisc;
begin
   if (SecurityLevel and $01)=0 then cbBit1.Checked:=false
                    else cbBit1.Checked:=true;
   if (SecurityLevel and $02)=0 then cbBit2.Checked:=false
                    else cbBit2.Checked:=true;
   if (SecurityLevel and $04)=0 then cbBit3.Checked:=false
                    else cbBit3.Checked:=true;

   case (SecurityLevel And $07) of
   0: rgSecurityLevel.ItemIndex:=0;
   1: rgSecurityLevel.ItemIndex:=1;
   3: rgSecurityLevel.ItemIndex:=2;
   7: rgSecurityLevel.ItemIndex:=3;
   else
     rgSecurityLevel.ItemIndex:=-1;
   end;
   edManufId.Text:=Format('%.2x',[ManufId]);
   edDevId1.Text:=Format('%.2x',[DevId1]);
   edDevId2.Text:=Format('%.2x',[DevId2]);
   case DevId2 of
   $80: cbDevice.ItemIndex:=3;
   $89: cbDevice.ItemIndex:=2;
   $8B: cbDevice.ItemIndex:=1;
   $8F: cbDevice.ItemIndex:=0;
   end;
   cbDeviceChange(Self);
   edStatusByte.Text:=Format('%.2x',[StatusByte]);
   edBootVector.Text:=Format('%.2x',[BootVector]);
end;


procedure TfrmDevicePhilips89.rgSecurityLevelClick(Sender: TObject);
begin
  inherited;
  case rgSecurityLevel.ItemIndex of
  0: begin
       cbBit1.Checked:=false;
       cbBit2.Checked:=false;
       cbBit3.Checked:=false;
     end;
  1: begin
       cbBit1.Checked:=true;
       cbBit2.Checked:=false;
       cbBit3.Checked:=false;
     end;
  2: begin
       cbBit1.Checked:=true;
       cbBit2.Checked:=true;
       cbBit3.Checked:=false;
     end;
  3: begin
       cbBit1.Checked:=true;
       cbBit2.Checked:=true;
       cbBit3.Checked:=true;
     end;
  end;
end;

procedure TfrmDevicePhilips89.cbDeviceChange(Sender: TObject);
begin
  inherited;
  case cbDevice.itemindex of
  0: begin
       edChipfrom.value:=0;
       edChipTo.MaxValue:=$1fff;
       edChipTo.Value:=$1fff;
     end;
  1: begin
       edChipfrom.value:=0;
       edChipTo.MaxValue:=$3fff;
       edChipTo.Value:=$3fff;
     end;
  2: begin
       edChipfrom.value:=0;
       edChipTo.MaxValue:=$7fff;
       edChipTo.Value:=$7fff;
     end;
  3: begin
       edChipfrom.value:=0;
       edChipTo.MaxValue:=$ffff;
       edChipTo.Value:=$ffff;
     end;
  end;
end;


// ----------------------------------------------------------------------------
//
//  Procedures called from SendThread
//
// ----------------------------------------------------------------------------
//

Procedure TfrmDevicePhilips89.Reset;
var
    Buf:TThreadBuf;
    FRead:Cardinal;  // Число прочитанных символов
    i,j:integer;
begin
  with  FSendThread do
  begin
    Synchronize(BottonsDisable);  // Запретить все кнопки
    try
      DeviceEnabled:=false;       // Считать вначале, что прибор недоступен
      PurgePort;
      SetTimeouts;        // Очистить порт и установить тайм-ауты

      // Для перевода в режим программирования необходимо
      // сигнал DTR установить в 0 , на выводе RTS импульс 0

      for j:=1 to 5 do
      begin
        if DeviceEnabled=true then break;
        CommPort.SetDTRState(true);
        CommPort.SetRTSState(true);
        Delay(1);
        CommPort.SetRTSState(false);
        Delay(50);

        // 10 раз подать символ "U" и ждать эха, если эха нет,
        //   то прибор недоступен

        for i:=1 to 10 do
        begin
          buf:='U';
          WriteToComm(1,buf);
          ReadFromComm(3,Buf,FRead);
          if FRead<1 then Continue;
          if Buf[0]='U' then
          begin
            DeviceEnabled:=true;
            Break;
          end;
          delay(10);
        end;
      end;

    except
      On E:ESendThreadError do MessageDlg(E.Message,mtError,[mbOK],0);
      else Raise;
    end;
  end;
end;



procedure TfrmDevicePhilips89.ResetLoader;
begin
  Self.Reset;
  if DeviceEnabled=true then
    MessageDlg('Device enabled!',mtInformation,[mbOK],0)
  else
    MessageDlg('Device disabled!',mtInformation,[mbOK],0)
end;



function TfrmDevicePhilips89.CheckDevice:boolean;
begin
  Self.Reset;
  if  DeviceEnabled then
    result:=true
  else
  begin
    result:=false;
    MessageDlg('No Answer!',mtInformation,[mbOK],0)
  end;
end;


function TfrmDevicePhilips89.GetCRCfromString(str:string):string;
var i:integer;
    CRC:byte;
begin
  CRC:=0;
  for i:=1 to (Length(str) div 2) do
  begin
    CRC:=CRC+StrToInt('$'+copy(str,(i-1)*2+1,2))
  end;
  CRC:=(CRC xor $FF)+1;
  result:=format('%.2x',[CRC]);
end;

function TfrmDevicePhilips89.ReadMisc(strCmd:string):byte;
var rstr:string;
    Buf:TThreadBuf;
    BufLen:Cardinal;
    FRead:Cardinal;
begin
  strCmd:=':'+strCmd+GetCRCfromString(strCmd);
  BufLen:=FormatBuf(Buf,SizeOf(Buf),'%s',2,[strCmd]);
  FSendThread.WriteToComm(BufLen,Buf);
  FSendThread.ReadFromComm(BufLen,Buf,FRead);
  SetString(rstr,Buf,Fread);
  if rstr<>strCmd then
  begin
    MessageDlg('Request:'+strCmd+#13+#10+
               'Answer: '+rstr,mtError,[mbOK],0);
    Abort;
  end;
  FSendThread.ReadFromComm(5,Buf,FRead);
  SetString(rstr,Buf,Fread);
  Result:=StrToInt('$'+copy(rstr,1,2));

end;

function TfrmDevicePhilips89.WriteCmd(strCmd,strAnsw:string):boolean;
var rstr:string;
    Buf:TThreadBuf;
    BufLen:Cardinal;
    FRead:Cardinal;
begin
  result:=true;
  strCmd:=':'+strCmd+GetCRCfromString(strCmd);
  BufLen:=FormatBuf(Buf,SizeOf(Buf),'%s',2,[strCmd]);
  FSendThread.WriteToComm(BufLen,Buf);

  FSendThread.ReadFromComm(BufLen,Buf,FRead);
  SetString(rstr,Buf,Fread);
  if rstr<>strCmd then
  begin
    MessageDlg('Request:'+strCmd+#13+#10+
               'Answer: '+rstr,mtError,[mbOK],0);
    result:=false;
  end;
  FSendThread.ReadFromComm(Length(strAnsw),Buf,FRead);
  SetString(rstr,Buf,Fread);
  if rstr<>strAnsw then
  begin
    MessageDlg('Command failure: '+strCmd,mtError,[mbOK],0);
    result:=false;
  end;
end;


procedure TfrmDevicePhilips89.ReadData;
var
    str:string;
    Buf:TThreadBuf;
    BufLen,OffSet:Cardinal;
    FRead,Addr:Cardinal;
    i:integer;
    j:word;
const MaxRead = 100;
begin
  with FSendThread do
  begin
    Synchronize(UpdateGrid);
    Synchronize(BottonsDisable);
    if not CheckDevice then exit;   // Не выполнять чтение если прибор недоступен
    PurgePort;
    SetTimeouts;
    try
{    Подготовить строку команды

     General Format of Function 04
       :05xxxx04sssseeeeffcc
     Where:
       05 = number of bytes (hex) in record
       xxxx = required field, but value is a “don’t care”
       04 = “Display Device Data or Blank Check” function code
       ssss = starting address
       eeee = ending address
       ff = subfunction
       00 = display data
       01 = blank check
       cc = checksum
     Example:
       :0500000440004FFF0069 display 4000–4FFF
}
      str:='05000004'+format('%.4x%.4x',[edChipFrom.value,edChipTo.value])+'00';
      str:=':'+str+GetCRCfromString(str)+Chr($0d);
      BufLen:=FormatBuf(Buf,SizeOf(Buf),'%s',2,[str]);
      WriteToComm(BufLen,Buf);

      str:='';
      OffSet:=Longint(Grid.BegAddr)-edBufFrom.value;
      repeat
        ReadFromComm(MaxRead,Buf,FRead);
        for i:=0 to  FRead-1 do
        begin
          str:=str+Buf[i];
          if Buf[i]=Chr($0a) then
          begin
            if Length(str)=39 then
            begin
              Addr:=StrToInt('$'+copy(str,1,4));
              for j:=0 to 15 do
              begin
                PDataBuf(Grid.DataBufer)^.data[j+OffSet+Addr]:=StrToInt('$'+copy(str,6+j*2,2));
              end;
              FProgressBarPos:=FProgressBarPos+16;
              Synchronize(UpdateProgress);
            end;
            str:='';
          end;
        end;

      until MaxRead<>FRead;
    finally
      Synchronize(RefreshGrid);
    end;
  end;
end;

procedure TfrmDevicePhilips89.WriteData;
var
    strCmd:String;
    Addr,Count,i,index:cardinal;
    nl,nh,b:byte;
const
    blockBounds:Array[0..5] of longint =(0,$1fff,$3fff,$7fff,$bfff,$ffff);

const MaxRead = 100;
begin
  with FSendThread do
  begin
    Synchronize(UpdateGrid);
    Synchronize(BottonsDisable);
    if not CheckDevice then exit;   // Не выполнять чтение если прибор недоступен
    PurgePort;
    SetTimeouts;
    try
{
     Data Record
       :nnaaaa00dd....ddcc
       Where:
       Nn = number of bytes (hex) in record
       Aaaa = memory address of first byte in record
       dd....dd = data bytes
       cc = checksum
     Example:
       :10008000AF5F67F0602703E0322CFA92007780C3FD
}

      // Записать частоту осцилятора
      strCmd:='01000002'+edOscFreq.text;
      if not WriteCmd(strCmd,'.'+#13+#10) then Abort;

      // Стереть необходимые участки памяти
      nl:=0;
      nh:=4;
      for i:=1 to 4 do
        if edChipFrom.Value>BlockBounds[i] then nl:=i;
      for i:=4 downto 1 do
        if edChipTo.Value<=BlockBounds[i] then nh:=i-1;
      FSendThread.TimeOuts(0,0,0,0,10);
      frmMessage:=TfrmMessage.Create(Self);
      frmMessage.show;
      try
        for i:=nl to nh do
        begin
          b:=i shl 5;
          strCmd:='0200000301'+Format('%.2x',[b]);


          frmMessage.lbMessage.Caption:=#13+#10+'Erasing block '+IntToStr(i)+#13+#10+
                   'Lower addr = '+Format('%.4x',[BlockBounds[i]])+#13+#10+
                   'Upper addr = '+Format('%.4x',[BlockBounds[i+1]]);
          Application.ProcessMessages;
          if not WriteCmd(strCmd,'.'+#13+#10) then Abort;
        end;
      finally
        frmMessage.Free;
      end;
      // Начать программирование
      Addr:=0;
      FSendThread.TimeOuts(10,1,10,0,10);
      repeat
        if (edChipTo.Value-edChipFrom.Value-Longint(Addr)+1)>8 then
          Count:=8
        else
          Count:=edChipTo.Value-edChipFrom.Value-Longint(Addr)+1;

        strCmd:='';
        for i:=1 to Count do
        begin
          index:=i-1+Addr+(Cardinal(edBufFrom.value)-Grid.BegAddr);
          strCmd:=strCmd+Format('%.2x',[PDataBuf(Grid.DataBufer)^.data[index]])
        end;
        strCmd:=Format('%.2x',[Count])+Format('%.4x',[edChipFrom.value+Longint(Addr)])+'00'+strCmd;
        if not WriteCmd(strCmd,'.'+#13+#10) then Abort;
        FProgressBarPos:=FProgressBarPos+LongInt(Count);
        Synchronize(UpdateProgress);
        Addr:=Addr+Count;
      until (edChipFrom.Value+Longint(Addr))>edChipTo.Value;
    finally
      Synchronize(RefreshGrid);
    end;
  end;
end;

procedure TfrmDevicePhilips89.ReadSecurityLevel;
begin
  with FSendThread do
  begin
    Synchronize(BottonsDisable);
    if not CheckDevice then exit;   // Не выполнять чтение если прибор недоступен
    PurgePort;
    SetTimeouts;
    try
{    Подготовить строку команды

     Miscellaneous Read Functions
       General Format of Function 05
       :02xxxx05ffsscc
       Where:
       02 = number of bytes (hex) in record
       xxxx = required field, but value is a “don’t care”
       05 = “Miscellaneous Read” function code
       ffss = subfunction and selection code
       0000 = read signature byte – manufacturer id (15H)
       0001 = read signature byte – device id # 1 (C2H)
       0002 = read signature byte – device id # 2
       (89C51RD+ = 80H)
       (89C51RC+ = 89H)
       0700 = read security bits
       0701 = read status byte
       0702 = read boot vector
       cc = checksum
     Example:
       :020000050001F0 read signature byte – device id # 1
}

      ManufId:=ReadMisc('020000050000');
      DevId1:=ReadMisc('020000050001');
      DevId2:=ReadMisc('020000050002');
      SecurityLevel:=ReadMisc('020000050700');
      SecurityLevel:=SecurityLevel shr 1;
      StatusByte:=ReadMisc('020000050701');
      BootVector:=ReadMisc('020000050702');
      Synchronize(UpdateMisc);

    finally
      Synchronize(RefreshGrid);
    end;
  end;
end;





procedure TfrmDevicePhilips89.VerifyData;
var
    str:string;
    Buf:TThreadBuf;
    BufLen,OffSet:Cardinal;
    FRead,Addr:Cardinal;
    i:integer;
    j:word;
    DataBuf,DataChip:byte;
    AddrBuf,AddrChip:Longint;
    k:byte;
const MaxRead = 100;
begin
  with FSendThread do
  begin
    Synchronize(UpdateGrid);
    Synchronize(BottonsDisable);
    if not CheckDevice then exit;   // Не выполнять чтение если прибор недоступен
    PurgePort;
    SetTimeouts;
    try
{    Подготовить строку команды

     General Format of Function 04
       :05xxxx04sssseeeeffcc
     Where:
       05 = number of bytes (hex) in record
       xxxx = required field, but value is a “don’t care”
       04 = “Display Device Data or Blank Check” function code
       ssss = starting address
       eeee = ending address
       ff = subfunction
       00 = display data
       01 = blank check
       cc = checksum
     Example:
       :0500000440004FFF0069 display 4000–4FFF
}
      str:='05000004'+format('%.4x%.4x',[edChipFrom.value,edChipTo.value])+'00';
      str:=':'+str+GetCRCfromString(str)+Chr($0d);
      BufLen:=FormatBuf(Buf,SizeOf(Buf),'%s',2,[str]);
      WriteToComm(BufLen,Buf);
      str:='';
      Addr:=0;
      k:=0;
      OffSet:=Longint(Grid.BegAddr)-edBufFrom.value;
      repeat
        ReadFromComm(MaxRead,Buf,FRead);
        for i:=0 to  FRead-1 do
        begin
          str:=str+Buf[i];
          if Buf[i]=Chr($0a) then
          begin
            if str[5]='=' then
            begin
              Addr:=StrToInt('$'+copy(str,1,4));
              k:=((Length(str)-7) div 2)-1;
              for j:=0 to k do
              begin
                AddrBuf:=j+Addr+Grid.BegAddr;
                DataBuf:=PDataBuf(Grid.DataBufer)^.data[j+OffSet+Addr];
                AddrChip:=Addr+j;
                DataChip:=StrToInt('$'+copy(str,6+j*2,2));
                if DataBuf<>DataChip then
                begin
                  MessageDlg('Verify error: '+#13+#10+
                             ' AddrBuf:'+Format('%.4x',[AddrBuf])+
                             ' ->  '+Format('%.2x',[DataBuf])+#13+#10+
                             'AddrChip:'+Format('%.4x',[AddrChip])+
                             ' ->  '+Format('%.2x',[DataChip]),mtError,[mbOK],0);
                  Abort;
                end
              end;
              FProgressBarPos:=FProgressBarPos+16;
              Synchronize(UpdateProgress);
            end;
            str:='';
          end;
        end;

      until MaxRead<>FRead;
      if Longint(Addr+k)<>edChipTo.Value then
        MessageDlg('Verify not complete: '+Format('%.4x',[Addr+k]),mtError,[mbOK],0);
    finally
      Synchronize(RefreshGrid);
    end;
  end;
end;

procedure TfrmDevicePhilips89.BlankCheck;
var
    str:string;
    Buf:TThreadBuf;
    BufLen:Cardinal;
    FRead,Addr:Cardinal;
    i:integer;
    j:word;
    DataChip:byte;
    AddrChip:Longint;
const MaxRead = 100;
begin
  with FSendThread do
  begin
    Synchronize(UpdateGrid);
    Synchronize(BottonsDisable);
    if not CheckDevice then exit;   // Не выполнять чтение если прибор недоступен
    PurgePort;
    SetTimeouts;
    try
{    Подготовить строку команды

     General Format of Function 04
       :05xxxx04sssseeeeffcc
     Where:
       05 = number of bytes (hex) in record
       xxxx = required field, but value is a “don’t care”
       04 = “Display Device Data or Blank Check” function code
       ssss = starting address
       eeee = ending address
       ff = subfunction
       00 = display data
       01 = blank check
       cc = checksum
     Example:
       :0500000440004FFF0069 display 4000–4FFF
}
      str:='05000004'+format('%.4x%.4x',[edChipFrom.value,edChipTo.value])+'00';
      str:=':'+str+GetCRCfromString(str)+Chr($0d);
      BufLen:=FormatBuf(Buf,SizeOf(Buf),'%s',2,[str]);
      WriteToComm(BufLen,Buf);

      str:='';
      repeat
        ReadFromComm(MaxRead,Buf,FRead);
        for i:=0 to  FRead-1 do
        begin
          str:=str+Buf[i];
          if Buf[i]=Chr($0a) then
          begin
            if Length(str)=39 then
            begin
              Addr:=StrToInt('$'+copy(str,1,4));
              for j:=0 to 15 do
              begin
                AddrChip:=Addr+j;
                DataChip:=StrToInt('$'+copy(str,6+j*2,2));
                if DataChip<>$FF then
                begin
                  MessageDlg('Chip not blank: '+#13+#10+
                             'Addres:'+Format('%.4x',[AddrChip])+
                             ' ->  '+Format('%.2x',[DataChip]),mtError,[mbOK],0);
                  Abort;
                end
              end;
              FProgressBarPos:=FProgressBarPos+16;
              Synchronize(UpdateProgress);
            end;
            str:='';
          end;
        end;

      until MaxRead<>FRead;
    finally
      Synchronize(RefreshGrid);
    end;
  end;
end;

procedure TfrmDevicePhilips89.ProgrStatus;
var
    strCmd:String;
Label RepeatPrgrBootVector,RepeatEraseBootVector,RepeatPrgrStatusByte;
begin
  with FSendThread do
  begin
    Synchronize(UpdateGrid);
    Synchronize(BottonsDisable);
    if not CheckDevice then exit;   // Не выполнять чтение если прибор недоступен
    PurgePort;
    SetTimeouts;
    try
{
     Miscellaneous Write Functions
       :nnxxxx03ffssddcc
     Where:
       nn = number of bytes (hex) in record
       xxxx = required field, but value is a “don’t care”
       03 = Write Function
       ff = subfunction code
       ss = selection code
       dd = data input (as needed)
       cc = checksum
     Subfunction Code = 01 (Erase Blocks)
       ff = 01
       ss = block number in bits 7:5, Bits 4:0 = zeros
     Example:
       :0200000301A05A erase block 5
     Subfunction Code = 04 (Erase Boot Vector and Status Byte)
       ff = 04
       ss = don’t care
       dd = don’t care
     Example:
       :0100000304F8 erase boot vector and status byte
     Subfunction Code = 05 (Program Security Bits)
       ff = 05
       ss = 00 program security bit 1
       01 program security bit 2
       02 program security bit 3
     Example:
       :020000030501F5 program security bit 2
     Subfunction Code = 06 (Program Status Byte or Boot Vector)
       ff = 06
       ss = 00 program status byte
       01 program boot vector
     Example:
       :020000030601F4 program boot vector
}
      // Записать частоту осцилятора
      strCmd:='01000002'+edOscFreq.text;
      if not WriteCmd(strCmd,'.'+#13+#10) then Abort;

      FSendThread.TimeOuts(10,1,1000,0,10);
      // Стереть загрузочный вектор и байт состояния
RepeatEraseBootVector:
      strCmd:='0100000304';
      if not WriteCmd(strCmd,'.'+#13+#10) then
            begin
        case MessageDlg('Boot vector not erase. Repeat? ',mtError,[mbOK,mbIgnore,mbCancel],0)  of
          mrOK:begin
                PurgePort;
                FSendThread.TimeOuts(10,1,1000,0,10);
                goto RepeatEraseBootVector
               end;
          mrCancel:Abort;
          mrIgnore:
        end;
      end;

      // Запрограммировать загрузочный вектор
RepeatPrgrBootVector:
      strCmd:='030000030601'+edBootVector.text;
      if not WriteCmd(strCmd,'.'+#13+#10) then
      begin
        case MessageDlg('Boot vector not program. Repeat? ',mtError,[mbOK,mbIgnore,mbCancel],0)  of
          mrOK:begin
                 PurgePort;
                 FSendThread.TimeOuts(10,1,1000,0,10);
                 goto RepeatPrgrBootVector
               end;
          mrCancel:Abort;
          mrIgnore:
        end;
      end;
      // Запрограммировать байт состояния
RepeatPrgrStatusByte:
      strCmd:='030000030600'+edStatusByte.text;
      if not WriteCmd(strCmd,'.'+#13+#10) then
      begin
        case MessageDlg('Status Byte not program. Repeat? ',mtError,[mbOK,mbIgnore,mbCancel],0)  of
          mrOK:begin
                 PurgePort;
                 FSendThread.TimeOuts(10,1,1000,0,10);
                 goto RepeatPrgrStatusByte
               end;
          mrCancel:Abort;
          mrIgnore:
        end;
      end;

    finally
      Synchronize(RefreshGrid);
    end;
  end;
end;

procedure TfrmDevicePhilips89.ProgrSecurity;
var
    strCmd:String;
    i:integer;
Label RepeatProgrSecBit;
begin
  with FSendThread do
  begin
    Synchronize(UpdateGrid);
    Synchronize(BottonsDisable);
    if not CheckDevice then exit;   // Не выполнять чтение если прибор недоступен
    PurgePort;
    SetTimeouts;
    try
{
     Miscellaneous Write Functions
       :nnxxxx03ffssddcc
     Where:
       nn = number of bytes (hex) in record
       xxxx = required field, but value is a “don’t care”
       03 = Write Function
       ff = subfunction code
       ss = selection code
       dd = data input (as needed)
       cc = checksum
     Subfunction Code = 01 (Erase Blocks)
       ff = 01
       ss = block number in bits 7:5, Bits 4:0 = zeros
     Example:
       :0200000301A05A erase block 5
     Subfunction Code = 04 (Erase Boot Vector and Status Byte)
       ff = 04
       ss = don’t care
       dd = don’t care
     Example:
       :0100000304F8 erase boot vector and status byte
     Subfunction Code = 05 (Program Security Bits)
       ff = 05
       ss = 00 program security bit 1
       01 program security bit 2
       02 program security bit 3
     Example:
       :020000030501F5 program security bit 2
     Subfunction Code = 06 (Program Status Byte or Boot Vector)
       ff = 06
       ss = 00 program status byte
       01 program boot vector
     Example:
       :020000030601F4 program boot vector
}
      // Записать частоту осцилятора
      strCmd:='01000002'+edOscFreq.text;
      if not WriteCmd(strCmd,'.'+#13+#10) then Abort;

      FSendThread.TimeOuts(10,1,1000,0,10);
      // Стереть загрузочный вектор и байт состояния

      for i:=1 to 3 do
      begin
RepeatProgrSecBit:
        case i of
          1:begin
              if not cbBit1.Checked then Continue;
              strCmd:='020000030500'
            end;
          2:begin
              if not cbBit2.Checked then Continue;
              strCmd:='020000030501'
            end;
          3:begin
              if not cbBit3.Checked then Continue;
              strCmd:='020000030502'
            end;
        end;
        if not WriteCmd(strCmd,'.'+#13+#10) then
        begin
          case MessageDlg('Secutity bit '+IntToStr(i)+' not programm. Repeat? ',mtError,[mbOK,mbIgnore,mbCancel],0)  of
            mrOK:begin
                  PurgePort;
                  FSendThread.TimeOuts(10,1,1000,0,10);
                  goto RepeatProgrSecBit
                 end;
            mrCancel:Abort;
            mrIgnore:
          end;
        end;
      end; {for i}

    finally
      Synchronize(RefreshGrid);
    end;
  end;
end;




procedure TfrmDevicePhilips89.FreeSendThread;
begin
  FProgressBarPos:=0;
  FSendThread.Synchronize(UpdateProgress);
  FSendThread.Synchronize(BottonsEnable);
  FSendThread:=nil;
end;






end.
