unit VoltMeteru;{v0.22 see voltmeter.txt}
interface
uses
  UlanType, VoltMeterType;

function ExtDevInit(var AExtDevDrv: PExtDevDrv; const ADesc: shortstring): integer; export;
function ExtDevDoAction(AExtDevDrv: PExtDevDrv; ea: TExtDevAction; AInfo: longint): integer;export;
function ExtDevSetStr(AExtDevDrv: PExtDevDrv; ep: TExtDevProperty; const S: shortstring):integer; export;
function ExtDevGetStr(AExtDevDrv: PExtDevDrv; ep: TExtDevProperty; var S: shortstring):integer; export;
function ExtDevStart(AExtDevDrv: PExtDevDrv): integer; export;
function ExtDevStop(AExtDevDrv: PExtDevDrv): integer; export;
function ExtDevDoCharIn(AExtDevDrv: PExtDevDrv; ch:char): integer; export;
function ExtDevReadPoint(AExtDevDrv: PExtDevDrv; var APoint: TExpPoint): integer; export;
function ExtDevDone(var AExtDevDrv: PExtDevDrv): integer; export;

implementation
uses
  SysUtils, WinUtl, fifou, timer, inifiles;
const
  VoltMeterBufSlotCount: integer = 1024;
  VoltMeterPointTimeInterval: single = 1000;{31.25;{ms}
  LineLen = 14;

type
  TVoltMeterDrv = class(TObject)
  private
    FFifo: TFifo;
    FCurLine: shortstring;
      { currently beeing input line from incoming bytes }
    FCurVal: single;
    FCurTime: single;
    FDesc: shortstring;

    FDeviceTypeName: shortstring;
      { manufacturer-model name of the voltmeter }
    FQuantityName: shortstring;
      { name of the measured quantity extracted from the
        last received line from voltmeter (DC, AC, .. }
    FUnitName: shortstring;
      { name of the unit of current quantity (V, mV, Ohm, MOhm..)
        extracted from the last received line from voltmeter }
    FZeroValue: single;
    FRunning: boolean;
    FLastResult: TExtDevResult;
  protected
    function DoLine: integer;
    procedure SetResult(er: TExtDevResult; const msg: string);
    procedure PortBeforeOpen(AInfo:longint);
    procedure SetDeviceTypeName(const S: shortstring);
  public
    constructor Create(ADesc: shortstring); reintroduce;
    function Start: integer;
    function Stop: integer;
    function DoAction(ea: TExtDevAction; AInfo: longint): integer;
    destructor Destroy; override;
    function DoCharIn(ch:char): integer;
    function ReadPoint(var APoint: TExpPoint): integer;
    function GetStr(ep: TExtDevProperty; var S: shortstring): integer;
    function SetStr(ep: TExtDevProperty; const S: shortstring): integer;

    property DeviceTypeName: shortstring read FDeviceTypeName write
      SetDeviceTypeName;
  end;


procedure TVoltMeterDrv.SetResult(er: TExtDevResult; const msg: string);
begin
  FLastResult := er;
end;

constructor TVoltMeterDrv.Create(ADesc: shortstring);
begin
  inherited Create;
  FDesc := ADesc;
  FFifo := TFifo.Create(sizeof(TExpPoint), VoltMeterBufSlotCount);
end;

function TVoltMeterDrv.Start: integer;
begin
  Result := 0;
  FCurTime := 0;
  FFifo.Clear;
  FRunning:= true;
end;

function TVoltMeterDrv.Stop: integer;
begin
  Result := 0;
  FRunning := false;
end;

destructor TVoltMeterDrv.Destroy;
begin
  FFifo.Free;
  inherited Destroy;
end;

procedure TVoltMeterDrv.PortBeforeOpen(AInfo:longint);

//  COMx:1200,N,7,2,RS,CD,DS,CD
//  (flow control none,RTS On/Off,DTR On, all other off)
var
  sec: shortstring;
  f: TIniFile;
begin
  if AInfo = 0 then begin
    {setresult}
    exit;
  end;
  f := TIniFile.Create(FindParentIniFile('Chromulan.ini'));
  sec := PShortString(AInfo)^;
  try
    f.WriteString(sec, 'bps','1200');
    f.WriteString(sec, 'parity','N');
    f.WriteString(sec, 'stopbits','1');
    f.WriteString(sec, 'databits','7');
    f.WriteString(sec, 'FlowControl','DTR');
    f.WriteString(sec, 'ParityCheck', '0');
    f.WriteString(sec, 'DsrSensitivity', '0');
    f.WriteString(sec, 'IgnoreXOff','0');
    f.WriteString(sec, 'UseErrorChar','0');
    f.WriteString(sec, 'NullStrip','0');
    f.WriteString(sec, 'AbortOnError','0');
    f.WriteString(sec, 'UseIniPars','1');
    f.WriteString(sec, 'DTROnOpen','1');
    f.WriteString(sec, 'RTSOnOpen','1');
    f.WriteString(sec, 'XOnOnOpen','0');
    f.WriteString(sec, 'BreakOnOpen','0');
  finally
    f.Free;
  end;
end;

function TVoltMeterDrv.DoAction(ea: TExtDevAction; AInfo: longint): integer;
begin
  FLastResult := 0;
  case ea of
    eaPortBeforeOpen: PortBeforeOpen(AInfo);
  else
    SetResult(edrInvalidExtDevAction, IntToStr(ea));
  end;
  Result := FLastResult;
end;

function TVoltMeterDrv.DoLine: integer;
var
  ep: TExpPoint;
  code: integer;
begin
  Result := 0;
  ep.X := FCurTime / 1000;
  FCurTime := FCurTime + VoltMeterPointTimeInterval;
  val(copy(FCurLine, 3, 7), FCurVal, code);
  if FCurLine[10]='m' then
    FCurVal := FCurVal / 1000;
  ep.Y := FCurVal - FZeroValue;
  if not FFifo.Put(ep) then
    Result := edrBufferFull;
end;

function TVoltMeterDrv.DoCharIn(ch:char): integer;
var
  b: byte absolute ch;
begin
  if FRunning then begin
    FLastResult := 0;
    if ch = #13 then begin
      if length(FCurLine) = LineLen - 1 then begin
        DoLine;
      end else begin
        SetResult(edrInvalidInput, FCurLine + ch);
      end;
      FCurLine := '';
    end else begin
      if length(FCurLine) < LineLen then begin
        FCurLine := FCurLine + ch;
      end else begin
        SetResult(edrInvalidInput, FCurLine + ch);
        FCurLine := '';
      end;
    end;
    Result := FLastResult;
  end else begin
    Result := edrNotRunning;
  end;
end;

function TVoltMeterDrv.ReadPoint(var APoint: TExpPoint): integer;
begin
  if FFifo.Get(APoint) then
    Result := 0
  else
    Result := -1;
end;

function TVoltMeterDrv.GetStr(ep: TExtDevProperty; var S: shortstring): integer;
begin
  FLastResult := 0;
  S := '';
  case ep of
    epQuantityName: S := FQuantityName;
    epUnitName: S := FUnitName;
    epDeviceTypeName: S := DeviceTypeName;
  else
    SetResult(edrInvalidGetStrProp, IntToStr(ep));
  end;
  Result := FLastResult;
end;

function TVoltMeterDrv.SetStr(ep: TExtDevProperty; const S: shortstring): integer;
begin
  FLastResult := 0;
  case ep of
    epDeviceTypeName: DeviceTypeName := s;
  else
    SetResult(edrInvalidSetStrProp, IntToStr(ep));
  end;
  Result := FLastResult;
end;

procedure TVoltMeterDrv.SetDeviceTypeName(const S: shortstring);
const
  SupportedTypesCount = 3;
  SupportedTypes: array[0..SupportedTypesCount - 1] of shortstring =
  ('VoltCraft M-4650CR','Metex M3850', 'Metex M3830');
var
  i: integer;
  found: boolean;
begin
  if FDeviceTypeName <> S then begin
    found := false;
    for i := 0 to SupportedTypesCount - 1 do begin
      if UpperCase(S) = UpperCase(SupportedTypes[i]) then begin
        found := true;
        break;
      end;
    end;
    if not found then begin {ulantype}
      SetResult(edrUnsupportedDeviceType, S);
    end;
  end;
end;

{/TVoltMeterDrv}

function ExtDevInit(var AExtDevDrv: PExtDevDrv; const ADesc: shortstring): integer;export;
var adrv: TVoltMeterDrv absolute AExtDevDrv;
begin
  try
    adrv := TVoltMeterDrv.Create(ADesc);
    Result := 0;
  except
    adrv := nil;
    Result := -1;
  end;
end;

function ExtDevSetStr(AExtDevDrv: PExtDevDrv; ep: TExtDevProperty; const S: shortstring):integer; export;
var
  adrv: TVoltMeterDrv absolute AExtDevDrv;
begin
  Result := -1;
  if adrv <> nil then
    Result := adrv.SetStr(ep, s);
end;

function ExtDevGetStr(AExtDevDrv: PExtDevDrv; ep: TExtDevProperty; var S: shortstring):integer; export;
var
  adrv: TVoltMeterDrv absolute AExtDevDrv;
begin
  Result := -1;
  if adrv <> nil then
    Result := adrv.GetStr(ep, s);
end;

function ExtDevDoAction(AExtDevDrv: PExtDevDrv; ea: TExtDevAction;
  AInfo: longint): integer;
var
  adrv: TVoltMeterDrv absolute AExtDevDrv;
begin
  Result := -1;
  if adrv <> nil then
    Result := adrv.DoAction(ea, AInfo);
end;


function ExtDevDone(var AExtDevDrv: PExtDevDrv): integer;export;
var
  adrv: TVoltMeterDrv absolute AExtDevDrv;
begin
  Result := -1;
  if adrv <> nil then begin
    adrv.Free;
    Result := 0;
  end;
end;

function ExtDevStart(AExtDevDrv: PExtDevDrv): integer;
var
  adrv: TVoltMeterDrv absolute AExtDevDrv;
begin
  Result := -1;
  if adrv <> nil then
    Result := adrv.Start;
end;

function ExtDevStop(AExtDevDrv: PExtDevDrv): integer;
var adrv: TVoltMeterDrv absolute AExtDevDrv;
begin
  Result := -1;
  if adrv <> nil then
    Result := adrv.Start;
end;

function ExtDevDoCharIn(AExtDevDrv: PExtDevDrv; ch:char): integer;
var
  ADrv: TVoltMeterDrv absolute AExtDevDrv;
begin
  Result := ADrv.DoCharIn(ch);
end;

function ExtDevReadPoint(AExtDevDrv: PExtDevDrv; var APoint: TExpPoint): integer;
var
{  gi: TVoltMeterPktInfo;}
  ADrv: TVoltMeterDrv absolute AExtDevDrv;
begin
  Result := ADrv.ReadPoint(APoint);
  (*
  Result := 1;
  with AExtDevDrv do begin
    {if ListRecGet(Lst, gi) then begin}
      Result := 0;
    {
  function MakeLogLine(var gi:TExtDevPacketInfo):string;
  var
    s:string;
    l:single;
    b:array[0..3]of byte absolute l;
  begin
    s := IntToStr(gi.Pkt[0]);
    MakeLogLine := s;
  end;}
  {  if LogPackets then begin
    SpectrumMemo.Lines.Add(MakeLogLine(gi));
    end;}
      for i := 0 to ExtDevPacketValueCount - 1 do begin
        CurExtDevTime := CurExtDevTime + ExtDevPointTimeInterval;
      dr.X := CurExtDevTime / 1000;


      dr.Y := 2 * (gi.Pkt[i]) / 1024 - ZeroValue;
      Data.AddPoint(dr);
      if ScrBuf[DataIndex].Points <> nil then begin
        if (dr.X >= ViewLimit.Min.X) and (dr.X <= ViewLimit.Max.X) then
        begin
          Data.ExpToScreen(dr, ScreenDisp, sr);
          ScrBuf[DataIndex].Points.AddPoint(sr.x,sr.y);
        end;
      end;
    end;
  end;
  *)
end;

end.
