
uses
  Crt,
  CrtWin,
  Kernel,
  CoBase,
  CoEth01,
  CoINET,
  CoUDP,
  NumToStr;

const
  g_fAppStop: Boolean = False;


procedure PrintEthStatistics( Sock: PCoDevice );
const
  PAD = 6;
var
  Counters : TEthCounters;
  Status   : TCoStatus;
  Delta    : Longint;
begin
  Status := Sock^.CoIoctl( DEV_CLASS_NIC, 0,
              IOCTL_ETH01_GETCOUNTERS, @Counters, SizeOf( Counters ), nil );

  if Status = CST_SUCCESS then
  begin

    WriteLn( 'Frames Sent             ', Counters[ ETHCTR_TX_FRAMES ]: PAD );
    Write  ( 'Frames Received         ', Counters[ ETHCTR_RX_FRAMES ]: PAD );
    Delta := Counters[ ETHCTR_TX_FRAMES ] - Counters[ ETHCTR_RX_FRAMES ];
    if Delta >= 0 then
      WriteLn( '   +', Delta, ' ' )
    else
      WriteLn( '   ', Delta, ' ' );
    WriteLn;
    WriteLn( 'TX Single Collisions    ', Counters[ ETHCTR_TX_SINGLECOL ]: PAD );
    WriteLn( 'TX Multiple Collisions  ', Counters[ ETHCTR_TX_MULTIPLECOL ]: PAD  );
    WriteLn( 'TX Defferals            ', Counters[ ETHCTR_TX_DEFFERAL ]: PAD );
    WriteLn( 'TX Excessive Defferals  ', Counters[ ETHCTR_TX_EXCDEFFERAL ]: PAD );
    WriteLn( 'TX Carrier Lost         ', Counters[ ETHCTR_TX_LOSTCARRIER ]: PAD );
    WriteLn( 'TX SQET                 ', Counters[ ETHCTR_TX_SQET ]: PAD );
    WriteLn( 'TX Link Error           ', Counters[ ETHCTR_TX_LINKERROR ]: PAD );
    WriteLn( 'TX Underrun             ', Counters[ ETHCTR_TX_UNDERRUN ]: PAD );
    WriteLn( 'TX Late Collisions      ', Counters[ ETHCTR_TX_LATECOL ]: PAD );
    WriteLn( 'TX 16 Collisions        ', Counters[ ETHCTR_TX_16COL ]: PAD );
    WriteLn;
    WriteLn( 'RX Frame Too Short      ', Counters[ ETHCTR_RX_TOOSHORT ]: PAD );
    WriteLn( 'RX Frame Too Long       ', Counters[ ETHCTR_RX_TOOLONG ]: PAD );
    WriteLn( 'RX FIFO Overrun         ', Counters[ ETHCTR_RX_OVERRUN ]: PAD );
    WriteLn( 'RX Bad CRC              ', Counters[ ETHCTR_RX_BADCRC ]: PAD );
    WriteLn( 'RX Invalid Header       ', Counters[ ETHCTR_RX_INVHEADER ]: PAD );
    WriteLn( 'RX Discards             ', Counters[ ETHCTR_RX_DISCARDS ]: PAD );

  end
  else
    WriteLn( 'CoIoctl failed(): ', CoStatusToStr( Status ) );
end;


procedure EchoTest( const AProcName: String; APortNumber: Word; AX: Integer ); far;
var
  Sock     : PCoDevice;
  Status   : TCoStatus;
  RecvBuff : array[0..4095] of Byte;
  RecvLen  : Word;
  SrcAddr  : TCoAddress;


  Win      : TCrtWin;

const
  Rect     : TRect = (X: 0; Y: 2; W: 37; H: 22);

begin

  Rect.X := AX * 40 + 2;

  Win.Init( Rect, AProcName, FrameS, $17, $2E, $3F, 2, 8 );

  Start(AProcName, 8192, 100, 254); Exit;
  repeat

    Win.LockWin;

    Status := NetOpenSocket( 'UDP', 'LPORT=' + WordStrDec(APortNumber, 0),
                              '', Sock );



    if Status <> CST_SUCCESS then
    begin
      WriteLn( 'NetOpenSocket() failed: ', CoStatusToStr( Status ) );
      Exit;
    end;

    Status := Sock^.CoBind( nil, COF_PROPAGATE , nil );

    if Status <> CST_SUCCESS then
    begin
      WriteLn( 'CoBind() failed: ', CoStatusToStr( Status ) );
      NetCloseSocket( Sock );
      Exit;
    end;


    WriteLn( 'UDP port initialized' );

    WriteLn( 'Press any key to leave test' );

    ClrScr;

    Win.Unlockwin;

    repeat

      Status := Sock^.CoRecvBufferFrom( @RecvBuff, SizeOf( RecvBuff ),
                                          @RecvLen, 0, @SrcAddr, nil );

      Win.Lockwin;

      GotoXY( 1, 2 );

      PrintEthStatistics( Sock );

      case Status of

        CST_SUCCESS:
        begin

          Status := Sock^.CoSendBufferTo( @RecvBuff, RecvLen, 0,
                                            @SrcAddr, nil );

          if Status <> CST_SUCCESS then
          begin
            WriteLn( 'CoSendBufferTo() failed: ', CoStatusToStr( Status ) );
          end;


        end;

        CST_ERR_TIMEOUT:
        begin
        end;

      else

        WriteLn( 'CoRecvBufferFrom() failed: ', CoStatusToStr( Status ) );

      end;

      Win.UnlockWin;

    until g_fAppStop;

    Status := Sock^.CoUnbind( 0, nil );

    if Status <> CST_SUCCESS then
    begin
      WriteLn( 'CoUnbind() failed: ', CoStatusToStr( Status ) );
    end;

    NetCloseSocket( Sock );

  until g_fAppStop;
end;



procedure MyCoSleep( Miliseconds: Word ); far;
begin
  Wait( 1 );
end;


var
  Status: TCoStatus;

begin
  StartMain(230, 0);
  InitInterruptStack(1, 4096);
  StartTimeSlicing(8);

  { Otevreni TCP/IP stacku }

  Status := NetOpenStack( 'ETH01', 'IOBASE=$300',
             'IPADDR="192.168.1.210" REASMTO=5000', '' );

  if Status <> CST_SUCCESS then
  begin
    WriteLn( 'NetOpenStack() failed: ', CoStatusToStr( Status ) );
    Exit;
  end;

  WriteLn( 'TCP/IP stack initialized' );

  CrtInit;

  { Spusteni testu }

  EchoTest('T1', 5000, 0);
  EchoTest('T2', 5001, 1);

  SetPriority(1, 254);

  repeat
    Kernel.Wait(1);
    if KeyPressed then g_fAppStop := True;
  until g_fAppStop;


  NetCloseStack( '' );

  Abort('*');
  TerminateMain;

  { Uzavreni TCP/IP stacku }

end.