unit UCommPin;

{$mode Delphi}{$H+}{$M+}

interface

uses
  Classes, SpecializedList;

type
  TCommPin = class;
  TCommNode = class;

  TDataDiretion = (ddReceive, ddSend);
  TOnLogDataEvent = procedure (Stream: TListByte; Direction: TDataDiretion) of object;
  TOnStreamEvent = procedure (Sender: TCommPin; Stream: TListByte) of object;
  TOnSetStatus = procedure (Sender: TCommPin; Status: Integer) of object;

  { TCommPin }

  TCommPin = class
  private
    FOnLogData: TOnLogDataEvent;
    FOnReceive: TOnStreamEvent;
    FDataTxCount: Integer;
    FDataRxCount: Integer;
    FFrameTxCount: Integer;
    FFrameRxCount: Integer;
    FOnSetStatus: TOnSetStatus;
    FRemotePin: TCommPin;
    FStatus: Integer;
    function GetConnected: Boolean;
    procedure SetRemotePin(AValue: TCommPin);
    procedure SetStatus(AValue: Integer);
  protected
    procedure Receive(Stream: TListByte);
    procedure ReceiveStatus(AValue: Integer);
  public
    Node: TCommNode;
    constructor Create;
    destructor Destroy; override;
    procedure Connect(Pin: TCommPin);
    procedure Disconnect;
    procedure Send(Stream: TListByte);
    procedure ResetCounters;
    property RemotePin: TCommPin read FRemotePin write SetRemotePin;
    property Connected: Boolean read GetConnected;
    property OnLogData: TOnLogDataEvent read FOnLogData write FOnLogData;
    property DataTxCount: Integer read FDataTxCount;
    property DataRxCount: Integer read FDataRxCount;
    property FrameTxCount: Integer read FFrameTxCount;
    property FrameRxCount: Integer read FFrameRxCount;
    property Status: Integer read FStatus write SetStatus; // Used for general status bits such as parity bit
    property OnReceive: TOnStreamEvent read FOnReceive write FOnReceive;
    property OnSetSatus: TOnSetStatus read FOnSetStatus write FOnSetStatus;
  end;

  { TCommNode }

  TCommNode = class(TComponent)
  private
  protected
    FActive: Boolean;
    procedure SetActive(const AValue: Boolean); virtual;
  public
    property Active: Boolean read FActive write SetActive;
  end;

  { TCommNodeSimple }

  TCommNodeSimple = class(TCommNode)
  public
    Pin: TCommPin;
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
  end;

implementation

{ TCommNodeSimple }

constructor TCommNodeSimple.Create(AOwner: TComponent);
begin
  inherited;
  Pin := TCommPin.Create;
end;

destructor TCommNodeSimple.Destroy;
begin
  Pin.Free;
  inherited Destroy;
end;

{ TCommNode }

procedure TCommNode.SetActive(const AValue: Boolean);
begin
  if FActive = AValue then Exit;
  FActive := AValue;
end;

{ TCommPin }

procedure TCommPin.Connect(Pin: TCommPin);
begin
  RemotePin := Pin;
end;

destructor TCommPin.Destroy;
begin
  Disconnect;
  inherited;
end;

procedure TCommPin.Disconnect;
begin
  RemotePin := nil;
end;

function TCommPin.GetConnected: Boolean;
begin
  Result := Assigned(RemotePin);
end;

procedure TCommPin.SetRemotePin(AValue: TCommPin);
begin
  if FRemotePin = AValue then Exit;
  if Assigned(FRemotePin) then
    FRemotePin.FRemotePin := nil;
  FRemotePin := AValue;
  if Assigned(FRemotePin) then begin
    FRemotePin.RemotePin := Self;
    FRemotePin.ReceiveStatus(FStatus);
  end;
end;

procedure TCommPin.SetStatus(AValue: Integer);
begin
  FStatus := AValue;
  if Assigned(RemotePin) then RemotePin.ReceiveStatus(AValue);
end;

constructor TCommPin.Create;
begin
  FRemotePin := nil;
  FStatus := 0;
  ResetCounters;
end;

procedure TCommPin.Receive(Stream: TListByte);
begin
  Inc(FDataRxCount, Stream.Count);
  Inc(FFrameRxCount);
  if Assigned(FOnLogData) then FOnLogData(Stream, ddReceive);
  if Assigned(FOnReceive) then FOnReceive(Self, Stream);
end;

procedure TCommPin.ReceiveStatus(AValue: Integer);
begin
  if Assigned(FOnSetStatus) then FOnSetStatus(Self, AValue);
end;

procedure TCommPin.ResetCounters;
begin
  FDataTxCount := 0;
  FDataRxCount := 0;
  FFrameTxCount := 0;
  FFrameRxCount := 0;
end;

procedure TCommPin.Send(Stream: TListByte);
begin
  Inc(FDataTxCount, Stream.Count);
  Inc(FFrameTxCount);
  if Assigned(FOnLogData) then FOnLogData(Stream, ddSend);
  if Assigned(RemotePin) then RemotePin.Receive(Stream);
end;


end.
