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  BB5_DeadFlashing():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, Stop: LongInt; FlashCfg, Byte1, Byte2, Byte3:byte):boolean;
function  BB5_EraseAreaSmallBlock(Start, Stop: 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  XSR6RAWBoot (core:string):Boolean;
function  OMAPFlash():Boolean;
function  Omap1610extrboot(ASIC:string):boolean;
function  OMAP1610boot () : boolean;
function  OMAP2420boot () : boolean;
function  ADLAPErestart(rb:Byte):Boolean;

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;
    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;
implementation

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;
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;
               //Сравнение имени найденного сертификата с искомым
               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));

               good:=0;
               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;
               //Сравнение имени найденного сертификата с искомым
               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_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;
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<>'') 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
       if not convertcnt(image) then begin
        Application.ProcessMessages;
       end
       else begin
       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;

     //Извлечение 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;
     Application.ProcessMessages;
      i:=0;
      repeat
      begin
      Sleep(100);
      Application.ProcessMessages;
      Inc(i)
      end;
      until (DevPresent=False) or ( i=200 );
     if i=200 then begin
     b:=False;
     Form1._msg('Error while restart phone - repower it and try again...');
     Exit;
     end;
     Application.ProcessMessages;
     b:=BB5_Flashing;
     Result:=b;
end;

function  BB5_Flashing():boolean;
var
     b, proto         : Boolean;
     i                : integer;
     rb               : Byte;
begin
     rb:=$04;
     Application.ProcessMessages;
     Form1._msg('Reopening the connection...');

     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;
          exit;
     end;

     //Phone in Flash Mode???
     CheckADLUpload[7]:=msgid;
     CheckADLUpload[8]:=ISIHeaderTransId;
     CheckADLUpload[9]:=$00;
     i:=USBBulkWritePort(@CheckADLUpload, Length(CheckADLUpload));
     if i<>12 then
     begin
     Form1._msg('Bootcode start in CMT fail ! Need flash via programming device :(');
     Form1.TimConChk.Interval:=2000;
     result:=False;
     exit;
     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 server [2nd] changing...');
               rb:=rxBuf[11];
          end;
     end
     else rb:=rxBuf[11];

    // Form1._msg(Byte2Str(rb));

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

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

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


     //Добавил для удобства кастом-прошивки
     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._msg('   ===Flashing [MCU]===');
          Form1.pb1.ForeColor:=clRed;
          if not BB5_EraseFile(core) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
          Form1.pb1.progress:=0;
          Form1.pb1.ForeColor:=clGreen;
          if not BB5_WriteFile(core) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
     end;
     Application.ProcessMessages;
     if Form1.chkPPMe.Checked=true then
     begin
          Form1._msg('   ===Flashing [PPM]===');
          Form1.pb1.ForeColor:=clRed;
          if not BB5_EraseFile(ppm) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
          Form1.pb1.progress:=0;
          Form1.pb1.ForeColor:=clGreen;
          if not BB5_WriteFile(ppm) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
     end;
     Application.ProcessMessages;
     if Form1.chkCNTe.Checked=true then
     begin
          Form1._msg('   ===Flashing [CNT]===');
          Form1.pb1.ForeColor:=clRed;
          if not BB5_EraseFile(image) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
          Form1.pb1.progress:=0;
          if not BB5_WriteFile(image) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
     end;
     Application.ProcessMessages;
     Form1._msg('');
     Form1._msg('Flashing done... Reboot phone now...');
     Form1._msg('');
     Application.ProcessMessages;
     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;

     BB5_ADL_RestartMCU(rb); // режим рестарта

     Form1.pb1.color:=clActiveBorder;
     Application.ProcessMessages;
     Sleep(1000);
     Application.ProcessMessages;
     Sleep(1000);
     Application.ProcessMessages;

     i:=0;
     if catchdevice<>$01 then
     begin
          repeat
                Application.ProcessMessages;
                Sleep(1000);
                Inc(i);
                Application.ProcessMessages;
          until (catchdevice=$01) or (i=50);
     end;

      if (i=50) and (catchdevice<>$01) 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;

     Form1.statusbar.Panels[6].Text:='BUSY';
     //Form1.statusbar.Panels[0].Text:=USBReadPhName;
     //Form1.statusbar.Panels[1].Text:=UsbReadIMEIPl;

     Form1.afterFlashdo;

     Application.ProcessMessages;
     Sleep(200);
     Form1.TimConChk.Enabled:=true;
     Form1._msg('Done!');

     Result:=true;
end;//End of Normal Mode Flashing

function  BB5_DeadFlashing():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! ---');
     Application.ProcessMessages;
     

     //Захват Nokia USB ROM устройства
     b:=false; i:=0;
     repeat
           if (i=1500) and (b=false) then begin
           Form1._msg('Phone not found.. :(');
           Form1.SetReady;
           form1.BtnDisable;
           Exit;
           end;
           Application.ProcessMessages;
           if catchdevice=$02 then
           begin
                b:=true;
                Form1._msg('Connection opened successfully');
           end;
           inc(i);
           Application.ProcessMessages;
     until b ;

     Application.ProcessMessages;

     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');
          result:=False;
          form1.BtnDisable;
          exit;
     end;

     //Парсинг 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. Unable to find flash CmtAlgorithm');
          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;
          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;

     //Извлечение Апдейт Агента
     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;
          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;

{================================== 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;

{================================== 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._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);

          USBControlPacket($222040, $8+PktLen, 0);
          Application.ProcessMessages;
     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._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);

          USBControlPacket($222040, $8+PktLen, 0);
          Application.ProcessMessages;
     end;
{======================================================================================}
     PASUB.Free;
     UAgent.Free;
     RAWLoader.Free;
     RAWBlock.Free;
      repeat
      begin
      Sleep(100);
      Application.ProcessMessages;
      end;
      until DevPresent=False;
     Application.ProcessMessages;
     b:=BB5_Flashing;
     Result:=b;

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;
begin
     Result:=false;
     partition:=false;
     partLen:=0;
     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(n,1);
     if n<>$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);
 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;
                if partition=True
                then
                begin
                RebuildPartition(partitionstream,partLen);
                partitionstream.Free;
                partition:=false;
                Application.ProcessMessages;
                end;
          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
                   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
                    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);
                        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
                        Form1._msg('Partition erase Error :(');
                        end;
                        end;
                       Application.ProcessMessages;

                      end;
                    end;
                  end;
                    Result:=True;
                    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;
     fs.Free;
 except
        on E:Exception do
        begin
             fs.Free;
             Form1._msg('EraseFile: Error: '+E.Message);
        end;
 end;
Application.ProcessMessages;
fullerase:=0;
Form1.pb1.MaxValue:=100;
Form1.pb1.Progress:=0;
end;

function BB5_EraseArea(Start, Stop: 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] := Stop div $1000000;
     Erase[21] := Stop div $10000;
     Erase[22] := Stop div $100;
     Erase[23] := Stop mod $100;

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

     n:=USBBulkWritePort(@Erase[0], Length(Erase));
     if n<>24 then exit;
     if Not USBBulkReadPort(16) or (Length(rxBuf)<16) then exit;

     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, Stop: 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(Stop, 8)+
                ', '+FlashType+', '+Subsystem);
     while (Start<Stop) and b do
     begin
          if ((Stop-Start)<PktLen) and b then //длина последнего кусочка
          begin
               b:=false;
               PktLen:=Stop-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(Stop, 4);
          Application.processmessages;

          n:=USBBulkWritePort(@Erase[0], Length(Erase));
          if n<>24 then exit;
          if Not USBBulkReadPort(16) or (Length(rxBuf)<16) then exit;

          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(Stop, 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 exit;
     if Not USBBulkReadPort(16) or (Length(rxBuf)<16) then exit;
     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 = $8000;
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;
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;
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...');

     while fs.Position<fs.Size do
     begin
          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;
               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
          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
                      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, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));

                        if Not USBBulkReadPort(12) or (Length(rxBuf)<12) then raise E.Create('Write Failed, err1, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));
                        if rxBuf[8]<>WriteData[8] then raise E.Create('Write Failed, (trans-err), at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));//целостность транзанкций
                        if rxBuf[11]<>$00         then raise E.Create('Write Failed, err4, 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
                      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, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));

                       if Not USBBulkReadPort(12) or (Length(rxBuf)<12) then raise E.Create('Write Failed, err1, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));
                       if rxBuf[8]<>WriteData[8] then raise E.Create('Write Failed, (trans-err), at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));//целостность транзанкций
                       if rxBuf[11]<>$00         then raise E.Create('Write Failed, err4, 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;
                 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));
                      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, err1, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));
                       if rxBuf[8]<>WriteData[8] then raise E.Create('Write Failed, (trans-err), at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));//целостность транзанкций
                       if rxBuf[11]<>$00         then raise E.Create('Write Failed, err4, 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;

               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, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));

                    if Not USBBulkReadPort(16) or (Length(rxBuf)<16) then raise E.Create('Write Failed, err2, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));
                    if rxBuf[8]<>txBuf[8] then raise E.Create('Write Failed,(trans-err), at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));//целостность транзанкций
                    if rxBuf[15]<>$00     then raise E.Create('Write Failed, err3, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));
{--------------------------------------------------------------------------------------------------------------------------------------------------------------}
               //Form1._msg('Send  : '+BufToHex_Str(@WriteData, 36));
               //Form1._msg('Receiv: '+BufToHex_Str(@rxBuf, n));
{=============================================================================================================================================================}
               end;
               continue;
          end;//end of case $54 - write Data

          $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));
               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
                    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
                    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
               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');
                    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');
                    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, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));

               if Not USBBulkReadPort(12) or (Length(rxBuf)<12) then raise E.Create('Write CERT Failed, err1, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));
               if rxBuf[8]<>txBuf[8] then raise E.Create('Write CERT Failed, (trans-err), at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));//целостность транзанкций
               if rxBuf[11]<>$00         then raise E.Create('Write CERT Failed, err4, 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, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));

                    if Not USBBulkReadPort(16) or (Length(rxBuf)<16) then raise E.Create('Write CERT Failed, err2, at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));
                    if rxBuf[8]<>txBuf[8] then raise E.Create('Write CERT Failed, (trans-err), at '+IntToHex(TargetOffset, 8)+':'+IntToHex(DataLen,8));//целостность транзанкций
                    if rxBuf[11]<>$00     then raise E.Create('Write CERT Failed, err2, 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;
     except
           on E:Exception do
           begin
                fs.Free;
                Form1._msg('Error: '+E.Message);
                Form1.pb1.Progress:=0;
                USBClosePort;
                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];
     Result:=(Count=Expected);
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
  case mode of
   $04: begin
      case oldsmart of
      false: 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;
             Result:=True;
             end;
      true: 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;
             Result:=True;
            end;
      end;
    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;
   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 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[7]:=msgid;
          GetRoot[8]:=ISIHeaderTransId;
          USBBulkWritePort(@GetRoot, Length(GetRoot));
          USBBulkReadPort($FFFF);

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

          //PreErase
          PreErase[7]:=msgid;
          PreErase[8]:=ISIHeaderTransId;
          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
          Form1._msg('ASIC CMT select Ok');
          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 - хз как ее ваять... =/

//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[9]=$28 then result:=True else result:=False;
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
     Form1.setbuzy;
     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! ---');
          Application.ProcessMessages;
     end;

     //?????? Nokia USB ROM ??????????
     b:=false; i:=0;
     repeat
           form1.setbuzy;
           if (i=2500) and (b=false) then
           begin
                Form1._msg('Phone not found.. :(');
                result:=False;
                Form1.SetReady;
                Exit;
           end;
           Application.ProcessMessages;
           //if BB5_USB_ScanAndOpenConnection('BB5', '*VID_0421&PID_0106&IF_OTH*', false) then
           if catchdevice=$02 then
           begin
                b:=true;
                Form1._msg('Connection opened successfully');
           end;
           Application.ProcessMessages;
           Sleep(10);
           inc(i);
           Application.ProcessMessages;
     until b ;

     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;

     // 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 ROOT_KEY_HASH Asic CMT. Unable to find flash CmtAlgorithm');
                        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);

                           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;
   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);
      end;
    until (DevPresent=False) or (i=2000);
   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;

     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;
          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;

     //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 server [2nd] changing...');
               rb:=rxBuf[11];
          end;
     end
     else rb:=rxBuf[11];

     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
     Form1._msg('ASIC CMT select Ok');
     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._msg('   ===Flashing [MCU]===');
          if not BB5_EraseFile(core) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
          Application.ProcessMessages;
          if not BB5_WriteFile(core) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
     end;
     Application.ProcessMessages;
     if Form1.chkPPMe.Checked=true then
     begin
          Form1._msg('   ===Flashing [PPM]===');
          if not BB5_EraseFile(ppm) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
           Application.ProcessMessages;
          if not BB5_WriteFile(ppm) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
     end;
     Application.ProcessMessages;
      if Form1.chkPPM1e.Checked=true then
     begin
          Form1._msg('   ===Flashing [PPM2]===');
          if not BB5_EraseFile(ppm1) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
           Application.ProcessMessages;
          if not BB5_WriteFile(ppm1) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
     end;
     Application.ProcessMessages;
     if Form1.chkCNTe.Checked=true then
     begin
          Form1._msg('   ===Flashing [CNT]===');
          if not BB5_EraseFile(image) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
          Application.ProcessMessages;
          if not BB5_WriteFile(image) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
     end;
     Application.ProcessMessages;
      if Form1.chkAPEe.Checked=true then
     begin
          Form1._msg('   ===Flashing [APE]===');
          if not BB5_EraseFile(ape) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
          Application.ProcessMessages;
          if not BB5_WriteFile(ape) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
     end;

     // режим рестарта
     AdlRestart06(rb);

     Application.ProcessMessages;
     Form1._msg('');
     Form1._msg('Flashing done... Reboot phone now...');
     Form1._msg('');
     Application.ProcessMessages;
     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;
     Application.ProcessMessages;
     Sleep(1000);
     Application.ProcessMessages;
     Sleep(1000);
     Application.ProcessMessages;

     i:=0;
     if catchdevice<>$01 then
     begin
          repeat
                Application.ProcessMessages;
                Sleep(1000);
                Inc(i);
                Application.ProcessMessages;
          until (catchdevice=$01) or (i=50);
     end;

      if (i=50) and (catchdevice<>$01) 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;

     Form1.statusbar.Panels[6].Text:='BUSY';
     //Form1.statusbar.Panels[0].Text:=USBReadPhName;
     //Form1.statusbar.Panels[1].Text:=UsbReadIMEIPl;

     Form1.afterFlashdo;

     Application.ProcessMessages;
     Sleep(200);
     Form1.SetReady;
     Form1.TimConChk.Enabled:=true;
     Form1._msg('Done!');
     //Form1.DisconnectFill;
     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
 $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;
 $72:
   begin
   buf2[0]:=$06;
   buf2[1]:=$06;
   buf2[2]:=$00;
   end;
 end;
////////=//////////
   buf1[0]:=$06;
   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
txBuf[0]:=$1B;
txBuf[1]:=$00;
txBuf[2]:=$10;
case cf of
0:txBuf[3]:=$6F;
1:txBuf[3]:=$21;
else txBuf[3]:=$6F;
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;
txBuf[5]:=(len+4) mod $100;
USBBulkWritePort(@txbuf[0],len+$A);
 if USBBulkReadPort($FFFF) then begin
 if (rxBuf[10]=0) and (rxBuf[11]=0 ) then begin
 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;
end;

function AdlRestart06 (rb:byte):Boolean;
var
  i:integer;
begin
  result:=false;
  case rb of
  $80:
   begin
    AdlPreBootReq[8]:=ISIHeaderTransId;
    USBBulkWritePort(@AdlPreBootReq, Length(AdlPreBootReq));
    if USBBulkReadPort($FFF) then begin
    if rxBuf[9]=$29 then Form1._msg('Finalize...');
     i:=USBBulkWritePort(@adlrestersxr15, Length(adlrestersxr15));
    if i<>12 then form1._msg('Error while rebooting :(');
    Application.ProcessMessages;
    end;
   end;
  $06:
   begin
   AdlPreBootReq[8]:=ISIHeaderTransId;
    USBBulkWritePort(@AdlPreBootReq, Length(AdlPreBootReq));
    if USBBulkReadPort($FFF) then begin
    if rxBuf[9]=$29 then Form1._msg('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('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
               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
               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;
               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;
               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;
               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;
               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  XSR6RAWBoot (core:string):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,PktLen       : integer;
  ms,
  RAWBlock,
  RAWLoader        : TmemoryStream;
  s, needSert      : String;
  Key, KeyLen      : Byte;
  b, proto         : Boolean;
begin
Form1.setbuzy;
     Form1._msg('Dead Mode is Selected');
     Form1._msg('Waiting for USB device...');
     Form1._msg('--- Press phone'+#39+'s power button! ---');
     Application.ProcessMessages;
    //Захват Nokia USB ROM устройства
     b:=false; i:=0;
     repeat
     form1.setbuzy;
           if (i=1500) and (b=false) then begin
           Form1._msg('Phone not found.. :(');
           result:=False;
           Form1.SetReady;
           Exit;
           end;
           Application.ProcessMessages;
            if catchdevice=$02 then begin
                b:=true;
                Form1._msg('Connection opened successfully');
           end;
           Application.ProcessMessages;
           inc(i);
           Application.ProcessMessages;
     until b ;

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

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

     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;

     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;

     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. Unable to find flash CmtAlgorithm');
          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;
          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;


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;
          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;

     //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('Auth Ok');
           Application.ProcessMessages;
          end;
         end;
     $03 :
         begin
         Application.Processmessages;
         form1._msg('Auth skip');
         //sentroot+pc+hash-> conf APE
         //send crc&
         end;
     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('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('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;

      if Form1.chkMCUen.Checked=true then
     begin
          Form1._msg('   ===Flashing [MCU]===');
          if not BB5_EraseFile(core) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
          Application.ProcessMessages;
          if not BB5_WriteFile(core) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
     end;
     Application.ProcessMessages;
     if Form1.chkPPMe.Checked=true then
     begin
          Form1._msg('   ===Flashing [PPM]===');
          if not BB5_EraseFile(ppm) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
          Application.ProcessMessages;
          if not BB5_WriteFile(ppm) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
     end;
     Application.ProcessMessages;
      if Form1.chkPPM1e.Checked=true then
     begin
          Form1._msg('   ===Flashing [PPM2]===');
          if not BB5_EraseFile(ppm1) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
          Application.ProcessMessages;
          if not BB5_WriteFile(ppm1) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
     end;
     Application.ProcessMessages;
     if Form1.chkCNTe.Checked=true then
     begin
          Form1._msg('   ===Flashing [CNT]===');
          if not BB5_EraseFile(image) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
           Application.ProcessMessages;
          if not BB5_WriteFile(image) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
     end;
     Application.ProcessMessages;
      if Form1.chkAPEe.Checked=true then
     begin
          Form1._msg('   ===Flashing [APE]===');
          if not BB5_EraseFile(ape) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
           Application.ProcessMessages;
          if not BB5_WriteFile(ape) then begin Form1.pb1.progress:=0; result:=False; Exit; end;
     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... Reboot phone now...');
     Form1._msg('');
     Application.ProcessMessages;
     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;
     Application.ProcessMessages;
     Sleep(1000);
     Application.ProcessMessages;
     Sleep(1000);
     Application.ProcessMessages;

     i:=0;
     if catchdevice<>$01 then
     begin
          repeat
                Application.ProcessMessages;
                Sleep(1000);
                Inc(i);
                Application.ProcessMessages;
          until (catchdevice=$01) or (i=50);
     end;

      if (i=50) and (catchdevice<>$01) 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;

     Form1.statusbar.Panels[6].Text:='BUSY';
     //Form1.statusbar.Panels[0].Text:=USBReadPhName;
     //Form1.statusbar.Panels[1].Text:=UsbReadIMEIPl;

     Form1.afterFlashdo;

     Application.ProcessMessages;
     Sleep(200);
     Form1.TimConChk.Enabled:=true;
     Form1._msg('Done!');
     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
           // режим рестарта
           CMTfinish[3]:=$6F;
           CMTfinish[8]:=ISIHeaderTransId;
           USBBulkWritePort(@CMTfinish, Length(CMTfinish));
           if USBBulkReadPort($FFFF) then begin
            if rxbuf[10]<>$00 then begin
                             Form1._msg('Close CMT session failed ');
                             result:=false;
                             Exit;
                             end;
           Form1._msg('Close CMT session...');
           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('Close APE session failed ');
                             result:=False;
                             Exit;
                             end;
            Form1._msg('Close APE session...');
            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
           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('Close CMT session failed ');
                             result:=false;
                             Exit;
                             end;
           Form1._msg('Close CMT session...');
           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('Close APE session failed ');
                             result:=false;
                             Exit;
                             end;
            Form1._msg('Close APE session...');
            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;


end.
