enet_1.0.0_54410889/src/net-generic_receiver.adb

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
-----------------------------------------------------------------------
--  receiver -- Ethernet Packet Receiver
--  Copyright (C) 2016-2024 Stephane Carrez
--  Written by Stephane Carrez (Stephane.Carrez@gmail.com)
--
--  Licensed under the Apache License, Version 2.0 (the "License");
--  you may not use this file except in compliance with the License.
--  You may obtain a copy of the License at
--
--      http://www.apache.org/licenses/LICENSE-2.0
--
--  Unless required by applicable law or agreed to in writing, software
--  distributed under the License is distributed on an "AS IS" BASIS,
--  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
--  See the License for the specific language governing permissions and
--  limitations under the License.
-----------------------------------------------------------------------
with Ada.Real_Time;
with Ada.Synchronous_Task_Control;
with Net.Buffers;
with Net.Protos.Arp;
with Net.Protos.Dispatchers;
with Net.Headers;

package body Net.Generic_Receiver is

   Ready  : Ada.Synchronous_Task_Control.Suspension_Object;
   ONE_US : constant Ada.Real_Time.Time_Span := Ada.Real_Time.Microseconds (1);

   ETHERTYPE_ARP : constant Net.Uint16 :=
     Net.Headers.To_Network (Net.Protos.ETHERTYPE_ARP);

   ETHERTYPE_IP : constant Net.Uint16 :=
     Net.Headers.To_Network (Net.Protos.ETHERTYPE_IP);

   --  ------------------------------
   --  Start the receiver loop.
   --  ------------------------------
   procedure Start is
   begin
      Ada.Synchronous_Task_Control.Set_True (Ready);
   end Start;

   task body Controller is
      use type Ada.Real_Time.Time;
      use type Ada.Real_Time.Time_Span;
      use type Net.Uint64;

      Packet  : Net.Buffers.Buffer_Type;
      Ether   : Net.Headers.Ether_Header_Access;
      Now     : Ada.Real_Time.Time;
      Dt      : Us_Time;
      Total   : Net.Uint64 := 0;
      Count   : Net.Uint64 := 0;
   begin
      --  Wait until the Ethernet driver is ready.
      Ada.Synchronous_Task_Control.Suspend_Until_True (Ready);

      --  Loop receiving packets and dispatching them.
      Min_Receive_Time := Us_Time'Last;
      Max_Receive_Time := Us_Time'First;
      loop
         if Packet.Is_Null then
            Net.Buffers.Allocate (Packet);
         end if;
         if not Packet.Is_Null then
            Ifnet.Receive (Packet);
            Now := Ada.Real_Time.Clock;
            Ether := Packet.Ethernet;
            if Ether.Ether_Type = ETHERTYPE_ARP then
               Net.Protos.Arp.Receive (Ifnet, Packet);
            elsif Ether.Ether_Type = ETHERTYPE_IP then
               Net.Protos.Dispatchers.Receive (Ifnet, Packet);
            end if;

            --  Compute the time taken to process the packet in microseconds.
            Dt := Us_Time ((Ada.Real_Time.Clock - Now) / ONE_US);

            --  Compute average, min and max values.
            Count := Count + 1;
            Total := Total + Net.Uint64 (Dt);
            Avg_Receive_Time := Us_Time (Total / Count);
            if Dt < Min_Receive_Time then
               Min_Receive_Time := Dt;
            end if;
            if Dt > Max_Receive_Time then
               Max_Receive_Time := Dt;
            end if;
         else
            delay until Ada.Real_Time.Clock + Ada.Real_Time.Milliseconds (100);
         end if;
      end loop;
   end Controller;

end Net.Generic_Receiver;