unit UnitE1;

interface
uses
    Windows, SysUtils, Graphics, Controls, Classes, Forms,
    UsbMain, HexUtils, UnitMisc, Masks, Boots, UnitAndrey, UnitPavel, Unit1, uTokens;

function  ISIHeaderTransId():byte;
function  ISIHeaderMsgBody():byte;
function  USBControlPacket(_Class: LongWord; Length: longword; Expected:Integer):Boolean;
function  BB5_USB_BootRom_GetFirstBlock:integer;
function  GetRAPInfo():boolean;
function  BB5_NormalFlashing():boolean;
function  BB5_Flashing():boolean;
function  cntrel():Boolean;
function  BB5_DeadFlashing(mode:integer):boolean;
procedure BB5_ExtractCertData (core:string; needSert:string; CertData:TMemoryStream; Result:boolean; ape : boolean);
procedure BB5_ExtractBlockOfRAWLoader(core: string;RAWBlock:TMemoryStream; var Result:boolean);
procedure BB5_ExtractRAWLoader(RAWBlock, RAWLoader:TMemoryStream; Result:boolean);
function  BB5_SendADLLoader(UAgent:TMemoryStream):Boolean;
function  CheckADLLoader:boolean;
function  GetLoaderCRC(Buf:Pointer; BufLen: integer): Word;//Функция расчета CHK UPDAPP
function  BB5restart2ndproto():boolean;
function  BB5_ADL_RestartMCU(mode: byte):boolean;
function  BB5_EraseFile(core: string):boolean;
function  BB5_EraseArea(Start, arStop: LongInt; FlashCfg, Byte1, Byte2, Byte3:byte):boolean;
function  BB5_EraseAreaSmallBlock(Start, arStop: LongInt; FlashCfg,Byte1,Byte2,Byte3:byte):boolean;
function  BB5_EraseSegment(startSegment, stopSegment:LongInt; FlashCfg, Byte1, Byte2, Byte3:byte):boolean;
function  BB5_EraseSector (startSector,EraseSectorSize:LongInt; FlashCfg, Byte1, Byte2, Byte3:byte):boolean;
function  BB5_WriteFile(core: string):boolean;
function  s40prep04 ():Boolean; //  $04 byte adl flashing ( normal s40 )
function  s40prep80():Boolean;
function  extractloader(core:string ; mode : integer):Boolean;
function  BB5_FlashingXSR15():boolean;
function  RebuildPartition(F:TMemoryStream; PLen: integer):boolean;
function  s60checkadl():Byte;
function  ADLBootInFlash():Boolean;
function  ADL06auth ():Boolean;
function  AdlRestart06 (rb:byte):Boolean;
function  ADL80auth ():Boolean;
function  OMAP1710boot () : boolean;
function  OMAPFlash():Boolean;
function  Omap1610extrboot(ASIC:string):boolean;
function  OMAP1610boot () : boolean;
function  OMAP2420boot () : boolean;
function  ADLAPErestart(rb:Byte):Boolean;
function  S40BuildCertBody(core:string):Boolean;
function  s4080Final():Boolean;
function  ExtractloaderXSRRap3Gv4(mode:integer):Boolean;
function  PrepareRAWloader(loader:TMemoryStream):TMemoryStream;
function  checkbootcode():Boolean;
function  RAPnewChkADL ():Boolean;
function  RapNewFinish():boolean;
function  RapNewFinishLocal():boolean;
function  CheckCMTboot():Boolean;
function  RAPUFinalizeboot(rapmode:integer):Boolean;
function  frameCrc(Buf:Pointer; buflen:Integer):Byte;
function  RapuYamaErase(core:string):Boolean;
function  RapuYamaWriteFile(core:string):Boolean;
function  BB5_FlashingXSR16():boolean;
function  NomandicBoot(mode:Integer):Boolean;
function  NomandicAPErawextract():Boolean;
function  PrepareApeNomandicloader(loader:Tmemorystream):TMemoryStream;
function  NomandicAPESendBoot():Boolean;
function  nomandicIniUpdServer():Boolean;
function  NomandicRawextract():Boolean;
function  PrepareCMTNomandicloader(loader:Tmemorystream):TMemoryStream;
function  NomandicSendBoot():Boolean;
function  NomandicFlprepare():Boolean;
function  NomandicEraseFile(core:string):Boolean;
function  NomandicWriteFile(core:string):Boolean;
procedure BB5_ExtractAPERAWLoader(RAWBlock, RAWLoader:TMemoryStream; Result:boolean);
function  nomandicEndflash():Boolean;
function  BB5_FlashingNomadic():boolean;
function  cmtreadreq():Boolean;
function  apereadreq():Boolean;
function  readcertrequsb(CERT : string):string;
function  buildxsr16cert(DataStream : widestring; cert : string ): Boolean;
function  CertErase(CERT : string):Boolean;
function  RAPnewChkADLWCRT ():Boolean;
function  RAPnewChkADL2 ():Boolean;
function  contentExplore():Boolean;
function  s40flashprepare2ndstage():Boolean;
function  BB5_PerFlashing():boolean;
function  BB5_EraseCustomArea_USB(area:string):boolean;
function  getversion(algfile:string):string;

type

    E = class(exception);

    TRAPInfoRecord = record
    SYSTEM_ASIC_ID : array[0..$13] of byte;
    EMx_ID         : array[0..$03] of byte;
    PUBLIC_ID      : array[0..$13] of byte;  //5800 - 1FF0001841158B52064E64D3C3E9A7F38DC47E29
    ASIC_MODE      : byte;
    ROOT_KEY_HASH  : array[0..$0f] of byte;  //5800 - CAEEBB65D3C48E6DC73B49DC5063A2EE
    ROM_ID         : array[0..$07] of byte;  //5800 - 4B9B75103E691FF8

    //Old version
    ASICID           : array[0..$14] of byte;  //5800 - 000000010000022600010006400C192101031103 [RAPIDO3G ver: 1.x]
    ROMID            : array[0..$07] of byte;  //5800 - 4B9B75103E691FF8
    PublicID         : array[0..$13] of byte;  //5800 - 1FF0001841158B52064E64D3C3E9A7F38DC47E29
    //for CMT
    BootID           : array[0..$07] of byte;  //6233 - 0803000002010000
    PAPUBKEYSID      : array[0..$13] of byte;  //6233 - 2F36DDC4990FD844712A61A80C033211BD9602E3
    FlashID          : array[0..$0A] of byte;  //6233 - 00EC2208012100000100
    //for APE
    PAPUBKEYSHashCMT : array[0..$13] of byte; //5800 - 76A20187051C30162EE91C77AE5E6011F5F1BA61
    EM1ID            : DWord;                  //5800 - 00000295
    EM2ID            : DWord;                  //5800 - 00000B22
    MODEID           : Byte;                   //00
    APErootkey       : array[0..$0f] of Byte;
    APEFlashID       : array [0..$0A] of byte;
    APEASICID        : array [0..$03] of Byte;
    ALGO             : array [0..$0F] of Byte;
    end;

    TBlockRec = record
    Block            : Byte;
    OffSet           : Dword;
    Size             : Word;
    end;
const
     BB5_EraseSectorSize: LongInt = $10000;

var
   TransId          : byte;
   MsgBody          : byte;
   msgid            : Byte;
   RAPInfo          : TRAPInfoRecord;
   partition        : Boolean;
   partitionstream  : TMemoryStream;
   fltime           : cardinal;
   adlmode          : Byte;
implementation
uses FbusMain;

function ISIHeaderTransId():byte;
begin
     inc(TransId);
     //if TransId=0 then inc(TransId);
     Result:=TransId;
end;

function ISIHeaderMsgBody():byte;
begin
     inc(MsgBody);
     //if MsgBody=0 then inc(MsgBody);
     Result:=MsgBody;
end;

//Get RAP Info
function GetRAPInfo():boolean;
var i,j    : integer;
    Key    : Byte;
    KeyLen : Byte;
begin
     FillMemory(@RAPInfo.ROOT_KEY_HASH,$10,$00);
     FillMemory(@RAPInfo.APErootkey,$10,$00);
     FillMemory(@RAPInfo.FlashID,$A,$00);
     FillMemory(@RAPInfo.APEFlashID,$A,$00);
     FillMemory(@RAPInfo.PublicID,$14,$00);
     FillMemory(@RAPInfo.BootID,$8,$00);
     FillMemory(@RAPInfo.PAPUBKEYSID,$14,$00);
     Result:=false; i:=$10;
     USBBulkWritePort(@GETRoot, Length(GETRoot));
     if Not USBBulkReadPort($FFFF) then exit;

     while i < Length(rxbuf) do
     begin
          Key   :=rxbuf[i];
          KeyLen:=rxbuf[i+1]-2;
          inc(i, 2);
          case Key of
          $01:
              begin
                   for j:=$0 to $9 do RAPInfo.FlashID[j]:= rxbuf[i+j];
                   inc(i, KeyLen);
              end;
          $03:
              begin
                   for j:=$0 to $9 do RAPInfo.APEFlashID[j]:= rxbuf[i+j];
                   inc(i, KeyLen);
              end;
          $04:
              begin
                   // 0803000002010000
                   for j:=$0 to $7 do RAPInfo.BootID[j]:= rxbuf[i+j];
                   inc(i,$10);
                   for j:=0 to $0F do RAPInfo.APErootkey[j]:= rxBuf[i+j];
                   inc(i, KeyLen-$10);
              end;
          $05:
              begin
                   // 0A900018A8B54650B9C89AA40EEC5059B5762F38
                   inc(i, $0A);
                   for j:=0 to $13 do RAPInfo.PublicID[j]:= rxbuf[i+j];
                   // BAF3A9C3DBFA8454937DB77F2B8852B1
                   inc(i, $14);
                   for j:=0 to $0F do RAPInfo.ROOT_KEY_HASH[j]:= rxbuf[i+j];
                   inc(i, $10);
                   // 2F36DDC4990FD844712A61A80C033211BD9602E3
                   for j:=0 to $13 do RAPInfo.PAPUBKEYSID[j]:= rxbuf[i+j];
                   inc(i, $14);
                   Result:=True;
                   inc(i, KeyLen-$42);
              end else
          inc(i, KeyLen);
          end;//End Of Case
     end;
{ ASICID           : array[0..$14] of byte;  //5800 - 000000010000022600010006400C192101031103 [RAPIDO3G ver: 1.x]
  ROMID            : array[0..$07] of byte;  //5800 - 4B9B75103E691FF8
  PublicID         : array[0..$13] of byte;  //5800 - 1FF0001841158B52064E64D3C3E9A7F38DC47E29
  //for CMT
  BootID           : array[0..$07] of byte;  //6233 - 0803000002010000
  RootKeyHash      : array[0..$0f] of byte;  //5800 - CAEEBB65D3C48E6DC73B49DC5063A2EE
  PAPUBKEYSID      : array[0..$14] of byte;  //6233 - 2F36DDC4990FD844712A61A80C033211BD9602E3
  //for APE
  PAPUBKEYSHashCMT : array[0..$13] of byte;  //5800 - 76A20187051C30162EE91C77AE5E6011F5F1BA61
  EM1ID            : DWord;                  //5800 - 00000295
  EM2ID            : DWord;                  //5800 - 00000B22
  MODEID           : Byte;                   //00}


{Processing file: RM-356_31.0.101_prd.core.C00
--- Press phone's POWER button or connect a CHARGER ! ---
warning: Some new phones consume more power, please connect cable to USB host instead of USB hub.
[ADL] Pooling for ADL device
[ADL] Device found : nmwcdnsuc\Nokia USB Flashing Generic-2c024cda
RAP SYSTEM ASIC ID: 000000010000022600010006400C192101031103 [RAPIDO3G ver: 1.x]
RAP EM1 ID: 00000295
RAP EM2 ID: 00000B22
RAP PUBLIC ID: 1FF0001841158B52064E64D3C3E9A7F38DC47E29
RAP ASIC MODE ID: 00
RAP ROOT KEY HASH: CAEEBB65D3C48E6DC73B49DC5063A2EE
RAP ROM ID: 4B9B75103E691FF8
[ADL] Flashing CMT Update Server Data, ULO: 0x3B80 bytes
[ADL] Update Server code succesfully sent to phone
[ADL] Flashing CMT Update Server Data, XSR: 0x2A3F45 bytes
[ADL] RAP3NAND sent.
[ADL] PASUBTOC sent.
[ADL] UPDAPP sent.
[ADL] Update Server code succesfully sent to phone
[ADL] Pooling for ADL device}
end;

procedure BB5_ExtractCertData(core:string;needSert:string;CertData:TMemoryStream;Result:boolean; ape:boolean);
var
     HdrLen, i, good                       : Integer;
     buf                                   : array[0..$3FFFF] of byte;
     DataLen, CertLen, CertOffSet, tmp     : LongInt;
     CertName                              : String;
     CertDone,
     NewCertBegin,
     NeedCertFound,
     CertDataBricked                       : Boolean;
     fs                                    : TFileStream;
     apeb                                  : byte;
Begin
     Result:=False;
    // Form1._msg('Processing '+ExtractFileName(core));
try
     fs:=TFileStream.Create(core,fmOpenRead);
     fs.Seek(0, sofromBeginning);
     fs.Read(i,1);
     if i<>$B2 then
     begin
          Form1._msg('Invalid Image File');
          USBClosePort;
          fs.Free;
          exit;
     end;
     fs.ReadBuffer(buf[0], 4);//Длина Flash Header
     HdrLen := HexToInt(IntToHex(buf[0], 2)+IntToHex(buf[1], 2)+IntToHex(buf[2], 2)+IntToHex(buf[3], 2));
     fs.Seek(HdrLen,soFromCurrent);
     CertDone:=False;//Признак концовки текущей части сертификата
     CertDataBricked:=False;//Признак того, что в данных сертификата присутствует разметка Flash-token
     NewCertBegin:=False;//Признак начала нового сертификата
     NeedCertFound:=False;//Признак того, что искомый серт найден
     while ((fs.Position+$13)<fs.Size) and Not (NewCertBegin and NeedCertFound) do
     begin
          fs.ReadBuffer(buf[0], 1);
          case buf[0] of
          $54://Разметка Flash-token
          begin
               fs.ReadBuffer(buf[0], $12);
               DataLen := HexToInt(IntToHex(buf[9], 2)+IntToHex(buf[10], 2)+IntToHex(buf[11], 2)+IntToHex(buf[12], 2));
               if CertDone then
               begin
                    CertOffSet:=fs.Position;
                    CertLen:=DataLen;
                    CertDone:=False;
                    //Form1._msg('Cert: '+CertName+' Found');
                    CertDataBricked:=False;
                    CertData.CopyFrom(fs, CertLen);

                    if fs.Position>=fs.Size then break;
                    fs.ReadBuffer(buf[0], $1);
                    //если следующий байт не является началом разметки Cert-token,
                    //значит данные искомого блока поделены на кусочки разметкой Flash-token
                    if buf[0]<>$5D then
                    begin
                        //Warning: Data is splitted into bricks!
                         CertDataBricked:=True;
                         fs.Seek(fs.Position-1, sofromBeginning);
                         continue;
                    end;
                    break;//найдено начало нового серта -> стоп
               end;
               if CertDataBricked and not NewCertBegin then
                  CertData.CopyFrom(fs, DataLen) else //копирование при условии, что это кусочек искомого блока
                  fs.Seek(DataLen, sofromCurrent);  //пропуск, если левый кусочек
          end;

          $5D://Разметка Cert-token
              case ape of

              false:  // CMT mode

              begin
               fs.ReadBuffer(buf[0], $3);
               fs.ReadBuffer(buf[0], buf[2]+1);
               DataLen := HexToInt(IntToHex(buf[37], 2)+IntToHex(buf[38], 2)+IntToHex(buf[39], 2)+IntToHex(buf[40], 2));
               good:=0;
               for i:=$0 to $0F do if RAPInfo.ROOT_KEY_HASH[i]=buf[i] then inc(good);
               if good<$10 then
               begin
                    //Начало сертификата не совпадает с Root-Hash, пропускаем
                    fs.Seek(DataLen, sofromCurrent);
                    continue;
               end;
               //Найдено начало нового сертификата, который совпадает с Root-Hash
               CertName:='';
               for i:=$14 to $23 do if buf[i]=$00 then break else CertName:=CertName+Chr(buf[i]);
               tmp:=CertData.Size;
               //form1._msg(certname);
               //Сравнение имени найденного сертификата с искомым
               if not MatchesMask(CertName, '*'+needSert+'*') then //Имя текущего сертификата не совпадает с искомым
               begin
                    //Если искомый серт уже был найден, то перед началом текущего находится концовка искомого
                    if NeedCertFound then NewCertBegin:=True;
                    fs.Seek(DataLen, sofromCurrent);//пропускаем найденный блок сертификата
                    continue;
               end
               else //Найдено начало искомого серта
               begin
                    NeedCertFound:=true;
                  // Form1._msg('Cert: '+CertName+' Match with Root');
                    if Not NewCertBegin then //Если после найденного начала искомого серта не было найдено начало следующего, то
                    begin
                         CertData.CopyFrom(fs, DataLen);//копируем текущий блок
                         CertDone:=True;//
                    end;
               end;
               end;

             True :   //APE mode
                 begin
               fs.ReadBuffer(buf[0], $3);
               fs.ReadBuffer(buf[0], buf[2]+1);
               DataLen := HexToInt(IntToHex(buf[37], 2)+IntToHex(buf[38], 2)+IntToHex(buf[39], 2)+IntToHex(buf[40], 2));
               apeb:=buf[32];
               good:=0;
                if apeb<>$01 then begin
                  fs.Seek(DataLen, sofromCurrent);
                  continue;
                end;
               for i:=$0 to $0F do if RAPInfo.APERootkey[i]=buf[i] then inc(good);
               if good<$10 then
               begin
                    //Начало сертификата не совпадает с Root-Hash, пропускаем
                    fs.Seek(DataLen, sofromCurrent);
                    continue;
               end;
               //Найдено начало нового сертификата, который совпадает с Root-Hash
               CertName:='';
               for i:=$14 to $23 do if buf[i]=$00 then break else CertName:=CertName+Chr(buf[i]);
               tmp:=CertData.Size;
               //form1._msg(certname);
               //Сравнение имени найденного сертификата с искомым
               if not MatchesMask(CertName, '*'+needSert+'*') then //Имя текущего сертификата не совпадает с искомым
               begin
                    //Если искомый серт уже был найден, то перед началом текущего находится концовка искомого
                    if NeedCertFound then NewCertBegin:=True;
                    fs.Seek(DataLen, sofromCurrent);//пропускаем найденный блок сертификата
                    continue;
               end
               else //Найдено начало искомого серта
               begin
                    NeedCertFound:=true;
                   // Form1._msg('APE Cert: '+CertName+' Match with Root');
                    if Not NewCertBegin then //Если после найденного начала искомого серта не было найдено начало следующего, то
                    begin
                         CertData.CopyFrom(fs, DataLen);//копируем текущий блок
                         CertDone:=True;//
                    end;
               end;
               end;
            end;
          end;//end of case
     end;//end while
     fs.free;
     CertData.Seek(0, soFromBeginning);
     Result:=True;
except
      begin
           fs.free;
           Result:=False;
           exit;
      end;
end;
end;

procedure BB5_ExtractBlockOfRAWLoader(core: string;RAWBlock:TMemoryStream; var Result:boolean);
var
     buf               : array[0..$3] of byte;
     HdrLen,                         //Длина Flash-заголовка
     SeemCount         : Dword;      //Кол-во блоков в Flash-заголовке
     CurrSeem          : Byte;       //Текущий блок
     CurrSeemLen       : Word;       //Длина данных текущего блока
     fs                : TFileStream;
begin
     Result:=false;
     //Form1.lst1.items.add('RawLoaderExtract: Processing '+ExtractFileName(core));
try
     fs:=TFileStream.Create(core,fmOpenRead);
     fs.Read(buf[0] ,1);
     if buf[0]<>$B2  then  //Заголовок / идентификатор
     begin
          Form1.lst1.items.add('RawLoaderExtract: Error extracting RAW-loader from '+ExtractFileName(core));
          fs.Free;
          exit;
     end;
     fs.ReadBuffer(buf[0], 4);//Длина Flash-header'a
     HdrLen    := HexToInt(IntToHex(buf[0], 2)+IntToHex(buf[1], 2)+IntToHex(buf[2], 2)+IntToHex(buf[3], 2));

     fs.ReadBuffer(buf[0], 4);//Кол-во блоков в Flash-заголовке
     SeemCount := HexToInt(IntToHex(buf[0], 2)+IntToHex(buf[1], 2)+IntToHex(buf[2], 2)+IntToHex(buf[3], 2));

     while (fs.Position<HdrLen) do
     begin
          //Поиск блока F3 в котором находится RAW-лоадер
          fs.ReadBuffer(CurrSeem, 1);
          case CurrSeem of//Перебор всех блоков, поиск блока со структурой RAW-loader'а
          $EE:
              begin
                   fs.ReadBuffer(buf[0], 2);
                   CurrSeemLen := (buf[0]*$100)+buf[1];
                   fs.Seek(CurrSeemLen, sofromcurrent);
              end;
          $F3:
              begin
                   //Читаем длину блока F3
                   fs.ReadBuffer(buf[0], 2);
                   CurrSeemLen := (buf[0]*$100)+buf[1];
                   fs.ReadBuffer(buf[0], 1);
                   //Проверка заголовка RAW-лоадера (байт B0)
                   if buf[0]<>$B0 then
                   begin
                        Form1._msg('RawLoader: Damaged data :(');
                        fs.free;
                        exit;
                   end
                   else
                   begin
                        fs.Seek(fs.Position-1, sofromBeginning);
                        RAWBlock.CopyFrom(fs, CurrSeemLen);
                        fs.free;
                        Result:=True;
                        exit;
                   end;
              end;//End of Block F3
          else
              begin
                   fs.ReadBuffer(buf[0], 1);
                   CurrSeemLen:=buf[0];
                   fs.Seek(CurrSeemLen, sofromcurrent);
              end;
          end;//end of Case
     end;
     fs.free;
except
      begin
           fs.free;
           Form1._msg('RawLoader: Error extracting RAW-loader');
           exit;
      end;
end;
end;

procedure BB5_ExtractAPERAWLoader(RAWBlock, RAWLoader:TMemoryStream; Result:boolean);
var
     b                 : Boolean;
     i, j, k, good     : Integer;
     buf               : array[0..$3] of byte;
     RootInBlock       : array[0..$F] of byte;
     RAWLoaderBuf      : array[0..$ffff] of byte;
     RAWHdrLen,
     BlockCount        : DWord;
     PatchOffset,
     PatchLen          : Word;
     BlockRec          : array of TBlockRec;
     RAWLoaderLen,
     RAWLoaderOffset   : Dword;
     SubstBlock        : byte;//Блок подстановки
begin
     Result:=false;

     RAWBlock.Seek(1, sofromBeginning);//Пропускаем идентификатор $B0, т.к. мы его проверили при извлечении
     RAWBlock.ReadBuffer(buf[0], 4);//Длина RAWBlock-header'a
     RAWHdrLen  := HexToInt(IntToHex(buf[0], 2)+IntToHex(buf[1], 2)+IntToHex(buf[2], 2)+IntToHex(buf[3], 2));

     RAWBlock.ReadBuffer(buf[0], 4);//Кол-во блоков в RAWBlock'е
     BlockCount := HexToInt(IntToHex(buf[0], 2)+IntToHex(buf[1], 2)+IntToHex(buf[2], 2)+IntToHex(buf[3], 2));

     if (RAWBlock.Size<RAWHdrLen) or (BlockCount<1) then //Проверка на целостность данных
     begin
          Form1._msg('RawLoader: Damaged data :(');
          exit;
     end;

     SetLength(BlockRec, BlockCount);//Инициализация массива блоков
     i:=0;
     while (RAWBlock.Position<RAWHdrLen) and (i<BlockCount) do
     begin
          RAWBlock.ReadBuffer(buf[0], 1);//Имя блока
          BlockRec[i].Block:=buf[0];
          if (buf[0]<>$E4) and (buf[0]<>$E5) and (buf[0]<>$EA) then
          begin
               RAWBlock.ReadBuffer(buf[0], 1);//Длина блока
               BlockRec[i].Size:=buf[0];
               BlockRec[i].OffSet:=RAWBlock.Position;//Начало данных блока
          end
          else
          begin
               RAWBlock.ReadBuffer(buf[0], 2);//Длина блока
               BlockRec[i].Size:=(buf[0]*$100)+buf[1];
               BlockRec[i].OffSet:=RAWBlock.Position;//Начало данных блока
          end;
          RAWBlock.Seek(BlockRec[i].Size, sofromCurrent);//Пропускаем данные текущего блока
          inc(i);
     end;

     RAWLoaderOffSet:=RAWBlock.Position;
     RAWLoaderLen:=RAWBlock.Size-RAWLoaderOffSet;

     if RAWLoaderLen<=0 then //Проверка на наличие RAW-loader'а в RAW-Block'е
     begin
          Form1._msg('RawLoader not found...');
          exit;
     end;
     //Копируем RAW-loader
     RAWLoader.CopyFrom(RAWBlock, RAWLoaderLen);
    // RAWLoader.SaveToFile('C:\Extract_RAW_Loader_extr_'+ExtractFileName(core)+'.bin');
     //Патчинг RAW-loader'a
     i:=0; SubstBlock:=0;
     while i<BlockCount do
     begin
          //Если RootHash в блоке длин/смещений не совпал c RAP-RootHash, то производим замену
          //Просмотрим эти блоки - $E2, $E3, $E9
          if (BlockRec[i].Block=$E2) or (BlockRec[i].Block=$E3) or (BlockRec[i].Block=$E9) then
          begin
               if BlockRec[i].Size<$18 then continue;//Неверная длина данных в блоке смещения, пропускаем
               RAWBlock.Seek(BlockRec[i].OffSet, sofromBeginning);//Переход к началу данных блока смещений
               RAWBlock.ReadBuffer(RootInBlock[0], $10);//Чтение Root из блока смещений

               //Проверка на совпадение RAP-Root & Block-Root
               good:=0;
               for j:=0 to $0f do if RootInBlock[j]=RAPInfo.APerootkey[j] then inc(good);
               if good<>$10 then
               begin
                    //Соответствие блоков длин/смещений и патчинговых блоков ($E4, $E5, $EA)
                    if BlockRec[i].Block=$E2 then SubstBlock:=$E4;
                    if BlockRec[i].Block=$E3 then SubstBlock:=$E5;
                    if BlockRec[i].Block=$E9 then SubstBlock:=$EA;

                    //Чтение данных из текущего блока длин/смещений
                    //Данные о длине и смещении всегда располагаются в конце блока (последние 4 байта)
                    RAWBlock.Seek((BlockRec[i].OffSet+BlockRec[i].Size-4), sofromBeginning);
                    RAWBlock.ReadBuffer(PatchOffset, 2);//Чтение смещения
                    PatchOffset:=Swap(PatchOffset);
                    RAWBlock.ReadBuffer(PatchLen, 2);//Чтение длины патча
                    PatchLen:=Swap(PatchLen);

                    //Поиск патчинг-блока с RootHash, который совпадает с RAP-RootHash
                    k:=0; b:=true;
                    while (k<BlockCount) and b do
                    begin
                         if BlockRec[k].Block=SubstBlock then
                         begin
                              RAWBlock.Seek(BlockRec[k].OffSet, sofromBeginning);//Переход к началу данных патчинг блока
                              RAWBlock.ReadBuffer(RootInBlock[0], $10);//Чтение Root из патчинг блока
                              //Проверка на совпадение RootHash'ей
                              good:=0;
                              for j:=0 to $0f do if RootInBlock[j]=RAPInfo.APErootkey[j] then inc(good);
                              if good=$10 then b:=false else begin
                              inc(k);
                              continue;
                              end;
                         end
                         else inc(k);//RootHash'и не совпали, пропускаем
                    end;
                    //RootHash'и совпали, патчим...
                    if Not b then
                    begin
                        // Form1.lst1.items.add('PatchRAWBlock: Found matching RootkeyHash substitution data, ID:'+IntToHex(BlockRec[k].Block, 2));
                         //Чтение данных патча и их длины

                         if (SubstBlock=$E4) or (SubstBlock=$E5) then
                         RAWBlock.Seek(BlockRec[k].OffSet+$14, sofromBeginning);//Пропуск $10 байт RootHash & 4 байт (возможно это CRC)
                         if SubstBlock=$EA then
                         RAWBlock.Seek(BlockRec[k].OffSet+$20, sofromBeginning);//Пропуск $10 байт RootHash & $10 байт (имя блока & возможно CRC)

                         RAWBlock.ReadBuffer(RAWLoaderBuf[0], PatchLen);

                         RAWLoader.Seek(PatchOffset, sofromBeginning);
                         RAWLoader.WriteBuffer(RAWLoaderBuf[0], PatchLen);
                    end;
               end;//end of good
               inc(i);
          end else inc(i);
     end;
     Result:=true;
end;

procedure BB5_ExtractRAWLoader(RAWBlock, RAWLoader:TMemoryStream; Result:boolean);
var
     b                 : Boolean;
     i, j, k, good     : Integer;
     buf               : array[0..$3] of byte;
     RootInBlock       : array[0..$F] of byte;
     RAWLoaderBuf      : array[0..$ffff] of byte;
     RAWHdrLen,
     BlockCount        : DWord;
     PatchOffset,
     PatchLen          : Word;
     BlockRec          : array of TBlockRec;
     RAWLoaderLen,
     RAWLoaderOffset   : Dword;
     SubstBlock        : byte;//Блок подстановки
begin
     Result:=false;

     RAWBlock.Seek(1, sofromBeginning);//Пропускаем идентификатор $B0, т.к. мы его проверили при извлечении
     RAWBlock.ReadBuffer(buf[0], 4);//Длина RAWBlock-header'a
     RAWHdrLen  := HexToInt(IntToHex(buf[0], 2)+IntToHex(buf[1], 2)+IntToHex(buf[2], 2)+IntToHex(buf[3], 2));

     RAWBlock.ReadBuffer(buf[0], 4);//Кол-во блоков в RAWBlock'е
     BlockCount := HexToInt(IntToHex(buf[0], 2)+IntToHex(buf[1], 2)+IntToHex(buf[2], 2)+IntToHex(buf[3], 2));

     if (RAWBlock.Size<RAWHdrLen) or (BlockCount<1) then //Проверка на целостность данных
     begin
          Form1._msg('RawLoader: Damaged data :(');
          exit;
     end;

     SetLength(BlockRec, BlockCount);//Инициализация массива блоков
     i:=0;
     while (RAWBlock.Position<RAWHdrLen) and (i<BlockCount) do
     begin
          RAWBlock.ReadBuffer(buf[0], 1);//Имя блока
          BlockRec[i].Block:=buf[0];
          if (buf[0]<>$E4) and (buf[0]<>$E5) and (buf[0]<>$EA) then
          begin
               RAWBlock.ReadBuffer(buf[0], 1);//Длина блока
               BlockRec[i].Size:=buf[0];
               BlockRec[i].OffSet:=RAWBlock.Position;//Начало данных блока
          end
          else
          begin
               RAWBlock.ReadBuffer(buf[0], 2);//Длина блока
               BlockRec[i].Size:=(buf[0]*$100)+buf[1];
               BlockRec[i].OffSet:=RAWBlock.Position;//Начало данных блока
          end;
          RAWBlock.Seek(BlockRec[i].Size, sofromCurrent);//Пропускаем данные текущего блока
          inc(i);
     end;

     RAWLoaderOffSet:=RAWBlock.Position;
     RAWLoaderLen:=RAWBlock.Size-RAWLoaderOffSet;

     if RAWLoaderLen<=0 then //Проверка на наличие RAW-loader'а в RAW-Block'е
     begin
          Form1._msg('RawLoader not found...');
          exit;
     end;
     //Копируем RAW-loader
     RAWLoader.CopyFrom(RAWBlock, RAWLoaderLen);
    // RAWLoader.SaveToFile('C:\Extract_RAW_Loader_extr_'+ExtractFileName(core)+'.bin');
     //Патчинг RAW-loader'a
     i:=0; SubstBlock:=0;
     while i<BlockCount do
     begin
          //Если RootHash в блоке длин/смещений не совпал c RAP-RootHash, то производим замену
          //Просмотрим эти блоки - $E2, $E3, $E9
          if (BlockRec[i].Block=$E2) or (BlockRec[i].Block=$E3) or (BlockRec[i].Block=$E9) then
          begin
               if BlockRec[i].Size<$18 then continue;//Неверная длина данных в блоке смещения, пропускаем
               RAWBlock.Seek(BlockRec[i].OffSet, sofromBeginning);//Переход к началу данных блока смещений
               RAWBlock.ReadBuffer(RootInBlock[0], $10);//Чтение Root из блока смещений

               //Проверка на совпадение RAP-Root & Block-Root
               good:=0;
               for j:=0 to $0f do if RootInBlock[j]=RAPInfo.ROOT_KEY_HASH[j] then inc(good);
               if good<>$10 then
               begin
                    //Соответствие блоков длин/смещений и патчинговых блоков ($E4, $E5, $EA)
                    if BlockRec[i].Block=$E2 then SubstBlock:=$E4;
                    if BlockRec[i].Block=$E3 then SubstBlock:=$E5;
                    if BlockRec[i].Block=$E9 then SubstBlock:=$EA;

                    //Чтение данных из текущего блока длин/смещений
                    //Данные о длине и смещении всегда располагаются в конце блока (последние 4 байта)
                    RAWBlock.Seek((BlockRec[i].OffSet+BlockRec[i].Size-4), sofromBeginning);
                    RAWBlock.ReadBuffer(PatchOffset, 2);//Чтение смещения
                    PatchOffset:=Swap(PatchOffset);
                    RAWBlock.ReadBuffer(PatchLen, 2);//Чтение длины патча
                    PatchLen:=Swap(PatchLen);

                    //Поиск патчинг-блока с RootHash, который совпадает с RAP-RootHash
                    k:=0; b:=true;
                    while (k<BlockCount) and b do
                    begin
                         if BlockRec[k].Block=SubstBlock then
                         begin
                              RAWBlock.Seek(BlockRec[k].OffSet, sofromBeginning);//Переход к началу данных патчинг блока
                              RAWBlock.ReadBuffer(RootInBlock[0], $10);//Чтение Root из патчинг блока
                              //Проверка на совпадение RootHash'ей
                              good:=0;
                              for j:=0 to $0f do if RootInBlock[j]=RAPInfo.ROOT_KEY_HASH[j] then inc(good);
                              if good=$10 then b:=false else begin
                              inc(k);
                              continue;
                              end;
                         end
                         else inc(k);//RootHash'и не совпали, пропускаем
                    end;
                    //RootHash'и совпали, патчим...
                    if Not b then
                    begin
                        // Form1.lst1.items.add('PatchRAWBlock: Found matching RootkeyHash substitution data, ID:'+IntToHex(BlockRec[k].Block, 2));
                         //Чтение данных патча и их длины

                         if (SubstBlock=$E4) or (SubstBlock=$E5) then
                         RAWBlock.Seek(BlockRec[k].OffSet+$14, sofromBeginning);//Пропуск $10 байт RootHash & 4 байт (возможно это CRC)
                         if SubstBlock=$EA then
                         RAWBlock.Seek(BlockRec[k].OffSet+$20, sofromBeginning);//Пропуск $10 байт RootHash & $10 байт (имя блока & возможно CRC)

                         RAWBlock.ReadBuffer(RAWLoaderBuf[0], PatchLen);

                         RAWLoader.Seek(PatchOffset, sofromBeginning);
                         RAWLoader.WriteBuffer(RAWLoaderBuf[0], PatchLen);
                    end;
               end;//end of good
               inc(i);
          end else inc(i);
     end;
     Result:=true;
end;

function  BB5_SendADLLoader(UAgent:TMemoryStream):Boolean;
var  i,j,k,PktLen  : Integer;
     b             : Boolean;
     CHK           : Word;
     tmp           : array of byte;
     ms            : TMemoryStream;
Begin
     Result:=false;
     UAgent.Seek(0, soFromBeginning);
     SetLength(tmp, UAgent.Size);
     if UAgent.size=0 then begin
     result:=False;
     Exit;
     end;
     UAgent.ReadBuffer(tmp[0], UAgent.Size);
     CHK:=GetLoaderCRC(@tmp[0], UAgent.Size);
     Form1._msg('Loader len: '+inttostr(UAgent.Size)+', CHK: '+inttohex(CHK, 4));
     Form1._msg('ADL -> Sending loader...');
     Application.ProcessMessages;
     //Get Block  - Х.з. зачем... Запрос 256 блока PM ????
     //При прошивке 6233 и 7900
     //запрос 6233 1B 00 10 23 00 06 00 15 54 42 01 00
     //запрос 7390 1B 00 10 23 00 06 00 16 63 42 01 00
     //ответ  6233 1B 10 00 23 00 16 15 36 54 43 00 01 07 10 00 00 00 00 00 00 00 02 00 00 00 00 00 00
     //ответ  7390 1B 10 00 23 00 16 16 32 63 43 00 01 07 10 00 00 00 00 00 00 00 02 00 00 00 00 00 00
     GetBlock[7]:=msgid;
     GetBlock[8]:=ISIHeaderTransId;
     GetBlock[9]:=$42;
     GetBlock[10]:=$01;
     GetBlock[11]:=$00;
     USBBulkWritePort(@GetBlock, Length(GetBlock));
     USBBulkReadPort($FFFF);

     //Передача данных о размере и контрольной сумме ADL-loader'а
     //При прошивке 6233 и 7900
     //запрос 6233 1B 00 10 6F 00 0F 00 15 55 02 00 1E 00 03 6E C0 F9 63 FF 00 00  --> Loader len: 224960, CHK: 0xF963
     //запрос 6270 1B 00 10 6F 00 0F 00 15 1C 02 00 1E 00 03 B1 40 A4 C9 FF 00 00  --> Loader len: 241984, CHK: 0xA4C9
     //запрос 7390 1B 00 10 6F 00 0F 00 16 64 02 00 1E 00 03 6E C0 FE 0F FF 00 00

     //ответ  6233 1B 10 00 6F 00 06 15 48 55 22 00 00
     //ответ  6270 1B 10 00 6F 00 06 15 48 1C 22 00 00
     //ответ  7390 1B 10 00 6F 00 06 16 44 64 22 00 00

     //SendADLCRC    : array[0..20] of Byte =
     //($1B, $00, $10, $6F, $00, $0F, $00, $16, $64, $02, $00, $1E, $00, $03, $6E, $C0, $FE, $0F, $FF, $00, $00);

     SendADLCRC[7]:=msgid; MsgBody:=$01;
     SendADLCRC[8]:=ISIHeaderTransId;
     SendADLCRC[9]:=ISIHeaderMsgBody;
     //Длина UPDAPP
     SendADLCRC[12]:=UAgent.Size div $1000000;
     SendADLCRC[13]:=UAgent.Size div $10000;
     SendADLCRC[14]:=UAgent.Size div $100;
     SendADLCRC[15]:=UAgent.Size mod $100;
     //Чек UPDAPP
     SendADLCRC[16]:=CHK div $100;
     SendADLCRC[17]:=CHK mod $100;
     USBBulkWritePort(@SendADLCRC, Length(SendADLCRC));
     USBBulkReadPort($FFFF);

     //Отправка агента по кусочкам
     b:=true;
     i:=1;//номер сообщения
     MsgBody:=2;//номер сообщения
     PktLen:=$0780;//длина отправляемого кусочка лоадера (длина как в Фениксе)
     Form1.pb1.Progress:=0;
     //ms:=TMemoryStream.Create;//для теста и сохранения текущего отправленного кусочка
     BufCopy(@SendADL[0], @txBuf[0], Length(SendADL));
     //SendADL    : array[0..15] of Byte =
     //($1B, $00, $10, $6F, $07, $8A, $00, $15, $56, $03, $00, $01, $00, $00, $07, $80);
     txBuf[6]  := $00;
     txBuf[7]  :=msgid;
     txBuf[9]  := ISIHeaderMsgBody;
     Form1.pb1.maxvalue:=100;
     UAgent.Seek(0, sofromBeginning);
     Application.ProcessMessages;
     while (UAgent.Position+PktLen)<=UAgent.Size do
     begin
          UAgent.ReadBuffer(txBuf[16], PktLen);
          Word((@txBuf[4])^):=Swap(PktLen+$0A);
          txBuf[8]  := ISIHeaderTransId;
          txBuf[11] := i;
          Word((@txBuf[14])^):=Swap(PktLen);

          //Только для сохранения отправляемых кусочков агента
          {ms.Seek(0, soFromBeginning);
          ms.WriteBuffer(txBuf[0], 16);
          ms.WriteBuffer(txBuf[16], PktLen);
          ms.SaveToFile('C:\ADL_Send\'+Int2Digs(i,4)+'.bin');
          ms.Clear;}

          k:=USBBulkWritePort(@txbuf[0], (PktLen+$10));
          if k<>(PktLen+$10) then
          begin
               USBClosePort;
               exit;
          end;

          if i=$0D then
          begin
               //данная команда присутствует в Phoenix'е - "включение подсветки дисплея"
               //Display3: array[0..11] of Byte =
               //($1B, $00, $10, $15, $00, $06, $00, $0C, $A4, $0E, $00, $00);
               USBBulkWritePort(@Display3, Length(Display3));
               USBBulkReadPort($FFFF);
          end;

          USBBulkReadPort(16);

          if ((UAgent.Size-UAgent.position)<PktLen) and b then //длина последнего кусочка
          begin
               PktLen:=UAgent.Size-UAgent.position;//последний кусочек агента
               b:=false;
          end;
          inc(i);
          Form1.pb1.Progress:=(UAgent.Position*100) div UAgent.Size;
     end;
     //ms.free;
     Form1.pb1.Progress:=0;

     //UAgent передан
     //SendADLEnd : array[0..11] of Byte =
     //($1B, $00, $10, $6F, $00, $06, $00, $0E, $80, $09, $00, $00);
     //Send 7390 1B 00 10 6F 00 06 00 16 DB 09 00 00
     //Send 6270 1B 00 10 6F 00 06 00 15 9C 09 00 00
     //Send 6233 1B 00 10 6F 00 06 00 15 CC 09 00 00

     //Read 7390 1B 10 00 6F 00 06 16 44 DB 29 00 00
     //Read 6270 1B 10 00 6F 00 06 15 48 9C 29 00 00
     //Read 6233 1B 10 00 6F 00 06 15 48 CC 29 00 00

     SendADLEnd[7]:=msgid;
     SendADLEnd[8]:=ISIHeaderTransId;
     //SendADLEnd[9]:=ISIHeaderMsgBody;
     SendADLEnd[9]:=$09;
     USBBulkWritePort(@SendADLEnd, Length(SendADLEnd));
     USBBulkReadPort(12);

     //Start UAgent
     //ADLStart   : array[0..11] of Byte =
     //($1B, $00, $10, $6F, $00, $06, $00, $0E, $81, $04, $00, $00);
     //Send 7900 1B 00 10 6F 00 06 00 16 DC 04 00 00
     //Send 6270 1B 00 10 6F 00 06 00 15 9D 04 00 00
     //Send 6233 1B 00 10 6F 00 06 00 15 CD 04 00 00

     //Read 7900 65542 байт

     ADLStart[7]:=msgid;
     ADLStart[8]:=ISIHeaderTransId;
     //ADLStart[9]:=ISIHeaderMsgBody;
     ADLStart[9]:=$04;
     USBBulkWritePort(@ADLStart, Length(ADLStart));
     USBBulkReadPort(65542);
     USBClosePort;
     Result:=true;
end;

function  BB5_NormalFlashing():boolean;
var
     b                : Boolean;
     i,phsec,flsec    : integer;
     UAgent           : TmemoryStream;
     s, needSert      : String;
     cmtflash         : DWord;
     cntc             : boolean;
Begin
     Result:=false;
     phsec:=0; flsec:=0;
      if catchdevice<>$01 then
     begin
          USBClosePort;
          exit;
     end;
     TransId:=$5E; MsgBody:=$0A;
     Application.ProcessMessages;
     preflashread;

      b:=true;
     //RootHash
     for i := 0 to $0F do b:=b and (RAPInfo.ROOT_KEY_HASH[i]<>0);

     if Not b then
     begin
          Form1._msg('->  No RootKey Asic! Unable to continue flashing...');
          exit;
     end;
     Application.ProcessMessages;
     Form1._msg('RAP_BOOT:     '      + BufToHexStr(@RAPInfo.BootID[0],      Length(RAPInfo.BootID)));
     Form1._msg('RAP_PUBLIC:   '    + BufToHexStr(@RAPInfo.PublicID[0],    Length(RAPInfo.PublicID)));
     Form1._msg('CMT_ROOTKEY:  '  + BufToHexStr(@RAPInfo.ROOT_KEY_HASH[0], Length(RAPInfo.ROOT_KEY_HASH)));
     Form1._msg('RAP_PAPUBKEY: '  + BufToHexStr(@RAPInfo.PAPUBKEYSID[0], Length(RAPInfo.PAPUBKEYSID)));

     Application.ProcessMessages;

     // Тут будет чек и репак контента
  if (not Smart) and (image<>'') and (Form1.chkCNTe.Checked=true) then
  begin
  Form1._msg('Checking CNT sector PN<>FL');
  cmtflash:=Swap(Word((@rxBuf[20])^));
  cmtflash:=cmtflash Shl 16;
  cmtflash:=cmtflash+Swap(Word((@rxBuf[18])^));
  phsec:=getcntsize(cmtflash);
  Form1._msg('PN CNT sector : '+inttostr(phsec)+' kb');
    if phsec=64 then Application.ProcessMessages else
    begin
       cntc:=False;
       if FileExists(image+'_128') then
       begin
       Form1._msg('Converted content already exist, skip convert and using 128k');
       image:=image+'_128';
       end
       else
       begin
        cntc:=convertimages40(image);
        if cntc=true then image:=image+'_128';
       end;
    end;
   end;

     Application.ProcessMessages;

     if not Form1.chkDEADMODE.Checked then begin
     if Form1.chkDOWNGRADE.Checked=true then
     begin
          if not downgradeprep then
          begin
               Form1._msg('->  Error on flash prepare! break, Uncheck DOWNGRADE');
               Form1.SetReady;
               Form1._msg('');
               exit;
          end;
     end;
     end;
     Application.ProcessMessages;
     starttime;
     Application.ProcessMessages;

     //Извлечение Update Agent
     UAgent:=TmemoryStream.Create;
     BB5_ExtractCertData(core, 'UPDAPP', UAgent, b, false);

     if Not b then
     begin
          UAgent.Free;
          Form1._msg('Error extracting Update Agent... (((');
          Form1.SetReady;
          exit;
     end;

     if Not BB5_SendADLLoader(UAgent) then
     begin
          UAgent.Free;
          Form1.pb1.Progress:=0;
          Form1._msg('Sending UAgent Error... (((');
          Form1.SetReady;
          exit;
     end else Form1._msg('Update Server code succesfully sent to phone!');
     UAgent.Free;

      i:=0;

      repeat
      begin
      Sleep(100);
      Application.ProcessMessages;
      Inc(i)
      end;
      until (DevPresent=False) or ( i=200 ) or (catchdevice=$02);

     if i=200 then begin
     b:=False;
     Form1._msg('->  Error while restart phone - repower it and try again...');
     Exit;
     end;
     Application.ProcessMessages;
     endtimecount;
     Form1._msg('TIME : Boot time : '+showtime(tmsres));
     Application.ProcessMessages;
     b:=BB5_Flashing;
     Result:=b;
end;

function  BB5_PerFlashing():boolean;
var
     b                : Boolean;
     i,phsec,flsec    : integer;
     UAgent           : TmemoryStream;
     s, needSert      : String;
     cmtflash         : DWord;
     cntc             : Boolean;
Begin
     Result:=false;
     phsec:=0; flsec:=0;
      if catchdevice<>$01 then
     begin
          USBClosePort;
          exit;
     end;
     if savepwds40=True then Form1._msg('MMC pwd backup saved');
     TransId:=$5E; MsgBody:=$0A;
     msgid:=$1B;
     Application.ProcessMessages;
     preflashread;

      b:=true;
     //RootHash
     for i := 0 to $0F do b:=b and (RAPInfo.ROOT_KEY_HASH[i]<>0);

     if Not b then
     begin
          Form1._msg('->  No RootKey Asic! Unable to continue flashing...');
          exit;
     end;
     Application.ProcessMessages;
    // Form1._msg('RAP_BOOT:     '      + BufToHexStr(@RAPInfo.BootID[0],      Length(RAPInfo.BootID)));
    // Form1._msg('RAP_PUBLIC:   '    + BufToHexStr(@RAPInfo.PublicID[0],    Length(RAPInfo.PublicID)));
    // Form1._msg('CMT_ROOTKEY:  '  + BufToHexStr(@RAPInfo.ROOT_KEY_HASH[0], Length(RAPInfo.ROOT_KEY_HASH)));
    // Form1._msg('RAP_PAPUBKEY: '  + BufToHexStr(@RAPInfo.PAPUBKEYSID[0], Length(RAPInfo.PAPUBKEYSID)));

     Application.ProcessMessages;

     // Тут будет чек и репак контента
  Form1._msg('Checking CNT sector PN<>FL');
  cmtflash:=Swap(Word((@rxBuf[20])^));
  cmtflash:=cmtflash Shl 16;
  cmtflash:=cmtflash+Swap(Word((@rxBuf[18])^));
  phsec:=getcntsize(cmtflash);
  Form1._msg('PN CNT sector : '+inttostr(phsec)+' kb');
    if phsec=64 then Application.ProcessMessages else begin
       Form1.statusbar.Panels[0].Text:='Repack content, wait...';
       if FileExists(image+'_128') then
       begin
       Form1._msg('Converted content already exist, skip convert and using 128k');
       image:=image+'_128';
       end
       else
       begin
        cntc:=convertimages40(image);
        if cntc=true then image:=image+'_128';
       end;
    end;

     Application.ProcessMessages;

     //Извлечение Update Agent
     UAgent:=TmemoryStream.Create;
     BB5_ExtractCertData(core, 'UPDAPP', UAgent, b, false);

     if Not b then
     begin
          UAgent.Free;
          Form1._msg('Error extracting Update Agent... (((');
          Form1.SetReady;
          exit;
     end;

     if Not BB5_SendADLLoader(UAgent) then
     begin
          UAgent.Free;
          Form1.pb1.Progress:=0;
          Form1._msg('Sending UAgent Error... (((');
          Form1.SetReady;
          exit;
     end
     else Application.ProcessMessages;
     UAgent.Free;

      i:=0;

      repeat
      begin
      Sleep(100);
      Application.ProcessMessages;
      Inc(i)
      end;
      until (DevPresent=False) or ( i=200 ) or (catchdevice=$02);

     if i=200 then begin
     b:=False;
     Form1._msg('->  Error while restart phone - repower it and try again...');
     Exit;
     end;
     Application.ProcessMessages;
     //Form1._msg('TIME : Boot time : '+showtime(tmsres));
     Application.ProcessMessages;
    result:=true;
end;

function  BB5_Flashing():boolean;
var
     b,proto          : Boolean;
     i,i2             : integer;
     rb               : Byte;
     cntx             : integer;
     n2way            : Boolean;
     mcufl            : Boolean;
     cntfl            : Boolean;
begin
     rb:=$04;
     n2way:=false;
     mcufl:=false;
     cntfl:=false;
     Application.ProcessMessages;
     Form1._msg('Reopening the connection...');
     Application.ProcessMessages;
     Sleep(2000);
     Application.ProcessMessages;
     i:=30;
     while i>0 do
     begin
          Form1._msg('Waiting for response: '+inttostr(i));
          Application.ProcessMessages;
          if catchdevice<>$02 then
          begin
               Application.ProcessMessages;
               sleep (1000);
               Application.ProcessMessages;
                if stop=True then
                begin
                // Stopping operation
                dostop('FLASH');
                i:=0;
                Form1.pb1.progress:=0;
                end;
               sleep (1000);
               Application.ProcessMessages;
          end else i:=0;
          dec(i);
     end;

     if not DevPresent then
     begin
          Form1._msg('->  Phone not found... :(');
          Form1.SetBuzy;
          Form1.StatusBar.Panels[4].Text:='';
          USBClosePort;
          exit;
     end;

     fltime:=0;
     //Phone in Flash Mode???
     CheckADLUpload[7]:=msgid;
     CheckADLUpload[8]:=ISIHeaderTransId;
     CheckADLUpload[9]:=$00;
     i:=USBBulkWritePort(@CheckADLUpload, Length(CheckADLUpload));
     if i<>12 then
     begin
       Sleep(200);
       Application.ProcessMessages;
       Form1._msg('Wait for device bootup');
       i:=0;
       repeat
        begin
        Sleep(100);
        Application.ProcessMessages;
        Inc(i);
        if catchdevice=$02 then i2:=USBBulkWritePort(@CheckADLUpload, Length(CheckADLUpload));
        Form1.statusbar.Panels[0].Text:='Wait phone '+IntToStr(100-i);
        end;
       until (i2=12) or (i=100);

       if i2<>12 then  begin
       Form1._msg('->  Bootcode start in CMT fail ! Need flash via programming device :(');
       Form1.TimConChk.Interval:=2000;
       result:=False;
       Form1.statusbar.Panels[0].Text:='';
       exit;
       end;
       Form1.statusbar.Panels[0].Text:='';
       Application.ProcessMessages;
     end;

     USBBulkReadPort(12);

     if rxBuf[11]<>$04 then
     begin
          if rxBuf[11]<>$80 then
          begin
               Form1._msg('ADL Server not confirmed flashmode!');
               Form1.SetReady;
               USBClosePort;
               exit;
          end
          else
          begin
               Form1._msg('ADL -> [2nd] changing...');
               rb:=rxBuf[11];
          end;
     end
     else rb:=rxBuf[11];

    // Form1._msg(Byte2Str(rb));
    Form1._msg('ADL Server confirm flashmode!');
    Application.ProcessMessages;

     case rb of
     $04: begin
      s40prep04;
      end;
     $80: begin
       s40prep80;
       end;

     else  begin
          Form1._msg('->  Error while prepare!');
          Form1.setready;
          Exit;
           end;

     end;

       if stop=True then
       begin
                // Stopping operation
                dostop('FLASH');
                i:=0;
                Form1.pb1.progress:=0;
                StuffFlashReset;
                result:=False;
                Exit;
       end;

     //Добавил для удобства кастом-прошивки
     Form1.statusbar.Panels[4].Text:='FLASHING';
     Form1.statusbar.Panels[3].Text:='Connected';
     Form1.TimConChk.Interval:=100;
     Application.ProcessMessages;
       if Form1.chkMCUen.Checked=true then
     begin
          Form1.chkMCUen.Enabled:=False;
          Form1._msg('   ===Flashing [MCU]===');
          if not BB5_EraseFile(core) then begin StuffFlashReset; result:=False; Exit; end;
          Application.ProcessMessages;
          if not BB5_WriteFile(core) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('MCU Write done');
          mcufl:=true;
     end;
     Application.ProcessMessages;
     if Form1.chkPPMe.Checked=true then
     begin
            Form1.chkPPMe.Enabled:=False;
            Form1.chkMCUen.Enabled:=False;
          Form1._msg('   ===Flashing [PPM]===');
          if not BB5_EraseFile(ppm) then begin StuffFlashReset; result:=False; Exit; end;
           Application.ProcessMessages;
          if not BB5_WriteFile(ppm) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('PPM Write done');
     end;
     Application.ProcessMessages;
      if Form1.chkPPM1e.Checked=true then
     begin
            Form1.chkPPMe.Enabled:=False;
            Form1.chkMCUen.Enabled:=False;
            Form1.chkPPM1e.Enabled:=False;
          Form1._msg('   ===Flashing [PPM2]===');
          if not BB5_EraseFile(ppm1) then begin StuffFlashReset; result:=False; Exit; end;
           Application.ProcessMessages;
          if not BB5_WriteFile(ppm1) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('PPM Write done');
     end;
     Application.ProcessMessages;
     if Form1.chkCNTe.Checked=true then
     begin
            Form1.chkPPMe.Enabled:=False;
            Form1.chkMCUen.Enabled:=False;
            Form1.chkPPM1e.Enabled:=False;
            Form1.chkCNTe.Enabled:=False;
            Form1._msg('   ===Flashing [CNT]===');
          if readset('verify','cntverify')=True then begin
           if Form1.chkDEADMODE.Checked=True then begin
            if mcufl=True then begin
             Application.ProcessMessages;
             Form1.pb1.Progress:=0;
             Form1.statusbar.Panels[0].Text:='';
             Form1.statusbar.Panels[1].Text:='';
             Application.ProcessMessages;
             cntx:=checkcnt(image);
             Form1._msg('Checking content info...');
             case cntx of
             0:Form1._msg('Check Image : Content analyze failed, use direct write');
             1:cntfl:=True;
             2:Form1._msg('Check Image : Content size is 128k, use direct write mode');
             3:Form1._msg('Check Image : Content size is not valid, use direct write');
             4:Form1._msg('Check Image : Content size not detected, use direct write');
             end;
             Application.ProcessMessages;
            end;
            if cntfl=true then begin
            Form1._msg('Resetting phone...');
            Form1.statusbar.Panels[0].Text:='Resetting... Wait...';
            Application.ProcessMessages;
            BB5_ADL_RestartMCU(rb);
             i:=0;
             repeat
             Application.ProcessMessages;
             Sleep(150);
             Application.ProcessMessages;
             Form1.statusbar.Panels[0].Text:='Wait '+inttostr(400-i);
             Inc(i);
             until (i=400) or (catchdevice=$01);
             if i=400 then begin
             Form1._msg('Error while resetting phone, MCU start error');
             Form1._msg('Looks like HW error or downgrade try...');
             Form1._msg('Flashing failed on content check : CMT not run');
             Form1._msg('');
             Form1.statusbar.Panels[0].Text:='';
             StuffFlashReset;
             result:=False;
             Exit;
             end
             else begin
               Application.ProcessMessages;
               Form1.statusbar.Panels[0].Text:='Reset done, preparing';
              if not s40flashprepare2ndstage then
              begin
               Form1._msg('Error while prepearing phone, bootcode start error');
               Form1._msg('Looks like HW or SW error or connection fault...');
               Form1._msg('Flashing failed on content check : Bootcode not run');
               Form1._msg('');
               StuffFlashReset;
               result:=False;
               Exit;
              end
              else Application.ProcessMessages;
             end;
            end
            else Application.ProcessMessages;
           end;
          end;
          if not BB5_EraseFile(image) then begin StuffFlashReset; result:=False; Exit; end;
          Application.ProcessMessages;
          if not BB5_WriteFile(image) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('CNT Write done');
     end;
     Application.ProcessMessages;
      if Form1.chkAPEe.Checked=true then
     begin
            Form1.chkPPMe.Enabled:=False;
            Form1.chkMCUen.Enabled:=False;
            Form1.chkPPM1e.Enabled:=False;
            Form1.chkCNTe.Enabled:=False;
            Form1.chkAPEe.Enabled:=False;
          Form1._msg('   ===Flashing [APE]===');
          if not BB5_EraseFile(ape) then begin StuffFlashReset; result:=False; Exit; end;
          Application.ProcessMessages;
          if not BB5_WriteFile(ape) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('APE Write done');
     end;
     Application.ProcessMessages;
     if Form1.chkcnt3.Checked=true then
     begin
            Form1.chkPPMe.Enabled:=False;
            Form1.chkMCUen.Enabled:=False;
            Form1.chkPPM1e.Enabled:=False;
            Form1.chkCNTe.Enabled:=False;
            Form1.chkAPEe.Enabled:=False;
            Form1.chkcnt3.Enabled:=False;
          Form1._msg('   ===Flashing [CNT3]===');
          if not BB5_EraseFile(cnt3) then begin StuffFlashReset; result:=False; Exit; end;
          Application.ProcessMessages;
          if not BB5_WriteFile(cnt3) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('CNT Write done');
     end;
     Application.ProcessMessages;
     Form1._msg('ADL : End flashing');
     Form1._msg('');
     Form1._msg('Flashing done!');
     Form1._msg('Total flash time : '+showtime(fltime));
     Form1._msg('Reboot phone now...');
     Form1._msg('');
     Application.ProcessMessages;
     fltime:=0;
     Form1.statusbar.Panels[0].Text:='';
     Form1.pb1.ForeColor:=clNavy;
     Form1.pbsm1.ForeColor:=clNavy;
     Form1.pb1.MaxValue:=100;
     Form1.pb1.progress:=0;
     Form1.statusbar.Panels[1].Text:='';
     Form1.TimConChk.Interval:=2000;

     if (Form1.chkMCUen.Checked=true) and (cntfl=false) then BB5_ADL_RestartMCU(rb) else begin
       case rb of
       $80: begin
            BB5_ADL_RestartMCU(rb);
                i:=0;
                repeat
                Sleep(500);
                Application.ProcessMessages;
                i:=i+1;
                until (catchdevice=$02) or (i=10);
                if i<>10 then begin
                s4080Final;
                BB5_ADL_RestartMCU(rb);
                end;
            end;
       $04: begin
            BB5_ADL_RestartMCU(rb);
                i:=0;
                repeat
                Sleep(500);
                Application.ProcessMessages;
                i:=i+1;
                until (catchdevice=$02) or (i=10);
                if i<>10 then begin
                BB5_ADL_RestartMCU(rb);
                end;
                Application.ProcessMessages;
                Sleep(500);
                Application.ProcessMessages;
                i:=0;
                repeat
                Application.ProcessMessages;
                Sleep(200);
                Inc(i);
                Form1.statusbar.Panels[0].Text:=IntToStr(100-i);
                Application.ProcessMessages;
                if catchdevice=$01 then i:=100
                else BB5_ADL_RestartMCU(rb);
                until (i=100) or (catchdevice=$01);
                Form1.statusbar.Panels[0].Text:='';
                Application.ProcessMessages;
                if (i=100) and (catchdevice=$02) then
                begin
                Form1._msg('Custom mode fail!');
                Form1._msg('Need reflash mcu only in DEAD mode');
                StuffFlashReset;
                result:=False;
                Exit;
                end;
            end;
       end;
      end;

     Form1.pb1.color:=clActiveBorder;

     if affenabled then Form1.afterFlashdo;

     Application.ProcessMessages;
     Sleep(200);
     Form1.TimConChk.Enabled:=true;
     Form1._msg('Done!');
      Form1.chkPPMe.Enabled:=True;
      Form1.chkMCUen.Enabled:=True;
      Form1.chkPPM1e.Enabled:=True;
      Form1.chkCNTe.Enabled:=True;
      Form1.chkAPEe.Enabled:=True;
      Form1.chkcnt3.Enabled:=True;
     Result:=true;
end;//End of Normal Mode Flashing

function  BB5_DeadFlashing(mode:integer):boolean;
var  i,j,n,k,PktLen   : integer;
     UAgent, ms,
     RAWBlock,
     RAWLoader,
     PASUB            : TmemoryStream;
     s, needSert      : String;
     Key, KeyLen      : Byte;
     PacketLen        : Byte;
     BlockCount       : Byte;
     CurrBlock        : Byte;
     CurrBlockLen     : Word;
     b, proto         : Boolean;

begin
     Result:=false;
     Form1._msg('Dead Mode is Selected');
     Form1._msg('Waiting for USB device...');
     Form1._msg('--- Press phone'+#39+'s power button or insert cable & charger! ---');
     Application.ProcessMessages;
     

     //Захват Nokia USB ROM устройства
     //Nokia USB ROM
     b:=false; i:=0;
     repeat
           if (i=2500) and (b=false) then
           begin
                Form1._msg('->  Phone not found.. :(');
                result:=False;
                Form1.SetReady;
                Exit;
           end;
           Application.ProcessMessages;
           if stop=True then
           begin
           // Stopping operation
               dostop('BOOT');
               result:=false;
               Form1.pb1.progress:=0;
               i:=2499; b:=false;
           end;
           if catchdevice=$02 then
           begin
                b:=true;
                Form1._msg('Connection opened successfully');
           end;
           Application.ProcessMessages;
           Sleep(10);
           inc(i);
           Form1.statusbar.Panels[0].Text:='Wait for phone '+inttostr(2500-i);
           Application.ProcessMessages;
     until b ;

     Application.ProcessMessages;
     Form1.statusbar.Panels[0].Text:='';
     Form1._msg('Waiting for communication response.');
     //Sleep(50);

     Application.ProcessMessages;
     if BB5_USB_BootRom_GetFirstBlock<>$60 then
     begin
          Form1.setready;
          Form1._msg('->  Error answer from BootRom');
          Form1._msg('->  1. Try make battery charge');
          Form1._msg('->  2. Try insert charger, without pressing poweron');
          Form1._msg('->  3. Try change USB port, if driver hang - restart PC');
          result:=False;
          StuffFlashReset;
          form1.BtnDisable;
          exit;
     end;
     Application.ProcessMessages;
     starttime;
     Application.ProcessMessages;
     Form1.statusbar.Panels[3].Text:='Connected';
     //Парсинг Root Hash
     Application.ProcessMessages;
     FillMemory(@RAPInfo.Root_Key_Hash,$10,$00);
     FillMemory(@RAPInfo.APErootkey,$10,$00);
     FillMemory(@RAPInfo.FlashID,$A,$00);
     FillMemory(@RAPInfo.APEFlashID,$A,$00);
     FillMemory(@RAPInfo.PublicID,$14,$00);
     FillMemory(@RAPInfo.BootID,$8,$00);
     Application.ProcessMessages;

//================================================================================================================================================================================================================================================================================
// Парсинг ответа 5800 (RM-356) на запрос BB5_USB_BootRom_GetFirstBlock
// Лог MX-кея
// RAP Data :
// SYSTEM ASIC ID: 000000010000022600010006400C192101031103 [RAPIDO3G ver: 1.x]
// EM1 ID: 00000295
// EM2 ID: 00000B22
// PUBLIC ID: 1FF0001841158B52064E64D3C3E9A7F38DC47E29
// ASIC MODE ID: 00
// ROOT KEY HASH: CAEEBB65D3C48E6DC73B49DC5063A2EE
// ROM ID: 4B9B75103E691FF8
// RAPIDOv11_2nd.fg: [BB5] version: 1.30.0 revision: 0.0 size: 0x3AC0
// Supported RAP Ids: 0003192101002003, 000C192101002003, 4003192101002003, 400C192101002003, 4003192101011103, 400C192101011103, 4003192101021103, 400C192101021103, 4003192101031103, 400C192101031103, 4003192101011105, 400C192101011105, 400C192101021105, 400C192101031105
// FlashID0: 00EC 0040  - 0040 0121 [Samsung 2Gb DDP OneNAND,2 Gbits] type: ONENAND,RAP
// ExtBUSC: 0000 0000 0000 0000 0000 0000 0000 0000
// ExtDEVC: FFFF 0000 - 0000 0000
// RAPIDOv11_algo.fg: [XSR 1.5] version: 1.35.0 revision: 0.0 size: 0x272B0
// Supported RAP Ids: 0003192101002003, 000C192101002003, 4003192101002003, 400C192101002003, 4003192101011103, 400C192101011103, 4003192101021103, 400C192101021103, 4003192101031103, 400C192101031103, 4003192101011105, 400C192101011105, 400C192101021105, 400C192101031105
// RAP PAPUBKEYS ID: 76A20187051C30162EE91C77AE5E6011F5F1BA61
//
// Ответ на запрос B5_USB_BootRom_GetFirstBlock приходит в таком виде:
// 6007011500000000010000022600010006400C1921010311030205000000029502050000000B221215001FF0
// 001841158B52064E64D3C3E9A7F38DC47E2913020000141100CAEEBB65D3C48E6DC73B49DC5063A2EE150900
// 4B9B75103E691FF8
//
// Разбираем:
// 60 - общая длина принятых данных ответа (переданных телефоном данных на запрос RootHash'a)
// 07 - количество блоков данных в ответе
// 0115 00 000000010000022600010006400C192101031103 - блок №1 ($01), его длина $15 - RAP SYSTEM ASIC ID
// 0205 00 00000295                                 - блок №2 ($02), его длина $05 - RAP EM0 ID (ну или RAP EM1 ID - кто как считает с нуля или с единицы)
// 0205 00 00000B22                                 - блок №3 ($02), его длина $05 - RAP EM1 ID (ну или RAP EM2 ID - кто как считает с нуля или с единицы)
// 1215 00 1FF0001841158B52064E64D3C3E9A7F38DC47E29 - блок №4 ($12), его длина $15 - RAP PUBLIC ID
// 1302 00 00                                       - блок №5 ($13), его длина $02 - RAP ASIC MODE ID
// 1411 00 CAEEBB65D3C48E6DC73B49DC5063A2EE         - блок №6 ($14), его длина $11 - RAP ROOT KEY HASH
// 1509 00 4B9B75103E691FF8                         - блок №7 ($15), его длина $09 - RAP ROM ID
//================================================================================================================================================================================================================================================================================

     i:=2;
     while i < Length(rxbuf) do
     begin
          Key   :=rxbuf[i];
          KeyLen:=rxbuf[i+1];
          inc(i, 2);
          case Key of
          $01:
              begin
                   for j:=$0 to KeyLen-1 do RAPInfo.FlashID[j]:= rxbuf[i+j];
                   inc(i, KeyLen);
              end;
          $12:
              begin
                   // 0A900018A8B54650B9C89AA40EEC5059B5762F38
                   inc(i);
                   for j:=0 to $13 do RAPInfo.PublicID[j]:= rxbuf[i+j];
                   inc(i, $14);
              end;
          $14: //Root Hash
              begin
                   // BAF3A9C3DBFA8454937DB77F2B8852B1
                   inc(i);
                   for j:=0 to $0F do RAPInfo.ROOT_KEY_HASH[j]:= rxbuf[i+j];
                   inc(i, $0F);
              end
              else inc(i, KeyLen);
          end;//End Of Case
     end;


    { Application.ProcessMessages;
     PacketLen  :=rxbuf[0];//длина принятого пакета данных
     BlockCount :=rxbuf[1];//количество блоков

     i:=2;//текущий байт в пакете данных
     j:=0;//текущий номер блока
     while (i<PacketLen) and (j<BlockCount) do
     begin
          CurrBlock    :=rxbuf[i];
          inc(i);
          CurrBlockLen := HexToInt(IntToHex(buf[i], 2)+IntToHex(buf[i+1], 2));
          inc(i);
          case CurrBlock of
          $01://RAP SYSTEM ASIC ID
              //5800 - 000000010000022600010006400C192101031103 [RAPIDO3G ver: 1.x]
              begin
                   for k:=0 to CurrBlockLen do RAPInfo.SYSTEM_ASIC_ID[i+k]:= rxbuf[i+k];
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          $02://RAP EMx ID
              //00000295
              //00000B22
              begin
                   if CurrBlockLen=5 then
                   for k:=0 to CurrBlockLen-1 do RAPInfo.EMx_ID[k]:= rxbuf[i+k];
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          $12://PUBLIC_ID
              //1FF0001841158B52064E64D3C3E9A7F38DC47E29
              begin
                   for k:=0 to CurrBlockLen do RAPInfo.PUBLIC_ID[i+k]:= rxbuf[i+k];
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          $13://ASIC_MODE
              //00
              begin
                   if CurrBlockLen=2 then
                   RAPInfo.ASIC_MODE:= rxbuf[i];
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          $14://ROOT_KEY_HASH
              //CAEEBB65D3C48E6DC73B49DC5063A2EE
              begin
                   for k:=0 to CurrBlockLen do RAPInfo.ROOT_KEY_HASH[i+k]:= rxbuf[i+k];
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          $15://ROM_ID
              //4B9B75103E691FF8
              begin
                   for k:=0 to CurrBlockLen do RAPInfo.ROM_ID[i+k]:= rxbuf[i+k];
                   inc(i, CurrBlockLen);
                   inc(j);
              end
              else
              begin
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          end;//End Of Case
     end;  }

     j:=0;
     //Проверка на пустой RootHash
     for i := 0 to $0F do inc(j, RAPInfo.Root_Key_Hash[i]);
     if j=0 then
     begin
          Form1.setready;
          Form1._msg('->  No RootKeyHash Asic CMT. (IMEI DAMAGED?) Unable to continue flashing');
          exit;
     end;

   Application.ProcessMessages;
         // Form1._msg('RAP_BOOT:  '+ BufToHexStr(@RAPInfo.BootID[0],      Length(RAPInfo.BootID)));
          Form1._msg('RAP_PUB:   '+ BufToHexStr(@RAPInfo.PublicID[0],    Length(RAPInfo.PublicID)));
          Form1._msg('CMT_ROOT:  '+ BufToHexStr(@RAPInfo.ROOT_KEY_HASH[0], Length(RAPInfo.ROOT_KEY_HASH)));
        //  Form1._msg('RAP_PAPUB: '+ BufToHexStr(@RAPInfo.PAPUBKEYSID[0], Length(RAPInfo.PAPUBKEYSID)));
      Application.ProcessMessages;

     //Извлечение RAW-Block
     RAWBlock:=TmemoryStream.Create;
     BB5_ExtractBlockOfRAWLoader(core, RAWBlock, b);

     if Not b then
     begin
          Form1.setready;
          Form1._msg('Error extracting RAW-loader');
          RAWBlock.Free;
          StuffFlashReset;
          exit;
     end;
   // RAWBlock.SaveToFile('C:\Extract_RAW_Loader_from_'+ExtractFileName(core)+'.bin');

     //Извлечение и патчинг RAW-loader'a
     RAWLoader:=TmemoryStream.Create;
     BB5_ExtractRAWLoader(RAWBlock, RAWLoader, b);

     if Not b then
     begin
          Form1.setready;
          Form1._msg('Error Patching RAW-loader');
          RAWLoader.Free;
          RAWBlock.Free;
          StuffFlashReset;
          exit;
     end;
     Form1._msg('PatchRAWLoader: Patched OK');
     //RAWLoader.SaveToFile('C:\RAW_Cert_Patch.bin');
     //RAWLoader.Clear;

     //Извлечение Апдейт Агента
     UAgent:=TmemoryStream.Create;
     BB5_ExtractCertData(core, 'UPDAPP', UAgent, b, false);

     if Not b then
     begin
          Form1.pb1.Progress:=0;
          Form1._msg('Error Extracting UAgent ... (((');
          Form1.setready;
          UAgent.Free;
          RAWLoader.Free;
          RAWBlock.Free;
          StuffFlashReset;
          exit;
     end;
     //UAgent.SaveToFile('C:\Extract_UA_from_'+ExtractFileName(core)+'.bin');

     //Извлечение PASUB-серта
     PASUB:=TmemoryStream.Create;
     BB5_ExtractCertData(core, 'PASUBTOC', PASUB, b, false);

     if Not b then
     begin
          Form1.setready;
          Form1._msg('Error extracting PASUB sert');
          PASUB.Free;
          UAgent.Free;
          RAWLoader.Free;
          RAWBlock.Free;
          exit;
     end;
     //PASUB.SaveToFile('C:\Extract_PASUBTOC_from_'+ExtractFileName(core)+'.bin');
     //ms:=TMemoryStream.Create;
     Form1.statusbar.Panels[4].Text:='Sending Boot';
     msgid:=$10;
{================================== SEND RAW LOADER ===================================}
     Application.processmessages;
     RAWLoader.Seek(0, sofrombeginning);
     b:=true; PktLen:=$1000; k:=1;
     txBuf[0]:=$40;
     txBuf[1]:=$57;
     txBuf[2]:=$01;
     txBuf[3]:=$00;
     txBuf[4]:=$00;
     txBuf[5]:=$00;
     Form1.pb1.Progress:=0;
     Form1.pb1.MaxValue:=100;
     Form1._msg('Processing RAWLOADER...');
     while (RAWLoader.position<RAWLoader.Size) and b do
     begin
          if ((RAWLoader.Size-RAWLoader.position)<PktLen) and b then //длина последнего кусочка
          begin
               b:=false;
               PktLen:=RAWLoader.Size-RAWLoader.position;//последний кусочек лоадера
               txBuf[2]:=$00;
               txBuf[6]:=PktLen mod $100;
               txBuf[7]:=PktLen div $100;
          end;
         // Form1._msg('Sending Raw-loader: '+inttohex(PktLen, 4));

          txBuf[6]:=PktLen mod $100;
          txBuf[7]:=PktLen div $100;
          RAWLoader.ReadBuffer(txBuf[8], PktLen);

          //ms.WriteBuffer(txBuf[8], PktLen);
          //ms.SaveToFile('C:\RAW\'+Int2Digs(k,4)+'_BEST.bin');
          //ms.Clear;
          inc(k);

          if not USBControlPacket($222040, $8+PktLen, 0) then begin
          Form1._msg('->  Error while send data to phone!');
          Form1._msg('    Check battery, connection. Try again');
          result:=False;
          PASUB.Free;
          UAgent.Free;
          RAWLoader.Free;
          RAWBlock.Free;
          StuffFlashReset;
          Exit;
          end;
          Application.ProcessMessages;
          Form1.pb1.Progress:=(RAWLoader.Position*100) div RAWLoader.Size;
     end;

{================================== SEND UA ===========================================}
     Application.processmessages;
     UAgent.Seek(0, sofrombeginning);
     b:=true; PktLen:=$1000; k:=1;
     txBuf[0]:=$40;
     txBuf[1]:=$5c;
     txBuf[2]:=$01;
     txBuf[3]:=$00;
     txBuf[4]:=$00;
     txBuf[5]:=$00;
     Form1.pb1.Progress:=0;
     Form1.pb1.MaxValue:=100;
      Form1._msg('Processing UPDAPP...');
     while (UAgent.position<UAgent.Size) and b do
     begin
          if ((UAgent.Size-UAgent.position)<PktLen) and b then //длина последнего кусочка
          begin
               b:=false;
               PktLen:=UAgent.Size-UAgent.position;//последний кусочек агента
               txBuf[2]:=$00;
               txBuf[6]:=PktLen mod $100;
               txBuf[7]:=PktLen div $100;
          end;
          //Form1._msg('Sending Update Agent: '+inttohex(PktLen, 4));

          txBuf[6]:=PktLen mod $100;
          txBuf[7]:=PktLen div $100;
          UAgent.ReadBuffer(txBuf[8], PktLen);

          //ms.WriteBuffer(txBuf[8], PktLen);
          //ms.SaveToFile('C:\UA\'+Int2Digs(k,4)+'_BEST.bin');
          //ms.Clear;
          inc(k);

          if not USBControlPacket($222040, $8+PktLen, 0) then begin
          Form1._msg('->  Error while send data to phone!');
          Form1._msg('    Check battery, connection. Try again');
          result:=False;
          PASUB.Free;
          UAgent.Free;
          RAWLoader.Free;
          RAWBlock.Free;
          StuffFlashReset;
          Exit;
          end;
          Application.ProcessMessages;
          Form1.pb1.Progress:=(UAgent.Position*100) div UAgent.Size;
     end;

{================================== SEND PASUBTOC = ===================================}
     Application.processmessages;
     PASUB.Seek(0, sofrombeginning);
     b:=true; PktLen:=$1000; k:=1;
     txBuf[0]:=$40;
     txBuf[1]:=$5D;
     txBuf[2]:=$01;
     txBuf[3]:=$00;
     txBuf[4]:=$00;
     txBuf[5]:=$00;
     Form1.pb1.Progress:=0;
     Form1.pb1.MaxValue:=100;
     Form1._msg('Processing PASUBTOC...');
     while (PASUB.position<PASUB.Size) and b do
     begin
          if ((PASUB.Size-PASUB.position)<PktLen) and b then //длина последнего кусочка
          begin
               b:=false;
               PktLen:=PASUB.Size-PASUB.position;//последний кусочек серта
               txBuf[2]:=$00;
               txBuf[6]:=PktLen mod $100;
               txBuf[7]:=PktLen div $100;
          end;
        //  Form1._msg('Sending PASUBTOC-Cert: '+inttohex(PktLen, 4));

          txBuf[6]:=PktLen mod $100;
          txBuf[7]:=PktLen div $100;
          PASUB.ReadBuffer(txBuf[8], PktLen);

          //ms.WriteBuffer(txBuf[8], PktLen);
          //ms.SaveToFile('C:\PASUB\'+Int2Digs(k,4)+'_BEST.bin');
          //ms.Clear;
          inc(k);

         if not  USBControlPacket($222040, $8+PktLen, 0) then begin
          Form1._msg('->  Error while send data to phone!');
          Form1._msg('    Check battery, connection. Try again');
          result:=False;
          PASUB.Free;
          UAgent.Free;
          RAWLoader.Free;
          RAWBlock.Free;
          StuffFlashReset;
          Exit;
          end;
          Application.ProcessMessages;
          Form1.pb1.Progress:=(PASUB.Position*100) div PASUB.Size;
     end;
{======================================================================================}
     PASUB.Free;
     UAgent.Free;
     RAWLoader.Free;
     RAWBlock.Free;
     Application.ProcessMessages;
     form1.pb1.progress:=0;
     Application.ProcessMessages;
     endtimecount;
     form1._msg('TIME : Boot time : '+showtime(tmsres));
     Application.ProcessMessages;
     i:=0;
      repeat
      begin
      Sleep(100);
      Inc(i);
      Application.ProcessMessages;
      end;
      until (DevPresent=False) or (i=150) or (catchdevice=$02);
     case mode of
     0:
      begin
      if i=150 then b:=false   else b:=BB5_Flashing;
      Form1.statusbar.Panels[4].Text:='';
      Application.ProcessMessages;
      Result:=b;
      end;
      1:
      begin
      if i=150 then b:=false   else b:=true;
      Form1.statusbar.Panels[4].Text:='';
      Application.ProcessMessages;
      result:=b;
      end;
     end;

end;//End of Dead Mode

function BB5_EraseFile(core: string):boolean;
var
     fs                         : TFileStream;
     buf                        : array[0..$FFFF] of byte;
     n,j                        : Integer;
     HdrLen                     : Integer;
     HdrPos                     : LongInt;
     CurrSeem                   : Byte;
     CurrSeemLen,CurrEraseLen,
     CurSeemcount               : Integer;
     EraseStart, EraseStop      : array[0..$FF] of LongInt;
     EraseCnt                   : Integer;
     FlashCFG,Byte1,Byte2,Byte3 : Byte;
     streamlen, ms              : TMemoryStream;
     loaderlen                  : DWORD;
     partitionlen, pcfg         : Byte;
     fullerase                  : Integer;
     partLen                    : integer;
     erase                      : Boolean;
     b                          : Byte;
begin
     Result:=false;
     partition:=false;
     partLen:=0;
     erase:=False;
     Form1.pb1.Progress:=0;
     Form1.pbsm1.Progress:=0;
     Form1._msg('Erase : Processing '+ExtractFileName(core));
     Application.processmessages;
     Form1.statusbar.Panels[1].text:='';
     Form1.pb1.ForeColor:=clYellow;
     Form1.pb1.progress:=0;
     Application.ProcessMessages;
     fs:=TFileStream.Create(core,fmOpenRead);
     fs.Seek(0, sofromBeginning);
     fs.Read(b,1);
     if b<>$B2 then
     begin
          Form1._msg('Erase: Invalid Image File');
          USBClosePort;
          fs.Free;
          exit;
     end;

     fs.ReadBuffer(buf[0], 4);//Длина Flash Header
     HdrLen := HexToInt(IntToHex(buf[0], 2)+IntToHex(buf[1], 2)+IntToHex(buf[2], 2)+IntToHex(buf[3], 2));
     fs.Seek(4,soFromCurrent);
     Application.ProcessMessages;
     starttime;
     Application.ProcessMessages;
 try
     while fs.Position<(HdrLen) do
     begin
          fs.ReadBuffer(CurrSeem, 1);
           case CurrSeem of
          $E4:
          begin
             //   Form1._msg('SEEM: E4');
               fs.ReadBuffer(buf[0], 2);
               CurrSeemLen:=(buf[0]*$100)+buf[1];
               fs.Seek(CurrSeemLen, sofromCurrent);
          end;
          $E5:
          begin
             //   Form1._msg('SEEM: E5');
               fs.ReadBuffer(buf[0], 2);
               CurrSeemLen:=(buf[0]*$100)+buf[1];
               fs.Seek(CurrSeemLen, sofromCurrent);
          end;
          $EA:
          begin
              //  Form1._msg('SEEM: EA');
               fs.ReadBuffer(buf[0], 2);
               CurrSeemLen:=(buf[0]*$100)+buf[1];
               fs.Seek(CurrSeemLen, sofromCurrent);
          end;
          $EE:
          begin
              partition:=True;
              partitionstream:=TmemoryStream.Create;
             // Form1._msg('SEEM: EE');
               fs.ReadBuffer(buf[0], 2);
               CurrSeemLen:=(buf[0]*$100)+buf[1];
               partLen:=currseemlen;
               //fs.Seek(CurrSeemLen, sofromCurrent);
              partitionstream.copyFrom(fs,CurrSeemlen);
             /// ms.SaveToFile('C:\partition.bin');
              Application.ProcessMessages;
          end;
          $F3:
          begin
              //  Form1._msg('SEEM: F3');
               fs.ReadBuffer(buf[0], 2);
               CurrSeemLen:=(buf[0]*$100)+buf[1];
               fs.Seek(CurrSeemLen, sofromCurrent);
          end;
          $FA: begin
             // Form1._msg('SEEM: FA');
              streamlen:=TmemoryStream.Create;
              streamlen.CopyFrom(fs,$E);  // создавал поток, потому что иначе пока не умею
              streamlen.Seek(1, sofromBeginning); // пропускаем один байт
              streamlen.ReadBuffer(loaderlen,4); // читаем длину - это длина всего адресного пространства блока FA, которое занимает апдейт апп, сразу после блока длины.
              dwordswap(@loaderlen); // разворачиваем
              fs.seek(loaderlen-9,sofromcurrent); // меняем позицию - после идут старые добрые С8
              Application.ProcessMessages;
              streamlen.Free;
              end;
           $C8:
               begin
                   erase:=True;
                   fs.ReadBuffer(buf[0], 1);
                   CurrSeemLen:=buf[0];
                   fs.ReadBuffer(CurSeemcount, 1);
                    //Form1._msg('');
                   // Form1._msg('Found '+IntToStr(CurrSeemLen)+' flash chips to erase');

                    for n:=1 to CurSeemcount do
                  begin
                      //form1._msg(IntToStr(fs.Position));
                    fs.ReadBuffer(currseem,1);
                    case currseem  of
                       $12:
                       begin
                         FlashCfg:=$12;
                         fs.ReadBuffer(CurrEraseLen, 1);
                         Dec(CurrEraseLen, 3);

                         fs.ReadBuffer(Byte1, 1);
                         fs.ReadBuffer(Byte2, 1);
                         fs.ReadBuffer(Byte3, 1);

                         EraseCnt:=CurrEraseLen div 8;

                         Form1._msg('Found '+IntToStr(EraseCnt)+' areas to erase');
                         fs.ReadBuffer(buf[0], CurrEraseLen);

                         if byte2=$00 then begin
                         Application.ProcessMessages;
                         fullerase:=0;
                         for j:=0 to EraseCnt-1 do
                         begin
                         EraseStart[n] := HexToInt(IntToHex(buf[j*8], 2)+IntToHex(buf[j*8+1], 2)+IntToHex(buf[j*8+2], 2)+IntToHex(buf[j*8+3], 2));
                         EraseStop[n] := HexToInt(IntToHex(buf[j*8+4], 2)+IntToHex(buf[j*8+5], 2)+IntToHex(buf[j*8+6], 2)+IntToHex(buf[j*8+7], 2));
                         fullErase:=fullerase+(EraseStop[n]-EraseStart[n]);
                         end;
                         Form1.pb1.MaxValue:=fullerase div $54000;
                         Application.ProcessMessages;
                         end;


                         for j:=0 to EraseCnt-1 do
                         begin
                              Form1.statusbar.Panels[0].Text:='';
                              Form1.statusbar.Panels[1].Text:='';
                              EraseStart[n] := HexToInt(IntToHex(buf[j*8], 2)+IntToHex(buf[j*8+1], 2)+IntToHex(buf[j*8+2], 2)+IntToHex(buf[j*8+3], 2));
                              EraseStop[n] := HexToInt(IntToHex(buf[j*8+4], 2)+IntToHex(buf[j*8+5], 2)+IntToHex(buf[j*8+6], 2)+IntToHex(buf[j*8+7], 2));
                              Form1.statusbar.Panels[0].Text:='Erase Area: '+  IntToStr(j+1);
                              // Form1._msg('Erase Area: '+  IntToStr(j+1) + ' EraseStart: ' + inttohex(EraseStart[n],8) + ' EraseStop: ' + inttohex(EraseStop[n], 8));
                              //if not BB5_EraseSegment(EraseStart[n], EraseStop[n], FlashCfg, Byte1, Byte2, Byte3) then
                              //raise E.Create('Erasure error, Area: '+IntToStr(n));

                              case byte2 of
                              $00:
                              begin
                              if not BB5_EraseAreaSmallBlock(EraseStart[n], EraseStop[n], FlashCfg, Byte1, Byte2, Byte3) then
                              raise E.Create('Erasure error, Area: '+IntToStr(n));
                              end;
                              $01:
                              begin
                              if not BB5_EraseArea(EraseStart[n], EraseStop[n], FlashCfg, Byte1, Byte2, Byte3) then
                              raise E.Create('Erasure error, Area: '+IntToStr(n));
                              Form1.pb1.progress:=Form1.pb1.progress+10;
                              end;
                              $03:
                              begin
                              if not BB5_EraseArea(EraseStart[n], EraseStop[n], FlashCfg, Byte1, Byte2, Byte3) then
                              raise E.Create('Erasure error, Area: '+IntToStr(n));
                              Form1.pb1.progress:=Form1.pb1.progress+10;
                              end;
                             end;

                         Application.ProcessMessages;
                         end;
                         Form1.statusbar.Panels[0].Text:='';
                         Form1.statusbar.Panels[1].Text:='';
                        // Form1._msg('');
                       end;
                       $19:
                      begin
                        fs.ReadBuffer(partitionlen,1);
                        fs.readbuffer(pcfg,1);
                        ////1B 00 10 6F 00 2E 00 14 06 92
                        txBuf[0]:=$1B;
                        txBuf[1]:=$00;
                        txBuf[2]:=$10;
                        txBuf[3]:=$6F;
                        txBuf[4]:=$00;
                        txBuf[5]:=partitionlen-1;
                        txBuf[6]:=$00;
                        txBuf[7]:=$15;
                        txBuf[8]:=ISIHeaderTransId;
                        txBuf[9]:=$92;
                        fs.ReadBuffer(txBuf[10], partitionlen-4);
                       case adlmode of
                       $80:
                        begin
                        Form1._msg('Erase partition 0x'+byte2str(txbuf[23]));
                        //Form1._msg(BufToHexStr(@txbuf[0],partitionlen+5));
                        usbbulkWriteport(@txbuf[0], partitionlen+5);
                          if usbbulkreadport($ffff) then begin
                          //form1._msg(buftohexstr(@rxbuf[0], length(rxbuf)));
                          if (rxBuf[9]=$93) and (rxBuf[10]=0) and (rxBuf[11]=0 ) then
                          begin
                          Form1._msg('Partition erase Ok');
                          end
                          else
                          begin
                          if rxBuf[10]=$22 then Form1._msg('Partition erase [Ok]') else Form1._msg('Partition erase [Minor]')
                          end;
                         end
                         else Form1._msg('Partition erase [Failed]');
                        end;
                       $06:
                        begin
                        Form1._msg('Partition erase not allowed by loader');
                        Application.ProcessMessages;
                        end;
                       end;
                       Application.ProcessMessages;
                       fs.ReadBuffer(txBuf[0],3);
                      // form1._msg('afPos : '+IntToStr(fs.Position));
                      end;
                    end;
                  end;

                   if partition=True
                   then
                   begin
                   RebuildPartition(partitionstream,partLen);
                   partitionstream.Free;
                   partition:=false;
                   Application.ProcessMessages;
                   end;
                   
                    Result:=True;
                    Application.ProcessMessages;
                    endtimecount;
                    Form1._msg('TIME : Erase time : '+showtime(tmsres));
                    Application.ProcessMessages;
                    Form1.pbsm1.Progress:=0;
                    fs.Free;
                    exit;
                   // fs.Seek(HdrLen, sofromBeginning);
               end
          else
          begin
            //Form1._msg('SEEM : '+byte2str(currseem));
              fs.ReadBuffer(buf[0], 1);
               CurrSeemLen:=buf[0];
               fs.readbuffer(buf[0],CurrSeemLen);
             //  form1._msg(buftohexstr(@buf[0], currseemlen));
             //  if CurrSeemLen<1 then fs.ReadBuffer(CurrSeemLen, 1);
               application.ProcessMessages;
          end;
          end;
     end;
       if erase=False then
       begin
        result:=True;
        Form1._msg('Erase : No any region, skip erase');
       end;
     fs.Free;
 except
        on E:Exception do
        begin
             fs.Free;
             Form1._msg('EraseFile: Error: '+E.Message);
        end;
 end;
Application.ProcessMessages;
endtimecount;
Form1._msg('TIME : Erase time : '+showtime(tmsres));
Application.ProcessMessages;
fullerase:=0;
Form1.pb1.MaxValue:=100;
Form1.pb1.Progress:=0;
end;

function BB5_EraseArea(Start, arStop: LongInt; FlashCfg,Byte1,Byte2,Byte3:byte):boolean;
var
     n                    : Integer;
     FlashType, Subsystem : String;
begin
     Result:=False;

     case Byte1 of
     $00: Subsystem:='CMT';
     $01: Subsystem:='APE';
     else Subsystem:='Unknown ('+IntToStr(Byte1)+')';
     end;

     case Byte2 of
     $00: FlashType:='NOR';
     $03: FlashType:='NAND';
     $01: FlashType:='NAND';
     else FlashType:='Unknown ('+IntToStr(Byte2)+')';
     end;

     case byte1 of
     0: begin
     //Transanc.Id
     Erase[3] := $6F;
     Erase[7] := msgid;
     Erase[8] := ISIHeaderTransId;
     Erase[9] := $42;
     //Config
     Erase[10] := Byte1;
     Erase[11] := $01;
     Erase[12] := FlashCFG;
     Erase[13] := $0c;
     Erase[14] := Byte2;
     Erase[15] := Byte3;
       end;
     1: begin
     //APE try
     Erase[3] := $21;
     Erase[7] := msgid;
     Erase[8] := ISIHeaderTransId;
     Erase[9] := $42;
     //Config
     Erase[10] := $00;
     Erase[11] := $01;
     Erase[12] := FlashCFG;
     Erase[13] := $0c;
     Erase[14] := Byte2;
     Erase[15] := Byte3;
     end;

     end;
     //Begin Block
     Erase[16] := Start div $1000000;
     Erase[17] := Start div $10000;
     Erase[18] := Start div $100;
     Erase[19] := Start mod $100;
     //End Block
     Erase[20] := arStop div $1000000;
     Erase[21] := arStop div $10000;
     Erase[22] := arStop div $100;
     Erase[23] := arStop mod $100;
     ///
     if stop=True then
     begin
     dostop('ERASE');
     result:=false;
     Exit;
     end;

     ///


     Form1._msg('Erasing area 0x'+IntToHex(Start,8)+' - 0x'+IntToHex(arStop, 8)+
                ', '+FlashType+', '+Subsystem);
     Application.processmessages;

     n:=USBBulkWritePort(@Erase[0], Length(Erase));
     if n<>24 then begin Form1._msg('Erase : ERR1 : connection lost or data missmatch'); exit; end;
     if Not USBBulkReadPort(16) or (Length(rxBuf)<16) then  begin Form1._msg('Erase : ERR1 : connection lost or data missmatch'); exit; end;

     Application.processmessages;
     if rxBuf[8]<>Erase[8] then exit; //целостность транзанкций

     if Word((@rxBuf[14])^)=$00 then
     Form1._msg('Result: '+IntToHex(Word((@rxBuf[14])^), 4));

     Result:=True;
end;

function BB5_EraseAreaSmallBlock(Start, arStop: LongInt; FlashCfg,Byte1,Byte2,Byte3:byte):boolean;
var
     n, PktLen            : Integer;
     FlashType, Subsystem : String;
     b, k                 : Boolean;
begin
     Result:=False;
     b:=true; k:=true; PktLen:=$54000;
     case Byte1 of
     $00: Subsystem:='CMT';
     $01: Subsystem:='APE';
     else Subsystem:='Unknown ('+IntToStr(Byte1)+')';
     end;

     case Byte2 of
     $00: FlashType:='NOR';
     $03: FlashType:='NAND';
     $01: FlashType:='NAND';
     else FlashType:='Unknown ('+IntToStr(Byte2)+')';
     end;

     case byte1 of
     0: begin
     //Transanc.Id
     Erase[3] := $6F;
     Erase[7] := msgid;
     Erase[8] := ISIHeaderTransId;
     Erase[9] := $42;
     //Config
     Erase[10] := Byte1;
     Erase[11] := $01;
     Erase[12] := FlashCFG;
     Erase[13] := $0c;
     Erase[14] := Byte2;
     Erase[15] := Byte3;
       end;
     1: begin
     //APE try
     Erase[3] := $21;
     Erase[7] := msgid;
     Erase[8] := ISIHeaderTransId;
     Erase[9] := $42;
     //Config
     Erase[10] := $00;
     Erase[11] := $01;
     Erase[12] := FlashCFG;
     Erase[13] := $0c;
     Erase[14] := Byte2;
     Erase[15] := Byte3;
     end;
     end;

     Form1._msg('Erasing area 0x'+IntToHex(Start,8)+' - 0x'+IntToHex(arStop, 8)+
                ', '+FlashType+', '+Subsystem);
     while (Start<arStop) and b do
     begin
               if stop=True then
               begin
               dostop('ERASE');
               k:=false;
               b:=False;
               continue;
               end;

          if ((arStop-Start)<PktLen) and b then //длина последнего кусочка
          begin
               b:=false;
               PktLen:=arStop-Start;//последний кусочек лоадера
          end;

          //Begin Block
          Erase[16] := Start div $1000000;
          Erase[17] := Start div $10000;
          Erase[18] := Start div $100;
          Erase[19] := Start mod $100;
          //End Block
          Erase[20] := (Start+PktLen) div $1000000;
          Erase[21] := (Start+PktLen) div $10000;
          Erase[22] := (Start+PktLen) div $100;
          Erase[23] := (Start+PktLen) mod $100;

          Form1.statusbar.Panels[1].Text:='0x'+IntToHex(Start, 4)+' - 0x'+IntToHex(arStop, 4);
          Application.processmessages;

          n:=USBBulkWritePort(@Erase[0], Length(Erase));
          if n<>24 then begin Form1._msg('Erase : ERR1 : connection lost or data missmatch'); exit; end;
          if Not USBBulkReadPort(16) or (Length(rxBuf)<16) then begin Form1._msg('Erase : ERR1 : connection lost or data missmatch'); exit; end;

          Application.processmessages;
          if rxBuf[8]<>Erase[8] then exit; //целостность транзанкций

          if Word((@rxBuf[14])^)<>$00 then
          begin
               k:=false;
               b:=false;
               continue;
          end;
          Application.ProcessMessages;
          Form1.pb1.Progress:=Form1.pb1.progress+1;
          Start:=Start+PktLen;
     end;
     if k then Form1._msg('Result: '+IntToHex(Word((@rxBuf[14])^), 4)) else
               Form1._msg('Error Eraising Area: 0x'+IntToHex(Start, 4)+' - 0x'+IntToHex(arStop, 4));
     Result:=k;
end;

function BB5_EraseSegment(startSegment, stopSegment: LongInt; FlashCfg,Byte1,Byte2,Byte3:byte):boolean;
var
     SectorsToErase,i    : integer;
     CurrentSector       : LongInt;
     CurrEraseSize       : LongInt;
     FlashType,Subsystem : string;
begin
     Result:=False;
     SectorsToErase:=(StopSegment-StartSegment) div BB5_EraseSectorSize;
     if ((StopSegment-StartSegment) mod BB5_EraseSectorSize) > 0 then inc(SectorsToErase);

     case Byte1 of
     $00: Subsystem:='CMT';
     $01: Subsystem:='APE';
     else Subsystem:='Unknown ('+IntToStr(Byte1)+')';
     end;

     case Byte2 of
     $00: FlashType:='NOR';
     $03: FlashType:='NAND';
     $01: FlashType:='NAND';
     else FlashType:='Unknown ('+IntToStr(Byte2)+')';
     end;

     //Form1._msg('Erasing area 0x'+IntToHex(StartSegment,8)+' - 0x'+IntToHex(StopSegment,8)+', Type: '+FlashType+', Subsystem: '+Subsystem);
     Application.processmessages;
     StopSegment   :=StopSegment+1;
     CurrentSector :=StartSegment;
     CurrEraseSize :=BB5_EraseSectorSize;

     for i:=0 to SectorsToErase-1 do
     begin
          if ((i=SectorsToErase-1) and (((StopSegment-StartSegment) mod BB5_EraseSectorSize) > 0)) then
          CurrEraseSize:=((StopSegment-StartSegment) mod BB5_EraseSectorSize);

          if not BB5_EraseSector(CurrentSector, CurrEraseSize, FlashCfg, Byte1, Byte2, Byte3) then exit;
          CurrentSector:=CurrentSector+CurrEraseSize;

          Application.ProcessMessages;
     end;
     Result:=True;
end;

function BB5_EraseSector(startSector,EraseSectorSize:LongInt; FlashCfg,Byte1,Byte2,Byte3:byte):boolean;
var
     n: integer;
     str:string;
begin
     Result:=False;
     Application.ProcessMessages;

     {Erase    : array[0..23] of Byte =
     ($1B, $00, $10, $6F, $00, $12, $00, $16, $00, $42, $00, $01, $00, $0C, $00, $00, $00, $00, $00, $C0, $00, $00, $00, $00);}

     case byte1 of
     0: begin
     //Transanc.Id
     Erase[3] := $6F;
     Erase[7] := msgid;
     Erase[8] := ISIHeaderTransId;
     Erase[9] := $42;
     //Config
     Erase[10] := Byte1;
     Erase[11] := $01;
     Erase[12] := FlashCFG;
     Erase[13] := $0c;
     Erase[14] := Byte2;
     Erase[15] := Byte3;
       end;
     1: begin
     //APE try
     Erase[3] := $21;
     Erase[7] := msgid;
     Erase[8] := ISIHeaderTransId;
     Erase[9] := $42;
     //Config
     Erase[10] := $00;
     Erase[11] := $01;
     Erase[12] := FlashCFG;
     Erase[13] := $0c;
     Erase[14] := Byte2;
     Erase[15] := Byte3;
     end;
     end;

     //Begin Block
     Erase[16] := StartSector div $1000000;
     Erase[17] := StartSector div $10000;
     Erase[18] := StartSector div $100;
     Erase[19] := StartSector mod $100;

     StartSector:=StartSector+(EraseSectorSize-1);

     //End Block
     Erase[20] := StartSector div $1000000;
     Erase[21] := StartSector div $10000;
     Erase[22] := StartSector div $100;
     Erase[23] := StartSector mod $100;

     n:=USBBulkWritePort(@Erase[0], Length(Erase));
     if n<>24 then begin Form1._msg('Erase : ERR1 : connection lost or data missmatch'); exit; end;
     if Not USBBulkReadPort(16) or (Length(rxBuf)<16) then begin Form1._msg('Erase : ERR1 : connection lost or data missmatch'); exit; end;
     if rxBuf[8]<>txBuf[8] then exit; //целостность транзанкций
     if rxBuf[15]<>$00 then exit;

     str:=BufToHex_Str(@Erase, Length(Erase));
     Form1._msg(str);

     Result:=True;
end;

function BB5_WriteFile(core: string):boolean;
const
     Write_Split : word = $FDE8;
var
     buf                :array[0..$3FFFF] of byte;
     EntryPoint,
     DataLen,
     TargetOffset,
     CRCTmp             : LongInt;
     i, n, Blocks,
     Packets,icl,
     CurrPacketSize     : Integer;
     cf1,cf2,cf3,apeb   : byte;
     good               : Integer;
     CertName,AsicType  : String;
     PAPUB_Already,
     APE_PAPUB          : boolean;
     fs                 : TFileStream;
     writen             : Dword;
     cmtcount,cmtdin,apedin,
     apecount,TokenType,
     unk                : integer;
     partitionbuf       : boolean;
     partitioncheck     : Boolean;
begin
     Result:=False;
     Form1._msg('Write : Processing '+ExtractFileName(core));
     fs:=TFileStream.Create(core,fmOpenRead);
     fs.Seek(0, sofromBeginning);
     Blocks:=0;
     cmtcount:=0; cmtdin:=0;
     apecount:=0; apedin:=0;
     unk:=0;
     Form1.pb1.ForeColor:=clGreen;
     Form1.pb1.progress:=0;
     Application.ProcessMessages;
     partitionbuf:=false;
     //if pos('_blank_504KB_pmm_10.fpsx',core)<>0 then partitioncheck:=false else partitioncheck:=true;
     //Application.ProcessMessages;
     //if partitioncheck=false then form1._msg('Blank_PMM detected, blank flashing enabled...');
     Application.ProcessMessages;
try
     fs.Read(i,1);
     if i<>$B2 then raise E.Create('Write : Bad image file');
     fs.ReadBuffer(buf[0], 4);//Длина Flash Header
     DataLen := HexToInt(IntToHex(buf[0], 2)+IntToHex(buf[1], 2)+IntToHex(buf[2], 2)+IntToHex(buf[3], 2));
     fs.Seek(DataLen,soFromCurrent);
     EntryPoint := fs.Position;
     //Form1._msg('Counting data+cert blocks...');
     starttime;
     Application.ProcessMessages;
     while fs.Position<fs.Size do
     begin
               if stop=True then
               begin
               dostop('WRITE');
               result:=false;
               Form1.pb1.progress:=0;
               Form1.pb1.MaxValue:=100;
               fs.Free;
               Exit;
               end;
          fs.ReadBuffer(buf[0], 1);
          if (buf[0]<>$54) and (buf[0]<>$5D) then
          raise E.Create('Write : Bad image file, Corrupted Data/Cert blocks!' );
          case buf[0] of
          $54://Phoenix-token
          begin
               fs.ReadBuffer(buf[0], $3);
               case buf[1] of
               $17 : begin
                     fs.ReadBuffer(buf[0], buf[2]+1);
                     DataLen := HexToInt(IntToHex(buf[6], 2)+IntToHex(buf[7], 2)+IntToHex(buf[8], 2)+IntToHex(buf[9], 2));
                     TokenType := buf[0];
                      case tokentype of
                      0:Inc(cmtcount);
                      1:Inc(apecount);
                      else inc(unk);
                       end;
                     //Form1._msg(inttohex(buf[0],2)+inttohex(buf[1],2));
                     fs.Seek(DataLen,soFromCurrent);
                     inc(blocks);
                     continue;
                     end;
               $2E : begin
                     fs.ReadBuffer(buf[0], buf[2]+1);
                     DataLen := HexToInt(IntToHex(buf[17], 2)+IntToHex(buf[18], 2)+IntToHex(buf[19], 2)+IntToHex(buf[20], 2));
                     TokenType := buf[0];
                      case tokentype of
                      0:Inc(cmtcount);
                      1:Inc(apecount);
                      else inc(unk);
                       end;
                     // Form1._msg(inttohex(buf[0],2)+inttohex(buf[1],2));
                     fs.Seek(DataLen,soFromCurrent);
                     inc(blocks);
                     continue;
                     end;
               $30 : begin
                     Application.ProcessMessages;
                     fs.ReadBuffer(buf[0], buf[2]+1);
                     DataLen := HexToInt(IntToHex(buf[13], 2)+IntToHex(buf[14], 2)+IntToHex(buf[15], 2)+IntToHex(buf[16], 2));
                     TokenType := buf[0];
                      case tokentype of
                      0:Inc(cmtcount);
                      1:Inc(apecount);
                      else inc(unk);
                       end;
                     // Form1._msg(inttohex(buf[0],2)+inttohex(buf[1],2));
                     fs.Seek(DataLen,soFromCurrent);
                     inc(blocks);
                     continue;
                     end;
               else
                     begin
                     fs.ReadBuffer(buf[0], buf[2]+1);
                     DataLen := HexToInt(IntToHex(buf[6], 2)+IntToHex(buf[7], 2)+IntToHex(buf[8], 2)+IntToHex(buf[9], 2));
                     fs.Seek(DataLen,soFromCurrent);
                     inc(blocks);
                     continue;
                     end;

               end;
          end;
          $5D://Phoenix-segment
          begin
               fs.ReadBuffer(buf[0], $3);
               fs.ReadBuffer(buf[0], buf[2]+1);
               DataLen := HexToInt(IntToHex(buf[37], 2)+IntToHex(buf[38], 2)+IntToHex(buf[39], 2)+IntToHex(buf[40], 2));
               TokenType := buf[32];
                      case tokentype of
                      0:Inc(cmtcount);
                      1:Inc(apecount);
                      else inc(unk);
                      end;
               //Form1._msg(inttohex(buf[32],2)+inttohex(buf[33],2));
              //Form1._msg(inttohex(buf[32],2)+inttohex(buf[33],2)+inttohex(buf[34],2)+inttohex(buf[35],2));
               fs.Seek(DataLen,soFromCurrent);
               inc(blocks);
               continue;
          end;
          end;
     end;
     writen:=0;
     if Blocks=0 then
     begin
     Form1._msg('No any data for write, skip write');
     fs.Free;
     result:=True;
     Exit;
     end;
     Form1._msg('Total '+IntToStr(blocks)+' ['+inttostr(cmtcount)+'/'+inttostr(apecount)+'/'+inttostr(unk)+'] blocks to write, writing... ');
     Application.ProcessMessages;
     Form1.statusbar.Panels[0].text:='Write Data....';
     //Form1.statusbar.panels[1].text:='Time : '+inttostr(blocks div 10)+' sec...';
     Form1.pb1.progress:=0;
     Form1.pb1.MaxValue:=Blocks;
     fs.Seek(EntryPoint, soFromBeginning);
     Application.ProcessMessages;
     Form1.statusbar.Panels[1].text:='0/'+inttostr(cmtcount);
     while fs.Position<fs.Size do
     begin

               if stop=True then
               begin
               dostop('WRITE');
               result:=false;
               Form1.pb1.progress:=0;
               Form1.pb1.MaxValue:=100;
               fs.Free;
               Exit;
               end;

          fs.ReadBuffer(buf[0], 1);
          if (buf[0]<>$54) and (buf[0]<>$5D) then
          raise E.Create('Bad image file! Write terminated!');

          case buf[0] of

          $54://Phoenix-token
          begin
               fs.ReadBuffer(buf[0], $3);
               case buf[1] of
                 $17: begin
                      partitionbuf:=false;
                      fs.ReadBuffer(buf[0], buf[2]+1);
                      DataLen      := HexToInt(IntToHex(buf[6],  2)+IntToHex(buf[7],  2)+IntToHex(buf[8],  2)+IntToHex(buf[9],  2));
                      TargetOffset := HexToInt(IntToHex(buf[10], 2)+IntToHex(buf[11], 2)+IntToHex(buf[12], 2)+IntToHex(buf[13], 2));
                      Application.ProcessMessages;

                        WriteData[6] := buf[0];
                        WriteData[7] := msgid;
                        WriteData[8] := ISIHeaderTransId;
                        WriteData[9] := $4C;
                        WriteData[10] := buf[1];
                        WriteData[11] := buf[2];

                        cf1:=buf[0];
                        cf2:=buf[1];
                        cf3:=buf[2];
                        apeb:=buf[0];

                        WriteData[12] := buf[6];
                        WriteData[13] := buf[7];
                        WriteData[14] := buf[8];
                        WriteData[15] := buf[9];

                        WriteData[16] := buf[10];
                        WriteData[17] := buf[11];
                        WriteData[18] := buf[12];
                        WriteData[19] := buf[13];

                        case apeb of
                        0: begin
                           WriteData[3]:=$6F;
                           WriteData[6]:=$00;
                           cmtdin:=cmtdin+1;
                           Form1.statusbar.Panels[1].text:='CMT : '+inttostr(cmtdin)+'/'+inttostr(cmtcount);
                           Application.ProcessMessages;
                           end;
                        1: begin
                           WriteData[3]:=$21;
                           WriteData[6]:=$00;
                           apedin:=apedin+1;
                           Form1.statusbar.Panels[1].text:='APE : '+inttostr(apedin)+'/'+inttostr(apecount);
                           Application.ProcessMessages;
                           end;
                        else
                        begin
                        WriteData[3]:=$6F;
                        WriteData[6]:=$00;
                        end;
                        end;


{=============================================================================================================================================================}
                        n:=USBBulkWritePort(@WriteData, 36);
                        if n<>36 then raise E.Create('Write Failed, ERR1 : Data missmatch, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));

                        if Not USBBulkReadPort(12) or (Length(rxBuf)<12) then raise E.Create('Write Failed, ERR0 : Connection lost, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));
                        if rxBuf[8]<>WriteData[8] then raise E.Create('Write Failed, ERR5 : Transaction error, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));//целостность транзанкций
                        if rxBuf[11]<>$00         then raise E.Create('Write Failed, ERR3 : Data not accepted, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));
{--------------------------------------------------------------------------------------------------------------------------------------------------------------}
                        //Form1._msg('Send  : '+BufToHex_Str(@WriteData, 36));
                        //Form1._msg('Receiv: '+BufToHex_Str(@rxBuf, n));
{=============================================================================================================================================================}
                        Application.ProcessMessages;
                      end;
                 $2E: begin
                      partitionbuf:=false;
                      fs.ReadBuffer(buf[0], buf[2]+1);
                      DataLen      := HexToInt(IntToHex(buf[17],  2)+IntToHex(buf[18],  2)+IntToHex(buf[19],  2)+IntToHex(buf[20],  2));
                      TargetOffset := HexToInt(IntToHex(buf[21],  2)+IntToHex(buf[22],  2)+IntToHex(buf[23],  2)+IntToHex(buf[24], 2));
                      //form1._msg(byte2str(buf[21])+byte2str(buf[22])+byte2str(buf[23])+byte2str(buf[24]));
                      Application.ProcessMessages;

                       WriteData[6] := buf[0];
                       WriteData[7] := msgid;
                       WriteData[8] := ISIHeaderTransId;
                       WriteData[9] := $4C;
                       WriteData[10] := buf[1];
                       WriteData[11] := buf[2];

                       cf1:=buf[0];
                       cf2:=buf[1];
                       cf3:=buf[2];
                       apeb:=buf[0];
                       dword((@writedata[12])^):=datalen;
                       dwordswap(@writedata[12]);


                       WriteData[16] := buf[21];
                       WriteData[17] := buf[22];
                       WriteData[18] := buf[23];
                       WriteData[19] := buf[24];

                       WriteData[20] := buf[5];
                       WriteData[21] := buf[6];
                       WriteData[22] := buf[7];
                       WriteData[23] := buf[8];
                       WriteData[24] := buf[9];
                       WriteData[25] := buf[10];
                       WriteData[26] := buf[11];
                       WriteData[27] := buf[12];
                       WriteData[28] := buf[13];
                       WriteData[29] := buf[14];
                       WriteData[30] := buf[15];
                       WriteData[31] := buf[16];

                       case apeb of
                        0: begin
                           WriteData[3]:=$6F;
                           WriteData[6]:=$00;
                            cmtdin:=cmtdin+1;
                           Form1.statusbar.Panels[1].text:='CMT : '+inttostr(cmtdin)+'/'+inttostr(cmtcount);
                           Application.ProcessMessages;
                           end;
                        1: begin
                           WriteData[3]:=$21;
                           WriteData[6]:=$00;
                            apedin:=apedin+1;
                           Form1.statusbar.Panels[1].text:='APE : '+inttostr(apedin)+'/'+inttostr(apecount);
                           Application.ProcessMessages;
                           end;
                        else
                        begin
                        WriteData[3]:=$6F;
                        WriteData[6]:=$00;
                        end;
                        end;

{=============================================================================================================================================================}
                       n:=USBBulkWritePort(@WriteData, 36);
                       if n<>36 then raise E.Create('Write Failed, ERR1 : Data missmatch, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));

                       if Not USBBulkReadPort(12) or (Length(rxBuf)<12) then raise E.Create('Write Failed, ERR0 : Connection lost, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));
                       if rxBuf[8]<>WriteData[8] then raise E.Create('Write Failed, ERR5 : Transaction error, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));//целостность транзанкций
                       if rxBuf[11]<>$00         then raise E.Create('Write Failed, ERR3 : Data not accepted, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));
{--------------------------------------------------------------------------------------------------------------------------------------------------------------}
                       //Form1._msg('Send  : '+BufToHex_Str(@WriteData, 36));
                       //Form1._msg('Receiv: '+BufToHex_Str(@rxBuf, n));
{=============================================================================================================================================================}
                       for icl:=20 to 31 do WriteData[icl]:=$00;
                       Application.ProcessMessages;
                      end;
                 $30 : Begin
                      partitionbuf:=true;
                      fs.ReadBuffer(buf[0], buf[2]+1);
                      DataLen := HexToInt(IntToHex(buf[13], 2)+IntToHex(buf[14], 2)+IntToHex(buf[15], 2)+IntToHex(buf[16], 2));
                      TargetOffset := HexToInt(IntToHex(buf[17], 2)+IntToHex(buf[18], 2)+IntToHex(buf[19], 2)+IntToHex(buf[20], 2));
                      Application.ProcessMessages;
                        partitonwrite[6] := buf[0];
                        partitonwrite[7] := msgid;
                        partitonwrite[8] := ISIHeaderTransId;
                        partitonwrite[9] := $88;
                        partitonwrite[10] := buf[1];
                        partitonwrite[11] := buf[2];

                        cf1:=buf[0];
                        cf2:=buf[1];
                        cf3:=buf[2];
                        apeb:=buf[0];

                        partitonwrite[12] := buf[5];
                        partitonwrite[13] := buf[6];
                        partitonwrite[14] := buf[7];
                        partitonwrite[15] := buf[8];

                        partitonwrite[16] := buf[13];
                        partitonwrite[17] := buf[14];
                        partitonwrite[18] := buf[15];
                        partitonwrite[19] := buf[16];

                        partitonwrite[20] := buf[17];
                        partitonwrite[21] := buf[18];
                        partitonwrite[22] := buf[19];
                        partitonwrite[23] := buf[20];

                        case apeb of
                        0: begin
                           partitonwrite[3]:=$6F;
                           partitonwrite[6]:=$00;
                           cmtdin:=cmtdin+1;
                            Application.ProcessMessages;
                            //Form1._msg('CMT : Write partition 0x'+byte2str(buf[8]));
                            Application.ProcessMessages;
                           Form1.statusbar.Panels[1].text:='CMT : partition 0x'+byte2str(buf[8])+' '+inttostr(cmtdin)+'/'+inttostr(cmtcount);
                           Application.ProcessMessages;
                           end;
                        1: begin
                           WriteData[3]:=$21;
                           WriteData[6]:=$00;
                           apedin:=apedin+1;
                            Application.ProcessMessages;
                            //Form1._msg('APE : Write partition 0x'+byte2str(buf[8]));
                            Application.ProcessMessages;
                           Form1.statusbar.Panels[1].text:='APE : partition 0x'+byte2str(buf[8])+' '+inttostr(apedin)+'/'+inttostr(apecount);
                           Application.ProcessMessages;
                           end;
                        else
                        begin
                        WriteData[3]:=$6F;
                        WriteData[6]:=$00;
                        end;
                        end;

{=============================================================================================================================================================}
                        n:=USBBulkWritePort(@partitonwrite, 24);
                        if n<>24 then raise E.Create('Write Failed, err1, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));

                        if Not USBBulkReadPort(12) or (Length(rxBuf)<12) then raise E.Create('Write Failed, ERR0  :Connection lost, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));
                        if rxBuf[8]<>partitonwrite[8] then raise E.Create('Write Failed, ERR5 : Transaction error, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));//целостность транзанкций
                       // if rxBuf[10]<>$00         then raise E.Create('Write Failed, err5, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));
{--------------------------------------------------------------------------------------------------------------------------------------------------------------}
                        //Form1._msg('Send  : '+BufToHex_Str(@WriteData, 36));
                        //Form1._msg('Receiv: '+BufToHex_Str(@rxBuf, n));
{=============================================================================================================================================================}
                        Application.ProcessMessages;
                      end;
                 else
                      begin
                        partitionbuf:=false;
                       fs.ReadBuffer(buf[0], buf[2]+1);
                      DataLen      := HexToInt(IntToHex(buf[6],  2)+IntToHex(buf[7],  2)+IntToHex(buf[8],  2)+IntToHex(buf[9],  2));
                      TargetOffset := HexToInt(IntToHex(buf[10], 2)+IntToHex(buf[11], 2)+IntToHex(buf[12], 2)+IntToHex(buf[13], 2));

                       WriteData[6] := buf[0];
                       WriteData[7] := msgid;
                       WriteData[8] := ISIHeaderTransId;
                       WriteData[9] := $4C;
                       WriteData[10] := buf[1];
                       WriteData[11] := buf[2];

                       cf1:=buf[0];
                       cf2:=buf[1];
                       cf3:=buf[2];
                       apeb:=buf[0];

                       WriteData[12] := buf[6];
                       WriteData[13] := buf[7];
                       WriteData[14] := buf[8];
                       WriteData[15] := buf[9];

                       WriteData[16] := buf[10];
                       WriteData[17] := buf[11];
                       WriteData[18] := buf[12];
                       WriteData[19] := buf[13];

                       case apeb of
                        0: begin
                           WriteData[3]:=$6F;
                           WriteData[6]:=$00;
                            cmtdin:=cmtdin+1;
                           Form1.statusbar.Panels[1].text:='CMT : '+inttostr(cmtdin)+'/'+inttostr(cmtcount);
                           Application.ProcessMessages;
                           end;
                        1: begin
                           WriteData[3]:=$21;
                           WriteData[6]:=$00;
                            apedin:=apedin+1;
                           Form1.statusbar.Panels[1].text:='APE : '+inttostr(apedin)+'/'+inttostr(apecount);
                           Application.ProcessMessages;
                           end;
                        else
                        begin
                        WriteData[3]:=$6F;
                        WriteData[6]:=$00;
                        end;
                        end;

{=============================================================================================================================================================}
                       n:=USBBulkWritePort(@WriteData, 36);
                       if n<>36 then raise E.Create('Write Failed, err1, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));

                       if Not USBBulkReadPort(12) or (Length(rxBuf)<12) then raise E.Create('Write Failed, ERR0 : Connection lost, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));
                       if rxBuf[8]<>WriteData[8] then raise E.Create('Write Failed, ERR5 : Transaction error, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));//целостность транзанкций
                       if rxBuf[11]<>$00         then raise E.Create('Write Failed, ERR3 : Data not accepted, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));
{--------------------------------------------------------------------------------------------------------------------------------------------------------------}
                       //Form1._msg('Send  : '+BufToHex_Str(@WriteData, 36));
                       //Form1._msg('Receiv: '+BufToHex_Str(@rxBuf, n));
{=============================================================================================================================================================}
                       Application.ProcessMessages;
                      end;
               end;
               Application.ProcessMessages;
               Form1.pb1.progress:=Form1.pb1.progress+1;


               // Header written... now Rock'n'Roll!
               fs.ReadBuffer(buf[0], DataLen);
               Packets:=1;
               CurrPacketSize:=DataLen;

               case  partitionbuf of
               false :
               begin
               if DataLen>Write_Split then
               begin
                    Packets:=DataLen div Write_Split;
                    if (DataLen mod Write_Split) > 0 then inc(Packets);
                    CurrPacketSize:=Write_Split;
               end;

               for i:=0 to Packets-1 do
               begin
                    if (i=Packets-1) and (Packets>1) then
                    begin
                         if (DataLen mod Write_Split)>0 then CurrPacketSize:=(DataLen mod Write_Split) else CurrPacketSize:=Write_Split;
                    end;

                    txBuf[0] := $1B;
                    txBuf[1] := $00;
                    txBuf[2] := $10;
                    txBuf[3] := $6F;

                    txBuf[4] := ((CurrPacketSize+8) div $100);
                    txBuf[5] := ((CurrPacketSize+8) mod $100);

                    txBuf[6] := cf1;
                    txBuf[7] := msgid;
                    txBuf[8] := ISIHeaderTransId;
                    txBuf[9] := $4B;

                    txBuf[10] := (CurrPacketSize div $100);
                    txBuf[11] := (CurrPacketSize mod $100);
                    txBuf[12] := $00;
                    txBuf[13] := $00;
                    for n:=0 to CurrPacketSize-1 do
                    begin
                         txBuf[14+n] := buf[(i*Write_Split)+n];
                    end;

                    CrcTmp:=$0000;
                    for n:=0 to CurrPacketSize-1 do
                    begin
                         if (n mod 2)=0 then CrcTmp:=CrcTmp xor ( (txBuf[14+n]*$100) + (txBuf[14+n+1]));
                    end;
                    CrcTmp := CrcTmp AND $FFFF;

                    txBuf[12] := CrcTmp div $100;
                    txBuf[13] := CrcTmp mod $100;

                    case apeb of
                    0: begin
                       txbuf[3]:=$6F;
                       txbuf[6]:=$00;
                       end;
                    1: begin
                       txbuf[3]:=$21;
                       txbuf[6]:=$00;
                       end;
                        else
                        begin
                        txbuf[3]:=$6F;
                        txbuf[6]:=$00;
                        end;
                        end;

{=============================================================================================================================================================}

                    n:=USBBulkWritePort(@txBuf, 14+CurrPacketSize);

                    if n<>14+CurrPacketSize then raise E.Create('Write Failed, ERR1 : Data missmatch, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));

                    if Not USBBulkReadPort(16) or (Length(rxBuf)<16) then raise E.Create('Write Failed, ERR0 : Connecttion lost, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));
                    if rxBuf[8]<>txBuf[8] then raise E.Create('Write Failed, ERR5 : Transaction error, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));//целостность транзанкций
                    if rxBuf[15]<>$00     then raise E.Create('Write Failed, ERR3 : Data not accepted, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));
{--------------------------------------------------------------------------------------------------------------------------------------------------------------}
               //Form1._msg('Send  : '+BufToHex_Str(@WriteData, 36));
               //Form1._msg('Receiv: '+BufToHex_Str(@rxBuf, n));
{=============================================================================================================================================================}
               end;
               end;
               true:
               begin
                if DataLen>$8000 then
                begin
                    Packets:=DataLen div $8000;
                    if (DataLen mod $8000) > 0 then inc(Packets);
                    CurrPacketSize:=$8000;
                end;

                for i:=0 to Packets-1 do
                begin
                    if (i=Packets-1) and (Packets>1) then
                    begin
                         if (DataLen mod $8000)>0 then CurrPacketSize:=(DataLen mod $8000) else CurrPacketSize:=$8000;
                    end;

                    txBuf[0] := $1B;
                    txBuf[1] := $00;
                    txBuf[2] := $10;
                    txBuf[3] := $6F;

                    txBuf[4] := ((CurrPacketSize+6) div $100);
                    txBuf[5] := ((CurrPacketSize+6) mod $100);

                    txBuf[6] := $00;
                    txBuf[7] := msgid;
                    txBuf[8] := ISIHeaderTransId;
                    txBuf[9] := $90;

                    txBuf[10] := (CurrPacketSize div $100);
                    txBuf[11] := (CurrPacketSize mod $100);
                    for n:=0 to CurrPacketSize-1 do
                    begin
                         txBuf[12+n] := buf[(i*$8000)+n];
                    end;

                    case apeb of
                    0: begin
                       txbuf[3]:=$6F;
                       txbuf[6]:=$00;
                       end;
                    1: begin
                       txbuf[3]:=$21;
                       txbuf[6]:=$00;
                       end;
                        else
                        begin
                        txbuf[3]:=$6F;
                        txbuf[6]:=$00;
                        end;
                        end;

{=============================================================================================================================================================}

                    n:=USBBulkWritePort(@txBuf, 12+CurrPacketSize);

                    if n<>12+CurrPacketSize then raise E.Create('Write Failed, ERR1 : Data missmatch, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));

                    if Not USBBulkReadPort(12) or (Length(rxBuf)<12) then raise E.Create('Write Failed, ERR0 : Connection lost, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));
                    if rxBuf[8]<>txBuf[8] then raise E.Create('Write Failed,ERR5 : Transaction failed, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));//целостность транзанкций
                    if (rxBuf[9]<>$91) and (rxBuf[10]<>$00)   then raise E.Create('Write Failed, ERR3 : Partition not accepted, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));
{--------------------------------------------------------------------------------------------------------------------------------------------------------------}
               //Form1._msg('Send  : '+BufToHex_Str(@WriteData, 36));
               //Form1._msg('Receiv: '+BufToHex_Str(@rxBuf, n));
{=============================================================================================================================================================}
                end;
               end;
            end;
               continue;
          end;//end of case $54 - write Data

          $5D://Phoenix-segment
          begin
               fillmemory(@txbuf[0],36,$00);
               fs.ReadBuffer(buf[0], 3);
               fs.ReadBuffer(buf[0], buf[2]+1);
               DataLen := HexToInt(IntToHex(buf[37], 2)+IntToHex(buf[38], 2)+IntToHex(buf[39], 2)+IntToHex(buf[40], 2));
               TargetOffset :=  HexToInt(IntToHex(buf[41], 2)+IntToHex(buf[42], 2)+IntToHex(buf[43], 2)+IntToHex(buf[44], 2));
               apeb:=buf[32];
               //form1._msg(byte2str(buf[32]));
               Application.ProcessMessages;

               case apeb of
               0: begin
                    good:=0;
                    for i:=$0 to $0F do if RAPInfo.Root_Key_Hash[i]=buf[i] then inc(good);
                    if good<$10 then
                    begin
                    form1.pb1.progress:=form1.pb1.progress+1;
                     cmtdin:=cmtdin+1;
                     Form1.statusbar.Panels[1].text:='CMT : '+inttostr(cmtdin)+'/'+inttostr(cmtcount);
                    Application.ProcessMessages;
                    fs.Seek(DataLen, sofromCurrent);
                    continue;
                    end;
                    AsicType:='CMT : ';
                  end;
               1: begin
                    good:=0;
                    for i:=$0 to $0F do if RAPInfo.APErootkey[i]=buf[i] then inc(good);
                    if good<$10 then
                    begin
                    form1.pb1.progress:=form1.pb1.progress+1;
                     apedin:=apedin+1;
                     Form1.statusbar.Panels[1].text:='APE : '+inttostr(apedin)+'/'+inttostr(apecount);
                    Application.ProcessMessages;
                    fs.Seek(DataLen, sofromCurrent);
                    continue;
                    end;
                    AsicType:='APE : ';
                  end;
               else
               begin
               good:=0;
               for i:=$0 to $0F do if RAPInfo.Root_Key_Hash[i]=buf[i] then inc(good);
               if good<$10 then
               begin
               form1.pb1.progress:=form1.pb1.progress+1;
                Form1.statusbar.Panels[1].text:='UNK : -/-';
               Application.ProcessMessages;
               fs.Seek(DataLen, sofromCurrent);
               continue;
               end;
               AsicType:='CMT : ';
               end;
               end;

               CertName:='';
               for i:=20 to 31 do if buf[i]=$00 then break else CertName:=CertName+Chr(buf[i]);

               Form1._msg(AsicType+'Writing Hash CERT ['+CertName+']');
               Application.ProcessMessages;

               txBuf[0] := $1B;
               txBuf[1] := $00;
               txBuf[2] := $10;
               txBuf[3] := $6F;

               txBuf[4] := $00;
               txBuf[5] := $1E;

               txBuf[6] := $00;
               txBuf[7] := msgid;
               txBuf[8] := ISIHeaderTransId;
               txBuf[9] := $4C;

               txBuf[10] := buf[33];
               txBuf[11] := buf[34];

               cf1:=buf[32];
               cf2:=buf[33];
               cf3:=buf[34];

               txBuf[12] := buf[37];
               txBuf[13] := buf[38];
               txBuf[14] := buf[39];
               txBuf[15] := buf[40];


               txBuf[16] := buf[41];
               txBuf[17] := buf[42];
               txBuf[18] := buf[43];
               txBuf[19] := buf[44];
               for i:=20 to 35 do txBuf[i]:=$00;


               case apeb of
               0: begin
               if CertName='PAPUBKEYS' then
                 begin
                    if not PAPUB_Already then
                    begin
                          //Form1._msg('CMT : Patch '+CertName);
                          txBuf[16] := $00;
                          txBuf[17] := $00;
                          txBuf[18] := $00;
                          txBuf[19] := $00;

                          for i:=20 to 31 do txBuf[i]:=buf[i];
                         PAPUB_Already:=True;
                    end else
                    begin
                          Form1._msg('CMT : PAPUBKEYS skip, already sent');
                    end;

                 end;
                  if CertName='SOS*ENO' then
                 begin
                      if BufToHexStr(@buf[41],4)='FFFFFFFF' then begin
                        txBuf[16] := $00;
                        txBuf[17] := $00;
                        txBuf[18] := $00;
                        txBuf[19] := $00;
                        for i:=20 to 31 do txBuf[i]:=buf[i];
                      end;
                  end;
                 if CertName='NPC' then
                 begin
                      if BufToHexStr(@buf[41],4)='FFFFFFFF' then begin
                        txBuf[16] := $00;
                        txBuf[17] := $00;
                        txBuf[18] := $00;
                        txBuf[19] := $00;
                        for i:=20 to 31 do txBuf[i]:=buf[i];
                      end;
                  end;
               end;
               1: begin
               if CertName='PAPUBKEYS' then
               begin
                    if not APE_PAPUB then
                    begin
                         // Form1._msg('APE : Patch '+CertName);
                          txBuf[16] := $00;
                          txBuf[17] := $00;
                          txBuf[18] := $00;
                          txBuf[19] := $00;

                          for i:=20 to 31 do txBuf[i]:=buf[i];
                         APE_PAPUB:=True;
                    end else
                    begin
                          Form1._msg('APE : PAPUBKEYS skip, already sent');
                    end;
               end;
               end;
             end;

               case apeb of
                0: begin
                   txbuf[3]:=$6F;
                    cmtdin:=cmtdin+1;
                    Form1.statusbar.Panels[1].text:='CMT : '+inttostr(cmtdin)+'/'+inttostr(cmtcount);
                    Application.ProcessMessages;
                   end;
                1: begin
                   txbuf[3]:=$21;
                    apedin:=apedin+1;
                    Form1.statusbar.Panels[1].text:='APE : '+inttostr(apedin)+'/'+inttostr(apecount);
                    Application.ProcessMessages;
                   end;
                else
                begin
                txbuf[3]:=$6F;
                end;
                end;
              // form1._msg(BufToHexStr(@txbuf[1],36));
              // Form1._msg('');
               Application.ProcessMessages;
{=============================================================================================================================================================}

               n:=USBBulkWritePort(@txBuf, 36);
               if n<>36 then raise E.Create('Write CERT Failed, ERR1 : Data missmatch, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));

               if Not USBBulkReadPort(12) or (Length(rxBuf)<12) then raise E.Create('Write CERT Failed, ERR0 : Connection lost, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));
               if rxBuf[8]<>txBuf[8] then raise E.Create('Write CERT Failed, ERR5 : Transaction failed, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));//целостность транзанкций
               if rxBuf[11]<>$00         then raise E.Create('Write CERT Failed, ERR2 : Cert not accepted, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));
{--------------------------------------------------------------------------------------------------------------------------------------------------------------}
               //Form1._msg('SendPrologiSert: '+BufToHex_Str(@txBuf, 36));
               //Form1._msg('RecPrologiSert : '+BufToHex_Str(@rxBuf, n));
{=============================================================================================================================================================}

               // Шапка записана - Зажигаем! =)

               fs.ReadBuffer(buf[0], DataLen);
               Packets:=1;
               CurrPacketSize:=DataLen;

               if DataLen>Write_Split then
               begin
                    Packets:=DataLen div Write_Split;
                    if (DataLen mod Write_Split) > 0 then inc(Packets);
                    CurrPacketSize:=Write_Split;
               end;

               for i:=0 to Packets-1 do
               begin
                    if (i=Packets-1) and (Packets>1) then
                    begin
                         if (DataLen mod Write_Split)>0 then CurrPacketSize:=(DataLen mod Write_Split) else CurrPacketSize:=Write_Split;
                    end;

                    txBuf[0] := $1B;
                    txBuf[1] := $00;
                    txBuf[2] := $10;

                  case ApeB of
                  0:txBuf[3] := $6F;
                  1:txBuf[3] := $21;
                  else txBuf[3]:= $6F;
                  end;

                    txBuf[4] := ((CurrPacketSize+8) div $100);
                    txBuf[5] := ((CurrPacketSize+8) mod $100);

                    txBuf[6] := $00;
                    txBuf[7] := msgid;
                    txBuf[8] := ISIHeaderTransId;
                    txBuf[9] := $4B;

                    txBuf[10] := (CurrPacketSize div $100);
                    txBuf[11] := (CurrPacketSize mod $100);

                    for n:=0 to CurrPacketSize-1 do
                    begin
                         txBuf[14+n] := buf[(i*Write_Split)+n];
                    end;

                    CrcTmp:=$0000;
                    for n:=0 to CurrPacketSize-1 do
                    begin
                         if (n mod 2)=0 then CrcTmp:=CrcTmp xor ( (txBuf[14+n]*$100) + (txBuf[14+n+1]));
                    end;
                    CrcTmp := CrcTmp AND $FFFF;

                    txBuf[12] := CrcTmp div $100;
                    txBuf[13] := CrcTmp mod $100;

{=============================================================================================================================================================}
                    n:=USBBulkWritePort(@txBuf, 14+CurrPacketSize);
                    if n<>14+CurrPacketSize then raise E.Create('Write CERT Failed, ERR1 : Data missamtch, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));

                    if Not USBBulkReadPort(16) or (Length(rxBuf)<16) then raise E.Create('Write CERT Failed, ERR0 : Connection losted , at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));
                    if rxBuf[8]<>txBuf[8] then raise E.Create('Write CERT Failed, ERR5 : Transaction failed, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));//целостность транзанкций
                    if rxBuf[11]<>$00     then raise E.Create('Write CERT Failed, ERR2 : Cert not accepted, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));

{--------------------------------------------------------------------------------------------------------------------------------------------------------------}
                    //Form1._msg(BufToHex_Str(@txBuf, 14+CurrPacketSize));
                    //Form1._msg(BufToHex_Str(@rxBuf, n);
{=============================================================================================================================================================}
               end;
               continue;
           form1.pb1.progress:=form1.pb1.progress+1;
           Application.ProcessMessages;
          end;//end of case $5D - write Sert
          end;
     end;
     Result:=True;
     fs.Free;
     endtimecount;
     form1._msg('TIME : Write time : '+showtime(tmsres));
     except
           on E:Exception do
           begin
                fs.Free;
                Form1._msg('Error: '+E.Message);
                Form1.pb1.Progress:=0;
                USBClosePort;
                endtimecount;
                exit;
           end;
     end;
     Form1.pb1.Progress:=0;
end;

function USBControlPacket(_Class: LongWord; Length: longword; Expected:Integer):Boolean;
var
     i        : integer;
     Count    : LongWord;
     Buffer   : array[0..$FFFE] of byte;
begin
     Result:=False;
     rxBuf:=nil;
     SetLength(rxBuf, 1);
     if hDevice = INVALID_HANDLE_VALUE then exit;
     if not DeviceIOControl(hDevice, _Class, @txBuf, Length, @Buffer, Expected, Count, nil) then exit;
     SetLength(rxBuf, Count);
     for i := 0 to Count - 1 do rxBuf[i]:=Buffer[i];
     if Expected>0 then result:=False else result:=True;
end;

function BB5_USB_BootRom_GetFirstBlock:integer;
begin
     Result:=0;
     txBuf[0]:=$40;
     txBuf[1]:=$59;
     txBuf[2]:=$00;
     txBuf[3]:=$00;
     txBuf[4]:=$00;
     txBuf[5]:=$00;
     txBuf[6]:=$00;
     txBuf[7]:=$00;
     try
     if USBControlPacket($222040, $8, 0) then
     begin
          Application.ProcessMessages;
          Form1._msg('[BB5 FLASH]: Bootrom Ok!');
     end else
     begin
          Form1._msg('[BB5 FLASH]: Can'+#39+'t verify Bootrom :( Try again...');
          USBClosePort;
          exit;
     end;
     Application.ProcessMessages;
     txBuf[0]:=$C0;
     txBuf[1]:=$56;
     txBuf[2]:=$00;
     txBuf[3]:=$00;
     txBuf[4]:=$00;
     txBuf[5]:=$00;
     txBuf[6]:=$00;
     txBuf[7]:=$03;

     USBControlPacket($222040, $8, $300);
     //Form1._msg('rxbuf: '+BufToHexStr(@rxBuf[0], Length(rxBuf)));

     if rxBuf[0]<1 then
     begin
          Application.ProcessMessages;
          Form1._msg('[BB5 FLASH]: GetFirstBlock Failed, Aborting');
          USBClosePort;
          exit;
     end;
     Result:=rxBuf[0];
   except
     Result:=0;
   end;
end;

function BB5_ADL_RestartMCU(mode: byte):boolean;
var
     n: integer;
begin
  Application.ProcessMessages;
  case mode of
      $04: begin
             Result:=False;
             txBuf[0] := $1B;
             txBuf[1] := $00;
             txBuf[2] := $10;
             txBuf[3] := $6f;
             txBuf[4] := $00;
             txBuf[5] := $06;
             txBuf[6] := $00;
             txBuf[7] := msgid;
             txBuf[8] := ISIHeaderTransId;
             txBuf[9] := $04;
             txBuf[10] := $00;
             txBuf[11] := $00;
             n:=USBBulkWritePort(@txBuf, 12);
             if n<>12 then exit;

             txBuf[0]  := $1B;
             txBuf[1]  := $00;
             txBuf[2]  := $10;
             txBuf[3]  := $6f;
             txBuf[4]  := $00;
             txBuf[5]  := $06;
             txBuf[6]  := $00;
             txBuf[7]  := msgid;
             txBuf[8]  := ISIHeaderTransId;
             txBuf[9]  := $00;
             txBuf[10] := $00;
             txBuf[11] := $00;
             n:=USBBulkWritePort(@txBuf, 12);
             if n<>12 then exit;
             Result:=True;
      end;
      $80: begin
       result:=False;
       txBuf[0] := $1B;
       txBuf[1] := $00;
       txBuf[2] := $10;
       txBuf[3] := $6f;
       txBuf[4] := $00;
       txBuf[5] := $06;
       txBuf[6] := $00;
       txBuf[7] := msgid;
       txBuf[8] := ISIHeaderTransId;
       txBuf[9] := $09;
       txBuf[10] := $02;
       txBuf[11] := $00;
       n:=USBBulkWritePort(@txBuf, 12);
       USBBulkReadPort($FF);
       if n<>12 then exit;

       txBuf[0] := $1B;
       txBuf[1] := $00;
       txBuf[2] := $10;
       txBuf[3] := $6f;
       txBuf[4] := $00;
       txBuf[5] := $06;
       txBuf[6] := $00;
       txBuf[7] := msgid;
       txBuf[8] := ISIHeaderTransId;
       txBuf[9] := $04;
       txBuf[10] := $02;
       txBuf[11] := $00;
       n:=USBBulkWritePort(@txBuf, 12);
       if n<>12 then exit;
       Result:=True;
      end
      else result:=False;
  end;

end;

function BB5restart2ndproto():boolean;
var
  n:integer;
begin

    //1B 00 10 6F 00 06 00 18 7D 09 02 00
    //1B 00 10 6F 00 06 00 18 2E 09 02 00
    //1B 00 10 6F 00 06 00 18 2F 04 02 00


end;

function s4080Final():Boolean;
begin
//1st recheck
adl80checkst[7]:=msgid;
adl80checkst[8]:=ISIHeaderTransId;
USBBulkWritePort(@adl80checkst, Length(adl80checkst));
UsbBulkReadport($FFFF);
adl80checkst[3]:=$21;
USBBulkWritePort(@adl80checkst, Length(adl80checkst));
adl80checkst[3]:=$6F;

//2nd - repeat check adl, send bytes
adl80precheck[7]:=msgid;
adl80precheck[8]:=ISIHeaderTransID;
USBBulkWritePort(@adl80precheck, Length(adl80precheck));
UsbBulkReadport($FFFF);
adl80checkst[7]:=msgid;
adl80checkst[8]:=ISIHeaderTransId;
USBBulkWritePort(@adl80checkst, Length(adl80checkst));
UsbBulkReadport($FFFF);
adl80checkst[3]:=$21;
USBBulkWritePort(@adl80checkst, Length(adl80checkst));
adl80checkst[3]:=$6F;

//3rd - getroot
adl80getroot[7]:=msgid;
adl80getroot[8]:=ISIHeaderTransId;
USBBulkWritePort(@adl80getroot, Length(adl80getroot));
UsbBulkReadport($FFFF);

//Select ASIC
adl80preasic[7]:=msgid;
adl80preasic[8]:=ISIHeaderTransId;
USBBulkWritePort(@adl80preasic, Length(adl80preasic));
UsbBulkReadport($FFFF);
adl80selASIC[7]:=msgid;
adl80selASIC[8]:=ISIHeaderTransId;
USBBulkWritePort(@adl80selASIC, Length(adl80selASIC));
UsbBulkReadport($FFFF);
if rxbuf[10]=$00 then result:=True else result:=False;
end;

function CheckADLLoader:boolean;
var
   n: integer;
begin
     Result:=False;
     n:=USBBulkWritePort(@CheckADLUpload[0], Length(CheckADLUpload));
     if n<>12 then exit;
     n:=ReadUBUSData;
     if n<6 then exit;
     if rxBuf[5]<>$04 then
     begin
          Form1._msg('ADL Server not confirmed flashmode!');
          USBClosePort;
          exit;
     end else
     begin
          Form1._msg('ADL Server has confirmed its flashmode');
          Result:=True;
     end;
end;

//Функция расчета CHK UPDAPP
function GetLoaderCRC(Buf:Pointer; BufLen: integer): Word;
begin
     Result:=0;
     while BufLen > 0 do begin
     Result:=Result+Byte(Buf^);
     inc(Integer(Buf));
     dec(BufLen);
     end;
     Result:=Result xor $FFFF;
end;

function s40prep04 ():Boolean;
var
  i:integer;
begin
     CheckADLUpload[7]:=msgid;
     CheckADLUpload[8]:=ISIHeaderTransId;
     CheckADLUpload[9]:=$00;
     i:=USBBulkWritePort(@CheckADLUpload, Length(CheckADLUpload));
     if i<>12 then exit;
     USBBulkReadPort(12);

     if rxBuf[11]<>$04 then
     result:=false
     else begin
          case oldsmart of
       false:
          begin;
          //GetRoot
          GetRoot[7]:=msgid;
          GetRoot[8]:=ISIHeaderTransId;
          GETRoot[9]:=$07;
          USBBulkWritePort(@GetRoot, Length(GetRoot));
          USBBulkReadPort($FFFF);

          GetRoot[7]:=msgid;
          GetRoot[8]:=ISIHeaderTransId;
          GETRoot[9]:=$01;
          //USBBulkWritePort(@GetRoot, Length(GetRoot));

          Application.ProcessMessages;
          sleep(100);
          Application.ProcessMessages;
          USBBulkWritePort(@oldsmGetRoot, Length(oldsmGetRoot));
          USBBulkReadPort($FFFF);
          selectAsicCMT[3]:=$6F;
          selectAsicCMT[8]:=ISIHeaderTransId;
          //USBBulkWritePort(@selectAsicCMT, Length(selectAsicCMT));
          Application.ProcessMessages;
          sleep(100);
          Application.ProcessMessages;
          //PreErase
          PreErase[7]:=msgid;
          PreErase[8]:=ISIHeaderTransId;
          PreErase[12]:=csbyte1;
          PreErase[13]:=csbyte2;
          PreErase[14]:=$00;
          PreErase[15]:=$00;
          USBBulkWritePort(@PreErase, Length(PreErase));
          result:=True;
          end;
       true:
        begin
          //oldsmgetroot
          USBBulkWritePort(@oldsmGetRoot, Length(oldsmGetRoot));
          USBBulkReadPort($FFFF);
          selectAsicCMT[3]:=$6F;
          selectAsicCMT[8]:=ISIHeaderTransId;
          USBBulkWritePort(@selectAsicCMT, Length(selectAsicCMT));
          if USBBulkReadPort($FFFF) then
          begin
           if rxbuf[10]=$00 then begin result:=True; Form1._msg('ADL : ASIC CMT select Ok');   end else begin result:=False; Form1._msg('ADL : Select CMT  failed'); end;
          end;
          Application.ProcessMessages;
        end;
      end;
     end;

end;

function s40prep80():Boolean;
begin
//1st recheck
adl80checkst[7]:=msgid;
adl80checkst[8]:=ISIHeaderTransId;
USBBulkWritePort(@adl80checkst, Length(adl80checkst));
UsbBulkReadport($FFFF);
adl80checkst[3]:=$21;
USBBulkWritePort(@adl80checkst, Length(adl80checkst));
adl80checkst[3]:=$6F;

//2nd - repeat check adl, send bytes
adl80precheck[7]:=msgid;
adl80precheck[8]:=ISIHeaderTransID;
USBBulkWritePort(@adl80precheck, Length(adl80precheck));
UsbBulkReadport($FFFF);
adl80checkst[7]:=msgid;
adl80checkst[8]:=ISIHeaderTransId;
USBBulkWritePort(@adl80checkst, Length(adl80checkst));
UsbBulkReadport($FFFF);
adl80checkst[3]:=$21;
USBBulkWritePort(@adl80checkst, Length(adl80checkst));
adl80checkst[3]:=$6F;

//3rd - getroot
adl80getroot[7]:=msgid;
adl80getroot[8]:=ISIHeaderTransId;
USBBulkWritePort(@adl80getroot, Length(adl80getroot));
UsbBulkReadport($FFFF);

//PRECRTDATA
if form1.chkMCUen.checked=true then S40BuildCertBody(core);

//Select ASIC
adl80preasic[7]:=msgid;
adl80preasic[8]:=ISIHeaderTransId;
USBBulkWritePort(@adl80preasic, Length(adl80preasic));
UsbBulkReadport($FFFF);
adl80selASIC[7]:=msgid;
adl80selASIC[8]:=ISIHeaderTransId;
USBBulkWritePort(@adl80selASIC, Length(adl80selASIC));
UsbBulkReadport($FFFF);
if rxbuf[10]=$00 then begin result:=True; Form1._msg('ADL : ASIC CMT select Ok');   end else begin result:=False; Form1._msg('ADL : Select CMT  failed'); end;
end;


function Extractloader(core:string ; mode : integer):Boolean;
var
     fs               : TfileStream;
     currcert,
     currtoken,
     streamlen        : TMemoryStream;
     data             : string;
     hdrlen,seemcount,
     CurrSeemLen,i    : Integer;
     currseem         : Byte;
     a                : string;
     blklen,loaderlen : DWORD;
     dcr              : Boolean;
     RootInBlock      : array[0..$F] of byte;
     j,good,i2        : Integer;
     n,k,l,m,PktLen   : integer;
     ms,
     RAWBlock,
     RAWLoader        : TmemoryStream;
     s, needSert      : String;
     Key, KeyLen      : Byte;
     PacketLen        : Byte;
     BlockCount       : Byte;
     CurrBlock        : Byte;
     CurrBlockLen     : Word;
     b, proto         : Boolean;
begin
     if mode=1 then
     begin
          Form1._msg('Dead Mode is Selected');
          Form1._msg('Waiting for USB device...');
          Form1._msg('--- Press phone'+#39+'s power button or insert cable & charger! ---');
          Application.ProcessMessages;
     end;

     //Nokia USB ROM
     b:=false; i:=0;
     repeat
           if (i=2500) and (b=false) then
           begin
                Form1._msg('->  Phone not found.. :(');
                result:=False;
                Form1.SetReady;
                Exit;
           end;
           Application.ProcessMessages;
           if stop=True then
           begin
           // Stopping operation
               dostop('BOOT');
               result:=false;
               Form1.pb1.progress:=0;
               i:=2499; b:=false;
           end;
           if catchdevice=$02 then
           begin
                b:=true;
                Form1._msg('Connection opened successfully');
           end;
           Application.ProcessMessages;
           Sleep(10);
           inc(i);
           Form1.statusbar.Panels[0].Text:='Wait for phone '+inttostr(2500-i);
           Application.ProcessMessages;
     until b ;
     Form1.statusbar.Panels[0].Text:='';
     Application.ProcessMessages;
     Form1._msg('Waiting for communication response...');
     Application.ProcessMessages;
     if BB5_USB_BootRom_GetFirstBlock<2 then
     begin
          Form1.setready;
          Form1._msg('->  Error answer from BootRom');
          Form1._msg('->  1. Try make battery charge');
          Form1._msg('->  2. Try insert charger, without pressing poweron');
          Form1._msg('->  3. Try change USB port, if driver hang - restart PC');
          result:=False;
          exit;
     end;
     Application.ProcessMessages;

     Form1.statusbar.Panels[3].Text:='Connected';

     starttime;
     Application.ProcessMessages;

     // Root Hash
     Application.ProcessMessages;
     FillMemory(@RAPInfo.ROOT_KEY_HASH,$10,$00);
     FillMemory(@RAPInfo.APErootkey,$10,$00);
     FillMemory(@RAPInfo.FlashID,$A,$00);
     FillMemory(@RAPInfo.APEFlashID,$A,$00);
     FillMemory(@RAPInfo.PublicID,$14,$00);
     FillMemory(@RAPInfo.BootID,$8,$00);
     Application.ProcessMessages;
     Application.ProcessMessages;
     PacketLen  :=rxbuf[0];
     BlockCount :=rxbuf[1];

     i:=2;
     j:=0;
     m:=0;
     while (i<PacketLen) and (j<BlockCount) do
     begin
          CurrBlock    :=rxbuf[i];
          inc(i);
          CurrBlockLen := HexToInt(IntToHex(rxbuf[i+1], 2)+IntToHex(rxbuf[i], 2))-1;
          inc(i,2);
          case CurrBlock of
          $01://RAP SYSTEM ASIC ID
              //5800 - 000000010000022600010006400C192101031103 [RAPIDO3G ver: 1.x]
              begin
                   for k:=0 to CurrBlockLen-1 do RAPInfo.SYSTEM_ASIC_ID[k]:= rxbuf[i+k];
                   Form1._msg('ASIC ID:       '+ BufToHexStr(@RAPInfo.SYSTEM_ASIC_ID[0],    Length(RAPInfo.SYSTEM_ASIC_ID)));
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          $02://RAP EMx ID
              //00000295
              //00000B22
              begin
                   if CurrBlockLen=4 then
                   for k:=0 to CurrBlockLen-1 do RAPInfo.EMx_ID[k]:= rxbuf[i+k];
                   Form1._msg('EM'+inttostr(m)+' ID:        '+ BufToHexStr(@RAPInfo.EMx_ID[0],    4));
                   inc(i, CurrBlockLen);
                   inc(j);inc(m);
              end;
          $12://PUBLIC_ID
              //1FF0001841158B52064E64D3C3E9A7F38DC47E29
              begin
                   for k:=0 to CurrBlockLen-1 do RAPInfo.PUBLIC_ID[k]:= rxbuf[i+k];
                   Form1._msg('PUBLIC ID:     '+ BufToHexStr(@RAPInfo.PUBLIC_ID[0],    Length(RAPInfo.PUBLIC_ID)));
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          $13://ASIC_MODE
              //00
              begin
                   if CurrBlockLen=2 then
                   RAPInfo.ASIC_MODE:= rxbuf[i];
                   Form1._msg('ASIC MODE ID:  '+ BufToHexStr(@RAPInfo.ASIC_MODE,    1));
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          $14://ROOT_KEY_HASH
              //CAEEBB65D3C48E6DC73B49DC5063A2EE
              begin
                   for k:=0 to CurrBlockLen-1 do RAPInfo.ROOT_KEY_HASH[k]:= rxbuf[i+k];
                   inc(i, CurrBlockLen);
                   inc(j);
                   //???????? ?? ?????? RootHash
                   l:=0;
                   for k := 0 to $0F do inc(l, RAPInfo.ROOT_KEY_HASH[k]);
                   if l=0 then
                   begin
                        Form1.setready;
                        Form1._msg('->  No ROOTKEY HASH Asic CMT. (IMEI DAMAGED?) Unable to continue flashing');
                        exit;
                   end;
                   Form1._msg('ROOT KEY HASH: '+ BufToHexStr(@RAPInfo.ROOT_KEY_HASH[0], Length(RAPInfo.ROOT_KEY_HASH)));
              end;
          $15://ROM_ID
              //4B9B75103E691FF8
              begin
                   for k:=0 to CurrBlockLen-1 do RAPInfo.ROM_ID[k]:= rxbuf[i+k];
                   Form1._msg('ROM ID:        '+ BufToHexStr(@RAPInfo.ROM_ID[0],    Length(RAPInfo.ROM_ID)));
                   inc(i, CurrBlockLen);
                   inc(j);
              end
              else
              begin
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          end;//End Of Case
     end;
     Application.ProcessMessages;

     //Извлечение RAW-Block
     RAWBlock:=TmemoryStream.Create;
     BB5_ExtractBlockOfRAWLoader(core, RAWBlock, b);

     if Not b then
     begin
          Form1.setready;
          Form1._msg('Error extracting RAW-loader');
          RAWBlock.Free;
          exit;
     end;
   // RAWBlock.SaveToFile('C:\Extract_RAW_Loader_from_'+ExtractFileName(core)+'.bin');

     //Извлечение и патчинг RAW-loader'a
     RAWLoader:=TmemoryStream.Create;
     BB5_ExtractRAWLoader(RAWBlock, RAWLoader, b);

     if Not b then
     begin
          Form1.setready;
          Form1._msg('Error Patching RAW-loader');
          RAWLoader.Free;
          RAWBlock.Free;
          exit;
     end;
     Form1._msg('PatchRAWLoader: Patched OK');
     //RAWLoader.SaveToFile('C:\RAW_Cert_Patch.bin');
     //RAWLoader.Clear;

{================================== SEND RAW LOADER ===================================}
     Application.processmessages;
     RAWLoader.Seek(0, sofrombeginning);
     b:=true; PktLen:=$1000; k:=1;
     txBuf[0]:=$40;
     txBuf[1]:=$57;
     txBuf[2]:=$01;
     txBuf[3]:=$00;
     txBuf[4]:=$00;
     txBuf[5]:=$00;
     Form1._msg('Processing RAWLOADER...');
     while (RAWLoader.position<RAWLoader.Size) and b do
     begin
          if ((RAWLoader.Size-RAWLoader.position)<PktLen) and b then //длина последнего кусочка
          begin
               b:=false;
               PktLen:=RAWLoader.Size-RAWLoader.position;//последний кусочек лоадера
               txBuf[2]:=$00;
               txBuf[6]:=PktLen mod $100;
               txBuf[7]:=PktLen div $100;
          end;
         // Form1._msg('Sending Raw-loader: '+inttohex(PktLen, 4));

          txBuf[6]:=PktLen mod $100;
          txBuf[7]:=PktLen div $100;
          RAWLoader.ReadBuffer(txBuf[8], PktLen);

          //ms.WriteBuffer(txBuf[8], PktLen);
          //ms.SaveToFile('C:\RAW\'+Int2Digs(k,4)+'_BEST.bin');
          //ms.Clear;
          inc(k);
          USBControlPacket($222040, $8+PktLen, 0);
          Application.ProcessMessages;
     end;

     fs:=TFileStream.Create(core,fmOpenRead);
     fs.Read(buf[0] ,1);
     if buf[0]<>$B2 then  //Заголовок / идентификатор
     begin
          Form1.lst1.items.add('File damaged or Unknow format... :(');
          fs.Free;
          exit;
     end;
     fs.ReadBuffer(buf[0], 4);//Длина Flash-header'a
     HdrLen    := HexToInt(IntToHex(buf[0], 2)+IntToHex(buf[1], 2)+IntToHex(buf[2], 2)+IntToHex(buf[3], 2));
     //form1._msg('HeaderLen: '+inttostr(HdrLen));
     fs.ReadBuffer(buf[0], 4);//Кол-во блоков в Flash-заголовке
     SeemCount := HexToInt(IntToHex(buf[0], 2)+IntToHex(buf[1], 2)+IntToHex(buf[2], 2)+IntToHex(buf[3], 2));
     //form1._msg('BlockCount: '+inttostr(SeemCount));
     Application.ProcessMessages;
     dcr:=false;
     currcert:=TMemoryStream.Create;
     currtoken:=TmemoryStream.Create;
     streamlen:=TMemoryStream.Create;
     good:=0;
     i2:=0;
     loaderlen:=0;

  try
    Form1.statusbar.Panels[4].Text:='Sending Boot';
     while (fs.Position<HdrLen) do
     begin
          fs.ReadBuffer(CurrSeem, 1);
          case CurrSeem of//Перебор всех блоков, поиск блока со структурой RAW-loader'а
           $EE:
              begin
                 //  Form1._msg('Partition found!');
                   fs.ReadBuffer(buf[0], 2);
                   CurrSeemLen := (buf[0]*$100)+buf[1];
                   fs.Seek(CurrSeemLen, sofromcurrent);
                   Application.ProcessMessages;
              end;
          $F3:
              begin
                  // Form1._msg('Raw found!');
                   //Читаем длину блока F3
                   fs.ReadBuffer(buf[0], 2);
                   CurrSeemLen := (buf[0]*$100)+buf[1];
                   fs.Seek(CurrSeemLen, sofromcurrent);
                   Application.ProcessMessages;
              end;//End of Block F3
           $FA: begin
              //Form1._msg('FA start found!');
              //CurrSeemLen := $E;
              //fs.Seek(CurrSeemLen, sofromcurrent);
              //fs.ReadBuffer(Buf[0],$E);
              //Form1._msg(buftohexstr(@Buf[0],$E));
              streamlen.CopyFrom(fs,$E);
              streamlen.Seek(1, sofromBeginning);
              streamlen.ReadBuffer(loaderlen,4);
              dwordswap(@loaderlen);
              //Form1._msg('Loader Len : '+inttostr(loaderlen));
              Form1.pb1.MaxValue:=loaderlen div $1000;
              Application.ProcessMessages;
              streamlen.Free;
              //fs.Free;
              //Exit;
              end;
            $56:
              begin
             // Form1._msg('Cert Token found, processing...');
              Application.ProcessMessages;
                  fs.ReadBuffer(buf[0], 3);
                  case Buf[1] of
                    $17: // UPDAPP body ( 1st block  - precrt )
                       begin
                     //  form1._msg('UpdAPP Body processing');
                       Application.ProcessMessages;
                       CurrSeemLen :=buf[2]+1;
                       //fs.ReadBuffer(buf[0], currseemlen);
                       fs.Seek(fs.Position-4, sofromBeginning);
                       currtoken.CopyFrom(fs,currseemlen+4);
                      // currtoken.SaveToFile('C:\token'+inttostr(i2)+'.bin');
                       // send token's header
                       Application.processmessages;

                       currtoken.Seek(0, sofrombeginning);
                       b:=true; PktLen:=$100; k:=1;
                       txBuf[0]:=$40;
                       txBuf[1]:=$60;
                       txBuf[2]:=$01;
                       txBuf[3]:=$00;
                       txBuf[4]:=$00;
                       txBuf[5]:=$00;
                       while (currtoken.position<currtoken.Size) and b do
                       begin
                       if ((currtoken.Size-currtoken.position)<PktLen) and b then //длина последнего кусочка
                       begin
                       b:=false;
                       PktLen:=currtoken.Size-currtoken.position;//последний кусочек лоадера
                       txBuf[2]:=$00;
                       txBuf[6]:=PktLen mod $100;
                       txBuf[7]:=PktLen div $100;
                       end;

                       txBuf[6]:=PktLen mod $100;
                       txBuf[7]:=PktLen div $100;
                       currtoken.ReadBuffer(txBuf[8], PktLen);
                           inc(k);

                       USBControlPacket($222040, $8+PktLen, 0);

                           Form1.pb1.progress:=Form1.pb1.progress+1;
                           Application.ProcessMessages;
                       end;
                       ///////
                       //send cert body
                       currtoken.Seek(10,sofromBeginning);
                       currtoken.ReadBuffer(blklen,4);
                       DWordSwap(@blklen);
                       currcert.CopyFrom(fs,blklen);
                       //currcert.SaveToFile('C:\Cert'+inttostr(i2)+'.bin');
                       Application.processmessages;

                       currcert.Seek(0, sofrombeginning);
                       b:=true; PktLen:=$1000; k:=1;
                       txBuf[0]:=$40;
                       txBuf[1]:=$62;
                       txBuf[2]:=$01;
                       txBuf[3]:=$00;
                       txBuf[4]:=$00;
                       txBuf[5]:=$00;
                       while (currcert.position<currcert.Size) and b do
                       begin
                       if ((currcert.Size-currcert.position)<PktLen) and b then //длина последнего кусочка
                       begin
                       b:=false;
                       PktLen:=currcert.Size-currcert.position;//последний кусочек лоадера
                       txBuf[2]:=$00;
                       txBuf[6]:=PktLen mod $100;
                       txBuf[7]:=PktLen div $100;
                       end;

                       txBuf[6]:=PktLen mod $100;
                       txBuf[7]:=PktLen div $100;
                       currcert.ReadBuffer(txBuf[8], PktLen);
                           inc(k);

                           USBControlPacket($222040, $8+PktLen, 0);
                           Form1.pb1.progress:=Form1.pb1.progress+1;
                           Application.ProcessMessages;
                       end;
                       ///////
                       Application.ProcessMessages;
                       currcert.clear;
                       currtoken.Clear;
                       i2:=i2+1;
                      end;
                    $27: // UPDAPP CERT
                       begin
                       Application.ProcessMessages;
                       good:=0;
                       CurrSeemLen :=buf[2]+1;
                       fs.Seek(fs.Position-4, sofromBeginning);
                       currtoken.CopyFrom(fs,currseemlen+4);
                       currtoken.seek(4,soFromBeginning);
                       currtoken.ReadBuffer(RootInBlock[0], $10);
                      // form1._msg('UPDAPP: '+buftohexstr(@rootinBlock[0], $10));
                       Application.ProcessMessages;
                       for j:=0 to $0f do if RootInBlock[j]=RAPInfo.Root_Key_Hash[j] then inc(good);
                       if good=$10 then
                         begin
                         //currtoken.SaveToFile('C:\token_upd_cert'+inttostr(i2)+'.bin');
                         form1._msg('Processing UPDAPP...');
                         //Form1._msg('Flashing header UpdAPP');
                         // send token's header
                          Application.processmessages;

                           currtoken.Seek(0, sofrombeginning);
                           b:=true; PktLen:=$100; k:=1;
                           txBuf[0]:=$40;
                           txBuf[1]:=$60;
                           txBuf[2]:=$01;
                           txBuf[3]:=$00;
                           txBuf[4]:=$00;
                           txBuf[5]:=$00;
                           while (currtoken.position<currtoken.Size) and b do
                           begin
                           if ((currtoken.Size-currtoken.position)<PktLen) and b then //длина последнего кусочка
                           begin
                           b:=false;
                           PktLen:=currtoken.Size-currtoken.position;//последний кусочек лоадера
                           txBuf[2]:=$00;
                           txBuf[6]:=PktLen mod $100;
                           txBuf[7]:=PktLen div $100;
                           end;

                           txBuf[6]:=PktLen mod $100;
                           txBuf[7]:=PktLen div $100;
                           currtoken.ReadBuffer(txBuf[8], PktLen);
                           inc(k);

                            USBControlPacket($222040, $8+PktLen, 0);
                           Form1.pb1.progress:=Form1.pb1.progress+1;
                           Application.ProcessMessages;
                            end;
                           ///////

                           currtoken.Seek(41,sofromBeginning);
                           currtoken.ReadBuffer(blklen,4);
                           DWordSwap(@blklen);
                           currcert.CopyFrom(fs,blklen);
                          // currcert.SaveToFile('C:\Cert_upd_cert'+inttostr(i2)+'.bin');

                           Application.processmessages;

                           currcert.Seek(0, sofrombeginning);
                           b:=true; PktLen:=$1000; k:=1;
                           txBuf[0]:=$40;
                           txBuf[1]:=$62;
                           txBuf[2]:=$01;
                           txBuf[3]:=$00;
                           txBuf[4]:=$00;
                           txBuf[5]:=$00;
                          while (currcert.position<currcert.Size) and b do
                          begin
                            if ((currcert.Size-currcert.position)<PktLen) and b then //длина последнего кусочка
                            begin
                            b:=false;
                            PktLen:=currcert.Size-currcert.position;//последний кусочек лоадера
                            txBuf[2]:=$00;
                            txBuf[6]:=PktLen mod $100;
                            txBuf[7]:=PktLen div $100;
                            end;

                           txBuf[6]:=PktLen mod $100;
                           txBuf[7]:=PktLen div $100;
                           currcert.ReadBuffer(txBuf[8], PktLen);
                           inc(k);

                           USBControlPacket($222040, $8+PktLen, 0);
                           Form1.pb1.progress:=Form1.pb1.progress+2;
                           Application.ProcessMessages;
                            end;
                           ///////

                         i2:=i2+1;
                         end
                         else begin
                         currtoken.Seek(41,sofromBeginning);
                         currtoken.ReadBuffer(blklen,4);
                         DWordSwap(@blklen);
                         currcert.CopyFrom(fs,blklen);
                         Form1.pb1.progress:=Form1.pb1.progress+1;
                         Application.ProcessMessages;
                         end;
                       Application.ProcessMessages;
                       currcert.clear;
                       currtoken.Clear;
                       end;
                    $28: // PAPUBKEYS match with root
                       begin
                        // form1._msg('PAPUBKEYS detected!');
                         Application.ProcessMessages;
                         good:=0;
                       CurrSeemLen :=buf[2]+1;
                       fs.Seek(fs.Position-4, sofromBeginning);
                       currtoken.CopyFrom(fs,currseemlen+4);
                       currtoken.seek(4,soFromBeginning);
                       currtoken.ReadBuffer(RootInBlock[0], $10);
                       ///form1._msg('PAPUBKEYS:'+buftohexstr(@rootinBlock[0], $10));
                       Application.ProcessMessages;
                       for j:=0 to $0f do if RootInBlock[j]=RAPInfo.Root_Key_Hash[j] then inc(good);
                       if good=$10 then
                         begin
                          form1._msg('Processing PAPUBKEYS...');
                         //currtoken.SaveToFile('C:\token_PAPUB'+inttostr(i2)+'.bin');

                            // send token's header
                           Application.processmessages;

                           currtoken.Seek(0, sofrombeginning);
                           b:=true; PktLen:=$100; k:=1;
                           txBuf[0]:=$40;
                           txBuf[1]:=$60;
                           txBuf[2]:=$01;
                           txBuf[3]:=$00;
                           txBuf[4]:=$00;
                           txBuf[5]:=$00;
                           while (currtoken.position<currtoken.Size) and b do
                           begin
                           if ((currtoken.Size-currtoken.position)<PktLen) and b then //длина последнего кусочка
                           begin
                           b:=false;
                           PktLen:=currtoken.Size-currtoken.position;//последний кусочек лоадера
                           txBuf[2]:=$00;
                           txBuf[6]:=PktLen mod $100;
                           txBuf[7]:=PktLen div $100;
                           end;

                           txBuf[6]:=PktLen mod $100;
                           txBuf[7]:=PktLen div $100;
                           currtoken.ReadBuffer(txBuf[8], PktLen);
                           inc(k);

                            USBControlPacket($222040, $8+PktLen, 0);
                           Form1.pb1.progress:=Form1.pb1.progress+1;
                           Application.ProcessMessages;
                            end;
                           ///////

                         currtoken.Seek(41,sofromBeginning);
                         currtoken.ReadBuffer(blklen,4);
                         DWordSwap(@blklen);
                         currcert.CopyFrom(fs,blklen);
                         //currcert.SaveToFile('C:\PAPUBKEYS'+inttostr(i2)+'.bin');

                         Application.processmessages;

                           currcert.Seek(0, sofrombeginning);
                           b:=true; PktLen:=$1000; k:=1;
                           txBuf[0]:=$40;
                           txBuf[1]:=$62;
                           txBuf[2]:=$01;
                           txBuf[3]:=$00;
                            txBuf[4]:=$00;
                           txBuf[5]:=$00;
                          while (currcert.position<currcert.Size) and b do
                          begin
                            Application.processmessages;
                            if ((currcert.Size-currcert.position)<PktLen) and b then //длина последнего кусочка
                            begin
                            b:=false;
                            PktLen:=currcert.Size-currcert.position;//последний кусочек лоадера
                            txBuf[2]:=$00;
                            txBuf[6]:=PktLen mod $100;
                            txBuf[7]:=PktLen div $100;
                            end;

                           txBuf[6]:=PktLen mod $100;
                           txBuf[7]:=PktLen div $100;
                           currcert.ReadBuffer(txBuf[8], PktLen);
                           inc(k);

                           USBControlPacket($222040, $8+PktLen, 0);
                           Form1.pb1.progress:=Form1.pb1.progress+1;
                           Application.ProcessMessages;
                           end;
                           ///////

                         i2:=i2+1;
                         end
                         else begin
                         currtoken.Seek(41,sofromBeginning);
                         currtoken.ReadBuffer(blklen,4);
                         DWordSwap(@blklen);
                         currcert.CopyFrom(fs,blklen);
                         Form1.pb1.progress:=Form1.pb1.progress+1;
                         Application.processmessages;
                         end;
                       Application.ProcessMessages;
                       currcert.clear;
                       currtoken.Clear;
                       end;
                    $3A:  // finalize command ( last )
                       begin
                       CurrSeemLen :=buf[2]+1;
                       fs.Seek(fs.Position-4, sofromBeginning);
                       currtoken.CopyFrom(fs,currseemlen+4);
                       // send token's header
                          Application.processmessages;

                           currtoken.Seek(0, sofrombeginning);
                           b:=true; PktLen:=$100; k:=1;
                           txBuf[0]:=$40;
                           txBuf[1]:=$60;
                           txBuf[2]:=$01;
                           txBuf[3]:=$00;
                           txBuf[4]:=$00;
                           txBuf[5]:=$00;
                           while (currtoken.position<currtoken.Size) and b do
                           begin
                           if ((currtoken.Size-currtoken.position)<PktLen) and b then //длина последнего кусочка
                           begin
                           b:=false;
                           PktLen:=currtoken.Size-currtoken.position;//последний кусочек лоадера
                           txBuf[2]:=$00;
                           txBuf[6]:=PktLen mod $100;
                           txBuf[7]:=PktLen div $100;
                           end;

                           txBuf[6]:=PktLen mod $100;
                           txBuf[7]:=PktLen div $100;
                           currtoken.ReadBuffer(txBuf[8], PktLen);
                           inc(k);

                           if not  USBControlPacket($222040, $8+PktLen, 0) then
                               begin
                               result:=False;
                               form1.pb1.progress:=0;
                               form1._msg('->  Boot error - device not ready - check battery/connection/HW');
                                currtoken.free;
                                currcert.free;
                               fs.Free;
                               Exit;
                               end;
                           Application.ProcessMessages;
                            end;
                           ///////
                       currtoken.clear;
                       result:=True;
                       Form1.pb1.progress:=Form1.pb1.progress+2;
                       Application.processmessages;
                       end;
                  end;
              end;
          else
            begin
                   fs.ReadBuffer(buf[0], 1);
                   CurrSeemLen:=buf[0];
                   fs.Seek(CurrSeemLen, sofromcurrent);
              end;
         end;
   end;
   Form1.pb1.progress:=0;
   Form1.pb1.maxvalue:=100;
   if Result= True then form1._msg('Boot Done! :)') else begin
   result:=False;
   Form1.pb1.progress:=0;
   Form1.pb1.maxvalue:=100;
   form1._msg('->  Boot error... :(');
   currtoken.free;
   currcert.free;
   Fs.free;
   end;
   Form1.statusbar.Panels[4].Text:='';
   currtoken.free;
   currcert.free;
   Fs.free;
   Application.ProcessMessages;
   i:=0;
    repeat
      begin
      Application.ProcessMessages;
      Inc(i);
      Form1.statusbar.Panels[0].Text:='Wait for phone '+inttostr(2000-i);
      Application.ProcessMessages;
      end;
    until (DevPresent=False) or (i=2000);
    Form1.statusbar.Panels[0].Text:='';
    if i=2000 then
    begin
    result:=false;
    form1._msg('->  Boot error... Phone can'+#39+'t reboot');
    exit;
    end;
    endtimecount;
    Form1._msg('TIME : Boot time : '+showtime(tmsres));
    Application.ProcessMessages;
   except
   result:=False;
   Form1.pb1.progress:=0;
   Form1.pb1.maxvalue:=100;
   form1._msg('->  Boot error... :(');
   currtoken.free;
   currcert.free;
   Fs.free;
   end;

end;



function  BB5_FlashingXSR15():boolean;
var
     b, proto         : Boolean;
     i                : integer;
     rb               : Byte;
     ms               : TMemoryStream;
begin

     Form1._msg('Reopening the connection...');
     Application.ProcessMessages;
     Sleep(500);
     Application.ProcessMessages;
     adlmode:=$00;
     i:=30;
     while i>0 do
     begin
          Form1._msg('Waiting for response: '+inttostr(i));
          Application.ProcessMessages;
          if catchdevice<>$02 then
          begin
          Application.ProcessMessages;
          sleep (1000);
            if stop=True then
            begin
                // Stopping operation
                dostop('FLASH');
                i:=0;
                Form1.pb1.progress:=0;
                StuffFlashReset;
                result:=False;
                Exit;
             end;
          Application.ProcessMessages;
          end
          else i:=0;
          dec(i);
     end;

     if not DevPresent then
     begin
          Form1._msg('Phone not found... :(');
          Form1.SetBuzy;
          Form1.StatusBar.Panels[4].Text:='';
          result:=False;
          USBClosePort;
          exit;
     end;
     fltime:=0;
     //Phone in Flash Mode???
     CheckADLUpload[7]:=msgid;
     CheckADLUpload[8]:=ISIHeaderTransId;
     CheckADLUpload[9]:=$00;
     i:=USBBulkWritePort(@CheckADLUpload, Length(CheckADLUpload));
     if i<>12 then exit;
     USBBulkReadPort(12);

     if rxBuf[11]<>$06 then
     begin
          if rxBuf[11]<>$80 then
          begin
               Form1._msg('ADL Server not confirmed flashmode!');
               Form1._msg('ADL ReqPh : '+byte2str(rxbuf[11]));
               Form1.SetReady;
               result:=False;
               USBClosePort;
               exit;
          end
          else
          begin
               Form1._msg('ADL -> [2nd] changing...');
               rb:=rxBuf[11];
          end;
     end
     else rb:=rxBuf[11];
     adlmode:=rb;
     Form1._msg('ADL Server confirm flashmode!');

     case rb of
     $06: ADL06auth; // 6120, n76........
     $80: ADL80auth; // 5800, n86........
     end;

     selectAsicCMT[3]:=$6F;
     selectAsicCMT[8]:=ISIHeaderTransId;
     USBBulkWritePort(@selectAsicCMT, Length(selectAsicCMT));
     if USBBulkReadPort($FFFF) then
     if rxBuf[10]=$00 then Form1._msg('ADL : ASIC CMT select Ok')
     else Form1._msg('ADL : Select CMT failed, try continue...');

     Application.ProcessMessages;

     //Добавил для удобства кастом-прошивки
     Form1.statusbar.Panels[0].Text:='';
     Form1.statusbar.Panels[1].Text:='';
     Form1.statusbar.Panels[2].Text:='';
     Form1.statusbar.Panels[4].Text:='FLASHING';
     Form1.statusbar.Panels[3].Text:='Connected';
     Form1.TimConChk.Interval:=100;
     Application.ProcessMessages;


      if Form1.chkMCUen.Checked=true then
     begin
          Form1.chkMCUen.Enabled:=False;
          Form1._msg('   ===Flashing [MCU]===');
          if not BB5_EraseFile(core) then begin StuffFlashReset; result:=False; Exit; end;
          Application.ProcessMessages;
          if not BB5_WriteFile(core) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('MCU Write done');
     end;
     Application.ProcessMessages;
     if Form1.chkPPMe.Checked=true then
     begin
            Form1.chkPPMe.Enabled:=False;
            Form1.chkMCUen.Enabled:=False;
          Form1._msg('   ===Flashing [PPM]===');
          if not BB5_EraseFile(ppm) then begin StuffFlashReset; result:=False; Exit; end;
           Application.ProcessMessages;
          if not BB5_WriteFile(ppm) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('PPM Write done');
     end;
     Application.ProcessMessages;
      if Form1.chkPPM1e.Checked=true then
     begin
            Form1.chkPPMe.Enabled:=False;
            Form1.chkMCUen.Enabled:=False;
            Form1.chkPPM1e.Enabled:=False;
          Form1._msg('   ===Flashing [PPM2]===');
          if not BB5_EraseFile(ppm1) then begin StuffFlashReset; result:=False; Exit; end;
           Application.ProcessMessages;
          if not BB5_WriteFile(ppm1) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('PPM Write done');
     end;
     Application.ProcessMessages;
     if Form1.chkCNTe.Checked=true then
     begin
            Form1.chkPPMe.Enabled:=False;
            Form1.chkMCUen.Enabled:=False;
            Form1.chkPPM1e.Enabled:=False;
            Form1.chkCNTe.Enabled:=False;
          Form1._msg('   ===Flashing [CNT]===');
          if not BB5_EraseFile(image) then begin StuffFlashReset; result:=False; Exit; end;
          Application.ProcessMessages;
          if not BB5_WriteFile(image) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('CNT Write done');
     end;
     Application.ProcessMessages;
      if Form1.chkAPEe.Checked=true then
     begin
            Form1.chkPPMe.Enabled:=False;
            Form1.chkMCUen.Enabled:=False;
            Form1.chkPPM1e.Enabled:=False;
            Form1.chkCNTe.Enabled:=False;
            Form1.chkAPEe.Enabled:=False;
          Form1._msg('   ===Flashing [APE]===');
          if not BB5_EraseFile(ape) then begin StuffFlashReset; result:=False; Exit; end;
          Application.ProcessMessages;
          if not BB5_WriteFile(ape) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('APE Write done');
     end;
     Application.ProcessMessages;
     if Form1.chkcnt3.Checked=true then
     begin
            Form1.chkPPMe.Enabled:=False;
            Form1.chkMCUen.Enabled:=False;
            Form1.chkPPM1e.Enabled:=False;
            Form1.chkCNTe.Enabled:=False;
            Form1.chkAPEe.Enabled:=False;
            Form1.chkcnt3.Enabled:=False;
          Form1._msg('   ===Flashing [CNT3]===');
          if not BB5_EraseFile(cnt3) then begin StuffFlashReset; result:=False; Exit; end;
          Application.ProcessMessages;
          if not BB5_WriteFile(cnt3) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('CNT Write done');
     end;
     Application.ProcessMessages;
     // режим рестарта
     AdlRestart06(rb);

     Application.ProcessMessages;
     Form1._msg('');
     Form1._msg('Flashing done!');
     Form1._msg('Total flash time : '+showtime(fltime));
     Form1._msg('Reboot phone now...');
     Form1._msg('');
     Application.ProcessMessages;
     fltime:=0;
     Form1.statusbar.Panels[0].Text:='';
     Form1.pb1.ForeColor:=clNavy;
     Form1.pbsm1.ForeColor:=clNavy;
     Form1.pb1.MaxValue:=100;
     Form1.pb1.progress:=0;
     Form1.statusbar.Panels[1].Text:='';
     Form1.TimConChk.Interval:=2000;

     Form1.pb1.color:=clActiveBorder;
     
     if affenabled then Form1.afterFlashdo;

     Application.ProcessMessages;
     Sleep(200);
     Form1.SetReady;
     Form1.TimConChk.Enabled:=true;
     Form1._msg('Done!');
      Form1.chkPPMe.Enabled:=True;
      Form1.chkMCUen.Enabled:=True;
      Form1.chkPPM1e.Enabled:=True;
      Form1.chkCNTe.Enabled:=True;
      Form1.chkAPEe.Enabled:=True;
      Form1.chkcnt3.Enabled:=True;
     Result:=true;
end;//End of Normal Mode Flashing

function RebuildPartition(F:TMemoryStream; PLen: integer):boolean;
var
 Outstream:TmemoryStream;
 i:Integer;
 buf1:array [0..3] of Byte ;
 buf2:array [0..2] of Byte;
 cf  : byte;
 len : Int64;
 blkcnt:DWORD;
begin
blkcnt:=0;
len:=0;
 case PLen of    // creating partition header, before tokens
 $22:
   Begin
   buf2[0]:=$01;
   buf2[1]:=$06;
   buf2[2]:=$00;
   end;
 $32:
   begin
   buf2[0]:=$02;
   buf2[1]:=$06;
   buf2[2]:=$00;
   end;
 $42:
   begin
   buf2[0]:=$03;
   buf2[1]:=$06;
   buf2[2]:=$00;
   end;
 $52:
   begin
   buf2[0]:=$04;
   buf2[1]:=$06;
   buf2[2]:=$00;
   end;
 $62:
   begin
   buf2[0]:=$05;
   buf2[1]:=$06;
   buf2[2]:=$00;
   end;
 $72:
   begin
   buf2[0]:=$06;
   buf2[1]:=$06;
   buf2[2]:=$00;
   end;
 end;
////////=//////////
   buf1[0]:=$06;  // partiton tokens
   buf1[1]:=$14;
   buf1[2]:=$00;
   buf1[3]:=$00;
   Outstream:=TmemoryStream.Create;
   F.Seek(3, soFromBeginning);
   F.readbuffer(cf,1);
   F.Seek(3, soFromBeginning);
   Outstream.copyFrom(F,3);
   Outstream.Writebuffer(buf2[0],3);
   Outstream.copyfrom(F,8);
   F.ReadBuffer(blkcnt,4);
   DWordSwap(@blkcnt);
   for i:=1 to blkcnt do
   begin
   Outstream.Writebuffer(buf1[0],4);
   Outstream.copyfrom(F,16);
   end;
////1B 00 10 6F 00 62 00 15 75 10
////1B 00 10 21 00 4E 00 12 11 10
////build frame
txBuf[0]:=$1B;
txBuf[1]:=$00;
txBuf[2]:=$10;
case cf of         // maybee ape exist?
0:txBuf[3]:=$6F;   //cmt
1:txBuf[3]:=$21;  // ape
else txBuf[3]:=$6F;  // anyway, if not detected - will be CMT
end;
txBuf[6]:=$00;
txBuf[7]:=$0F;
txBuf[8]:=ISIHeaderTransId;
txBuf[9]:=$10;
len:=Outstream.size;
outstream.seek(0,soFromBeginning);
outstream.ReadBuffer(txBuf[10], len);
txBuf[4]:=(len+4) div $100; // build framelen
txBuf[5]:=(len+4) mod $100;
//form1._msg('buf : '+buftohexstr(@txbuf[0],len+$0A));
USBBulkWritePort(@txbuf[0],len+$A); // send data
 if USBBulkReadPort($FFFF) then begin
 if (rxBuf[10]=0) and (rxBuf[11]=0 ) then begin // Check buffer for answer - should be 00 00
 Form1._msg('Partitioning : Ok ['+inttostr(blkcnt+1)+']');
 result:=true;
 end
 else
 begin
 Form1._msg('Partitioning : Error :(');
 result:=False;
 end;
 end;
Application.ProcessMessages;
//Outstream.SaveToFile('C:\Data.bin');
Outstream.Free;
end;

function s60checkadl():Byte;
begin
///1B 10 00 6F 00 06 17 37 08 20 00 07
///1B 00 10 6F 00 06 00 17 08 00 00 00
AdlCheckst[8]:=ISIHeaderTransId;
USBBulkWritePort(@AdlCheckst[0], Length(AdlCheckst));
 If USBBulkReadPort($FFFF) then begin
 result:=rxbuf[11];
 end;
end;


function ADLBootInFlash():Boolean;
var
  n:Integer;
begin
 ///1B 00 10 6F 00 06 00 14 09 04 00 00  - reboot in flash mode
Application.ProcessMessages;
 ADLReboot[8]:=ISIHeaderTransId;
 n:=USBBulkWritePort(@AdlReboot[0], Length(ADLReboot));
 if n<>12 then begin
  result:=False;
  Exit;
  end;

  n:=200;
  repeat
  begin
  Sleep(50);
  Application.ProcessMessages;
  dec(n);
  end;
  until (DevPresent=False) or (n=0);
 if n=0 then result:=False else result:=True;
end;

function ADL06auth ():Boolean;
var
  len:Byte;
begin
USBBulkWritePort(@GetRootAsic, Length(GetRootAsic));
if USBBulkReadPort($FFFF) then //form1._msg(BufToHexStr(@rxBuf[0], Length(rxBuf)));
 len:=rxBuf[10];
 if len>0 then begin
 bufcopy(@rxBuf[14],@txbuf[10],len);
 //1B00106F002E000F0406
 txbuf[0]:=$1B;
 txbuf[1]:=$00;
 txbuf[2]:=$10;
 txbuf[3]:=$6F;
 txbuf[4]:=$00;
 txbuf[5]:=len+4;
 txbuf[6]:=$00;
 txbuf[7]:=$0F;
 txbuf[8]:=$04;
 txbuf[9]:=$06;
 USBBulkWritePort(@txbuf[0], len+$A);
  if USBBulkReadPort($FFF) then begin
   if rxBuf[10]<>0 then result:=true else result:=false;
  end;
 end
 else begin
 form1._msg('Get req info : empty');

 end;
end;

function AdlRestart06 (rb:byte):Boolean;
var
  i:integer;
begin
  result:=false;
  case rb of
  $80:
   begin
     Form1._msg(' =================');
     Form1._msg('ADL : End flashing');
    AdlPreBootReq[8]:=ISIHeaderTransId;
    USBBulkWritePort(@AdlPreBootReq, Length(AdlPreBootReq));
    if USBBulkReadPort($FFF) then begin
    if rxBuf[9]=$29 then Form1._msg('ADL : Finalize...');
     i:=USBBulkWritePort(@adlrestersxr15, Length(adlrestersxr15));
    if i<>12 then form1._msg('Error while rebooting :(');
    Application.ProcessMessages;
    end;
   end;
  $06:
   begin
   Form1._msg(' =================');
   Form1._msg('ADL : End flashing');
   AdlPreBootReq[8]:=ISIHeaderTransId;
    USBBulkWritePort(@AdlPreBootReq, Length(AdlPreBootReq));
    if USBBulkReadPort($FFF) then begin
    if rxBuf[9]=$29 then Form1._msg('ADL : Finalize...');
     i:=USBBulkWritePort(@adlrestersxr15, Length(adlrestersxr15));
    if i<>12 then form1._msg('Error while rebooting :(');
    Application.ProcessMessages;
   end;
  end;
  end;
end;

function ADL80auth ():Boolean;
var
  len:Byte;
begin
  result:=False;
ReqAdl80[8]:=ISIHeaderTransId;
USBBulkWritePort(@ReqAdl80, Length(ReqAdl80));
 if USBBulkReadPort($FFF) then begin
 if rxbuf[11]<>$01 then  exit;
 ADL80RootReq[8]:=ISIHeaderTransId;
    USBBulkWritePort(@ADL80RootReq, Length(ADL80RootReq));
 if USBBulkReadPort($FFF) then
                          begin
                          Application.ProcessMessages;
                          end;
 Flastartreq[8]:=ISIHeaderTransId;
  USBBulkWritePort(@Flastartreq, Length(Flastartreq));
 if USBBulkReadPort($FFF) then
                          begin
                            if rxbuf[10]<>$01 then Exit;
                          Application.ProcessMessages;
                          end;
 result:=True;
 form1._msg('ADL : Auth done...');
 end;
end;

function OMAP2420boot () : boolean;
var
  CMTadl, APEadl:TMemoryStream;
  b             :Boolean;
  tmp           :array of Byte;
  CHK, pktlen   :Word;
  k             :Integer;
  i             :Word;
begin

// mdstart
adlstartmode[8]:=ISIHeaderTransId;
adlstartmode[7]:= $14;
USBBulkWritePort(@adlstartmode, Length(adlstartmode));
 If USBBulkReadPort($FFFF) then
 begin
 Application.ProcessMessages;
 //Form1._msg(BufToHexStr(@rxBuf[0], Length(rxBuf)));
 end;

CMTadl:=TMemoryStream.Create;
BB5_ExtractCertData(core,'UPDAPP', CMTAdl, b, false);
///CMTAdl.SaveToFile('C:\ADL.bin');
CMTAdl.Seek(0, soFromBeginning);
     SetLength(tmp, CMTAdl.Size);
     if CMTAdl.size=0 then begin
     result:=False;
     Exit;
     end;
     CMTAdl.ReadBuffer(tmp[0], CMTAdl.Size);
     CHK:=GetLoaderCRC(@tmp[0], CMTAdl.Size);
Form1._msg('CMT Loader len: '+inttostr(CMTAdl.Size)+', CHK: '+inttohex(CHK, 4));
Application.ProcessMessages;
Form1._msg('Sending CMT boot....');
// sending CRC and len of loader
Sendomapcrcadl[7]:= $14;
Sendomapcrcadl[8]:=ISIHeaderTransId;
Sendomapcrcadl[12]:=CMTAdl.Size div $1000000;
Sendomapcrcadl[13]:=CMTAdl.Size div $10000;
Sendomapcrcadl[14]:=CMTAdl.Size div $100;
Sendomapcrcadl[15]:=CMTAdl.Size mod $100;
Sendomapcrcadl[16]:=CHK div $100;
Sendomapcrcadl[17]:=CHK mod $100;
USBBulkWritePort(@sendomapcrcadl, Length(Sendomapcrcadl));
 If USBBulkReadPort($FFFF) then begin
 //Form1._msg(buftohexstr(@rxBuf[0],Length(rxBuf)));
 if rxBuf[11]<>0 then Form1._msg('Accept error, skip');
 end;


     //Отправка агента по кусочкам
     b:=true;
     i:=1;//номер сообщения
     MsgBody:=2;//номер сообщения
     PktLen:=$0780;//длина отправляемого кусочка лоадера (длина как в Фениксе)
     Form1.pb1.Progress:=0;
     //ms:=TMemoryStream.Create;//для теста и сохранения текущего отправленного кусочка
     BufCopy(@Sendomapadl[0], @txBuf[0], Length(Sendomapadl));
     //SendADL    : array[0..15] of Byte =
     //($1B, $00, $10, $6F, $07, $8A, $00, $15, $56, $03, $00, $01, $00, $00, $07, $80);
     txBuf[8]  := ISIHeaderTransId;
     CMTAdl.Seek(0, sofromBeginning);
     Application.ProcessMessages;
     while (CMTAdl.Position+PktLen)<=CMTAdl.Size do
     begin
          CMTAdl.ReadBuffer(txBuf[16], PktLen);
          Word((@txBuf[4])^):=Swap(PktLen+$0A);
          txBuf[3]  :=$6F;
          txBuf[7]  := $14;
          txBuf[8]  := ISIHeaderTransId;
          Word((@txBuf[10])^):=Swap(i);
          Word((@txBuf[14])^):=Swap(PktLen);

          //Только для сохранения отправляемых кусочков агента
          {ms.Seek(0, soFromBeginning);
          ms.WriteBuffer(txBuf[0], 16);
          ms.WriteBuffer(txBuf[16], PktLen);
          ms.SaveToFile('C:\ADL_Send\'+Int2Digs(i,4)+'.bin');
          ms.Clear;}

          k:=USBBulkWritePort(@txbuf[0], (PktLen+$10));
          if k<>(PktLen+$10) then
          begin
               Form1.pb1.progress:=0;
               Form1._msg('Error while boot... :(');
               Form1._msg('');
               USBClosePort;
               exit;
          end;

          USBBulkReadPort(16);

          if ((CMTAdl.Size-CMTAdl.position)<PktLen) and b then //длина последнего кусочка
          begin
               PktLen:=CMTAdl.Size-CMTAdl.position;//последний кусочек агента
               b:=false;
          end;
          inc(i);
          Form1.pb1.Progress:=(CMTAdl.Position*100) div CMTAdl.Size;
     end;
     //ms.free;
     Form1.pb1.Progress:=0;

CMTAdl.Free;

APEadl:=TMemoryStream.Create;
BB5_ExtractCertData(core,'UPDAPP', APEadl, b, true);
///APEadl.SaveToFile('C:\ADL_APE.bin');
APEadl.Seek(0, soFromBeginning);
     SetLength(tmp, APEadl.Size);
     if APEadl.size=0 then begin
     Result:=false;
     Exit;
     end;
     APEadl.ReadBuffer(tmp[0], APEadl.Size);
     CHK:=GetLoaderCRC(@tmp[0], APEadl.Size);
     Form1._msg('APE Loader len: '+inttostr(APEadl.Size)+', CHK: '+inttohex(CHK, 4));
// send APE data len
SendaAPecrcadl[7]:=$14;
SendaAPecrcadl[8]:=ISIHeaderTransId;
SendaAPecrcadl[12]:=APEadl.Size div $1000000;
SendaAPecrcadl[13]:=APEadl.Size div $10000;
SendaAPecrcadl[14]:=APEadl.Size div $100;
SendaAPecrcadl[15]:=APEadl.Size mod $100;
USBBulkWritePort(@SendaAPecrcadl, Length(SendaAPecrcadl));
 If USBBulkReadPort($FFFF) then begin
 //Form1._msg(buftohexstr(@rxBuf[0],Length(rxBuf)));
 if rxBuf[11]<>0 then Form1._msg('Accept error, skip');
 end;
Application.ProcessMessages;
Form1._msg('Sending APE boot....');
 //Отправка агента по кусочкам
     b:=true;
     i:=1;//номер сообщения
     MsgBody:=2;//номер сообщения
     PktLen:=$0780;//длина отправляемого кусочка лоадера (длина как в Фениксе)
     Form1.pb1.Progress:=0;
     //ms:=TMemoryStream.Create;//для теста и сохранения текущего отправленного кусочка
     BufCopy(@Sendomapadl[0], @txBuf[0], Length(Sendomapadl));
     //SendADL    : array[0..15] of Byte =
     //($1B, $00, $10, $6F, $07, $8A, $00, $15, $56, $03, $00, $01, $00, $00, $07, $80);
     txBuf[8]  := ISIHeaderTransId;
     APEAdl.Seek(0, sofromBeginning);
     Application.ProcessMessages;
     while (APEAdl.Position+PktLen)<=APEAdl.Size do
     begin
          APEAdl.ReadBuffer(txBuf[16], PktLen);
          Word((@txBuf[4])^):=Swap(PktLen+$0A);
          txBuf[3]  := $21;
          txBuf[7]  := $14;
          txBuf[8]  := ISIHeaderTransId;
          Word((@txBuf[10])^):=Swap(i);
          Word((@txBuf[14])^):=Swap(PktLen);

          k:=USBBulkWritePort(@txbuf[0], (PktLen+$10));
          if k<>(PktLen+$10) then
          begin
               Form1.pb1.progress:=0;
               Form1._msg('Error while boot... :(');
               Form1._msg('');
               USBClosePort;
               exit;
          end;

          USBBulkReadPort(16);

          if ((APEAdl.Size-APEAdl.position)<PktLen) and b then //длина последнего кусочка
          begin
               PktLen:=APEAdl.Size-APEAdl.position;//последний кусочек агента
               b:=false;
          end;
          inc(i);
          Form1.pb1.Progress:=(APEAdl.Position*100) div APEAdl.Size;
     end;
     //ms.free;
     Form1.pb1.Progress:=0;
APEadl.Free;

Aperestartreq1[8]:=ISiheaderTransId;
Aperestartreq1[3]:=$6F;
Aperestartreq1[7]:=$14;
 UsbbulkWritePort(@Aperestartreq1, length(Aperestartreq1));
  If usbbulkreadport($FFFF) then begin
    if (rxbuf[9]=$29) and (rxbuf[10]=0) then begin
     Aperestartreq1[3]:=$21;
     Aperestartreq1[7]:= $14;
     Aperestartreq1[8]:=ISiheaderTransId;
     UsbbulkWritePort(@Aperestartreq1, length(Aperestartreq1));
     If usbbulkreadport($FFFF) then begin
       if (rxbuf[9]=$29) and (rxbuf[10]=0) then begin
        Application.ProcessMessages;
        end else begin form1._msg('Reboot fail :('); exit; end;
     end;

    end else begin
     UsbbulkWritePort(@Aperestartreq1, length(Aperestartreq1));
     If usbbulkreadport($FFFF) then begin
       if (rxbuf[9]=$29) and (rxbuf[10]=0) then begin
       Aperestartreq1[3]:=$21;
        Aperestartreq1[7]:= $14;
        Aperestartreq1[8]:=ISiheaderTransId;
        UsbbulkWritePort(@Aperestartreq1, length(Aperestartreq1));
         If usbbulkreadport($FFFF) then begin
           if (rxbuf[9]=$29) and (rxbuf[10]=0) then begin
           Application.ProcessMessages;
           end else begin form1._msg('Reboot fail :('); exit; end;
          end;

        end
        else begin form1._msg('Reboot fail :('); exit; end;
       end;
    end;


  end;
USBBulkWritePort(@RestartADl, Length(RestartADl));
Application.ProcessMessages;
  i:=0;
  repeat
  begin
  application.ProcessMessages;
  sleep(10);
  inc(i);
  end;
  until (devpresent=false) or (i=700);
  if i=700 then begin result:=False; form1._msg('Reboot failed!'); Exit; end;
Form1._msg('Boot done');
result:=true;
end;

function OMAP1710boot () : boolean;
var
  CMTadl, APEadl:TMemoryStream;
  b             :Boolean;
  tmp           :array of Byte;
  CHK, pktlen   :Word;
  k             :Integer;
  i             :Word;
begin

// mdstart
adlstartmode[8]:=ISIHeaderTransId;
USBBulkWritePort(@adlstartmode, Length(adlstartmode));
 If USBBulkReadPort($FFFF) then
 begin
 Application.ProcessMessages;
 //Form1._msg(BufToHexStr(@rxBuf[0], Length(rxBuf)));
 end;

CMTadl:=TMemoryStream.Create;
BB5_ExtractCertData(core,'ADL', CMTAdl, b, false);
//CMTAdl.SaveToFile('C:\ADL.bin');
CMTAdl.Seek(0, soFromBeginning);
     SetLength(tmp, CMTAdl.Size);
     if CMTAdl.size=0 then begin
     result:=False;
     Exit;
     end;
     CMTAdl.ReadBuffer(tmp[0], CMTAdl.Size);
     CHK:=GetLoaderCRC(@tmp[0], CMTAdl.Size);
Form1._msg('CMT Loader len: '+inttostr(CMTAdl.Size)+', CHK: '+inttohex(CHK, 4));
Application.ProcessMessages;
Form1._msg('Sending CMT boot....');
// sending CRC and len of loader
Sendomapcrcadl[7]:= $18;
Sendomapcrcadl[8]:=ISIHeaderTransId;
Sendomapcrcadl[12]:=CMTAdl.Size div $1000000;
Sendomapcrcadl[13]:=CMTAdl.Size div $10000;
Sendomapcrcadl[14]:=CMTAdl.Size div $100;
Sendomapcrcadl[15]:=CMTAdl.Size mod $100;
Sendomapcrcadl[16]:=CHK div $100;
Sendomapcrcadl[17]:=CHK mod $100;
USBBulkWritePort(@sendomapcrcadl, Length(Sendomapcrcadl));
 If USBBulkReadPort($FFFF) then begin
 //Form1._msg(buftohexstr(@rxBuf[0],Length(rxBuf)));
 if rxBuf[11]<>0 then Form1._msg('Accept error, skip');
 end;


     //Отправка агента по кусочкам
     b:=true;
     i:=1;//номер сообщения
     MsgBody:=2;//номер сообщения
     PktLen:=$0780;//длина отправляемого кусочка лоадера (длина как в Фениксе)
     Form1.pb1.Progress:=0;
     //ms:=TMemoryStream.Create;//для теста и сохранения текущего отправленного кусочка
     BufCopy(@Sendomapadl[0], @txBuf[0], Length(Sendomapadl));
     //SendADL    : array[0..15] of Byte =
     //($1B, $00, $10, $6F, $07, $8A, $00, $15, $56, $03, $00, $01, $00, $00, $07, $80);
     txBuf[8]  := ISIHeaderTransId;
     CMTAdl.Seek(0, sofromBeginning);
     Application.ProcessMessages;
     while (CMTAdl.Position+PktLen)<=CMTAdl.Size do
     begin
          CMTAdl.ReadBuffer(txBuf[16], PktLen);
          Word((@txBuf[4])^):=Swap(PktLen+$0A);
          txBuf[3]  :=$6F;
          txBuf[7]  := $18;
          txBuf[8]  := ISIHeaderTransId;
          Word((@txBuf[10])^):=Swap(i);
          Word((@txBuf[14])^):=Swap(PktLen);

          //Только для сохранения отправляемых кусочков агента
          {ms.Seek(0, soFromBeginning);
          ms.WriteBuffer(txBuf[0], 16);
          ms.WriteBuffer(txBuf[16], PktLen);
          ms.SaveToFile('C:\ADL_Send\'+Int2Digs(i,4)+'.bin');
          ms.Clear;}

          k:=USBBulkWritePort(@txbuf[0], (PktLen+$10));
          if k<>(PktLen+$10) then
          begin
               USBClosePort;
               Form1._msg('Error while boot... :(');
               Form1._msg('');
               exit;
          end;

          USBBulkReadPort(16);

          if ((CMTAdl.Size-CMTAdl.position)<PktLen) and b then //длина последнего кусочка
          begin
               PktLen:=CMTAdl.Size-CMTAdl.position;//последний кусочек агента
               b:=false;
          end;
          inc(i);
          Form1.pb1.Progress:=(CMTAdl.Position*100) div CMTAdl.Size;
     end;
     //ms.free;
     Form1.pb1.Progress:=0;

CMTAdl.Free;

APEadl:=TMemoryStream.Create;
BB5_ExtractCertData(core,'ADL', APEadl, b, true);
//APEadl.SaveToFile('C:\ADL_APE.bin');
APEadl.Seek(0, soFromBeginning);
     SetLength(tmp, APEadl.Size);
     if APEadl.size=0 then begin
     Result:=false;
     Exit;
     end;
     APEadl.ReadBuffer(tmp[0], APEadl.Size);
     CHK:=GetLoaderCRC(@tmp[0], APEadl.Size);
     Form1._msg('APE Loader len: '+inttostr(APEadl.Size)+', CHK: '+inttohex(CHK, 4));
// send APE data len
SendaAPecrcadl[7]:=$18;
SendaAPecrcadl[8]:=ISIHeaderTransId;
SendaAPecrcadl[12]:=APEadl.Size div $1000000;
SendaAPecrcadl[13]:=APEadl.Size div $10000;
SendaAPecrcadl[14]:=APEadl.Size div $100;
SendaAPecrcadl[15]:=APEadl.Size mod $100;
USBBulkWritePort(@SendaAPecrcadl, Length(SendaAPecrcadl));
 If USBBulkReadPort($FFFF) then begin
 //Form1._msg(buftohexstr(@rxBuf[0],Length(rxBuf)));
 if rxBuf[11]<>0 then Form1._msg('Accept error, skip');
 end;
Application.ProcessMessages;
Form1._msg('Sending APE boot....');
 //Отправка агента по кусочкам
     b:=true;
     i:=1;//номер сообщения
     MsgBody:=2;//номер сообщения
     PktLen:=$0780;//длина отправляемого кусочка лоадера (длина как в Фениксе)
     Form1.pb1.Progress:=0;
     //ms:=TMemoryStream.Create;//для теста и сохранения текущего отправленного кусочка
     BufCopy(@Sendomapadl[0], @txBuf[0], Length(Sendomapadl));
     //SendADL    : array[0..15] of Byte =
     //($1B, $00, $10, $6F, $07, $8A, $00, $15, $56, $03, $00, $01, $00, $00, $07, $80);
     txBuf[8]  := ISIHeaderTransId;
     APEAdl.Seek(0, sofromBeginning);
     Application.ProcessMessages;
     while (APEAdl.Position+PktLen)<=APEAdl.Size do
     begin
          APEAdl.ReadBuffer(txBuf[16], PktLen);
          Word((@txBuf[4])^):=Swap(PktLen+$0A);
          txBuf[3]  := $21;
          txBuf[7]  := $18;
          txBuf[8]  := ISIHeaderTransId;
          Word((@txBuf[10])^):=Swap(i);
          Word((@txBuf[14])^):=Swap(PktLen);

          k:=USBBulkWritePort(@txbuf[0], (PktLen+$10));
          if k<>(PktLen+$10) then
          begin
               USBClosePort;
               Form1._msg('Error while boot... :(');
               Form1._msg('');
               exit;
          end;

          USBBulkReadPort(16);

          if ((APEAdl.Size-APEAdl.position)<PktLen) and b then //длина последнего кусочка
          begin
               PktLen:=APEAdl.Size-APEAdl.position;//последний кусочек агента
               b:=false;
          end;
          inc(i);
          Form1.pb1.Progress:=(APEAdl.Position*100) div APEAdl.Size;
     end;
     //ms.free;
     Form1.pb1.Progress:=0;
APEadl.Free;

Aperestartreq1[8]:=ISiheaderTransId;
Aperestartreq1[3]:=$6F;
 UsbbulkWritePort(@Aperestartreq1, length(Aperestartreq1));
  If usbbulkreadport($FFFF) then begin
    if (rxbuf[9]=$29) and (rxbuf[10]=0) then begin
     Aperestartreq1[3]:=$21;
     Aperestartreq1[7]:= $18;
     Aperestartreq1[8]:=ISiheaderTransId;
     UsbbulkWritePort(@Aperestartreq1, length(Aperestartreq1));
     If usbbulkreadport($FFFF) then begin
       if (rxbuf[9]=$29) and (rxbuf[10]=0) then begin
        Application.ProcessMessages;
        end else begin form1._msg('Reboot fail :('); exit; end;
     end;

    end else begin
     UsbbulkWritePort(@Aperestartreq1, length(Aperestartreq1));
     If usbbulkreadport($FFFF) then begin
       if (rxbuf[9]=$29) and (rxbuf[10]=0) then begin
       Aperestartreq1[3]:=$21;
        Aperestartreq1[7]:= $18;
        Aperestartreq1[8]:=ISiheaderTransId;
        UsbbulkWritePort(@Aperestartreq1, length(Aperestartreq1));
         If usbbulkreadport($FFFF) then begin
           if (rxbuf[9]=$29) and (rxbuf[10]=0) then begin
           Application.ProcessMessages;
           end else begin form1._msg('Reboot fail :('); exit; end;
          end;

        end
        else begin form1._msg('Reboot fail :('); exit; end;
       end;
    end;


  end;
USBBulkWritePort(@RestartADl, Length(RestartADl));
Application.ProcessMessages;
  i:=0;
  repeat
  begin
  application.ProcessMessages;
  sleep(10);
  inc(i);
  end;
  until (devpresent=false) or (i=700);
  if i=700 then begin result:=False; form1._msg('Reboot failed!'); Exit; end;
Form1._msg('Boot done');
result:=true;
end;

function OMAP1610boot () : boolean;
var
  CMTadl, APEadl:TMemoryStream;
  b             :Boolean;
  tmp           :array of Byte;
  CHK, pktlen   :Word;
  k             :Integer;
  i             :Word;
begin

result:=False;
// mdstart
adlstartmode[8]:=ISIHeaderTransId;
USBBulkWritePort(@adlstartmode, Length(adlstartmode));
 If USBBulkReadPort($FFFF) then
 begin
 Application.ProcessMessages;
 //Form1._msg(BufToHexStr(@rxBuf[0], Length(rxBuf)));
 end;

CMTadl:=TMemoryStream.Create;
if not Omap1610extrboot('CMT') then Exit;
CMTadl.LoadFromStream(Omap1610);
//CMTAdl.SaveToFile('C:\ADL.bin');
CMTAdl.Seek(0, soFromBeginning);
     SetLength(tmp, CMTAdl.Size);
     if CMTAdl.size=0 then begin
     result:=False;
     Exit;
     end;
     CMTAdl.ReadBuffer(tmp[0], CMTAdl.Size);
     CHK:=GetLoaderCRC(@tmp[0], CMTAdl.Size);
Form1._msg('CMT Loader len: '+inttostr(CMTAdl.Size)+', CHK: '+inttohex(CHK, 4));
Application.ProcessMessages;
Form1._msg('Sending CMT boot....');
// sending CRC and len of loader
Sendomapcrcadl[7]:= $18;
Sendomapcrcadl[8]:=ISIHeaderTransId;
Sendomapcrcadl[12]:=CMTAdl.Size div $1000000;
Sendomapcrcadl[13]:=CMTAdl.Size div $10000;
Sendomapcrcadl[14]:=CMTAdl.Size div $100;
Sendomapcrcadl[15]:=CMTAdl.Size mod $100;
Sendomapcrcadl[16]:=CHK div $100;
Sendomapcrcadl[17]:=CHK mod $100;
USBBulkWritePort(@sendomapcrcadl, Length(Sendomapcrcadl));
 If USBBulkReadPort($FFFF) then begin
 //Form1._msg(buftohexstr(@rxBuf[0],Length(rxBuf)));
 if rxBuf[11]<>0 then Form1._msg('Accept error, skip');
 end;


     //Отправка агента по кусочкам
     b:=true;
     i:=1;//номер сообщения
     MsgBody:=2;//номер сообщения
     PktLen:=$0780;//длина отправляемого кусочка лоадера (длина как в Фениксе)
     Form1.pb1.Progress:=0;
     //ms:=TMemoryStream.Create;//для теста и сохранения текущего отправленного кусочка
     BufCopy(@Sendomapadl[0], @txBuf[0], Length(Sendomapadl));
     //SendADL    : array[0..15] of Byte =
     //($1B, $00, $10, $6F, $07, $8A, $00, $15, $56, $03, $00, $01, $00, $00, $07, $80);
     txBuf[8]  := ISIHeaderTransId;
     CMTAdl.Seek(0, sofromBeginning);
     Application.ProcessMessages;
     while (CMTAdl.Position+PktLen)<=CMTAdl.Size do
     begin
          CMTAdl.ReadBuffer(txBuf[16], PktLen);
          Word((@txBuf[4])^):=Swap(PktLen+$0A);
          txBuf[3]  :=$6F;
          txBuf[7]  := $18;
          txBuf[8]  := ISIHeaderTransId;
          Word((@txBuf[10])^):=Swap(i);
          Word((@txBuf[14])^):=Swap(PktLen);

          //Только для сохранения отправляемых кусочков агента
          {ms.Seek(0, soFromBeginning);
          ms.WriteBuffer(txBuf[0], 16);
          ms.WriteBuffer(txBuf[16], PktLen);
          ms.SaveToFile('C:\ADL_Send\'+Int2Digs(i,4)+'.bin');
          ms.Clear;}

          k:=USBBulkWritePort(@txbuf[0], (PktLen+$10));
          if k<>(PktLen+$10) then
          begin
               USBClosePort;
               Form1._msg('Error while boot... :(');
               Form1._msg('');
               exit;
          end;

          USBBulkReadPort(16);

          if ((CMTAdl.Size-CMTAdl.position)<PktLen) and b then //длина последнего кусочка
          begin
               PktLen:=CMTAdl.Size-CMTAdl.position;//последний кусочек агента
               b:=false;
          end;
          inc(i);
          Form1.pb1.Progress:=(CMTAdl.Position*100) div CMTAdl.Size;
     end;
     //ms.free;
     Form1.pb1.Progress:=0;
CMTAdl.Free;
OMAP1610.Free;
Application.ProcessMessages;
APEadl:=TMemoryStream.Create;
if not Omap1610extrboot('APE') then Exit;
ApeAdl.LoadFromStream(Omap1610);
//APEadl.SaveToFile('C:\ADL_APE.bin');
APEadl.Seek(0, soFromBeginning);
     SetLength(tmp, APEadl.Size);
     if APEadl.size=0 then begin
     Result:=false;
     Exit;
     end;
     APEadl.ReadBuffer(tmp[0], APEadl.Size);
     CHK:=GetLoaderCRC(@tmp[0], APEadl.Size);
     Form1._msg('APE Loader len: '+inttostr(APEadl.Size)+', CHK: '+inttohex(CHK, 4));
// send APE data len
SendaAPecrcadl[7]:=$18;
SendaAPecrcadl[8]:=ISIHeaderTransId;
SendaAPecrcadl[12]:=APEadl.Size div $1000000;
SendaAPecrcadl[13]:=APEadl.Size div $10000;
SendaAPecrcadl[14]:=APEadl.Size div $100;
SendaAPecrcadl[15]:=APEadl.Size mod $100;
USBBulkWritePort(@SendaAPecrcadl, Length(SendaAPecrcadl));
 If USBBulkReadPort($FFFF) then begin
 //Form1._msg(buftohexstr(@rxBuf[0],Length(rxBuf)));
 if rxBuf[11]<>0 then Form1._msg('Accept error, skip');
 end;
Application.ProcessMessages;
Form1._msg('Sending APE boot....');
 //Отправка агента по кусочкам
     b:=true;
     i:=1;//номер сообщения
     MsgBody:=2;//номер сообщения
     PktLen:=$0780;//длина отправляемого кусочка лоадера (длина как в Фениксе)
     Form1.pb1.Progress:=0;
     //ms:=TMemoryStream.Create;//для теста и сохранения текущего отправленного кусочка
     BufCopy(@Sendomapadl[0], @txBuf[0], Length(Sendomapadl));
     //SendADL    : array[0..15] of Byte =
     //($1B, $00, $10, $6F, $07, $8A, $00, $15, $56, $03, $00, $01, $00, $00, $07, $80);
     txBuf[8]  := ISIHeaderTransId;
     APEAdl.Seek(0, sofromBeginning);
     Application.ProcessMessages;
     while (APEAdl.Position+PktLen)<=APEAdl.Size do
     begin
          APEAdl.ReadBuffer(txBuf[16], PktLen);
          Word((@txBuf[4])^):=Swap(PktLen+$0A);
          txBuf[3]  := $21;
          txBuf[7]  := $18;
          txBuf[8]  := ISIHeaderTransId;
          Word((@txBuf[10])^):=Swap(i);
          Word((@txBuf[14])^):=Swap(PktLen);

          k:=USBBulkWritePort(@txbuf[0], (PktLen+$10));
          if k<>(PktLen+$10) then
          begin
               USBClosePort;
               Form1._msg('Error while boot... :(');
               Form1._msg('');
               exit;
          end;

          USBBulkReadPort(16);

          if ((APEAdl.Size-APEAdl.position)<PktLen) and b then //длина последнего кусочка
          begin
               PktLen:=APEAdl.Size-APEAdl.position;//последний кусочек агента
               b:=false;
          end;
          inc(i);
          Form1.pb1.Progress:=(APEAdl.Position*100) div APEAdl.Size;
     end;
     //ms.free;
     Form1.pb1.Progress:=0;
APEadl.Free;
OMAP1610.Free;
Application.ProcessMessages;
Aperestartreq1[8]:=ISiheaderTransId;
Aperestartreq1[3]:=$6F;
 UsbbulkWritePort(@Aperestartreq1, length(Aperestartreq1));
  If usbbulkreadport($FFFF) then begin
    if (rxbuf[9]=$29) and (rxbuf[10]=0) then begin
     Aperestartreq1[3]:=$21;
     Aperestartreq1[7]:= $18;
     Aperestartreq1[8]:=ISiheaderTransId;
     UsbbulkWritePort(@Aperestartreq1, length(Aperestartreq1));
     If usbbulkreadport($FFFF) then begin
       if (rxbuf[9]=$29) and (rxbuf[10]=0) then begin
        Application.ProcessMessages;
        end else begin form1._msg('Reboot fail :('); exit; end;
     end;

    end else begin
     UsbbulkWritePort(@Aperestartreq1, length(Aperestartreq1));
     If usbbulkreadport($FFFF) then begin
       if (rxbuf[9]=$29) and (rxbuf[10]=0) then begin
       Aperestartreq1[3]:=$21;
        Aperestartreq1[7]:= $18;
        Aperestartreq1[8]:=ISiheaderTransId;
        UsbbulkWritePort(@Aperestartreq1, length(Aperestartreq1));
         If usbbulkreadport($FFFF) then begin
           if (rxbuf[9]=$29) and (rxbuf[10]=0) then begin
           Application.ProcessMessages;
           end else begin form1._msg('Reboot fail :('); exit; end;
          end;

        end
        else begin form1._msg('Reboot fail :('); exit; end;
       end;
    end;


  end;
USBBulkWritePort(@RestartADl, Length(RestartADl));
Application.ProcessMessages;
  i:=0;
  repeat
  begin
  application.ProcessMessages;
  sleep(10);
  inc(i);
  end;
  until (devpresent=false) or (i=700);
  if i=700 then begin result:=False; form1._msg('Reboot failed!'); Exit; end;
Form1._msg('Boot done');
result:=true;
end;

function OMAPFlash():Boolean;
var
     b, proto         : Boolean;
     i                : integer;
     rb               : Byte;
     ms               : TMemoryStream;
begin
     result:=False;
     Form1._msg('Reopening the connection...');
     Application.ProcessMessages;
     Sleep(500);
     Application.ProcessMessages;

     i:=30;
     while i>0 do
     begin
          Form1._msg('Waiting for response: '+inttostr(i));
          Application.ProcessMessages;
          if catchdevice<>$02 then
          begin
          Application.ProcessMessages;
          sleep (1500);
          Application.ProcessMessages;
            if stop=True then
             begin
           // Stopping operation
               dostop('BOOT');
               Form1.pb1.progress:=0;
               i:=0;
             end;
          sleep (1500);
          Application.ProcessMessages;
          end
          else i:=0;
          dec(i);
     end;

     if not DevPresent then
     begin
          Form1._msg('Phone not found... :(');
          Form1.SetBuzy;
          Form1.StatusBar.Panels[4].Text:='';
          result:=False;
          USBClosePort;
          exit;
     end;
     fltime:=0;
     //Phone in Flash Mode???
     CheckADLUpload[3]:=$6F;
     CheckADLUpload[7]:=msgid;
     CheckADLUpload[8]:=ISIHeaderTransId;
     CheckADLUpload[9]:=$00;
     i:=USBBulkWritePort(@CheckADLUpload, Length(CheckADLUpload));
     if i<>12 then exit;
     USBBulkReadPort(12);

     if rxBuf[11]<>$03 then
     begin
         if rxBuf[11]<>$80 then begin
             Form1._msg('ADL Server (CMT) not confirmed flashmode!');
             Form1._msg('ADL ReqPh : '+byte2str(rxbuf[11]));
             Form1.SetReady;
             result:=False;
             USBClosePort;
             exit;
         end else begin
         //1B 00 10 6F 00 06 00 14 A9 80 00 00    


         end;
     end;
     //Phone in Flash Mode???
     CheckADLUpload[3]:=$21;
     CheckADLUpload[7]:=msgid;
     CheckADLUpload[8]:=ISIHeaderTransId;
     CheckADLUpload[9]:=$00;
     i:=USBBulkWritePort(@CheckADLUpload, Length(CheckADLUpload));
     if i<>12 then exit;
     USBBulkReadPort(12);
     CheckADLUpload[3]:=$6F; // чистим, на всякий

     if rxBuf[11]<>$03 then
     begin
        if rxBuf[11]<>$80 then begin
               Form1._msg('ADL Server (APE) not confirmed flashmode!');
               Form1._msg('ADL ReqPh : '+byte2str(rxbuf[11]));
               Form1.SetReady;
               result:=False;
               USBClosePort;
               exit;
        end;
     end;

     rb:=rxbuf[11];

     Form1._msg('ADL Server confirm flashmode!');

     case rb of
     $80 :
         begin
         get2420root[8]:=ISIHeaderTransID;
          UsbBulkWriteport(@get2420root, Length(get2420root));
          if usbbulkreadport($FFFF) then begin
           form1._msg('ADL : Auth Ok');
           Application.ProcessMessages;
          end;
         end;
     $03 :
         begin
         Application.Processmessages;
         form1._msg('ADL : Auth skip');
         //sentroot+pc+hash-> conf APE
         //send crc&
         end;
     end;

       if stop=True then
       begin
           // Stopping operation
         dostop('FLASH');
         Form1.pb1.progress:=0;
         Form1._msg('       Flashing failed...');
         Form1.SetReady;
         Form1.enableFLtab;
         StuffFlashReset;
         result:=False;
         Exit;
         Form1._msg('');
         exit;
       end;

     selectAsicCMT[3]:=$6F;
     selectAsicCMT[8]:=ISIHeaderTransId;
     USBBulkWritePort(@selectAsicCMT, Length(selectAsicCMT));
     if USBBulkReadPort($FFFF) then begin
      if rxbuf[10]<>$00 then begin
                             Form1._msg('ADL : Select CMT failed!');
                             Exit;
                             end;
     Form1._msg('ADL : ASIC CMT select Ok');
     Application.ProcessMessages;
     end;
     selectAsicCMT[3]:=$21;
     SelectAsicCMT[8]:=ISIHeaderTransId;
     USBBulkWritePort(@selectAsicCMT, Length(selectAsicCMT));
     if USBBulkReadPort($FFFF) then begin
      if rxbuf[10]<>$00 then begin
                             Form1._msg('ADL : Select APE failed!');
                             Exit;
                             end;
     Form1._msg('ADL : ASIC APE select Ok');
     selectAsicCMT[3]:=$6F;
     Application.ProcessMessages;
     end;

     //Добавил для удобства кастом-прошивки
     Form1.statusbar.Panels[0].Text:='';
     Form1.statusbar.Panels[1].Text:='';
     Form1.statusbar.Panels[2].Text:='';
     Form1.statusbar.Panels[4].Text:='FLASHING';
     Form1.statusbar.Panels[3].Text:='Connected';
     Form1.TimConChk.Interval:=100;
     Application.ProcessMessages;

      Form1.chkMCUen.checked:=true;
      Form1.chkPPMe.checked:=true;
      Form1.chkMCUen.Enabled:=False;
      Form1.chkPPMe.Enabled:=False;

      if Form1.chkMCUen.Checked=true then
     begin
          Form1._msg('   ===Flashing [MCU]===');
          if not BB5_EraseFile(core) then begin StuffFlashReset; result:=False; Exit; end;
          Application.ProcessMessages;
          if not BB5_WriteFile(core) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('MCU Write done');
     end;
     Application.ProcessMessages;
     if Form1.chkPPMe.Checked=true then
     begin
            Form1.chkPPMe.Enabled:=False;
            Form1.chkMCUen.Enabled:=False;
          Form1._msg('   ===Flashing [PPM]===');
          if not BB5_EraseFile(ppm) then begin StuffFlashReset; result:=False; Exit; end;
          Application.ProcessMessages;
          if not BB5_WriteFile(ppm) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('PPM Write done');
     end;
     Application.ProcessMessages;
      if Form1.chkPPM1e.Checked=true then
     begin
            Form1.chkPPMe.Enabled:=False;
            Form1.chkMCUen.Enabled:=False;
            Form1.chkPPM1e.Enabled:=False;
          Form1._msg('   ===Flashing [PPM2]===');
          if not BB5_EraseFile(ppm1) then begin StuffFlashReset; result:=False; Exit; end;
          Application.ProcessMessages;
          if not BB5_WriteFile(ppm1) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('PPM Write done');
     end;
     Application.ProcessMessages;
     if Form1.chkCNTe.Checked=true then
     begin
            Form1.chkPPMe.Enabled:=False;
            Form1.chkMCUen.Enabled:=False;
            Form1.chkPPM1e.Enabled:=False;
            Form1.chkCNTe.Enabled:=False;
          Form1._msg('   ===Flashing [CNT]===');
          if not BB5_EraseFile(image) then begin StuffFlashReset; result:=False; Exit; end;
           Application.ProcessMessages;
          if not BB5_WriteFile(image) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('CNT Write done');
     end;
     Application.ProcessMessages;
      if Form1.chkAPEe.Checked=true then
     begin
            Form1.chkPPMe.Enabled:=False;
            Form1.chkMCUen.Enabled:=False;
            Form1.chkPPM1e.Enabled:=False;
            Form1.chkCNTe.Enabled:=False;
            Form1.chkAPEe.Enabled:=False;
          Form1._msg('   ===Flashing [APE]===');
          if not BB5_EraseFile(ape) then begin StuffFlashReset; result:=False; Exit; end;
           Application.ProcessMessages;
          if not BB5_WriteFile(ape) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('APE Write done');
     end;
     Application.ProcessMessages;
      if Form1.chkcnt3.Checked=true then
     begin
            Form1.chkPPMe.Enabled:=False;
            Form1.chkMCUen.Enabled:=False;
            Form1.chkPPM1e.Enabled:=False;
            Form1.chkCNTe.Enabled:=False;
            Form1.chkAPEe.Enabled:=False;
            Form1.chkcnt3.Enabled:=False;
          Form1._msg('   ===Flashing [CNT3]===');
          if not BB5_EraseFile(cnt3) then begin StuffFlashReset; result:=False; Exit; end;
          Application.ProcessMessages;
          if not BB5_WriteFile(cnt3) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('CNT Write done');
     end;

     if not ADLAPErestart(rb) then begin
      Application.ProcessMessages;
      Sleep(200);
      Form1.SetReady;
      Form1.TimConChk.Enabled:=true;
      Form1._msg('->  Flashing Failed! :( Maybee HW error, or Downgrade try???!');
      Form1._msg('');
      Form1.DisconnectFill;
      Result:=false;
      exit;
     end;


     Application.ProcessMessages;
     Form1._msg('');
     Form1._msg('Flashing done!');
     Form1._msg('Total flash time : '+showtime(fltime));
     Form1._msg('Reboot phone now...');
     Form1._msg('');
     Application.ProcessMessages;
     fltime:=0;
     Form1.statusbar.Panels[0].Text:='';
     Form1.pb1.ForeColor:=clNavy;
     Form1.pbsm1.ForeColor:=clNavy;
     Form1.pb1.MaxValue:=100;
     Form1.pb1.progress:=0;
     Form1.statusbar.Panels[1].Text:='';
     Form1.TimConChk.Interval:=2000;

     Form1.pb1.color:=clActiveBorder;

     if affenabled then Form1.afterFlashdo;

     Application.ProcessMessages;
     Sleep(200);
     Form1.TimConChk.Enabled:=true;
     Form1._msg('Done!');
       Form1.chkPPMe.Enabled:=True;
       Form1.chkMCUen.Enabled:=True;
       Form1.chkPPM1e.Enabled:=True;
       Form1.chkCNTe.Enabled:=True;
       Form1.chkAPEe.Enabled:=True;
       Form1.chkcnt3.Enabled:=true;
     Result:=true;
end;

function Omap1610extrboot(ASIC:string):boolean;
var
  fs,resstream      :TMemoryStream;
  data              :string;
  hdrlen,seemcount,
  CurrSeemLen,i     :Integer;
  currseem          :Byte;
  loaderlen         :DWORD;
  copysize          :int64;
begin
  result:=False;
  try
  fs:=TMemoryStream.Create;
  if ASIC='CMT' then fs.LoadFromFile(ExtractFilePath(Application.ExeName)+'\Flash\ADLREVC00.adl')
  else fs.LoadFromFile(ExtractFilePath(Application.ExeName)+'\Flash\ADLREVA00.adl');
     fs.Read(buf[0] ,1);
     if buf[0]<>$B3 then  //Заголовок / идентификатор
     begin
          Form1.lst1.items.add('->  File damaged or Unknow format... :(');
          fs.Free;
          exit;
     end;
     fs.ReadBuffer(buf[0], 4);//Длина Flash-header'a
     HdrLen    := HexToInt(IntToHex(buf[0], 2)+IntToHex(buf[1], 2)+IntToHex(buf[2], 2)+IntToHex(buf[3], 2));
      fs.ReadBuffer(buf[0], 4);//Кол-во блоков в Flash-заголовке
     SeemCount := HexToInt(IntToHex(buf[0], 2)+IntToHex(buf[1], 2)+IntToHex(buf[2], 2)+IntToHex(buf[3], 2));
     Application.ProcessMessages;
     while (fs.Position<HdrLen) do
     begin
          fs.ReadBuffer(CurrSeem, 1);
          case CurrSeem of//Перебор всех блоков, поиск блока со структурой RAW-loader'а

          $E5:
              begin
               //Form1._msg('SEEM: E5');
               fs.ReadBuffer(buf[0], 2);
               CurrSeemLen:=(buf[0]*$100)+buf[1];
               fs.Seek(CurrSeemLen, sofromCurrent);
               OMAP1610:=TMemoryStream.Create;
              copysize:=fs.Size-fs.Position;
              OMAP1610.CopyFrom(fs,copysize);
              result:=True;
              fs.free;
              Exit;
              end
              else
            begin
                   fs.ReadBuffer(buf[0], 1);
                   CurrSeemLen:=buf[0];
                   fs.Seek(CurrSeemLen, sofromcurrent);
              end;
         end;
   end;
    Fs.free;
   except
   result:=False;
   end;
end;

function ADLAPErestart(rb:Byte):Boolean;
var
  i:Integer;
begin
 result:=False;
	 case rb of
     $03: begin
           // режим рестарта
           Form1._msg(' =================');
           Form1._msg('ADL : End flashing');
           CMTfinish[3]:=$6F;
           CMTfinish[8]:=ISIHeaderTransId;
           USBBulkWritePort(@CMTfinish, Length(CMTfinish));
           if USBBulkReadPort($FFFF) then begin
            if rxbuf[10]<>$00 then begin
                             Form1._msg('->  ADL : Close CMT session failed :(');
                             result:=false;
                             Exit;
                             end;
           Form1._msg('ADL : Close CMT session Ok');
           Application.ProcessMessages;
           end;
           CMTfinish[3]:=$21;
           CMTfinish[8]:=ISIHeaderTransId;
           USBBulkWritePort(@CMTfinish, Length(CMTfinish));
           if USBBulkReadPort($FFFF) then begin
             if rxbuf[10]<>$00 then begin
                             Form1._msg('->  ADL : Close APE session failed :(');
                             result:=False;
                             Exit;
                             end;
            Form1._msg('ADL : Close APE session Ok');
            Application.ProcessMessages;
            end;

            EndOmapFlash[3]:=$6F;
            EndOmapFlash[8]:=ISIHeaderTransId;
            USBBulkWritePort(@EndOmapFlash, Length(EndOmapFlash));
            EndOmapFlash[3]:=$21;
            EndOmapFlash[8]:=ISIHeaderTransId;
            USBBulkWritePort(@EndOmapFlash, Length(EndOmapFlash));
            EndOmapFlash[3]:=$6F;
            EndOmapFlash[8]:=ISIHeaderTransId;
            USBBulkWritePort(@EndOmapFlash, Length(EndOmapFlash));
            result:=True;
          end;
     $80: begin
           Form1._msg(' =================');
           Form1._msg('ADL : End flashing');
           CMTfinish[3]:=$6F;
           CMTfinish[8]:=ISIHeaderTransId;
           CMTfinish[10]:=$02;
           USBBulkWritePort(@CMTfinish, Length(CMTfinish));
           if USBBulkReadPort($FFFF) then begin
            if rxbuf[10]<>$00 then begin
                             Form1._msg('->  ADL : Close CMT session failed :(');
                             result:=false;
                             Exit;
                             end;
           Form1._msg('ADL : Close CMT session Ok');
           Application.ProcessMessages;
           end;

           CMTfinish[3]:=$21;
           CMTfinish[8]:=ISIHeaderTransId;
           CMTfinish[10]:=$00;
           USBBulkWritePort(@CMTfinish, Length(CMTfinish));
           if USBBulkReadPort($FFFF) then begin
             if rxbuf[10]<>$00 then begin
                             Form1._msg('->  ADL : Close APE session failed :(');
                             result:=false;
                             Exit;
                             end;
            Form1._msg('ADL : Close APE session Ok');
            Application.ProcessMessages;
            end;

            EndOmapFlash[3]:=$6F;
            EndOmapFlash[8]:=ISIHeaderTransId;
            EndOmapFlash[10]:=$02;
            USBBulkWritePort(@EndOmapFlash, Length(EndOmapFlash));
            EndOmapFlash[3]:=$21;
            EndOmapFlash[8]:=ISIHeaderTransId;
            EndOmapFlash[10]:=$00;
            USBBulkWritePort(@EndOmapFlash, Length(EndOmapFlash));

            EndOmapFlash[3]:=$6F;
            EndOmapFlash[10]:=$00;
            result:=True;
          end;
     end;
end;

function S40BuildCertBody(core:string):Boolean;
var
     buf                :array[0..$3FFFF] of byte;
     EntryPoint,
     DataLen,
     TargetOffset,
     CRCTmp             : LongInt;
     i, n, Blocks,
     Packets,icl        : Integer;
     good               : Integer;
     fs                 : TFileStream;
     certname           : string;
begin
     fs:=TFileStream.Create(core,fmOpenRead);
     fs.Seek(0, sofromBeginning);
     Application.ProcessMessages;
   S40adl80CRTdata[7]:=msgid;
   S40adl80CRTdata[8]:=ISIHEaderTransID;

   S40adl80CRTdata[28]:=csbyte1;
   S40adl80CRTdata[29]:=csbyte2;
   S40adl80CRTdata[30]:=csbyte3;
   //31 - DSP
   S40adl80CRTdata[48]:=csbyte1;
   S40adl80CRTdata[49]:=csbyte2;
   S40adl80CRTdata[50]:=csbyte3;
   //51 - MCUSW
   S40adl80CRTdata[68]:=csbyte1;
   S40adl80CRTdata[69]:=csbyte2;
   S40adl80CRTdata[70]:=csbyte3;
   //71 - NOLO
   S40adl80CRTdata[88]:=csbyte1;
   S40adl80CRTdata[89]:=csbyte2;
   S40adl80CRTdata[90]:=csbyte3;
   //91 - UPDAPP

   try
     fs.Read(i,1);
     if i<>$B2 then raise E.Create('CRTBuild : Bad image file');
     fs.ReadBuffer(buf[0], 4);//Длина Flash Header
     DataLen := HexToInt(IntToHex(buf[0], 2)+IntToHex(buf[1], 2)+IntToHex(buf[2], 2)+IntToHex(buf[3], 2));
     fs.Seek(DataLen,soFromCurrent);
     EntryPoint := fs.Position;
     Form1._msg('ADL : Check data');

     while fs.Position<fs.Size do
     begin
          fs.ReadBuffer(buf[0], 1);
          if (buf[0]<>$54) and (buf[0]<>$5D) then raise E.Create('CRTBuild : Bad image file, Corrupted blocks!' );
          case buf[0] of
          $54://Phoenix-token
          begin
               fs.ReadBuffer(buf[0], $3);
               case buf[1] of
               $17 : begin
                     fs.ReadBuffer(buf[0], buf[2]+1);
                     DataLen := HexToInt(IntToHex(buf[6], 2)+IntToHex(buf[7], 2)+IntToHex(buf[8], 2)+IntToHex(buf[9], 2));
                     //Form1._msg(inttohex(buf[0],2)+inttohex(buf[1],2));
                     fs.Seek(DataLen,soFromCurrent);
                     continue;
                     end;
               $2E : begin
                     fs.ReadBuffer(buf[0], buf[2]+1);
                     DataLen := HexToInt(IntToHex(buf[17], 2)+IntToHex(buf[18], 2)+IntToHex(buf[19], 2)+IntToHex(buf[20], 2));
                     // Form1._msg(inttohex(buf[0],2)+inttohex(buf[1],2));
                     fs.Seek(DataLen,soFromCurrent);
                     continue;
                     end;
               else
                     begin
                     fs.ReadBuffer(buf[0], buf[2]+1);
                     DataLen := HexToInt(IntToHex(buf[6], 2)+IntToHex(buf[7], 2)+IntToHex(buf[8], 2)+IntToHex(buf[9], 2));
                     fs.Seek(DataLen,soFromCurrent);
                     inc(blocks);
                     continue;
                     end;

               end;
          end;
           $5D://Phoenix-segment
            begin
               fs.ReadBuffer(buf[0], $3);
               fs.ReadBuffer(buf[0], buf[2]+1);
               DataLen := HexToInt(IntToHex(buf[37], 2)+IntToHex(buf[38], 2)+IntToHex(buf[39], 2)+IntToHex(buf[40], 2));
               good:=0;
               for i:=$0 to $0F do if RAPInfo.Root_Key_Hash[i]=buf[i] then inc(good);
               if good<$10 then
               begin
               fs.Seek(DataLen, sofromCurrent);
               continue;
               end;

			         CertName:='';
               for i:=20 to 31 do if buf[i]=$00 then break else CertName:=CertName+Chr(buf[i]);

               if certname='NOLO' then begin
               //Form1._msg('Hash CERT ['+CertName+']');
               fs.readbuffer(buf[0],$D);
               csbyte4:=buf[12];
               S40adl80CRTdata[71]:=csbyte4;
               fs.Seek(DataLen-$D,soFromCurrent);
               continue;
               end
               else
               if certname='DSP0' then begin
               //Form1._msg('Hash CERT ['+CertName+']');
               fs.readbuffer(buf[0],$D);
               csbyte4:=buf[12];
               S40adl80CRTdata[31]:=csbyte4;
               fs.Seek(DataLen-$D,soFromCurrent);
               continue;
               end
               else
               if certname='MCUSW' then begin
               //Form1._msg('Hash CERT ['+CertName+']');
               fs.readbuffer(buf[0],$D);
               csbyte4:=buf[12];
               S40adl80CRTdata[51]:=csbyte4;
               fs.Seek(DataLen-$D,soFromCurrent);
               continue;
               end
               else
               if certname='UPDAPP' then begin
               //Form1._msg('Hash CERT ['+CertName+']');
               fs.readbuffer(buf[0],$D);
               csbyte4:=buf[12];
               S40adl80CRTdata[91]:=csbyte4;
               fs.Seek(DataLen-$D,soFromCurrent);
               continue;
               end
               else begin
               Application.ProcessMessages;
               fs.Seek(DataLen,soFromCurrent);
               continue;
               end;
            end;
          end;
     end;
     //form1._msg(buftohexstr(@S40adl80CRTdata[0],length(S40adl80CRTdata)));
     UsbBulkWritePort(@S40adl80CRTdata[0],length(S40adl80CRTdata));
     UsbBulkReadPort($FFFF);
     if rxbuf[10]<>$00 then form1._msg('ADL : Data NOT accepted by phone, continue at user risk') else
     if rxbuf[11]=$FF then form1._msg('ADL : Data accepted') else form1._msg('ADL : Data accepted as update');
   fs.Free;
   except
   Fs.free;
   form1._msg('ADL : Build check data failed!');
   end;
end;

function ExtractloaderXSRRap3Gv4(mode:integer):Boolean;
var
     fs               : TfileStream;
     currcert,
     currtoken,
     streamlen        : TMemoryStream;
     data             : string;
     hdrlen,seemcount,
     CurrSeemLen,i    : Integer;
     fblen            :Byte;
     currseem         : Byte;
     a                : string;
     blklen,loaderlen : DWORD;
     dcr              : Boolean;
     RootInBlock      : array[0..$F] of byte;
     j,good,i2        : Integer;
     n,k,l,m,PktLen   : integer;
     ms,
     RAWBlock,
     RAWLoader        : TmemoryStream;
     s, needSert      : String;
     Key, KeyLen      : Byte;
     PacketLen        : Byte;
     BlockCount       : Byte;
     CurrBlock        : Byte;
     CurrBlockLen     : Word;
     b, proto         : Boolean;
     ASIC             : string;
     rapmode          : Integer;
     loaderinfo       : string;
begin
     if mode=1 then
     begin
          Form1._msg('Dead Mode is Selected');
          Form1._msg('Waiting for USB device...');
          Form1._msg('--- Insert cable and charger or press phone'+#39+'s power button! ---');
          Application.ProcessMessages;
     end;
     loaderinfo:='';
     //Nokia USB ROM
     b:=false; i:=0;
     repeat
           if (i=2500) and (b=false) then
           begin
                Form1._msg('->  Phone not found.. :(');
                result:=False;
                Form1.statusbar.Panels[0].Text:='';
                Form1.SetReady;
                Exit;
           end;
           Application.ProcessMessages;
           if stop=True then
           begin
           // Stopping operation
           dostop('BOOT');
           Form1.pb1.progress:=0;
           i:=2499; b:=false;
           end;
           if catchdevice=$02 then
           begin
                b:=true;
                Form1._msg('Connection opened successfully');
           end;
           Application.ProcessMessages;
           Sleep(10);
           inc(i);
           Form1.statusbar.Panels[0].Text:='Wait for phone '+inttostr(2500-i);
           Application.ProcessMessages;
     until b ;
     Form1.statusbar.Panels[0].Text:='';
     ASIC:='';
     //rapmode:=1; // rapmode=0 - rapu, rapmode=1 rap3gv4

     Application.ProcessMessages;
     Form1._msg('Waiting for communication response...');
     Application.ProcessMessages;
     if BB5_USB_BootRom_GetFirstBlock<2 then
     begin
          Form1.setready;
          Form1._msg('->  Error answer from BootRom');
          result:=False;
          exit;
     end;
     Application.ProcessMessages;

     Form1.statusbar.Panels[3].Text:='Connected';
     Application.ProcessMessages;
     starttime;
     Application.ProcessMessages;

     // Root Hash
     Application.ProcessMessages;
     FillMemory(@RAPInfo.ROOT_KEY_HASH,$10,$00);
     FillMemory(@RAPInfo.APErootkey,$10,$00);
     FillMemory(@RAPInfo.FlashID,$A,$00);
     FillMemory(@RAPInfo.APEFlashID,$A,$00);
     FillMemory(@RAPInfo.PublicID,$14,$00);
     FillMemory(@RAPInfo.BootID,$8,$00);
     FillMemory(@RapInfo.Algo,$F,$00);
     Application.ProcessMessages;
     //form1._msg('rxBuf : '+buftohexstr(@rxBuf[0], Length(rxBuf)));
     //Application.ProcessMessages;
     PacketLen  :=rxbuf[0];
     BlockCount :=rxbuf[1];

     i:=2;
     j:=0;
     m:=0;
     while (i<PacketLen) and (j<BlockCount) do
     begin
          CurrBlock    :=rxbuf[i];
          inc(i);
          CurrBlockLen := HexToInt(IntToHex(rxbuf[i+1], 2)+IntToHex(rxbuf[i], 2))-1;
          inc(i,2);
          case CurrBlock of
          $01://RAP SYSTEM ASIC ID
              //5800 - 000000010000022600010006400C192101031103 [RAPIDO3G ver: 1.x]
              begin
                   for k:=0 to CurrBlockLen-1 do RAPInfo.SYSTEM_ASIC_ID[k]:= rxbuf[i+k];
                   Form1._msg('ASIC ID:       '+ BufToHexStr(@RAPInfo.SYSTEM_ASIC_ID[0],    CurrBlockLen));
                   inc(i, CurrBlockLen);
                   inc(j);
                   if currblocklen=$10 then ASIC:=BufToHexStr(@RAPInfo.SYSTEM_ASIC_ID[8],8) else ASIC:=BufToHexStr(@RAPInfo.SYSTEM_ASIC_ID[12],8);
              end;
          $02://RAP EMx ID
              //00000295
              //00000B22
              begin
                   if CurrBlockLen=4 then
                   for k:=0 to CurrBlockLen-1 do RAPInfo.EMx_ID[k]:= rxbuf[i+k];
                   Form1._msg('EM'+inttostr(m)+' ID:        '+ BufToHexStr(@RAPInfo.EMx_ID[0],    4));
                   inc(i, CurrBlockLen);
                   inc(j);inc(m);
              end;
          $12://PUBLIC_ID
              //1FF0001841158B52064E64D3C3E9A7F38DC47E29
              begin
                   for k:=0 to CurrBlockLen-1 do RAPInfo.PUBLIC_ID[k]:= rxbuf[i+k];
                   Form1._msg('PUBLIC ID:     '+ BufToHexStr(@RAPInfo.PUBLIC_ID[0],    Length(RAPInfo.PUBLIC_ID)));
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          $13://ASIC_MODE
              //00
              begin
                   if CurrBlockLen=2 then
                   RAPInfo.ASIC_MODE:= rxbuf[i];
                   Form1._msg('ASIC MODE ID:  '+ BufToHexStr(@RAPInfo.ASIC_MODE,    1));
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          $14://ROOT_KEY_HASH
              //CAEEBB65D3C48E6DC73B49DC5063A2EE
              begin
                   for k:=0 to CurrBlockLen-1 do RAPInfo.ROOT_KEY_HASH[k]:= rxbuf[i+k];
                   inc(i, CurrBlockLen);
                   inc(j);
                   // RootHash
                   l:=0;
                   for k := 0 to $0F do inc(l, RAPInfo.ROOT_KEY_HASH[k]);
                   if l=0 then
                   begin
                        Form1.setready;
                        Form1._msg('->  No ROOTKEY HASH Asic CMT. (IMEI DAMAGED?) Unable to continue flashing');
                        exit;
                   end;
                   Form1._msg('ROOT KEY HASH: '+ BufToHexStr(@RAPInfo.ROOT_KEY_HASH[0], Length(RAPInfo.ROOT_KEY_HASH)));
              end;
          $15://ROM_ID
              //4B9B75103E691FF8
              begin
                   for k:=0 to CurrBlockLen-1 do RAPInfo.ROM_ID[k]:= rxbuf[i+k];
                   Form1._msg('ROM ID:        '+ BufToHexStr(@RAPInfo.ROM_ID[0],    Length(RAPInfo.ROM_ID)));
                   inc(i, CurrBlockLen);
                   inc(j);
              end
              else
              begin
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          end;//End Of Case
     end;
    Application.ProcessMessages;

    if (ASIC<>'') and (ASIC<>'0000000000000000') then SelLoaders(asic) else
    begin
    result:=False;
    Form1._msg('Error finding bootdata or ASIC not supported!');
    Form1._msg('');
    Form1.SetReady;
    Exit;
    end;

    if (ExtractFileName(Floader))='' then
    begin
    result:=False;
    Form1._msg('Error finding bootdata or ASIC not supported!');
    Form1._msg('');
    Form1.SetReady;
    Exit;
    end;

    if (ExtractFileName(Floader)='RAP3Gv40_2nd.fg') or (Pos('BCM',ExtractFileName(Floader))<>0) then rapmode:=1 else rapmode:=0;

    try
	loaderinfo:=getversion(Floader);
    fs:=TFileStream.Create(floader,fmOpenRead);
    except
    Form1._msg('Can'+#39+'t open file '+ ExtractFileName(floader));
    result:=false;
    exit;
    end; 
    Form1._msg('Use '+ExtractFileName(Floader)+' '+loaderinfo);
      RAWLoader:=TmemoryStream.Create;
      RAWBlock:=TmemoryStream.Create;
      RAWblock.LoadFromstream(fs);
      Application.ProcessMessages;
      if Pos('BCM',ExtractFileName(Floader))<>0 then  BB5_ExtractRAWLoader(RAWblock, RAWLoader, b) else RAWLoader:=PrepareRAWloader(RAWblock) ;
      fs.Free;

{================================== SEND RAW LOADER ===================================}
     Application.processmessages;
     //RAWLoader.Seek(0, sofrombeginning);
     //RAWLoader.savetofile('C:\raw.bin');
     RAWLoader.Seek(0, sofrombeginning);
     b:=true; PktLen:=$1000; k:=1;
     txBuf[0]:=$40;
     txBuf[1]:=$57;
     txBuf[2]:=$01;
     txBuf[3]:=$00;
     txBuf[4]:=$00;
     txBuf[5]:=$00;
     Form1._msg('Processing RAWLOADER...');
     while (RAWLoader.position<RAWLoader.Size) and b do
     begin
          if ((RAWLoader.Size-RAWLoader.position)<PktLen) and b then //длина последнего кусочка
          begin
               b:=false;
               PktLen:=RAWLoader.Size-RAWLoader.position;//последний кусочек лоадера
               txBuf[2]:=$00;
               txBuf[6]:=PktLen mod $100;
               txBuf[7]:=PktLen div $100;
          end;
           //Form1._msg('Sending Raw-loader: '+inttohex(PktLen, 4));
          Application.ProcessMessages;
          txBuf[6]:=PktLen mod $100;
          txBuf[7]:=PktLen div $100;
          RAWLoader.ReadBuffer(txBuf[8], PktLen);
          Application.ProcessMessages;
          //ms.WriteBuffer(txBuf[8], PktLen);
          //ms.SaveToFile('C:\RAW\'+Int2Digs(k,4)+'_BEST.bin');
          //ms.Clear;
          inc(k);
          USBControlPacket($222040, $8+PktLen, 0);
          Application.ProcessMessages;
     end;


    case rapmode of
    0:checkbootcode;
    1: begin
       if Pos('BCM',ExtractFileName(Floader))<>0  then Application.ProcessMessages else checkbootcode;
       end;
    end;
    CheckCMTboot; // проверяем верность загрузки равки
   
   loaderinfo:='';
   
    try
    loaderinfo:=getversion(sloader);
    fs:=TFileStream.Create(sloader,fmOpenRead);
    except
    Form1._msg('Can'+#39+'t open file '+ ExtractFileName(sloader));
    result:=false;
    exit;
    end;
   
   
   Form1._msg('Use '+ExtractFileName(sloader)+' '+loaderinfo);
     fs.Read(buf[0] ,1);
     if buf[0]<>$B1 then  //Заголовок / идентификатор
     begin
          Form1.lst1.items.add('File damaged or Unknow format... :(');
          fs.Free;
          exit;
     end;
     fs.ReadBuffer(buf[0], 4);//Длина Flash-header'a
     HdrLen    := HexToInt(IntToHex(buf[0], 2)+IntToHex(buf[1], 2)+IntToHex(buf[2], 2)+IntToHex(buf[3], 2));
     //form1._msg('HeaderLen: '+inttostr(HdrLen));
     fs.ReadBuffer(buf[0], 4);//Кол-во блоков в Flash-заголовке
     SeemCount := HexToInt(IntToHex(buf[0], 2)+IntToHex(buf[1], 2)+IntToHex(buf[2], 2)+IntToHex(buf[3], 2));
     //form1._msg('BlockCount: '+inttostr(SeemCount));
     Application.ProcessMessages;
     dcr:=false;
     currcert:=TMemoryStream.Create;
     currtoken:=TmemoryStream.Create;
     streamlen:=TMemoryStream.Create;
     good:=0;
     i2:=0;
     loaderlen:=0;
  try
    Form1.statusbar.Panels[4].Text:='Sending Boot';
     while (fs.Position<>(fs.size)) do
     begin
          fs.ReadBuffer(CurrSeem, 1);
          case CurrSeem of//Перебор всех блоков, поиск блока со структурой RAW-loader'а
            $56:
              begin
              //Form1._msg('Cert Token found, processing...');
              Application.ProcessMessages;
                  fs.ReadBuffer(buf[0], 3);
                  case Buf[1] of
                    $17: // UPDAPP body ( 1st block  - precrt )
                       begin
                      //form1._msg('UpdAPP Body processing');
                       Application.ProcessMessages;
                       CurrSeemLen :=buf[2]+1;
                       //fs.ReadBuffer(buf[0], currseemlen);
                       fs.Seek(fs.Position-4, sofromBeginning);
                       currtoken.CopyFrom(fs,currseemlen+4);
                       //currtoken.SaveToFile('C:\token'+inttostr(i2)+'.bin');
                       // send token's header
                       Application.processmessages;

                       currtoken.Seek(0, sofrombeginning);
                       b:=true; PktLen:=$100; k:=1;
                       txBuf[0]:=$40;
                       txBuf[1]:=$60;
                       txBuf[2]:=$00;
                       txBuf[3]:=$00;
                       txBuf[4]:=$00;
                       txBuf[5]:=$00;
                       k:=0;
                       while (currtoken.position<currtoken.Size) and b do
                       begin
                       if ((currtoken.Size-currtoken.position)<PktLen) and b then //длина последнего кусочка
                       begin
                       b:=false;
                       PktLen:=currtoken.Size-currtoken.position;//последний кусочек лоадера
                       txBuf[2]:=$00;
                       txBuf[6]:=PktLen mod $100;
                       txBuf[7]:=PktLen div $100;
                       end;
                       txBuf[6]:=PktLen mod $100;
                       txBuf[7]:=PktLen div $100;
                       currtoken.ReadBuffer(txBuf[8], PktLen);
                       inc(k);
                       USBControlPacket($222040, $8+PktLen, 0);
                       Form1.pb1.progress:=Form1.pb1.progress+1;
                       Application.ProcessMessages;
                       end;

                       //send cert body
                       currtoken.Seek(10,sofromBeginning);
                       currtoken.ReadBuffer(blklen,4);
                       DWordSwap(@blklen);
                       currcert.CopyFrom(fs,blklen);
                       Application.processmessages;

                       currcert.Seek(0, sofrombeginning);
                       b:=true; PktLen:=$1000; k:=1;
                       txBuf[0]:=$40;
                       txBuf[1]:=$60;
                       txBuf[2]:=$01;
                       txBuf[3]:=$00;
                       txBuf[4]:=$00;
                       txBuf[5]:=$00;
                       //Form1._msg('CERT SIZE : '+inttostr(currcert.Size));
                       k:=0;
                       while (currcert.position<currcert.Size) and b do
                       begin
                       if ((currcert.Size-currcert.position)<PktLen) and b then //длина последнего кусочка
                       begin
                       b:=false;
                       PktLen:=currcert.Size-currcert.position;//последний кусочек лоадера
                       txBuf[2]:=$00;
                       txBuf[6]:=PktLen mod $100;
                       txBuf[7]:=PktLen div $100;
                       end;
                       Inc(k);
                       txBuf[6]:=PktLen mod $100;
                       txBuf[7]:=PktLen div $100;
                       currcert.ReadBuffer(txBuf[8], PktLen);
                       if k=(currcert.Size div $1000)  then txBuf[2]:=$00;
                       if ((currcert.Size mod $1000)>0) and (k=(currcert.Size div $1000)) then txbuf[2]:=$01;
                       USBControlPacket($222040, $8+PktLen, 0);
                       //Form1._msg('Cert K : '+inttostr(k)+' / '+inttostr(currcert.size div $1000)+' / byte '+byte2str(txbuf[2]));
                       Form1.pb1.progress:=Form1.pb1.progress+1;
                       Application.ProcessMessages;
                       end;
                       
                       Application.ProcessMessages;
                       currcert.clear;
                       currtoken.Clear;
                      end;
                    $27: // UPDAPP CERT
                       begin
                       Application.ProcessMessages;
                       good:=0;
                       CurrSeemLen :=buf[2]+1;
                       fs.Seek(fs.Position-4, sofromBeginning);
                       currtoken.CopyFrom(fs,currseemlen+4);
                       currtoken.seek(4,soFromBeginning);
                       currtoken.ReadBuffer(RootInBlock[0], $10);
                       //form1._msg('UPDAPP: '+buftohexstr(@rootinBlock[0], $10));
                       Application.ProcessMessages;
                       for j:=0 to $0f do if RootInBlock[j]=RAPInfo.Root_Key_Hash[j] then inc(good);
                       if good=$10 then
                         begin
                         //currtoken.SaveToFile('C:\token_upd_cert'+inttostr(i2)+'.bin');
                         //form1._msg('Processing UPDAPP...');
                         //Form1._msg('Flashing header UpdAPP');
                         // send token's header
                          Application.processmessages;

                           currtoken.Seek(0, sofrombeginning);
                           b:=true; PktLen:=$100; k:=1;
                           txBuf[0]:=$40;
                           txBuf[1]:=$60;
                           txBuf[2]:=$00;
                           txBuf[3]:=$00;
                           txBuf[4]:=$00;
                           txBuf[5]:=$00;
                           while (currtoken.position<currtoken.Size) and b do
                           begin
                           if ((currtoken.Size-currtoken.position)<PktLen) and b then //длина последнего кусочка
                           begin
                           b:=false;
                           PktLen:=currtoken.Size-currtoken.position;//последний кусочек лоадера
                           txBuf[2]:=$00;
                           txBuf[6]:=PktLen mod $100;
                           txBuf[7]:=PktLen div $100;
                           end else txBuf[2]:=$01;

                           txBuf[6]:=PktLen mod $100;
                           txBuf[7]:=PktLen div $100;
                           currtoken.ReadBuffer(txBuf[8], PktLen);
                           inc(k);

                            USBControlPacket($222040, $8+PktLen, 0);
                           Form1.pb1.progress:=Form1.pb1.progress+1;
                           Application.ProcessMessages;
                            end;


                           currtoken.Seek(41,sofromBeginning);
                           currtoken.ReadBuffer(blklen,4);
                           DWordSwap(@blklen);
                           currcert.CopyFrom(fs,blklen);

                           Application.processmessages;

                           currcert.Seek(0, sofrombeginning);
                           b:=true; PktLen:=$1000; k:=1;
                           txBuf[0]:=$40;
                           txBuf[1]:=$60;
                           txBuf[2]:=$00;
                           txBuf[3]:=$00;
                           txBuf[4]:=$00;
                           txBuf[5]:=$00;
                          while (currcert.position<currcert.Size) and b do
                          begin
                            if ((currcert.Size-currcert.position)<PktLen) and b then //длина последнего кусочка
                            begin
                            b:=false;
                            PktLen:=currcert.Size-currcert.position;//последний кусочек лоадера
                            txBuf[2]:=$00;
                            txBuf[6]:=PktLen mod $100;
                            txBuf[7]:=PktLen div $100;
                            end else txBuf[2]:=$01;

                           txBuf[6]:=PktLen mod $100;
                           txBuf[7]:=PktLen div $100;
                           currcert.ReadBuffer(txBuf[8], PktLen);
                           inc(k);

                           USBControlPacket($222040, $8+PktLen, 0);
                           Form1.pb1.progress:=Form1.pb1.progress+2;
                           Application.ProcessMessages;
                            end;
                           ///////
                         end
                         else begin
                         currtoken.Seek(41,sofromBeginning);
                         currtoken.ReadBuffer(blklen,4);
                         DWordSwap(@blklen);
                         currcert.CopyFrom(fs,blklen);
                         Form1.pb1.progress:=Form1.pb1.progress+1;
                         Application.ProcessMessages;
                         end;
                       Application.ProcessMessages;
                       currcert.clear;
                       currtoken.Clear;
                       end;
                    $28: // PAPUBKEYS match with root
                       begin
                        // form1._msg('PAPUBKEYS detected!');
                         Application.ProcessMessages;
                         good:=0;
                       CurrSeemLen :=buf[2]+1;
                       fs.Seek(fs.Position-4, sofromBeginning);
                       currtoken.CopyFrom(fs,currseemlen+4);
                       currtoken.seek(4,soFromBeginning);
                       currtoken.ReadBuffer(RootInBlock[0], $10);
                       //form1._msg('PAPUBKEYS:'+buftohexstr(@rootinBlock[0], $10));
                       Application.ProcessMessages;
                       for j:=0 to $0f do if RootInBlock[j]=RAPInfo.Root_Key_Hash[j] then inc(good);
                       if good=$10 then
                         begin
                          //form1._msg('Processing PAPUBKEYS...');
                            // send token's header
                           Application.processmessages;

                           currtoken.Seek(0, sofrombeginning);
                           b:=true; PktLen:=$100; k:=1;
                           txBuf[0]:=$40;
                           txBuf[1]:=$60;
                           txBuf[2]:=$00;
                           txBuf[3]:=$00;
                           txBuf[4]:=$00;
                           txBuf[5]:=$00;
                           while (currtoken.position<currtoken.Size) and b do
                           begin
                           if ((currtoken.Size-currtoken.position)<PktLen) and b then //длина последнего кусочка
                           begin
                           b:=false;
                           PktLen:=currtoken.Size-currtoken.position;//последний кусочек лоадера
                           txBuf[2]:=$00;
                           txBuf[6]:=PktLen mod $100;
                           txBuf[7]:=PktLen div $100;
                           end else txBuf[2]:=$01;

                           txBuf[6]:=PktLen mod $100;
                           txBuf[7]:=PktLen div $100;
                           currtoken.ReadBuffer(txBuf[8], PktLen);
                           inc(k);

                            USBControlPacket($222040, $8+PktLen, 0);
                           Form1.pb1.progress:=Form1.pb1.progress+1;
                           Application.ProcessMessages;
                            end;
                           ///////

                         currtoken.Seek(41,sofromBeginning);
                         currtoken.ReadBuffer(blklen,4);
                         DWordSwap(@blklen);
                         currcert.CopyFrom(fs,blklen);
                         //currcert.SaveToFile('C:\PAPUBKEYS'+inttostr(i2)+'.bin');

                         Application.processmessages;

                           currcert.Seek(0, sofrombeginning);
                           b:=true; PktLen:=$1000; k:=1;
                           txBuf[0]:=$40;
                           txBuf[1]:=$60;
                           txBuf[2]:=$00;
                           txBuf[3]:=$00;
                           txBuf[4]:=$00;
                           txBuf[5]:=$00;
                          while (currcert.position<currcert.Size) and b do
                          begin
                            Application.processmessages;
                            if ((currcert.Size-currcert.position)<PktLen) and b then //длина последнего кусочка
                            begin
                            b:=false;
                            PktLen:=currcert.Size-currcert.position;//последний кусочек лоадера
                            txBuf[2]:=$00;
                            txBuf[6]:=PktLen mod $100;
                            txBuf[7]:=PktLen div $100;
                            end else txBuf[2]:=$01;

                           txBuf[6]:=PktLen mod $100;
                           txBuf[7]:=PktLen div $100;
                           currcert.ReadBuffer(txBuf[8], PktLen);
                           inc(k);

                           USBControlPacket($222040, $8+PktLen, 0);
                           Form1.pb1.progress:=Form1.pb1.progress+1;
                           Application.ProcessMessages;
                           end;
                           ///////

                         i2:=i2+1;
                         end
                         else begin
                         currtoken.Seek(41,sofromBeginning);
                         currtoken.ReadBuffer(blklen,4);
                         DWordSwap(@blklen);
                         currcert.CopyFrom(fs,blklen);
                         Form1.pb1.progress:=Form1.pb1.progress+1;
                         Application.processmessages;
                         end;
                       Application.ProcessMessages;
                       currcert.clear;
                       currtoken.Clear;
                       end;
                    $3A:  // finalize command ( last )
                       begin
                       CurrSeemLen :=buf[2]+1;
                       fs.Seek(fs.Position-4, sofromBeginning);
                       currtoken.CopyFrom(fs,currseemlen+4);
                       // send token's header
                          Application.processmessages;

                           currtoken.Seek(0, sofrombeginning);
                           b:=true; PktLen:=$100; k:=1;
                           txBuf[0]:=$40;
                           txBuf[1]:=$60;
                           txBuf[2]:=$00;
                           txBuf[3]:=$00;
                           txBuf[4]:=$00;
                           txBuf[5]:=$00;
                           while (currtoken.position<currtoken.Size) and b do
                           begin
                           if ((currtoken.Size-currtoken.position)<PktLen) and b then //длина последнего кусочка
                           begin
                           b:=false;
                           PktLen:=currtoken.Size-currtoken.position;//последний кусочек лоадера
                           txBuf[2]:=$00;
                           txBuf[6]:=PktLen mod $100;
                           txBuf[7]:=PktLen div $100;
                           end;

                           txBuf[6]:=PktLen mod $100;
                           txBuf[7]:=PktLen div $100;
                           currtoken.ReadBuffer(txBuf[8], PktLen);
                           inc(k);

                          { if not  USBControlPacket($222040, $8+PktLen, 0) then
                               begin
                               result:=False;
                               form1.pb1.progress:=0;
                               form1._msg('->  Boot error - device not ready - check battery/connection/HW');
                                currtoken.free;
                                currcert.free;
                               fs.Free;
                               Exit;
                               end;  }
                           USBControlPacket($222040, $8+PktLen, 0);
                           Application.ProcessMessages;
                            end;
                           ///////
                       currtoken.clear;
                       result:=True;
                       Form1.pb1.progress:=Form1.pb1.progress+2;
                       Application.processmessages;
                       end;
                  end;
              end;

          else
            begin
                   fs.ReadBuffer(buf[0], 1);
                   CurrSeemLen:=buf[0];
                   fs.Seek(CurrSeemLen, sofromcurrent);
              end;
         end;
   end;

  if RAPUFinalizeboot(rapmode) then result:=True else result:=False; // финализируем

   Form1.pb1.progress:=0;
   Form1.pb1.maxvalue:=100;
   if Result= True then form1._msg('Boot Done! :)') else begin
   result:=False;
   Form1.pb1.progress:=0;
   Form1.pb1.maxvalue:=100;
   form1._msg('->  Boot error... :(');
   currtoken.free;
   currcert.free;
   Fs.free;
   Exit;
   end;
   Form1.statusbar.Panels[4].Text:='';
   currtoken.free;
   currcert.free;
   Fs.free;
   Application.ProcessMessages;
   i:=0;
    repeat
      begin
      Sleep(100);
      Application.ProcessMessages;
      Inc(i);
      Form1.statusbar.Panels[0].Text:='Wait for phone '+inttostr(300-i);
      end;
    until (DevPresent=False) or (i=300);
    Form1.statusbar.Panels[0].Text:='';
    if i=300 then begin
    result:=false;
    form1._msg('->  Boot error... Phone can'+#39+'t reboot');
    exit;
    end;
   except
   result:=False;
   Form1.pb1.progress:=0;
   Form1.pb1.maxvalue:=100;
   form1._msg('->  Boot error... :(');
   currtoken.free;
   currcert.free;
   Fs.free;
   end;
Application.ProcessMessages;
endtimecount;
form1._msg('TIME : Boot time : '+showtime(tmsres)+' ');
Application.ProcessMessages;
end;

function PrepareRAWloader(loader:TMemoryStream):TMemoryStream;
var
  b            : Boolean;
  ULO          : array[0..3] of Byte;
  MEDia        : array[0..10] of Byte;
  RAWLoader    : TMemoryStream;
begin
  ULO[0]:=$55;ULO[1]:=$4C;ULO[2]:=$4F;ULO[3]:=$00;
  MEDia[0]:=$42;MEDia[1]:=$4F;MEDia[2]:=$4F;MEDia[3]:=$54;
  MEDia[4]:=$5F;MEDia[5]:=$4D;MEDia[6]:=$45;MEDia[7]:=$44;
  MEDia[8]:=$49;MEDia[9]:=$41;MEDia[10]:=$31;
  try
  //Извлечение и патчинг RAW-loader'a
  RAWLoader:=TmemoryStream.Create;
  BB5_ExtractRAWLoader(loader, RAWLoader, b);
  //Подготовка патчинга равки
  RAWloader.Seek(20,soFromBeginning);
  RAWloader.readbuffer(Buf[0],4);
  if buf[0]<>$4B then begin   // Если не равно - начит позиция смещена на $32 вперед
  RAWloader.Seek(20,soFromBeginning); //RAP3GV4 SILO
  RAWloader.writebuffer(ulo[0],4);
  end else begin
  RAWloader.Seek(52,soFromBeginning);  //RAPUx  SILO
  RAWloader.writebuffer(ulo[0],4);
  end;
  RAWloader.Seek(148,soFromBeginning);
  RAWloader.readbuffer(Buf[0],$B);
  RAWloader.Seek(148,soFromBeginning);
  if (buf[0]=$42) and (buf[1]=$4F) then RAWloader.WriteBuffer(Media[0],$B) else result:=nil;
  //RAWloader.SaveToFile('C:\RAW_RAPNEW_patch.bin');
  Result:=RAWloader;
  except
  Result:=nil;
  end;
end;

function checkbootcode():Boolean;
begin
  result:=False;
  Sleep(50);
  Application.ProcessMessages;
  /// Check Upload Bootcode
     txBuf[0]:=$C0;
     txBuf[1]:=$61;
     txBuf[2]:=$00;
     txBuf[3]:=$00;
     txBuf[4]:=$00;
     txBuf[5]:=$00;
     txBuf[6]:=$00;
     txBuf[7]:=$10;
     USBControlPacket($222040, $8, $1000);
     //Form1._msg('rxbuf: '+BufToHexStr(@rxBuf[0], Length(rxBuf)));

     Application.ProcessMessages;
     sleep(50);
     /// Check Upload Bootcode
     txBuf[0]:=$C0;
     txBuf[1]:=$61;
     txBuf[2]:=$00;
     txBuf[3]:=$00;
     txBuf[4]:=$00;
     txBuf[5]:=$00;
     txBuf[6]:=$00;
     txBuf[7]:=$10;

     USBControlPacket($222040, $8, $1000);
     //Form1._msg('rxbuf: '+BufToHexStr(@rxBuf[0], Length(rxBuf)));
     //
     result:=True;
end;

function CheckCMTboot():Boolean;
var
  BlockCount   : Integer;
  j,k,i        : Integer;
  currblock,
  currblocklen : Byte;
  devasic      : Byte;
begin
     bufcopy(@VenCHeckUpl[0],@txbuf[0], Length(VenCHeckUpl));
     USBControlPacket($222040, Length(VenCHeckUpl), 0);
     Sleep(50);
     Application.ProcessMessages;
      /// Check Preboot
     txBuf[0]:=$C0;
     txBuf[1]:=$61;
     txBuf[2]:=$00;
     txBuf[3]:=$00;
     txBuf[4]:=$00;
     txBuf[5]:=$00;
     txBuf[6]:=$00;
     txBuf[7]:=$10;

     USBControlPacket($222040, $8, $1000);
     //Form1._msg('rxbuf: '+BufToHexStr(@rxBuf[0], Length(rxBuf)));
     if (rxbuf[0]=$C3) and (rxbuf[1]=$00) and (rxbuf[2]=$FF) then application.ProcessMessages
     else form1._msg('2nd boot not accepted... Alive Request not done :(');

     Application.ProcessMessages;

     bufcopy(@VenCheckFlic[0],@txbuf[0], Length(VenCheckFlic));
     USBControlPacket($222040, Length(VenCheckFlic), 0);
     Sleep(50);
     Application.ProcessMessages;
      /// Check FLic
     txBuf[0]:=$C0;
     txBuf[1]:=$61;
     txBuf[2]:=$00;
     txBuf[3]:=$00;
     txBuf[4]:=$00;
     txBuf[5]:=$00;
     txBuf[6]:=$00;
     txBuf[7]:=$10;

     USBControlPacket($222040, $8, $1000);
     //Form1._msg('rxbuf: '+BufToHexStr(@rxBuf[0], Length(rxBuf)));
     if rxBuf[0]=$C1 then
     begin
       BlockCount :=rxbuf[1];
       i:=2;
       j:=0;
       while j<BlockCount do
       begin
          Application.ProcessMessages;
          CurrBlock    :=rxbuf[i];
          inc(i);
          CurrBlockLen := rxbuf[i];
          inc(i);
          case CurrBlock of
          $10://data block
              begin
                   if currblocklen=$B then
				           begin
				            if rxbuf[i+1]=$03 then
                    begin
                    for k:=3 to CurrBlockLen-4 do RAPInfo.FlashID[k-3]:=rxbuf[i+k];
				            form1._msg('FLIC : '+BufToHexStr(@RAPInfo.FlashID[2],2)+BufToHexStr(@RAPInfo.FlashID[0],2));
                    end;
				           end;
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          $35: // algorithm
              begin
                   devasic:=rxbuf[i];
				           inc(i);
                   for k:=0 to CurrBlockLen-2 do RAPInfo.ALGO[k]:=rxbuf[i+k];
                   form1._msg('Req : '+hex2chr(BufToHexStr(@RAPInfo.ALGO[0],CurrBlockLen-2)));
                   inc(i, CurrBlockLen);
                   inc(j);
              end
              else
              begin
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          end;//End Of Case
        end;
     end
     else
     form1._msg('MCU configuration response not received, 2nd boot fail');

     Application.ProcessMessages;
end;

function RAPUFinalizeboot(rapmode:integer):Boolean;
begin
  result:=False;
  case rapmode of
  0:
  begin
  bufcopy(@algsend[0],@txbuf[0], Length(algsend));  //RAPU
  USBControlPacket($222040, Length(algsend), 0);    //RAPU
     Sleep(50);
     txBuf[0]:=$C0;
     txBuf[1]:=$61;
     txBuf[2]:=$00;
     txBuf[3]:=$00;
     txBuf[4]:=$00;
     txBuf[5]:=$00;
     txBuf[6]:=$00;
     txBuf[7]:=$10;
     USBControlPacket($222040, $8, $1000);  //
     Application.ProcessMessages;
  end;
  1: // RAP3Gv4
  begin
      if Pos('BCM',ExtractFileName(Floader))<>0 then
      begin
      bufcopy(@algsend3[0],@txbuf[0], Length(algsend3));  //Broadcomm
      USBControlPacket($222040, Length(algsend2), 0); // BroadComm
      end
      else
      begin
      bufcopy(@algsend2[0],@txbuf[0], Length(algsend2));  //RAP3Gv4
      USBControlPacket($222040, Length(algsend2), 0); // Rap3Gv4
       Sleep(50);
      txBuf[0]:=$C0;
      txBuf[1]:=$61;
      txBuf[2]:=$00;
      txBuf[3]:=$00;
      txBuf[4]:=$00;
      txBuf[5]:=$00;
      txBuf[6]:=$00;
      txBuf[7]:=$10;
      USBControlPacket($222040, $8, $1000);  //
      Application.ProcessMessages;
      end;
  end;
 end;

     bufcopy(@VenCHeckUpl[0],@txbuf[0], Length(VenCHeckUpl));
     USBControlPacket($222040, Length(VenCHeckUpl), 0);

      /// Check updboot
     txBuf[0]:=$C0;
     txBuf[1]:=$61;
     txBuf[2]:=$00;
     txBuf[3]:=$00;
     txBuf[4]:=$00;
     txBuf[5]:=$00;
     txBuf[6]:=$00;
     txBuf[7]:=$10;

     USBControlPacket($222040, $8, $1000);
     //Form1._msg('rxbuf: '+BufToHexStr(@rxBuf[0], Length(rxBuf)));
     Application.ProcessMessages;

     bufcopy(@bootflash[0],@txbuf[0], Length(bootflash));
     USBControlPacket($222040, Length(bootflash), 0);

      /// Check updboot
     txBuf[0]:=$C0;
     txBuf[1]:=$61;
     txBuf[2]:=$00;
     txBuf[3]:=$00;
     txBuf[4]:=$00;
     txBuf[5]:=$00;
     txBuf[6]:=$00;
     txBuf[7]:=$10;

     USBControlPacket($222040, $8, $1000);
     //Form1._msg('rxbuf: '+BufToHexStr(@rxBuf[0], Length(rxBuf)));
     if (rxbuf[0]=$C3) and (rxbuf[1]=$00) and (rxbuf[2]=$FF) then result:=true
     else form1._msg('Transmission type request fail ['+byte2str(rxbuf[0])+byte2str(rxbuf[1])+byte2str(rxbuf[2])+']');
     Application.ProcessMessages;
end;

function RAPnewChkADL ():Boolean;
begin
form1._msg('ADL: Check mode');
USBBulkWritePort(@rapuchkadl[0], Length(rapuchkadl));
if USBBulkReadPort($FFFF) then //form1._msg('rxbuf: '+buftohexstr(@rxBuf[0], Length(rxBuf)));
if cmtreadreq then application.ProcessMessages
else  begin Form1._msg('ADL: flash mode confirm error...'); result:=false; exit; end;
//form1._msg('ADL: Select ASIC');
UsbBulkWriteport(@rapuselAsic[0], length(rapuselAsic));
if USBBulkReadPort($FFFF) then //form1._msg('rxbuf: '+buftohexstr(@rxBuf[0], Length(rxBuf)));
if (rxBuf[8]=$00) and (rxBuf[9]=$00) then Application.ProcessMessages else Form1._msg('Select ASIC ['+byte2str(rxBuf[8])+byte2str(rxBuf[9])+']');
//form1._msg('ADL: PAPUBKEYS_REQ');
UsbBulkWriteport(@rapugetroot[0], length(rapugetroot));
if USBBulkReadPort($FFFF) then Application.ProcessMessages; //form1._msg('rxbuf: '+buftohexstr(@rxBuf[0], Length(rxBuf)));
//form1._msg('ADL: CRTCHK_REQ');
UsbBulkWriteport(@rapucrtchkreq[0], length(rapucrtchkreq));
if USBBulkReadPort($FFFF) then //form1._msg('rxbuf: '+buftohexstr(@rxBuf[0], Length(rxBuf)));
if cmtreadreq then application.ProcessMessages
else Form1._msg('CRT store return bad status...');
result:=true;
end;

function RAPnewChkADLWCRT ():Boolean;
begin
form1._msg('ADL: Check mode');
USBBulkWritePort(@rapuchkadl[0], Length(rapuchkadl));
if USBBulkReadPort($FFFF) then //form1._msg('rxbuf: '+buftohexstr(@rxBuf[0], Length(rxBuf)));
if cmtreadreq then application.ProcessMessages
else  begin Form1._msg('ADL: flash mode confirm error...'); result:=false; exit; end;
//form1._msg('ADL: Select ASIC');
UsbBulkWriteport(@rapuselAsic[0], length(rapuselAsic));
if USBBulkReadPort($FFFF) then //form1._msg('rxbuf: '+buftohexstr(@rxBuf[0], Length(rxBuf)));
if (rxBuf[8]=$00) and (rxBuf[9]=$00) then Application.ProcessMessages else Form1._msg('Select ASIC ['+byte2str(rxBuf[8])+byte2str(rxBuf[9])+']');
//form1._msg('ADL: PAPUBKEYS_REQ');
UsbBulkWriteport(@rapugetroot[0], length(rapugetroot));
if USBBulkReadPort($FFFF) then Application.ProcessMessages; //form1._msg('rxbuf: '+buftohexstr(@rxBuf[0], Length(rxBuf)));
result:=true;
end;

function RAPnewChkADL2 ():Boolean;
begin
form1._msg('ADL: Request programm status');
UsbBulkWriteport(@rapucloseASIC[0], length(rapucloseASIC));
if USBBulkReadPort($FFFF) then contentexplore;
//form1._msg('ADL: PAPUBKEYS_REQ');
UsbBulkWriteport(@rapugetroot[0], length(rapugetroot));
if USBBulkReadPort($FFFF) then Application.ProcessMessages; //form1._msg('rxbuf: '+buftohexstr(@rxBuf[0], Length(rxBuf)));
end;

function RapNewFinish():boolean;
begin
form1._msg('ADL: Close_Session');
UsbBulkWriteport(@rapucloseASIC[0], length(rapucloseASIC));
if USBBulkReadPort($FFFF) then form1._msg('Content: '+buftohexstr(@rxBuf[12], $0F));
form1._msg('ADL: Reboot');
Application.ProcessMessages;
Sleep(10);
UsbBulkWriteport(@rapureboot[0], length(rapureboot));
Sleep(50);
{if catchdevice<>$02 then Application.ProcessMessages
else
begin
UsbBulkWriteport(@rapureboot[0], length(rapureboot)); }
if USBBulkReadPort($FFFF) then //form1._msg('rxbuf: '+buftohexstr(@rxBuf[0], Length(rxBuf)));
if ((rxBuf[0]=$80) and (rxBuf[1]=$0F) and (rxBuf[2]=$70)) or ((rxBuf[0]=$80) and (rxBuf[1]=$F0) and (rxBuf[2]=$8F)) then application.ProcessMessages
else Form1._msg('Reboot req not accepted...');
end;

function RapNewFinishLocal():boolean;
begin
form1._msg('ADL: Close_Session');
UsbBulkWriteport(@rapucloseASIC[0], length(rapucloseASIC));
if USBBulkReadPort($FFFF) then form1._msg('Content: '+buftohexstr(@rxBuf[12], $0F));
form1._msg('ADL: Reboot');
Application.ProcessMessages;
Sleep(10);
UsbBulkWriteport(@rapurebootlocal[0], length(rapurebootlocal));
Sleep(50);
{if catchdevice<>$02 then Application.ProcessMessages
else
begin
UsbBulkWriteport(@rapureboot[0], length(rapureboot)); }
if USBBulkReadPort($FFFF) then //form1._msg('rxbuf: '+buftohexstr(@rxBuf[0], Length(rxBuf)));
if ((rxBuf[0]=$80) and (rxBuf[1]=$0F) and (rxBuf[2]=$70)) or ((rxBuf[0]=$80) and (rxBuf[1]=$F0) and (rxBuf[2]=$8F)) then application.ProcessMessages
else Form1._msg('Reboot req not accepted...');
end;


function frameCrc(Buf:Pointer; buflen:Integer):Byte;
begin
     Result:=0;
     while BufLen > 0 do begin
     Result:=Result+Byte(Buf^);
     inc(Integer(Buf));
     dec(BufLen);
     end;
     Result:=Result xor $FF;
end;

function RapuYamaErase(core:string):Boolean;
var
     fs                         : TFileStream;
     buf                        : array[0..$FFFF] of byte;
     n,j,buflen                 : Integer;
     HdrLen                     : Integer;
     HdrPos                     : LongInt;
     CurrSeem                   : Byte;
     CurrSeemLen, CurSeemcount  : Integer;
     ms                         : TMemoryStream;
     loaderlen                  : DWORD;
     erase                      : Boolean;
     framelen                   : DWORD;
begin
     Result:=false;
     partition:=false;
     erase:=False;
     Form1._msg('Erase : Processing '+ExtractFileName(core));
     Application.processmessages;
     Form1.statusbar.Panels[1].text:='';
     Application.ProcessMessages;
     fs:=TFileStream.Create(core,fmOpenRead);
     fs.Seek(0, sofromBeginning);
     fs.Read(buf[0],1);
     if buf[0]<>$B2 then
     begin
          fs.free;
          raise E.Create('Erase : Bad image file');
          Exit;
     end;
     Application.ProcessMessages;
     starttime;
     Application.ProcessMessages;
     fs.ReadBuffer(buf[0], 4);//Длина Flash Header
     HdrLen := HexToInt(IntToHex(buf[0], 2)+IntToHex(buf[1], 2)+IntToHex(buf[2], 2)+IntToHex(buf[3], 2));
     fs.Seek(4,soFromCurrent);
 try
     while fs.Position<(HdrLen) do
     begin
          fs.ReadBuffer(CurrSeem, 1);
           case CurrSeem of
          $EE:
           begin
              Application.ProcessMessages;
              form1._msg('Partitioning....');
              partition:=True;
              partitionstream:=TmemoryStream.Create;
              fs.ReadBuffer(buf[0], 2);
              CurrSeemLen:=(buf[0]*$100)+buf[1];
              partitionstream.copyFrom(fs,CurrSeemlen);
              partitionstream.Seek(0,soFromBeginning);
              Application.ProcessMessages;
                if partition=True
                then
                begin
                Application.ProcessMessages;
                framelen:=CurrSeemLen+10;
                DWord((@txBuf[0])^):=framelen;
                DWordSwap(@txbuf[0]);
                txBuf[4]:=$01;
                txBuf[5]:=$10;
                txBuf[6]:=$00;
                txBuf[7]:=frameCrc(@txbuf[0],7);
                txBuf[8]:=$64;
                partitionstream.ReadBuffer(txBuf[9], CurrSeemLen);
                txBuf[framelen-1]:=frameCrc(@txbuf[9],CurrSeemLen);
                //Form1._msg('txbuf : '+BufToHexStr(@txbuf[0],framelen));
                USBBulkWritePort(@txbuf[0],framelen);
                delay(200);
                Application.ProcessMessages;
                USBBulkReadPort($FFFF);
                //Form1._msg('RxBuf : '+buftohexstr(@rxBuf[0],Length(rxBuf)));
                 try
                  if cmtreadreq then form1._msg('Partitioning Ok...') else
                  begin
                  Form1._msg('Partitioning error : '+buftohexstr(@rxBuf[0],4));
                  form1._msg('Partitioning failed! :(');
                  result:=false;
                  end;
                  except
                  Form1._msg('Partitioning error! Phone Not respond!');
                  Application.ProcessMessages;
                  end;
                 delay(300);
                Application.ProcessMessages;
                partitionstream.free;
                end;
            end;
           $C8:
           begin
                     if stop=True then
                     begin
                     // Stopping operation
                     dostop('ERASE');
                     Form1.pb1.progress:=0;
                     Application.ProcessMessages;
                     fs.Free;
                     ms.free;
                     exit;
                     end;
                   form1._msg('Erasing....');
                   erase:=True;
                   Application.ProcessMessages;
                   fs.ReadBuffer(buf[0], 1);
                   CurrSeemLen:=buf[0];
                   ms:=TmemoryStream.Create;
                   ms.copyFrom(fs,CurrSeemlen);
                   ms.Seek(0,soFromBeginning);
                   framelen:=CurrSeemLen+10;
                   DWord((@txBuf[0])^):=framelen;
                   DWordSwap(@txbuf[0]);
                   txBuf[4]:=$01;
                   txBuf[5]:=$10;
                   txBuf[6]:=$00;
                   txBuf[7]:=frameCrc(@txbuf[0],7);
                   txBuf[8]:=$50;
                   ms.ReadBuffer(txBuf[9], CurrSeemLen);
                   txBuf[framelen-1]:=frameCrc(@txbuf[9],CurrSeemLen);
                   //Form1._msg('txbuf : '+BufToHexStr(@txbuf[0],framelen));
                   USBBulkWritePort(@txbuf[0],framelen);
                   delay(200);
                   Application.ProcessMessages;
                   USBBulkReadPort($FFFF);
                   //Form1._msg('RxBuf : '+buftohexstr(@rxBuf[0],Length(rxBuf)));
                   try
                   if cmtreadreq then
                   begin
                   form1._msg('Erasing Ok...');
                   Result:=True;
                   end
                   else
                   begin
                   Form1._msg('Erase error : '+buftohexstr(@rxBuf[0],4));
                   form1._msg('Erasing failed! :(');
                   form1._msg('');
                   result:=false;
                   end;
                   except
                   Form1._msg('Erase error : Connection lost => HW error or Cable problem...');
                   form1._msg('Erasing failed! :(');
                   form1._msg('');
                   fs.Free;
                   ms.free;
                   exit;
                   end;
                   delay(300);
                   Application.ProcessMessages;
                   endtimecount;
                   Form1._msg('TIME : Erase time : '+showtime(tmsres)+' ');
                   Application.ProcessMessages;
                   Form1.pbsm1.Progress:=0;
                   fs.Free;
                   ms.free;
                   exit;
           end
           else
           begin
              // Form1._msg('SEEM : '+byte2str(currseem));
               fs.ReadBuffer(buf[0], 1);
               CurrSeemLen:=buf[0];
               fs.readbuffer(buf[0],CurrSeemLen);
               application.ProcessMessages;
           end;
          end;
     end;
     if erase=False then
     begin
      result:=True;
      Form1._msg('Erase : No any region, skip erase');
      end;
     fs.Free;
 except
        on E:Exception do
        begin
             fs.Free;
             Form1._msg('EraseFile: Error: '+E.Message);
        end;
 end;
Application.ProcessMessages;
endtimecount;
Form1._msg('TIME : Erase time : '+showtime(tmsres)+' ');
Application.ProcessMessages;
end;

function RapuYamaWriteFile(core:string):Boolean;
const
      maxlen             : dWORD = $4FFFF ;
var
     buf                :array[0..$4FFFF] of byte;
     HdrLen,
     CurrBlockLen       : Cardinal;
     EntryPoint,
     DataLen,
     TargetOffset,
     CRCTmp             : LongInt;
     i, n, Blocks,
     Packets,icl,
     CurrPacketSize,
     TokenHdrLen        : Integer;
     good               : Integer;
     CertName,AsicType  : String;
     PAPUB_Already,
     APE_PAPUB          : boolean;
     fs                 : TFileStream;
     ms                 : TMemoryStream;
     writen,framelen    : Dword;
     cmtcount,cmtdin,
     TokenSubType, unk  : integer;
     nopbyte            : byte;
     nopword            : word;
     ttxbuf              : array[0..$4FFFF] of byte;
begin
     Result:=False;
     Form1._msg('Write : Processing '+ExtractFileName(core));
     fs:=TFileStream.Create(core,fmOpenRead);
     fs.Seek(0, sofromBeginning);
     Blocks:=0;
     cmtcount:=0; cmtdin:=0;
     unk:=0;
     Form1.pb1.ForeColor:=clGreen;
     Form1.pb1.progress:=0;
     Application.ProcessMessages;
try
     fs.Read(ttxbuf[0],1);
     if ttxbuf[0]<>$B2 then
     begin
          fs.free;
          raise E.Create('Write : Bad image file');
     end;

     Application.ProcessMessages;
     starttime;
     Application.ProcessMessages;

     fs.ReadBuffer(ttxbuf[0], 4);//Длина Flash-header'a
     HdrLen     := HexToInt(IntToHex(ttxbuf[0], 2)+IntToHex(ttxbuf[1], 2)+
                            IntToHex(ttxbuf[2], 2)+IntToHex(ttxbuf[3], 2));

     fs.Seek(HdrLen, sofromcurrent);//К началу первого Flash-токена
     {ms:=TMemoryStream.Create;}
     form1.pb1.maxvalue:=(fs.size-hdrlen);
     form1.statusbar.Panels.Items[0].Text:='Writing...';
     while fs.Position<fs.Size do
     begin
            if stop=True then
            begin
             // Stopping operation
               dostop('WRITE');
               Form1.pb1.progress:=0;
               Application.ProcessMessages;
               fs.Free;
               result:=false;
               exit;
            end;
          fs.ReadBuffer(ttxbuf[8], 1);
          case ttxbuf[8] of
          $54://Flash-token
              begin
                   //54 0117 0E 000300 4D9C 01 00000400 00000000 E8
                   fs.ReadBuffer(ttxbuf[$09], $3);//Чтение значения подтипа токена и длины его заголовка
                   TokenHdrLen:=ttxbuf[$0B];//Длина заголовка токена
                   TokenSubType:=TokenHdrLen;
                   fs.Seek(fs.position-4, sofrombeginning);//смещение на начало токена
                   inc(TokenHdrLen, 5);//Увеличим длину до общей длины токена с его CRC
                   fs.ReadBuffer(ttxbuf[8], TokenHdrLen);//Чтение значений токена с его CRC

                   //Длина текущего блока между токенами
                   CurrBlockLen := HexToInt(IntToHex(ttxbuf[TokenHdrLen-1], 2)+
                                            IntToHex(ttxbuf[TokenHdrLen],   2)+
                                            IntToHex(ttxbuf[TokenHdrLen+1], 2)+
                                            IntToHex(ttxbuf[TokenHdrLen+2], 2));
                   //Form1._msg('CurrLen : '+inttostr(CurrBlockLen));

                   case TokenSubType of
                   $0E :
                   begin
                   ttxbuf[8+TokenHdrLen]:=$00;//Добавление байта-разделителя $00
                   fs.ReadBuffer(ttxbuf[9+TokenHdrLen], CurrBlockLen);//Копирование данных токена в буфер
                   framelen:=CurrBlockLen+TokenHdrLen+$09;//Состоит из 8 байт команды, токена, байта-разделитель,
                   end;
                   $15 :
                   begin
                   DWord((@ttxBuf[$8+TokenHdrLen])^):=$0000;//Добавление байта-разделителя $0000
                   fs.ReadBuffer(ttxbuf[$0A+TokenHdrLen], CurrBlockLen);//Копирование данных токена в буфер
                   framelen:=CurrBlockLen+TokenHdrLen+$0A;//Состоит из 8 байт команды, токена, байта-разделитель,
                   end;
                   else
                   DWord((@ttxBuf[$8+TokenHdrLen])^):=$0000;//Добавление байта-разделителя $0000
                   fs.ReadBuffer(ttxbuf[$0A+TokenHdrLen], CurrBlockLen);//Копирование данных токена в буфер
                   framelen:=CurrBlockLen+TokenHdrLen+$0A;//Состоит из 8 байт команды, токена, байта-разделитель,
                   end;
                   //Расчет длины фрейма                  //              данных пакета
                   DWord((@ttxBuf[0])^):=framelen;
                   DWordSwap(@ttxbuf[0]);
                   //form1._msg('Token Len : '+IntToStr(framelen));
                   ttxBuf[4]:=$01;
                   ttxBuf[5]:=$10;
                   ttxBuf[6]:=$00;
                   //Расчет первой crc (crc шапки команды)
                   ttxBuf[7]:=frameCrc(@ttxbuf[0],7);

                   //Form1._msg('txbuf : '+BufToHexStr(@txbuf[0],framelen));
                   USBBulkWritePort(@ttxbuf[0],framelen);
                   USBBulkReadPort($FFFF);
                   //Form1._msg('RxBuf : '+buftohexstr(@rxBuf[0],Length(rxBuf)));
                   try
                   if cmtreadreq then Application.ProcessMessages
                   else
                   begin
                   Form1._msg('Write CMT block error : '+buftohexstr(@rxBuf[0],4));
                   form1._msg('Write CMT failed on block '+inttostr(Blocks)+' :(');
                   form1._msg('');
                   result:=false;
                   fs.free;
                   exit;
                   end;
                   except
                   Form1._msg('Write error : Connection lost => HW error or Cable problem...');
                   form1._msg('Write CMT failed on block '+inttostr(Blocks)+' :(');
                   form1._msg('');
                   fs.Free;
                   exit;
                   end;

                   Application.ProcessMessages;

                   inc(blocks);
              form1.statusbar.Panels[1].Text:='CMT : '+inttostr(Blocks);
              end;//End of Case $54

          $5D://Phoenix-segment
              begin
                   //5D 0127 2D 25B977A055BE9B5DEC0C38A2A279C695 8594B99841444100000000000000000000030077E7 00000400 000A0800 BB
                   //       Len          RootKey Hash                                                         Len     Flash   CRC
                   //5D 0128 43 25B977A055BE9B5DEC0C38A2A279C695 8594B99850415055424B4559530000000003 00A70900 00060000 11F000397DCE210733C335E84BAD369EC893FCA06D1BC3 0100 A5
                   //       Len          RootKey Hash                                                    Len     Flash                                                      CRC

                   fs.ReadBuffer(ttxbuf[$09], $3);//Чтение значения подтипа токена и длины его заголовка
                   TokenHdrLen:=ttxbuf[$0B];//Длина заголовка токена
                   TokenSubType:=TokenHdrLen;
                   fs.Seek(fs.position-4, sofrombeginning);//смещение на начало токена
                   inc(TokenHdrLen, 5);//Увеличим длину до общей длины токена с его CRC
                   fs.ReadBuffer(ttxbuf[8], TokenHdrLen);//Чтение значений токена с его CRC

                   case TokenSubType of
                   $2D:
                       //Длина текущего блока между токенами
                       CurrBlockLen := HexToInt(IntToHex(ttxbuf[TokenHdrLen-1], 2)+
                                                IntToHex(ttxbuf[TokenHdrLen],   2)+
                                                IntToHex(ttxbuf[TokenHdrLen+1], 2)+
                                                IntToHex(ttxbuf[TokenHdrLen+2], 2));
                   $43:
                       //Длина текущего блока между токенами
                       CurrBlockLen := HexToInt(IntToHex(ttxbuf[TokenHdrLen-$17], 2)+
                                                IntToHex(ttxbuf[TokenHdrLen-$16], 2)+
                                                IntToHex(ttxbuf[TokenHdrLen-$15], 2)+
                                                IntToHex(ttxbuf[TokenHdrLen-$14], 2));
                   else
                   begin
                        fs.Free;
                        E.Create('Write : Bad image file');
                   end;
                   end;//End of Case

                   //Сравнение RootKey Hash телефона и RootKey Hash блока сертов
                   good:=0;
                   for i:=$0 to $0F do if RAPInfo.Root_Key_Hash[i]=ttxbuf[i+$0C] then inc(good);

                   if good<$10 then
                   begin//RootKey Hash не совпал, пропускаем
                        fs.Seek(CurrBlockLen, soFromCurrent);//Пропускаем токен и его данные
                        continue;
                   end
                   else
                   begin//RootKey Hash серта совпал, копируем
                        case TokenSubType of
                        $2D:
                        begin
                        DWord((@ttxBuf[$8+TokenHdrLen])^):=$0000;//Добавление слова-разделителя $0000

                        fs.ReadBuffer(ttxBuf[$0A+TokenHdrLen],CurrBlockLen);//Копирование данных
                        Application.ProcessMessages;
                        CertName:='';
                        for i:=32 to 45 do if ttxbuf[i]=$00 then break else CertName:=CertName+Chr(ttxbuf[i]);
                        Form1._msg('CMT: Writing Hash CERT ['+CertName+']');
                        Application.ProcessMessages;
                        framelen:=CurrBlockLen+TokenHdrLen+$0A;//Состоит из 8 байт команды, токена, слова-разделителя,
                        //Расчет длины фрейма                  //              данных пакета
                        DWord((@ttxBuf[0])^):=framelen;
                        DWordSwap(@ttxbuf[0]);
                        //form1._msg('Cert Len : '+IntToStr(framelen));
                        ttxBuf[4]:=$01;
                        ttxBuf[5]:=$10;
                        ttxBuf[6]:=$00;

                        //Расчет первой crc (crc шапки команды)
                        ttxBuf[7]:=frameCrc(@ttxbuf[0],7);

                        //Form1._msg('txbuf : '+BufToHexStr(@txbuf[0],framelen));
                        USBBulkWritePort(@ttxbuf[0],framelen);
                        USBBulkReadPort($FFFF);
                        //Form1._msg('RxBuf : '+buftohexstr(@rxBuf[0],Length(rxBuf)));
                         try
                         if cmtreadreq then Application.ProcessMessages
                         else
                         begin
                         Form1._msg('Write cert error : '+buftohexstr(@rxBuf[0],4));
                         form1._msg('Write cert failed! :(');
                         form1._msg('');
                         result:=false;
                         fs.free;
                         exit;
                         end;
                         except
                         Form1._msg('Write cert error : Connection lost => HW error or Cable problem...');
                         form1._msg('Write cert failed! :(');
                         form1._msg('');
                         result:=false;
                         fs.free;
                         exit;
                         end;
                        Application.ProcessMessages;
                        inc(blocks);
                        Application.ProcessMessages;
                        form1.statusbar.Panels[1].Text:='CMT : '+inttostr(Blocks);
                        end;
                        $43:
                        begin
                        fs.ReadBuffer(ttxBuf[$08+TokenHdrLen],CurrBlockLen);//Копирование данных
                        Form1._msg('CMT: Writing Hash CERT [PAPUBKEYS]');
                        Application.ProcessMessages;
                        framelen:=CurrBlockLen+TokenHdrLen+$08;//Состоит из 8 байт команды, токена, слова-разделителя,
                        //Расчет длины фрейма                  //              данных пакета
                        DWord((@ttxBuf[0])^):=framelen;
                        DWordSwap(@ttxbuf[0]);
                        //form1._msg('Cert Len : '+IntToStr(framelen));
                        ttxBuf[4]:=$01;
                        ttxBuf[5]:=$10;
                        ttxBuf[6]:=$00;

                        //Расчет первой crc (crc шапки команды)
                        ttxBuf[7]:=frameCrc(@ttxbuf[0],7);

                        //Form1._msg('txbuf : '+BufToHexStr(@txbuf[0],framelen));
                        USBBulkWritePort(@ttxbuf[0],framelen);
                        USBBulkReadPort($FFFF);
                        //Form1._msg('RxBuf : '+buftohexstr(@rxBuf[0],Length(rxBuf)));
                         try
                         if cmtreadreq then Application.ProcessMessages
                         else
                         begin
                         Form1._msg('Write PAPUBKEYS error : '+buftohexstr(@rxBuf[0],4));
                         form1._msg('Write PAPUBKEYS failed! :(');
                         form1._msg('');
                         result:=false;
                         fs.free;
                         exit;
                         end;
                         except
                         Form1._msg('Write PAPUBKEYS error : Connection lost => HW error or Cable problem...');
                         form1._msg('Write PAPUBKEYS failed! :(');
                         form1._msg('');
                         result:=false;
                         fs.free;
                         exit;
                         end;
                        Application.ProcessMessages; 
                        inc(blocks);
                        Application.ProcessMessages;
                        form1.statusbar.Panels[1].Text:='CMT : '+inttostr(Blocks);
                        end;
                    end;
                   end;
              end//End of Case $5D
          else
              begin//Unknow Tokens or Bad File
                   fs.free;
                   E.Create('Write : Bad image file');
              end;
          end;//End of Case
     form1.pb1.progress:=fs.Position;
     end;//End of While
     fs.free;
     Form1._msg('Total writen '+inttostr(blocks)+' blocks');
     form1.statusbar.Panels[1].Text:='';
     Application.ProcessMessages;
     endtimecount;
     Form1._msg('TIME : Write time : '+showtime(tmsres)+' ');
     result:=True;
     //form1._msg('Errors : '+inttostr(GetLastError));
     Exit;

     {writen:=0;
     if Blocks=0 then
     begin
          Form1._msg('No any data for write, skip write');
          ms.Free;
          result:=True;
          Exit;
     end;}



     //54 0117 0E 000300 4D9C 01 00000400 00000000 E8
                   {fs.ReadBuffer(buf[0], $3);//Чтение значения подтипа токена и длины его заголовка
                   TokenHdrLen:=buf[2];//Длина заголовка токена
                   fs.Seek(fs.position-4, sofrombeginning);//смещение на начало токена
                   inc(TokenHdrLen, 5);//Увеличим длину до общей длины токена с его CRC
                   fs.ReadBuffer(buf[0], TokenHdrLen);//Чтение значений токена с его CRC
                   /Длина текущего блока между токенами
                   CurrBlockLen := HexToInt(IntToHex(txbuf[TokenHdrLen-9], 2)+
                                            IntToHex(txbuf[TokenHdrLen-8], 2)+
                                            IntToHex(txbuf[TokenHdrLen-7], 2)+
                                            IntToHex(txbuf[TokenHdrLen-6], 2));

                   Application.ProcessMessages;
                   ms.WriteBuffer(buf[0], TokenHdrLen);//Копирование текущего токена
                   buf[0]:=0;
                   ms.WriteBuffer(buf[0], 1);//Добавление байта-разделителя $00
                   ms.CopyFrom(fs, CurrBlockLen);//Копирование данных
                   Application.ProcessMessages;
                   inc(blocks);
              end;//End of Case $54

              $5D://Phoenix-segment
              begin
                   //5D 0127 2D 25B977A055BE9B5DEC0C38A2A279C695 8594B99841444100000000000000000000030077E7 00000400 000A0800 BB
                   //       Len          RootKey Hash                                                         Len     Flash   CRC
                   //5D 0128 43 25B977A055BE9B5DEC0C38A2A279C695 8594B99850415055424B4559530000000003 00A70900 00060000 11F000397DCE210733C335E84BAD369EC893FCA06D1BC3 0100 A5
                   //       Len          RootKey Hash                                                    Len     Flash                                                      CRC

                   fs.ReadBuffer(buf[0], $3);//Чтение значения подтипа токена и длины его заголовка
                   TokenHdrLen:=buf[2];//Длина заголовка токена
                   TokenSubType:=TokenHdrLen;
                   fs.Seek(fs.position-4, sofrombeginning);//смещение на начало токена
                   inc(TokenHdrLen, 5);//Увеличим длину до общей длины токена с его CRC
                   fs.ReadBuffer(buf[0], TokenHdrLen);//Чтение значений токена с его CRC

                   case TokenSubType of
                   $2D:
                       //Длина текущего блока между токенами
                       CurrBlockLen := HexToInt(IntToHex(buf[TokenHdrLen-9], 2)+
                                                IntToHex(buf[TokenHdrLen-8], 2)+
                                                IntToHex(buf[TokenHdrLen-7], 2)+
                                                IntToHex(buf[TokenHdrLen-6], 2));
                   $43:
                       //Длина текущего блока между токенами
                       CurrBlockLen := HexToInt(IntToHex(buf[TokenHdrLen-$1F], 2)+
                                                IntToHex(buf[TokenHdrLen-$1E], 2)+
                                                IntToHex(buf[TokenHdrLen-$1D], 2)+
                                                IntToHex(buf[TokenHdrLen-$1C], 2));
                   else
                   begin
                        ms.Free;
                        E.Create('Write : Bad image file');
                   end;
                   end;//End of Case

                   //Сравнение RootKey Hash телефона и RootKey Hash блока сертов
                   good:=0;
                   for i:=$0 to $0F do if RAPInfo.Root_Key_Hash[i]=buf[i+4] then inc(good);
                   Application.ProcessMessages;

                   if good<$10 then
                   begin//RootKey Hash не совпал, пропускаем
                        fs.Seek(CurrBlockLen, soFromCurrent);//Пропускаем токен и его данные
                        continue;
                   end
                   else
                   begin//RootKey Hash серта совпал, копируем
                        ms.WriteBuffer(buf[0], TokenHdrLen);//Копирование текущего токена
                        buf[0]:=0; buf[1]:=0;
                        ms.WriteBuffer(buf[0], 2);//Добавление слова-разделителя $0000
                        Application.ProcessMessages;
                        ms.CopyFrom(fs, CurrBlockLen);//Копирование данных
                        Application.ProcessMessages;
                        inc(blocks);
                   end;
              end//End of Case $5D}









    {ms.Seek(0, sofrombeginning);
    ms.SaveToFile('C:\1.bin');
    ms.Seek(0, sofrombeginning);
    Form1._msg('Total '+IntToStr(blocks)+' ['+inttostr(cmtcount)+'/'+inttostr(unk)+'] blocks to write, writing... ');
    Application.ProcessMessages;
    Form1.statusbar.Panels[0].text:='Write Data....';
    //Form1.statusbar.panels[1].text:='Time : '+inttostr(blocks div 10)+' sec...';
    Form1.pb1.progress:=0;
    Form1.pb1.MaxValue:=Blocks;
    Application.ProcessMessages;
    Form1.statusbar.Panels[1].text:='0/'+inttostr(cmtcount);
    while ms.Position<ms.Size do
    begin
         form1._msg('POS : '+inttostr(ms.position));
         ms.ReadBuffer(buf[0], 1);
         case buf[0] of

         $54://Phoenix-token
             begin
                  ms.ReadBuffer(buf[0], $3);//Чтение значения подтипа токена и длины его заголовка
                  TokenHdrLen:=buf[2];//Длина заголовка токена
                  ms.Seek(ms.position-4, sofrombeginning);//смещение на начало токена
                  inc(TokenHdrLen, 5);//Увеличим длину до общей длины токена с его CRC
                  ms.ReadBuffer(buf[0], TokenHdrLen);//Чтение значений токена с его CRC

                   //Длина текущего блока между токенами
                   CurrBlockLen := HexToInt(IntToHex(buf[TokenHdrLen-9], 2)+
                                            IntToHex(buf[TokenHdrLen-8], 2)+
                                            IntToHex(buf[TokenHdrLen-7], 2)+
                                            IntToHex(buf[TokenHdrLen-6], 2));

                   //Оффсет по которому будет записан данный блок
                   TargetOffset := HexToInt(IntToHex(buf[TokenHdrLen-5], 2)+
                                            IntToHex(buf[TokenHdrLen-4], 2)+
                                            IntToHex(buf[TokenHdrLen-3], 2)+
                                            IntToHex(buf[TokenHdrLen-2], 2));

                   Form1._msg(IntToStr(CurrBlockLen)+'/'+inttostr(TargetOffset));
                   Application.ProcessMessages;
                   ms.Seek(CurrBlockLen+1,soFromCurrent);//пропускаем данные и байт-разделитель $00
                   inc(cmtdin);
                   Form1.pb1.progress:=Form1.pb1.progress+1;
                   Form1.statusbar.Panels[1].text:='CMT : '+inttostr(cmtdin)+'/'+inttostr(cmtcount);
                   Application.ProcessMessages;
             end;//end of case $54 - write Data

         $5D://Phoenix-segment
             begin
                  ms.ReadBuffer(buf[0], $3);//Чтение значения подтипа токена и длины его заголовка
                  TokenHdrLen:=buf[2];//Длина заголовка токена
                  TokenSubType:=TokenHdrLen;
                  ms.Seek(ms.position-4, sofrombeginning);//смещение на начало токена
                  inc(TokenHdrLen, 5);//Увеличим длину до общей длины токена с его CRC
                  ms.ReadBuffer(buf[0], TokenHdrLen);//Чтение значений токена с его CRC

                   case TokenSubType of
                   $2D:
                       //Длина текущего блока между токенами
                       CurrBlockLen := HexToInt(IntToHex(buf[TokenHdrLen-9], 2)+
                                                IntToHex(buf[TokenHdrLen-8], 2)+
                                                IntToHex(buf[TokenHdrLen-7], 2)+
                                                IntToHex(buf[TokenHdrLen-6], 2));
                   $43:
                       //Длина текущего блока между токенами
                       CurrBlockLen := HexToInt(IntToHex(buf[TokenHdrLen-$1F], 2)+
                                                IntToHex(buf[TokenHdrLen-$1E], 2)+
                                                IntToHex(buf[TokenHdrLen-$1D], 2)+
                                                IntToHex(buf[TokenHdrLen-$1C], 2));
                   else
                   begin
                        ms.Free;
                        E.Create('Write : Bad image file');
                   end;
                   end;//End of Case

                   ms.ReadBuffer(buf[0], CurrBlockLen+1);//Чтение данных в буфер с учетом байта-разделителя $00
                   Form1._msg(IntToStr(CurrBlockLen)+'/'+inttostr(TargetOffset));
                   Application.ProcessMessages;

                   //Сравнение RootKey Hash телефона и RootKey Hash блока сертов
                   good:=0;
                   for i:=$0 to $0F do if RAPInfo.Root_Key_Hash[i]=buf[i+4] then inc(good);

                   if good<$10 then
                   begin//RootKey Hash не совпал, пропускаем
                        Form1.pb1.progress:=form1.pb1.progress+1;
                        inc(cmtdin);
                        Form1.statusbar.Panels[1].text:='CMT : '+inttostr(cmtdin)+'/'+inttostr(cmtcount);
                        Application.ProcessMessages;
                        ms.Seek(CurrBlockLen, soFromCurrent);//Пропускаем токен и его данные
                        continue;
                   end
                   else
                   begin//RootKey Hash серта совпал, копируем
                        AsicType:='CMT : ';
                        Form1._msg('RootKey : '+buftohexstr(@Buf[4],$0F));
                        CertName:='';
                        for i:=20 to 31 do if buf[i+4]=$00 then break else CertName:=CertName+Chr(buf[i+4]);

                        Form1._msg(AsicType+'Writing Hash CERT ['+CertName+']');
                        Application.ProcessMessages;
                        inc(cmtdin);

                        ms.ReadBuffer(buf[0], TokenHdrLen+2);//Копирование текущего токена с учетом слова-разделителя $0000
                        ms.Seek(CurrBlockLen, soFromCurrent);//Пропускаем данных
                        inc(blocks);
                   end;
             end//End of Case $5D - write Cert
         else
             begin//Unknow Tokens or Bad File
                  ms.Free;
                  E.Create('Write : Bad image file');
             end;
         end;//End of Case
     end;//End of While
     ms.free;}
     Result:=True;

except
     on E:Exception do
     begin
          Form1._msg('Error: '+E.Message);
          Form1.pb1.Progress:=0;
          USBClosePort;
          exit;
     end;
end;
     Form1.pb1.Progress:=0;
end;

function  BB5_FlashingXSR16():boolean;
var
     b, proto         : Boolean;
     i                : integer;
     rb               : Byte;
     ms               : TMemoryStream;
begin
     fltime:=0;
     Form1._msg('Reopening the connection...');
     Application.ProcessMessages;
     Sleep(500);
     Application.ProcessMessages;

     i:=30;
     while i>0 do
     begin
          Form1._msg('Waiting for response: '+inttostr(i));
          Application.ProcessMessages;
          if catchdevice<>$02 then
          begin
          Application.ProcessMessages;
          sleep (1000);
           if stop=true then
           begin
           dostop('BOOT');
           Application.ProcessMessages;
           i:=0;
           end;
          Application.ProcessMessages;
          end
          else i:=0;
          dec(i);
     end;

     if not DevPresent then
     begin
          Form1._msg('Phone not found... :(');
          Form1.SetBuzy;
          Form1.StatusBar.Panels[4].Text:='';
          result:=False;
          USBClosePort;
          exit;
     end;

     RAPnewChkADL;

     Form1._msg('ADL: phone is in flash mode');
     //Добавил для удобства кастом-прошивки
     Form1.statusbar.Panels[0].Text:='';
     Form1.statusbar.Panels[1].Text:='';
     Form1.statusbar.Panels[2].Text:='';
     Form1.statusbar.Panels[4].Text:='FLASHING';
     Form1.statusbar.Panels[3].Text:='Connected';
     Form1.TimConChk.Interval:=100;
     Application.ProcessMessages;

     if Form1.chkBackup.Checked=True then
     begin
     try
     Form1._msg('');
     form1._msg('Backup enabled, will read all certificates...');
     grabrpl(0);
     Form1.writeRpl(imei_global);
     finally
     Application.ProcessMessages;
     end;
     Application.ProcessMessages;
     end;

     delay(1000);

     if Form1.chkMCUen.Checked=true then
     begin
          Form1.chkMCUen.Enabled:=False;
          Form1._msg('   ===Flashing [MCU]===');
          if not RapuYamaErase(core) then begin StuffFlashReset; result:=False; Exit; end;
          Application.ProcessMessages;
          if not RapuYamaWriteFile(core) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('MCU Write done');
           Application.ProcessMessages;
           RAPnewChkADL2;
           Application.ProcessMessages;
     end;

     delay(1000);

     Application.ProcessMessages;
     if Form1.chkPPMe.Checked=true then
     begin
            Form1.chkPPMe.Enabled:=False;
            Form1.chkMCUen.Enabled:=False;
          Form1._msg('   ===Flashing [PPM]===');
          if not RapuYamaErase(ppm) then begin StuffFlashReset; result:=False; Exit; end;
           Application.ProcessMessages;
          if not RapuYamaWriteFile(ppm) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('PPM Write done');
          Application.ProcessMessages;
          RAPnewChkADL2;
          Application.ProcessMessages;
     end;

     delay(1000);

     Application.ProcessMessages;
      if Form1.chkPPM1e.Checked=true then
     begin
            Form1.chkPPMe.Enabled:=False;
            Form1.chkMCUen.Enabled:=False;
            Form1.chkPPM1e.Enabled:=False;
          Form1._msg('   ===Flashing [PPM2]===');
          if not RapuYamaErase(ppm1) then begin StuffFlashReset; result:=False; Exit; end;
           Application.ProcessMessages;
          if not RapuYamaWriteFile(ppm1) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('PPM Write done');
           Application.ProcessMessages;
           RAPnewChkADL2;
           Application.ProcessMessages;
     end;

     delay(1000);

     Application.ProcessMessages;
     if Form1.chkCNTe.Checked=true then
     begin
            Form1.chkPPMe.Enabled:=False;
            Form1.chkMCUen.Enabled:=False;
            Form1.chkPPM1e.Enabled:=False;
            Form1.chkCNTe.Enabled:=False;
          Form1._msg('   ===Flashing [CNT]===');
          if not RapuYamaErase(image) then begin StuffFlashReset; result:=False; Exit; end;
          Application.ProcessMessages;
          if not RapuYamaWriteFile(image) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('CNT Write done');
          Application.ProcessMessages;
          RAPnewChkADL2;
          Application.ProcessMessages;
     end;

     delay(1000);

     Application.ProcessMessages;
      if Form1.chkAPEe.Checked=true then
     begin
            Form1.chkPPMe.Enabled:=False;
            Form1.chkMCUen.Enabled:=False;
            Form1.chkPPM1e.Enabled:=False;
            Form1.chkCNTe.Enabled:=False;
            Form1.chkAPEe.Enabled:=False;
          Form1._msg('   ===Flashing [APE]===');
          if not RapuYamaErase(ape) then begin StuffFlashReset; result:=False; Exit; end;
          Application.ProcessMessages;
          if not RapuYamaWriteFile(ape) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('APE Write done');
          Application.ProcessMessages;
          RAPnewChkADL2;
          Application.ProcessMessages;
     end;

     delay(1000);

     Application.ProcessMessages;
     if Form1.chkcnt3.Checked=true then
     begin
            Form1.chkPPMe.Enabled:=False;
            Form1.chkMCUen.Enabled:=False;
            Form1.chkPPM1e.Enabled:=False;
            Form1.chkCNTe.Enabled:=False;
            Form1.chkAPEe.Enabled:=False;
            Form1.chkcnt3.Enabled:=False;
          Form1._msg('   ===Flashing [CNT3]===');
          if not RapuYamaErase(cnt3) then begin StuffFlashReset; result:=False; Exit; end;
          Application.ProcessMessages;
          if not RapuYamaWriteFile(cnt3) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('CNT Write done');
           Application.ProcessMessages;
           RAPnewChkADL2;
           Application.ProcessMessages;
     end;

     Application.ProcessMessages;
     RapNewFinish; // режим рестарта
     Application.ProcessMessages;
     Form1._msg('');
     Form1._msg('Flashing done!');
     Form1._msg('Total flash time : '+showtime(fltime));
     Form1._msg('Reboot phone now...');
     Form1._msg('');
     Application.ProcessMessages;
     fltime:=0;
     Form1.statusbar.Panels[0].Text:='';
     Form1.pb1.ForeColor:=clNavy;
     Form1.pbsm1.ForeColor:=clNavy;
     Form1.pb1.MaxValue:=100;
     Form1.pb1.progress:=0;
     Form1.statusbar.Panels[1].Text:='';
     Form1.TimConChk.Interval:=2000;

     Form1.pb1.color:=clActiveBorder;

     if affenabled then Form1.afterFlashdo;

     Application.ProcessMessages;
     delay(300);
     Form1.SetReady;
     Form1.TimConChk.Enabled:=true;
     Form1._msg('Done!');
      Form1.chkPPMe.Enabled:=True;
      Form1.chkMCUen.Enabled:=True;
      Form1.chkPPM1e.Enabled:=True;
      Form1.chkCNTe.Enabled:=True;
      Form1.chkAPEe.Enabled:=True;
      Form1.chkcnt3.Enabled:=True;
     Result:=true;
end;//End of Normal Mode Flashing

function NomandicRawextract():Boolean;
var
  i,k,j,m,blockcount,l :Integer;
  CurrBlock            : Byte;
  CurrBlockLen         : integer;
  fs                   : TFileStream;
  Rawloader,Rawblock   : TmemoryStream;
  rawsize              : Int64;
  bulkread             : integer;
  loaderinfo           : string;
begin
  result:=false;
 Form1._msg('Req CMT info');
 DWord((@txBuf[0])^):=$0B;
 DWordSwap(@txbuf[0]);
 UsbBulkWriteport(@txbuf[0],4);
 Application.ProcessMessages;
 UsbBulkWriteport(@NomSelAPE, Length(NomSelAPe));
 repeat
 bulkread:=usbbulkreadportint($FFFF)
 until bulkread<>0;
  // Root Hash
     Application.ProcessMessages;
     FillMemory(@RAPInfo.ROOT_KEY_HASH,$10,$00);
     //FillMemory(@RAPInfo.APErootkey,$10,$00);
     FillMemory(@RAPInfo.FlashID,$A,$00);
     FillMemory(@RAPInfo.APEFlashID,$A,$00);
     FillMemory(@RAPInfo.PublicID,$14,$00);
     FillMemory(@RAPInfo.BootID,$8,$00);
     Application.ProcessMessages;
     Application.ProcessMessages;
     BlockCount :=rxbuf[20];

     i:=21;
     j:=0;
     m:=0;
     while j<BlockCount do
     begin
          CurrBlock    :=rxbuf[i];
          inc(i);
          CurrBlockLen := HexToInt(IntToHex(rxbuf[i], 2));
          inc(i);
          case CurrBlock of
          $01://RAP SYSTEM ASIC ID
              //5800 - 000000010000022600010006400C192101031103 [RAPIDO3G ver: 1.x]
              begin
                inc(i);
                   CurrBlockLen:=CurrBlockLen-1;
                   for k:=0 to CurrBlockLen-1 do RAPInfo.SYSTEM_ASIC_ID[k]:= rxbuf[i+k];
                   Form1._msg('ASIC ID:       '+ BufToHexStr(@RAPInfo.SYSTEM_ASIC_ID[0], Length(RAPInfo.SYSTEM_ASIC_ID)));
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          $02://RAP EMx ID
              //00000295
              //00000B22
              begin
                   inc(i);
                   CurrBlockLen:=CurrBlockLen-1;
                   if CurrBlockLen=4 then
                   for k:=0 to CurrBlockLen-1 do RAPInfo.EMx_ID[k]:= rxbuf[i+k];
                   Form1._msg('EM'+inttostr(m)+' ID:        '+ BufToHexStr(@RAPInfo.EMx_ID[0],    4));
                   inc(i, CurrBlockLen);
                   inc(j);inc(m);
              end;
          $12://PUBLIC_ID
              //1FF0001841158B52064E64D3C3E9A7F38DC47E29
              begin
                inc(i);
                   CurrBlockLen:=CurrBlockLen-1;
                   for k:=0 to CurrBlockLen-1 do RAPInfo.PUBLIC_ID[k]:= rxbuf[i+k];
                   Form1._msg('PUBLIC ID:     '+ BufToHexStr(@RAPInfo.PUBLIC_ID[0],    Length(RAPInfo.PUBLIC_ID)));
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          $13://ASIC_MODE
              //00
              begin
                inc(i);
                   CurrBlockLen:=CurrBlockLen-1;
                   if CurrBlockLen=2 then
                   RAPInfo.ASIC_MODE:= rxbuf[i];
                   Form1._msg('ASIC MODE ID:  '+ BufToHexStr(@RAPInfo.ASIC_MODE,    1));
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          $14://ROOT_KEY_HASH
              //CAEEBB65D3C48E6DC73B49DC5063A2EE
              begin
                   inc(i);
                   CurrBlockLen:=CurrBlockLen-1;
                   for k:=0 to CurrBlockLen-1 do RAPInfo.ROOT_KEY_HASH[k]:= rxbuf[i+k];
                   inc(i, CurrBlockLen);
                   inc(j);
                   //???????? ?? ?????? RootHash
                   l:=0;
                   for k := 0 to $0F do inc(l, RAPInfo.ROOT_KEY_HASH[k]);
                   if l=0 then
                   begin
                        Form1.setready;
                        Form1._msg('->  No ROOTKEY HASH Asic CMT. (IMEI DAMAGED?) Unable to continue flashing');
                        exit;
                   end;
                   Form1._msg('ROOT KEY HASH: '+ BufToHexStr(@RAPInfo.ROOT_KEY_HASH[0], Length(RAPInfo.ROOT_KEY_HASH)));
              end;
          $15://ROM_ID
              //4B9B75103E691FF8
              begin
                   inc(i);
                   CurrBlockLen:=CurrBlockLen-1;
                   for k:=0 to CurrBlockLen-1 do RAPInfo.ROM_ID[k]:= rxbuf[i+k];
                   Form1._msg('ROM ID:        '+ BufToHexStr(@RAPInfo.ROM_ID[0],    Length(RAPInfo.ROM_ID)));
                   inc(i, CurrBlockLen);
                   inc(j);
              end
              else
              begin
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          end;//End Of Case
     end;
      Application.ProcessMessages;
      Form1._msg('Send CMT loader...');
	  loaderinfo:='';
      try
	  loaderinfo:=getversion(ExtractFilePath(Application.ExeName)+'\Flash\RAPIDOv11_2nd.fg');
      fs:=TFileStream.Create(ExtractFilePath(Application.ExeName)+'\Flash\RAPIDOv11_2nd.fg',fmOpenRead);
      except
      Form1._msg('Error on prepare - loader not found or damaged!');
      exit;
      end;
      
      Form1._msg('Use '+ExtractFileName(ExtractFilePath(Application.ExeName)+'\Flash\RAPIDOv11_2nd.fg')+' '+loaderinfo);
      RAWLoader:=TmemoryStream.Create;
      RAWBlock:=TmemoryStream.Create;
      RAWblock.LoadFromstream(fs);
      RAWLoader:=PrepareCMTNomandicloader(RAWblock);
      fs.Free;
      //Sendloader
       if Rawloader<>nil then begin
      Application.ProcessMessages;
      DWord((@txbuf[0])^):=Rawloader.Size+52;
      DWordSwap(@txbuf[0]);
      USBBulkWritePort(@txbuf[0], 4);

      DWord((@txbuf[0])^):=Rawloader.Size+52;
      DWordSwap(@txbuf[0]);
      txBuf[4]:=$01;
      txbuf[5]:=$20;
      txBuf[6]:=$00;
      txBuf[7]:=frameCrc(@txbuf[0],7);
      txBuf[8]:=$5B;
      txBuf[9]:=$01;
      txBuf[10]:=$24;
      txBuf[11]:=$04;
      DWord((@txbuf[12])^):=Rawloader.Size+32;
      DWordSwap(@txbuf[12]);
      txBuf[16]:=frameCrc(@txbuf[0],16);
      txBuf[17]:=$00;
      txBuf[18]:=$00;
      txBuf[19]:=$00;
      RAWLoader.Seek(0,soFromBeginning);
      Rawloader.ReadBuffer(txBuf[20], Rawloader.size);
      rawsize:=Rawloader.size+20;
      for i:=rawsize to rawsize+32 do
      txBuf[i]:=$00;
      USBBulkWritePort(@txbuf[0], Rawloader.size+52);
      repeat
      bulkread:=usbbulkreadportint($FFFF)
      until bulkread<>0;
      if apereadreq then begin result:=True; Form1._msg('CMT loader sent') end else result:=false;
   Application.ProcessMessages;
   RAWLoader.free;
   RAWBlock.free;
   //Form1._msg('Req CMT info');
   DWord((@txBuf[0])^):=$0B;
   DWordSwap(@txbuf[0]);
   UsbBulkWriteport(@txbuf[0],4);
   Application.ProcessMessages;
   UsbBulkWriteport(@NomSelectFlCmt, Length(NomSelectFlCmt));
    repeat
    bulkread:=usbbulkreadportint($FFFF)
    until bulkread<>0;
   if rxBuf[8]<>$C1 then Form1._msg('Error while reading initial info, boot not accepted')
   else Form1._msg('CMT FLID : '+buftohexstr(@rxBuf[43],2)+buftohexstr(@rxBuf[41],2)+' , NOR , CMT');
   end
   else begin
      result:=false;
      RAWLoader.free;
      RAWBlock.free;
      end;
   Application.ProcessMessages;
end;

function NomandicSendBoot():Boolean;
var
     fs               : TfileStream;
     currcert,
     currtoken,
     streamlen        : TMemoryStream;
     data             : string;
     hdrlen,seemcount,
     CurrSeemLen,i    : Integer;
     fblen            : Byte;
     currseem         : Byte;
     blklen,loaderlen : DWORD;
     RootInBlock      : array[0..$F] of byte;
     j,good           : Integer;
     n,k,l,m          : integer;
     ms               : TmemoryStream;
     BlockCount       : Byte;
     CurrBlock        : Byte;
     CurrBlockLen     : Word;
     b                : Boolean;
     bulkread         : integer;
     loaderinfo       : string;
begin
   result:=false;
   loaderinfo:='';
   try
   loaderinfo:=getversion(ExtractFilePath(Application.ExeName)+'\Flash\RAPIDOv11_XSR15_alg.fg');
   fs:=TFileStream.Create(ExtractFilePath(Application.ExeName)+'\Flash\RAPIDOv11_XSR15_alg.fg',fmOpenRead);
   except
   Form1._msg('Error on prepare - loader not found or damaged!');
   exit;
   end;
   Form1._msg('Use '+ExtractFileName(ExtractFilePath(Application.ExeName)+'\Flash\RAPIDOv11_XSR15_alg.fg')+' '+loaderinfo);
     fs.Read(buf[0] ,1);
     if buf[0]<>$B1 then  //Заголовок / идентификатор
     begin
          Form1.lst1.items.add('File damaged or Unknow format... :(');
          fs.Free;
          exit;
     end;
     fs.ReadBuffer(buf[0], 4);//Длина Flash-header'a
     HdrLen    := HexToInt(IntToHex(buf[0], 2)+IntToHex(buf[1], 2)+IntToHex(buf[2], 2)+IntToHex(buf[3], 2));
     //form1._msg('HeaderLen: '+inttostr(HdrLen));
     fs.ReadBuffer(buf[0], 4);//Кол-во блоков в Flash-заголовке
     SeemCount := HexToInt(IntToHex(buf[0], 2)+IntToHex(buf[1], 2)+IntToHex(buf[2], 2)+IntToHex(buf[3], 2));
     //form1._msg('BlockCount: '+inttostr(SeemCount));
     Application.ProcessMessages;
     currcert:=TMemoryStream.Create;
     currtoken:=TmemoryStream.Create;
     streamlen:=TMemoryStream.Create;
     good:=0;
     loaderlen:=0;
     form1.pb1.MaxValue:=fs.Size;
  try
    Form1.statusbar.Panels[4].Text:='Sending Boot';
     while (fs.Position<>(fs.size)) do
     begin
          fs.ReadBuffer(CurrSeem, 1);
          case CurrSeem of//Перебор всех блоков, поиск блока со структурой RAW-loader'а
            $56:
              begin
              //Form1._msg('Cert Token found, processing...');
                  Application.ProcessMessages;
                  fs.ReadBuffer(buf[0], 3);
                  case Buf[1] of
                    $17: // UPDAPP body ( 1st block  - precrt )
                       begin
                      //form1._msg('UpdAPP Body processing');
                       Application.ProcessMessages;
                       CurrSeemLen :=buf[2]+1;
                       //fs.ReadBuffer(buf[0], currseemlen);
                       fs.Seek(fs.Position-4, sofromBeginning);
                       currtoken.CopyFrom(fs,currseemlen+4);
                       currtoken.Seek(0,soFromBeginning);
                       currtoken.ReadBuffer(txBuf[8],currtoken.size);
                       // send token's header
                       Application.processmessages;
                       currtoken.Seek(10,sofromBeginning);
                       currtoken.ReadBuffer(blklen,4);
                       DWordSwap(@blklen);
                       currcert.CopyFrom(fs,blklen);
                       Application.processmessages;

                       currcert.Seek(0, sofrombeginning);
                       //Form1._msg('CERT SIZE : '+inttostr(currcert.Size));
                       dword((@txbuf[0])^):=currcert.size+9+currtoken.size;
                       dwordswap(@txbuf[0]);
                       UsbBulkWritePort(@txbuf[0],4);
                       txBuf[4]:=$01;
                       txbuf[5]:=$10;
                       txBuf[6]:=$00;
                       txbuf[7]:=frameCrc(@txbuf[0],7);
                       txBuf[8+(Currtoken.size)]:=$00;
                       currcert.readbuffer(txbuf[8+(Currtoken.size+1)],currcert.size);
                       UsbBulkWritePort(@txbuf[0],currcert.size+(9+Currtoken.size));
                        repeat
                        bulkread:=usbbulkreadportint($FFFF)
                        until bulkread<>0;
                       Application.ProcessMessages;
                       currcert.clear;
                       currtoken.Clear;
                      end;
                    $27: // UPDAPP CERT
                       begin
                       Application.ProcessMessages;
                       good:=0;
                       CurrSeemLen :=buf[2]+1;
                       fs.Seek(fs.Position-4, sofromBeginning);
                       currtoken.CopyFrom(fs,currseemlen+4);
                       currtoken.seek(4,soFromBeginning);
                       currtoken.ReadBuffer(RootInBlock[0], $10);
                       //form1._msg('UPDAPP: '+buftohexstr(@rootinBlock[0], $10));
                       Application.ProcessMessages;
                       for j:=0 to $0f do if RootInBlock[j]=RAPInfo.Root_Key_Hash[j] then inc(good);
                       if good=$10 then
                         begin
                         // send token's header
                           Application.processmessages;
                           currtoken.Seek(41,sofromBeginning);
                           currtoken.ReadBuffer(blklen,4);
                           DWordSwap(@blklen);
                           currcert.CopyFrom(fs,blklen);
                           Application.processmessages;
                           currcert.Seek(0, sofrombeginning);
                           dword((@txbuf[0])^):=currcert.size+10+currtoken.size;
                           dwordswap(@txbuf[0]);
                           UsbBulkWriteport(@txBuf[0],4);
                           txBuf[4]:=$01;
                           txbuf[5]:=$10;
                           txBuf[6]:=$00;
                           txbuf[7]:=frameCrc(@txbuf[0],7);
                           currtoken.Seek(0,sofromBeginning);
                           currtoken.ReadBuffer(txBuf[8],currtoken.size);
                           word((@txBuf[currtoken.size+9])^):=$0000;
                           currcert.readbuffer(txbuf[8+(currtoken.size+2)],currcert.size);
                           UsbBulkWritePort(@txbuf[0],currcert.size+(10+currtoken.size));
                           repeat
                           bulkread:=usbbulkreadportint($FFFF)
                           until bulkread<>0;
                           Application.ProcessMessages;
                         end
                         else begin
                         currtoken.Seek(41,sofromBeginning);
                         currtoken.ReadBuffer(blklen,4);
                         DWordSwap(@blklen);
                         currcert.CopyFrom(fs,blklen);
                         Application.ProcessMessages;
                         end;
                       Application.ProcessMessages;
                       currcert.clear;
                       currtoken.Clear;
                       end;
                  end;
              end;

          else
            begin
                   fs.ReadBuffer(buf[0], 1);
                   CurrSeemLen:=buf[0];
                   fs.Seek(CurrSeemLen, sofromcurrent);
              end;
         end;
     form1.pb1.Progress:=fs.Position;
     Application.ProcessMessages;
   end;
  except
  fs.free;
  result:=false;
  Form1.pb1.progress:=0;
  Form1.pb1.MaxValue:=100;
  Application.ProcessMessages;
  exit;
  end;

  dword((@txbuf[0])^):=$1F;
  dwordswap(@txbuf[0]);
  UsbBulkWritePort(@txbuf[0],4);
  UsbBulkWritePort(@fincmtbootrapido15, length(fincmtbootrapido15));
  repeat
  bulkread:=usbbulkreadportint($FFFF)
  until bulkread<>0;
  if apereadreq then begin
   dword((@txbuf[0])^):=$12;
   dwordswap(@txbuf[0]);
   UsbBulkWritePort(@txbuf[0],4);
   UsbBulkWriteport(@cmtrunnomadic,length(cmtrunnomadic));
   repeat
   bulkread:=usbbulkreadportint($FFFF)
   until bulkread<>0;
   if cmtreadreq then begin
   result:=true;
   form1._msg('CMT algo sent');
   end else result:=false;
  end
  else result:=False;
  fs.Free;
  Form1.pb1.progress:=0;
  Form1.pb1.MaxValue:=100;
  Application.ProcessMessages;
end;

function NomandicAPErawextract():Boolean;
var
  fs                 : TFileStream;
  Rawloader,Rawblock : TmemoryStream;
  rawsize            : Int64;
  bulkread           : Integer;
  loaderinfo         : string;
begin
      result:=false;
	  loaderinfo:='';
      try
	  loaderinfo:=getversion(ExtractFilePath(Application.ExeName)+'\Flash\STn8815_2nd.fg');
      fs:=TFileStream.Create(ExtractFilePath(Application.ExeName)+'\Flash\STn8815_2nd.fg',fmOpenRead);
      except
      Form1._msg('Error on prepare - loader not found or damaged!');
      exit;
      end;
      Form1._msg('Use '+ExtractFileName(ExtractFilePath(Application.ExeName)+'\Flash\STn8815_2nd.fg')+' '+loaderinfo);
      RAWLoader:=TmemoryStream.Create;
      RAWBlock:=TmemoryStream.Create;
      RAWblock.LoadFromstream(fs);
      RAWLoader:=PrepareApeNomandicloader(RAWblock);
      fs.Free;
      //Sendloader
      Application.ProcessMessages;
      if Rawloader<>nil then begin
      rawsize:=Rawloader.size;
      DWord((@txBuf[0])^):=Rawsize;
      //Form1._msg(BufToHexStr(@txbuf[0], 4));
      UsbBulkWriteport(@txbuf[0],4);
      Rawloader.Seek(0,soFromBeginning);
      RAWLoader.ReadBuffer(txBuf[0], rawsize);
      UsbBulkWriteport(@txbuf[0],rawsize);
       repeat
       bulkread:=usbbulkreadportint($FFFF)
       until bulkread<>0;
      if (rxbuf[0]=$37) and (rxbuf[1]=$78) and (rxbuf[2]=$62) and (rxbuf[3]=$00) then begin
        form1._msg('APE loader sent');
        Application.ProcessMessages;
        end
        else begin
        form1._msg('Minor error, try skip');
        end;
      RAWLoader.free;
      RAWBlock.free;
        DWord((@txBuf[0])^):=4;
        DWordSwap(@txbuf[0]);
        UsbBulkWriteport(@txbuf[0],4);
        Application.ProcessMessages;
        txBuf[0]:=$66; txBuf[1]:=$00; txBuf[2]:=$FF; txBuf[3]:=$00;
        UsbBulkWriteport(@txbuf[0],4);
        repeat
        bulkread:=usbbulkreadportint($FFFF)
        until bulkread<>0;
        if rxBuf[0]<>$C1 then
                              begin
                              result:=False;
                              Form1._msg('Error while reading initial info, boot not accepted');
                              end
                              else begin
                              Form1._msg('APE FLID : '+buftohexstr(@rxBuf[36],2)+buftohexstr(@rxBuf[34],2)+' , NAND , APE');
                              result:=true;
                              end;
      Application.ProcessMessages;
      end
      else begin
      result:=false;
      RAWLoader.free;
      RAWBlock.free;
      end;
end;


function PrepareApeNomandicloader(loader:Tmemorystream):TMemoryStream;
var
  b            : Boolean;
  ULO          : array[0..3] of Byte;
  MEDia        : array[0..10] of Byte;
  RAWLoader    : TMemoryStream;
begin
  ULO[0]:=$32;ULO[1]:=$4E;ULO[2]:=$44;ULO[3]:=$00;
  MEDia[0]:=$42;MEDia[1]:=$4F;MEDia[2]:=$4F;MEDia[3]:=$54;
  MEDia[4]:=$5F;MEDia[5]:=$4D;MEDia[6]:=$45;MEDia[7]:=$44;
  MEDia[8]:=$49;MEDia[9]:=$41;MEDia[10]:=$31;
  try
  //Извлечение и патчинг RAW-loader'a
  RAWLoader:=TmemoryStream.Create;
  BB5_ExtractAPERAWLoader(loader, RAWLoader, b);
  //RAWloader.SaveToFile('C:\RAW_Nomandic_patch.bin');
  //Подготовка патчинга равки
  RAWloader.Seek(20,soFromBeginning);
  RAWloader.readbuffer(Buf[0],4);
  if buf[0]<>$53 then begin
  Form1._msg('Prepare loader failed');
  result:=nil;
  end else begin
  RAWloader.Seek(20,soFromBeginning);  //RAPUx  SILO
  RAWloader.writebuffer(ulo[0],4);
  end;
  RAWloader.Seek(148,soFromBeginning);
  RAWloader.readbuffer(Buf[0],$B);
  RAWloader.Seek(148,soFromBeginning);
  if (buf[0]=$42) and (buf[1]=$4F) then RAWloader.WriteBuffer(Media[0],$B) else result:=nil;
  //RAWloader.SaveToFile('C:\RAW_RAPNEW_patch.bin');
  Result:=RAWloader;
  except
  Result:=nil;
  end;
end;

function PrepareCMTNomandicloader(loader:Tmemorystream):TMemoryStream;
var
  b            : Boolean;
  ULO          : array[0..3] of Byte;
  MEDia        : array[0..10] of Byte;
  RAWLoader    : TMemoryStream;
begin
  MEDia[0]:=$42;MEDia[1]:=$4F;MEDia[2]:=$4F;MEDia[3]:=$54;
  MEDia[4]:=$5F;MEDia[5]:=$4D;MEDia[6]:=$45;MEDia[7]:=$44;
  MEDia[8]:=$49;MEDia[9]:=$41;MEDia[10]:=$32;
  try
  //Извлечение и патчинг RAW-loader'a
  RAWLoader:=TmemoryStream.Create;
  BB5_ExtractRAWLoader(loader, RAWLoader, b);
  //RAWloader.SaveToFile('C:\RAW_Nomandic_patch.bin');
  //Подготовка патчинга равки
  RAWloader.Seek(148,soFromBeginning);
  RAWloader.readbuffer(Buf[0],$B);
  RAWloader.Seek(148,soFromBeginning);
  if (buf[0]=$42) and (buf[1]=$4F) then RAWloader.WriteBuffer(Media[0],$B) else result:=nil;
  //RAWloader.SaveToFile('C:\RAW_CMT_RAPNEW_patch.bin');
  Result:=RAWloader;
  except
  Result:=nil;
  end;
end;

function NomandicAPESendBoot():Boolean;
var
     fs               : TfileStream;
     currcert,
     currtoken,
     streamlen        : TMemoryStream;
     data             : string;
     hdrlen,seemcount,
     CurrSeemLen,i    : Integer;
     fblen            :Byte;
     currseem         : Byte;
     blklen,loaderlen : DWORD;
     RootInBlock      : array[0..$F] of byte;
     j,good           : Integer;
     n,k,l,m          : integer;
     ms               : TmemoryStream;
     BlockCount       : Byte;
     CurrBlock        : Byte;
     CurrBlockLen     : Word;
     b                : Boolean;
     bulkread         : integer;
     loaderinfo       : string;
begin
   result:=false;
   loaderinfo:='';
   try
   loaderinfo:=getversion(ExtractFilePath(Application.ExeName)+'\Flash\STn8815_STNFMS_alg.fg');
   fs:=TFileStream.Create(ExtractFilePath(Application.ExeName)+'\Flash\STn8815_STNFMS_alg.fg',fmOpenRead);
   except
   Form1._msg('Error on prepare - loader not found or damaged!');
   exit;
   end;
   Form1._msg('Use '+ExtractFileName(ExtractFilePath(Application.ExeName)+'\Flash\STn8815_STNFMS_alg.fg')+' '+loaderinfo);
     fs.Read(buf[0] ,1);
     if buf[0]<>$B1 then  //Заголовок / идентификатор
     begin
          Form1.lst1.items.add('File damaged or Unknow format... :(');
          fs.Free;
          exit;
     end;
     fs.ReadBuffer(buf[0], 4);//Длина Flash-header'a
     HdrLen    := HexToInt(IntToHex(buf[0], 2)+IntToHex(buf[1], 2)+IntToHex(buf[2], 2)+IntToHex(buf[3], 2));
     //form1._msg('HeaderLen: '+inttostr(HdrLen));
     fs.ReadBuffer(buf[0], 4);//Кол-во блоков в Flash-заголовке
     SeemCount := HexToInt(IntToHex(buf[0], 2)+IntToHex(buf[1], 2)+IntToHex(buf[2], 2)+IntToHex(buf[3], 2));
     //form1._msg('BlockCount: '+inttostr(SeemCount));
     Application.ProcessMessages;
     currcert:=TMemoryStream.Create;
     currtoken:=TmemoryStream.Create;
     streamlen:=TMemoryStream.Create;
     good:=0;
     loaderlen:=0;
     form1.pb1.MaxValue:=fs.Size;
  try
    Form1.statusbar.Panels[4].Text:='Sending Boot';
     while (fs.Position<>(fs.size)) do
     begin
          fs.ReadBuffer(CurrSeem, 1);
          case CurrSeem of//Перебор всех блоков, поиск блока со структурой RAW-loader'а
            $56:
              begin
              //Form1._msg('Cert Token found, processing...');
                  Application.ProcessMessages;
                  fs.ReadBuffer(buf[0], 3);
                  case Buf[1] of
                    $17: // UPDAPP body ( 1st block  - precrt )
                       begin
                      //form1._msg('UpdAPP Body processing');
                       Application.ProcessMessages;
                       CurrSeemLen :=buf[2]+1;
                       //fs.ReadBuffer(buf[0], currseemlen);
                       fs.Seek(fs.Position-4, sofromBeginning);
                       currtoken.CopyFrom(fs,currseemlen+4);
                       //currtoken.SaveToFile('C:\token'+inttostr(i2)+'.bin');
                       // send token's header
                       Application.processmessages;

                       currtoken.Seek(0, sofrombeginning);
                       dword((@txbuf[0])^):=currtoken.size;
                       dwordswap(@txbuf[0]);
                       UsbBulkWritePort(@txbuf[0],4);
                       currtoken.readbuffer(txbuf[0],currtoken.size);
                       UsbBulkWritePort(@txbuf[0],currtoken.size);
                       //send cert body
                       currtoken.Seek(10,sofromBeginning);
                       currtoken.ReadBuffer(blklen,4);
                       DWordSwap(@blklen);
                       currcert.CopyFrom(fs,blklen);
                       Application.processmessages;

                       currcert.Seek(0, sofrombeginning);
                       //Form1._msg('CERT SIZE : '+inttostr(currcert.Size));
                       dword((@txbuf[0])^):=currcert.size;
                       dwordswap(@txbuf[0]);
                       UsbBulkWritePort(@txbuf[0],4);
                       currcert.readbuffer(txbuf[0],currcert.size);
                       UsbBulkWritePort(@txbuf[0],currcert.size);
                       Application.ProcessMessages;
                       currcert.clear;
                       currtoken.Clear;
                      end;
                    $27: // UPDAPP CERT
                       begin
                       Application.ProcessMessages;
                       good:=0;
                       CurrSeemLen :=buf[2]+1;
                       fs.Seek(fs.Position-4, sofromBeginning);
                       currtoken.CopyFrom(fs,currseemlen+4);
                       currtoken.seek(4,soFromBeginning);
                       currtoken.ReadBuffer(RootInBlock[0], $10);
                       //form1._msg('UPDAPP: '+buftohexstr(@rootinBlock[0], $10));
                       Application.ProcessMessages;
                       for j:=0 to $0f do if RootInBlock[j]=RAPInfo.Aperootkey[j] then inc(good);
                       if good=$10 then
                         begin
                         // send token's header
                          Application.processmessages;
                          currtoken.Seek(0, sofrombeginning);
                          dword((@txbuf[0])^):=currtoken.size;
                          dwordswap(@txbuf[0]);
                          UsbBulkWritePort(@txbuf[0],4);
                          currtoken.readbuffer(txbuf[0],currtoken.size);
                          UsbBulkWritePort(@txbuf[0],currtoken.size);

                           currtoken.Seek(41,sofromBeginning);
                           currtoken.ReadBuffer(blklen,4);
                           DWordSwap(@blklen);
                           currcert.CopyFrom(fs,blklen);
                           Application.processmessages;
                           currcert.Seek(0, sofrombeginning);
                           //Form1._msg('ROOTCERT SIZE : '+inttostr(currcert.Size));
                           dword((@txbuf[0])^):=currcert.size;
                           dwordswap(@txbuf[0]);
                           UsbBulkWritePort(@txbuf[0],4);
                           currcert.readbuffer(txbuf[0],currcert.size);
                           UsbBulkWritePort(@txbuf[0],currcert.size);
                           Application.ProcessMessages;
                         end
                         else begin
                         currtoken.Seek(41,sofromBeginning);
                         currtoken.ReadBuffer(blklen,4);
                         DWordSwap(@blklen);
                         currcert.CopyFrom(fs,blklen);
                         Application.ProcessMessages;
                         end;
                       Application.ProcessMessages;
                       currcert.clear;
                       currtoken.Clear;
                       end;
                  end;
              end;

          else
            begin
                   fs.ReadBuffer(buf[0], 1);
                   CurrSeemLen:=buf[0];
                   fs.Seek(CurrSeemLen, sofromcurrent);
              end;
         end;
     Form1.pb1.progress:=fs.Position;
     Application.ProcessMessages;
   end;
  except
  fs.free;
  result:=false;
  Form1.pb1.progress:=0;
  Form1.pb1.MaxValue:=100;
  exit;
  end;

  dword((@txbuf[0])^):=$17;
  dwordswap(@txbuf[0]);
  UsbBulkWritePort(@txbuf[0],4);
  UsbBulkWritePort(@NomandicAPeend, length(NomandicAPeend));
  repeat
  bulkread:=usbbulkreadportint($FFFF)
  until bulkread<>0;
  if rxBuf[0]=$37 then begin
  result:=true;
  form1._msg('APE algo sent');
  end
  else result:=False;
  fs.Free;
  Form1.pb1.progress:=0;
  Form1.pb1.MaxValue:=100;
  Application.ProcessMessages;
end;

function nomandicIniUpdServer():Boolean;
var
  i        : Integer;
  bulkread : integer;
begin
  result:=False;
  dword((@txbuf[0])^):=$12;
  dwordswap(@txbuf[0]);
  UsbBulkWritePort(@txbuf[0],4);
  i:=UsbBulkWritePort(@ApeNomUpl, Length(ApeNomUpl));
  if i<>18 then Exit;
  repeat
  bulkread:=usbbulkreadportint($FFFF)
  until bulkread<>0;
  if apereadreq then application.ProcessMessages
  else form1._msg('Ape server init fail');
  dword((@txbuf[0])^):=$12;
  dwordswap(@txbuf[0]);
  UsbBulkWritePort(@txbuf[0],4);
  i:=UsbBulkWritePort(@ApeNomUpl2, Length(ApeNomUpl2));
  if i<>18 then Exit;
  repeat
  bulkread:=usbbulkreadportint($FFFF)
  until bulkread<>0;
  if apereadreq then result:=True;
end;

function NomandicBoot(mode:Integer):Boolean;
var
     fs               : TfileStream;
     currcert,
     currtoken,
     streamlen        : TMemoryStream;
     data             : string;
     hdrlen,seemcount,
     CurrSeemLen,i    : Integer;
     fblen            :Byte;
     currseem         : Byte;
     a                : string;
     blklen,loaderlen : DWORD;
     dcr              : Boolean;
     RootInBlock      : array[0..$F] of byte;
     j,good,i2        : Integer;
     n,k,l,m,PktLen   : integer;
     ms,
     RAWBlock,
     RAWLoader        : TmemoryStream;
     s, needSert      : String;
     Key, KeyLen      : Byte;
     PacketLen        : Byte;
     BlockCount       : Byte;
     CurrBlock        : Byte;
     CurrBlockLen     : Word;
     b, proto         : Boolean;
     ASIC             : string;
     rapmode          : Integer;
     bulkread         : Integer;
begin
     if mode=1 then
     begin
          Form1._msg('Dead Mode is Selected');
          Form1._msg('Waiting for USB device...');
          Form1._msg('--- Press phone'+#39+'s power button or insert charger! ---');
          Application.ProcessMessages;
     end;

     //Nokia USB ROM
     b:=false; i:=0;
     repeat
           if (i=2500) and (b=false) then
           begin
                Form1._msg('->  Phone not found.. :(');
                result:=False;
                Form1.SetReady;
                Exit;
           end;
           Application.ProcessMessages;
           if stop=true then
           begin
           dostop('BOOT');
           i:=2499; b:=False;
           end;
           if catchdevice=$02 then
           begin
                b:=true;
                Form1._msg('Connection opened successfully');
           end;
           Application.ProcessMessages;
           Sleep(10);
           inc(i);
           Form1.statusbar.Panels[0].Text:='Wait for phone '+inttostr(2500-i);
           Application.ProcessMessages;
     until b ;
     Form1.statusbar.Panels[0].Text:='';
     Form1.statusbar.Panels[3].Text:='Connected';
     txBuf[0]:=$15; txBuf[1]:=$88; txBuf[2]:=$54; txBuf[3]:=$53;
     i:=USBBulkWritePort(@txbuf[0],4);
     if i<>4 then begin
             Form1._msg('->  Read initial data failed : phone not in flash mode.. :(');
             result:=False;
             Form1.SetReady;
             Exit;
             end;
     try
     Form1._msg('Req APE info');
        repeat
        bulkread:=usbbulkreadportint($FFFF)
        until bulkread<>0;
     Application.ProcessMessages;

     // Root Hash
     Application.ProcessMessages;
     FillMemory(@RAPInfo.ROOT_KEY_HASH,$10,$00);
     FillMemory(@RAPInfo.APErootkey,$10,$00);
     FillMemory(@RAPInfo.FlashID,$A,$00);
     FillMemory(@RAPInfo.APEFlashID,$A,$00);
     FillMemory(@RAPInfo.PublicID,$14,$00);
     FillMemory(@RAPInfo.BootID,$8,$00);
     Application.ProcessMessages;
     Application.ProcessMessages;
     BlockCount :=rxbuf[0];

     i:=1;
     j:=0;
     m:=0;
     while j<BlockCount do
     begin
          CurrBlock    :=rxbuf[i];
          inc(i);
          CurrBlockLen := HexToInt(IntToHex(rxbuf[i], 2));
          inc(i);
          case CurrBlock of
          $01://RAP SYSTEM ASIC ID
              //5800 - 000000010000022600010006400C192101031103 [RAPIDO3G ver: 1.x]
              begin
                inc(i);
                   CurrBlockLen:=CurrBlockLen-1;
                   for k:=0 to CurrBlockLen-1 do RAPInfo.SYSTEM_ASIC_ID[k]:= rxbuf[i+k];
                   Form1._msg('ASIC ID:       '+ BufToHexStr(@RAPInfo.SYSTEM_ASIC_ID[0], 4));
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          $02://RAP EMx ID
              //00000295
              //00000B22
              begin
                   if CurrBlockLen=4 then
                   for k:=0 to CurrBlockLen-1 do RAPInfo.EMx_ID[k]:= rxbuf[i+k];
                   Form1._msg('EM'+inttostr(m)+' ID:        '+ BufToHexStr(@RAPInfo.EMx_ID[0],    4));
                   inc(i, CurrBlockLen);
                   inc(j);inc(m);
              end;
          $12://PUBLIC_ID
              //1FF0001841158B52064E64D3C3E9A7F38DC47E29
              begin
                inc(i);
                   CurrBlockLen:=CurrBlockLen-1;
                   for k:=0 to CurrBlockLen-1 do RAPInfo.PUBLIC_ID[k]:= rxbuf[i+k];
                   Form1._msg('PUBLIC ID:     '+ BufToHexStr(@RAPInfo.PUBLIC_ID[0],    Length(RAPInfo.PUBLIC_ID)));
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          $13://ASIC_MODE
              //00
              begin
                inc(i);
                   CurrBlockLen:=CurrBlockLen-1;
                   if CurrBlockLen=2 then
                   RAPInfo.ASIC_MODE:= rxbuf[i];
                   Form1._msg('ASIC MODE ID:  '+ BufToHexStr(@RAPInfo.ASIC_MODE,    1));
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          $14://ROOT_KEY_HASH
              //CAEEBB65D3C48E6DC73B49DC5063A2EE
              begin
                   inc(i);
                   CurrBlockLen:=CurrBlockLen-1;
                   for k:=0 to CurrBlockLen-1 do RAPInfo.Aperootkey[k]:= rxbuf[i+k];
                   inc(i, CurrBlockLen);
                   inc(j);
                   //???????? ?? ?????? RootHash
                   l:=0;
                   for k := 0 to $0F do inc(l, RAPInfo.Aperootkey[k]);
                   if l=0 then
                   begin
                        Form1.setready;
                        Form1._msg('->  No ROOTKEY HASH Asic APE. (IMEI DAMAGED?) Unable to continue flashing');
                        exit;
                   end;
                   Form1._msg('ROOT KEY HASH: '+ BufToHexStr(@RAPInfo.Aperootkey[0], Length(RAPInfo.Aperootkey)));
              end;
          $15://ROM_ID
              //4B9B75103E691FF8
              begin
                   inc(i);
                   CurrBlockLen:=CurrBlockLen-1;
                   for k:=0 to CurrBlockLen-1 do RAPInfo.ROM_ID[k]:= rxbuf[i+k];
                   Form1._msg('ROM ID:        '+ BufToHexStr(@RAPInfo.ROM_ID[0],    Length(RAPInfo.ROM_ID)));
                   inc(i, CurrBlockLen);
                   inc(j);
              end
              else
              begin
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          end;//End Of Case
     end;
     Application.ProcessMessages;

     //02 00 03 F0
     txBuf[0]:=$02; txBuf[1]:=$00; txBuf[2]:=$03; txBuf[3]:=$F0;
     i:=USBBulkWritePort(@txbuf[0],4);
     if i<>4 then begin
             Form1._msg('->  Setup initial data failed : phone not in flash mode.. :(');
             result:=False;
             Form1.SetReady;
             Form1.statusbar.Panels[0].Text:='';
             Form1.statusbar.Panels[4].Text:='';
             Exit;
             end;
     except
     form1._msg('Error on initialization stage');
     result:=false;
     Exit;
     end;
     Application.ProcessMessages;
     //Prepare and send RAWloader
     Form1.statusbar.Panels[0].Text:='Boot stage #1';
     Form1._msg('Send APE loader...');
     try
     if not NomandicAPErawextract then begin
     form1._msg('Error on boot stage #1');
     result:=false;
     Form1.statusbar.Panels[0].Text:='';
     Form1.statusbar.Panels[4].Text:='';
     exit;
     end;
     except
     form1._msg('Error on boot stage #1');
     result:=false;
     Form1.statusbar.Panels[0].Text:='';
     Form1.statusbar.Panels[4].Text:='';
     exit;
     end;

     Application.ProcessMessages;
     //Prepare and send algo
     Form1.statusbar.Panels[0].Text:='Boot stage #2';
     Form1._msg('Send APE algo...');
     try
     if not NomandicAPESendBoot then begin
     form1._msg('Error on boot stage #2');
     result:=false;
     Form1.statusbar.Panels[0].Text:='';
     Form1.statusbar.Panels[4].Text:='';
     exit;
     end;
     except
     form1._msg('Error on boot stage #2');
     result:=false;
     Form1.statusbar.Panels[0].Text:='';
     Form1.statusbar.Panels[4].Text:='';
     exit;
     end;
     Application.ProcessMessages;
     //initialize updServer
     Form1.statusbar.Panels[0].Text:='UpdateServer initialize';
     Form1._msg('Initialize UpdateServer...');
     try
     if not nomandicIniUpdServer then begin
     form1._msg('Error initialize UpdateServer');
     result:=false;
     Form1.statusbar.Panels[0].Text:='';
     Form1.statusbar.Panels[4].Text:='';
     exit;
     end;
     except
     form1._msg('Error initialize UpdateServer');
     result:=false;
     Form1.statusbar.Panels[0].Text:='';
     Form1.statusbar.Panels[4].Text:='';
     exit;
     end;
     Form1._msg('UpdateServer initialized');
     Application.ProcessMessages;
     form1._msg('Processing Slave part');
     //SendCMTrawloader
     Form1.statusbar.Panels[0].Text:='Boot stage #3';
     try
     if not NomandicRawextract then begin
     form1._msg('Error on boot stage #3');
     result:=false;
     Form1.statusbar.Panels[0].Text:='';
     Form1.statusbar.Panels[4].Text:='';
     exit;
     end;
     except
     form1._msg('Error on boot stage #3');
     result:=false;
     Form1.statusbar.Panels[0].Text:='';
     Form1.statusbar.Panels[4].Text:='';
     exit;
     end;
     Application.ProcessMessages;
     //SendCMT algo
     Form1.statusbar.Panels[0].Text:='Boot stage #4';
     Form1._msg('Send CMT algo...');
     try
     if not NomandicSendBoot then begin
     form1._msg('Error on boot stage #4');
     result:=false;
     Form1.statusbar.Panels[0].Text:='';
     Form1.statusbar.Panels[4].Text:='';
     exit;
     end;
     except
     form1._msg('Error on boot stage #4');
     result:=false;
     Form1.statusbar.Panels[0].Text:='';
     Form1.statusbar.Panels[4].Text:='';
     exit;
     end;
     Application.ProcessMessages;
     Form1.statusbar.Panels[0].Text:='';
     Form1.statusbar.Panels[4].Text:='';
     try
     if not NomandicFlprepare then begin
     form1._msg('Error on flash prepare');
     result:=false;
     Form1.statusbar.Panels[0].Text:='';
     Form1.statusbar.Panels[4].Text:='';
     exit;
     end;
     except
     form1._msg('Error on flash prepare');
     result:=false;
     Form1.statusbar.Panels[0].Text:='';
     Form1.statusbar.Panels[4].Text:='';
     exit;
     end;
     Form1._msg('Flash prepare done');
     result:=True;
end;

function NomandicFlprepare():Boolean;
var
  i        : Integer;
  bulkread : Integer;
begin
  result:=false;
 Application.ProcessMessages;
 //confirm cmtselect
 USBBulkWritePort(@nomselcmt[0],4);
 i:=USBBulkWritePort(@nomselcmt,Length(nomselcmt));
 if i<>11 then Exit;
 repeat
 bulkread:=usbbulkreadportint($FFFF)
 until bulkread<>0;
 if (rxBuf[7]=$E5) and (rxBuf[8]=$00) then Form1._msg('ADL : CMT select Ok') else  Form1._msg('ADL : CMT select : already on adl');
 //get cmt papub
 Application.ProcessMessages;
 USBBulkWritePort(@nomgetcmtpapub[0],4);
 i:=USBBulkWritePort(@nomgetcmtpapub,Length(nomgetcmtpapub));
 if i<>14 then Exit;
 repeat
 bulkread:=usbbulkreadportint($FFFF)
 until bulkread<>0;
 if rxBuf[11]=$15 then Form1._msg('ADL : CMT PapubKeys req Ok') else Form1._msg('ADL : CMT PapubKeys req : blank/erased');
 // check CRT req
 Application.ProcessMessages;
 USBBulkWritePort(@nomcmreqcert[0],4);
 i:=USBBulkWritePort(@nomcmreqcert,Length(nomcmreqcert));
 if i<>71 then Exit;
 repeat
 bulkread:=usbbulkreadportint($FFFF)
 until bulkread<>0;
 if cmtreadreq then Form1._msg('ADL : CMT CRT check Ok') else Form1._msg('ADL : CMT CRT check failed');
 // cmt fl req
 Application.ProcessMessages;
 USBBulkWritePort(@nomselcmtfl[0],4);
 i:=USBBulkWritePort(@nomselcmtfl,Length(nomselcmtfl));
 if i<>11 then Exit;
 repeat
 bulkread:=usbbulkreadportint($FFFF)
 until bulkread<>0;
 //get ape papub
 Application.ProcessMessages;
 USBBulkWritePort(@nomgetapepapub[0],4);
 i:=USBBulkWritePort(@nomgetapepapub,Length(nomgetapepapub));
 if i<>14 then exit;
 repeat
 bulkread:=usbbulkreadportint($FFFF)
 until bulkread<>0;
 if rxBuf[11]=$15 then Form1._msg('ADL : APE PapubKeys req Ok') else Form1._msg('ADL : APE PapubKeys req : blank/erased');
 // check CRT ape req
 Application.ProcessMessages;
 USBBulkWritePort(@nomapereqcert[0],4);
 i:=USBBulkWritePort(@nomapereqcert,Length(nomapereqcert));
 if i<>71 then Exit;
 repeat
 bulkread:=usbbulkreadportint($FFFF)
 until bulkread<>0;
 if apereadreq then Form1._msg('ADL : APE CRT check Ok') else Form1._msg('ADL : APE CRT check failed');
 result:=True;
end;

function NomandicEraseFile(core:string):Boolean;
var
     fs                         : TFileStream;
     buf1                        : array[0..$FFFF] of byte;
     n,j,buflen,i               : Integer;
     HdrLen                     : Integer;
     HdrPos                     : LongInt;
     CurrSeem                   : Byte;
     CurrSeemLen, CurSeemcount  : Integer;
     ms                         : TMemoryStream;
     loaderlen                  : DWORD;
     erase                      : Boolean;
     framelen                   : DWORD;
     cmt,ape                    : Boolean;
     bulkread                   : integer;
begin
     Result:=false;
     partition:=false;
     erase:=False;
     cmt:=false;
     ape:=false;
     Form1._msg('Erase : Processing '+ExtractFileName(core));
     Application.processmessages;
     Form1.statusbar.Panels[1].text:='';
     Application.ProcessMessages;
     fs:=TFileStream.Create(core,fmOpenRead);
     fs.Seek(0, sofromBeginning);
     fs.Read(buf1[0],1);
     if buf1[0]<>$B2 then
     begin
          fs.free;
          raise E.Create('Erase : Bad image file');
          Exit;
     end;
     Application.ProcessMessages;
     starttime;
     Application.ProcessMessages;
     fs.ReadBuffer(buf1[0], 4);//Длина Flash Header
     HdrLen := HexToInt(IntToHex(buf1[0], 2)+IntToHex(buf1[1], 2)+IntToHex(buf1[2], 2)+IntToHex(buf1[3], 2));
     fs.Seek(4,soFromCurrent);
 try
     while fs.Position<(HdrLen) do
     begin
           if stop=true then
           begin
           dostop('ERASE');
           Application.ProcessMessages;
           fs.free;
           result:=False;
           Exit;
           end;
          fs.ReadBuffer(CurrSeem, 1);
           case CurrSeem of
          $EE:
           begin
              Application.ProcessMessages;
              Form1.statusbar.Panels[0].Text:='Partitioning, Wait';
              Application.ProcessMessages;
              cmt:=false;
              ape:=false;
              form1._msg('Partitioning....');
              partition:=True;
              partitionstream:=TmemoryStream.Create;
              fs.ReadBuffer(buf1[0], 2);
              CurrSeemLen:=(buf1[0]*$100)+buf1[1];
              partitionstream.copyFrom(fs,CurrSeemlen);
              Application.ProcessMessages;
                if partition=True
                then
                begin
                 partitionstream.Seek(0,soFromBeginning);
                 partitionstream.ReadBuffer(buf1[0],1);
                 n:=buf1[0];
                 for i:=1 to n do
                 begin
                 partitionstream.ReadBuffer(buf1[0],2);
                 buflen:=buf1[1];
                 partitionstream.ReadBuffer(buf1[0],buflen);
                 case buf1[1] of
                 $01 : ape:=True;
                 $00 : cmt:=True;
                 end;
                 end;
                 if cmt=True then begin
                 partitionstream.Seek(0,soFromBeginning);
                 framelen:=CurrSeemLen+10;
                 DWord((@txBuf[0])^):=framelen;
                 DWordSwap(@txbuf[0]);
                 txBuf[4]:=$01;
                 txBuf[5]:=$10;
                 txBuf[6]:=$00;
                 txBuf[7]:=frameCrc(@txbuf[0],7);
                 txBuf[8]:=$64;
                 partitionstream.ReadBuffer(txBuf[9], CurrSeemLen);
                 txBuf[framelen-1]:=frameCrc(@txbuf[9],CurrSeemLen);
                 //Form1._msg('CMT txbuf : '+BufToHexStr(@txbuf[0],framelen));
                 USBBulkWritePort(@txbuf[0],4);
                  i:=USBBulkWritePort(@txbuf[0],framelen);
                  if i<>framelen then begin
                   result:=False;
                   Form1._msg('Error sending CMT partition req, partition operation fail');
                   fs.free;
                   ms.free;
                   Exit;
                   end;
                  repeat
                   bulkread:=usbbulkreadportint($FFFF)
                  until bulkread<>0;
                //Form1._msg('RxBuf : '+buftohexstr(@rxBuf[0],Length(rxBuf)));
                 if cmtreadreq then form1._msg('Partitioning CMT Ok...') else
                 begin
                 form1._msg('Partitioning CMT failed! :(');
                 result:=false;
                 end;
                 end;
                 if ape=True then begin
                 partitionstream.Seek(0,soFromBeginning);
                 framelen:=CurrSeemLen+10;
                 DWord((@txBuf[0])^):=framelen;
                 DWordSwap(@txbuf[0]);
                 txBuf[4]:=$01;
                 txBuf[5]:=$20;
                 txBuf[6]:=$00;
                 txBuf[7]:=frameCrc(@txbuf[0],7);
                 txBuf[8]:=$64;
                 partitionstream.ReadBuffer(txBuf[9], CurrSeemLen);
                 txBuf[framelen-1]:=frameCrc(@txbuf[9],CurrSeemLen);
                 //Form1._msg('APE txbuf : '+BufToHexStr(@txbuf[0],framelen));
                 USBBulkWritePort(@txbuf[0],4);
                 i:=USBBulkWritePort(@txbuf[0],framelen);
                   if i<>framelen then begin
                   result:=False;
                   Form1._msg('Error sending APE partition req, partition operation fail');
                   fs.free;
                   ms.free;
                   Exit;
                   end;
                   repeat
                   bulkread:=usbbulkreadportint($FFFF)
                   until bulkread<>0;
                 //Form1._msg('RxBuf : '+buftohexstr(@rxBuf[0],Length(rxBuf)));
                 if apereadreq then form1._msg('Partitioning APE Ok...') else
                 begin
                 form1._msg('Partitioning APE failed! :(');
                 result:=false;
                 end;
                 end;
                Application.ProcessMessages;
                partitionstream.free;
                end;
            end;
           $C8:
           begin
                   Application.ProcessMessages;
                   Form1.statusbar.Panels[0].Text:='Erasing, Wait';
                   Application.ProcessMessages;
                   ape:=false;
                   cmt:=false;
                   form1._msg('Erasing....');
                   erase:=True;
                   fs.ReadBuffer(buf1[0], 1);
                   CurrSeemLen:=buf1[0];
                   ms:=TmemoryStream.Create;
                   ms.copyFrom(fs,CurrSeemlen);
                   ms.Seek(0,soFromBeginning);
                 ms.readbuffer(buf1[0],1);
                 n:=buf1[0];
                 for i:=1 to n do
                 begin
                 ms.ReadBuffer(buf1[0],2);
                 buflen:=buf1[1];
                 ms.ReadBuffer(buf1[0],buflen);
                  case buf1[1] of
                  $01 : ape:=True;
                  $00 : cmt:=True;
                  end;
                 end;
                if cmt=true then begin
                   Application.ProcessMessages;
                   Form1.statusbar.Panels[0].Text:='Erasing CMT, Wait';
                   Application.ProcessMessages;
                   ms.Seek(0,soFromBeginning);
                   framelen:=CurrSeemLen+10;
                   DWord((@txBuf[0])^):=framelen;
                   DWordSwap(@txbuf[0]);
                   txBuf[4]:=$01;
                    txBuf[5]:=$10;
                    txBuf[6]:=$00;
                    txBuf[7]:=frameCrc(@txbuf[0],7);
                    txBuf[8]:=$50;
                    ms.ReadBuffer(txBuf[9], CurrSeemLen);
                    txBuf[framelen-1]:=frameCrc(@txbuf[9],CurrSeemLen);
                    //Form1._msg('CMT txbuf : '+BufToHexStr(@txbuf[0],framelen));
                    USBBulkWritePort(@txbuf[0],4);
                    i:=USBBulkWritePort(@txbuf[0],framelen);
                     if i<>framelen then begin
                    result:=False;
                    Form1._msg('Error sending CMT erase req, erase fail');
                    fs.free;
                    ms.free;
                    Exit;
                    end;
                     repeat
                     bulkread:=usbbulkreadportint($FFFF)
                     until bulkread<>0;
                    //Form1._msg('RxBuf : '+buftohexstr(@rxBuf[0],Length(rxBuf)));

                    if cmtreadreq then begin
                    form1._msg('Erasing CMT Ok...');
                    Result:=True;
                    end
                    else
                    begin
                    form1._msg('Erasing CMT failed! :(');
                    result:=false;
                    end;
                 Application.ProcessMessages;
                 end;
                 if ape=True then begin
                   Application.ProcessMessages;
                   Form1.statusbar.Panels[0].Text:='Erasing APE, Wait';
                   Application.ProcessMessages;
                   ms.Seek(0,soFromBeginning);
                   framelen:=CurrSeemLen+10;
                   DWord((@txBuf[0])^):=framelen;
                   DWordSwap(@txbuf[0]);
                   txBuf[4]:=$01;
                   txBuf[5]:=$20;
                   txBuf[6]:=$00;
                   txBuf[7]:=frameCrc(@txbuf[0],7);
                   txBuf[8]:=$50;
                   ms.ReadBuffer(txBuf[9], CurrSeemLen);
                   txBuf[framelen-1]:=frameCrc(@txbuf[9],CurrSeemLen);
                   //Form1._msg('APE txbuf : '+BufToHexStr(@txbuf[0],framelen));
                   USBBulkWritePort(@txbuf[0],4);
                   i:=USBBulkWritePort(@txbuf[0],framelen);
                   if i<>framelen then begin
                   result:=False;
                   Form1._msg('Error sending APE erase req, erase fail');
                   fs.free;
                   ms.free;
                   Exit;
                   end;
                    repeat
                    bulkread:=usbbulkreadportint($FFFF)
                    until bulkread<>0;
                   //Form1._msg('RxBuf : '+buftohexstr(@rxBuf[0],Length(rxBuf)));
                   if apereadreq  then begin
                   form1._msg('Erasing APE Ok...');
                   Result:=True;
                   end
                   else
                   begin
                   form1._msg('Erasing APE failed! :(');
                   result:=false;
                   end;
                 Application.ProcessMessages;
                 end;
                   Application.ProcessMessages;
                   endtimecount;
                   Form1._msg('TIME : Erase time : '+showtime(tmsres)+' ');
                   Application.ProcessMessages;
                   Form1.pbsm1.Progress:=0;
                   fs.Free;
                   ms.free;
                   Form1.statusbar.Panels[0].Text:='';
                   exit;
           end
           else
           begin
              // Form1._msg('SEEM : '+byte2str(currseem));
               fs.ReadBuffer(buf[0], 1);
               CurrSeemLen:=buf[0];
               fs.readbuffer(buf[0],CurrSeemLen);
               application.ProcessMessages;
           end;
          end;
     end;
     if erase=False then begin
      result:=True;
      Form1._msg('Erase : No any region, skip erase');
      end;
     fs.Free;
 except
        on E:Exception do
        begin
             fs.Free;
             Form1._msg('EraseFile: Error: '+E.Message);
             result:=False;
             Application.ProcessMessages;
             Form1.statusbar.Panels[0].Text:='';
        end;
 end;
Form1.statusbar.Panels[0].Text:='';
Application.ProcessMessages;
endtimecount;
Form1._msg('TIME : Erase time : '+showtime(tmsres)+' ');
end;

function NomandicWriteFile(core:string):Boolean;
const
      maxlen             : dWORD = $4FFFF ;
var
     buf                :array[0..$4FFFF] of byte;
     HdrLen,
     CurrBlockLen       : Cardinal;
     EntryPoint,
     DataLen,
     TargetOffset,
     CRCTmp             : LongInt;
     i, n, Blocks,
     Packets,icl,
     CurrPacketSize,
     TokenHdrLen        : Integer;
     good               : Integer;
     CertName,AsicType  : String;
     PAPUB_Already,
     APE_PAPUB          : boolean;
     fs                 : TFileStream;
     ms                 : TMemoryStream;
     writen,framelen    : Dword;
     cmtcount,cmtdin,
     TokenSubType, unk  : integer;
     nopbyte            : byte;
     nopword            : word;
     ttxbuf             : array[0..$4FFFF] of byte;
     ape,cmt            : Boolean;
     apebyte            : Byte;
     bulkread           : integer;
begin
     Result:=False;
     Form1._msg('Write : Processing '+ExtractFileName(core));
     fs:=TFileStream.Create(core,fmOpenRead);
     fs.Seek(0, sofromBeginning);
     Blocks:=0;
     cmtcount:=0; cmtdin:=0;
     unk:=0;
     Form1.pb1.ForeColor:=clGreen;
     Form1.pb1.progress:=0;
     Application.ProcessMessages;
try
     fs.Read(ttxbuf[0],1);
     if ttxbuf[0]<>$B2 then
     begin
          fs.free;
          raise E.Create('Write : Bad image file');
     end;

     Application.ProcessMessages;
     starttime;
     Application.ProcessMessages;

     fs.ReadBuffer(ttxbuf[0], 4);//Длина Flash-header'a
     HdrLen     := HexToInt(IntToHex(ttxbuf[0], 2)+IntToHex(ttxbuf[1], 2)+
                            IntToHex(ttxbuf[2], 2)+IntToHex(ttxbuf[3], 2));

     fs.Seek(HdrLen, sofromcurrent);//К началу первого Flash-токена
     {ms:=TMemoryStream.Create;}
     form1.pb1.maxvalue:=(fs.size-hdrlen);
     form1.statusbar.Panels.Items[0].Text:='Writing...';
     while fs.Position<fs.Size do
     begin

           if stop=true then
           begin
           dostop('WRITE');
           Application.ProcessMessages;
           fs.Free;
           result:=false;
           Exit;
           end;

          Application.ProcessMessages;
          fs.ReadBuffer(ttxbuf[8], 1);
          case ttxbuf[8] of
          $54://Flash-token
              begin
                   //54 0117 0E 000300 4D9C 01 00000400 00000000 E8
                   fs.ReadBuffer(ttxbuf[$09], $3);//Чтение значения подтипа токена и длины его заголовка
                   TokenHdrLen:=ttxbuf[$0B];//Длина заголовка токена
                   TokenSubType:=TokenHdrLen;
                   fs.Seek(fs.position-4, sofrombeginning);//смещение на начало токена
                   inc(TokenHdrLen, 5);//Увеличим длину до общей длины токена с его CRC
                   fs.ReadBuffer(ttxbuf[8], TokenHdrLen);//Чтение значений токена с его CRC
                   apebyte:=ttxbuf[12];
                   //Длина текущего блока между токенами
                   CurrBlockLen := HexToInt(IntToHex(ttxbuf[TokenHdrLen-1], 2)+
                                            IntToHex(ttxbuf[TokenHdrLen],   2)+
                                            IntToHex(ttxbuf[TokenHdrLen+1], 2)+
                                            IntToHex(ttxbuf[TokenHdrLen+2], 2));
                   //Form1._msg('CurrLen : '+inttostr(CurrBlockLen));

                   case TokenSubType of
                   $0E :
                   begin
                   ttxbuf[8+TokenHdrLen]:=$00;//Добавление байта-разделителя $00
                   fs.ReadBuffer(ttxbuf[9+TokenHdrLen], CurrBlockLen);//Копирование данных токена в буфер
                   framelen:=CurrBlockLen+TokenHdrLen+$09;//Состоит из 8 байт команды, токена, байта-разделитель,
                   end;
                   $15 :
                   begin
                   DWord((@ttxBuf[$8+TokenHdrLen])^):=$0000;//Добавление байта-разделителя $0000
                   fs.ReadBuffer(ttxbuf[$0A+TokenHdrLen], CurrBlockLen);//Копирование данных токена в буфер
                   framelen:=CurrBlockLen+TokenHdrLen+$0A;//Состоит из 8 байт команды, токена, байта-разделитель,
                   end;
                   else
                   DWord((@ttxBuf[$8+TokenHdrLen])^):=$0000;//Добавление байта-разделителя $0000
                   fs.ReadBuffer(ttxbuf[$0A+TokenHdrLen], CurrBlockLen);//Копирование данных токена в буфер
                   framelen:=CurrBlockLen+TokenHdrLen+$0A;//Состоит из 8 байт команды, токена, байта-разделитель,
                   end;
                   //Расчет длины фрейма                  //              данных пакета
                   DWord((@ttxBuf[0])^):=framelen;
                   DWordSwap(@ttxbuf[0]);
                   //form1._msg('Token Len : '+IntToStr(framelen));
                   ttxBuf[4]:=$01;
                   case apebyte of
                   $00:ttxBuf[5]:=$10;
                   $01:ttxBuf[5]:=$20;
                   end;
                   ttxBuf[6]:=$00;
                   //Расчет первой crc (crc шапки команды)
                   ttxBuf[7]:=frameCrc(@ttxbuf[0],7);

                   //Form1._msg('txbuf : '+BufToHexStr(@txbuf[0],framelen));
                   Application.ProcessMessages;
                   case apebyte of
                   $00: begin
                   USBBulkWritePort(@ttxbuf[0],4);
                   USBBulkWritePort(@ttxbuf[0],framelen);
                    repeat
                    bulkread:=USBBulkReadPortInt($FFFF);
                    until bulkread<>0;
                   //Form1._msg('RxBuf : '+buftohexstr(@rxBuf[0],Length(rxBuf)));
                   if cmtreadreq then Application.ProcessMessages
                   else
                    begin
                    form1._msg('Write CMT failed on block '+inttostr(Blocks)+' :(');
                    result:=false;
                    fs.free;
                    exit;
                    end;
                   end;
                   $01: begin
                   USBBulkWritePort(@ttxbuf[0],4);
                   USBBulkWritePort(@ttxbuf[0],framelen);
                    repeat
                    bulkread:=USBBulkReadPortInt($FFFF);
                    until bulkread<>0;
                   //Form1._msg('RxBuf : '+buftohexstr(@rxBuf[0],Length(rxBuf)));
                   if apereadreq then Application.ProcessMessages
                   else
                    begin
                    form1._msg('Write APE failed on block '+inttostr(Blocks)+' :(');
                    result:=false;
                    fs.free;
                    exit;
                    end;
                   end;
                  end;

                   Application.ProcessMessages;

                   inc(blocks);
               case apebyte of
               $00:form1.statusbar.Panels[1].Text:='CMT : '+inttostr(Blocks);
               $01:form1.statusbar.Panels[1].Text:='APE : '+inttostr(Blocks);
               end;
              end;//End of Case $54

          $5D://Phoenix-segment
              begin
                   //5D 0127 2D 25B977A055BE9B5DEC0C38A2A279C695 8594B99841444100000000000000000000030077E7 00000400 000A0800 BB
                   //       Len          RootKey Hash                                                         Len     Flash   CRC
                   //5D 0128 43 25B977A055BE9B5DEC0C38A2A279C695 8594B99850415055424B4559530000000003 00A70900 00060000 11F000397DCE210733C335E84BAD369EC893FCA06D1BC3 0100 A5
                   //       Len          RootKey Hash                                                    Len     Flash                                                      CRC

                   fs.ReadBuffer(ttxbuf[$09], $3);//Чтение значения подтипа токена и длины его заголовка
                   TokenHdrLen:=ttxbuf[$0B];//Длина заголовка токена
                   TokenSubType:=TokenHdrLen;
                   fs.Seek(fs.position-4, sofrombeginning);//смещение на начало токена
                   inc(TokenHdrLen, 5);//Увеличим длину до общей длины токена с его CRC
                   fs.ReadBuffer(ttxbuf[8], TokenHdrLen);//Чтение значений токена с его CRC
                   apebyte:=ttxbuf[44];
                   case TokenSubType of
                   $2D:
                       //Длина текущего блока между токенами
                       CurrBlockLen := HexToInt(IntToHex(ttxbuf[TokenHdrLen-1], 2)+
                                                IntToHex(ttxbuf[TokenHdrLen],   2)+
                                                IntToHex(ttxbuf[TokenHdrLen+1], 2)+
                                                IntToHex(ttxbuf[TokenHdrLen+2], 2));
                   $43:
                       //Длина текущего блока между токенами
                       CurrBlockLen := HexToInt(IntToHex(ttxbuf[TokenHdrLen-$17], 2)+
                                                IntToHex(ttxbuf[TokenHdrLen-$16], 2)+
                                                IntToHex(ttxbuf[TokenHdrLen-$15], 2)+
                                                IntToHex(ttxbuf[TokenHdrLen-$14], 2));
                   else
                     begin
                        fs.Free;
                        E.Create('Write : Bad image file');
                     end;
                   end;//End of Case

                   //Сравнение RootKey Hash телефона и RootKey Hash блока сертов
                   good:=0;
                   case apebyte of
                   $00: begin
                        for i:=$0 to $0F do if RAPInfo.Root_Key_Hash[i]=ttxbuf[i+$0C] then inc(good);
                        end;
                   $01: begin
                        for i:=$0 to $0F do if RAPInfo.APErootkey[i]=ttxbuf[i+$0C] then inc(good);
                        end;
                   end;
                   if good<$10 then
                   begin//RootKey Hash не совпал, пропускаем
                        fs.Seek(CurrBlockLen, soFromCurrent);//Пропускаем токен и его данные
                        continue;
                   end
                   else
                   begin//RootKey Hash серта совпал, копируем
                        case TokenSubType of
                        $2D:
                        begin
                        DWord((@ttxBuf[$8+TokenHdrLen])^):=$0000;//Добавление слова-разделителя $0000
                        fs.ReadBuffer(ttxBuf[$0A+TokenHdrLen],CurrBlockLen);//Копирование данных
                        Application.ProcessMessages;
                        CertName:='';
                        for i:=32 to 45 do if ttxbuf[i]=$00 then break else CertName:=CertName+Chr(ttxbuf[i]);
                         case apebyte of
                         $00:Form1._msg('CMT: Writing Hash CERT ['+CertName+']');
                         $01:Form1._msg('APE: Writing Hash CERT ['+CertName+']');
                         end;
                        Application.ProcessMessages;
                        framelen:=CurrBlockLen+TokenHdrLen+$0A;//Состоит из 8 байт команды, токена, слова-разделителя,
                        //Расчет длины фрейма                  //              данных пакета
                        DWord((@ttxBuf[0])^):=framelen;
                        DWordSwap(@ttxbuf[0]);
                        //form1._msg('Cert Len : '+IntToStr(framelen));
                        ttxBuf[4]:=$01;
                         case apebyte of
                         $01:ttxBuf[5]:=$20;
                         $00:ttxBuf[5]:=$10;
                         end;
                        ttxBuf[6]:=$00;

                        //Расчет первой crc (crc шапки команды)
                        ttxBuf[7]:=frameCrc(@ttxbuf[0],7);

                        //Form1._msg('txbuf : '+BufToHexStr(@txbuf[0],framelen));
                           Application.ProcessMessages;
                           case apebyte of
                           $00:begin
                            USBBulkWritePort(@ttxbuf[0],4);
                            USBBulkWritePort(@ttxbuf[0],framelen);
                            repeat
                            bulkread:=USBBulkReadPortInt($FFFF);
                            until bulkread<>0;
                            //Form1._msg('RxBuf : '+buftohexstr(@rxBuf[0],Length(rxBuf)));
                            if cmtreadreq then Application.ProcessMessages
                            else
                            begin
                            form1._msg('Write CMT cert failed! :(');
                            result:=false;
                            fs.free;
                            exit;
                            end;
                           end;
                           $01: begin
                           USBBulkWritePort(@ttxbuf[0],4);
                           USBBulkWritePort(@ttxbuf[0],framelen);
                              repeat
                              bulkread:=USBBulkReadPortInt($FFFF);
                              until bulkread<>0;
                             //Form1._msg('RxBuf : '+buftohexstr(@rxBuf[0],Length(rxBuf)));
                            if apereadreq then Application.ProcessMessages
                            else
                            begin
                            form1._msg('Write APE cert failed! :(');
                            result:=false;
                            fs.free;
                            exit;
                            end;
                           end;

                         end;

                        Application.ProcessMessages;
                        inc(blocks);
                        Application.ProcessMessages;
                         case apebyte of
                         $00:form1.statusbar.Panels[1].Text:='CMT : '+inttostr(Blocks);
                         $01:form1.statusbar.Panels[1].Text:='APE : '+inttostr(Blocks);
                         end;
                        end;
                        $43:
                        begin
                        fs.ReadBuffer(ttxBuf[$08+TokenHdrLen],CurrBlockLen);//Копирование данных
                        case apebyte of
                        $00:Form1._msg('CMT: Writing Hash CERT [PAPUBKEYS]');
                        $01:Form1._msg('APE: Writing Hash CERT [PAPUBKEYS]');
                        end;
                        Application.ProcessMessages;
                        framelen:=CurrBlockLen+TokenHdrLen+$08;//Состоит из 8 байт команды, токена, слова-разделителя,
                        //Расчет длины фрейма                  //              данных пакета
                        DWord((@ttxBuf[0])^):=framelen;
                        DWordSwap(@ttxbuf[0]);
                        //form1._msg('Cert Len : '+IntToStr(framelen));
                        ttxBuf[4]:=$01;
                         case apebyte of
                         $01:ttxBuf[5]:=$20;
                         $00:ttxBuf[5]:=$10;
                         end;
                        ttxBuf[6]:=$00;

                        //Расчет первой crc (crc шапки команды)
                        ttxBuf[7]:=frameCrc(@ttxbuf[0],7);

                        //Form1._msg('txbuf : '+BufToHexStr(@txbuf[0],framelen));
                         Application.ProcessMessages;
                          case apebyte of
                           $00:begin
                            USBBulkWritePort(@ttxbuf[0],4);
                            USBBulkWritePort(@ttxbuf[0],framelen);
                                repeat
                                bulkread:=USBBulkReadPortInt($FFFF);
                                until bulkread<>0;
                            //Form1._msg('RxBuf : '+buftohexstr(@rxBuf[0],Length(rxBuf)));
                            if cmtreadreq then Application.ProcessMessages
                            else
                            begin
                            form1._msg('Write CMT cert failed! :(');
                            result:=false;
                            fs.free;
                            exit;
                            end;
                           end;
                           $01: begin
                           USBBulkWritePort(@ttxbuf[0],4);
                           USBBulkWritePort(@ttxbuf[0],framelen);
                            repeat
                            bulkread:=USBBulkReadPortInt($FFFF);
                            until bulkread<>0;
                           //Form1._msg('RxBuf : '+buftohexstr(@rxBuf[0],Length(rxBuf)));
                            if apereadreq then Application.ProcessMessages
                            else
                            begin
                            form1._msg('Write APE cert failed! :(');
                            result:=false;
                            fs.free;
                            exit;
                            end;
                           end;

                         end;

                        Application.ProcessMessages;
                        inc(blocks);
                        Application.ProcessMessages;
                        case apebyte of
                        $01:form1.statusbar.Panels[1].Text:='APE : '+inttostr(Blocks);
                        $00:form1.statusbar.Panels[1].Text:='CMT : '+inttostr(Blocks);
                        end;
                       end;
                     end;
                   end;
              end//End of Case $5D
          else
              begin//Unknow Tokens or Bad File
                   fs.free;
                   E.Create('Write : Bad image file');
              end;
          end;//End of Case
     form1.pb1.progress:=fs.Position;
     Application.ProcessMessages;
     end;//End of While
     fs.free;
     Form1._msg('Total writen '+inttostr(blocks)+' blocks');
     Application.ProcessMessages;
     endtimecount;
     Form1._msg('TIME : Write time : '+showtime(tmsres)+' ');
     form1.statusbar.Panels[1].Text:='';
     form1.statusbar.Panels[0].Text:='';
     result:=True;
     //form1._msg('Errors : '+inttostr(GetLastError));
     form1.pb1.maxvalue:=100;
     form1.pb1.progress:=0;
     Application.ProcessMessages;
except
     on E:Exception do
     begin
          Form1._msg('Error: '+E.Message);
          Form1.pb1.Progress:=0;
          USBClosePort;
          exit;
     end;
end;     
     Form1.pb1.Progress:=0;
end;

function nomandicEndflash():Boolean;
var
  i,bulkread:Integer;
begin
  result:=False;
  //nomclosecmt
  form1._msg('ADL : Close CMT session');
  USBBulkWritePort(@nomclosecmt,4);
  i:=UsbBulkWriteport(@nomclosecmt, Length(nomclosecmt));
  if i<>11 then Exit;
   repeat
   bulkread:=USBBulkReadPortInt($FFFF);
   until bulkread<>0;
   //Form1._msg(buftohexstr(@rxBuf[0], Length(rxBuf)));
  Application.ProcessMessages;
  //nomcloseape
  form1._msg('ADL : Close APE session');
  USBBulkWritePort(@nomcloseape,4);
  i:=UsbBulkWriteport(@nomcloseape, Length(nomcloseape));
  if i<>11 then Exit;
   repeat
   bulkread:=USBBulkReadPortInt($FFFF);
   until bulkread<>0;
  Form1._msg('Content : '+buftohexstr(@rxBuf[14], 12));
  Application.ProcessMessages;
  //nomrebootreq
  form1._msg('ADL : Reboot');
  USBBulkWritePort(@nomrebootreq,4);
  i:=UsbBulkWriteport(@nomrebootreq, Length(nomrebootreq));
  if i<>14 then Exit;
  //if USBBulkReadPortInt($FFFF)=0 then USBBulkReadPort($FFFF);
  //Form1._msg(buftohexstr(@rxBuf[0], Length(rxBuf)));
  Application.ProcessMessages;
  result:=true;
end;

function  BB5_FlashingNomadic():boolean;
var
     b, proto         : Boolean;
     i                : integer;
     rb               : Byte;
     ms               : TMemoryStream;
begin
     Application.ProcessMessages;
     Sleep(500);
     Application.ProcessMessages;
     fltime:=0;
     if not DevPresent then
     begin
          Form1._msg('Phone not found... :(');
          Form1.SetBuzy;
          Form1.StatusBar.Panels[4].Text:='';
          result:=False;
          USBClosePort;
          exit;
     end;

     Form1._msg('ADL : phone is in flash mode');
     //Добавил для удобства кастом-прошивки
     Form1.statusbar.Panels[0].Text:='';
     Form1.statusbar.Panels[1].Text:='';
     Form1.statusbar.Panels[2].Text:='';
     Form1.statusbar.Panels[4].Text:='FLASHING';
     Form1.statusbar.Panels[3].Text:='Connected';
     Form1.TimConChk.Interval:=100;
     Application.ProcessMessages;

      if Form1.chkMCUen.Checked=true then
     begin
          Form1.chkMCUen.Enabled:=False;
          Form1._msg('   ===Flashing [MCU]===');
          if not NomandicEraseFile(core) then begin StuffFlashReset; result:=False; Exit; end;
          Application.ProcessMessages;
          if not NomandicWriteFile(core) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('MCU Write done');
          Application.ProcessMessages;
     end;
     Application.ProcessMessages;
     if Form1.chkPPMe.Checked=true then
     begin
          Form1.chkPPMe.Enabled:=False;
          Form1.chkMCUen.Enabled:=False;
          Form1._msg('   ===Flashing [PPM]===');
          if not NomandicEraseFile(ppm) then begin StuffFlashReset; result:=False; Exit; end;
          Application.ProcessMessages;
          if not NomandicWriteFile(ppm) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('PPM Write done');
          Application.ProcessMessages;
     end;
     Application.ProcessMessages;
      if Form1.chkPPM1e.Checked=true then
     begin
          Form1.chkPPMe.Enabled:=False;
          Form1.chkMCUen.Enabled:=False;
          Form1.chkPPM1e.Enabled:=False;
          Form1._msg('   ===Flashing [PPM2]===');
          if not NomandicEraseFile(ppm1) then begin StuffFlashReset; result:=False; Exit; end;
          Application.ProcessMessages;
          if not NomandicWriteFile(ppm1) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('PPM Write done');
          Application.ProcessMessages;
     end;
     Application.ProcessMessages;
     if Form1.chkCNTe.Checked=true then
     begin
          Form1.chkPPMe.Enabled:=False;
          Form1.chkMCUen.Enabled:=False;
          Form1.chkPPM1e.Enabled:=False;
          Form1.chkCNTe.Enabled:=False;
          Form1._msg('   ===Flashing [CNT]===');
          if not NomandicEraseFile(image) then begin StuffFlashReset; result:=False; Exit; end;
          Application.ProcessMessages;
          if not NomandicWriteFile(image) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('CNT Write done');
          Application.ProcessMessages;
     end;
     Application.ProcessMessages;
      if Form1.chkAPEe.Checked=true then
     begin
          Form1.chkPPMe.Enabled:=False;
          Form1.chkMCUen.Enabled:=False;
          Form1.chkPPM1e.Enabled:=False;
          Form1.chkCNTe.Enabled:=False;
          Form1.chkAPEe.Enabled:=False;
          Form1._msg('   ===Flashing [APE]===');
          if not NomandicEraseFile(ape) then begin StuffFlashReset; result:=False; Exit; end;
          Form1._msg('Erase taken : '+showtime(tmsres)+' s');
          Application.ProcessMessages;
          if not NomandicWriteFile(ape) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('APE Write done');
          Application.ProcessMessages;
     end;
     Application.ProcessMessages;
     if Form1.chkcnt3.Checked=true then
     begin
          Form1.chkPPMe.Enabled:=False;
          Form1.chkMCUen.Enabled:=False;
          Form1.chkPPM1e.Enabled:=False;
          Form1.chkCNTe.Enabled:=False;
          Form1.chkAPEe.Enabled:=False;
          Form1.chkcnt3.Enabled:=False;
          Form1._msg('   ===Flashing [CNT3]===');
          if not NomandicEraseFile(cnt3) then begin StuffFlashReset; result:=False; Exit; end;
          Application.ProcessMessages;
          if not NomandicWriteFile(cnt3) then begin StuffFlashReset; result:=False; Exit; end;
          form1._msg('CNT Write done');
          Application.ProcessMessages;
     end;

     Application.ProcessMessages;
     if not nomandicEndflash then Form1._msg('Flash finalization fail!'); // режим рестарта
     Application.ProcessMessages;
     Application.ProcessMessages;
     Form1._msg('');
     Form1._msg('Flashing done!');
     Form1._msg('Total flash time : '+showtime(fltime));
     Form1._msg('Reboot phone now...');
     Form1._msg('');
     Application.ProcessMessages;
     fltime:=0;
     Form1.statusbar.Panels[0].Text:='';
     Form1.pb1.ForeColor:=clNavy;
     Form1.pbsm1.ForeColor:=clNavy;
     Form1.pb1.MaxValue:=100;
     Form1.pb1.progress:=0;
     Form1.statusbar.Panels[1].Text:='';
     Form1.TimConChk.Interval:=2000;

     Form1.pb1.color:=clActiveBorder;

    if affenabled then Form1.afterFlashdo;

     Application.ProcessMessages;
     Sleep(200);
     //form1._msg(Form1.SetReady);
     Form1.TimConChk.Enabled:=true;
     Form1._msg('Done!');
     Form1.chkPPMe.Enabled:=True;
     Form1.chkMCUen.Enabled:=True;
     Form1.chkPPM1e.Enabled:=True;
     Form1.chkCNTe.Enabled:=True;
     Form1.chkAPEe.Enabled:=True;
     Form1.chkcnt3.Enabled:=True;
     Result:=true;
end;//End of Normal Mode Flashing

function cmtreadreq():Boolean;
begin
  try
  if (rxbuf[0]=$80) and (rxbuf[1]=$01) and (rxbuf[2]=$7E) and (rxbuf[3]=$00) then result:=True else
   begin
   if (rxbuf[0]=$80) and (rxbuf[1]=$10) and (rxbuf[2]=$6F) and (rxbuf[3]=$00) then result:=True else
   end;
  except
  result:=false;
  end;
end;

function apereadreq():Boolean;
begin
  try
  if (rxbuf[0]=$80) and (rxbuf[1]=$02) and (rxbuf[2]=$7D) and (rxbuf[3]=$00) then result:=True else begin
   if  (rxbuf[0]=$80) and (rxbuf[1]=$20) and (rxbuf[2]=$5F) and (rxbuf[3]=$00)
   then result:=true
   else result:=False;
   end;
  except
  result:=false;
  end;
end;

function readcertrequsb(CERT : string):string;
var
  framelen : dword;
  i        : Integer;
  blkcnt   : Integer;
  Blen     : Integer;
  certstr  : string;
  startblk : Integer;
begin
result:='';
startblk:=11;
for i:=12 to 25 do rednpcreq[i]:=$00;
Form1._msg('Reading '+CERT+' certificate...');
framelen:=Length(rednpcreq);
DWord((@rednpcreq[0])^):=framelen;
DWordSwap(@rednpcreq[0]);
rednpcreq[7]:=frameCrc(@rednpcreq[0],7);
for i:=0 to Length(CERT) do rednpcreq[i+12]:=Ord(CERT[i+1]);
rednpcreq[framelen-1]:=frameCrc(@rednpcreq[9],Length(rednpcreq)-9);
USBBulkWritePort(@rednpcreq[0], Length(rednpcreq));
If USBBulkReadPort($FFFF) then
  begin
  blkcnt:=rxbuf[9];
  if blkcnt=0 then Exit;
  for i:=0 to blkcnt-1 do
   begin
   Blen:=rxbuf[startblk];
   certstr:=certstr+buftohexstr(@rxBuf[startblk+1],Blen);
   startblk:=startblk+blen+2;
   end;
  //Form1._msg(CERT+' : '+certstr);
  result:=certstr;
  end;
end;

function buildxsr16cert(DataStream : widestring; cert : string ): Boolean;
var
  i, framelen : Integer;
  tmp         : array of Byte;
  chk         : word;
  x           : Integer;
begin
  result:=False;
  // prepare and clear start buffer
  CopyMemory(@txbuf[0],@CRTwriteBuf[0],32);
  for i:=32 to 43 do txbuf[i]:=$00;
  for i:=0 to Length(CERT) do txbuf[i+32]:=Ord(CERT[i+1]);
  txBuf[44]:=$00;
  txBuf[45]:=$03;
  txBuf[46]:=$00;
 SetLength(tmp, length(DataStream) div 2);
 x:=StrToBufHex(DataStream,@tmp[0]);
 CHK:=FbusGetChk(@tmp[0], x);
 Word((@txBuf[47])^):=chk;
 DWord((@txBuf[49])^):=x;
 DWordSwap(@txbuf[49]);
 txBuf[53]:=$FF;
 txBuf[54]:=$FF;
 txBuf[55]:=$FF;
 txBuf[56]:=$FF;
 txBuf[57]:=framecrc(@txbuf[9],46);
 txBuf[58]:=$00;
 txBuf[59]:=$00;
 StrToBufHex(DataStream,@txbuf[60]);
 framelen:=x+60;
 DWord((@txBuf[0])^):=framelen;
 DWordSwap(@txbuf[0]);
 txBuf[7]:=framecrc(@txbuf[0],7);
 //Form1._msg(BufToHexStr(@txbuf[0],framelen));
 USBBulkWritePort(@txbuf[0],framelen);
 if USBBulkReadPort($FFFF) then
 if cmtreadreq=true then result:=true else exit
 else exit;
end;

function CertErase(CERT : string):Boolean;
begin
  result:=buildxsr16cert(Zerobyte, CERT);
end;

function contentExplore():Boolean;
var
  i:Integer;
  s,asic,cnt1,cnt2,cnt3:string;
begin
  Application.ProcessMessages;
  if rxbuf[11]=$0F then begin
   case rxBuf[13] of
   $03:asic:='NAND';
   $01:asic:='NAND';
   $00:asic:='NOR';
   else asic:='Unknow'
   end;
   cnt1:=BufToHexStr(@rxBuf[15],4);
   cnt2:=BufToHexStr(@rxBuf[19],4);
   cnt3:=BufToHexStr(@rxBuf[23],4);
  Application.ProcessMessages;
  Form1._msg(asic +' status : '+cnt1+' / '+cnt2+' / '+cnt3);
  end
  else Form1._msg('Status : '+buftohexstr(@rxBuf[12],$0F));
  form1._msg('');
  Application.ProcessMessages;
  result:=true;
end;

function cntrel():Boolean;
var
cmtflash : Dword;
phsec    : integer;
b        : Boolean;
begin
    TransId:=$5E; MsgBody:=$0A;
     Application.ProcessMessages;
     GetRoot[7]:=msgid;
     GetRoot[8]:=ISIHeaderTransId;
     GetRAPInfo;
     Application.ProcessMessages;
  Form1._msg('Checking CNT sector PN<>FL');
  cmtflash:=Swap(Word((@rxBuf[20])^));
  cmtflash:=cmtflash Shl 16;
  cmtflash:=cmtflash+Swap(Word((@rxBuf[18])^));
  phsec:=getcntsize(cmtflash);
  Form1._msg('PN CNT sector : '+inttostr(phsec)+' kb');
    if phsec=64 then
    Begin
    Application.ProcessMessages ;
		Form1._msg('No need convertion, continue flashing...');
		end
	   else begin
       if FileExists(image+'_128') then Form1._msg('Converted data exist')
       else
       begin
     b:=convertimages40(image);
     if b=True then image:=image+'_128';
     end;
    end;
end;

function s40flashprepare2ndstage():Boolean;
var
  b          : Boolean;
  Uagent     : TMemoryStream;
  i,i2       : integer;
  rb         : Byte;
  cmtflash   : DWord;
begin
     if not BB5_PerFlashing then exit;
     rb:=$04;
     Application.ProcessMessages;
     Form1._msg('Reset connection...');
     Application.ProcessMessages;
     Sleep(2000);
     Application.ProcessMessages;
     i:=30;
     while i>0 do
     begin
         Form1.StatusBar.Panels[0].Text:='Wait '+inttostr(i);
          Application.ProcessMessages;
          if catchdevice<>$02 then
          begin
               Application.ProcessMessages;
               sleep (1000);
               Application.ProcessMessages;
               sleep (1000);
               Application.ProcessMessages;
          end else i:=0;
          dec(i);
     end;

     if not DevPresent then
     begin
          Form1._msg('->  Phone not found... :(');
          Form1.StatusBar.Panels[0].Text:='';
          USBClosePort;
          exit;
     end;

     Form1.StatusBar.Panels[0].Text:='';
     
     //Phone in Flash Mode???
     CheckADLUpload[7]:=msgid;
     CheckADLUpload[8]:=ISIHeaderTransId;
     CheckADLUpload[9]:=$00;
     i:=USBBulkWritePort(@CheckADLUpload, Length(CheckADLUpload));
     if i<>12 then
     begin
       Sleep(200);
       Application.ProcessMessages;
       Form1._msg('Wait for device bootup...');
       i:=0;
       repeat
        begin
        Sleep(100);
        Application.ProcessMessages;
        Inc(i);
        if catchdevice=$02 then i2:=USBBulkWritePort(@CheckADLUpload, Length(CheckADLUpload));
        Form1.statusbar.Panels[0].Text:='Wait phone '+IntToStr(100-i);
        end;
       until (i2=12) or (i=100);

       if i2<>12 then  begin
       Form1._msg('->  Bootcode start in CMT fail ! Need flash via programming device :(');
       Form1.TimConChk.Interval:=2000;
       result:=False;
       Form1.statusbar.Panels[0].Text:='';
       exit;
       end;
       Form1.statusbar.Panels[0].Text:='';
       Application.ProcessMessages;
     end;

     USBBulkReadPort(12);

     if rxBuf[11]<>$04 then
     begin
          if rxBuf[11]<>$80 then
          begin
               //Form1._msg('ADL Server not confirmed flashmode!');
               Form1.SetReady;
               USBClosePort;
               exit;
          end
          else
          begin
               //Form1._msg('ADL -> [2nd] changing...');
               rb:=rxBuf[11];
          end;
     end
     else rb:=rxBuf[11];

    // Form1._msg(Byte2Str(rb));
    Application.ProcessMessages;
     case rb of
     $04: begin
      s40prep04;
      end;
     $80: begin
       s40prep80;
       end;

     else  begin
           Form1._msg('->  Error while prepare!');
           Exit;
           end;

     end;
     //Добавил для удобства кастом-прошивки
     Form1.statusbar.Panels[4].Text:='FLASHING';
     Form1.statusbar.Panels[3].Text:='Connected';
     Form1.TimConChk.Interval:=100;
     Application.ProcessMessages;
    result:=True;
end;


function  BB5_EraseCustomArea_USB(area:string):boolean;
var
     b,proto          : Boolean;
     i,i2             : integer;
     rb               : Byte;
     cntx             : integer;
     n2way            : Boolean;
     mcufl            : Boolean;
     cntfl            : Boolean;
     erasestart,
     erasestop        : LongInt;
begin
     result:=false;

     erasestart:=Hextoint(Copy(area,1,8));
     erasestop:=Hextoint(Copy(area,9,8));
     if   (erasestart=0) or (erasestop=0) then Exit;
     starttime;
     rb:=$04;
     n2way:=false;
     mcufl:=false;
     cntfl:=false;
     Application.ProcessMessages;
     Form1._msg('Reopening the connection...');
     Application.ProcessMessages;
     Sleep(2000);
     Application.ProcessMessages;
     i:=30;
     while i>0 do
     begin
          Form1._msg('Waiting for response: '+inttostr(i));
          Application.ProcessMessages;
          if catchdevice<>$02 then
          begin
               Application.ProcessMessages;
               sleep (1000);
               Application.ProcessMessages;
               sleep (1000);
               Application.ProcessMessages;
          end else i:=0;
          dec(i);
     end;

     if not DevPresent then
     begin
          Form1._msg('->  Phone not found... :(');
          Form1.SetBuzy;
          Form1.StatusBar.Panels[4].Text:='';
          USBClosePort;
          endtimecount;
          exit;
     end;

     fltime:=0;
     //Phone in Flash Mode???
     CheckADLUpload[7]:=msgid;
     CheckADLUpload[8]:=ISIHeaderTransId;
     CheckADLUpload[9]:=$00;
     i:=USBBulkWritePort(@CheckADLUpload, Length(CheckADLUpload));
     if i<>12 then
     begin
       Sleep(200);
       Application.ProcessMessages;
       Form1._msg('Wait for device bootup');
       i:=0;
       repeat
        begin
        Sleep(100);
        Application.ProcessMessages;
        Inc(i);
        if catchdevice=$02 then i2:=USBBulkWritePort(@CheckADLUpload, Length(CheckADLUpload));
        Form1.statusbar.Panels[0].Text:='Wait phone '+IntToStr(100-i);
        end;
       until (i2=12) or (i=100);

       if i2<>12 then  begin
       Form1._msg('->  Bootcode start in CMT fail ! Need flash via programming device :(');
       Form1.TimConChk.Interval:=2000;
       result:=False;
       Form1.statusbar.Panels[0].Text:='';
       endtimecount;
       exit;
       end;
       Form1.statusbar.Panels[0].Text:='';
       Application.ProcessMessages;
     end;

     USBBulkReadPort(12);

     if rxBuf[11]<>$04 then
     begin
          if rxBuf[11]<>$80 then
          begin
               Form1._msg('ADL Server not confirmed flashmode!');
               Form1.SetReady;
               USBClosePort;
               endtimecount;
               exit;
          end
          else
          begin
               Form1._msg('ADL -> [2nd] changing...');
               rb:=rxBuf[11];
          end;
     end
     else rb:=rxBuf[11];

    // Form1._msg(Byte2Str(rb));
    Form1._msg('ADL Server confirm flashmode!');
    Application.ProcessMessages;

     case rb of
     $04: begin
      s40prep04;
      end;
     $80: begin
       s40prep80;
       end;

     else  begin
          Form1._msg('->  Error while prepare!');
          Form1.setready;
          endtimecount;
          Exit;
           end;

     end;

     //Добавил для удобства кастом-прошивки
     Form1.statusbar.Panels[4].Text:='FLASHING';
     Form1.statusbar.Panels[3].Text:='Connected';
     Form1.TimConChk.Interval:=100;
     Application.ProcessMessages;

     form1._msg('Starting Erase Custom Block');

     if not BB5_EraseAreaSmallBlock(EraseStart, EraseStop, $12, $00, $00, $00) then
     begin
     Form1._msg('Error Erase Area! Check Model, setting');
      Form1.SetReady;
      result:=False;
      Form1._msg('');
      exit;
     end;

     endtimecount;
     Application.ProcessMessages;
     Form1._msg('ADL : End Erasing');
     Form1._msg('');
     Form1._msg('Erase done!');
     Form1._msg('Total  time : '+showtime(fltime));
     Form1._msg('Try Reboot phone now...');
     Form1._msg('');
     Application.ProcessMessages;
     fltime:=0;
     Form1.statusbar.Panels[0].Text:='';
     Form1.pb1.ForeColor:=clNavy;
     Form1.pbsm1.ForeColor:=clNavy;
     Form1.pb1.MaxValue:=100;
     Form1.pb1.progress:=0;
     Form1.statusbar.Panels[1].Text:='';
     Form1.TimConChk.Interval:=2000;

       case rb of
       $80: begin
            BB5_ADL_RestartMCU(rb);
                i:=0;
                repeat
                Sleep(500);
                Application.ProcessMessages;
                i:=i+1;
                until (catchdevice=$02) or (i=10);
                if i<>10 then begin
                s4080Final;
                BB5_ADL_RestartMCU(rb);
                end;
            end;
       $04: begin
            BB5_ADL_RestartMCU(rb);
                i:=0;
                repeat
                Sleep(500);
                Application.ProcessMessages;
                i:=i+1;
                until (catchdevice=$02) or (i=10);
                if i<>10 then begin
                BB5_ADL_RestartMCU(rb);
                end;
                Application.ProcessMessages;
                Sleep(500);
                Application.ProcessMessages;
                i:=0;
                repeat
                Application.ProcessMessages;
                Sleep(200);
                Inc(i);
                Form1.statusbar.Panels[0].Text:=IntToStr(100-i);
                Application.ProcessMessages;
                if catchdevice=$01 then i:=100
                else BB5_ADL_RestartMCU(rb);
                until (i=100) or (catchdevice=$01);
                Form1.statusbar.Panels[0].Text:='';
                Application.ProcessMessages;
                if (i=100) and (catchdevice=$02) then
                begin
                Form1._msg('Custom mode fail!');
                Form1._msg('Need reflash mcu only in DEAD mode');
                StuffFlashReset;
                result:=False;
                Exit;
                end;
            end;
       end;


     Form1.pb1.color:=clActiveBorder;

     //if affenabled then Form1.afterFlashdo;
     Application.ProcessMessages;
     Sleep(200);
     Form1.TimConChk.Enabled:=true;
     Form1._msg('Done!');
     Result:=true;
end;

function getversion(algfile:string):string;
var
   fs        : TfileStream;
   bcount    : Integer;
   jblkbuf   : array[0..$1FFFF] of Byte;
   i,i2      : Integer;
   data, a   : string;
   CurrSeemLen, Currblocklen, hdrlen,
   SeemCount : Integer;
   CurrSeem  : Byte;
   rev, vers : string;
   loaderlen : DWORD;
begin
   result:='';
try
     fs:=TFileStream.Create(algfile,fmOpenRead);
     fs.seek(0,sofrombeginning);
     fs.Read(jblkbuf[0] ,1);
     if (jblkbuf[0]<>$B0) and (jblkbuf[0]<>$B1) then  //Caaieiaie / eaaioeoeeaoi?
     begin
          fs.Free;
          exit;
     end;
     fs.Readbuffer(jblkbuf[0], 4);//Aeeia Flash-header'a
     HdrLen    := HexToInt(IntToHex(jblkbuf[0], 2)+IntToHex(jblkbuf[1], 2)+IntToHex(jblkbuf[2], 2)+IntToHex(jblkbuf[3], 2));
     //form1._msg('HeaderLen: '+inttostr(HdrLen));
     fs.Readbuffer(jblkbuf[0], 4);//Eie-ai aeieia a Flash-caaieiaea
     SeemCount := HexToInt(IntToHex(jblkbuf[0], 2)+IntToHex(jblkbuf[1], 2)+IntToHex(jblkbuf[2], 2)+IntToHex(jblkbuf[3], 2));
     //form1._msg('BlockCount: '+inttostr(SeemCount));
     Application.ProcessMessages;
     while (fs.Position<HdrLen) do
     begin
          fs.Readbuffer(CurrSeem, 1);
          case CurrSeem of//Ia?aai? anao aeieia, iiene aeiea ni no?oeoo?ie RAW-loader'a
          $E4:
              begin
               //Form1._msg('SEEM: E4');
               fs.Readbuffer(jblkbuf[0], 2);
               CurrSeemLen:=(jblkbuf[0]*$100)+jblkbuf[1];
               fs.Seek(CurrSeemLen, sofromCurrent);
              end;
          $E5:
              begin
               //Form1._msg('SEEM: E5');
               fs.Readbuffer(jblkbuf[0], 2);
               CurrSeemLen:=(jblkbuf[0]*$100)+jblkbuf[1];
               fs.Seek(CurrSeemLen, sofromCurrent);
              end;
          $EA:
              begin
               //Form1._msg('SEEM: EA');
               fs.Readbuffer(jblkbuf[0], 2);
               CurrSeemLen:=(jblkbuf[0]*$100)+jblkbuf[1];
               fs.Seek(CurrSeemLen, sofromCurrent);
              end;
          $EE:
              begin
               //Form1._msg('SEEM: EE');
               fs.Readbuffer(jblkbuf[0], 2);
               CurrSeemLen:=(jblkbuf[0]*$100)+jblkbuf[1];
               fs.Seek(CurrSeemLen, sofromCurrent);
               partition:=True;
              Application.ProcessMessages;
              end;
          $F3:
              begin
              // Form1._msg('SEEM: F3');
               fs.Readbuffer(jblkbuf[0], 2);
               CurrSeemLen:=(jblkbuf[0]*$100)+jblkbuf[1];
              // Form1._msg('Dead mode support : True');
               //dead:=True;
               fs.Seek(CurrSeemLen, sofromCurrent);
               end;
          $FA: begin
              //Form1._msg('SEEM: FA');
              fs.ReadBuffer(jblkbuf[0],1);
              fs.Readbuffer(loaderlen,4); // ?eoaai aeeio - yoi aeeia anaai aa?aniiai i?ino?ainoaa aeiea FA, eioi?ia caieiaao aiaaeo aii, n?aco iinea aeiea aeeiu.
              fs.Readbuffer(jblkbuf,$0A);
              dwordswap(@loaderlen); // ?acai?a?eaaai
              //form1._msg('SEEM: FA:LEN: '+ inttostr(loaderlen));
              fs.seek(loaderlen-9,sofromcurrent); // iaiyai iiceoe? - iinea eaoo noa?ua aia?ua N8
              Application.ProcessMessages;
              end;
            $D8://Revision
              begin
                   fs.Readbuffer(CurrBlockLen, 1);
                   //Form1._msg('Found Block '+inttohex(CurrBlock, 1)+': Len: '+inttohex(CurrBlockLen, 2));
                   fs.Readbuffer(jblkbuf[0], CurrBlockLen);

                   if (CurrBlockLen>1) and (CurrBlockLen<3) then
                   begin
                   Rev:=inttostr(jblkbuf[0])+'.'+
                        inttostr(jblkbuf[1]);
                   result:=result+' Rev : '+rev+' ';
                   end
                   else Rev:='';
                   inc(i);

              end;
          $DB://Version
              begin
                   fs.Readbuffer(CurrBlockLen, 1);
                   //Form1._msg('Found Block '+inttohex(CurrBlock, 1)+': Len: '+inttohex(CurrBlockLen, 2));
                   fs.Readbuffer(jblkbuf[0], CurrBlockLen);

                   if (CurrBlockLen>1) and (CurrBlockLen<4) then
                   begin
                   Vers:=inttostr(jblkbuf[0])+'.'+
                         inttostr(jblkbuf[1])+'.'+
                         inttostr(jblkbuf[2]);
                   result:=result+' Ver : '+vers+' ';
                   end
                   else Vers:='';
                   inc(i);
              end;
            else
            begin
                   fs.Readbuffer(jblkbuf[0], 1);
                   CurrSeemLen:=jblkbuf[0];
                   fs.Seek(CurrSeemLen, sofromcurrent);
              end;
         end;
   end;
    Fs.free;
except
  result:='';
end;
end;

end.
