unit ADCDevice;

interface

uses
  Windows, WakeDevice, Classes;

//---------------------------------------------------------------------------
//  Коды команд
//---------------------------------------------------------------------------
const
  // $00..$03 - Стандартные коды команд протокола WAKE
  CMD_SETM  = $04;                      // установка режима
  CMD_GETA1 = $06;                      // считывание значения первого канала АЦП
  CMD_GETA2 = $07;                      // считывание значения второго канала АЦП

const
  CHANNEL_COUNT  = 2;
  GAIN_COUNT     = 8;

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

  TADCDevice = class(TWakeDevice)
  private
    FMode  : byte;
    FGain0 : byte;
    FGain1 : byte;
    // Признак подключенного устройства
    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 SetM(AMode: byte; AGain1: byte; AGain2: byte): boolean; overload;
    function SetM: boolean; overload;
    function GetA1(const AtxData: TWakeData; var ArxData: TWakeData): boolean;
    function GetA2(const AtxData: TWakeData; var ArxData: TWakeData): boolean;

    function IndexToGain(Gain: integer):byte;
    function ADCTransform(Code: integer; PGA: integer): double;

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

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


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

var
  Device: TADCDevice;

implementation

uses
  SysUtils, Calib, Config, Math;

constructor TADCDevice.Create();
begin
  // ABaudRate - Скорость двоичной передачи; ATimeOut - RX Таймаут, мсек
  inherited Create;
  FbaudRateCOM := 19200;
//  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('ADCS24-2T', Inf) = 1 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;


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.SetM(AMode: byte; AGain1: byte; AGain2: byte): boolean;
begin
  Lock;
  try
    FtxData[0] := AMode;
    FtxDAta[1] := AGain1;
    FtxData[2] := AGain2;

    ExeCmd(CMD_SETM, 3);
  finally
    UnLock;
  end;
  result := true;

end;

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

function TADCDevice.GetA2(const AtxData: TWakeData; var ArxData: TWakeData): boolean;
begin
  Lock;
  try
    ExeCmd(CMD_GETA2, 0, 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 := 4;
    3 : Result := 8;
    4 : Result := 16;
    5 : Result := 32;
    6 : Result := 64;
    7 : Result := 128;
    else
        result := 0;
  end;

end;

function TADCDevice.SetM: boolean;
begin
  FMode := Configuration.General.Freequ and $03;
  if not Configuration.General.RangeH then
      FMode := FMode or $04;

  if Configuration.General.BufferEnable then
      FMode := FMode or $10;

  if not Configuration.General.Fmod128 then
      FMode := FMode or $20;

  if Configuration.General.Unipolar then
      FMode := FMode or $40;

  FGain0 := Configuration.general.Gain[0] and $07;

  if Configuration.General.TestADC0 then
      FGain0 := FGain0 or $08;

  FGain1 := Configuration.general.Gain[1] and $07;
  if Configuration.General.TestADC1 then
      FGain1 := FGain1 or $08;

//  messagebox(0, Pchar(format('mode:%s', [IntToHex(fmode,2)])), '', mb_ok);
  result := SetM(FMode, FGain0, FGain1);
end;

function TADCDevice.ADCTransform(Code: integer; PGA: integer): double;
var
  FSR  : double;
  VREF : double;
begin
  if (FMode and $04) = 0 then // полная шкала АЦП ±2.5В
      VREF := 2.5
  else
      VREF := 1.25;

  FSR:= (VREF / PGA) / $FFFFFF;

  if (FMode and $04) <> 0 then // полная шкала АЦП ±1.25В
    FSR := FSR * 2;

  If (FMode and $40) = 0 then  //если биполярный режим
  begin
    if Code > $7FFFFF then
        Code := Code - $1000000;

    FSR := FSR * 2;
  end;

  ADCTransform := Code * FSR;
end;

function TADCDevice.ReadADC(AChannel: integer; AIndexGain: integer; out Value : double): boolean;
var
  txData, rxData : TWakeData;
  Code : integer;
  X : byte;
  PGA  : integer;
//  Min, Max : integer;
begin
  Result := false;
  x := 0;
  case AChannel of
    0: begin
         result := GetA1(txData, rxData);
         X := FGain0 and $07;// Mask_Amplifer128;
       end;
    1: begin
         result := GetA2(txData, rxData);
         X := FGain1 and $07;// Mask_Amplifer128;
       end;
  end;

  PGA:= round(power(2, X));
  Code:=(rxData[3] shl 16) + (rxData[2] shl 8) +rxData[1];

{
  if (FMode and $40) = 0 then      //если биполярный режим
  begin
    Min := $800000;
    Max := $7FFFFF;
  end
  else
  begin
    Min := -1;
    Max := $FFFFFF;
  end;
}
//  If (Code <> Max)and(Code <> Min) then
        Value := ADCTransform(Code, PGA) * Calibration.Calib.K[AChannel, AIndexGain] + Calibration.Calib.S[AChannel, AIndexGain];
//  else
//        Value := -1;

//  messagebox(0, Pchar(format('result:%s mode:$%s pga:%d code:$%s value:%f [%s][%s][%s]', [BoolTostr(result, true), IntToHex(fmode,2), pga, IntToHex(code, 8), value, IntToHex(rxData[1],2), IntToHex(rxData[2],2),IntToHex(rxData[3],2)])), '', mb_ok);
  Value := RoundTo(Value, (-1) * Configuration.General.Round[AChannel]);

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.
