unit ADCDevice;

interface

uses
  Windows, WakeDevice, Classes, SysUtils, Math;

//---------------------------------------------------------------------------
//  Коды команд
//---------------------------------------------------------------------------
const
  // $00..$03 - Стандартные коды команд протокола WAKE
  CMD_GETA = $04;                      // чтение АЦП.

  CHANNEL_COUNT  = 8;
  GAIN_COUNT     = 7;

type

//---------------------------------------------------------------------------
//    TADCDevice = class(TWakeDevice)
//---------------------------------------------------------------------------

  TADCDevice = class(TWakeDevice)
  private
    // Признак подключенного устройства
    function GetConnect(): boolean;

  protected
    // Проверка на наличие ошибки
    procedure CheckErrorCode(ACmd: byte; AErrCode: byte);override;

  public
    // ABaudRate - Скорость двоичной передачи; ATimeOut - RX Таймаут, мсек
    constructor Create();
//    destructor Destroy(); override;

    // Поиск устройства
//    function DeviceSearch(ADeviceVersion : string = ''; ADeviceSerialNumber: integer = 0): boolean;

    // Список подключенных устройств
    procedure DiveceList(AList: TStrings);override;

     // Пример
//    procedure SetP();

    function GetConnectInf(const Inf: string): boolean;

    function GetEcho(const AtxData: TWakeData; var ArxData: TWakeData; ACount: byte): boolean;

    function GetA(const AtxData: TWakeData; var ArxData: TWakeData): boolean;
    function ReadADC(AChannel: integer; AIndexGain: integer; out Value : double): boolean;
    function IndexToGain(Gain: integer):byte;
  published
    // Признак подключенного устройства
    property Connected: boolean read GetConnect;

//    property DeviceSerialNumber;
//    property PortNumber;
  end; //  TADCDevice = class(TWakeDevice)


//---------------------------------------------------------------------------
// Ошибки при работе с устройством
//---------------------------------------------------------------------------
//resourcestring
  // код = $01..$05 - Стандартные ошибки при работе с устройством
//  SNoCarrier = 'Отсутствует несущая.';     // код = $06

var
  Device: TADCDevice;

implementation

uses
  Config, Calib;

constructor TADCDevice.Create();
begin
  // ABaudRate - Скорость двоичной передачи; ATimeOut - RX Таймаут, мсек
  inherited Create;
//  FbaudRateCOM := 100;
//  FbaudRateUSB := 100;

  FDeviceName   := '';

end;

{
destructor TSignalDevice.Destroy();
begin

  inherited Destroy;
end;
}

// Поиск устройства
{function TADCDevice.DeviceSearch(ADeviceVersion : string; ADeviceSerialNumber: integer): boolean;
begin
  result := inherited DeviceSearch(FDeviceName, ADeviceVersion, ADeviceSerialNumber);
end;
}
// Список устройств
procedure TADCDevice.DiveceList(AList: TStrings);
var
  PortBox : TStringList;
  i : integer;
  Inf         : string;
begin
  AList.Clear;

  if FOpened then
      ClosePort;

  PortBox := TStringList.Create;
  try
    GetListPorts(PortBox);

    for i := 0 to PortBox.Count - 1 do
    begin
      try
        if OpenPort(PChar(PortBox.Strings[i])) then
        begin
          Sleep(1);
          if GetInfo(Inf) then
          begin
            if AnsiPos('14-8D', Inf) = 5 then
                AList.Add(Inf);
          end;

        end;
      except on EWakePortError do
      end;
      if FOpened then
          ClosePort;
    end;

  finally
    PortBox.free;
  end;

end;

// Проверка подключенного устройства
function TADCDevice.GetConnect(): boolean;
var
  DeviceName,
  DeviceVersion : string;
  DeviceSerialNumber : integer;
begin
  result := false;
  try
    if GetInfo(DeviceName, DeviceVersion, DeviceSerialNumber) then
        if AnsiCompareText(FDeviceName, DeviceName) = 0 then
            result := true;
  except on EWakePortError do
  end;

end;

function TADCDevice.GetConnectInf(const Inf: string): boolean;
var s : string;
begin
  result := false;
  try
    if GetInfo(s) then
        if AnsiSameText(s, Inf) then
            result := true;
  except on EWakePortError do
  end;
end;

(*
procedure TADCDevice.SetP();
var mode : byte;
begin
  Lock;
  try
   mode := $FF;

// Logical (bitwise) operators
{
  Operator  Operation             Operand types  Result type  Examples

  not       bitwise negation      integer        integer      not X
  and       bitwise and           integer        integer      X and Y
  or        bitwise or            integer        integer      X or Y
  xor       bitwise xor           integer        integer      X xor Y
  shl       bitwise shift left    integer        integer      X shl 2
  shr       bitwise  shift right  integer        integer      Y shr I
}

   FtxData[0]  := mode;       // (unsigned char)(mode);
   FtxData[1]  := mode shr 8; // (unsigned char)(mode >> 8);
   FtxData[2]  := mode shl 8; // (unsigned char)(mode << 8);

   ExeCmd(1 {txCmd}, 0{txCount});
  finally
    UnLock;
  end;
end;
*)

function TADCDevice.GetEcho(const AtxData: TWakeData; var ArxData: TWakeData; ACount: byte): boolean;
begin
  Lock;
  try
    ExeCmd(CMD_ECHO, ACount, AtxData, ArxData);
  finally
    UnLock;
  end;
  result := true;

end;

function TADCDevice.GetA(const AtxData: TWakeData; var ArxData: TWakeData): boolean;
begin
  Lock;
  try
    ExeCmd(CMD_GETA, 2, AtxData, ArxData);
  finally
    UnLock;
  end;
  result := true;
end;


function TADCDevice.IndexToGain(Gain: integer):byte;
begin
  case Gain of
    0 : Result := 1;
    1 : Result := 2;
    2 : Result := 5;
    3 : Result := 10;
    4 : Result := 20;
    5 : Result := 50;
    6 : Result := 100;
    else
        result := 255;
  end;

end;

function TADCDevice.ReadADC(AChannel: integer; AIndexGain: integer; out Value : double): boolean;
var
  txData, rxData : TWakeData;
  Code : integer;
begin
  // Channel от 0 до 7
  txData[0] := AChannel;

  // Gain
  // 1,     2,    5,    10,   20,      50,      100
  // ±10 В, ±5 В, ±2 В, ±1 В, ±500 мВ, ±200 мВ, ±100 мВ
  txData[1] := IndexToGain(AIndexGain);

  result := GetA(txData, rxData);

  Code := MakeWord(rxData[1], rxData[2]);
//  Code := rxData[1] + 256 * rxData[2];

  if Code > $7FFF then
      Code := Code - $10000;
  Value := Calibration.Calib.K[AChannel, AIndexGain] * 10 * (Code / $7FFF) / IndexToGain(AIndexGain) + Calibration.Calib.S[AChannel, AIndexGain];
  Value := RoundTo(Value, (-1) * Configuration.General.Round[AChannel]);

//  messagebox(0, PChar(Format('Channel:%d  Gain:%d  k:%f  s:%f  value:%f  code:%d', [AChannel, AIndexGain, Calibration.Calib.K[AChannel, AIndexGain], Calibration.Calib.S[AChannel,AIndexGain], Value, Code])) , nil, mb_ok);
end;

procedure TADCDevice.CheckErrorCode(ACmd: byte; AErrCode: byte);
var
  ErrStr: string;
begin
  if (not (ACmd in [CMD_INFO, CMD_ECHO{, CMD_PING}])) and
     (AErrCode <> 0) then
  begin
    case AErrCode of
      $01..$05 :  inherited CheckErrorCode(ACmd, AErrCode);
//      $06 : ErrStr := SNoCarrier;
      else
          ErrStr := Format('Неизвестная ошибка.'#13'Код: %d'#13'Class: %s', [AErrCode, Self.ClassName]);
    end;

//    if assigned(FOnGetErrString) then
//        FOnGetErrString(Cmd, ErrCode, ErrStr);
    raise EWakeDeviceError.Create(ErrStr);
  end;


end;

end.
