unit DeviceRD;

interface

uses D2xxUnit, SysUtils, dialogs, Windows, math;

//пользовательские типы
type bit_array_8 = array[0..7] of byte;   //массив из 8 чисел. Используется для байта
     bit_Array_32 = array[0..31] of byte; //массив из 32 чисел. Используется для 32-битного числа
     message_Array = array[0..24002] of integer; //массив посылки
     TMatrix = array [0..4,0..4] of extended; //тип  массива
                                           //для матрицы 5 на 5
     TMes_array = array [0..4] of message_Array;
     Tbool   = array of boolean;
     TCol    = array [0..4] of extended;
     params_record = record                //запись для результатов разбора
        R:extended;
        C:extended;
        g0:extended;
        g1:extended;
        g2:extended;
        g3:extended;
        U_izm: array [0..2400] of extended;
        I_izm: array [0..2400] of extended;
     end;
//непосредственно класс устройства
type
  TDevice = class (TObject)
    private
      connected       :boolean;    //существует ли связь с прибором.
      port_opened     :boolean;    //открыт ли порт прибора
      device_name     :string;     //Название прибора
      device_serial_no:string;     //Серийный номер прибора
      device_desc     :string;     //Описание прибора
      const version = '0.1.4';



      //function to_binary(x:integer): bit_array_32; //переводит целое число<256 в двоичное
      //function add_to_32_binary(x:bit_array_32; start_pos,count:integer; ar:bit_array_32):bit_array_32;
//записывает байт в 32-битное число начиная с start_pos
      //function to_decimal(x:bit_Array_32):extended;
      //переводит двоичное число в десятичное
      function Determinant(FirstRow : Integer; Matrica:TMatrix; k:integer; ac:Tbool): extended;
      function copy_col(Al:TMatrix; Bl:TCol; coll:integer):TMatrix;
      function det5(A:TMatrix):extended;



   public
      message_    :    message_Array;
      got_message :  boolean;
      constructor Create();
      destructor  Destroy();
      function  IsConnected:boolean;
      function  IsPortOpened:boolean;

      function  Show_device_name:string;
      function  Show_device_serial_no:string;
      function  Show_device_desc:string;

      function message_decode(massiv:message_Array):params_record;

      function Start_waiting(mode:integer):message_Array;

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


end;

implementation

uses device_thread, MainUnit;

constructor TDevice.Create;
var device_index,i:integer;
begin
GetFTDeviceCount;
FT_Enable_Error_Report := true;
connected:=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_desc:=FT_Device_String;
      Device_Index := Device_Index + 1;
      connected:=true;
  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;
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
      PortStatus := Open_USB_Device;  // Try and open device
      If PortStatus = 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
connected:=false;
port_opened:=false;
If Open_USB_Device_By_Serial_Number(device_serial_no) = FT_OK then
begin
  connected:=true;
  //showmessage('1');
  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;
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;
function TDevice.Show_device_desc;
begin result:=device_desc end;

function TDevice.Start_waiting(mode:integer):message_Array;
var i:integer;
f:Textfile;
message_:Message_Array;
res_m:params_record;
begin
if mode=1 then
  if port_opened then
                  TTH:=device_thread_th.Create(false);
if mode=2 then
begin
assignfile(f, 'message');
reset(f);
i:=0;
repeat
readln(f, message_[i]);
inc(i);
until EOF(f);
closefile(f);
//if got_message then
//showmessage('Сообщение получено')
res_m:=self.message_decode(message_);
MainForm.Memo1.Clear;
MainForm.Memo1.Visible:=false;
 for I := 0 to 2400 do
                    MainForm.Memo1.Lines.Add(floattostr(res_m.U_izm[i]));
 MainForm.Memo1.Lines.SaveToFile('1');



end;

end;

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

var k,                         //текущее значение строчки в массиве измерения
    i,                         //счетчик в цикле
                             //значение массива
    j,j1
    ,a1,b1,c1,d1,a2,b2,c2,d2:                      //счетчики для инициализации
    integer;
    bin_volt,                  //двоичное значение напряжения
    bin_curr:bit_Array_32;     //двоичное значение тока
    U0,                        //
    I0,                        //
    Ud0,                       //
    Up0
                            //
        :Extended;
    A: TMatrix;
    B
    : TCol;
    Det0:extended;


begin
///инициализация переменных
//setlength(a,5,5);
U0:=0;Ud0:=0; I0:=0;
for j:=0 to 4 do begin
            B[j]:=0;
              for j1:=0 to 4 do
             A[j,j1]:=0;
end;

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

      for j:=0 to 31 do
          bin_volt[j]:=0;

      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;

      for j:=0 to 31 do
          bin_curr[j]:=0;

          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=2393 then
          begin

           Det0:=det5(A);

          showmessage(floattostr(Det0));

           result.g0:=det5(copy_col(A,B,0))/Det0*Ku/Ki*rescale;

           result.g1:=det5(copy_col(A,B,1))/Det0*Ku/Ki*rescale;

           result.g2:=det5(copy_col(A,B,2))/Det0*Ku/Ki*rescale;

           result.g3:=det5(copy_col(A,B,3))/Det0*Ku/Ki*rescale;

           result.C:=det5(copy_col(A,B,4))/Det0*Ku/Ki*rescale;

           result.R:= rescale/result.g0;


          end;
       end;
end;

//функции работы с числами и байтами
{function TDevice.to_binary(x:integer):bit_array_32;
var i:integer;
begin
if x>0 then
    begin
	    for i:=31 downto 0 do result[i]:=0;

	    i:=31;
	    repeat
		      result[i]:=x mod 2; //остаток от деления на 2
		      x:=x div 2;
		      dec(i);
	    until (x=0);
    end
    else if x=0 then for i:=0 to 31 do result[i]:=0
    {else if x<0 then
      begin
        result:=to_binary(-x);
          for i:=7 downto 0 do
		          if result[i]=1 then result[i]:=0 else result[i]:=1; //доп. код.
          for i:=7 downto 0 do
		          if result[i]=0 then begin result[i]:=1; break; end else result[i]:=0;
              //скорее всего добавляем 1 к доп. коду???
end;
end
else //возможное добавление обработки ошибок
end; 
function TDevice.to_decimal(x:bit_Array_32):extended;
var i:Integer;
begin
result:=0;
for i:=31 downto 1 do
if x[i]=1 then result:=result+ldexp(1,i);
if x[0]=1 then result:=result*(-1);
end;
{function TDevice.add_to_32_binary(x:bit_array_32; start_pos,count:integer; ar:bit_array_32):bit_array_32;
var i:integer;
begin
for i:=1 to count do
ar[start_pos-i+1]:=x[8-i];
result:=ar;
end;
//вычисление определителя произвольной матрицы
function TDevice.Determinant(FirstRow : Integer; Matrica:TMatrix; k:integer; ac:Tbool) : extended;
Массив ActiveCols будем использовать для обозначения "вычеркнутых" колонок
FirstRow указывает на первую строку массива, с которой начинается
матрица, рассматриваемая на текущем шаге. Строки вычеркиваем последовательно
var
  i : Integer;
  Odd : Boolean;
begin
//setLength(Matrica, n-1,n-1);
if ac=nil then
begin
  setlength(ac,k);
  for I:=0 to k-1 do ac[i]:=true;
end;
  Result:=0;
  Odd:=true;
  for i:=0 to k-1 do // пробегаем по всем элементам текущей строки
    begin
    if NOT ac[i] then Continue; // если колонка вычеркнута, то пропускаем
// если первая строка равна размерности матрицы, значит у нас остался один единственный элемент (матрица 1х1). Этот элемент и будет детерминантом.
    if FirstRow = k-1
    then
      begin
      Result:=Matrica[FirstRow,i];
      Exit;
      end;
    ac[i]:=false; // вычеркиваем текущий столбец
    if Odd
    then
если позиция нечетная, то к результату прибавляем произведение элемента на дополниетльный минор
      Result:=Result+Matrica[FirstRow,i]*Determinant((FirstRow+1), Matrica, k,ac)
    else
если позиция четная, то вычитаем
      Result:=Result-Matrica[FirstRow,i]*Determinant(FirstRow+1, Matrica, k,ac);
    ac[i]:=true;  // восстанавливаем вычеркнутый стобец
    Odd:=NOT Odd; // меняем четность
    end;
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;

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.





