unit DeviceRD;

interface

uses D2xxUnit, SysUtils, dialogs, Windows, math, ExtCtrls, Controls, user_types;

//пользовательские типы
type
//непосредственно класс устройства
  TDevice = class (TObject)
    private
      connected       :boolean;    //существует ли связь с прибором.
      port_opened     :boolean;    //открыт ли порт прибора
      device_name     :string;     //Название прибора
      device_serial_no:string;     //Серийный номер прибора
      const version = '0.4.4';
      function copy_col(Al:TMatrix; Bl:TCol; coll:integer):TMatrix;
      function det5(A:TMatrix):extended;



   public
      message_    :    message_Array;
      timer       :TTimer;     //таймер на подключение прибора

      procedure TimerTimer(Sender: TObject);
      constructor Create();
      //destructor  Destroy();
      function  IsConnected:boolean;
      function  IsPortOpened:boolean;
      procedure Close_thread;
      function  Show_device_name:string;
      function  Show_device_serial_no:string;

      function message_decode(massiv:message_Array):params_record;

      procedure Start_waiting(mode:integer);

     // procedure  receive;
     // procedure  Check_device;
      procedure  Open_device;
      procedure  Close_usb;
    protected
      { protected declarations }
end;

implementation

uses MainUnit, device_thread, ConstUnit;

var TTH: device_thread_th;

procedure TDevice.Close_thread;
begin
  TTH.Suspend;
  //TTH.Terminate;
  //FreeAndNil(TTH);

end;

procedure TDevice.Close_usb;
begin
   connected:=false;
   Port_opened:=false;
   Close_USB_device;
end;

constructor TDevice.Create;
var device_index,i:integer;
begin
GetFTDeviceCount;
FT_Enable_Error_Report := true;
connected:=false;
port_opened:=false;
Device_Index := 0;
//предполагается что устройств всегда будет только одно
If FT_Device_Count > 0 then
  For  i:=1 to FT_Device_Count do
  Begin
      GetFTDeviceSerialNo(Device_Index);
      device_serial_no:=FT_Device_String;
      GetFTDeviceDescription ( Device_Index );
      Device_Index := Device_Index + 1;
      connected:=true;
  End;
//создаем таймер для проверки подключения прибора
timer:=TTimer.Create(MainForm);
timer.Interval:=1000;
Timer.OnTimer:=TimerTimer;
end;

procedure TDevice.TimerTimer(Sender: TObject);
begin
//получаем количество подключенных устройств,
//считаем если их больше 0, то прибор подключен
GetFTDeviceCount;
if FT_Device_Count>0 then
  begin
    if not connected then
      begin
        MainForm.new_izm_warning_label.Caption:=devicerd_device_just_connected;
        //sleep(6000);
        //Open_device;

        //MainForm.enabled:=true;
      end;
  end
else
  if connected then
  begin
    Close_usb;
  end;
end;

{destructor TDevice.Destroy;
begin
If port_opened then begin
Set_USB_Device_BitMode($ff,0);
Purge_USB_Device_In;
Purge_USB_Device_Out;
Close_USB_Device;
end
else //Close_USB_Device;
end;
}
{Procedure Tdevice.Check_device;
Var
    PortStatus : FT_Result;
    device_index,i :integer;
begin
FT_Enable_Error_Report := true;
If Not Connected then
    Begin
      Close_USB_Device; // In case device was already open
      If Open_USB_Device = FT_OK then      // Device is Now Present !
          Begin
            Connected := True;
            //Reset_USB_Device;     // warning - this will destroy any pending data.
            //получаем информацию о приборе
            device_index:=0;
            if FT_Device_Count > 0 then
              For  i:= 1 to FT_Device_Count do
                  Begin
                    GetFTDeviceSerialNo(Device_Index );
                    device_serial_no:=FT_Device_String;
                    GetFTDeviceDescription ( Device_Index );
                    device_desc:=FT_Device_String;
                    Device_Index := Device_Index + 1;
                  End;
          End;
    End
else
    Begin
      PortStatus := Get_USB_Device_QueueStatus;
      If PortStatus <> FT_OK then
          begin   // Device has been Unplugged
            Connected := False;
          end
          else
          //
    End;
end;
}
Procedure TDevice.Open_device;
begin
{if port_opened then
begin
  //Reset_USB_Device;
  //Close_USB_Device; // In case device was already open

end;  }
GetFTDeviceCount;
If Open_USB_Device_By_Serial_Number(device_serial_no) = FT_OK then
begin
  Set_USB_Parameters(16384,16384); //размеры буферов
  FT_Current_Baud:=FT_BAUD_921600;
  if (not Set_USB_Device_BaudRate = FT_OK) then
    MessageBox(0,
               PChar('Ошибка при установки скорости соединения'),
               PChar('Ошибка устройства'),
               MB_ICONERROR or MB_OK
              );

  FT_Current_DataBits:=FT_DATA_BITS_8;
  FT_Current_StopBits:=FT_STOP_BITS_1;
  FT_Current_Parity:=FT_PARITY_NONE;

  if (not Set_USB_Device_DataCharacteristics = FT_OK) then
       MessageBox(0,
               PChar('Ошибка при установке параметров(Бит,СтопБит,Паритет)'),
               PChar('Ошибка устройства'),
               MB_ICONERROR or MB_OK
              );

  if not Set_USB_Device_TimeOuts(5,5) = FT_OK then
       MessageBox(0,
               PChar('Ошибка при установке таймаутов'),
               PChar('Ошибка устройства'),
               MB_ICONERROR or MB_OK
              );
  if not Set_USB_Device_BitMode($ff,0) = FT_OK then
        MessageBox(0,
               PChar('Ошибка при выключении Bit Mode'),
               PChar('Ошибка устройства'),
               MB_ICONERROR or MB_OK
              );
  if (not Purge_USB_Device_In = FT_OK) and (Purge_USB_Device_Out = FT_OK) then
        MessageBox(0,
               PChar('Ошибка при очистке буферов I/O'),
               PChar('Ошибка устройства'),
               MB_ICONERROR or MB_OK
              );


port_opened:=true;
Reset_USB_Device;     // warning - this will destroy any pending data.
Set_USB_Device_TimeOuts(500,500); // read and write timeouts = 500mS
end
else  MessageBox(0,
               PChar('Ошибка при открытии устройства. Проверьте подключение'),
               PChar('Ошибка устройства'),
               MB_ICONERROR or MB_OK
              );
end;

procedure TDevice.Start_waiting(mode:integer);
begin
if mode=1 then
    begin
      TTH:=device_thread_th.Create(true);
     // sleep(500);
     // TTH.Resume;

    end;
if mode=2 then
     TTH.Resume;
end;
//разбор посылки
function TDevice.message_decode(massiv: message_Array):params_record;
const N=2400;                   //количество замеров тока и напряжения
      T2=0.00083717036416911;   //время в секундах между отсчетами
      Ki=33554431999999.996;    //коэф. пересчета из целочисленных в реальные тока
      Ku=3355443.2;             //коэф. пересчета из целочисленных в реальные напряжения


var k,                         //текущее значение строчки в массиве измерения
    i,                         //счетчик в цикле
    drei:integer;
    a1,b1,c1,d1,a2,b2,c2,d2:   //временные переменные для составных частей посылки
    extended;

    U0,                        //
    I0,                        //
    Ud0,                       //
    Up0,
    Det0            :Extended;
    A: TMatrix;
    B: TCol;
  j: Integer;
    
begin
///инициализация переменных
//setlength(a,5,5);
U0:=0;Ud0:=0; I0:=0;
  k:=-9;
for I:= 0 to 4 do
begin
  B[i]:=0;
  for j:= 0 to 4 do
    A[i,j]:=0;
end;
a1:=0;
b1:=0;
c1:=0;
d1:=0;

a2:=0;
b2:=0;
c2:=0;
d2:=0;

for I := 0 to length(result.I_izm) - 1 do
begin
  result.I_izm[i]:=0;
  result.U_izm[i]:=0;
end;

//ошибки
result.U_mis:=false;
result.I_mis:=false;;

for i:=0 to N do
		begin
			k:=k+10;
			//разбор блока значений напряжения
			//вся посылка 5 байт


      a1:=(((((massiv[k] shl 4) and $80) or massiv[k+1]) shl 24) and $FF000000);
      b1:=(((((massiv[k] shl 5) and $80) or massiv[k+2]) shl 16) and $FFFF0000);
      c1:=(((((massiv[k] shl 6) and $80) or massiv[k+3]) shl 8) and  $FFFFFF00);
      d1:=(((((massiv[k] shl 7) and $80) or massiv[k+4]) shl 0) and $FFFFFFFF);

      result.U_izm[i]:=a1+b1+c1+d1;


          a2:=(((((massiv[k+5] shl 4) and $80) or massiv[k+6]) shl 24) and $FF000000);
          b2:=(((((massiv[k+5] shl 5) and $80) or massiv[k+7]) shl 16) and $FFFF0000);
          c2:=(((((massiv[k+5] shl 6) and $80) or massiv[k+8]) shl 8) and  $FFFFFF00);
          d2:=(((((massiv[k+5] shl 7) and $80) or massiv[k+9]) shl 0) and $FFFFFFFF);

    result.I_izm[i]:=a2+b2+c2+d2;
//начало нарастания 977 отсчет


       { ///Подсчёт значений R, g0, g1, g2, g3, C силами программы
        if (i=1000) then Ud0:=a1+b1+c1+d1;
				if (i=1001) then
          begin
            U0:=a1+b1+c1+d1;
            I0:=a2+b2+c2+d2;
          end;
        if ((i>=1002)and(i<=2201)) then
          begin
            Up0:=a1+b1+c1+d1;

				    A[0,0]:=A[0,0]+intpower(U0,2);
				    A[0,1]:=A[0,1]+intpower(U0,3);
				    A[0,2]:=A[0,2]+intpower(U0,4);
				    A[0,3]:=A[0,3]+intpower(U0,5);
				    A[1,3]:=A[1,3]+intpower(U0,6);
				    A[2,3]:=A[2,3]+intpower(U0,7);
				    A[3,3]:=A[3,3]+intpower(U0,8);
				    A[0,4]:=A[0,4]+U0*(Up0-Ud0);
				    A[1,4]:=A[1,4]+intpower(U0,2)*(Up0-Ud0);
				    A[2,4]:=A[2,4]+intpower(U0,3)*(Up0-Ud0);
				    A[3,4]:=A[3,4]+intpower(U0,4)*(Up0-Ud0);
				    A[4,4]:=A[4,4]+intpower((Up0-Ud0),2);
            //приводим к диагональному виду матрицу А
				    A[1,0]:=A[0,1]; A[2,0]:=A[0,2]; A[3,0]:=A[0,3]; A[3,1]:=A[1,3];
            A[4,0]:=A[0,4]; A[3,2]:=A[2,3]; A[4,1]:=A[1,4];	A[4,2]:=A[2,4];
            A[4,3]:=A[3,4];
            //НЕ ПОНЯТНО!!!!!!!!!!!!!!!
            A[1,1]:=A[0,2];  A[1,2]:=A[0,3]; A[2,1]:=A[0,3]; A[2,2]:=A[1,3];

            //формируем столбец В
				    B[0]:=B[0]+I0*U0;
				    B[1]:=B[1]+I0*intpower(U0,2);
				    B[2]:=B[2]+I0*intpower(U0,3);
				    B[3]:=B[3]+I0*intpower(U0,4);
				    B[4]:=B[4]+I0*(Up0-Ud0);

				    I0:=a2+b2+c2+d2;
				    Ud0:=U0;
				    U0:=Up0;
          end;
       if i=2390 then
          begin

           Det0:=det5(A);
           result.g0:=det5(copy_col(A,B,0))/Det0*Ku/Ki;
           result.g1:=det5(copy_col(A,B,1))/Det0*Ku/Ki*Ku;
           result.g2:=det5(copy_col(A,B,2))/Det0*Ku/Ki*Ku*Ku;
           result.g3:=det5(copy_col(A,B,3))/Det0*Ku/Ki*Ku*Ku*Ku;
           result.C:=det5(copy_col(A,B,4))/Det0*Ku/Ki*T2;
           result.R:= 1/result.g0;
           //result.Usm:=det5(copy_col(A,B,3))/Det0*Ku/Ki*Ku*Ku*Ku;
           }

           result.g0:=0;
           result.g1:=0;
           result.g2:=0;
           result.g3:=0;
           result.C:=0;
           result.R:= 0;
           result.Usm:=0;
         //end;
       //2392 - байт ошибки
       //канал U-выход за диапазон измерения
       //канал I - отпустили электрод
       if i=2392 then
       begin

        if a1+b1+c1+d1<>0 then result.U_mis:=true;
        if a2+b2+c2+d2<>0 then result.I_mis:=true;


       end;

       if i>=2393 then
          begin
           drei:=round(result.I_izm[i]-round(result.I_izm[i]/intpower(2,24))*intpower(2,24)-1023);
           if i=2393 then
              begin
                if round(result.I_izm[i]/intpower(2,24)) mod 2=0 then
                    result.R_e:=result.U_izm[i]/intpower(2,30)*intpower(2,drei)
                else result.R_e:=-1*result.U_izm[i]/intpower(2,30)*intpower(2,drei)
              end;
           if i=2394 then
              begin
                if round(result.I_izm[i]/intpower(2,24)) mod 2=0 then
                    result.g0_e:=result.U_izm[i]/intpower(2,30)*intpower(2,drei)
                else result.g0_e:=-1*result.U_izm[i]/intpower(2,30)*intpower(2,drei)
              end;
           if i=2395 then
              begin
                if round(result.I_izm[i]/intpower(2,24)) mod 2=0 then
                    result.g1_e:=result.U_izm[i]/intpower(2,30)*intpower(2,drei)
                else result.g1_e:=-1*result.U_izm[i]/intpower(2,30)*intpower(2,drei)
              end;
           if i=2396 then
              begin
                if round(result.I_izm[i]/intpower(2,24)) mod 2=0 then
                    result.g2_e:=result.U_izm[i]/intpower(2,30)*intpower(2,drei)
                else result.g2_e:=-1*result.U_izm[i]/intpower(2,30)*intpower(2,drei)
              end;
           if i=2397 then
              begin
                if round(result.I_izm[i]/intpower(2,24)) mod 2=0 then
                    result.g3_e:=result.U_izm[i]/intpower(2,30)*intpower(2,drei)
                else result.g3_e:=-1*result.U_izm[i]/intpower(2,30)*intpower(2,drei)
              end;
           if i=2398 then
              begin
                if round(result.I_izm[i]/intpower(2,24)) mod 2=0 then
                    result.C_e:=result.U_izm[i]/intpower(2,30)*intpower(2,drei)
                else result.C_e:=-1*result.U_izm[i]/intpower(2,30)*intpower(2,drei)
              end;
           if i=2399 then
              begin
                if round(result.I_izm[i]/intpower(2,24)) mod 2=0 then
                    result.Usm_e:=result.U_izm[i]/Ku
                else result.Usm_e:=-1*result.U_izm[i]/Ku;
              end;
          end;
       end;
end;


//функции вызова свойств класса
function TDevice.IsConnected;
begin
  if connected then result:=true else result:=false;
end;
function TDevice.IsPortOpened;
begin
if port_opened then result:=true else result:=false;

end;
function TDevice.Show_device_name;
begin result:=device_name; end;
function TDevice.Show_device_serial_no;
begin result:=device_serial_no; end;

//копирование столбца В в матрицу А в колонку col
function TDevice.copy_col(Al:TMatrix; Bl:TCol; coll:integer):TMatrix;
var i:integer;
begin
for I := 0 to 4 do
Al[i,coll]:=Bl[i];
result:=Al;
end;
//определитель матрицы 5х5
function TDevice.det5(A:TMatrix):extended;
  function det4(A11,A12,A13,A14,A21,A22,A23,A24,A31,A32,A33,A34,A41,A42,A43,A44:extended):extended;
    function det3(A11,A12,A13,A21,A22,A23,A31,A32,A33:extended):extended;
      function det2(A11,A12,A21,A22:extended):extended;
        begin
          result:=A11*A22-A12*A21;
        end;
      begin
          result:=A11*det2(A22,A23,A32,A33)-A12*det2(A21,A23,A31,A33)+A13*det2(A21,A22,A31,A32);
      end;
    begin
      result:=A11*det3(A22,A23,A24,A32,A33,A34,A42,A43,A44)-
        A12*det3(A21,A23,A24,A31,A33,A34,A41,A43,A44)+
        A13*det3(A21,A22,A24,A31,A32,A34,A41,A42,A44)-
        A14*det3(A21,A22,A23,A31,A32,A33,A41,A42,A43);
    end;
begin
    result:=A[0,0]*det4(A[1,1],A[1,2],A[1,3],A[1,4],A[2,1],A[2,2],A[2,3],A[2,4],A[3,1],A[3,2],A[3,3],A[3,4],A[4,1],A[4,2],A[4,3],A[4,4])-
        A[0,1]*det4(A[1,0],A[1,2],A[1,3],A[1,4],A[2,0],A[2,2],A[2,3],A[2,4],A[3,0],A[3,2],A[3,3],A[3,4],A[4,0],A[4,2],A[4,3],A[4,4])+
        A[0,2]*det4(A[1,0],A[1,1],A[1,3],A[1,4],A[2,0],A[2,1],A[2,3],A[2,4],A[3,0],A[3,1],A[3,3],A[3,4],A[4,0],A[4,1],A[4,3],A[4,4])-
        A[0,3]*det4(A[1,0],A[1,1],A[1,2],A[1,4],A[2,0],A[2,1],A[2,2],A[2,4],A[3,0],A[3,1],A[3,2],A[3,4],A[4,0],A[4,1],A[4,2],A[4,4])+
        A[0,4]*det4(A[1,0],A[1,1],A[1,2],A[1,3],A[2,0],A[2,1],A[2,2],A[2,3],A[3,0],A[3,1],A[3,2],A[3,3],A[4,0],A[4,1],A[4,2],A[4,3]);
end;


end.





