{
  Autor: Michael Springwald

  Datum: Dienstag, 6.Januar.2015

  Dient als Interface Klasse zwischen PC und Arduino Modulen.
  Es soll egal sein, woher die Daten kommen.
  Ob vom Uart oder per Lan oder oder.
}

unit uplArduinoPCInterface;

{$mode objfpc}{$H+}

interface

uses
  Classes, SysUtils, contnrs,
  synaser, blcksock,
  uplthreadtimertest;

type
  TPLArduinoPCInterface_OnData = procedure (Data:String; const aDeviceIndex:Integer) of object;

  { TPLArduinoPCInterfaceBase }
  TPLArduinoPCInterfaceBase = class
  private
    fDescription: string;
    fDevice: string;
    fDeviceIndex: Integer;
    fEnabled: Boolean;
    fError: Byte;
    fName: String;
    fOnData: TPLArduinoPCInterface_OnData;

  protected
    procedure SetEnabled(AValue: Boolean); virtual;
  public
    ThreadTimer:TPLThreadTimer;
    OK:Boolean;

    procedure TimerEvent1; virtual;
    procedure DoOnData(const data:string; const aDeviceIndex:Integer); virtual;

    procedure SendAString(const aValue:String); Virtual;
    constructor Create(const aDevice:String);
    destructor Destroy; override;
  published
    property Device:string read fDevice write fDevice;

    property Error:Byte read fError write fError;
    property Name:String read fName write fName;
    property Description:string read fDescription write fDescription;
    property Enabled:Boolean read fEnabled write SetEnabled;
    property DeviceIndex:Integer read fDeviceIndex write fDeviceIndex;

    property OnData:TPLArduinoPCInterface_OnData read fOnData write fOnData;
  end; // TPLArduinoPCInterfaceBase

  { TPLArduinoPCInterface_Uart }
  TPLArduinoPCInterface_Uart = class(TPLArduinoPCInterfaceBase)
  private
  protected
    procedure SetEnabled(AValue: Boolean); override;
    procedure OnSenderTimer;

  public
    BlockSerial:TBlockSerial;
    NoEvent:Boolean;
    Lock:Boolean;
    SendeTimer:TPLThreadTimer;
    Log:TStringList;
    WorkIndex, LogIndex:Integer;
    procedure TimerEvent1; override;
    procedure SendAString(const aValue: String); override;
    constructor Create(const aUSB_Device:string);
    destructor Destroy; override;
  published
  end; // TPLArduinoPCInterface_Uart

  { TPLArduinoPCInterfaceList }
  TPLArduinoPCInterfaceList = class
  private
    fEnabled: Boolean;
    function GetCount: Integer;
    function GetItem(index: Integer): TPLArduinoPCInterfaceBase;
    procedure SetEnabled(AValue: Boolean);
  protected

  public
    Items:TObjectList;
    constructor Create;
    destructor Destroy; override;

    function Add(Value:TPLArduinoPCInterfaceBase):TPLArduinoPCInterfaceBase;
    function FindByUSBDevice(const aValue:String):TPLArduinoPCInterfaceBase;

    property Count:Integer read GetCount;
    property Item[index:Integer]:TPLArduinoPCInterfaceBase read GetItem; default;
  published
    property Enabled:Boolean read fEnabled write SetEnabled;
  end; // TPLArduinoPCInterfaceList

implementation

function TPLArduinoPCInterfaceList.GetCount: Integer;
begin
  result:=Items.Count;
end; // TPLArduinoPCInterfaceList.GetCount

function TPLArduinoPCInterfaceList.GetItem(index: Integer): TPLArduinoPCInterfaceBase;
begin
  result:=Items[index] as TPLArduinoPCInterfaceBase;
end; // TPLArduinoPCInterfaceList.GetItem

procedure TPLArduinoPCInterfaceList.SetEnabled(AValue: Boolean);
var
  i:integer;
begin
//  if fEnabled=AValue then Exit;
  fEnabled:=AValue;
  for i:=0 to Count-1 do begin
    Item[i].Enabled:=AValue;
  end; // for i
end; // TPLArduinoPCInterfaceList.SetEnabled

constructor TPLArduinoPCInterfaceList.Create;
begin
  inherited Create;
  Items:=TObjectList.Create;
  fEnabled:=False;
end; // TPLArduinoPCInterfaceList.Create

destructor TPLArduinoPCInterfaceList.Destroy;
begin
  Items.Free;
  inherited Destroy;
end; // TPLArduinoPCInterfaceList.Destroy

function TPLArduinoPCInterfaceList.Add(Value: TPLArduinoPCInterfaceBase): TPLArduinoPCInterfaceBase;
begin
  result:=item[items.Add(Value)];
  result.DeviceIndex:=Count-1;
end; // TPLArduinoPCInterfaceList.Add

function TPLArduinoPCInterfaceList.FindByUSBDevice(const aValue: String): TPLArduinoPCInterfaceBase;
var
  i:integer;
begin
  result:=nil;
  for i:=0 to Count-1 do begin
    if Item[i].Device = aValue then begin
      result:=Item[i];
      break;
    end;
  end;
end; // TPLArduinoPCInterfaceList.FindByUSBDevice

// http://www.lazarusforum.de/viewtopic.php?f=55&t=9303
procedure TPLArduinoPCInterface_Uart.SetEnabled(AValue: Boolean);
begin
  inherited SetEnabled(AValue);
//  ThreadTimer.SynMod:=false;
  if (not FileExists(Device)) or (not Enabled) then begin
    if Assigned(BlockSerial) then begin
  //    writeln('Socket Closed!!!');
      FreeAndNil(BlockSerial);
      BlockSerial:=nil;
    end;
  end
  else begin
    if not Assigned(BlockSerial) then begin
//      writeln('Verbunden mit "',Device,'"');

      if Assigned(BlockSerial) then begin
        BlockSerial.Free;
        BlockSerial:=nil;
      end;

      BlockSerial:=TBlockSerial.Create;
      BlockSerial.Purge;
      BlockSerial.LinuxLock:=False;
      BlockSerial.RaiseExcept:=False;
//      BlockSerial.ConvertLineEnd:=True;
      BlockSerial.Connect(Device);
      sleep(1000);
      BlockSerial.Config(9600,8,'N',SB1,false,false);
      sleep(500);

      TimerEvent1;
    end;
  end;
end; // TPLArduinoPCInterface_Uart.SetEnabled

procedure TPLArduinoPCInterface_Uart.TimerEvent1;
var
  signal:string;
begin
  if (Assigned(BlockSerial)) then begin
//    if BlockSerial.CanRead(1) then begin
      signal := BlockSerial.Recvstring(1);
      if BlockSerial.LastError <> 0 then exit;
//      writeln('signal:',signal);
      DoOnData(Trim(signal),DeviceIndex);
      sleep(100);
  //  end;
  end;
end; // TPLArduinoPCInterface_Uart.TimerEvent1

procedure TPLArduinoPCInterface_Uart.SendAString(const aValue: String);
begin
  if (Enabled) and (BlockSerial.CanWrite(1)) then begin
//    writeln('"',Trim(aValue),'"');
    BlockSerial.SendString(Trim(aValue)+#10);
  end;
end; // TPLArduinoPCInterface_Uart.SendAString

procedure TPLArduinoPCInterface_Uart.OnSenderTimer;
begin
end; // TPLArduinoPCInterface_Uart.OnSenderTimer

constructor TPLArduinoPCInterface_Uart.Create(const aUSB_Device:string);
begin
  inherited Create(aUSB_Device);
  Name:='USB Interface';
  Description:='Eine Daten Verbindung über USB per Uart';
  fEnabled:=False;
  NoEvent:=false;
  Lock:=false;

  LogIndex:=0;
  WorkIndex:=0;
  Log:=TStringList.Create;

//  SendeTimer:=TPLThreadTimer.Create(false);
//  SendeTimer.Enabled:=false;
//  SendeTimer.Interval:=100;
//  SendeTimer.OnTimerEvent:=@OnSenderTimer;
end; // TPLArduinoPCInterface_Uart.Create

destructor TPLArduinoPCInterface_Uart.Destroy;
begin
  Enabled:=false;
  Log.Free; SendeTimer.Free;
  inherited Destroy;
end; // TPLArduinoPCInterface_Uart.Destroy

procedure TPLArduinoPCInterfaceBase.SetEnabled(AValue: Boolean);
begin
  if fEnabled=AValue then Exit;
  fEnabled:=AValue;
  if Enabled then begin
    if Assigned(ThreadTimer) then FreeAndNil(ThreadTimer);
    ThreadTimer:=TPLThreadTimer.Create(True);
    ThreadTimer.Interval:=2;
    ThreadTimer.OnTimerEvent:=@TimerEvent1;
  end;

  ThreadTimer.Enabled:=AValue;
end; // TPLArduinoPCInterfaceBase.SetEnabled

procedure TPLArduinoPCInterfaceBase.TimerEvent1;
begin

end; // TPLArduinoPCInterfaceBase.TimerEvent1

procedure TPLArduinoPCInterfaceBase.DoOnData(const data: string; const aDeviceIndex:Integer);
begin
  if Assigned(OnData) then begin
    OnData(Data, aDeviceIndex);
  end;
end; // TPLArduinoPCInterfaceBase.DoOnData

procedure TPLArduinoPCInterfaceBase.SendAString(const aValue: String);
begin

end; // TPLArduinoPCInterfaceBase.SendAString

{ TPLArduinoPCInterfaceBase }
constructor TPLArduinoPCInterfaceBase.Create(const aDevice:String);
begin
  inherited Create;
  OK:=false;

  if FileExists(aDevice) then begin
    fError:=1;
    Device:=aDevice
  end
  else begin
    Device:='';
    fError:=0;
    writeln(format('Device %S gibt es nicht !!!',[aDevice]));
  end;
  ThreadTimer:=nil;
  fOnData:=nil;

  fName:='';
  fDescription:='';
  fEnabled:=false;
end; // TPLArduinoPCInterfaceBase.Create

destructor TPLArduinoPCInterfaceBase.Destroy;
begin
  Enabled:=False;
  if Assigned(ThreadTimer) then begin
    ThreadTimer.Free;
  end;

  inherited Destroy;
end; // TPLArduinoPCInterfaceBase.Destroy

end.

