unit UnitUFS;

interface
Uses
  D2XXUnit,HexUtils, FBoots, Windows, Masks, Forms,sysutils, classes, boots, dialogs ;

  function BArmInterface():boolean;
  function readData():boolean;
  function SwitchBoxMode(Mode: string): boolean;
  function ChecCMTData():boolean;
    procedure FetchBootData;
  function ufsresetpower():Boolean;
  function replyverify():Boolean;
  function replyverify2():Boolean;
  function SendRaw(Asic:integer; Loader:string) : integer;
  function Freaddata(bytes:byte):Boolean;
  function Freadflashic ():boolean;
  Function SendAlgorihtm(Asic : integer; algo : string):integer;
  function CheckVpp():Boolean;
  function ReadCert(ASIC : Byte ; CERT : string):string;
  function GetReadLen():Byte;
  function ReadDatarequest(bytes:byte):Boolean;
  function replyend():Boolean;
  function PreCertreq():Boolean;
  function ufs_cmd(timeout:dword; pCmd:pointer; CmdLen:dword; pDst:Pointer; Expected:dword):dword;
  function ufsfl_cmd(timeout:dword; pCmd:pointer; CmdLen:dword; pDst:Pointer; Expected:dword):dword;
  function replyverify3():byte;
  function ufx_boot(sn: string):boolean;
  function ufx_sw_fbus(sn: string ; mode: string): boolean;
  function incheck(bytes:Integer):Boolean;
  function phoneready(retry:Integer):Boolean;
  Function FlashPrepare (flimage:string):Boolean;
  function UFSPartitioning(core:string):Boolean;
  function SendRawID(Asic:integer; Loader:string) : integer;

function getapepapub():Boolean;
function UFSprepareForFlash(image:string):Boolean;
function UFSeraseUni(core:string):Boolean;
function ConFigureAsic(ASIC:Byte):Boolean;
function AsicComandFur():Boolean;
function checkc7():Boolean;
function UFSfinishsession():integer;
function UFSEBLock():integer;
function buildUFScert(DataStream : widestring; cert : string; asic : byte ): Boolean;
function UFSeraseCRT (CRT : string; Asic : Byte) : Boolean;
function UFSEBLockAPE():boolean;

function busreset():boolean;
///
function ufssys_cmd (CmdLen:dword; pDst:Pointer; Expected:dword):dword;
//Infineon
//Infineon
function Boot_infineon({Boot1:TMemoryStream;Boot2:TMemoryStream}):Boolean;
function BusCheckInfineon():Boolean;
function InfineonEnd():Boolean;
function FlashInfineonFile(FlasHfile:string):Boolean;
function InfineonErase(infcore:string; curreg:string):Boolean;
function sendCert(infcore:string):Boolean;
function infgetblockcnt(infcore:string; Erlist:Tstringlist):Integer;
function InfineonWrite(infcore:string; mode:Integer; dlen:string):Boolean;
function checkready():Boolean;
function getchksuminf():Boolean;
function halfboot():Boolean;
procedure dumpregionepp(start,stop:dword ; resstr:Tmemorystream);
procedure dumpppmcatalog(start,stop:dword ; resstr:Tmemorystream);
//special
function UFSeraseS40(area:string):Boolean;
function UFSFormatLow(area:string):Boolean;

implementation
uses UnitE1, UnitPavel, unit1, FlashBoots,USBmain, FbusMain, unitmisc,Graphics;
var
  if_layer_dir: string;
  u_id: DWord;
  u_id_reprezentation : String;
  u_sn: String;
  u_g_sn: String;
  EEProm: string;
  Atmel_Sn: Integer;
  RxFrBuf,TxFrBuf:array[0..$8000] of byte;
  FrameInside: array[0..$FFFF] of byte;
  Seq: Integer;
  AckPacket: array[0..9] of byte;
 // Fbus_Timeout: integer;
  FR_CNT1:byte;
  Mode12A4:byte;
  McuSW_Buf, SWVersion, SWDate, Product, Manufacturer: String;
  PMWrLen            : integer;
  PMWrBuffer: array[0..$800000] of byte;
  PMData: array[0..$800000] of byte;
  FLbyte             : Byte;
  CFltype,AFltype    : Byte;


  const
    Fbus_Timeout=3000;

function ufsresetpower():Boolean;
var
  retry, i: integer;
  InterfaceArmed: boolean;
  c_buf: string;
label
  dummy_sn_retry;
begin
   try
   
 except
  result:=false;
 end;

end;

function MakeSeq:integer;
begin
if Seq=$40 then
  begin
    Seq:=$41;
    Result:=Seq;
    exit;
  end;
if Seq=$41 then
  begin
    Seq:=$42;
    Result:=Seq;
    exit;
  end;
if Seq=$42 then
  begin
    Seq:=$43;
    Result:=Seq;
    exit;
  end;
if Seq=$43 then
  begin
    Seq:=$44;
    Result:=Seq;
    exit;
  end;
if Seq=$44 then
  begin
    Seq:=$45;
    Result:=Seq;
    exit;
  end;
if Seq=$45 then
  begin
    Seq:=$46;
    Result:=Seq;
    exit;
  end;
if Seq=$46 then
  begin
    Seq:=$47;
    Result:=Seq;
    exit;
  end;
if Seq=$47 then
  begin
    Seq:=$40;
    Result:=Seq;
    exit;
  end;
end;


function ufssys_cmd (CmdLen:dword; pDst:Pointer; Expected:dword):dword;
begin
result:=0;
if write_usb_device_buffer(cmdlen)<>cmdlen then exit;
if read_usb_device_buffer(expected)<>expected then result:=0;
move(ft_in_buffer,pointer(dword(pdst))^,expected);
end;


function ufs_cmd(timeout:dword; pCmd:pointer; CmdLen:dword; pDst:Pointer; Expected:dword):dword;
var
tries,totalread,toread,leftover:dword;
finished:boolean;
cnt,cnt1:longint;
begin
Application.ProcessMessages;
FillMemory(@cmd_buf,65536,$00);
PURGE_USB_DEVICE_IN;
result:=0;
finished:=false;
if cmdlen>0 then
begin
move(pCmd^,ft_out_buffer,cmdlen);
if write_usb_device_buffer(cmdlen)<>cmdlen then exit;
end;
if expected=0 then
begin
result:=cmdlen;
exit;
end;
cnt:=gettickcount+timeout;
Get_USB_Device_QueueStatus;
while (ft_q_bytes<expected) do
begin
if (cnt-gettickcount)<=0 then break;
Get_USB_Device_QueueStatus;
end;
if read_usb_device_buffer(ft_q_bytes)<>ft_q_bytes
then exit else
move(ft_in_buffer,pointer(dword(pdst))^,ft_q_bytes );
PURGE_USB_DEVICE_OUT;
result:=ft_q_bytes;
end;

function ufsfl_cmd(timeout:dword; pCmd:pointer; CmdLen:dword; pDst:Pointer; Expected:dword):dword;
var
tries,totalread,toread,leftover:dword;
finished:boolean;
cnt,cnt1:longint;
begin
Application.ProcessMessages;
FillMemory(@cmd_buf,65536,$00);
PURGE_USB_DEVICE_IN;
result:=0;
finished:=false;
if cmdlen>0 then
begin
move(pCmd^,ft_out_buffer,cmdlen);
if write_usb_device_buffer(cmdlen)<>cmdlen then exit;
end;
if expected=0 then
begin
result:=cmdlen;
exit;
end;
cnt:=gettickcount+timeout;
Get_USB_Device_QueueStatus;
while (ft_q_bytes<expected) do
begin
if (cnt-gettickcount)<=0 then break;
Get_USB_Device_QueueStatus;
end;
if read_usb_device_buffer(ft_q_bytes)<>ft_q_bytes
then exit else
move(ft_in_buffer,pointer(dword(pdst))^,ft_q_bytes );
PURGE_USB_DEVICE_OUT;
result:=ft_q_bytes;
end;

function ufx_boot(sn: string):boolean;
var
  cmd_buf:array [0..1024] of byte;
  i,j: integer;
label
TryAgain;
begin

 try
 Reset_USB_Device;
 Close_USB_Device;
 except
 Application.ProcessMessages;
 end;

if (Open_USB_Device_By_Serial_Number(sn) <> FT_OK) then
  begin
    form1._msg('Error open UFS #'+sn);
    Close_USB_Device;  Result:=False; exit;
  end;

if (Reset_USB_Device <> FT_OK) then
  begin
    form1._msg('Error reset UFS #'+sn);
    Close_USB_Device;  Result:=False; exit;
  end;

if Set_USB_Device_TimeOuts(100,2000) <> ft_ok then
  begin
    form1._msg('UFS timeout set failed');
    Close_USB_Device;  Result:=False; exit;
  end;

if (Reset_USB_Device <> FT_OK) then
  begin
    form1._msg('Error reset UFS');
    Close_USB_Device;  Result:=False; exit;
  end;

if (Purge_USB_Device_Out <> FT_OK) then
  begin
     Close_USB_Device; Result:=False; exit;
  end;

if (Purge_USB_Device_IN <> FT_OK) then
  begin
     Close_USB_Device; Result:=False; exit;
  end;

if Set_USB_Parameters($10000, $10000)<>FT_OK then
              begin
                form1._msg('Parameters set error');
                Close_USB_Device; Result:=False; exit;
              end;

FT_current_DataBits:=8;
FT_Current_StopBits:=0;
FT_Current_Parity:=0;
if Set_USB_Device_DataCharacteristics <> FT_OK then
  begin
    form1._msg('Data set error');
    Close_USB_Device;  Result:=False; exit;
  end;


FT_Current_FlowControl:=0;
FT_XON_Value:=$11;
FT_XOFF_Value:=$13;

if Set_USB_Device_FlowControl <> FT_OK then
  begin
    form1._msg('UFS flowcontrol set error');
    Close_USB_Device;  Result:=False; exit;
  end;


if (Set_USB_Device_BaudRate_Divisor(26) <> FT_OK) then
  begin
    form1._msg('UFS bd switch failed');
    Close_USB_Device;  Result:=False; exit;
  end;


if (set_usb_Device_dtr <> FT_OK) then
  begin
    form1._msg('UFS dtrset error');
    Close_USB_Device;  Result:=False; exit;
  end;

j:=0;

TryAgain:
FT_out_buffer[0]:=$3F;
ufs_cmd(1000,@ft_out_buffer,1,@cmd_buf,$2);
j:=j+1;

  if ((cmd_buf[0]<>$62) or (cmd_buf[1]<>$cf)) and (cmd_buf[0]<>$3F) then
  begin
    if j>5 then
    begin
      form1._msg('UFS Boot Enter error ('+IntToHex(cmd_buf[0],2)+IntToHex(Cmd_Buf[1], 2)+')');
      Close_USB_Device;  Result:=False; exit;
    end
    else
      begin
        sleep(500);
         if (Reset_USB_Device <> FT_OK) then
          begin
          form1._msg('Error reset UFS #'+sn);
          Close_USB_Device;  Result:=False; exit;
         end;

        if Set_USB_Device_TimeOuts(2000,2000) <> ft_ok then
        begin
        form1._msg('UFS timeout set failed');
        Close_USB_Device;  Result:=False; exit;
        end;

        if (Reset_USB_Device <> FT_OK) then
        begin
        form1._msg('Error reset UFS');
        Close_USB_Device;  Result:=False; exit;
        end;

        if (Purge_USB_Device_Out <> FT_OK) then
        begin
        Close_USB_Device; Result:=False; exit;
        end;

        if (Purge_USB_Device_IN <> FT_OK) then
         begin
          Close_USB_Device; Result:=False; exit;
         end;

       if Set_USB_Parameters($10000, $10000)<>FT_OK then
              begin
                form1._msg('Parameters set error');
                Close_USB_Device; Result:=False; exit;
              end;

         FT_current_DataBits:=8;
         FT_Current_StopBits:=0;
         FT_Current_Parity:=0;
         if Set_USB_Device_DataCharacteristics <> FT_OK then
         begin
         form1._msg('Data set error');
         Close_USB_Device;  Result:=False; exit;
         end;


        FT_Current_FlowControl:=0;
        FT_XON_Value:=$11;
        FT_XOFF_Value:=$13;

        if Set_USB_Device_FlowControl <> FT_OK then
        begin
         form1._msg('UFS flowcontrol set error');
         Close_USB_Device;  Result:=False; exit;
        end;


        if (Set_USB_Device_BaudRate_Divisor(16696) <> FT_OK) then
        begin
        form1._msg('UFS bd switch failed');
         Close_USB_Device;  Result:=False; exit;
        end;

        if (clr_usb_Device_dtr <> FT_OK) then
        begin
        form1._msg('UFS clrdtr error');
        Close_USB_Device;  Result:=False; exit;
        end;

          if (clr_usb_Device_rts <> FT_OK) then
         begin
         form1._msg('UFS clrrts error');
         Close_USB_Device;  Result:=False; exit;
         end;

         if (Purge_USB_Device_Out <> FT_OK) then
         begin
         Close_USB_Device; Result:=False; exit;
         end;

         if (Purge_USB_Device_IN <> FT_OK) then
         begin
         Close_USB_Device; Result:=False; exit;
         end;

          if (set_usb_Device_rts <> FT_OK) then
         begin
         form1._msg('UFS rtsset error');
         Close_USB_Device;  Result:=False; exit;
         end;

          if (clr_usb_Device_rts <> FT_OK) then
         begin
         form1._msg('UFS clrrts error');
         Close_USB_Device;  Result:=False; exit;
         end;

         if (set_usb_Device_dtr <> FT_OK) then
         begin
         form1._msg('UFS dtrset error');
         Close_USB_Device;  Result:=False; exit;
         end;


          if (set_usb_Device_rts <> FT_OK) then
         begin
         form1._msg('UFS rtsset error');
         Close_USB_Device;  Result:=False; exit;
         end;
         if (Purge_USB_Device_Out <> FT_OK) then
         begin
         Close_USB_Device; Result:=False; exit;
         end;

         if (Purge_USB_Device_IN <> FT_OK) then
         begin
         Close_USB_Device; Result:=False; exit;
         end;


        goto TryAgain;
      end;
  end
  else result:=true;

end;


function WriteByte(inp : Byte):boolean;
begin
 FT_Out_Buffer[0] := inp;
 Write_USB_Device_Buffer(1);
end;

function SwitchBoxMode(Mode: string): boolean;
const
BoxBoot : Array[0..6] of Byte = ($4C,$1D,$1D,$1F,$02,$0D,$98);
var
PrevStatus: String;
ic:Integer;
begin
Result:=False;

if Mode='FBUS' then
begin
if (Set_USB_Device_Event_Notification(01) <> FT_OK) then
  begin
     Close_USB_Device; Result:=False; exit;
  end;

FT_current_DataBits:=8;
FT_Current_StopBits:=0;
FT_Current_Parity:=0;
if Set_USB_Device_DataCharacteristics <> FT_OK then
  begin
    Close_USB_Device;  Result:=False; exit;
  end;

FT_Current_FlowControl:=0;
FT_XON_Value:=$11;
FT_XOFF_Value:=$13;

if Set_USB_Device_FlowControl <> FT_OK then
  begin
    Close_USB_Device;  Result:=False; exit;
  end;

FT_Out_Buffer[0]:=$38;
ufs_cmd(50,@ft_out_buffer,1,@cmd_buf,$05);

FT_Out_Buffer[0]:=$44;
FT_Out_Buffer[1]:=$00;
FT_Out_Buffer[2]:=$00;
FT_Out_Buffer[3]:=$08;
FT_Out_Buffer[4]:=$00;
ufs_cmd(250,@ft_out_buffer,5,@cmd_buf,$05);

FT_Out_Buffer[0]:=$44;
FT_Out_Buffer[1]:=$18;
FT_Out_Buffer[2]:=$00;
FT_Out_Buffer[3]:=$08;
FT_Out_Buffer[4]:=$00;
ufs_cmd(250,@ft_out_buffer,5,@cmd_buf,$05);

FT_Out_Buffer[0]:=$55;
FT_Out_Buffer[1]:=$05;
ufs_cmd(50,@ft_out_buffer,2,@cmd_buf,$03);

if Set_USB_Device_TimeOuts(60000,60000) <> ft_ok then
  begin
    Close_USB_Device;  Result:=False; exit;
  end;

FT_Out_Buffer[0]:=$42;
FT_Out_Buffer[1]:=$10;
ufs_cmd(1,@ft_out_buffer,2,@cmd_buf,$01);

if (Set_USB_Device_BaudRate_Divisor($50001A) <> FT_OK) then
  begin
    form1._msg('Baudrate switch failed. This is critical.');
    Close_USB_Device;  Result:=False; exit;
  end;

FT_Out_Buffer[0]:=$58;
ufs_cmd(1000,@ft_out_buffer,1,@cmd_buf,1);

FT_Out_Buffer[0]:=$32;
ufs_cmd(50,@ft_out_buffer,1,@cmd_buf,1);

if (clr_usb_Device_dtr <> FT_OK) then
  begin
    Close_USB_Device;  Result:=False; exit;
  end;

if (clr_usb_Device_dtr <> FT_OK) then
  begin
    Close_USB_Device;  Result:=False; exit;
  end;

if (set_usb_Device_dtr <> FT_OK) then
  begin
    Close_USB_Device;  Result:=False; exit;
  end;


if (Purge_USB_Device_Out <> FT_OK) then
  begin
     Close_USB_Device; Result:=False; exit;
  end;

if (Purge_USB_Device_IN <> FT_OK) then
  begin
     Close_USB_Device; Result:=False; exit;
  end;

FT_Out_Buffer[0]:=$67;
ufs_cmd(500,@ft_out_buffer,1,@cmd_buf,1);

// FBUS Mode, DTR High, RTS Low, Flow: NO
FT_Out_Buffer[0]:=$68;
FT_Out_Buffer[1]:=$00;
ufs_cmd(50,@ft_out_buffer,2,@cmd_buf,$01);

FT_Out_Buffer[0]:=$66;
ufs_cmd(100,@ft_out_buffer,1,@cmd_buf,$01);

FT_Out_Buffer[0]:=$A5;
ufs_cmd(50,@ft_out_buffer,1,@cmd_buf,$01);

// DTR falling-edge

if (clr_usb_Device_dtr <> FT_OK) then
  begin
    Close_USB_Device;  Result:=False; exit;
  end;

Result:=True;
end;

if Mode='FlashBus' then
begin



{FT_Out_Buffer[0]:=$32;
ufs_cmd(200,@ft_out_buffer,1,@cmd_buf,$01);

    FT_Current_FlowControl:=FT_FLOW_NONE;
    FT_XON_Value:=$11;
    FT_XOFF_Value:=$13;
    if Set_USB_Device_FlowControl <> FT_OK then
      begin
        form1._msg('UFS flowcontrol set failed');
        Close_USB_Device;  exit;
      end;

if (set_usb_Device_dtr <> FT_OK) then
  begin
    Close_USB_Device;  Result:=False; exit;
  end;

if (Purge_USB_Device_IN <> FT_OK) then
  begin
     Close_USB_Device; Result:=False; exit;
  end;

if (Set_USB_Device_TimeOuts($10000,$10000)<> FT_OK) then
    begin
     Close_USB_Device; Result:=False; exit;
    end;

FT_Out_Buffer[0]:=$78;
ufs_cmd(200,@ft_out_buffer,1,@cmd_buf,$01);

FT_Out_Buffer[0]:=$42;
FT_Out_Buffer[1]:=$00;
ufs_cmd(200,@ft_out_buffer,2,@cmd_buf,$01);
sleep(100);

if (Set_USB_Device_BaudRate_Divisor($1) <> FT_OK) then
  begin
    Close_USB_Device;  Result:=False; exit;
  end;

FT_Out_Buffer[0]:=$32;
ufs_cmd(300,@ft_out_buffer,1,@cmd_buf,$01);

    FT_Current_FlowControl:=FT_FLOW_DTR_DSR;
    FT_XON_Value:=$11;
    FT_XOFF_Value:=$13;
    if Set_USB_Device_FlowControl <> FT_OK then
      begin
        form1._msg('UFS flowcontrol set failed');
        Close_USB_Device;  exit;
      end;

FT_Out_Buffer[0]:=$67;
ufs_cmd(500,@ft_out_buffer,1,@cmd_buf,1);

 FT_out_Buffer[0] := $62;
 FT_out_Buffer[1] := $FB;
 FT_out_Buffer[2] := $01;
 FT_out_Buffer[3] := $AA;
ufs_cmd(2000,@ft_out_buffer,4,@cmd_buf,3); }

Reset_USB_Device ;
Set_USB_Device_FlowControl;
Set_USB_Device_DTR;
Purge_USB_Device_Out;
Purge_USB_Device_In;
Set_USB_Device_TimeOuts(10000,10000);

Purge_USB_Device_Out;
Purge_USB_Device_In;

Sleep(100);
FT_Out_Buffer[0] := $4C;
FT_Out_Buffer[1] := $1D;
FT_Out_Buffer[2] := $1D;
FT_Out_Buffer[3] := $1F;
FT_Out_Buffer[4] := $02;
FT_Out_Buffer[5] := $0D;
FT_Out_Buffer[6] := $98;
ufs_cmd(600,@Ft_out_buffer,7,@cmd_buf,5);

Reset_USB_Device ;

FT_Out_Buffer[0] := $42;  
FT_Out_Buffer[1] := $00;  
ufs_cmd(600,@Ft_out_buffer,2,@cmd_buf,0);



//Set UFS to Atmel MODE first
Reset_USB_Device ;
Purge_USB_Device_Out;
Purge_USB_Device_In;
Set_USB_Device_DTR;
Purge_USB_Device_Out;
Purge_USB_Device_In;
Set_USB_Device_TimeOuts(500,8000);
FT_Current_FlowControl := 0;
Set_USB_Device_FlowControl;

Set_USB_Device_TimeOuts(6000,8000);
If Set_USB_Device_BaudRate_Divisor($1) <> FT_Ok Then Exit; 

FT_out_Buffer[0] := $58;  
ufs_cmd(600,@Ft_out_buffer,1,@cmd_buf,1);

FT_Out_Buffer[0] := $32;  
ufs_cmd(600,@Ft_out_buffer,1,@cmd_buf,1);


FT_out_Buffer[0] := $68;   
FT_out_Buffer[1] := $01;
ufs_cmd(600,@Ft_out_buffer,2,@cmd_buf,1);

FT_Out_Buffer[0] := $67;   
ufs_cmd(600,@Ft_out_buffer,1,@cmd_buf,1);

Set_USB_Device_FlowControl;
Set_USB_Device_DTR;
Purge_USB_Device_Out;
Purge_USB_Device_In;
Set_USB_Device_TimeOuts(10000,10000);

Purge_USB_Device_Out;
Purge_USB_Device_In;


FT_Out_Buffer[0] := $78;   
ufs_cmd(600,@Ft_out_buffer,1,@cmd_buf,1);



Purge_USB_Device_Out;
Purge_USB_Device_In;


FT_Out_Buffer[0] := $42;  
FT_Out_Buffer[1] := $00;  
ufs_cmd(600,@Ft_out_buffer,2,@cmd_buf,0);


If Set_USB_Device_BaudRate_Divisor($1) <> FT_Ok Then Exit;  


FT_Out_Buffer[0] := $32;   
ufs_cmd(600,@Ft_out_buffer,1,@cmd_buf,1);


FT_Current_FlowControl := 512;
Set_USB_Device_FlowControl;
If Set_USB_Parameters(65536,65536) <> FT_Ok Then Exit;

FT_Out_Buffer[0] := $67;   
ufs_cmd(600,@Ft_out_buffer,1,@cmd_buf,1);

sleep(100);

FT_out_Buffer[0] := $62;
FT_out_Buffer[1] := $FB;    
FT_out_Buffer[2] := $01;
FT_out_Buffer[3] := $AA;
ufs_cmd(2000,@Ft_out_buffer,4,@cmd_buf,3);
Form1.statusbar.Panels[4].Text:='';
if {(cmd_buf[0]=$FF) and }(cmd_buf[1]=$FF) or (cmd_buf[2]=$72) then
begin
form1._msg('FlashMode set Ok');
result:=True;
end
else result:=False;
end;

if Mode='FastReset' then
begin

FT_Out_Buffer[0]:=$67;
ufs_cmd(500,@ft_out_buffer,1,@cmd_buf,1);

Result:=True;

end;

if Mode='Infineon' then
 begin
    If Set_USB_Device_TimeOuts($2710,$2710)<> FT_Ok Then Exit;
    sleep(5);
    If Set_USB_Device_BaudRate_Divisor($1A) <> FT_Ok Then Exit;
    Form1.statusbar.Panels[4].Text:='';
    result:=True;
  end;
end;

function ufx_sw_fbus(sn: string ; mode: string): boolean;
var
  cmd_buf: array [0..1024] of byte;
  chksum: byte;
  i: integer;
  Fuses:array[1..2] of byte;
begin

FT_Out_Buffer[0]:=$4C;
FT_Out_Buffer[1]:=$4D;
FT_Out_Buffer[2]:=$54;
FT_Out_Buffer[3]:=$31;
FT_Out_Buffer[4]:=$39;
FT_Out_Buffer[5]:=$06;
FT_Out_Buffer[6]:=$EF;
ufsfl_cmd(1200,@FT_out_buffer,7,@cmd_buf,1);

//if cmd_buf[0]<>$2A then Form1._msg('Error prepare UFSx / '+byte2str(cmd_buf[0]));

// check_licence
FT_Out_Buffer[0]:=$4C;
FT_Out_Buffer[1]:=$1D;
FT_Out_Buffer[2]:=$1D;
FT_Out_Buffer[3]:=$1F;
FT_Out_Buffer[4]:=$02;
FT_Out_Buffer[5]:=$0D;
FT_Out_Buffer[6]:=$98;
ufsfl_cmd(300,@ft_out_buffer,7,@cmd_buf,$01);

//if cmd_buf[0]<>$3E then Form1._msg('Prepare error UFSx / '+byte2str(cmd_buf[0]));

// firmware version
FT_Out_Buffer[0]:=$41;
ufsfl_cmd(300,@ft_out_buffer,1,@cmd_buf,32);

FT_Out_Buffer[0]:=$58;
ufsfl_cmd(300,@ft_out_buffer,1,@cmd_buf,$01);

//if cmd_buf[0]<>$5A then Form1._msg('Fail init UFSx / '+byte2str(cmd_buf[0]));


{// bootloader version
FT_Out_Buffer[0]:=$56;
ufs_cmd(100,@ft_out_buffer,1,@cmd_buf,32);

// firmware version
FT_Out_Buffer[0]:=$41;
ufs_cmd(100,@ft_out_buffer,1,@cmd_buf,32);

// amtel sn
FT_Out_Buffer[0]:=$54;
ufs_cmd(50,@ft_out_buffer,1,@cmd_buf,$03);
if (Purge_USB_Device_Out <> FT_OK) then
  begin
    form1._msg('Cannot purge UFSx #'+sn+'. This is critical.');
    Close_USB_Device;  Result:=False; exit;
  end;
atmel_sn:=HexToInt(IntToHex(cmd_buf[0], 2)+IntToHex(cmd_buf[1], 2));

// read fuses
FT_Out_Buffer[0]:=$53;
ufs_cmd(50,@ft_out_buffer,1,@cmd_buf,$03);
fuses[1]:=cmd_buf[1];
fuses[2]:=cmd_buf[2];

// check_licence
FT_Out_Buffer[0]:=$4C;
FT_Out_Buffer[1]:=$1D;
FT_Out_Buffer[2]:=$1D;
FT_Out_Buffer[3]:=$1F;
FT_Out_Buffer[4]:=$02;
FT_Out_Buffer[5]:=$0D;
chksum:=FT_Out_buffer[1]+FT_Out_buffer[2]+FT_Out_buffer[3]+FT_Out_buffer[4]+FT_Out_buffer[5];
FT_Out_Buffer[6]:=-chksum;
ufs_cmd(50,@ft_out_buffer,7,@cmd_buf,$03);

// download eeprom
FT_Out_Buffer[0]:=$39;
ufs_cmd(500,@ft_out_buffer,1,@cmd_buf,194);
eeprom:='';
for i:=0 to 193 do eeprom:=eeprom+IntToHex(cmd_buf[i], 2); }

Result:=SwitchBoxMode(mode);
end;


function NFB_Send55str():boolean;
var
  i: integer;
begin

Result:=False;
for i:=1 to 5 do
begin
FT_Out_Buffer[0]:=$55;
FT_Out_Buffer[1]:=$55;
FT_Out_Buffer[2]:=$55;
FT_Out_Buffer[3]:=$55;
FT_Out_Buffer[4]:=$55;
if (Write_USB_Device_Buffer(5))<>5 then exit;
end;
Result:=true;
end;

function fbus_crc(data: string):string;
var
  crc: byte;
  i: integer;
  s_crc: string;
begin

crc:=0;
i:=0;
while i < (strlen(pchar(data)) div 2) do
  begin
    crc:=crc xor HexToInt(data[i*2+1]+data[i*2+2]);
    inc(i, 2);
  end;
s_crc:=inttohex(crc, 2);

crc:=0;
i:=1;
while i < (strlen(pchar(data)) div 2) do
  begin
    crc:=crc xor HexToInt(data[i*2+1]+data[i*2+2]);
    inc(i, 2);
  end;
s_crc:=s_crc+inttohex(crc, 2);

Result:=s_crc;
end;

function Suck_Fbus(timeout:dword; pCmd:pointer; CmdLen:dword; pDst:Pointer; CheckAck: boolean; SendAck: boolean):dword;
var
tries,totalread,toread,leftover:dword;
finished:boolean;
cnt,cnt1:longint;
cBuf: array [0..$FFFF] of byte;
crcBuf: string;
CalculatedCRC, PacketCRC: String;
ExpectedBuf: integer;
i,j,k: integer;
LoadCounter: integer;
SecondPacketLength: Integer;
SeqTmp: integer;
BruteForce: Boolean;
PrevStatus: String;
begin
Application.ProcessMessages;

if (Purge_USB_Device_IN <> FT_OK) then exit;
if (Purge_USB_Device_OUT <> FT_OK) then exit;

Finished:=False;
Move(pCmd^, FT_OUT_BUFFER, CmdLen);
if Write_USB_Device_Buffer(CmdLen)<>CmdLen then exit;

Cnt:=GetTickCount+TimeOut;
Get_USB_Device_Queuestatus;

if (CheckAck) then
begin
Cnt:=GetTickCount+TimeOut;
Get_USB_Device_Queuestatus;
while (FT_Q_Bytes<10) do
  begin
    Application.ProcessMessages;
    // check if Time not exceeded.
    if (Cnt-GetTickCount)<=0 then break;
    Get_USB_Device_Queuestatus;
  end;
if (Cnt-GetTickCount)<=0 then exit else
if Read_USB_Device_Buffer(10)<>10 then exit;
for i:=0 to 10-1 do AckPacket[i]:=FT_IN_Buffer[i];
for i:=0 to 10-1 do FT_In_Buffer[i]:=$00;
// I think we have now ACK packet!
if AckPacket[0]<>$1E then exit;
if AckPacket[1]<>$10 then exit;
if AckPacket[2]<>$00 then exit;
if AckPacket[3]<>$7F then exit;
// Now needed to Calculate and Check the ACK packet CRC
crcBuf:='';
for i:=0 to 7 do crcBuf:=crcBuf+IntToHex(AckPacket[i], 2);
CalculatedCRC:=Fbus_CRC(crcBuf);
PacketCRC:=IntToHex(AckPacket[8], 2)+IntToHex(AckPacket[9], 2);
if CalculatedCRC<>PacketCRC then exit;
end;
// If crc is OK we need now to read the rest of packet

Cnt:=GetTickCount+TimeOut;
Get_USB_Device_Queuestatus;
while (FT_Q_Bytes<1) do
  begin
    Application.ProcessMessages;
    // check if Time not exceeded.
    if (Cnt-GetTickCount)<=0 then break;
    Get_USB_Device_Queuestatus;
  end;
if (Cnt-GetTickCount)<=0 then exit else if Read_USB_Device_Buffer(1)<>1 then exit;
if FT_In_Buffer[0]<>$1E then exit; // Trashed packet
Cmd_Buf[0]:=FT_In_Buffer[0];
FT_In_Buffer[0]:=$00;
// 1E i have now to come: 10, 00, TYPE, 00, LEN, in fact, 5 bytes
Cnt:=GetTickCount+TimeOut;
Get_USB_Device_Queuestatus;
while (FT_Q_Bytes<5) do
  begin
    Application.ProcessMessages;
    // check if Time not exceeded.
    if (Cnt-GetTickCount)<=0 then break;
    Get_USB_Device_Queuestatus;
  end;
if (Cnt-GetTickCount)<=0 then exit else if Read_USB_Device_Buffer(5)<>5 then exit;
for i:=1 to 5 do Cmd_Buf[i]:=FT_In_Buffer[i-1];
for i:=0 to 4 do FT_IN_Buffer[i]:=$00;
// how many bytes more to come?
Cnt:=GetTickCount+TimeOut;
Get_USB_Device_Queuestatus;
while (FT_Q_Bytes<Cmd_Buf[5]) do
  begin
  Application.ProcessMessages;  
    // check if Time not exceeded.
    if (Cnt-GetTickCount)<=0 then break;
    Get_USB_Device_Queuestatus;
  end;
if (Cnt-GetTickCount)<=0 then exit else if Read_USB_Device_Buffer(Cmd_Buf[5])<>Cmd_Buf[5] then exit;
for i:=6 to Cmd_Buf[5]+6 do Cmd_Buf[i]:=FT_In_Buffer[i-6];
// Download payload
Cnt:=GetTickCount+TimeOut;
Get_USB_Device_Queuestatus;
if FT_Q_Bytes>0 then if Read_USB_Device_Buffer(FT_Q_Bytes)<>FT_Q_Bytes then exit;
for i:=6+Cmd_Buf[5]+1 to 6+Cmd_Buf[5]+1+FT_Q_Bytes do Cmd_Buf[i]:=FT_In_Buffer[i-(6+Cmd_Buf[5]+1)];
SecondPacketLength:=6+Cmd_Buf[5]+FT_Q_Bytes;
for i:=0 to FT_Q_Bytes do FT_IN_Buffer[i]:=$00;
// Calculate and send CRC
if (SendAck) then
begin
AckPacket[1]:=$00;
AckPacket[2]:=$10;
AckPacket[6]:=Cmd_Buf[3];
//if AckPacket[7]=$07 then AckPacket[7]:=$00 else AckPacket[7]:=AckPacket[7]+1;
AckPacket[7]:=(Seq+1)-$40;
// Calculate ack packet crc
crcBuf:='';
for i:=0 to 7 do crcBuf:=crcBuf+IntToHex(AckPacket[i], 2);
CalculatedCRC:=Fbus_CRC(crcBuf);
AckPacket[8]:=HexToInt(CalculatedCRC[1]+CalculatedCRC[2]);
AckPacket[9]:=HexToInt(CalculatedCRC[3]+CalculatedCRC[4]);
for i:=0 to 9 do FT_Out_Buffer[i]:=AckPacket[i];
// Send ack packet
if Write_USB_Device_Buffer(10)<>10 then exit;
end;

// When all ok, clear buffers
if (Purge_USB_Device_IN <> FT_OK) then exit;
if (Purge_USB_Device_OUT <> FT_OK) then exit;

// Notify peer process that all is ok
Result:=SecondPacketLength;
end;

function SendFBusFrame(var FrameBuf:array of byte; CheckAck: boolean; SendAck: boolean):boolean;
var n,len:integer;
    tstr:string;
    CRC:word;
    // UFSx only
    RxBuf: array[0..$FFFF] of byte;
    i: integer;
begin
Application.ProcessMessages;
   result:=false;

   len := FrameBuf[4]*$100 + FrameBuf[5];

   len:=(len+1) AND $FFFFFFFE;   {Round UP}

   len:=len+2+6;

  {--- Update Frames counter ------}

  FR_CNT1:=(FR_CNT1 AND $07) OR $40;

  if ((FrameBuf[len-3]<=$50) OR (len<=$0A)) then
     begin
        if FrameBuf[3]<>$7F then
           if len>$0A then
             if Mode12A4<>0 then
                 begin
                    if (FrameBuf[5] AND 1)=1 then
                         FrameBuf[len-4]:=FR_CNT1
                       else
                         FrameBuf[len-3]:=FR_CNT1;

                    FR_CNT1:=((FR_CNT1+1) AND $07) OR $40;


                 end;
     end
     else
     begin
       FR_CNT1:=FrameBuf[len-3]+1;
     end;

  {- Calculate frame CRC -}

   CRC:=0;
   for n:=0 to ((len-2) DIV 2)-1  do
      CRC:=CRC XOR ( (FrameBuf[n*2]*$100)+FrameBuf[n*2+1] );

   FrameBuf[len-2]:=(CRC DIV $100) AND $FF;
   FrameBuf[len-1]:=CRC AND $FF;

  {---------------------------------}



  for n:=0 to len-1 do FT_Out_Buffer[n]:=FrameBuf[n];
  ///form1._msg('TXbuf: '+buftohexstr(@FT_Out_Buffer[0], len));
  n:=Suck_FBUS(Fbus_Timeout, @FT_OUT_BUFFER, len, @cmd_buf, CheckAck, SendAck);
  if (n > 0) and (n<255) then
    begin
      for i:=0 to n do RxFrBuf[i]:=Cmd_Buf[i];
      Result:=True
    end;

end;



function SendFrameAndSendAck(Frame: array of byte; IFrameLen: integer; MekeSeq: Boolean; CheckAck: Boolean; SendAck: Boolean): integer;
var
  CurrentBuffer: array [0..$8000] of byte;
  FrameLen, FrameLenTmp: integer;
  i,n: integer;
  rdd: integer;
  Retry: integer;
  EndframePointer: integer;
  MaxRetry: integer;
  DebugBuf: string;
  TID: longword;
Label
  Start, StartUFSx;
begin
Application.ProcessMessages;


MaxRetry:=8;
Result:=0;
Retry:=1;
// SEND FRAME :: DETECT PHONE
for i:=0 to $8000 do RxFrBuf[i]:=$00;
for i:=0 to IFrameLen do TxFrBuf[i]:=Frame[i];
for i:=0 to $8000 do FrameInside[i]:=$00;
// Check ack is make Seq
if (MekeSeq) then
  begin
    IFrameLen:=IFrameLen+1;
    TxFrBuf[IFrameLen]:=MakeSeq; // Make sequentional number
  end;

StartUFSx:

 if Retry>1 then
  begin
  if (NFB_Send55str)=FALSE then
  begin
  form1._msg('UFS 0x55 error');
  exit;
  end;
  end;


  if (SendFBUSFrame(TxFrBuf, CheckAck, SendAck))=FALSE then
  begin
    Retry:=Retry+1;
    if Retry>=MaxRetry then
      begin
      form1._msg('UFS ack error');
      exit;
      end else
        begin
          sleep(2000);
        goto StartUFSx;
        end;
    end;

    FrameLen:=RxFrBuf[5];
    for i:=6 to FrameLen+6 do FrameInside[i-6]:=RxFrBuf[i];
    Result:=Framelen-2;

end;


function BArmInterface():boolean;
var
  retry, i: integer;
  InterfaceArmed: boolean;
  c_buf: string;
label
  dummy_sn_retry;
begin
    USBClosePort;
    form1._msg('Searching Devices... ');
    GetFTDeviceCount;
    form1._msg(IntToStr(FT_Device_Count)+' devices found.');
    if FT_Device_Count<1 then exit;
    u_id:=0;
    retry:=1;
    dummy_sn_retry:
    GetFTDeviceDescription(u_id);
    u_id_reprezentation:=FT_Device_String;
    GetFTDeviceSerialNo(u_id);
    u_sn:=FT_Device_String;
   Application.ProcessMessages;
    if (u_sn = '') or (MatchesMask(u_id_reprezentation, '*UFS*') = false) then
      begin
        if (FT_Device_Count) > 0 then
          begin
            if FT_Device_Count=Retry then
              begin
               form1._msg('UFS not found. Try to reconnect it');
               exit;
              end;
            for i:=retry+1 to FT_Device_Count do
              begin
                retry:=i;
                u_id:=i-1;
                goto dummy_sn_retry;
              end;
          end;
        end
        else u_g_sn:=inttostr(strtoint(u_sn)*1); // fix the 000* sn
        form1._msg('Booting UFS #'+u_g_sn);
        if (ufx_boot(u_sn)) then
  begin
  Application.ProcessMessages;

  ///4C 4D 54 31 39 06 EF
  //2A

  //4C 1D 1D 1F 02 0D 98
  //3E

  //41

  //58 =>5A
  //32 =>72
        FT_Out_Buffer[0]:=$56;
        ufs_cmd(100,@ft_out_buffer,1,@cmd_buf,$20);
        c_buf:='';
        for i:=0 to 31 do c_buf:=c_buf+Chr(cmd_buf[i]);
        if(MatchesMask(c_buf, 'UFxBoot V?.? (c) SarasSoft 200?.')=FALSE) then
          begin
            form1._msg('UFSBoot is damaged!');
            Close_USB_Device;
            exit;
          end;
        form1._msg(c_buf);
        Application.ProcessMessages;
        FT_Out_Buffer[0]:=$41;
        ufs_cmd(100,@ft_out_buffer,1,@cmd_buf,$20);
        c_buf:='';
        for i:=0 to 31 do c_buf:=c_buf+chr(cmd_buf[i]);
        if(MatchesMask(c_buf, 'UFS_USB V2.? (c) SarasSoft 200?.')=FALSE) then
          begin
            form1._msg('UFS Firmware is damaged!');
            Close_USB_Device;
            exit;
          end;
        form1._msg(c_buf);
        if (ufx_sw_fbus(u_sn,'FBUS')) then
          begin
            Seq:=$40;

            for i:=0 to 20 do
            begin
            Sleep(50);
            Application.ProcessMessages;
            end;
          end;

  Application.ProcessMessages;
  end;
  form1._msg('');
end;


function GetPMFieldLength(Field: integer):Integer;
var
  Frame_GetPMFieldLength:array[0..$C] of byte;
  n,i: integer;
  Str_Field: string;
begin
Result:=0;
Str_Field:=IntToHex(Field, 4);
// Build frame
Frame_GetPMFieldLength[$0]:=$1E; // fbus header
Frame_GetPMFieldLength[$1]:=$00; // destination - phone
Frame_GetPMFieldLength[$2]:=$10; // source - PC
Frame_GetPMFieldLength[$3]:=$23; // Msg TYPE
Frame_GetPMFieldLength[$4]:=$00; // msg len 0x00
Frame_GetPMFieldLength[$5]:=$08; // msg len 0x01
Frame_GetPMFieldLength[$6]:=$00; // payload 7bytes
Frame_GetPMFieldLength[$7]:=$0D;
Frame_GetPMFieldLength[$8]:=$C2;
Frame_GetPMFieldLength[$9]:=$0E;
Frame_GetPMFieldLength[$A]:=HexToInt(Str_Field[1]+Str_Field[2]); // Field_1
Frame_GetPMFieldLength[$B]:=HexToInt(Str_Field[3]+Str_Field[4]); // Field_2
Frame_GetPMFieldLength[$C]:=$01; // overhead not included
n:=SendFrameAndSendAck(Frame_GetPMFieldLength, $C, True, True, True);
Result:=FrameInside[n-1];
end;

function PMWriteCurrentKey(Field: integer;Key:integer;KeyLength: integer): integer;
var
Frame_WritePM:array[0..$8000] of byte;
n,i,j,k,z: integer;
HowManyPackets, OverAllPackets: integer;
CurrentPacket: integer;
SectorSize: integer;
tmp: string;
ProceedWithAck: Boolean;
OverheadpacketsDone, OverHeadPacketsLeft: integer;
ConvBuf: String;
CurrWriteSectorSize: integer;
begin
Result:=0;
// Build Frame
Frame_WritePM[0]:=$1E;//header
Frame_WritePM[1]:=$00;//src
Frame_WritePM[2]:=$10;//dst
Frame_WritePM[3]:=$23;//msgtype
// [4] length
// [5] length
// Current payload
Frame_WritePM[6]:=$00;
Frame_WritePM[7]:=$08;
Frame_WritePM[8]:=$01;
Frame_WritePM[9]:=$02;
ConvBuf:=IntToHex(Field, 4);
Frame_WritePM[10]:=HexToInt(ConvBuf[1]+ConvBuf[2]);
Frame_WritePM[11]:=HexToInt(ConvBuf[3]+ConvBuf[4]);
ConvBuf:=IntToHex(Key, 4);
Frame_WritePM[12]:=HexToInt(ConvBuf[1]+ConvBuf[2]);
Frame_WritePM[13]:=HexToInt(ConvBuf[3]+ConvBuf[4]);
Frame_WritePM[14]:=00;
Frame_WritePM[15]:=00;
Frame_WritePM[16]:=00;
// 17 PM Data Length - 1
// 18 PM Data Length - 2
// 19 PM Data Length - 3

CurrWriteSectorSize:=96;

if KeyLength<=CurrWriteSectorSize then
  begin
    Frame_WritePM[4]:=(KeyLength+16) div $100;
    Frame_WritePM[5]:=(KeyLength+16) mod $100;
    Frame_WritePM[17]:=$00;
    Frame_WritePM[18]:=KeyLength div $100;
    Frame_WritePM[19]:=KeyLength mod $100;
    for i:=0 to KeyLength-1 do
      begin
        Frame_WritePM[20+i]:=PMWrBuffer[i];
      end;
    Frame_WritePM[20+KeyLength]:=$01;
    n:=SendFrameAndSendAck(Frame_WritePM, 20+KeyLength, True, True, True);
    if FrameInside[5]=$01 then
      begin
        Result:=KeyLength;
      end else Result:=0;
  end
  else
  begin
  // First Sector size is ALWAYS 106 bytes, cause PM_PACKET_TYPE must be MAX 0x7A , so 106+overhead > 7A
  SectorSize:=CurrWriteSectorSize;
  // 106 + 0xFE * 120 (max_sector_size) = 30586
  if KeyLength>$FFA0 then exit;
  // Here we need to count how many packets will be sent to phone. Algo is
  // simple. Keylength-106(cause first packet)
  HowManyPackets:=((KeyLength-CurrWriteSectorSize) div CurrWriteSectorSize)+3; /// or +3.. have no idea, need to test with FBUS olso
  // Multi-Packet Flag
  Frame_WritePM[8]:=$02;
  CurrentPacket:=1;
  OverAllPackets:=HowManyPackets;
  // Send first packet
  Frame_WritePM[4]:=(SectorSize+16) div $100;
  Frame_WritePM[5]:=(SectorSize+16) mod $100; //Result shoudl be 7A!
  Frame_WritePM[17]:=00;
  Frame_WritePM[18]:=KeyLength div $100;
  Frame_WritePM[19]:=KeyLength mod $100;
  for i:=0 to SectorSize-1 do
    begin
    Frame_WritePM[20+i]:=PMWrBuffer[i];
    end;
  Frame_WritePM[20+SectorSize]:=OverAllPackets;
  // Send first packet
  n:=SendFrameAndSendAck(Frame_WritePM, 20+SectorSize, True, False, False);

  SectorSize:=CurrWriteSectorSize; //Switching to BIG_MODE
  // One packet sent
  HowManyPackets:=HowManyPackets-2;
  CurrentPacket:=CurrentPacket+1;
  OverHeadPacketsDone:=0;
  OverHeadPacketsLeft:=HowManyPackets;
  for i:=1 to HowManyPackets do
    begin

      if i=HowManyPackets then
        begin
          SectorSize:= (KeyLength-CurrWriteSectorSize) - (((KeyLength-CurrWriteSectorSize) div CurrWriteSectorSize) * CurrWriteSectorSize);
          ProceedWithAck:=True;
        end else SectorSize:=CurrWriteSectorSize;

      Frame_WritePM[4]:=(SectorSize+2) div $100;
      Frame_WritePM[5]:=(SectorSize+2) mod $100;

      z:=0;

      for j:=CurrWriteSectorSize+(  (i-1)*CurrWriteSectorSize  ) to (CurrWriteSectorSize+(  (i-1)*CurrWriteSectorSize  ))+(SectorSize-1) do
        begin
        // Fill buffer with data
          Frame_WritePM[6 + z]:=PMWrBuffer[j];
          z:=z+1;
        end;

      Frame_WritePM[6+SectorSize]:=OverHeadPacketsLeft;
      Frame_WritePM[7+SectorSize]:=MakeSeq-$40;

      SendFrameAndSendAck(Frame_WritePM, 5+SectorSize+1+1, False, ProceedWithAck, ProceedWithAck);

      OverHeadPacketsLeft:=OverHeadPacketsLeft-1;
      OverHeadPacketsDone:=OverHeadPacketsDone+1;
    end;

    if FrameInside[5]=$01 then
      begin
        Result:=KeyLength;
      end else Result:=0;

  end;
end;


function GetPMKeyLength(Field:integer;Key:integer):Integer;
var
  Frame_GetPMKey:array[0..$10] of byte;
  n,i: integer;
  KeyLength: integer;
  Str_Field: String;
  Str_Key: String;
begin
Result:=0;
Str_Field:=IntToHex(Field, 4);
Str_Key:=IntToHex(Key, 4);
Frame_GetPMKey[$0]:=$1E;
Frame_GetPMKey[$1]:=$00;
Frame_GetPMKey[$2]:=$10;
Frame_GetPMKey[$3]:=$23;
Frame_GetPMKey[$4]:=$00;
Frame_GetPMKey[$5]:=$0C;
Frame_GetPMKey[$6]:=$00;
Frame_GetPMKey[$7]:=$0D;
Frame_GetPMKey[$8]:=$0F;
Frame_GetPMKey[$9]:=$0C;
Frame_GetPMKey[$A]:=HexToInt(Str_Field[1]+Str_Field[2]);
Frame_GetPMKey[$B]:=HexToInt(Str_Field[3]+Str_Field[4]);
Frame_GetPMKey[$C]:=HexToInt(Str_Key[1]+Str_Key[2]);
Frame_GetPMKey[$D]:=HexToInt(Str_Key[3]+Str_Key[4]);
Frame_GetPMKey[$E]:=$00;
Frame_GetPMKey[$F]:=$00;
Frame_GetPMKey[$10]:=$01;
n:=SendFrameAndSendAck(Frame_GetPMKey, $10, True, True, True);
if n=0 then exit;
if FrameInside[5]=$00 then KeyLength:=0;
if FrameInside[5]=$01 then
  begin
    KeyLength:=HexToInt(IntToHex(FrameInside[n-3], 2)+IntToHex(FrameInside[n-2], 2)+IntToHex(FrameInside[n-1], 2));
    if KeyLength=0 then KeyLength:=$FFFFFF;
  end;
Result:=KeyLength;
end;

function PMReadCurrentKey(Field: integer;Key: Integer;KeyLength: Integer):Integer;
var
  Frame_GetPMContent: array[0..24] of byte;
  i,n,j: integer;
  CurrentSector: integer;
  SectorLength: integer;
  PMCount: integer;
  CurrentBuffer: array[0..$8000] of byte;
  ExtractedPMSize: integer;
  ConvBuf: string;
  MaxGauge,CurrGauge: integer;
  Str_Field: String;
  Str_Key: String;
  OldStatus: String;
  MaxKeyLen: word;
begin
Result:=0;
PMCount:=0;
Str_Field:=IntToHex(Field, 4);
Str_Key:=IntToHex(Key, 4);
MaxKeyLen:=$64;
if KeyLength>MaxKeyLen then
begin
//OldStatus:=Form1.NStatus.Panels.Items[0].Text;
end;
for i:=0 to (KeyLength div MaxKeyLen) do // Sector size is $64
  begin
    if KeyLength>MaxKeyLen then
      begin
        //Form1.NStatus.Panels.Items[0].Text:='Reading Long PM Field '+IntToStr(Field)+', Key '+IntToStr(Key)+', Len '+IntTOStr(KeyLength)+' bytes, Readen Sectors: '+IntToStr(i)+'/'+IntToStr((KeyLength div $64));
      end;
    CurrentSector:=i*MaxKeyLen;
    if i=(KeyLength div MaxKeyLen) then SectorLength:=(KeyLength mod MaxKeyLen) else SectorLength:=MaxKeyLen; // if overhead is detected
    Frame_GetPMContent[0]:=$1E;
    Frame_GetPMContent[1]:=$00;
    Frame_GetPMContent[2]:=$10;
    Frame_GetPMContent[3]:=$23;
    Frame_GetPMContent[4]:=$00;
    Frame_GetPMContent[5]:=$14;
    Frame_GetPMContent[6]:=$00;
    Frame_GetPMContent[7]:=$0D;
    Frame_GetPMContent[8]:=$10;
    Frame_GetPMContent[9]:=$04;
    Frame_GetPMContent[10]:=HexToInt(Str_Field[1]+Str_Field[2]);
    Frame_GetPMContent[11]:=HexToInt(Str_Field[3]+Str_Field[4]);
    Frame_GetPMContent[12]:=HexToInt(Str_Key[1]+Str_Key[2]);
    Frame_GetPMContent[13]:=HexToInt(Str_Key[3]+Str_Key[4]);
    Frame_GetPMContent[14]:=$00;
    Frame_GetPMContent[15]:=$00;
    Frame_GetPMContent[16]:=$00;
    ConvBuf:=IntToHex(CurrentSector, 6);
    Frame_GetPMContent[17]:=HexToInt(ConvBuf[1]+ConvBuf[2]);
    Frame_GetPMContent[18]:=HexToInt(ConvBuf[3]+ConvBuf[4]);
    Frame_GetPMContent[19]:=HexToInt(ConvBuf[5]+ConvBuf[6]);
    Frame_GetPMContent[20]:=$00;
    Frame_GetPMContent[21]:=$00;
    Frame_GetPMContent[22]:=SectorLength div $100;
    Frame_GetPMContent[23]:=SectorLength mod $100;
    Frame_GetPMContent[24]:=$01;
    n:=SendFrameAndSendAck(Frame_GetPMContent, 24, True, True, True);
    if n=0 then exit;
    if n<SectorLength+5 then exit;
    if FrameInside[0]<>Frame_GetPMContent[7] then exit;
    ExtractedPMSize:=(FrameInside[16] * $100) + FrameInside[17];
    if ExtractedPMSize<>SectorLength then exit;
    for j:=PMCount to PMCount+(ExtractedPMSize-1) do PMData[j]:=FrameInside[18+(j-PMCount)];
    // we have so it located into CurrentBuffer what then ?
    PMCount:=PMCount+SectorLength;
  end;
if KeyLength>MaxKeyLen then
begin
//Form1.NStatus.Panels.Items[0].Text:=OldStatus;
end;
Result:=PMCount-1;
end;

function readData():boolean;
const
  Frame_GetOTPIMEI:array[0..$E] of byte =
    ($1E,$00,$10,$1B,$00,$0A,$00,$01,$01,$00,$41,$00,$00,$00,$01);
  Frame_DetectPPM:array[0..$C] of byte =
    ($1E,$00,$10,$1B,$00,$08,$00,$03,$1F,$07,$01,$00,$01);
  Frame_GetCodeCount:array[0..$B] of byte =
    ($1E,$00,$10,$53,$00,$07,$00,$08,$00,$12,$0D,$01);
  Frame_BB5_GetCP:array[0..$10] of byte =
    ($1e, $00, $10, $1b, $00, $0c, $00, $06, $06, $07, $00, $00, $00, $00, $04, $00, $01);
  Frame_BB5_GetAPESW:array[0..$10] of byte =
    ($1e, $00, $10, $1b, $00, $0c, $00, $06, $06, $07, $00, $00, $00, $00, $00, $02, $01);
  Frame_BB5_GetAPEVA:array[0..$10] of byte =
    ($1e, $00, $10, $1b, $00, $0c, $00, $06, $06, $07, $00, $00, $00, $00, $00, $04, $01);
  Frame_DetectPhone:array[0..$B] of byte =
      ($1E,$00,$10,$D1,$00,$07,$00,$01,$00,$03,$00,$01);
var
  n, i, x, j: integer;
  buf: string;
  DelimiterPos, PointerBuf: integer;
  PPM, Tmp: String;
begin
Product:='';
SWVersion:='';
SWDate:='';
Manufacturer:='';
SwitchBoxMode('FBUS');
if (NFB_Send55str)=FALSE then
  begin
  form1._msg('0x55 Reset Error');
  exit;
  end;

n:=SendFrameAndSendAck(Fphonename, Length(fphonename), True, True, True);
if n=0 then
  begin
  form1._msg('Phone not found');
  exit;
  end;

Form1._msg('Name : '+hex2chr(BufToHexStr(@FrameInside[10], FrameInside[9])));

n:=SendFrameAndSendAck(Frame_DetectPhone, $B, True, True, True);
if n=0 then
  begin
  form1._msg('Phone not found');
  exit;
  end;

for i:=0 to n-1 do
  begin
    if (FrameInside[i]>$0F) or (FrameInside[i]=$0A) then if FrameInside[i]=$0A then McuSW_Buf:=McuSW_BUf+', ' else McuSW_Buf:=McuSW_Buf+Chr(FrameInside[i]);
  end;

// Scan all stuff in McuSW buf
for i:=1 to StrLen(PChar(McuSW_Buf)) do
  begin
    if McuSW_Buf[i]=',' then
      begin
        PointerBuf:=i;
        break;
      end;
    SWVersion:=SWVersion+McuSW_Buf[i];
  end;

for i:=PointerBuf+2 to StrLen(PChar(McuSW_Buf)) do
  begin
    if McuSW_Buf[i]=',' then
      begin
        PointerBuf:=i;
        break;
      end;
    SWDate:=SWDate+McuSW_Buf[i];
  end;

for i:=PointerBuf+2 to StrLen(PChar(McuSW_Buf)) do
  begin
    if McuSW_Buf[i]=',' then
      begin
        PointerBuf:=i;
        break;
      end;
    Product:=Product+McuSW_Buf[i];
  end;

for i:=PointerBuf+2 to StrLen(PChar(McuSW_Buf)) do
  begin
    if McuSW_Buf[i]=',' then
      begin
        PointerBuf:=i;
        break;
      end;
    Manufacturer:=Manufacturer+McuSW_Buf[i];
  end;

// OK we have all needed info, lets roll!

form1._msg('SWver : '+Product+' , '+SWVersion+' , '+SWDate+' , '+Manufacturer);

n:=SendFrameAndSendAck(Frame_GetOTPIMEI, $E, True, True, True);
if n=0 then
  begin
    form1._msg('Extended info, Get OTP IMEI, Transmit error, aborting');
    exit;
  end;
Buf:='';
for i:=1 to FrameInside[9]-1 do Buf:=Buf+Chr(FrameInside[9+i]);
form1._msg('IMEI : '+BUF);

n:=SendFrameAndSendAck(Frame_DetectPPM, $C, True, True, True);
if n=0 then
  begin
    form1._msg('Extended info, PPM Info, Transmit error, aborting');
    exit;
  end;

for i:=0 to n do
  begin
    Buf:=Buf+Chr(FrameInside[i]);
  end;
i:=StrLen(PChar(Buf));
repeat
  i:=i-1;
until Buf[i]=',';
DelimiterPos:=i;
for i:=DelimiterPos+2 to StrLen(PChar(Buf)) do PPM:=PPM+Buf[i];
x:=0;
for i:=1 to StrLen(PChar(PPM)) do
  begin
  if PPM[i]='.' then x:=i;
  end;
Buf:='';
if x<>0 then
  begin
  for i:=x+1 to StrLen(PChar(PPM)) do
    begin
      buf:=buf+PPM[i];
    end;
  PPM:=Buf;
  end;
form1._msg('PPM Variant : '+PPM);

n:=SendFrameAndSendAck(Frame_BB5_GetCP, $10, True, True, True);
if n=0 then
  begin
    form1._msg('Extended info, Get CP, Transmit error, aborting');
    exit;
  end;
Buf:='';
for i:=1 to FrameInside[9]-1 do
  begin
    if FrameInside[9+i]=$0A then Buf:=Buf+', ' else Buf:=Buf+Chr(FrameInside[9+i]);
  end;
if Buf<>'' then
  begin
  Tmp:='';
  j:=0;
  for i:=1 to StrLen(pChar(Buf))-2 do
    begin
      if j=50 then
        begin
          form1._msg('CNT Version : '+Tmp);
          Tmp:='';
          j:=0;
        end
        else
        begin
          j:=j+1;
          Tmp:=Tmp+Buf[i];
          if i=StrLen(pChar(Buf)) then j:=50;
        end;
    end;
  end;

n:=SendFrameAndSendAck(Frame_BB5_GetAPESW, $10, True, True, True);
if n=0 then
  begin
    form1._msg('Extended info, Get APESW, Transmit error, aborting');
    exit;
  end;
Buf:='';
for i:=1 to FrameInside[9]-1 do
  begin
    if FrameInside[9+i]=$0A then Buf:=Buf+', ' else Buf:=Buf+Chr(FrameInside[9+i]);
  end;
if Buf<>'' then form1._msg('APE Core : '+BUF);

n:=SendFrameAndSendAck(Frame_BB5_GetAPEVA, $10, True, True, True);
if n=0 then
  begin
    form1._msg('Extended info, Get APEVA, Transmit error, aborting');
    exit;
  end;
Buf:='';
for i:=1 to FrameInside[9]-1 do
  begin
    if FrameInside[9+i]=$0A then Buf:=Buf+', ' else Buf:=Buf+Chr(FrameInside[9+i]);
  end;
if Buf<>'' then form1._msg('APE Variant : '+BUF);

n:=SendFrameAndSendAck(Frame_GetCodeCount, $B, True, True, True);
if n=0 then
  begin
    form1._msg('Extended info, Get Simlock_Code_Count, Transmit error, aborting');
    exit;
  end;
Buf:='';
form1._msg('SL Key Count : '+IntToStr(FrameInside[29] mod $10)+'/'+IntToStr(FrameInside[29] div $10));
Buf:='';
n:=GetPMFieldLength(4);
if n>=(4 div 2) then // 0 is key position
  begin
    n:=GetPMKeyLength(4, 4);
    if n>=7 then
      begin
        n:=PMReadCurrentKey(4, 4, n);
        for i:=0 to n do Buf:=Buf+Chr(PMData[i]);
        form1._msg('Product Code : '+Buf);
      end;
  end;

n:=GetPMFieldLength(120);
if n>1 then
  begin
   form1._msg('New Security BB5 Phone');
  end;

end;

function ChecCMTData():boolean;
begin
Application.ProcessMessages;
//Move(pCmd^, FT_OUT_BUFFER, CmdLen);
FillMemory(@FT_IN_BUFFER,$FFFF, $00);
FT_OUT_BUFFER[0]:=$6E;
FT_OUT_BUFFER[1]:=$1F;
if Write_USB_Device_Buffer(2)<>2 then exit;
Form1._msg('BootData : '+BufToHexStr(@FT_IN_BUFFER[0], $62));

end;

procedure FetchBootData;
var
     Key, KeyLen      : Byte;
     PacketLen        : Byte;
     BlockCount       : Byte;
     CurrBlock        : Byte;
     CurrBlockLen     : Word;
     i,j,k,l,m        : integer;
     ape              : Byte;
begin
     apeexist:=false;
     FASICape:='';
     FASICcmt:='';
     Application.ProcessMessages;
     FillMemory(@RAPInfo.APEASICID,$4,$00);
     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.ROM_ID,$8,$00);
     Application.ProcessMessages;
     PacketLen  :=cmd_buf[1];
     BlockCount :=cmd_buf[3];
     FLbyte:=cmd_buf[Packetlen+2];
     i:=4;
     j:=0;
     m:=0;
     form1._msg('');
     form1._msg('1st boot Ok, '+byte2str(cmd_buf[2]));
     while (i<PacketLen) and (j<BlockCount) do
     begin
          Application.ProcessMessages;
          CurrBlock    :=cmd_buf[i];
          inc(i);
          CurrBlockLen :=(cmd_buf[i]);
          inc(i);
          case CurrBlock of
          $01://RAP SYSTEM ASIC ID
              //5800 - 000000010000022600010006400C192101031103 [RAPIDO3G ver: 1.x]
              begin
                ape:=cmd_buf[i];
                inc(i);
                   case ape of
                   $01:
                   Begin
                   Form1._msg('');
                   Form1._msg('APE part info : ');
                   Application.ProcessMessages;
                    for k:=0 to CurrBlockLen do RAPInfo.APEASICID[k]:= cmd_buf[i+k];
                   Form1._msg('APE ASICID   : '+ BufToHexStr(@RAPInfo.APEASICID[0],    Length(RAPInfo.APEASICID)));
                   inc(i, CurrBlockLen-1);
                   FASICape:=BufToHexStr(@RAPInfo.APEASICID[0],    Length(RAPInfo.APEASICID));
                   inc(j);
                   apeexist:=True;
                   Application.ProcessMessages;
                   end;
                   $00:
                   Begin
                   Form1._msg('');
                   Form1._msg('CMT part info : ');
                   Application.ProcessMessages;
                   for k:=0 to CurrBlockLen do RAPInfo.SYSTEM_ASIC_ID[k]:= cmd_buf[i+k];
                   FASICcmt:=Copy(BufToHexStr(@RAPInfo.SYSTEM_ASIC_ID[12], 8),1,16);
                   Form1._msg('CMT ASICID   : '+ BufToHexStr(@RAPInfo.SYSTEM_ASIC_ID[0],    Length(RAPInfo.SYSTEM_ASIC_ID)));
                   inc(i, CurrBlockLen-1);
                   inc(j);
                   Application.ProcessMessages;
                   end;
                end;
              end;
          $02://RAP EMx ID
              //00000295
              //00000B22
             begin
                ape:=FT_IN_BUFFER[i];
                inc(i);
                case ape of
                $01:
                Begin
                   for k:=0 to CurrBlockLen do RAPInfo.EMx_ID[k]:= cmd_buf[i+k];
                   Form1._msg('APE EM'+inttostr(m)+' ID  : '+ BufToHexStr(@RAPInfo.EMx_ID[0],    4));
                   inc(i, CurrBlockLen-1);
                   inc(j);inc(m);
                   Application.ProcessMessages;
                end;
                $00:
                Begin
                   for k:=0 to CurrBlockLen do RAPInfo.EMx_ID[k]:= cmd_buf[i+k];
                   Form1._msg('CMT EM'+inttostr(m)+' ID  : '+ BufToHexStr(@RAPInfo.EMx_ID[0],    4));
                   inc(i, CurrBlockLen-1);
                   inc(j);inc(m);
                   Application.ProcessMessages;
                end;
              end;
             end;
          $12://PUBLIC_ID
              //1FF0001841158B52064E64D3C3E9A7F38DC47E29
            begin
                ape:=FT_IN_BUFFER[i];
                inc(i);
                case ape of
                $01:
                begin
                   for k:=0 to CurrBlockLen do RAPInfo.PUBLIC_ID[k]:= cmd_buf[i+k];
                   Form1._msg('APE PUB ID    : '+ BufToHexStr(@RAPInfo.PUBLIC_ID[0],    Length(RAPInfo.PUBLIC_ID)));
                   inc(i, CurrBlockLen-1);
                   inc(j);
                   Application.ProcessMessages;
                end;
                $00:
                Begin
                     for k:=0 to CurrBlockLen do RAPInfo.PUBLIC_ID[k]:= cmd_buf[i+k];
                   Form1._msg('CMT PUB ID  : '+ BufToHexStr(@RAPInfo.PUBLIC_ID[0],    Length(RAPInfo.PUBLIC_ID)));
                   inc(i, CurrBlockLen-1);
                   inc(j);
                   Application.ProcessMessages;
                end;
              end;
            end;
           $13://ASIC_MODE
              //00
              begin
                 ape:=FT_IN_BUFFER[i];
                 inc(i);
                 case ape of
                 $01:
                 Begin
                   RAPInfo.ASIC_MODE:= cmd_buf[i];
                   Form1._msg('APE MODE ID : '+ BufToHexStr(@RAPInfo.ASIC_MODE,    1));
                   inc(i, CurrBlockLen-1);
                   inc(j);
                   Application.ProcessMessages;
                 end;
                 $00:
                 Begin
                   RAPInfo.ASIC_MODE:= cmd_buf[i];
                   Form1._msg('CMT MODE ID : '+ BufToHexStr(@RAPInfo.ASIC_MODE,    1));
                   inc(i, CurrBlockLen-1);
                   inc(j);
                   Application.ProcessMessages;
                   end;
                end;
              end;
          $14://ROOT_KEY_HASH
              //CAEEBB65D3C48E6DC73B49DC5063A2EE
              begin
                 ape:=cmd_buf[i];
                 inc(i);
                 case ape of
                 $01:
                 Begin
                 for k:=0 to CurrBlockLen-1 do RAPInfo.APErootkey[k]:= cmd_buf[i+k];
                 inc(i, CurrBlockLen-1);
                 inc(j);
                 Form1._msg('APE R_HASH  : '+ BufToHexStr(@RAPInfo.APErootkey[0], Length(RAPInfo.ROOT_KEY_HASH)));
                 Application.ProcessMessages;
                 end;
                 $00:
                 Begin
                 for k:=0 to CurrBlockLen-1 do RAPInfo.ROOT_KEY_HASH[k]:= cmd_buf[i+k];
                 inc(i, CurrBlockLen-1);
                 inc(j);
                 Form1._msg('CMT R_HASH  : '+ BufToHexStr(@RAPInfo.ROOT_KEY_HASH[0], Length(RAPInfo.ROOT_KEY_HASH)));
                 ROOTKEY:=BufToHexStr(@RAPInfo.ROOT_KEY_HASH[0], Length(RAPInfo.ROOT_KEY_HASH));
                 Application.ProcessMessages;
                 end;
               end;
              end;
          $15://ROM_ID
              //4B9B75103E691FF8
              begin
                   ape:=cmd_buf[i];
                   inc(i);
                   case ape of
                   $01:
                   begin
                   for k:=0 to CurrBlockLen-1 do RAPInfo.ROM_ID[k]:= cmd_buf[i+k];
                   Form1._msg('APE ROM ID  : '+ BufToHexStr(@RAPInfo.ROM_ID[0],    Length(RAPInfo.ROM_ID)));
                   inc(i, CurrBlockLen-1);
                   inc(j);
                   Application.ProcessMessages;
                   end;
                   $00:
                   begin
                   for k:=0 to CurrBlockLen-1 do RAPInfo.ROM_ID[k]:= cmd_buf[i+k];
                   Form1._msg('CMT ROM ID  : '+ BufToHexStr(@RAPInfo.ROM_ID[0],    Length(RAPInfo.ROM_ID)));
                   inc(i, CurrBlockLen-1);
                   inc(j);
                   Application.ProcessMessages;
                   end;
                 end;
                end;
              else
              begin
                   inc(i, CurrBlockLen);
                   inc(j);
              end;
          end;//End Of Case
     end;
     form1._msg('');
end;

function replyverify():Boolean;
begin
  result:=false;
 ufsfl_cmd(150,@Verifyreply[0],6,@cmd_buf,2);
 if cmd_buf[0]>$F0 then
 result:=True;
end;

function replyverify2():Boolean;
begin
  result:=false;
 ufsfl_cmd(50,@Verifyreply[0],6,@cmd_buf,2);
 if cmd_buf[0]>$F0  then Exit;
 result:=True;
end;

function replyverify3():byte;
begin
 ufsfl_cmd(50,@Verifyreply[0],6,@cmd_buf,2);
 Result:=cmd_buf[0];
end;

function CheckVpp():Boolean;
var
  vpp, dual : string;
begin
  result:=false;
 {if not write_frame(@vppchk[0], Length(vppchk)) then Exit;
 if not read_frame(2,1000) then exit; }
 ufsfl_cmd(1500,@vppchk[0],2,@cmd_buf,2);
 if cmd_buf[0]<>$3F then vpp:='False' else vpp:='True';
 if cmd_buf[1]<>$3F then dual:='False' else dual:='True';
 //form1._msg('IGNITION : VPP : '+vpp+' , DUAL : '+dual);
  result:=True;
end;

function GetReadLen():Byte;
begin
  result:=$00;
  readDataReq[5]:=$02;
  ufsfl_cmd(150,@readDataReq[0],Length(readDataReq),@cmd_buf,4);
  result:=cmd_buf[1];
  readDataReq[5]:=$00;
end;

function ReadDatarequest(bytes:byte):Boolean;
var
  len:integer;
begin
  result:=false;
  readDataReq[5]:=bytes;
  len:=hexToInt(Byte2Str(bytes))+2;
  ufsfl_cmd(150,@readDataReq[0],Length(readDataReq),@cmd_buf,len);
  result:=true;
  readDataReq[5]:=$00;
end;


function Freaddata(bytes:byte):Boolean;
var
  len:integer;
begin
  result:=false;
  readrDta[5]:=bytes;
  len:=hexToInt(Byte2Str(bytes))+2;
  ufs_cmd(150,@readrdta[0],Length(readrdta),@cmd_buf,len);
   result:=true;
end;

function Freadflashic ():boolean;
var
  FLasic, asfltype, s : string;
begin
  flven:=0;
  Cfltype:=$00;
  FLtype:='';
  asfltype:='';
  case cmd_buf[0] of
  $00 : FLasic :='CMT';
  $01 : FLasic :='APE';
  else FLasic:='Unknow';
  end;
  case cmd_buf[1] of
  $00 :
  begin
  FLtype :='NOR';
  CFltype:=$00;
  end;
  $01 :
  begin
  AsFLtype :='NAND';
  Afltype:=$01;
  end;
  $03 :
  begin
  FLtype :='NAND';
  Cfltype:=$03;
  end;
  $04 :
  begin
  FLtype :='MMC , EXT';
  Cfltype:=$04;
  end;
  else fltype:='Unknow';
  end;
  flven:=dword((@cmd_buf[3])^);
  //DWordSwap(@flven);
  reversedword(@flven);
  case FT_In_Buffer[0] of
  1:
   begin
   Form1._msg('FLASHID : '+IntToHex(flven,8)+' , '+FLasic+' , NAND');
   ReadFlashIc(0,flven);
   end;
  0:
   begin
   Form1._msg('FLASHID : '+IntToHex(flven,8)+' , '+FLasic+' , '+ fltype);
   ReadFlashIc(flven,0);
   end;
  end;
  if Flven<>$0000FFFF then
  begin
  result:=True;
  flicven:=flven;
  end;
end;

function SendRaw(Asic:integer; Loader:string) : integer;
var
  rawloader,
  rawblock  : TMemoryStream;
  b         : Boolean;
  chk       : word;
  tmp       : array of Byte;
  i         : integer;
  flblk     : integer;
  lb        : Byte;
  blkcnt,cblk,cblklen : Byte;
  flcnt     : string;
begin
  result:=9;
  algo:='';
  case asic of
  $00:
  Begin
     Form1.statusbar.Panels[0].Text:='UFS : CMT 2ND boot...';
     Form1._msg('CMT : Sending 2nd loader...');
     Application.ProcessMessages;
     RAWblock:=TMemoryStream.Create;
     rawblock.LoadFromFile(loader);
     form1._msg('Use : '+extractfilename(Loader));
     rawblock.Seek(0,soFromBeginning);
     RAWloader:=TMemoryStream.Create;
     BB5_ExtractRAWLoader(RAWBlock, RAWLoader, b);
     rawloader.Seek(0,soFromBeginning);
     SetLength(tmp, rawloader.Size);
      if rawloader.size=0 then exit;
     result:=8; // RAwloader prepare error
     //form1._msg('STbyte :'+byte2str(flbyte));
     if FLbyte>$F0 then begin
      ufs_cmd(50,@prerawcheck[0],3,@cmd_buf,1);
      //Form1._msg('Set Data ['+Byte2Str(ft_in_buffer[0])+']');
      //form1._msg('Set Data ['+Byte2Str(replyverify3)+']');
      end;
   rawloader.ReadBuffer(tmp[0], rawloader.Size);
   RawLen[6]:=rawloader.Size  mod $100;
   RawLen[5]:=rawloader.Size  div $100;
   result:=7; // PrebootCheck error - raw len no accepted
   ufs_cmd(70,@Rawlen[0],7,@cmd_buf,2);
   //Form1._msg('Set data ['+byte2str(FT_In_Buffer[0])+']');
   if cmd_buf[1]<>$72 then Exit;
    Application.ProcessMessages;
    FT_Out_Buffer[0]:=$69;
    FT_Out_Buffer[1]:=$02;
    FT_Out_Buffer[2]:=$0A;
    FT_Out_Buffer[3]:=$00;
    FT_Out_Buffer[5]:=rawloader.Size  mod $100;
    FT_Out_Buffer[4]:=rawloader.Size  div $100;
    FT_Out_Buffer[6]:=$00;
    FT_Out_Buffer[7]:=$00;
    Application.ProcessMessages;
    for i:=0 to rawloader.size+7 do FT_Out_Buffer[i+8]:=TMP[i];
    ufs_cmd(600,@FT_out_buffer,(rawloader.Size+8),@cmd_buf,7);
    result:=6; // rawloader not accepted by phone
    if cmd_buf[0]<>$00 then exit;
    if cmd_buf[6]<>$72 then exit;
  Application.ProcessMessages;
  Form1._msg('CMT Loader sent, Boot Ok');
  Form1._msg('MCU Configuration');
  Form1.statusbar.Panels[0].Text:='UFS : 2ND Boot Ok, wait...';
    case apeexist of
    true  : ufs_cmd(75,@APEcrc[0],16,@cmd_buf,11);
    false : ufs_cmd(75,@CMTcrc[0],16,@cmd_buf,11);
    end;
   result:=5; // Fetch data fail
   blkcnt:=Ft_in_buffer[1];
   cblk:=ft_in_buffer[2];
   cblklen:=ft_in_buffer[3];

   if cblklen=0 then Exit;
            for i:=0 to blkcnt-1 do
            begin
             case cblk of
               $10:
               begin
               FreadData(cblklen+2); // Flash ID descriptor
               //form1._msg(buftohexstr(@Ft_in_buffer[0],cblklen+2));
               Freadflashic;
               cblk:=ft_in_buffer[cblklen];
               cblklen:=ft_in_buffer[cblklen+1];
               if cblklen=0 then Break;
               end;
               $15:
               begin
               FreadData(cblklen+4); // FLCNT ( flash content )
               //form1._msg(buftohexstr(@Ft_in_buffer[0],cblklen+4));
               flcnt:='';
               flcnt:=buftohexstr(@Ft_in_buffer[0],19);
               form1._msg('FLCNT   : '+flcnt);
               cblk:=ft_in_buffer[cblklen+2];
               cblklen:=ft_in_buffer[cblklen+3];
               if cblklen=0 then Break;
               end;
               $35:
               begin
               FreadData(cblklen+2);
               //form1._msg(buftohexstr(@Ft_in_buffer[0],cblklen+2));
               algo:=Hex2Chr(BufToHexStr(@Ft_in_buffer[1], cblklen-2));
               form1._msg('ReqAlgo : CMT , '+algo);
               cblk:=ft_in_buffer[cblklen];
               cblklen:=ft_in_buffer[cblklen+1];
               end;
               $11:
               begin
               FreadData(cblklen+2); // FLCNT ( flash content )
               flcnt:='';
               //form1._msg(buftohexstr(@Ft_in_buffer[0],cblklen+2));
               flcnt:=buftohexstr(@Ft_in_buffer[0],19);
               form1._msg('FLCNT   : '+flcnt);
               cblk:=ft_in_buffer[cblklen];
               cblklen:=ft_in_buffer[cblklen+1];
               if cblklen=0 then Break;
               end
               else
               begin
               Form1._msg('ERR : UNK : '+Byte2Str(cblk));
               FreadData(cblklen+2);
               //Form1._msg(BufToHexStr(@ft_in_buffer[0],cblklen+4));
               end;
             end;
            end;

  {case flblk of
   $01 :
   begin
    Application.ProcessMessages;
    if not FreadData($0D) then Exit;   //CMTMCID
    Form1._msg('FLMCID : '+buftohexstr(@cmd_buf[3],8));
    Application.ProcessMessages;
   end;
   $03 :
   begin
    Application.ProcessMessages;
    if not FreadData($0D) then Exit;
    Freadflashic(0); // check flash ic
      case flven of
      $89820089 : FbusSloader:=StartDir+'Flash\UFS\RAP3Gv3_algo_v1331.fg';
      else Application.ProcessMessages;
      end;
    Application.ProcessMessages;
    if not FreadData($15) then Exit;
    Form1._msg('FLCNT  : '+buftohexstr(@cmd_buf[3],16));
    Application.ProcessMessages;
    if not FreadData($0D) then Exit;   //CMTMCID
    Form1._msg('FLMCID : '+buftohexstr(@cmd_buf[3],8));
    Application.ProcessMessages;
   end;
   $04 :
   begin
    Application.ProcessMessages;
    if not FreadData($0D) then Exit;
    Freadflashic(0); // check flash ic
    Application.ProcessMessages;
    if not FreadData($0D) then Exit;
    Freadflashic(0); // check flash ic
    Application.ProcessMessages;
    if not FreadData($15) then Exit;
    Form1._msg('FLCNT  : '+buftohexstr(@cmd_buf[3],16));
    Application.ProcessMessages;
    if not FreadData($0D) then Exit;   //CMTMCID
    Form1._msg('FLMCID : '+buftohexstr(@cmd_buf[3],8));
    Application.ProcessMessages;
   end;
   $05 :
   begin
    Application.ProcessMessages;
    if not FreadData($0D) then Exit;
    Freadflashic(0); // check flash ic
    if not FreadData($0D) then Exit;
    Freadflashic(0);
    if not FreadData($11) then Exit;
    algo:=Hex2Chr(BufTohexStr(@cmd_buf[1],$10));
    Form1._msg('ALG : '+algo);
    Application.ProcessMessages;
    if not FreadData($15) then Exit;
    Form1._msg('FLCNT  : '+buftohexstr(@cmd_buf[0],16));
    Application.ProcessMessages;
    if not FreadData($0D) then Exit;   //CMTMCID
    Form1._msg('FLMCID : '+buftohexstr(@cmd_buf[3],8));
    Application.ProcessMessages;
    end;
    else begin form1._msg('Sorry, cant'+#39+'t proceed ['+inttostr(flblk)+']'); exit; end;
   end; }
  end;
 $01 :
    begin
     result:=8;
     Form1._msg('');
     Application.processMessages;
      if not replyverify then form1._msg('ready ['+buftohexstr(@ft_in_buffer[0],4)+']');
     Application.ProcessMessages;
      if not replyverify then form1._msg('ready ['+buftohexstr(@ft_in_buffer[0],4)+']');
     Application.ProcessMessages;
     Form1.statusbar.Panels[0].Text:='UFS : APE 2ND boot...';
     Form1._msg('APE : Sending 2nd loader...');
     Application.ProcessMessages;
     RAWblock:=TMemoryStream.Create;
     rawblock.LoadFromFile(loader);
     form1._msg('Use : '+extractfilename(Loader));
     rawblock.Seek(0,soFromBeginning);
     RAWloader:=TMemoryStream.Create;
     BB5_ExtractAPERAWLoader(RAWBlock, RAWLoader, b);
     rawloader.Seek(0,soFromBeginning);
     SetLength(tmp, rawloader.Size);
     rawloader.ReadBuffer(tmp[0], rawloader.Size);
     result:=8;
      if rawloader.size=0 then Exit;
      Application.ProcessMessages;
      FT_Out_Buffer[0]:=$65;
      FT_Out_Buffer[1]:=$00;
      FT_Out_Buffer[2]:=$08;
      FT_Out_Buffer[3]:=$09;
      FT_Out_Buffer[4]:=$00;
      FT_Out_Buffer[5]:=rawloader.Size  div $100;
      FT_Out_Buffer[6]:=rawloader.Size  mod $100;
      FT_Out_Buffer[7]:=$00;
      FT_Out_Buffer[8]:=$00;
      FT_Out_Buffer[9]:=$5B;
      FT_Out_Buffer[10]:=$01;
      FT_Out_Buffer[11]:=$24;
      FT_Out_Buffer[12]:=$04;
      FT_Out_Buffer[13]:=$00;
      FT_Out_Buffer[14]:=$00;
      FT_Out_Buffer[15]:=rawloader.Size  div $100;
      FT_Out_Buffer[16]:=rawloader.Size  mod $100;
      FT_Out_Buffer[17]:=framecrc(@ft_out_buffer[10],7);
      Application.ProcessMessages;
      for i:=0 to rawloader.size+17 do FT_Out_Buffer[i+18]:=TMP[i];
      ufs_cmd(700,@FT_out_buffer,(rawloader.Size+18),@cmd_buf,7);
      result:=6;
      if cmd_buf[0]<>$00 then exit;
      if cmd_buf[1]<>$10 then form1._msg('Payload message : '+byte2str(ft_in_buffer[1]));
      if cmd_buf[5]<$F0 then form1._msg('Payload message : '+byte2str(ft_in_buffer[5]));
      if cmd_buf[6]<>$72 then exit;
      Application.ProcessMessages;
      Form1._msg('APE Loader sent, Boot Ok');
      if not replyverify  then form1._msg('ready ['+buftohexstr(@ft_in_buffer[0],4)+']');
      result:=6;
      // Boot sent, need collect flash info now and check some stuff
      Application.processMessages;
      Form1.statusbar.Panels[0].Text:='UFS : Running APE...';
      Application.processMessages;
      if not replyverify then form1._msg('ready ['+buftohexstr(@ft_in_buffer[0],4)+']');
     Application.ProcessMessages;
      ufs_cmd(70,@apePredta,6,@cmd_buf,3);
      Application.ProcessMessages;
      if not replyverify2 then form1._msg('repl2 ['+buftohexstr(@ft_in_buffer[0],4)+']');
      ufs_cmd(70,@apePredta,6,@cmd_buf,3);
      Application.ProcessMessages;
     if not replyverify then form1._msg('ready ['+buftohexstr(@ft_in_buffer[0],4)+']');
     Application.ProcessMessages;
      ufs_cmd(70,@aperun,16,@cmd_buf,9);
      Application.ProcessMessages;
      flblk:=cmd_buf[1];
      case flblk of
       $02 :
       begin
       lb:=GetReadLen;
       ReadDatarequest(lb);
       Freadflashic(); // check flash ic
       Application.ProcessMessages;
       lb:=GetReadLen;
       ReadDatarequest(lb);
       form1._msg('FLCNT : '+buftohexstr(@cmd_buf[2], lb-4));
       Application.ProcessMessages;
       lb:=GetReadLen;
       ReadDatarequest(lb);
       end;
       $03 :
       begin
       lb:=GetReadLen;
       ReadDatarequest(lb);
       Freadflashic(); // check flash ic
       Application.ProcessMessages;
       lb:=GetReadLen;
       ReadDatarequest(lb);
       algo:='';
       for i:=1 to lb-3 do if cmd_buf[i]<>$00 then algo:=algo+chr(cmd_buf[i]);
       Form1._msg('ALGO : '+algo);
       Application.ProcessMessages;
       lb:=GetReadLen;
       ReadDatarequest(lb);
       form1._msg('FLMCID : '+buftohexstr(@cmd_buf[2], lb-4));
       Application.ProcessMessages;
       lb:=GetReadLen;
       ReadDatarequest(lb);
       end
       else begin form1._msg('Sorry, cant'+#39+'t proceed ['+inttostr(flblk)+']'); exit; end;
      end;
      Application.ProcessMessages;
      result:=5;
      if not replyverify then form1._msg('ready ['+buftohexstr(@ft_in_buffer[0],4)+']');
      Application.ProcessMessages;
      if not replyverify then form1._msg('ready ['+buftohexstr(@ft_in_buffer[0],4)+']');
      Application.ProcessMessages;
    end;

 end;
 result:=0;
end;

Function SendAlgorihtm(Asic : integer; algo : string):integer;
var
  rawloader,rawblock  : TMemoryStream;
  b                   : Boolean;
  chk                 : word;
  tmp                 : array of Byte;
  ostlen,packets,i2,i : integer;
  currpacketsize      : integer;
begin
  result:=9;
case Asic of
$00: begin
Form1.statusbar.Panels[0].Text:='UFS : Send CMT algo, wait...';
ufsfl_cmd(300,@Checkalgo[0], Length(checkalgo),@cmd_buf, 14);
if ft_in_buffer[0]<>$C3 then exit;
if ft_in_buffer[12]<$F0 then form1._msg('reply '+byte2str(ft_in_buffer[12]));
if ft_in_buffer[13]<>$72 then exit;
Application.ProcessMessages;
result:=8;
if not replyverify then form1._msg('prepare for algo send ['+buftohexstr(@ft_in_buffer[0],4)+']');
Application.ProcessMessages;
if not replyverify then form1._msg('prepare for algo send ['+buftohexstr(@ft_in_buffer[0],4)+']');
Application.ProcessMessages;
form1._msg('Sending ALGO....');
result:=7;
RAWblock:=TMemoryStream.Create;
rawblock.LoadFromFile(algo);
form1._msg('Use : '+extractfilename(algo));
rawblock.Seek(0,soFromBeginning);
RAWloader:=TMemoryStream.Create;
BB5_ExtractRAWLoader(RAWBlock, RAWLoader, b);
rawloader.Seek(0,soFromBeginning);
SetLength(tmp, rawloader.Size);
Rawloader.Readbuffer(tmp[0], rawloader.size);
FT_Out_Buffer[0]:=$69;
FT_Out_Buffer[1]:=$02;
FT_Out_Buffer[2]:=$0A;
FT_Out_Buffer[3]:=rawloader.Size  div $10000;
FT_Out_Buffer[4]:=rawloader.Size  div $100;
FT_Out_Buffer[5]:=(rawloader.Size  mod $100)+4;
FT_Out_Buffer[6]:=$00;
FT_Out_Buffer[7]:=$00;
FT_Out_Buffer[8]:=$00;
FT_Out_Buffer[9]:=rawloader.Size  div $10000;
FT_Out_Buffer[10]:=rawloader.Size  div $100;
FT_Out_Buffer[11]:=rawloader.Size  mod $100;
 if rawloader.size>$FFF4 then begin
  for i:=0 to $FFF4-1 do FT_Out_Buffer[i+12]:=TMP[i];
  ufsfl_cmd(800,@FT_out_buffer,$10000,@cmd_buf,0);
  ostlen:=rawloader.size-$FFF4;
  packets:=ostlen div $10000;
  if ostlen mod $10000>0 then inc(packets);
  rawloader.Seek(0,soFromBeginning);
  SetLength(tmp, rawloader.Size);
  Rawloader.Readbuffer(tmp[0], $FFF4);
  currpacketsize:=$10000;
  Application.ProcessMessages;
  for i2:=0 to packets-1 do
  begin
   Application.ProcessMessages;
                    if (i2=Packets-1) and (Packets>1) then
                    begin
                         if (ostlen mod $10000)>0 then CurrPacketSize:=(ostLen mod $10000) else CurrPacketSize:=$10000;
                    end;
   Rawloader.Readbuffer(tmp[0], currpacketsize);
   for i:=0 to currpacketsize-1 do FT_Out_Buffer[i]:=TMP[i];
   if currpacketsize<$10000 then ufs_cmd(800,@FT_out_buffer,currpacketsize,@cmd_buf,7) else
   ufsfl_cmd(800,@FT_out_buffer,currpacketsize,@cmd_buf,0);
   Application.ProcessMessages;
   //Form1._msg('Packet : '+inttostr(packets)+' Len : '+inttostr(currpacketsize));
  end;
 end;
 if cmd_buf[0]<>$00 then exit;
 if cmd_buf[1]<>$00 then exit;
 if cmd_buf[4]<>$00 then exit;
 if cmd_buf[5]<$F0 then form1._msg('Payload msg : '+byte2str((FT_In_Buffer[5])));
 if cmd_buf[6]<>$72 then exit;
 result:=6;
 Application.ProcessMessages;
 Form1._msg('CMT Algo sent');
 ufsfl_cmd(150,@asicch[0],length(asicch),@cmd_buf,11);
 if cmd_buf[0]<>$C5 then Exit;
 case cmd_buf[1] of
  0: form1._msg('PAPUBkeys blank (erased or HW failure)');
  1:
  begin
  Application.ProcessMessages;
  if not FreadData($17) then Exit;
  form1._msg('CMT PAPUB : ' +buftohexstr(@cmd_buf[2],$15));
  end
  else Form1._msg('Can'+#39+'t proceed ['+byte2str(ft_in_buffer[1])+']');
 end;
 ufsfl_cmd(100,@asicunk[0],length(asicunk),@cmd_buf,7);
 Application.ProcessMessages;
 if not replyverify then form1._msg('reply ['+buftohexstr(@ft_in_buffer[0],4)+']');
 checkvpp;
 result:=0;
 Form1.statusbar.Panels[0].Text:='';
end;
$01:
 begin
  Form1.statusbar.Panels[0].Text:='UFS : Send APE algo, wait...';
  Application.ProcessMessages;
  form1._msg('Sending ALGO....');
  RAWblock:=TMemoryStream.Create;
  rawblock.LoadFromFile(algo);
  form1._msg('Use : '+extractfilename(algo));
  rawblock.Seek(0,soFromBeginning);
  RAWloader:=TMemoryStream.Create;
  BB5_ExtractAPERAWLoader(RAWBlock, RAWLoader, b);
  rawloader.Seek(0,soFromBeginning);
  SetLength(tmp, rawloader.Size);
  Rawloader.Readbuffer(tmp[0], rawloader.size);
  Application.ProcessMessages;
      FT_Out_Buffer[0]:=$65;
      FT_Out_Buffer[1]:=$00;
      FT_Out_Buffer[2]:=$08;
      FT_Out_Buffer[3]:=$09;
      FT_Out_Buffer[4]:=rawloader.Size  div $10000;
      FT_Out_Buffer[5]:=rawloader.Size  div $100;
      FT_Out_Buffer[6]:=rawloader.Size  mod $100;
      FT_Out_Buffer[7]:=$00;
      FT_Out_Buffer[8]:=$00;
      FT_Out_Buffer[9]:=$5B;
      FT_Out_Buffer[10]:=$01;
      FT_Out_Buffer[11]:=$25;
      FT_Out_Buffer[12]:=$04;
      FT_Out_Buffer[13]:=$00;
      FT_Out_Buffer[14]:=rawloader.Size  div $10000;
      FT_Out_Buffer[15]:=rawloader.Size  div $100;
      FT_Out_Buffer[16]:=rawloader.Size  mod $100;
      FT_Out_Buffer[17]:=framecrc(@ft_out_buffer[10],7);
      Application.ProcessMessages;
  if rawloader.size>$FFEE then begin
  for i:=0 to $FFEE-1 do FT_Out_Buffer[i+18]:=TMP[i];
  ufsfl_cmd(1200,@FT_out_buffer,$10000,@cmd_buf,0);
  ostlen:=rawloader.size-$FFEE;
  packets:=ostlen div $10000;
  if ostlen mod $10000>0 then inc(packets);
  rawloader.Seek(0,soFromBeginning);
  SetLength(tmp, rawloader.Size);
  Rawloader.Readbuffer(tmp[0], $FFEE);
  currpacketsize:=$10000;
  Application.ProcessMessages;
  for i2:=0 to packets-1 do
  begin
   Application.ProcessMessages;
   if packets-1=0 then CurrPacketSize:=(ostLen mod $10000);
                    if (i2=Packets-1) and (Packets>1) then
                    begin
                         if (ostlen mod $10000)>0 then CurrPacketSize:=(ostLen mod $10000) else CurrPacketSize:=$10000;
                    end;
   Rawloader.Readbuffer(tmp[0], currpacketsize);
   for i:=0 to currpacketsize-1 do FT_Out_Buffer[i]:=TMP[i];
   if currpacketsize<$10000 then ufs_cmd(1200,@FT_out_buffer,currpacketsize,@cmd_buf,7) else
   ufsfl_cmd(1200,@FT_out_buffer,currpacketsize,@cmd_buf,0);
   Application.ProcessMessages;
   end;
  end
  else
  begin
  for i:=0 to Rawloader.size-1 do FT_Out_Buffer[i+18]:=TMP[i];
  ufsfl_cmd(1200,@FT_out_buffer,Rawloader.size+18,@cmd_buf,7);
  end;
 if cmd_buf[0]<>$00 then exit;
 //if ft_in_buffer[1]<>$00 then form1._msg('Fur     msg : '+byte2str((FT_In_Buffer[1])));
 if cmd_buf[4]<>$00 then form1._msg('Fur     msg : '+byte2str((FT_In_Buffer[4])));
 if cmd_buf[5]<$F0 then form1._msg('Payload msg : '+byte2str((FT_In_Buffer[5])));
 if cmd_buf[6]<>$72 then exit;
 Application.ProcessMessages;
 Form1._msg('APE Algo sent');
 ufsfl_cmd(500,@asicunk[0],length(asicunk),@cmd_buf,11);
 if not replyverify then form1._msg('['+buftohexstr(@ft_in_buffer[0],4)+']');
 Application.ProcessMessages;
 CheckVpp;
 getapepapub;
 Form1.statusbar.Panels[0].Text:='UFS : Boot Done';
 end;
end;
 result:=0;
end;

function getapepapub():Boolean;
begin
 Application.ProcessMessages;
 ufsfl_cmd(500,@apepapub[0], Length(apepapub),@cmd_buf,11);
  if cmd_buf[0]<>$C5 then
  begin
  form1._msg('RX : '+buftohexstr(@ft_in_buffer[0],10));
  Exit;
  end;
  case FT_In_Buffer[1] of
  0: form1._msg('PAPUBkeys blank (erased or HW failure)');
  1:
  begin
  Application.ProcessMessages;
  if not FreadData($17) then Exit;
  form1._msg('APE PAPUB : ' +buftohexstr(@cmd_buf[2],$15));
  end
  else Form1._msg('Can'+#39+'t proceed ['+byte2str(cmd_buf[1])+']');
  end;
 PreCertreq;
 if not replyverify then form1._msg('['+buftohexstr(@ft_in_buffer[0],4)+']');
 Application.ProcessMessages;
 result:=True;
end;

function ReadCert(ASIC : Byte ; CERT : string):string;
var
  i,rwal : Integer;
  chkb   : Byte;
  b      : Boolean;
  data,sd: string;
  cbyte  : byte;
  blkcnt : Integer;
  certsize : integer;
begin
   data:='';
   certsize:=0;
   if not  phoneready(5) then
   begin
   form1._msg('Error while prepare, can'+#39+'t read certificate... :(');
   result:='';
   Exit;
   end;
  for i:=12 to 25 do readCertReq[i]:=$00;
  Form1.statusbar.Panels[0].Text:='UFS : Read '+CERT+' cert';
  Form1.pb1.Progress:=0;
  case ASIC of
  $00: // CMT
   begin
   Form1._msg('CMT : Read '+CERT+' certificate...');
   for i:=0 to Length(CERT) do readCertReq[i+12]:=Ord(CERT[i+1]);
   readCertReq[24]:=$00;
   readCertReq[25]:=frameCrc(@readCertReq[9], 16);
   ufs_cmd(1000,@readcertreq[0],Length(readCertReq),@cmd_buf,9);
   //Form1._msg('PrecertReq : '+buftohexstr(@Ft_in_buffer[0],9));
   if (cmd_buf[7]<$B0) and (cmd_buf[8]<>$72) then begin result:=''; Exit; end;
   blkcnt:=cmd_buf[1];
   Form1.pb1.MaxValue:=blkcnt;
   //Form1._msg('BlkCNT : '+inttostr(blkcnt));
   Application.ProcessMessages;
   if blkcnt=0 then result:='';
     repeat
     readDataReq[5]:=$02;
     ufs_cmd(1000,@readdatareq[0], Length(readdataReq),@cmd_buf,4);
     chkb:=cmd_buf[1];
     cbyte:=cmd_buf[0];
     //Form1._msg(Byte2Str(chkb)+byte2str(cbyte));
     if (chkb>0) and (cbyte=$2C) then begin
     Application.ProcessMessages;
     readDataReq[5]:=chkb;
     certsize:=certsize+chkb;
     ufs_cmd(1000,@readdatareq[0], Length(readdataReq),@cmd_buf,chkb);
     data:=data+BufToHexStr(@cmd_buf[0], chkb);
     b:=True;
     end
     else b:=False;
     Application.ProcessMessages;
     Form1.pb1.Progress:=Form1.pb1.Progress+1;
     Application.ProcessMessages;
     until b=false;
    form1._msg('Cert size : '+inttostr(certsize)+' byte(s)');
    replyend;
    if Length(data)>80 then result:=data else result:='';
   end;
  $01: // APE
   begin
   Form1._msg('APE : Read '+CERT+' certificate...');
   for i:=0 to Length(CERT) do readCertReq[i+12]:=Ord(CERT[i+1]);
   readCertReq[24]:=$01;
   readCertReq[25]:=frameCrc(@readCertReq[9], 16);
   ufs_cmd(1000,@readcertreq[0],Length(readCertReq),@cmd_buf,9);
   //Form1._msg('PrecertReq : '+buftohexstr(@Ft_in_buffer[0],9));
   if (cmd_buf[7]<$B0) and (cmd_buf[8]<>$72) then begin result:=''; Exit; end;
   blkcnt:=cmd_buf[1];
   Form1.pb1.MaxValue:=blkcnt;
   //Form1._msg('BlkCNT : '+inttostr(blkcnt));
   Application.ProcessMessages;
   if blkcnt=0 then result:='';
     repeat
     readDataReq[5]:=$02;
     ufs_cmd(1000,@readdatareq[0], Length(readdataReq),@cmd_buf,4);
     chkb:=cmd_buf[1];
     cbyte:=cmd_buf[0];
     //Form1._msg(Byte2Str(chkb)+byte2str(cbyte));
     if (chkb>0) and (cbyte=$2C) then begin
     Application.ProcessMessages;
     readDataReq[5]:=chkb;
     certsize:=certsize+chkb;
     ufs_cmd(1000,@readdatareq[0], Length(readdataReq),@cmd_buf,chkb);
     data:=data+BufToHexStr(@cmd_buf[0], chkb);
     b:=True;
     end
     else b:=False;
     Application.ProcessMessages;
     Form1.pb1.Progress:=Form1.pb1.Progress+1;
     Application.ProcessMessages;
     until b=false;
    form1._msg('Cert size : '+inttostr(certsize)+' byte(s)');
    replyend;
    if Length(data)>80 then result:=data else result:='';
   end;
  end;
  Form1.statusbar.Panels[0].Text:='';
  Form1.pb1.MaxValue:=100;
  Form1.pb1.progress:=0;
end;

function replyend():Boolean;
begin
  result:=false;
  Verifyreply[2]:=$14;
  if replyverify then result:=True;
  Verifyreply[2]:=$40;
end;

function PreCertreq():Boolean;
begin
 result:=false;
 ufsfl_cmd(120, @Precert[0], Length(Precert), @cmd_buf, 14);
 //form1._msg('PreDta : '+buftohexstr(@FT_in_buffer[0],14));
 //C3 01 20 01 04 D9 00 00 00 00 00 00 B1 72
 if cmd_buf[0]=$C3 then
 begin
  if (cmd_buf[3]=$01) and (cmd_buf[4]=$04) then form1._msg('Transmission mode :  Dual (Ddr, TX2) ')
  else form1._msg('Transmission mode :  16 bit ( Single) ');
  result:=true;
 end
 else result:=false;
 Application.ProcessMessages;
end;

function incheck(bytes:Integer):Boolean;
var
  i,i2:integer;
begin
result:=False;
i2:=0;
for i:=1 to bytes do if FT_In_Buffer[i-1]=$00 then i2:=i2+1;
if i2=bytes then Result:=True;
end;

function phoneready(retry:Integer):Boolean;
var
  i:integer;
begin
if not replyverify then
begin
i:=0;
repeat
Application.ProcessMessages;
Inc(i);
Sleep(20);
Application.ProcessMessages;
until (replyverify) or (i=retry);
if i<>retry then result:=True else Result:=false;
end
else result:=true;
end;

Function FlashPrepare (flimage:string):Boolean;
begin
 // prepare data here Storecert and trans-proto check

  if not phoneready(20) then
  begin
  result:=false;
  form1._msg('Error while prepare , transrequest error');
  Exit;
  end;

// CertStore request
 ufsfl_cmd(500,@storecert[0], Length(storecert),@cmd_buf,7);
 if (ft_in_Buffer[0]<>$00) or (ft_in_Buffer[1]<>$00)  then
 begin
 result:=false;
 form1._msg('Error while prepare : CertStore error');
 form1._msg('ERR : '+buftohexstr(@ft_in_buffer[0], 7));
 Exit;
 end;

 if not phoneready(20) then
 begin
 result:=false;
 form1._msg('Error while prepare : transrequest error');
 form1._msg('ERR : '+buftohexstr(@ft_in_buffer[0], 3));
 Exit;
 end;

 if not UFSPartitioning(flimage) then
 begin
  Form1._msg('Error on Flash Prepare : Partitioning error!');
  exit;
 end;

 if not PreCertreq then exit;

 if not ConFigureAsic($00) then form1._msg('CMT CFG not done');
 if apeexist then  if not ConFigureAsic($01) then form1._msg('APE CFG not done');
 result:=True;
end;

function ConFigureAsic(ASIC:Byte):Boolean;
begin
  case ASIC of
   $00 : //CMT FUR client
   begin
       ufs_cmd(500,@setfmcuconfig[0], Length(setfmcuconfig),@cmd_buf,7);
       if not AsicComandFur then
       begin
        result:=false;
        form1._msg('Error FUR CMT client, MCU cfg not done');
        form1._msg('ERR : '+buftohexstr(@ft_in_buffer[0], 7));
        Exit;
       end
       else
       begin
       //form1._msg('CMT select Ok');
       furCMT:=$00;
       end;
   end;
   $01 : //APE FUR client
   begin
        ufs_cmd(500,@setfmcuconfigAPE[0], Length(setfmcuconfig),@cmd_buf,7);
       if not AsicComandFur then
       begin
        result:=false;
        form1._msg('Error FUR APE client, MCU cfg not done');
        form1._msg('ERR : '+buftohexstr(@ft_in_buffer[0], 7));
        Exit;
       end
       else
       begin
       //form1._msg('APE select Ok');
       furCMT:=$01;
       end;
   end;
  end;
  result:=True;
end;

function UFSPartitioning(core:string):Boolean;
var
     fs                         : TFileStream;
     buf                        : array[0..$FFFF] of byte;
     n,j,buflen                 : Integer;
     HdrLen                     : Integer;
     HdrPos                     : LongInt;
     CurrSeem                   : Byte;
     CurrSeemLen, CurSeemcount  : Integer;
     ms                         : TMemoryStream;
     loaderlen                  : DWORD;
     erase                      : Boolean;
     framelen                   : DWORD;
     streamlen                  :TMemoryStream;
begin
     Result:=false;
     partition:=false;
     erase:=False;
     //Form1._msg('Erase : Processing '+ExtractFileName(core));
     Application.processmessages;
     Form1.statusbar.Panels[1].text:='';
     Application.ProcessMessages;
     fs:=TFileStream.Create(core,fmOpenRead);
     fs.Seek(0, sofromBeginning);
     fs.Read(buf[0],1);
     if buf[0]<>$B2 then
     begin
          fs.free;
          raise E.Create('Partition : Bad image file');
          Exit;
     end;
     Application.ProcessMessages;
     starttime;
     Application.ProcessMessages;
     fs.ReadBuffer(buf[0], 4);//Äëèíà Flash Header
     HdrLen := HexToInt(IntToHex(buf[0], 2)+IntToHex(buf[1], 2)+IntToHex(buf[2], 2)+IntToHex(buf[3], 2));
     fs.Seek(4,soFromCurrent);
 try
     while fs.Position<(HdrLen) do
     begin
          fs.ReadBuffer(CurrSeem, 1);
           case CurrSeem of
          $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;
          $F3:
              begin
              // Form1._msg('SEEM: F3');
               fs.ReadBuffer(buf[0], 2);
               CurrSeemLen:=(buf[0]*$100)+buf[1];
              // Form1._msg('Dead mode support : True');
               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); // ?????????????
              //form1._msg('SEEM: FA:LEN: '+ inttostr(loaderlen));
              fs.seek(loaderlen-9,sofromcurrent); // ?????? ??????? - ????? ???? ?????? ?????? ?8
              Application.ProcessMessages;
              streamlen.Free;
              end;
          $EE:
           begin
              form1._msg('Partitioning....');
              partition:=True;
              partitionstream:=TmemoryStream.Create;
              fs.ReadBuffer(buf[0], 2);
              CurrSeemLen:=(buf[0]*$100)+buf[1];
              partitionstream.copyFrom(fs,CurrSeemlen);
              partitionstream.Seek(0,soFromBeginning);
              Application.ProcessMessages;
                if partition=True
                then
                begin
                framelen:=CurrSeemLen+10;
                FT_Out_Buffer[0]:=$69;
                FT_Out_Buffer[1]:=$0A;
                FT_Out_Buffer[2]:=$0A;
                FT_Out_Buffer[3]:=$00;
                Word((@FT_Out_Buffer[4])^):=currseemlen+2;
                WordSwap(@FT_out_buffer[4]);
                FT_Out_Buffer[6]:=$00;
                FT_Out_Buffer[7]:=$00;
                FT_Out_Buffer[8]:=$64;
                partitionstream.ReadBuffer(FT_out_buffer[9], CurrSeemLen);
                FT_out_buffer[framelen-1]:=frameCrc(@FT_out_buffer[9],CurrSeemLen);
                 //Form1._msg('txbuf : '+BufToHexStr(@FT_out_buffer[0],framelen));
                 ufs_cmd(8000,@FT_out_buffer[0], framelen,@cmd_buf,7);
                 //Form1._msg('Partition result : '+buftohexstr(@cmd_buf[0],7));
                 if FT_In_Buffer[0]=$00 then form1._msg('Partitioning Ok...') else
                 begin
                 Form1._msg('Partitioning error : '+buftohexstr(@cmd_buf[0],7));
                 form1._msg('Partitioning failed! :(');
                 result:=false;
                 end;
                Application.ProcessMessages;
                partitionstream.free;
                fs.free;
                result:=true;
                Exit;
                end;
           end
           else
           begin
              // Form1._msg('SEEM : '+byte2str(currseem));
               fs.ReadBuffer(buf[0], 1);
               CurrSeemLen:=buf[0];
               fs.readbuffer(buf[0],CurrSeemLen);
               application.ProcessMessages;
           end;
          end;
     end;
     if not partition then result:=true;
     fs.Free;
 except
        on E:Exception do
        begin
             fs.Free;
             Form1._msg('PartitionFile: Error: '+E.Message);
        end;
 end;
Application.ProcessMessages;
end;


function SendRawID(Asic:integer; Loader:string) : integer;
var
  rawloader,
  rawblock  : TMemoryStream;
  b         : Boolean;
  chk       : word;
  tmp       : array of Byte;
  i         : integer;
  flblk     : integer;
  lb        : Byte;
  filename  : string;
  mmc       : System.Text;
  id        : string;
  idstart   : string;
  idint     : integer;
begin
  result:=9;
  algo:='';

     Form1.statusbar.Panels[0].Text:='UFS : CMT 2ND boot...';
     Form1._msg('CMT : Sending 2nd loader...');
     Application.ProcessMessages;
     RAWloader:=TMemoryStream.Create;
     rawloader.LoadFromFile(loader);
     rawloader.Seek(0,soFromBeginning);
     SetLength(tmp, rawloader.Size);
      if rawloader.size=0 then exit;
     result:=8; // RAwloader prepare error
     if FLbyte>$F0 then begin
      ufsfl_cmd(500,@prerawcheck[0],3,@cmd_buf,1);
      //Form1._msg('Set Data ['+Byte2Str(ft_in_buffer[0])+']');
      //form1._msg('Set Data ['+Byte2Str(replyverify3)+']');
      end;
   rawloader.ReadBuffer(tmp[0], rawloader.Size);
   RawLen[6]:=rawloader.Size  mod $100;
   RawLen[5]:=rawloader.Size  div $100;
   result:=7; // PrebootCheck error - raw len no accepted
   ufsfl_cmd(500,@Rawlen[0],7,@cmd_buf,2);
   //Form1._msg('Set data ['+byte2str(FT_In_Buffer[0])+']');
   devbyte:=FT_In_Buffer[0];
   if FT_In_Buffer[1]<>$72 then Exit;
    Application.ProcessMessages;
    FT_Out_Buffer[0]:=$69;
    FT_Out_Buffer[1]:=$02;
    FT_Out_Buffer[2]:=$0A;
    FT_Out_Buffer[3]:=$00;
    FT_Out_Buffer[5]:=rawloader.Size  mod $100;
    FT_Out_Buffer[4]:=rawloader.Size  div $100;
    FT_Out_Buffer[6]:=$00;
    FT_Out_Buffer[7]:=$00;
    Application.ProcessMessages;
    for i:=0 to rawloader.size+7 do FT_Out_Buffer[i+8]:=TMP[i];
    ufs_cmd(3000,@FT_out_buffer,(rawloader.Size+8),@cmd_buf,7);
    result:=6; // rawloader not accepted by phone
    if ft_in_buffer[0]<>$00 then exit;
    //if ft_in_buffer[5]<>$F1 then exit;
    if ft_in_buffer[6]<>$72 then exit;
  Application.ProcessMessages;
  Form1._msg('CMT Loader sent, Boot Ok');
  Form1.statusbar.Panels[0].Text:='UFS : 2ND Boot Ok, wait...';
  rawloader.Free;
   {  RAWloader:=TMemoryStream.Create;
     rawloader.LoadFromFile(bof);
      rawloader.Seek(0,soFromBeginning);
     SetLength(tmp, rawloader.Size);
     rawloader.ReadBuffer(tmp[0], rawloader.Size); }
  Application.ProcessMessages;
    FT_Out_Buffer[0]:=$74;
    FT_Out_Buffer[1]:=$20;
    FT_Out_Buffer[2]:=$00;
    FT_Out_Buffer[3]:=$02;
    FT_Out_Buffer[4]:=$E4;
    case bof of
    1:  for i:=0 to 740+4 do FT_Out_Buffer[i+5]:=BOF1rapv2[i];
    2:  for i:=0 to 740+4 do FT_Out_Buffer[i+5]:=BOF2rapv3[i];
    3:  for i:=0 to 740+4 do FT_Out_Buffer[i+5]:=BOF3Rapido[i];
    end;
    ufsfl_cmd(5000,@FT_out_buffer,(740+5),@cmd_buf,2);
    //rawloader.Free;
    if ft_in_buffer[1]<>$72 then exit;
    Application.ProcessMessages;
    ufsfl_cmd(5000,@flow,Length(flow),@cmd_buf,2);
    Form1.statusbar.Panels[0].Text:='UFS : Exploit Ok, wait...';
    Application.ProcessMessages;
    //Form1._msg('OWF : '+byte2str(ft_in_buffer[0]));
    if ft_in_buffer[1]<>$72 then exit;
     RAWloader:=TMemoryStream.Create;
     rawloader.LoadFromFile(FbusSloader);
      rawloader.Seek(0,soFromBeginning);
     SetLength(tmp, rawloader.Size);
     rawloader.ReadBuffer(tmp[0], rawloader.Size);
     Application.ProcessMessages;
    FT_Out_Buffer[0]:=$74;
    FT_Out_Buffer[1]:=$20;
    FT_Out_Buffer[2]:=$00;
    FT_Out_Buffer[4]:=rawloader.Size  mod $100;
    FT_Out_Buffer[3]:=rawloader.Size  div $100;
    for i:=0 to rawloader.size+4 do FT_Out_Buffer[i+5]:=TMP[i];
    dwordswap(@FT_out_buffer[5]);
    ufsfl_cmd(5000,@FT_out_buffer,(rawloader.Size+5),@cmd_buf,2);
    rawloader.free;
    if ft_in_buffer[1]<>$72 then exit;
    Application.ProcessMessages;
    ufsfl_cmd(5000,@flow,Length(flow),@cmd_buf,2);
    Application.ProcessMessages;
   // Form1._msg('OWF2 : '+byte2str(ft_in_buffer[0]));
    if ft_in_buffer[1]<>$72 then exit;
    Application.ProcessMessages;
    ufsfl_cmd(5000,@overready , 9 ,@cmd_buf,11);
   // Form1._msg('OWF : '+byte2str(ft_in_buffer[9]));
    //if ft_in_buffer[8]<>$72 then exit;
    Application.ProcessMessages;
    ufsfl_cmd(5000,@readdieid , 6 ,@cmd_buf, $40);
    Form1.statusbar.Panels[0].Text:='UFS : Fetching data, wait...';
   id:=buftohexstr(@ft_in_buffer[0],$40);

  UkeyData.PID:=BufToHexStr(@Rapinfo.PUBLIC_ID[0],Length(Rapinfo.PUBLIC_ID));
  UkeyData.Hash:=buftohexstr(@Rapinfo.ROOT_KEY_HASH[0],Length(RAPInfo.ROOT_KEY_HASH));
  idint:=Pos(UkeyData.PID,id);
  idstart:=Copy(id,idint+40,40);
  UkeyData.key:=idstart;

  //form1._msg(id);            // Show Data in log
//  form1._msg('PID : '+UkeyData.PID);
//  form1._msg('HSH : '+UkeyData.Hash);
//  form1._msg('KEY : '+UkeyData.key);

   //id);

 result:=0;
end;


function UFSWriteFileUNI(core:string):Boolean;
const
      maxlen             : dWORD = $4FFFF ;
var
     buf                :array[0..$4FFFF] of byte;
     HdrLen,
     CurrBlockLen       : Cardinal;
     EntryPoint,
     DataLen,
     TargetOffset,
     CRCTmp             : LongInt;
     i, n, Blocks,
     Packets,icl,
     CurrPacketSize,
     TokenHdrLen        : Integer;
     good               : Integer;
     CertName,AsicType  : String;
     PAPUB_Already,
     APE_PAPUB          : boolean;
     fs                 : TFileStream;
     ms                 : TMemoryStream;
     writen,framelen    : Dword;
     cmtcount,cmtdin,
     TokenSubType, unk  : integer;
     nopbyte            : byte;
     nopword            : word;
     ttxbuf             : array[0..$4FFFF] of byte;
     ape,cmt            : Boolean;
     apebyte            : Byte;
     bulkread           : integer;
     ostlen             : DWORD;
     i2                 : integer;
     inslen             : integer;
     fspos              : Integer;

begin
     Result:=False;
     Form1._msg('Write : Processing '+ExtractFileName(core));
     fs:=TFileStream.Create(core,fmOpenRead);
     fs.Seek(0, sofromBeginning);
     Blocks:=0;
     cmtcount:=0; cmtdin:=0;
     unk:=0;
     Form1.pb1.ForeColor:=clGreen;
     Form1.pb1.progress:=0;
     Application.ProcessMessages;
     PAPUB_Already:=False;
     APE_PAPUB:=false;
try
     fs.Read(ttxbuf[0],1);
     if ttxbuf[0]<>$B2 then
     begin
          fs.free;
          raise E.Create('Write : Bad image file');
     end;

     Application.ProcessMessages;
     starttime;
     Application.ProcessMessages;

     fs.ReadBuffer(ttxbuf[0], 4);//Äëèíà Flash-header'a
     HdrLen     := HexToInt(IntToHex(ttxbuf[0], 2)+IntToHex(ttxbuf[1], 2)+
                            IntToHex(ttxbuf[2], 2)+IntToHex(ttxbuf[3], 2));

     fs.Seek(HdrLen, sofromcurrent);//Ê íà÷àëó ïåðâîãî Flash-òîêåíà
     {ms:=TMemoryStream.Create;}
     form1.pb1.maxvalue:=(fs.size-hdrlen);
     form1.statusbar.Panels.Items[0].Text:='Writing...';
     while fs.Position<fs.Size do
     begin
            if stop=True then
            begin
            dostop('WRITE');
            result:=False;
            fs.Free;
            Application.ProcessMessages;
            UFSeblock;
            SwitchBoxMode('FBUS');
            Exit;
            end;
          Application.ProcessMessages;
          fs.ReadBuffer(ttxbuf[8], 1);
          case ttxbuf[8] of
          $54://Flash-token
              begin
                   //form1._msg('CurrPos : ' +inttostr(fs.position));
                   Application.ProcessMessages;
                   //54 0117 0E 000300 4D9C 01 00000400 00000000 E8
                   fs.ReadBuffer(ttxbuf[$09], $3);//×òåíèå çíà÷åíèÿ ïîäòèïà òîêåíà è äëèíû åãî çàãîëîâêà
                   TokenHdrLen:=ttxbuf[$0B];//Äëèíà çàãîëîâêà òîêåíà
                   TokenSubType:=TokenHdrLen;
                   fs.Seek(fs.position-4, sofrombeginning);//ñìåùåíèå íà íà÷àëî òîêåíà
                   inc(TokenHdrLen, 5);//Óâåëè÷èì äëèíó äî îáùåé äëèíû òîêåíà ñ åãî CRC
                   fs.ReadBuffer(ttxbuf[8], TokenHdrLen);//×òåíèå çíà÷åíèé òîêåíà ñ åãî CRC
                   apebyte:=ttxbuf[12];
                   fs.Seek(fs.position-TokenHdrLen, sofrombeginning);//ñìåùåíèå íà íà÷àëî òîêåíà
                   Application.ProcessMessages;
                   //Äëèíà òåêóùåãî áëîêà ìåæäó òîêåíàìè
                   CurrBlockLen := HexToInt(IntToHex(ttxbuf[TokenHdrLen-1], 2)+
                                            IntToHex(ttxbuf[TokenHdrLen],   2)+
                                            IntToHex(ttxbuf[TokenHdrLen+1], 2)+
                                            IntToHex(ttxbuf[TokenHdrLen+2], 2));

                  //Form1._msg('CurrLen : '+inttostr(CurrBlockLen));
                  //fs.ReadBuffer(ttxbuf[0],(tokenhdrlen+currblocklen));
                  Application.ProcessMessages;
                  case apebyte of
                   $00:
                   begin
                    if furCMT<>$00 then
                    begin
                    if ConFigureAsic($00) then furcmt:=$00 else
                     begin
                     form1._msg('CMT select error, impossible continue flashing. Check HW/Cable');
                     result:=false;
                     fs.free;
                     Exit;
                    end;
                    Application.ProcessMessages;
                   end;

                   end;
                   $01:
                   begin
                    if furCMT<>$01 then
                    begin
                    if ConFigureAsic($01) then furcmt:=$01
                    else
                     begin
                     form1._msg('APE select error, impossible continue flashing. Check HW/Cable');
                     result:=false;
                     fs.free;
                     Exit;
                     end;
                    end;
                     Application.ProcessMessages;
                   end;

                  end;
                     application.ProcessMessages;
                     //FillMemory(@cmd_buf[0],9,$00);
                     FT_Out_Buffer[0]:=$65;
                     FT_Out_Buffer[1]:=$00;
                     FT_Out_Buffer[2]:=$0C; //0C
                     FT_Out_Buffer[3]:=TokenSubtype+$05;
                     FT_Out_Buffer[4]:=CurrBlockLen  div $10000;
                     FT_Out_Buffer[5]:=CurrBlockLen  div $100;
                     FT_Out_Buffer[6]:=CurrBlockLen  mod $100;
                     FT_Out_Buffer[7]:=$07;   //07
                     FT_Out_Buffer[8]:=$00;
                     Application.ProcessMessages;
                     currblocklen:=currblocklen+tokenhdrlen;
                     //fspos:=fs.Position;
                      if CurrBlockLen>$FFF7 then begin
                       fs.ReadBuffer(FT_Out_Buffer[9],$fff7);
                       ufsfl_cmd(8000,@FT_out_buffer,$10000,@cmd_buf,0);
                       ostlen:=CurrBlockLen-$FFF7;
                       packets:=ostlen div $10000;
                       if ostlen mod $10000>0 then inc(packets);
                       currpacketsize:=$10000;
                       Application.ProcessMessages;
                       for i2:=0 to packets-1 do
                       begin
                        Application.ProcessMessages;
                                         if (i2=Packets-1) and (Packets>=1) then
                                         begin
                                              if (ostlen mod $10000)>0 then CurrPacketSize:=(ostLen mod $10000) else CurrPacketSize:=$10000;
                                         end;
                        Application.ProcessMessages;
                        //form1._msg(inttostr(ostlen mod $10000));
                        fs.ReadBuffer(FT_Out_Buffer[0],currpacketsize);
                        if currpacketsize<$10000 then ufsfl_cmd(8000,@FT_out_buffer,currpacketsize,@cmd_buf,14) else
                        ufsfl_cmd(8000,@FT_out_buffer,currpacketsize,@cmd_buf,0);
                        Application.ProcessMessages;
                       end;
                      end
                      else
                      begin
                      fs.ReadBuffer(FT_Out_Buffer[9],currblocklen);
                      ufsfl_cmd(8000,@FT_out_buffer,CurrBlockLen+9,@cmd_buf,14);
                      end;
                      //Form1._msg(BufToHexStr(@cmd_buf[0],7));
                     Application.ProcessMessages;
                               if not checkc7 then
                               begin
                                form1._msg('Error write  block at : '+ IntToStr(blocks));
                                form1._msg('ERR : '+buftohexstr(@cmd_buf[0],12));
                                result:=False;
                                fs.Free;
                                Exit;
                               end;
               Application.ProcessMessages;
               inc(blocks);
               case apebyte of
               $00:form1.statusbar.Panels[1].Text:='CMT : '+inttostr(Blocks);
               $01:form1.statusbar.Panels[1].Text:='APE : '+inttostr(Blocks);
               end;
               Application.ProcessMessages;
              end;//End of Case $54

          $5D://Phoenix-segment
              begin
                   //5D 0127 2D 25B977A055BE9B5DEC0C38A2A279C695 8594B99841444100000000000000000000030077E7 00000400 000A0800 BB
                   //       Len          RootKey Hash                                                         Len     Flash   CRC
                   //5D 0128 43 25B977A055BE9B5DEC0C38A2A279C695 8594B99850415055424B4559530000000003 00A70900 00060000 11F000397DCE210733C335E84BAD369EC893FCA06D1BC3 0100 A5
                   //       Len          RootKey Hash                                                    Len     Flash                                                      CRC
                   Application.ProcessMessages;
                   fs.ReadBuffer(ttxbuf[$09], $3);//×òåíèå çíà÷åíèÿ ïîäòèïà òîêåíà è äëèíû åãî çàãîëîâêà
                   TokenHdrLen:=ttxbuf[$0B];//Äëèíà çàãîëîâêà òîêåíà
                   TokenSubType:=TokenHdrLen;
                   fs.Seek(fs.position-4, sofrombeginning);//ñìåùåíèå íà íà÷àëî òîêåíà
                   inc(TokenHdrLen, 5);//Óâåëè÷èì äëèíó äî îáùåé äëèíû òîêåíà ñ åãî CRC
                   fs.ReadBuffer(ttxbuf[8], TokenHdrLen);//×òåíèå çíà÷åíèé òîêåíà ñ åãî CRC
                   apebyte:=ttxbuf[44];
                   Application.ProcessMessages;
                   case TokenSubType of
                   $2D:
                       //Äëèíà òåêóùåãî áëîêà ìåæäó òîêåíàìè
                       CurrBlockLen := HexToInt(IntToHex(ttxbuf[TokenHdrLen-1], 2)+
                                                IntToHex(ttxbuf[TokenHdrLen],   2)+
                                                IntToHex(ttxbuf[TokenHdrLen+1], 2)+
                                                IntToHex(ttxbuf[TokenHdrLen+2], 2));
                   $43:
                       //Äëèíà òåêóùåãî áëîêà ìåæäó òîêåíàìè
                       CurrBlockLen := HexToInt(IntToHex(ttxbuf[TokenHdrLen-$17], 2)+
                                                IntToHex(ttxbuf[TokenHdrLen-$16], 2)+
                                                IntToHex(ttxbuf[TokenHdrLen-$15], 2)+
                                                IntToHex(ttxbuf[TokenHdrLen-$14], 2));
                   else
                     begin
                        fs.Free;
                        E.Create('Write : Bad image file');
                     end;
                   end;//End of Case

                   //Ñðàâíåíèå RootKey Hash òåëåôîíà è RootKey Hash áëîêà ñåðòîâ
                   good:=0;
                   case apebyte of
                   $00: begin
                        for i:=$0 to $0F do if RAPInfo.Root_Key_Hash[i]=ttxbuf[i+$0C] then inc(good);
                        end;
                   $01: begin
                        for i:=$0 to $0F do if RAPInfo.APErootkey[i]=ttxbuf[i+$0C] then inc(good);
                        end;
                   end;
                   if good<$10 then
                   begin//RootKey Hash íå ñîâïàë, ïðîïóñêàåì
                        fs.Seek(CurrBlockLen, soFromCurrent);//Ïðîïóñêàåì òîêåí è åãî äàííûå
                        continue;
                   end
                   else
                   begin
                        fs.Seek(fs.position-Tokenhdrlen, soFromBeginning);
                        //RootKey Hash ñåðòà ñîâïàë, êîïèðóåì
                        case TokenSubType of
                        $2D:
                        begin

                        fs.ReadBuffer(ttxBuf[0],TokenHdrLen);//Êîïèðîâàíèå äàííûõ
                        Application.ProcessMessages;
                        CertName:='';
                        for i:=24 to 39 do if ttxbuf[i]=$00 then break else CertName:=CertName+Chr(ttxbuf[i]);
                         case apebyte of
                         $00:Form1._msg('CMT: Writing Hash CERT ['+CertName+']');
                         $01:Form1._msg('APE: Writing Hash CERT ['+CertName+']');
                         end;
                        Application.ProcessMessages;

                        //Form1._msg('txbuf : '+BufToHexStr(@txbuf[0],framelen));
                           Application.ProcessMessages;
                           case apebyte of
                           $00:
                           begin
                             if furCMT<>$00 then
                             begin
                             if ConFigureAsic($00) then furcmt:=$00
                             else
                              begin
                              form1._msg('APE select error, impossible continue flashing. Check HW/Cable');
                              result:=false;
                              fs.free;
                              Exit;
                              end;
                             end;

                           end;
                           $01:
                           begin
                            if furCMT<>$01 then
                            begin
                            if ConFigureAsic($01) then furcmt:=$01
                             else
                              begin
                              form1._msg('APE select error, impossible continue flashing. Check HW/Cable');
                              result:=false;
                              fs.free;
                              Exit;
                              end;
                            end;
                            Application.ProcessMessages;
                           end;
                         end;
                             application.ProcessMessages;
                             fs.Seek(fs.position-Tokenhdrlen, soFromBeginning);
                             application.ProcessMessages;
                             //FillMemory(@cmd_buf[0],9,$00);
                             FT_Out_Buffer[0]:=$65;
                             FT_Out_Buffer[1]:=$00;
                             FT_Out_Buffer[2]:=$0C;
                             FT_Out_Buffer[3]:=$32;
                             FT_Out_Buffer[4]:=CurrBlockLen  div $10000;
                             FT_Out_Buffer[5]:=CurrBlockLen  div $100;
                             FT_Out_Buffer[6]:=CurrBlockLen  mod $100;
                             FT_Out_Buffer[7]:=$07;
                             FT_Out_Buffer[8]:=$00;
                             Application.ProcessMessages;
                              currblocklen:=currblocklen+tokenhdrlen;
                             if CurrBlockLen>$FFF7 then begin
                              fs.ReadBuffer(FT_Out_Buffer[9],$fff7);
                              ufsfl_cmd(6000,@FT_out_buffer,$10000,@cmd_buf,0);
                              ostlen:=CurrBlockLen-$FFF7;
                              packets:=ostlen div $10000;
                              if ostlen mod $10000>0 then inc(packets);
                              currpacketsize:=$10000;
                              Application.ProcessMessages;
                              for i2:=0 to packets-1 do
                              begin
                               Application.ProcessMessages;
                                         if (i2=Packets-1) and (Packets>=1) then
                                         begin
                                              if (ostlen mod $10000)>0 then CurrPacketSize:=(ostLen mod $10000) else CurrPacketSize:=$10000;
                                         end;
                              // form1._msg(inttostr(ostlen mod $10000));
                               fs.ReadBuffer(FT_Out_Buffer[0],currpacketsize);
                               if currpacketsize<$10000 then ufsfl_cmd(6000,@FT_out_buffer,currpacketsize,@cmd_buf,14) else
                               ufsfl_cmd(6000,@FT_out_buffer,currpacketsize,@cmd_buf,0);
                               Application.ProcessMessages;
                              end;
                             end
                             else
                             begin
                             fs.ReadBuffer(FT_Out_Buffer[9],currblocklen);
                             ufsfl_cmd(6000,@FT_out_buffer,CurrBlockLen+9,@cmd_buf,14);
                             end;
                             //Form1._msg(BufToHexStr(@cmd_buf[0],7));
                              Application.ProcessMessages;
                               if not checkc7 then
                               begin
                                form1._msg('Error write CERT block at : '+ IntToStr(blocks));
                                form1._msg('ERR : '+buftohexstr(@cmd_buf[0],12));
                                result:=False;
                                fs.Free;
                                Exit;
                               end;
                        Application.ProcessMessages;
                        inc(blocks);
                        Application.ProcessMessages;
                         case apebyte of
                         $00:form1.statusbar.Panels[1].Text:='CMT : '+inttostr(Blocks);
                         $01:form1.statusbar.Panels[1].Text:='APE : '+inttostr(Blocks);
                         end;
                        end;
                        $43:
                        begin
                        fs.ReadBuffer(ttxBuf[0],CurrBlockLen+TokenHdrLen);//Êîïèðîâàíèå äàííûõ
                        Application.ProcessMessages;

                        //Form1._msg('txbuf : '+BufToHexStr(@txbuf[0],framelen));
                         Application.ProcessMessages;
                           case apebyte of
                           $00:
                           begin
                             if furCMT<>$00 then
                             begin
                             if ConFigureAsic($00) then furcmt:=$00
                             else
                              begin
                              form1._msg('APE select error, impossible continue flashing. Check HW/Cable');
                              result:=false;
                              fs.free;
                              Exit;
                              end;
                             end;

                           end;
                           $01:
                           begin
                            if furCMT<>$01 then
                            begin
                            if ConFigureAsic($01) then furcmt:=$01
                             else
                              begin
                              form1._msg('APE select error, impossible continue flashing. Check HW/Cable');
                              result:=false;
                              fs.free;
                              Exit;
                              end;
                            end;
                            Application.ProcessMessages;
                           end;
                         end;
                           case apebyte of
                           $00:
                            begin
                              if PAPUB_Already then Application.ProcessMessages
                              else
                              begin
                                Form1._msg('CMT: Writing Hash CERT [PAPUBKEYS]');
                             // FillMemory(@cmd_buf[0],9,$00);
                                 FT_Out_Buffer[0]:=$65;
                                 FT_Out_Buffer[1]:=$00;
                                 FT_Out_Buffer[2]:=$0C;
                                 FT_Out_Buffer[3]:=$48;
                                 FT_Out_Buffer[4]:=CurrBlockLen  div $10000;
                                 FT_Out_Buffer[5]:=CurrBlockLen  div $100;
                                 FT_Out_Buffer[6]:=CurrBlockLen  mod $100;
                                 FT_Out_Buffer[7]:=$07;
                                 FT_Out_Buffer[8]:=$00;
                                 currblocklen:=currblocklen+tokenhdrlen;
                                  if CurrBlockLen>$FFF7 then begin
                                   for i:=0 to $FFF7-1 do FT_Out_Buffer[i+9]:=ttxbuf[i];
                                   ufsfl_cmd(6000,@FT_out_buffer,$10000,@cmd_buf,0);
                                   ostlen:=CurrBlockLen-$FFF7;
                                   packets:=ostlen div $10000;
                                   if ostlen mod $10000>0 then inc(packets);
                                   currpacketsize:=$10000;
                                   Application.ProcessMessages;
                                   for i2:=0 to packets-1 do
                                   begin
                                    Application.ProcessMessages;
                                             if (i2=Packets-1) and (Packets>1) then
                                             begin
                                                  if (ostlen mod $10000)>0 then CurrPacketSize:=(ostLen mod $10000) else CurrPacketSize:=$10000;
                                             end;
                                    for i:=0 to currpacketsize-1 do FT_Out_Buffer[i]:=ttxbuf[i];
                                    if currpacketsize<$10000 then ufsfl_cmd(6000,@FT_out_buffer,currpacketsize,@cmd_buf,14) else
                                    ufsfl_cmd(6000,@FT_out_buffer,currpacketsize,@cmd_buf,0);
                                    Application.ProcessMessages;
                                   end;
                                  end
                                  else
                                  begin
                                  for i:=0 to CurrBlockLen do FT_Out_Buffer[i+9]:=ttxbuf[i];
                                  ufsfl_cmd(6000,@FT_out_buffer,CurrBlockLen+9,@cmd_buf,14);
                                  end;
                                  //Form1._msg(BufToHexStr(@cmd_buf[0],7));
                                  Application.ProcessMessages;
                                    if not checkc7 then
                                   begin

                                    form1._msg('Error write CERT block at : '+ IntToStr(blocks));
                                    form1._msg('ERR : '+buftohexstr(@cmd_buf[0],12));
                                    result:=False;
                                    fs.Free;
                                    Exit;
                                    end;
                                 PAPUB_Already:=True;
                               end;
                            end;
                           $01:
                            begin
                               if APE_PAPUB then Application.ProcessMessages
                              else
                              begin
                                 Form1._msg('APE: Writing Hash CERT [PAPUBKEYS]');
                             // FillMemory(@cmd_buf[0],9,$00);
                                 FT_Out_Buffer[0]:=$65;
                                 FT_Out_Buffer[1]:=$00;
                                 FT_Out_Buffer[2]:=$0C;
                                 FT_Out_Buffer[3]:=$48;
                                 FT_Out_Buffer[4]:=CurrBlockLen  div $10000;
                                 FT_Out_Buffer[5]:=CurrBlockLen  div $100;
                                 FT_Out_Buffer[6]:=CurrBlockLen  mod $100;
                                 FT_Out_Buffer[7]:=$07;
                                 FT_Out_Buffer[8]:=$00;
                                 currblocklen:=currblocklen+tokenhdrlen;
                                  if CurrBlockLen>$FFF7 then begin
                                   for i:=0 to $FFF7-1 do FT_Out_Buffer[i+9]:=ttxbuf[i];
                                   ufsfl_cmd(6000,@FT_out_buffer,$10000,@cmd_buf,0);
                                   ostlen:=CurrBlockLen-$FFF7;
                                   packets:=ostlen div $10000;
                                   if ostlen mod $10000>0 then inc(packets);
                                   currpacketsize:=$10000;
                                   Application.ProcessMessages;
                                   for i2:=0 to packets-1 do
                                   begin
                                    Application.ProcessMessages;
                                             if (i2=Packets-1) and (Packets>1) then
                                             begin
                                                  if (ostlen mod $10000)>0 then CurrPacketSize:=(ostLen mod $10000) else CurrPacketSize:=$10000;
                                             end;
                                    for i:=0 to currpacketsize-1 do FT_Out_Buffer[i]:=ttxbuf[i];
                                    if currpacketsize<$10000 then ufsfl_cmd(6000,@FT_out_buffer,currpacketsize,@cmd_buf,14) else
                                    ufsfl_cmd(6000,@FT_out_buffer,currpacketsize,@cmd_buf,0);
                                    Application.ProcessMessages;
                                   end;
                                  end
                                  else
                                  begin
                                  for i:=0 to CurrBlockLen do FT_Out_Buffer[i+9]:=ttxbuf[i];
                                  ufsfl_cmd(6000,@FT_out_buffer,CurrBlockLen+9,@cmd_buf,14);
                                  end;
                                  //Form1._msg(BufToHexStr(@cmd_buf[0],7));
                                  Application.ProcessMessages;
                                    if not checkc7 then
                                   begin

                                    form1._msg('Error write CERT block at : '+ IntToStr(blocks));
                                    form1._msg('ERR : '+buftohexstr(@cmd_buf[0],12));
                                    result:=False;
                                    fs.Free;
                                    Exit;
                                    end;
                                 APE_PAPUB:=True;
                             end;
                            end;
                          end;
                          Application.ProcessMessages;
                         end;
                       end;
                    end;
                        Application.ProcessMessages;
                        inc(blocks);
                        Application.ProcessMessages;
                        case apebyte of
                        $01:form1.statusbar.Panels[1].Text:='APE : '+inttostr(Blocks);
                        $00:form1.statusbar.Panels[1].Text:='CMT : '+inttostr(Blocks);
                        end;

              end//End of Case $5D
          else
              begin//Unknow Tokens or Bad File
                   fs.free;
                   E.Create('Write : Bad image file');
              end;


       end;//End of Case
     form1.pb1.progress:=fs.Position;
     Application.ProcessMessages;
     end;//End of While
     fs.free;
     Form1._msg('Total writen '+inttostr(blocks)+' blocks');
     Application.ProcessMessages;
     endtimecount;
     Form1._msg('TIME : Write time : '+showtime(tmsres)+' ');
     form1.statusbar.Panels[1].Text:='';
     form1.statusbar.Panels[0].Text:='';
     result:=True;
     //form1._msg('Errors : '+inttostr(GetLastError));
     form1.pb1.maxvalue:=100;
     form1.pb1.progress:=0;
     Application.ProcessMessages;
except
     on E:Exception do
     begin
          Form1._msg('Error: '+E.Message);
          Form1.pb1.Progress:=0;
          //USBClosePort;
          exit;
     end;
end;     
     Form1.pb1.Progress:=0;
end;

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

     fs.ReadBuffer(buf[0], 4);//Äëèíà Flash Header
     HdrLen := HexToInt(IntToHex(buf[0], 2)+IntToHex(buf[1], 2)+IntToHex(buf[2], 2)+IntToHex(buf[3], 2));
     fs.Seek(4,soFromCurrent);
     Application.ProcessMessages;
     starttime;
     regioncnt:=0;
     Application.ProcessMessages;
 try
     while fs.Position<(HdrLen) do
     begin
          fs.ReadBuffer(CurrSeem, 1);
           case CurrSeem of
          $E4:
          begin
             //   Form1._msg('SEEM: E4');
               fs.ReadBuffer(buf[0], 2);
               CurrSeemLen:=(buf[0]*$100)+buf[1];
               fs.Seek(CurrSeemLen, sofromCurrent);
          end;
          $E5:
          begin
             //   Form1._msg('SEEM: E5');
               fs.ReadBuffer(buf[0], 2);
               CurrSeemLen:=(buf[0]*$100)+buf[1];
               fs.Seek(CurrSeemLen, sofromCurrent);
          end;
          $EA:
          begin
              //  Form1._msg('SEEM: EA');
               fs.ReadBuffer(buf[0], 2);
               CurrSeemLen:=(buf[0]*$100)+buf[1];
               fs.Seek(CurrSeemLen, sofromCurrent);
          end;
          $EE:
          begin
              partition:=True;
              partitionstream:=TmemoryStream.Create;
             // Form1._msg('SEEM: EE');
               fs.ReadBuffer(buf[0], 2);
               CurrSeemLen:=(buf[0]*$100)+buf[1];
               partLen:=currseemlen;
               //fs.Seek(CurrSeemLen, sofromCurrent);
              partitionstream.copyFrom(fs,CurrSeemlen);
             /// ms.SaveToFile('C:\partition.bin');
              Application.ProcessMessages;
          end;
          $F3:
          begin
              //  Form1._msg('SEEM: F3');
               fs.ReadBuffer(buf[0], 2);
               CurrSeemLen:=(buf[0]*$100)+buf[1];
               fs.Seek(CurrSeemLen, sofromCurrent);
          end;
          $FA: begin
             // Form1._msg('SEEM: FA');
              streamlen:=TmemoryStream.Create;
              streamlen.CopyFrom(fs,$E);  // ñîçäàâàë ïîòîê, ïîòîìó ÷òî èíà÷å ïîêà íå óìåþ
              streamlen.Seek(1, sofromBeginning); // ïðîïóñêàåì îäèí áàéò
              streamlen.ReadBuffer(loaderlen,4); // ÷èòàåì äëèíó - ýòî äëèíà âñåãî àäðåñíîãî ïðîñòðàíñòâà áëîêà FA, êîòîðîå çàíèìàåò àïäåéò àïï, ñðàçó ïîñëå áëîêà äëèíû.
              dwordswap(@loaderlen); // ðàçâîðà÷èâàåì
              fs.seek(loaderlen-9,sofromcurrent); // ìåíÿåì ïîçèöèþ - ïîñëå èäóò ñòàðûå äîáðûå Ñ8
              Application.ProcessMessages;
              streamlen.Free;
              end;
           $C8:
               begin
                   erase:=True;
                   cmt:=True;
                   fs.ReadBuffer(buf[0], 1);
                   CurrSeemLen:=buf[0];
                   fs.ReadBuffer(CurSeemcount, 1);
                    //Form1._msg('');
                   // Form1._msg('Found '+IntToStr(CurrSeemLen)+' flash chips to erase');

                  for n:=1 to CurSeemcount do
                  begin
                      //form1._msg(IntToStr(fs.Position));
                     if stop=True then
                     begin
                     dostop('ERASE');
                     result:=False;
                     fs.Free;
                     Application.ProcessMessages;
                     Exit;
                     end;
                    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);

                        if furCMT<>Byte1 then begin
                         ConFigureAsic(Byte1);
                         furCMT:=Byte1;
                        end;

                         FillMemory(@Ft_out_buffer[0],$10000,$00);
                         FT_Out_Buffer[0]:=$74;
                         FT_Out_Buffer[1]:=$0A;
                         FT_Out_Buffer[2]:=$00;
                         FT_Out_Buffer[3]:=$00;
                         FT_Out_Buffer[4]:=$00;
                         FT_Out_Buffer[5]:=$50;
                         FT_Out_Buffer[6]:=$00;
                         di:=7;

                         EraseCnt:=CurrEraseLen div 8;


                         Form1._msg('Found '+IntToStr(EraseCnt)+' areas to erase, erase group');
                         Form1._msg('Asic : '+GetAsic(Byte1)+' , Sub : '+GetSub(Byte2));
                         //fs.ReadBuffer(buf[0], CurrEraseLen);
                         for j:=0 to EraseCnt-1 do
                         begin
                         FT_Out_Buffer[di]:=FlashCFG;
                         Inc(di);
                         FT_Out_Buffer[di]:=$0B;
                         Inc(di);
                         FT_Out_Buffer[di]:=byte1;
                         Inc(di);
                         FT_Out_Buffer[di]:=byte2;
                         Inc(di);
                         FT_Out_Buffer[di]:=byte3;
                         Inc(di);
                         fs.ReadBuffer(FT_Out_Buffer[di], 8);
                         Application.ProcessMessages;
                         Form1._msg(GetAsic(Byte1)+' , '+GetSub(Byte2)+' , Area : 0x'+buftohexstr(@FT_out_buffer[di],4)+' - 0x'+buftohexstr(@FT_out_buffer[di+4],4));
                         Application.ProcessMessages;
                         Inc(di,8);
                         Application.ProcessMessages;
                         end;
                         Form1.statusbar.Panels[0].Text:='';
                         Form1.statusbar.Panels[1].Text:='';
                         Application.ProcessMessages;
                         Word((@FT_Out_Buffer[3])^):=di-4;
                         wordswap(@FT_Out_Buffer[3]);
                         FT_Out_Buffer[6]:=erasecnt;
                         crc:=frameCrc(@Ft_out_buffer[6], di-6);
                         FT_Out_Buffer[di]:=crc;
                         inc(di);
                         application.processMessages;
                         form1.pb1.progress:=0;
                         form1.pb1.maxvalue:=5000;
                        // Form1._msg('Erase : '+buftohexstr(@FT_Out_Buffer[0],di));
                         if Byte2=$00 then Form1._msg('Using TimeOut : 5 min ( 300 sec )');
                         Form1._msg('Erasing, wait.....');
                         application.processMessages;
                         ufsfl_cmd(1000,@FT_out_buffer,di,@cmd_buf,2);
                        if FT_In_Buffer[0]<$F0 then
                        begin
                           ufsfl_cmd(1000,@Verifyreply,length(Verifyreply),@cmd_buf,2);
                           if FT_In_Buffer[0]<$F0 then
                           begin
                             ufsfl_cmd(1000,@rd1byte,length(rd1byte),@cmd_buf,3);
                            // form1._msg(byte2str(FT_In_Buffer[0]));
                             repeat
                             FillMemory(@cmd_buf[0],2,$00);
                             ufsfl_cmd(1000,@Verifyreply,length(Verifyreply),@cmd_buf,2);
                             if (cmd_buf[0]>$F0) or (cmd_buf[0]<$B0) then break;
                             application.processMessages;
                             form1.pb1.progress:=form1.pb1.progress+1;
                             application.processMessages;
                                if stop=True then
                               begin
                               dostop('ERASE');
                               result:=False;
                               fs.Free;
                               Application.ProcessMessages;
                               UFSeblock;
                               SwitchBoxMode('FBUS');
                               Exit;
                               end;
                             sleep(20);
                             until cmd_buf[0]>$F0;
                             if cmd_buf[0]<$B0 then
                             begin
                             form1._Msg('Erase error! Conection lost :(');
                             result:=False;
                             fs.Free;
                             Exit;
                             end;
                           end;
                         ufsfl_cmd(1000,@rd7byte,length(rd7byte),@cmd_buf,9);
                         if not AsicComandFur then
                         begin
                         form1._msg('Erase '+GetAsic(furCMT)+' group error!');
                          form1._msg('ERR : '+buftohexstr(@cmd_buf[0],7));
                          result:=False;
                          fs.Free;
                          Exit;
                         end;
                         form1._msg(GetAsic(furCMT)+' : Group erase Ok');
                         Application.ProcessMessages;
                        end
                        else
                        begin
                         ufsfl_cmd(1000,@rd7byte,length(rd7byte),@cmd_buf,9);
                         // form1._msg(buftohexstr(@ft_In_Buffer[0],9));
                         if not AsicComandFur then
                         begin
                         form1._msg('Erase '+GetAsic(furCMT)+' group error!');
                          form1._msg('ERR : '+buftohexstr(@cmd_buf[0],7));
                          result:=False;
                          fs.Free;
                          Exit;
                         end;
                         form1._msg(GetAsic(furCMT)+' : Group erase Ok');
                         Application.ProcessMessages;
                        end;
                        //for i:=0 to di do form1._msg(byte2str(framecrc(@Ft_out_buffer[i],(di-i))));
                        //Form1._msg('Erase : '+buftohexstr(@FT_Out_Buffer[0],di));

                      end;
                      $19:
                      begin
                         fs.ReadBuffer(partitionlen,1);
                         fs.ReadBuffer(byte1,1);
                         if furCMT<>Byte1 then
                         begin
                         ConFigureAsic(Byte1);
                         furcmt:=Byte1;
                         end;
                         Application.ProcessMessages;
                         fs.Seek(fs.position-2,soFromBeginning);
                         Application.ProcessMessages;
                         FillMemory(@Ft_out_buffer[0],$10000,$00);
                         FT_Out_Buffer[0]:=$74;
                         FT_Out_Buffer[1]:=$0A;
                         FT_Out_Buffer[2]:=$00;
                         FT_Out_Buffer[3]:=$00;
                         FT_Out_Buffer[4]:=$00;
                         FT_Out_Buffer[5]:=$50;
                         FT_Out_Buffer[6]:=$00;
                         di:=7;
                        //regioncnt:=regioncnt+1;
                        FT_Out_Buffer[di]:=$19;
                        Inc(di);
                        fs.ReadBuffer(partitionlen,1);
                        FT_Out_Buffer[di]:=partitionlen;
                        Inc(di);
                        fs.ReadBuffer(FT_Out_Buffer[di],partitionlen);
                        byte1:=Ft_out_buffer[di];
                        byte2:=Ft_out_buffer[di+1];
                        partbyte:=Ft_out_buffer[di+14];
                        Inc(di,partitionlen);
                        form1._msg('Erase Partition 0x'+byte2str(partbyte)+' , '+GetAsic(Byte1)+' , '+GetSub(Byte2));
                         Application.ProcessMessages;
                         Word((@FT_Out_Buffer[3])^):=di-4;
                         wordswap(@FT_Out_Buffer[3]);
                         FT_Out_Buffer[6]:=$01;
                         crc:=frameCrc(@Ft_out_buffer[6], di-6);
                         FT_Out_Buffer[di]:=crc;
                         inc(di);
                         application.processMessages;
                         form1.pb1.progress:=0;
                         form1.pb1.maxvalue:=1000;
                         //Form1._msg('Erase : '+buftohexstr(@FT_Out_Buffer[0],di));
                         //Form1._msg('Using TimeOut : 5 min ( 300 sec )');
                         //Form1._msg('Erasing, wait.....');
                         application.processMessages;
                         ufsfl_cmd(1000,@FT_out_buffer,di,@cmd_buf,2);
                        if FT_In_Buffer[0]<$F0 then
                        begin
                           ufsfl_cmd(1000,@Verifyreply,length(Verifyreply),@cmd_buf,2);
                           if FT_In_Buffer[0]<$F0 then
                           begin
                             ufsfl_cmd(1000,@rd1byte,length(rd1byte),@cmd_buf,3);
                             //form1._msg(byte2str(FT_In_Buffer[0]));
                             repeat
                             FillMemory(@cmd_buf[0],2,$00);
                             ufsfl_cmd(1000,@Verifyreply,length(Verifyreply),@cmd_buf,2);
                             if (cmd_buf[0]>$F0) or (cmd_buf[0]<$B0) then break;
                             application.processMessages;
                             form1.pb1.progress:=form1.pb1.progress+1;
                             application.processMessages;
                             sleep(10);
                             until cmd_buf[0]>$F0;
                             if cmd_buf[0]<$B0 then
                             begin
                              form1._Msg('Erase partition error! Conection lost :(');
                              form1._msg('ERR : '+buftohexstr(@cmd_buf[0],7));
                              result:=False;
                              fs.Free;
                              Exit;
                             end;
                           end;
                           ufsfl_cmd(1000,@rd7byte,length(rd7byte),@cmd_buf,9);
                         if not AsicComandFur then
                         begin
                         form1._msg('Erase '+GetAsic(furCMT)+' Partition error!');
                          form1._msg('ERR : '+buftohexstr(@cmd_buf[0],7));
                          result:=False;
                          fs.Free;
                          Exit;
                         end;
                         form1._msg(GetAsic(furCMT)+' : Partition erase Ok');
                         Application.ProcessMessages;
                        end
                        else
                        begin
                         ufsfl_cmd(1000,@rd7byte,length(rd7byte),@cmd_buf,9);
                         if not AsicComandFur then
                         begin
                         form1._msg('Erase '+GetAsic(furCMT)+' Partition error!');
                          form1._msg('ERR : '+buftohexstr(@cmd_buf[0],7));
                          result:=False;
                          fs.Free;
                          Exit;
                         end;
                         form1._msg(GetAsic(furCMT)+': Partition erase Ok');
                         Application.ProcessMessages;
                        end;
                     // form1._msg('afPos : '+IntToStr(fs.Position));
                      end;
                      $13: // Erase USRFL
                      begin
                        //regioncnt:=regioncnt+1;
                        //FillMemory(@Ft_out_buffer[0],$10000,$00);
                        ercrt:='';
                        fs.ReadBuffer(partitionlen,1);
                        fs.ReadBuffer(Flashcfg,1);
                        if furCMT<>Flashcfg then ConFigureAsic(FlashCfg);
                        erasecnt:=(partitionlen-1) div $C;
                        for i:=0 to erasecnt-1 do
                        begin
                         ercrt:='';
                         Application.ProcessMessages;
                         FT_Out_Buffer[0]:=$74;
                         FT_Out_Buffer[1]:=$0A;
                         FT_Out_Buffer[2]:=$00;
                         FT_Out_Buffer[3]:=$00;
                         FT_Out_Buffer[4]:=$00;
                         FT_Out_Buffer[5]:=$50;
                         FT_Out_Buffer[6]:=$00;
                         di:=7;
                         FT_Out_Buffer[di]:=$13;
                         Inc(di);
                         FT_Out_Buffer[di]:=$0D;
                         Inc(di);
                         FT_Out_Buffer[di]:=FlashCFG;
                         Inc(di);
                         fs.ReadBuffer(FT_Out_Buffer[di],$0C);
                         for i2:=0 to $0B do  if FT_Out_Buffer[di+i2]=$00 then break else ercrt:=ercrt+Chr(FT_Out_Buffer[di+i2]);
                         Inc(di,$0C);

                        //inc(di);
                        form1._msg('Erase CRTFL : '+Ercrt);
                        Application.ProcessMessages;
                         Word((@FT_Out_Buffer[3])^):=di-4;
                         wordswap(@FT_Out_Buffer[3]);
                         FT_Out_Buffer[6]:=$01;
                         crc:=frameCrc(@Ft_out_buffer[6], di-6);
                         FT_Out_Buffer[di]:=crc;
                         inc(di);
                         application.processMessages;
                         form1.pb1.progress:=0;
                         form1.pb1.maxvalue:=1000;
                         //Form1._msg('Erase : '+buftohexstr(@FT_Out_Buffer[0],di));
                         //Form1._msg('Using TimeOut : 5 min ( 300 sec )');
                         //Form1._msg('Erasing, wait.....');
                         application.processMessages;
                         ufsfl_cmd(1000,@FT_out_buffer[0],di,@cmd_buf,2);
                        if FT_In_Buffer[0]<$F0 then
                        begin
                           ufsfl_cmd(1000,@Verifyreply,length(Verifyreply),@cmd_buf,2);
                           if FT_In_Buffer[0]<$F0 then
                           begin
                             ufsfl_cmd(1000,@rd1byte,length(rd1byte),@cmd_buf,3);
                             //form1._msg(byte2str(FT_In_Buffer[0]));
                             repeat
                             FillMemory(@cmd_buf[0],2,$00);
                             ufsfl_cmd(1000,@Verifyreply,length(Verifyreply),@cmd_buf,2);
                             if (cmd_buf[0]>$F0) or (cmd_buf[0]<$B0) then break;
                             application.processMessages;
                             form1.pb1.progress:=form1.pb1.progress+1;
                             application.processMessages;
                             sleep(10);
                             until cmd_buf[0]>$F0;
                             if cmd_buf[0]<$B0 then begin
                              form1._Msg('Erase CRTFL error! Conection lost :(');
                              form1._msg('ERR : '+buftohexstr(@cmd_buf[0],7));
                              result:=False;
                              fs.Free;
                              Exit;
                             end;
                           end;
                           ufsfl_cmd(1000,@rd7byte,length(rd7byte),@cmd_buf,9);
                          if not AsicComandFur then
                          begin
                          form1._msg(GetAsic(furCMT)+' : Erase CRTFL error!');
                          form1._msg('ERR : '+buftohexstr(@cmd_buf[0],7));
                          result:=False;
                          fs.Free;
                          Exit;
                          end;
                          form1._msg(GetAsic(furCMT)+' : CRTFL erase Ok');
                          Application.ProcessMessages;
                        end
                        else
                        begin
                         ufsfl_cmd(1000,@rd7byte,length(rd7byte),@cmd_buf,9);
                         // form1._msg(buftohexstr(@ft_In_Buffer[0],9));
                         if not AsicComandFur then
                         begin
                         form1._msg('Erase '+GetAsic(furCMT)+' CRTFL erase error!');
                          form1._msg('ERR : '+buftohexstr(@cmd_buf[0],7));
                          result:=False;
                          fs.Free;
                          Exit;
                         end;
                         form1._msg(GetAsic(furCMT)+' : CRTFL erase Ok');
                         Application.ProcessMessages;
                        end;
                        end;
                      end;
                    end;
                  end;

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

function UFSprepareForFlash(image:string):Boolean;
begin
  result:=False;

  {if not UFSPartitioning(image) then
  begin
  Form1._msg('Error on Flash Prepare : Partitioning error!');
  exit;
  end;  }

 if stop=True then
 begin
 dostop('FLASH');
 Application.ProcessMessages;
 Exit;
 end;

  if not FlashPrepare(image) then
  begin
  Form1._msg('Error on Flash Prepare!');
  exit;
  end;

 if stop=True then
 begin
 dostop('FLASH');
 Application.ProcessMessages;
 Exit;
 end;

  if not UFSeraseUni(image) then
  begin
  Form1._msg('Error on Erasing Phone!');
  exit;
  end;

  UFSfinishsession;

  if not phoneready(20) then
  begin
  Form1._msg('Error on Prepare for Flashing Phone!');
  exit;
  end;

  if not PreCertreq then exit;

  if not phoneready(20) then
  begin
  Form1._msg('Error on Prepare for Flashing Phone!');
  exit;
  end;


  if not UFSWriteFileUNI(image) then
  begin
  Form1._msg('Error on Flashing Phone!');
  exit;
  end;
  //form1._msg('All done ;)');
  result:=True;
end;

function UFSFormatLow(area:string):Boolean;
begin
result:=False;

if not phoneready(20) then
begin
result:=false;
form1._msg('Error while prepare , phone not ready');
Exit;
end;

 if not PreCertreq then exit;

  if not phoneready(20) then
  begin
  result:=false;
  form1._msg('Error while prepare , transrequest error');
  Exit;
  end;

// CertStore request
 ufsfl_cmd(500,@storecert[0], Length(storecert),@cmd_buf,7);
 if (ft_in_Buffer[0]<>$00) or (ft_in_Buffer[1]<>$00)  then
 begin
 result:=false;
 form1._msg('Error while prepare : CertStore error');
 form1._msg('ERR : '+buftohexstr(@ft_in_buffer[0], 7));
 Exit;
 end;

 if not phoneready(20) then
 begin
 result:=false;
 form1._msg('Error while prepare : transrequest error');
 form1._msg('ERR : '+buftohexstr(@ft_in_buffer[0], 3));
 Exit;
 end;

 if not ConFigureAsic($00) then form1._msg('CMT CFG not done');

Application.ProcessMessages;

  if not UFSeraseS40(area) then
  begin
  Form1._msg('Error on Formatting Phone!');
  //exit;
  end;

  Application.ProcessMessages;

  if not phoneready(20) then
  begin
  Form1._msg('Error on finish format... :( ');
  //exit;
  end;

  Application.ProcessMessages;

  if UFSfinishsession<>0 then Exit;

  UFSfinishsession;

  result:=True;
end;

function AsicComandFur():Boolean;
begin
        if cmd_buf[0]<>$C7 then result:=False
        else
        begin
         if (cmd_buf[1]=$01) and (cmd_buf[2]=$2D) and (cmd_buf[3]=$01) and (cmd_buf[4]=$00) and (cmd_buf[5]=$D0) then
          result:=true
         else
         begin
           if (cmd_buf[1]=$01) and (cmd_buf[2]=$2D) and (cmd_buf[3]=$01) and (cmd_buf[4]=$01) and (cmd_buf[5]=$CF) then
           result:=true
           else result:=false;
         end;
        end;
        if (cmd_buf[4]=$03) then Form1._msg('Error, 03, DataMissMatch, Check Cable, FlashPack, Firmware');
end;

function checkc7():Boolean;
begin
  result:=False;
  if not AsicComandFur then exit
  else
  result:=True;
end;

function UFSfinishsession():integer;
var
  st , st2 : Byte;
  asic,len : Byte;
  strasic  : string;
  i        : integer;
begin
 result:=5;
 //if not phoneready(20) then exit;
 Application.ProcessMessages;
 ufsfl_cmd(3000,@Flbcloseasic[0],11,@cmd_buf,9);
 if cmd_buf[0]<>$C2 then Exit;
 repeat
 Application.ProcessMessages;
 rdreqdta[5]:=$02;
 ufsfl_cmd(1500,@rdreqdta[0],6,@cmd_buf,4);
 asic:=cmd_buf[0];
 len:=cmd_buf[1];
 if len=0 then Break;
 rdreqdta[5]:=len;
 ufsfl_cmd(1500,@rdreqdta[0],6,@cmd_buf,len+2);
 //Form1._msg('Asic : '+byte2str(asic)+' data : '+buftohexstr(@cmd_buf[0],len));
 if asic=$16 then
  begin
  Application.ProcessMessages;
  strasic:='';
   for i:=3 to 12 do if cmd_buf[i]<>$00 then strasic:=strasic+chr(cmd_buf[i]) else break;
  form1._msg('Programming report : Error '+strasic);
  Application.ProcessMessages;
  end;
 until len=0;
 Application.ProcessMessages;
 if not phoneready(20) then exit;
 result:=0;
 furCMT:=$03;
end;

function UFSEBLock():integer;
begin
ufsfl_cmd(1200,@EBlock[0],11,@cmd_buf,14);
//Form1._msg('EngageBootLock : '+buftohexstr(@cmd_buf[0],12));
end;

function UFSEBLockAPE():boolean;
begin
ufsfl_cmd(1200,@EBlockAPE[0],14,@cmd_buf,7);
//Form1._msg('EngageBootLock : '+buftohexstr(@cmd_buf[0],12));
if phoneready(50) then result:=True;
end;

function buildUFScert(DataStream : widestring; cert : string; asic : byte ): Boolean;
var
  i, framelen : Integer;
  tmp         : array of Byte;
  chk         : word;
  x,i2,len,
  flen        : Integer;
begin
  result:=False;
 // if cert='HWC' then datastream:=datastream+'FFFFFFFF';
 flen:=length(datastream) mod 80;
 if flen <> 0 then
 begin
  len:=80-(length(datastream) mod 80);
  for i2:=0 to len-1 do datastream:=datastream+'F';
 // form1._msg('Collect : '+inttostr(len)+'/'+inttostr(flen));
 end;

  // prepare and clear start buffer
  FillMemory(@Ft_out_buffer[0],800,$00);
  FT_Out_Buffer[0]:=$65;
  FT_Out_Buffer[1]:=$00;
  FT_Out_Buffer[2]:=$0C;
  FT_Out_Buffer[3]:=$32;
  FT_Out_Buffer[4]:=$00;
  FT_Out_Buffer[5]:=$00;
  FT_Out_Buffer[6]:=$00;
  FT_Out_Buffer[7]:=$00;
  FT_Out_Buffer[8]:=$00;
  FT_Out_Buffer[9]:=$5D;
  FT_Out_Buffer[10]:=$01;
  FT_Out_Buffer[11]:=$27;
  FT_Out_Buffer[12]:=$2D;
  for i:=13 to 32 do FT_Out_Buffer[i]:=$FF;
  for i:=33 to 44 do FT_Out_Buffer[i]:=$00;
  for i:=0 to Length(CERT) do FT_Out_Buffer[i+33]:=Ord(CERT[i+1]);
  FT_Out_Buffer[45]:=asic;
  case Asic of
 $00:
  if FLtype='NAND' then FT_Out_Buffer[46]:=$03
  else FT_Out_Buffer[46]:=$00;
 $01: FT_Out_Buffer[46]:=$01;
 end;
  FT_Out_Buffer[47]:=$00;
 SetLength(tmp, length(DataStream) div 2);
 x:=StrToBufHex(DataStream,@tmp[0]);
 CHK:=FbusGetChk(@tmp[0], x);
 Word((@FT_Out_Buffer[48])^):=chk;
 DWord((@FT_Out_Buffer[50])^):=x;
 DWordSwap(@FT_Out_Buffer[50]);
 FT_Out_Buffer[54]:=$FF;
 FT_Out_Buffer[55]:=$FF;
 FT_Out_Buffer[56]:=$FF;
 FT_Out_Buffer[57]:=$FF;

 FT_Out_Buffer[58]:=framecrc(@FT_Out_Buffer[0],58);

 StrToBufHex(DataStream,@FT_Out_Buffer[59]);
  FT_Out_Buffer[4]:=x div $10000;
  FT_Out_Buffer[5]:=x div $100;
  FT_Out_Buffer[6]:=x mod $100;
  //form1._msg(BufToHexStr(@Ft_out_buffer[0],x+59));
  ufsfl_cmd(1500,@FT_out_buffer[0],x+59,@cmd_buf[0],7);
  //form1._msg(BufToHexStr(@cmd_buf[0],7));
  if cmd_buf[5]>$F0 then result:=True;
  UFSfinishsession;
  UFSfinishsession;
end;

function UFSeraseCRT (CRT : string; Asic : Byte) : Boolean;
var
   i,di : integer;
   crc  : byte;
begin
 Application.ProcessMessages;
 FT_Out_Buffer[0]:=$74;
 FT_Out_Buffer[1]:=$0A;
 FT_Out_Buffer[2]:=$00;
 FT_Out_Buffer[3]:=$00;
 FT_Out_Buffer[4]:=$00;
 FT_Out_Buffer[5]:=$50;
 FT_Out_Buffer[6]:=$00;
 di:=7;
 FT_Out_Buffer[di]:=$13;
 Inc(di);
 FT_Out_Buffer[di]:=$0D;
 Inc(di);
 case Asic of
 $00: FT_Out_Buffer[di]:=$00;
 $01: FT_Out_Buffer[di]:=$01;
 end;
 Inc(di);
 fillmemory(@FT_Out_Buffer[di],$0C,$00);
 for i:=0 to Length(CRT)-1 do FT_Out_Buffer[di+i]:=Ord(crt[i+1]);
 Inc(di,$0C);
 form1._msg('Erase CRT FL : '+crt);
 Application.ProcessMessages;
 Word((@FT_Out_Buffer[3])^):=di-4;
 wordswap(@FT_Out_Buffer[3]);
 FT_Out_Buffer[6]:=$01;
 crc:=frameCrc(@Ft_out_buffer[6], di-6);
 FT_Out_Buffer[di]:=crc;
 inc(di);
 application.processMessages;
 form1.pb1.ForeColor:=clYellow;
 form1.pb1.progress:=0;
 form1.pb1.maxvalue:=1000;
 application.processMessages;
 ufsfl_cmd(1000,@FT_out_buffer[0],di,@cmd_buf,2);
 if FT_In_Buffer[0]<$F0 then
 begin
 ufsfl_cmd(1000,@Verifyreply,length(Verifyreply),@cmd_buf,2);
 if FT_In_Buffer[0]<$F0 then
  begin
  ufsfl_cmd(1000,@rd1byte,length(rd1byte),@cmd_buf,3);
                            repeat
                             FillMemory(@cmd_buf[0],2,$00);
                             ufsfl_cmd(1000,@Verifyreply,length(Verifyreply),@cmd_buf,2);
                             if (cmd_buf[0]>$F0) or (cmd_buf[0]<$B0) then break;
                             application.processMessages;
                             form1.pb1.progress:=form1.pb1.progress+1;
                             application.processMessages;
                             sleep(10);
                             until cmd_buf[0]>$F0;
                             if cmd_buf[0]<$B0 then begin
                              form1._Msg('Erase CRT FL error! Conection lost :(');
                              form1._msg('ERR : '+buftohexstr(@cmd_buf[0],7));
                              result:=False;
                              Exit;
                             end;
  end;
  form1._msg('CMT : '+crt+' erase Ok');
  Application.ProcessMessages;
  end
 else
 begin
  form1._msg('CMT : '+crt+' erase Ok');
  Application.ProcessMessages;
 end;
 form1.pb1.Progress:=0;
 form1.pb1.ForeColor:=clNavy;
 form1.pb1.MaxValue:=100;
 Application.ProcessMessages;
  UFSfinishsession;
  UFSfinishsession;
end;

function UFSeraseS40(area:string):Boolean;
var
  di,erasecnt:Integer;
  crc         :Byte;
begin
 Form1._msg('Erase User Area now, Selected model : '+form1.cbbLFmdel.text);

 Application.ProcessMessages;

 if furCMT<>$00 then begin
 ConFigureAsic($00);
 furCMT:=$00;
 end;

 FillMemory(@Ft_out_buffer[0],$10000,$00);
 FT_Out_Buffer[0]:=$74;
 FT_Out_Buffer[1]:=$0A;
 FT_Out_Buffer[2]:=$00;
 FT_Out_Buffer[3]:=$00;
 FT_Out_Buffer[4]:=$00;
 FT_Out_Buffer[5]:=$50;
 FT_Out_Buffer[6]:=$00;
 di:=7;

 FT_Out_Buffer[di]:=$12;
 Inc(di);
 FT_Out_Buffer[di]:=$0B;
 Inc(di);
 FT_Out_Buffer[di]:=$00;
 Inc(di);
 FT_Out_Buffer[di]:=$00;
 Inc(di);
 FT_Out_Buffer[di]:=$00;
 Inc(di);
 FT_Out_Buffer[di]:=Str2Byte(Copy(area,1,2));
 Inc(di);
 FT_Out_Buffer[di]:=Str2Byte(Copy(area,3,2));
 Inc(di);
 FT_Out_Buffer[di]:=Str2Byte(Copy(area,5,2));
 Inc(di);
 FT_Out_Buffer[di]:=Str2Byte(Copy(area,7,2));
 Inc(di);
 FT_Out_Buffer[di]:=Str2Byte(Copy(area,9,2));
 Inc(di);
 FT_Out_Buffer[di]:=Str2Byte(Copy(area,11,2));
 Inc(di);
 FT_Out_Buffer[di]:=Str2Byte(Copy(area,13,2));
 Inc(di);
 FT_Out_Buffer[di]:=Str2Byte(Copy(area,15,2));
 Inc(di);
 Application.ProcessMessages;
 Form1.statusbar.Panels[0].Text:='';
 Form1.statusbar.Panels[1].Text:='';
 Application.ProcessMessages;
 Word((@FT_Out_Buffer[3])^):=di-4;
 wordswap(@FT_Out_Buffer[3]);
 FT_Out_Buffer[6]:=$01;
 crc:=frameCrc(@Ft_out_buffer[6], di-6);
 FT_Out_Buffer[di]:=crc;
 inc(di);
// form1._msg(buftohexstr(@Ft_out_buffer[0],di));
   application.processMessages;
   form1.pb1.progress:=0;
   form1.pb1.maxvalue:=5000;
                        // Form1._msg('Erase : '+buftohexstr(@FT_Out_Buffer[0],di));
   Form1._msg('Using TimeOut : 5 min ( 300 sec )');
   Form1._msg('Erasing, wait.....');
   application.processMessages;
   ufsfl_cmd(1000,@FT_out_buffer,di,@cmd_buf,2);
   if FT_In_Buffer[0]<$F0 then
    begin
     ufsfl_cmd(1000,@Verifyreply,length(Verifyreply),@cmd_buf,2);
                           if FT_In_Buffer[0]<$F0 then
                           begin
                             ufsfl_cmd(1000,@rd1byte,length(rd1byte),@cmd_buf,3);
                            // form1._msg(byte2str(FT_In_Buffer[0]));
                             repeat
                             FillMemory(@cmd_buf[0],2,$00);
                             ufsfl_cmd(1000,@Verifyreply,length(Verifyreply),@cmd_buf,2);
                             if (cmd_buf[0]>$F0) or (cmd_buf[0]<$B0) then break;
                             application.processMessages;
                             form1.pb1.progress:=form1.pb1.progress+1;
                             application.processMessages;
                             sleep(20);
                             until cmd_buf[0]>$F0;
                             if cmd_buf[0]<$B0 then
                             begin
                             form1._Msg('Erase error! Conection lost :(');
                             result:=False;
                             Exit;
                             end;
                           end;
                         ufsfl_cmd(1000,@rd7byte,length(rd7byte),@cmd_buf,9);
                         if not AsicComandFur then
                         begin
                         form1._msg('Erase CMT error!');
                          form1._msg('ERR : '+buftohexstr(@cmd_buf[0],7));
                          result:=False;
                          Exit;
                         end;
                         form1._msg('CMT : Format Ok');
                         Application.ProcessMessages;
                         result:=True;
   end
   else
   begin
   ufsfl_cmd(1000,@rd7byte,length(rd7byte),@cmd_buf,9);
                       // form1._msg(buftohexstr(@ft_In_Buffer[0],9));
       if not AsicComandFur then
       begin
       form1._msg('Erase CMT error!');
       form1._msg('ERR : '+buftohexstr(@cmd_buf[0],7));
       result:=False;
       Exit;
       end;
       form1._msg('CMT : Format Ok');
       Application.ProcessMessages;
   end;
   result:=True;
end;


function Boot_infineon({Boot1:TMemoryStream;Boot2:TMemoryStream}):Boolean;
var
  bflag   : boolean;
  tryinit : integer;
  len     : word;
  bcount : integer;
  x : Integer;
begin
result:=false;
 Form1.statusbar.Panels[0].Text:='UFS : Booting phone...';
 form1._msg('Booting phone now....');
 bcount:=0;
 repeat
  tryinit:=0;
  if not busreset then
  begin;
  form1._msg('UFSx init fail, reconnect box');
  exit;
  end;
  //reset_usb_device;
  repeat
  FT_Out_Buffer[0]:=$55;
  Write_USB_Device_Buffer(1);
  Read_USB_Device_Buffer(5);
  Application.ProcessMessages;
  //if FT_In_Buffer[0]=$C3 then Break;
  if FT_In_Buffer[0]=$A2 then Break;
  Application.ProcessMessages;
  sleep(50);
  Application.ProcessMessages;
  //sleep(200);
  Application.ProcessMessages;
  Application.ProcessMessages;
  Inc(tryinit);
  until tryinit=35 ;
  inc(bcount);
  if FT_In_Buffer[0]=$A2 then Break;
 until bcount=5;
 if (tryinit=35) and (bcount=5) then Exit;
 Form1._msg('Sync Ok , '+byte2str(FT_In_Buffer[0]));
 //form1._msg('D : '+buftohexstr(@FT_In_Buffer[0],4));
 tryinit:=0;
 Application.ProcessMessages;
 form1._msg('CPU ID : XGOLD , '+buftohexstr(@FT_In_Buffer[0],5));
 result:=True;
 end;


function BusCheckInfineon():Boolean;
var
  pbl,sbl,dstr         : TMemoryStream;
  i                    : integer;
  dsize                : word;
  ostlen,packets,i2    : integer;
  currpacketsize       : integer;
  chkbuf               : array of Byte;
  loadercheck          : byte;
  flashven             : string;
begin
result:=false;
Reset_USB_Device;
Set_USB_Device_TimeOuts($2710,$2710);
 pbl:=TMemoryStream.Create;
 pbl.Seek(0,soFromBeginning);
 pbl.LoadFromFile(ExtractFileDir(Application.ExeName)+'\Flash\UFS\SGPBL.bin');

 dsize:=pbl.Size;
 Purge_USB_Device_Out;
 Purge_USB_Device_In;
 FT_Out_Buffer[0]:=$30;
 Word((@FT_Out_Buffer[1])^):=dsize;
 Write_USB_Device_Buffer(3);

 pbl.Seek(0,soFromBeginning);
 if pbl.size>$10000 then
 begin
  ostlen:=pbl.size;
  packets:=ostlen div $10000;
  if ostlen mod $10000>0 then inc(packets);
  pbl.Seek(0,soFromBeginning);
  currpacketsize:=$10000;
  Application.ProcessMessages;
  for i2:=0 to packets-1 do
  begin
   Application.ProcessMessages;
                    if (i2=Packets-1) and (Packets>1) then
                    begin
                         if (ostlen mod $10000)>0 then CurrPacketSize:=(ostLen mod $10000) else CurrPacketSize:=$10000;
                    end;
   pbl.Readbuffer(FT_Out_Buffer[0], currpacketsize);
   Write_USB_Device_Buffer(currpacketsize);
   Application.ProcessMessages;
   //Form1._msg('Packet : '+inttostr(packets)+' Len : '+inttostr(currpacketsize));
  end;
 end
 else
 begin
 pbl.Readbuffer(FT_Out_Buffer[0], pbl.Size);
 Write_USB_Device_Buffer(pbl.Size);
 end;
 Application.ProcessMessages;
 Sleep(200);
 Application.ProcessMessages;
 FT_Out_Buffer[0]:=$FE; //loadercheck;
 Write_USB_Device_Buffer(1);
 Read_USB_Device_Buffer(2);
 if ft_in_buffer[0]=$FF then
 begin
 form1._msg('Error booting! 2nd [PBL] not accepted!');
 pbl.Free;
 exit;
 end;
 form1._msg('Boot Ok , '+byte2str(ft_in_buffer[0]));
 pbl.Free;
 Application.ProcessMessages;
 Purge_USB_Device_Out;
 Purge_USB_Device_In;
 Application.ProcessMessages;
 Sleep(100);
 Application.ProcessMessages;
 FT_Out_Buffer[0]:=$B4;
 FT_Out_Buffer[1]:=$01;
 FT_Out_Buffer[2]:=$02;
 FT_Out_Buffer[3]:=$00;
 Write_USB_Device_Buffer(4);
 Application.ProcessMessages;
 FT_Current_Baud:=FT_BAUD_921600;
 Set_USB_Device_BaudRate;
 Application.ProcessMessages;
 fillmemory(@ft_in_buffer[0],200,$00);
 Application.ProcessMessages;
 Read_USB_Device_Buffer($1);
 if ft_in_buffer[0]<>$01 then exit;
 Application.ProcessMessages;
 read_USB_Device_Buffer($93);
 Application.ProcessMessages;
 Application.ProcessMessages;
 form1._msg('PBL : '+hex2chr(buftohexstr(@FT_in_buffer[23],$0F)));
 Application.ProcessMessages;
 sbl:=TMemoryStream.Create;
 sbl.Seek(0,soFromBeginning);
 sbl.loadfromfile(ExtractFileDir(Application.ExeName)+'\Flash\UFS\SGSBL.bin');
 sbl.Seek(0,soFromBeginning);
 dsize:=sbl.Size;
 Word((@FT_Out_Buffer[0])^):=dsize;
 Write_USB_Device_Buffer(2);
 sbl.Seek(0,soFromBeginning);
 if sbl.size>$A000 then
 begin
  ostlen:=sbl.size;
  packets:=ostlen div $A000;
  if ostlen mod $A000>0 then inc(packets);
  sbl.Seek(0,soFromBeginning);
  currpacketsize:=$A000;
  Application.ProcessMessages;
  for i2:=0 to packets-1 do
  begin
   Application.ProcessMessages;
                    if (i2=Packets-1) and (Packets>1) then
                    begin
                         if (ostlen mod $A000)>0 then CurrPacketSize:=(ostLen mod $A000) else CurrPacketSize:=$A000;
                    end;
   sbl.Readbuffer(FT_Out_Buffer[0], currpacketsize);
   Write_USB_Device_Buffer(currpacketsize);
   Application.ProcessMessages;
   //Form1._msg('Packet : '+inttostr(packets)+' Len : '+inttostr(currpacketsize));
  end;
 end
 else
 begin
 pbl.Readbuffer(FT_Out_Buffer[0], sbl.Size);
 Write_USB_Device_Buffer(sbl.Size);
 end;
 Application.ProcessMessages;
 Sleep(100);
 Application.ProcessMessages;
 FT_Out_Buffer[0]:=$8E; //loadercheck;
 Write_USB_Device_Buffer(1);
 Read_USB_Device_Buffer(1);
 if (ft_in_buffer[0]=$FF) or (ft_in_buffer[0]<>$01)  then
 begin
 form1._msg('Error booting! ALGO [SBL] not accepted!');
 Application.ProcessMessages;
 sbl.Free;
 exit;
 end;
 form1._msg('Algo Ok , '+byte2str(ft_in_buffer[0]));
 Application.ProcessMessages;
 sbl.Free;
 Read_USB_Device_Buffer(1);
 if FT_In_Buffer[0]<>$CC then
 begin
 form1._msg('Error booting! Algo not start ['+byte2str(Ft_in_buffer[0])+']');
 Exit;
 end;
 Application.ProcessMessages;
 form1._msg('SBL mode Ok');
 if FT_In_Buffer[0]<>$CC then
 begin
 form1._msg('Error booting! Info stage failed! ['+byte2str(ft_in_buffer[0])+']');
 Application.ProcessMessages;
 exit;
 end;
 Read_USB_Device_Buffer($4B);
 form1._msg('SBL : '+hex2chr(buftohexstr(@FT_in_buffer[11],$16)));
 Application.ProcessMessages;
 BufCopy(@BLCFG[0],@ft_out_buffer[0],Length(BLCFG));
 Write_USB_Device_Buffer(82);
 Application.ProcessMessages;
 Read_USB_Device_Buffer(12);
 //form1._msg('BL : '+buftohexstr(@FT_in_buffer[0],12));

 BufCopy(@BLCHK[0],@ft_out_buffer[0],Length(BLCHK));
 Write_USB_Device_Buffer(14);
 Application.ProcessMessages;
 Read_USB_Device_Buffer(14);
 Application.ProcessMessages;
 if not CompareTwoHexBuf(@BLCHK[0],@ft_in_buffer[0],14) then
 begin
 form1._msg('Error booting! Check Boot failed! ['+buftohexstr(@ft_in_buffer[0],4)+']');
 Application.ProcessMessages;
 exit;
 end;
 form1._msg('EPP CFG [Bering]...');
 BufCopy(@EPPCFGB[0],@ft_out_buffer[0],Length(EPPCFGB));
 Write_USB_Device_Buffer(182);
 Application.ProcessMessages;
 Read_USB_Device_Buffer(12);
 //form1._msg('BL : '+buftohexstr(@FT_in_buffer[0],12));
 Purge_USB_Device_Out;
 Purge_USB_Device_In;
 BufCopy(@Get_FlashID[0],@ft_out_buffer[0],Length(Get_FlashID));
 Write_USB_Device_Buffer(12);
 Application.ProcessMessages;
 Read_USB_Device_Buffer($10A);
 if FT_In_Buffer[2]<>$84 then
 begin
 form1._msg('Error Get Flash Info! Boot failed! ['+buftohexstr(@ft_in_buffer[0],8)+']');
 Application.ProcessMessages;
 exit;
 end;
 flashven:='';
 flashven:=buftohexstr(@Ft_in_buffer[9],8);
 form1._msg('FLASH ID : '+flashven);
 if flashven='0020000000C08800' then
    Form1._msg('FLASH ID : ST, M58WR064') else
     if flashven='00EC000000542200' then
        Form1._msg('FLASH ID : Samsung, K8S6415E') else
       if  flashven='0000000000000000' then
             Form1._msg('FLASH ID : Damaged/Unknow') else
             Form1._msg('FLASH ID : UNKNOW [Not In Base]');
 BufCopy(@ft_in_buffer[0],@ft_out_buffer[0],$10A);
 ft_out_buffer[2]:=$85;
 ft_out_buffer[$107]:=ft_out_buffer[$107]+1;
 Write_USB_Device_Buffer($10A);
 Application.ProcessMessages;
 Read_USB_Device_Buffer(12);
 //form1._msg('BL : '+buftohexstr(@FT_in_buffer[0],12));
 if (ft_in_buffer[0]<>$02) and (ft_in_buffer[2]<>$85) and (ft_in_buffer[6]<>$FF)
 then
 begin
 form1._msg('Error booting! Check Boot failed! ['+buftohexstr(@ft_in_buffer[0],4)+']');
 Application.ProcessMessages;
 exit;
 end;
 Application.ProcessMessages;
 form1._msg('Boot Done!');
 form1._msg('');
 result:=True;
end;

function InfineonEnd():Boolean;
begin
 result:=false;
 BufCopy(@end_esession[0],@ft_out_buffer[0],length(end_esession));
 Write_USB_Device_Buffer(14);
 Application.ProcessMessages;
 Read_usb_device_buffer(5);
 result:=True;
end;

function sendCert(infcore:string):Boolean;
var
  dtms        : TmemoryStream;
  i           : integer;
  a,b         : byte;
  c           : word;
begin
// sending certificate
  result:=false;
  dtms :=TmemoryStream.create;
  dtms.seek(0,sofrombeginning);
  ParseInfineon(infcore,8,dtms);
  if (dtms.Size<=0) or (dtms.size<>$80C) then
  begin
  dtms.Free;
  Exit;
  end;
  form1._msg('Cert block found, sending....');
  dtms.seek($C,sofrombeginning);
  FT_Out_Buffer[0]:=$02;
  FT_Out_Buffer[1]:=$00;
  FT_Out_Buffer[2]:=$04;
  FT_Out_Buffer[3]:=$02;
  FT_Out_Buffer[4]:=$00;
  FT_Out_Buffer[5]:=$08;
  dtms.ReadBuffer(FT_Out_Buffer[6],$800);
  c:=0;
  b:=(2052 div $100)+1;
  a:=b xor $FF;
  for i:=2 to 2051 do
  begin
  c:=a+FT_Out_Buffer[i];
  a:=a+FT_Out_Buffer[i];
  b:=b+(c shr 8);
  end;
  //a:=a-$A;
  //b:=b+$A;
  FT_Out_Buffer[$806]:=a;
  FT_Out_Buffer[$807]:=b;
  FT_out_buffer[$808]:=$03;
  FT_Out_Buffer[$809]:=$00;
  FillMemory(@ft_in_buffer[0],20,$00);
  //Form1._msg(BufToHexStr(@Ft_out_buffer[0],$80A));
  write_usb_device_buffer($80A);
  Application.ProcessMessages;
  read_usb_device_buffer(12);
  if (ft_in_buffer[0]=$02) and (ft_in_buffer[6]=$01) then
  begin
  form1._msg('Cert sent');
  result:=True
  end
  else
  begin
  form1._msg('Cert not accepted ['+buftohexstr(@ft_in_buffer[0],10)+']');
  result:=false;
  end;
end;

function InfineonErase(infcore:string; curreg:string):Boolean;
var
  erstrt,erstop,wrl   : string;
  rstart,rstop,rwrlen : DWORD;
  i,i2                : Integer;
  cs                  : byte;
  dcs,chkb            : Integer;
  currer              : DWORD;
begin
//erasing region
  result:=False;
//Form1._msg('Erase : '+curreg);
//result:=True;
//Exit;
erstrt:=Copy(curreg,1,8);
erstop:=Copy(curreg,9,8);
wrl:=Copy(curreg,17,8);
currer:=0;
Form1.statusbar.Panels.Items[0].text:='Erasing....';
Application.ProcessMessages;
Form1._msg('Erase , Start : 0x'+erstrt+' , Len : 0x'+wrl);
ft_out_buffer[0]:=$02;
ft_out_buffer[1]:=$00;
ft_out_buffer[2]:=$05;
ft_out_buffer[3]:=$08;
ft_out_buffer[4]:=$08;
ft_out_buffer[5]:=$00;
//fillmemory(@ft_out_buffer[5],20,$FF);
rstart:=0;
rstop:=0;
rstart:=hextoint(erstrt);
DWord((@FT_Out_Buffer[6])^):=rstart;
rstop:=(rstart+hextoint(wrl))-2;
DWord((@FT_Out_Buffer[10])^):=rstop;
///++ ) - 8
cs:=$00; dcs:=0; chkb:=0;
for i:=2 to 13 do
begin
cs:=cs+ft_out_buffer[i];
dcs:=dcs+ft_out_buffer[i];
end;
cs:=cs-$08;
chkb:=dcs div $100;
//form1._msg(inttostr(chkb));
//ft_out_buffer[13]:=$00;
ft_out_buffer[14]:=cs;
ft_out_buffer[15]:=$08+chkb;
ft_out_buffer[16]:=$03;
ft_out_buffer[17]:=$00;
//Form1._msg('TX : '+BufToHexStr(@FT_out_buffer[0],18));
Form1._msg('Erasing, wait ... ');
Write_USB_Device_Buffer(18);
Application.ProcessMessages;
Read_USB_Device_Buffer(12);
if (FT_In_Buffer[0]<>$02) and (FT_In_Buffer[3]<>$08) and (FT_In_Buffer[8]<>$0F) then
Form1._msg('ERR : '+BufToHexStr(@Ft_in_buffer[0],10))
else Application.ProcessMessages;
rwrlen:=hextoint(wrl);
form1.pb1.MaxValue:=rstop-rstart;
Form1.pb1.ForeColor:=clYellow;
 repeat
 BufCopy(@chhkerase[0],@Ft_out_buffer[0],12);
 Write_USB_Device_Buffer(12);
 Application.ProcessMessages;
 Read_USB_Device_Buffer(16);
 if FT_In_Buffer[6]=$01 then Break;
 if FT_In_Buffer[4]<>$06 then Break;
 Application.ProcessMessages;
 DWordSwap(@Ft_in_buffer[7]);
 Application.ProcessMessages;
 currer:=HexToInt(BufToHexStr(@Ft_in_buffer[7],4));
 Form1.pb1.Progress:=currer-rstart;
 Application.ProcessMessages;
 Form1.statusbar.Panels.Items[1].text:='CMT : 0x'+BufToHexStr(@Ft_in_buffer[7],4);
 Application.ProcessMessages;
 until FT_In_Buffer[6]=$01;
 if (FT_In_Buffer[4]=$06) and (FT_In_Buffer[6]=$01) then
 begin
 Form1._msg('Erase done');
 result:=True;
 end
 else
 begin
 Form1._msg('Erase Error ['+buftohexstr(@FT_in_buffer[0],14)+']');
 result:=false;
 end;
 Application.ProcessMessages;
 Form1.statusbar.Panels.Items[1].text:='';
 Form1.statusbar.Panels.Items[0].text:='';
 Form1.pb1.ForeColor:=clNavy;
 form1.pb1.MaxValue:=100;
 form1.pb1.Progress:=0;
 Application.ProcessMessages;
end;

function InfineonWrite(infcore:string; mode:Integer; dlen:string):Boolean;
var
   prgstart,
   prglen    : string;
   rstrt     : dword ;
   i         : Integer;
   cs        : Byte;
   Flstream  : TMemoryStream;
   a,b       : byte;
   c         : word;
   bb        : Boolean;
   ostlen,
   packets,
   i2,
   currpacketsize : integer;
   dcs,chkb       : Integer;
begin
//writing region
// set start adress
prgstart:=Copy(dlen,1,8);
prglen:=Copy(dlen,17,8);
Form1.statusbar.Panels.Items[0].text:='Write Data....';
form1._msg('Write , Start : 0x'+prgstart+' , Len : 0x'+prglen);
Application.ProcessMessages;
ft_out_buffer[0]:=$02;
ft_out_buffer[1]:=$00;
ft_out_buffer[2]:=$02;
ft_out_buffer[3]:=$08;
ft_out_buffer[4]:=$04;
ft_out_buffer[5]:=$00;
rstrt:=hextoint(prgstart);
DWord((@FT_Out_Buffer[6])^):=rstrt;
cs:=$00; dcs:=0; chkb:=0;
for i:=2 to 9 do
begin
cs:=cs+ft_out_buffer[i];
dcs:=dcs+ft_out_buffer[i];
end;
cs:=cs-$08;
chkb:=dcs div $100;
ft_out_buffer[10]:=cs;
ft_out_buffer[11]:=$08+chkb;
ft_out_buffer[12]:=$03;
ft_out_buffer[13]:=$00;
//Form1._msg('TX : '+BufToHexStr(@FT_out_buffer[0],14));
Write_USB_Device_Buffer(14);
Application.ProcessMessages;
Read_USB_Device_Buffer(12);
if (FT_In_Buffer[0]<>$02) and (FT_In_Buffer[3]<>$08) and (FT_In_Buffer[8]<>$0C) then
Form1._msg('ERR : '+BufToHexStr(@Ft_in_buffer[0],10))
else Form1._msg('Flashing , wait ...');
Flstream:=TMemoryStream.Create;
ParseInfineon(infcore,mode,flstream);
 if (Flstream.Size<$29) and (Flstream=nil) then
 begin
 form1._msg('No write data, skip');
 Flstream.Free;
 result:=true;
 Exit;
 end;
Flstream.Seek(0,soFromBeginning);
//Flstream.savetofile('C:\data_write.bin');
Application.ProcessMessages;
if (Flstream.Size-$28)<>HexToInt(prglen) then form1._msg('Check cert <=> flash failed! Trying continue...');
Application.ProcessMessages;
Flstream.Seek(40,soFromBeginning);
//(Flstream.Size-$28)
 bb:=True;
 ostlen:=(Flstream.Size-$28);
 packets:=ostlen div $800;
 if ostlen mod $800>0 then inc(packets);
 currpacketsize:=$800;
 Form1.pb1.MaxValue:=packets;
 Form1.pb1.ForeColor:=clGreen;
 Form1.pb1.Progress:=0;
 Application.ProcessMessages;
 for i2:=0 to packets-1 do
 begin
 Application.ProcessMessages;
  if (i2=Packets-1) and (Packets>=1) then
  begin
  if (ostlen mod $800)>0 then CurrPacketSize:=(ostLen mod $800) else CurrPacketSize:=$800;
  end;
 Application.ProcessMessages;
 Form1.statusbar.Panels.Items[1].text:='CMT : '+inttostr(i2)+'/'+inttostr(packets-1);
 Application.ProcessMessages;
 //form1._msg(inttostr(ostlen mod $800));
 FT_Out_Buffer[0]:=$02;
 FT_Out_Buffer[1]:=$00;
 FT_Out_Buffer[2]:=$04;
 FT_Out_Buffer[3]:=$08;
 FT_Out_Buffer[4]:=$00;
 FT_Out_Buffer[5]:=$00;
 word((@Ft_out_buffer[4])^):=currpacketsize;
 Flstream.ReadBuffer(FT_Out_Buffer[6],currpacketsize);
 Application.ProcessMessages;
  // inpacket crc
  c:=0;
  b:=(currpacketsize div $100)+7;
  a:=b xor $FF;
  for i:=2 to (currpacketsize+5) do
  begin
  c:=a+FT_Out_Buffer[i];
  a:=a+FT_Out_Buffer[i];
  b:=b+(c shr 8);
  end;
  ///
  //form1._msg(byte2str(a)+byte2str(b));
  Application.ProcessMessages;
 FT_Out_Buffer[currpacketsize+6]:=a;
 FT_Out_Buffer[currpacketsize+7]:=b;
 FT_Out_Buffer[currpacketsize+8]:=$03;
 FT_Out_Buffer[currpacketsize+9]:=$00;
 Application.ProcessMessages;
 //Form1._msg('RX : '+buftohexstr(@ft_out_buffer[0], currpacketsize+$0A));
 Write_USB_Device_Buffer(currpacketsize+$A);
 Application.ProcessMessages;
 Read_USB_Device_Buffer(12);
 if (FT_In_Buffer[0]<>$02) or (FT_In_Buffer[2]<>$04) and (FT_In_Buffer[10]<>$03) then
  begin
  Form1._msg('Error, '+inttostr(i2)+' , data missmatch! ['+buftohexstr(@ft_in_buffer[0],10)+']');
  Application.ProcessMessages;
  bb:=False;
  Break;
  end;
 Application.ProcessMessages;
 //form1._msg(buftohexstr(@ft_in_buffer[0],12));
 Form1.pb1.Progress:=Form1.pb1.Progress+1;
 Application.ProcessMessages;
 end;
 if bb=true then
 begin
 Form1._msg('Region flash done');
 result:=true;
 end
 else
 begin
 Form1._msg('Region flash error');
 result:=False;
 end;
 Application.ProcessMessages;
 Form1.statusbar.Panels.Items[1].text:='';
 Form1.statusbar.Panels.Items[0].text:='';
 Form1.pb1.ForeColor:=clNavy;
 form1.pb1.MaxValue:=100;
 form1.pb1.Progress:=0;
 Application.ProcessMessages;
end;

function getchecksum(infcore:string):Boolean;
begin
// check CS file CS data
end;

function infgetblockcnt(infcore:string; Erlist:Tstringlist):Integer;
var
  dstrm : Tmemorystream;
  i     : integer;
begin
// get count block, fill list of regions
  dstrm:=TMemoryStream.Create;
  ParseInfineon(infcore,8,dstrm);
  if (dstrm.Size<40) or (dstrm=nil)
  then
  begin
  dstrm.Free;
  result:=0;
  Form1._msg('Error on file prepare, probably damaged!');
  Exit;
  end;
  result:=GetEraseBlk(dstrm,Erlist);
end;

function checkready():Boolean;
begin
  result:=False;
 BufCopy(@chhkerase[0],@Ft_out_buffer[0],12);
 Write_USB_Device_Buffer(12);
 Application.ProcessMessages;
 Read_USB_Device_Buffer(16);
 if FT_In_Buffer[6]=$01 then result:=true;
 //Form1._msg(BufToHexStr(@ft_in_buffer[0],16));
 //if FT_In_Buffer[4]<>$06 then exit;
end;

function getchksuminf():Boolean;
begin
    result:=False;
 BufCopy(@getscss[0],@ft_out_buffer[0],12);
 Write_USB_Device_Buffer(12);
 Application.ProcessMessages;
 Read_USB_Device_Buffer(14);
 if FT_In_Buffer[0]=$02 then result:=true;
 Form1._msg('Check : '+BufToHexStr(@ft_in_buffer[8],2));
 //if FT_In_Buffer[6]<>$01 then result:=false;
end;

function FlashInfineonFile(FlasHfile:string):Boolean;
var
  i,cnt:integer;
  imgs:string;
  EraseList : TStringList;
begin
 result:=False;
 i:=0; cnt:=0;
 //form1._msg('');
 Application.ProcessMessages;
 Form1._msg('File : '+extractfilename(flashfile));
 Application.ProcessMessages;
 imgs:=getFwinfo(flashfile);
 if imgs='' then Exit;
 form1._msg('Image : '+imgs);
 //Exit;
 if not sendCert(FlasHfile) then Exit;
 EraseList:=TStringList.Create;
 cnt:=infgetblockcnt(FlasHfile,EraseList);
 form1._msg('Found '+inttostr(cnt)+' region(s)');
 for i:=0 to cnt-1 do
 begin
 form1._msg('Processing Region '+inttostr(i+1)+'/'+inttostr(cnt));
 if not InfineonErase(Flashfile,EraseList[i]) then Exit;
 if not InfineonWrite(Flashfile,i+1,EraseList[i]) then Exit;
 Application.ProcessMessages;
 Sleep(50);
 Application.ProcessMessages;
 end;
 Application.ProcessMessages;
 Sleep(150);
 Application.ProcessMessages;
 if not checkready then Form1._msg('Check error!');
 Application.ProcessMessages;
 Sleep(150);
 Application.ProcessMessages;
 if not getchksuminf then Form1._msg('Error on Verify');
 Application.ProcessMessages;
  Sleep(50);
 Application.ProcessMessages;
 result:=true;
end;


function halfboot():Boolean;
var
  pbl,sbl,dstr : TMemoryStream;
  i:integer;
  dsize: word;
  ostlen,packets,i2 : integer;
  currpacketsize      : integer;
  chkbuf       : array of Byte;
  loadercheck  : byte;
  check:Word;
begin
result:=false;
check:=0;
Reset_USB_Device;
Set_USB_Device_TimeOuts($2710,$2710);
 pbl:=TMemoryStream.Create;
 pbl.Seek(0,soFromBeginning);
 pbl.LoadFromFile(ExtractFileDir(Application.ExeName)+'\Flash\UFS\SGPBL.bin');

 dsize:=pbl.Size;
 Purge_USB_Device_Out;
 Purge_USB_Device_In;
 FT_Out_Buffer[0]:=$30;
 Word((@FT_Out_Buffer[1])^):=dsize;
 Write_USB_Device_Buffer(3);

 pbl.Seek(0,soFromBeginning);
 if pbl.size>$10000 then
 begin
  ostlen:=pbl.size;
  packets:=ostlen div $10000;
  if ostlen mod $10000>0 then inc(packets);
  pbl.Seek(0,soFromBeginning);
  currpacketsize:=$10000;
  Application.ProcessMessages;
  for i2:=0 to packets-1 do
  begin
   Application.ProcessMessages;
                    if (i2=Packets-1) and (Packets>1) then
                    begin
                         if (ostlen mod $10000)>0 then CurrPacketSize:=(ostLen mod $10000) else CurrPacketSize:=$10000;
                    end;
   pbl.Readbuffer(FT_Out_Buffer[0], currpacketsize);
   Write_USB_Device_Buffer(currpacketsize);
   Application.ProcessMessages;
   //Form1._msg('Packet : '+inttostr(packets)+' Len : '+inttostr(currpacketsize));
  end;
 end
 else
 begin
 pbl.Readbuffer(FT_Out_Buffer[0], pbl.Size);
 Write_USB_Device_Buffer(pbl.Size);
 end;
 Application.ProcessMessages;
 Sleep(200);
 Application.ProcessMessages;
 FT_Out_Buffer[0]:=$FE; //loadercheck;
 Write_USB_Device_Buffer(1);
 Read_USB_Device_Buffer(1);
 if ft_in_buffer[0]<>$01 then
 begin
 form1._msg('Error booting! 2nd [PBL] not accepted!');
 pbl.Free;
 exit;
 end;
 form1._msg('Boot Ok , '+byte2str(ft_in_buffer[0]));
 Read_USB_Device_Buffer(1);
 pbl.Free;
 Application.ProcessMessages;
 Purge_USB_Device_Out;
 Purge_USB_Device_In;
 Application.ProcessMessages;
 Sleep(100);
 Application.ProcessMessages;
 FT_Out_Buffer[0]:=$B4;
 FT_Out_Buffer[1]:=$01;
 FT_Out_Buffer[2]:=$02;
 FT_Out_Buffer[3]:=$00;
 Write_USB_Device_Buffer(4);
 Application.ProcessMessages;
 FT_Current_Baud:=FT_BAUD_921600;
 Set_USB_Device_BaudRate;
 Application.ProcessMessages;
 fillmemory(@ft_in_buffer[0],200,$00);
 Application.ProcessMessages;
 Read_USB_Device_Buffer($1);
 if ft_in_buffer[0]<>$01 then exit;
 psi:='';
 Application.ProcessMessages;
 read_USB_Device_Buffer($93);
 Application.ProcessMessages;
// form1._msg('PSI Data : '+buftohexstr(@FT_in_buffer[0],$93));
 psi:='01'+buftohexstr(@FT_in_buffer[0],$93);
 Application.ProcessMessages;
 form1._msg('PBL : '+hex2chr(buftohexstr(@FT_in_buffer[23],$0F)));
 Application.ProcessMessages;
 sbl:=TMemoryStream.Create;
 sbl.Seek(0,soFromBeginning);
 sbl.loadfromfile(ExtractFileDir(Application.ExeName)+'\Flash\UFS\SGSBL.bin');
 sbl.Seek(0,soFromBeginning);
 dsize:=sbl.Size;
 Word((@FT_Out_Buffer[0])^):=dsize;
 Write_USB_Device_Buffer(2);
 sbl.Seek(0,soFromBeginning);
 if sbl.size>$A000 then
 begin
  ostlen:=sbl.size;
  packets:=ostlen div $A000;
  if ostlen mod $A000>0 then inc(packets);
  sbl.Seek(0,soFromBeginning);
  currpacketsize:=$A000;
  Application.ProcessMessages;
  for i2:=0 to packets-1 do
  begin
   Application.ProcessMessages;
                    if (i2=Packets-1) and (Packets>1) then
                    begin
                         if (ostlen mod $A000)>0 then CurrPacketSize:=(ostLen mod $A000) else CurrPacketSize:=$A000;
                    end;
   sbl.Readbuffer(FT_Out_Buffer[0], currpacketsize);
   Write_USB_Device_Buffer(currpacketsize);
   Application.ProcessMessages;
   //Form1._msg('Packet : '+inttostr(packets)+' Len : '+inttostr(currpacketsize));
  end;
 end
 else
 begin
 pbl.Readbuffer(FT_Out_Buffer[0], sbl.Size);
 Write_USB_Device_Buffer(sbl.Size);
 end;
 Application.ProcessMessages;
 Sleep(100);
 Application.ProcessMessages;
 FT_Out_Buffer[0]:=$8E; //loadercheck;
 Write_USB_Device_Buffer(1);
 Read_USB_Device_Buffer(1);
 if (ft_in_buffer[0]=$FF) or (ft_in_buffer[0]<>$01)  then
 begin
 form1._msg('Error booting! ALGO [SBL] not accepted!');
 Application.ProcessMessages;
 sbl.Free;
 exit;
 end;
 form1._msg('Algo Ok , '+byte2str(ft_in_buffer[0]));
 Application.ProcessMessages;
 sbl.Free;
 Read_USB_Device_Buffer($4C);
 if FT_In_Buffer[0]<>$CC then
 begin
 form1._msg('Error booting! Info stage failed! ['+byte2str(ft_in_buffer[0])+']');
 Application.ProcessMessages;
 exit;
 end;
 form1._msg('SBL mode Ok');
 form1._msg('SBL : '+hex2chr(buftohexstr(@FT_in_buffer[12],$16)));

 Application.ProcessMessages;
 bufcopy(@ft_in_buffer[0],@ft_out_buffer[6],$48);
 ft_out_buffer[0]:=$02;
 ft_out_buffer[1]:=$00;
 Word((@ft_out_buffer[2])^):=$86;
 Word((@ft_out_buffer[4])^):=$48;
 check:=$86+$48;
 ft_out_buffer[$36]:=$00;
 ft_out_buffer[$37]:=$00;
 for i:=6 to 5+$48 do check:=check+FT_Out_Buffer[i];
 Word((@ft_out_buffer[$4E])^):=check;
 Word((@ft_out_buffer[$50])^):=$03;
 Word((@ft_out_buffer[$51])^):=$00;
 //Form1._msg(buftohexstr(@ft_out_buffer[0],82));
 Write_USB_Device_Buffer(82);
 Application.ProcessMessages;
 Read_USB_Device_Buffer(12);
 //Form1._msg(buftohexstr(@ft_in_buffer[0],12));
 result:=True;
end;

procedure dumpregionepp(start,stop:dword ; resstr:Tmemorystream);
var
  len:dword;
  i,i2,j,j2:integer;
  eblcur:dword;
  tempstream:Tmemorystream;
begin
  len:=0;
  len:=stop-start;
  eblcur:=0;
  eblcur:=start;
  resstr.seek(0,soFromBeginning);
  form1.pb1.MaxValue:=len div $800;
  for i:=1 to (len div $800) do
  begin
   EBLcomandStartRead($80b,eblcur);
   Write_USB_Device_Buffer(14);
   Application.ProcessMessages;
   Read_USB_Device_Buffer(12);
   //if ft_in_buffer[8]<>$15 then break;
   Application.ProcessMessages;
   EBLcomandRead($803,$800);
   Write_USB_Device_Buffer(12);
   Application.ProcessMessages;
   fillmemory(@ft_in_buffer[0],$80A,$00);
   Application.ProcessMessages;
   Read_USB_Device_Buffer($80A);
   resstr.Write(ft_in_buffer[6],$800);
   form1.pb1.progress:=form1.pb1.progress+1;
   Application.ProcessMessages;
   Inc(eblcur,$800);
  end;
  form1.pb1.Progress:=0;
end;

procedure dumpppmcatalog(start,stop:dword ; resstr:Tmemorystream);
var
  len:dword;
  i,i2,j,j2:integer;
  eblcur:dword;
  tempstream:Tmemorystream;
begin
  len:=0;
  len:=stop-start;
  eblcur:=0;
  eblcur:=start;
  resstr.seek(0,soFromBeginning);
  form1.pb1.MaxValue:=len div $4000;
  for i:=1 to (len div $4000) do
  begin
   EBLcomandStartRead($80b,eblcur);
   Write_USB_Device_Buffer(14);
   Application.ProcessMessages;
   Read_USB_Device_Buffer(12);
   if ft_in_buffer[8]<>$15 then break;
   Application.ProcessMessages;
   EBLcomandRead($803,$800);
   Write_USB_Device_Buffer(12);
   Application.ProcessMessages;
   fillmemory(@ft_in_buffer[0],$80A,$00);
   Application.ProcessMessages;
   Read_USB_Device_Buffer($80A);
   if (FT_In_Buffer[8]=$f8) and (FT_In_Buffer[12]=$50) and (FT_In_Buffer[13]=$4D)
    then
    begin
     resstr.Write(ft_in_buffer[6],$800);
     inc(eblcur,$800);
     for j:=1 to 7 do
     begin
     EBLcomandStartRead($80b,eblcur);
     Write_USB_Device_Buffer(14);
     Application.ProcessMessages;
     Read_USB_Device_Buffer(12);
      //if ft_in_buffer[8]<>$15 then break;
     Application.ProcessMessages;
     EBLcomandRead($803,$800);
     Write_USB_Device_Buffer(12);
     Application.ProcessMessages;
     fillmemory(@ft_in_buffer[0],$80A,$00);
     Application.ProcessMessages;
     Read_USB_Device_Buffer($80A);
     resstr.Write(ft_in_buffer[6],$800);
     form1.pb1.progress:=form1.pb1.progress+1;
     Application.ProcessMessages;
     inc(eblcur,$800);
     end;
    end
   else Inc(eblcur,$4000);
   form1.pb1.progress:=form1.pb1.progress+1;
   Application.ProcessMessages;
  end;
  form1.pb1.Progress:=0;
end;

function busreset():boolean;
var
  ic,dc:integer;
begin
  result:=false;
  //reset_usb_device;
   FT_Out_Buffer[0] := $4C;
   FT_Out_Buffer[1] := $1D;
   FT_Out_Buffer[2] := $1D;
   FT_Out_Buffer[3] := $1F;
   FT_Out_Buffer[4] := $02;
   FT_Out_Buffer[5] := $0D;
   FT_Out_Buffer[6] := $98;
   Write_USB_Device_Buffer(7);   //(7,$5, 300);
   // set ufs commands speed to 115200
   FT_Out_Buffer[0] := $42;  //  >> just send this no reply needed
   FT_Out_Buffer[1] := $10;
   Write_USB_Device_Buffer(2);
   //Set UFS to Atmel MODE first
   Reset_USB_Device ;
   Purge_USB_Device_Out;
   Purge_USB_Device_In;
   Set_USB_Device_DTR;
   Purge_USB_Device_Out;
   Purge_USB_Device_In;
   FT_Current_FlowControl := 0;
   Set_USB_Device_FlowControl;
   Set_USB_Device_TimeOuts(2000,5000);
   Set_USB_Device_BaudRate_Divisor($1A); 
   FT_out_Buffer[0] := $58;   // 
   Write_USB_Device_Buffer(1);
   sleep(5);
   Read_USB_Device_Buffer(1);
   FT_Out_Buffer[0] := $32;   
   Write_USB_Device_Buffer(1);
   Read_USB_Device_Buffer(1);
   FT_out_Buffer[0] := $68;    
   FT_out_Buffer[1] := $01;
   Write_USB_Device_Buffer(2);
   sleep(5);
   Read_USB_Device_Buffer(1);
   FT_Out_Buffer[0] := $67;  
   sleep(5);
   Write_USB_Device_Buffer(1);
   sleep(5);
   Read_USB_Device_Buffer(1);
   Set_USB_Device_FlowControl;
   Purge_USB_Device_Out;
   Purge_USB_Device_In;
   Set_USB_Device_DTR;
   Purge_USB_Device_Out;
   Purge_USB_Device_In;
   FT_Out_Buffer[0] := $68;  
   FT_Out_Buffer[1] := $00;
   sleep(5);
   Write_USB_Device_Buffer(2);
   sleep(5);
   Read_USB_Device_Buffer(1);
   FT_Out_Buffer[0] := $66;   
   sleep(5);
   Write_USB_Device_Buffer(1);
   sleep(5);
   Set_USB_Device_DTR;
   Purge_USB_Device_Out;
   Purge_USB_Device_In;
   Set_USB_Device_FlowControl;
   Set_USB_Device_BaudRate_Divisor($1A) ;
   FT_Current_DataBits := $8;
   FT_Current_StopBits := $1;
   FT_Current_Parity := $0;
   Set_USB_Device_DataCharacteristics;    //DataBits: 8, StopBits: 0 , Parity: 0
   Set_USB_Device_TimeOuts(8000,8000);
   Reset_USB_Device ;
   Purge_USB_Device_Out;
   Purge_USB_Device_In;
   FT_out_Buffer[0] := $A5;   // #$A5      >> must read 1 byte
   Write_USB_Device_Buffer(1);
   sleep(5);
   Read_USB_Device_Buffer(1);
   if ft_in_buffer[0]=$c3 then result:=true;
   Clr_USB_Device_DTR;
   Purge_USB_Device_Out;
   Purge_USB_Device_In;
   Set_USB_Device_TimeOuts($50,$50);
end;


end.
