A4A : Infrastructure Messagerie Hilscher cifX – Layer 2 – Objet

Bonjour,

L’infrastructure présentée dans l’article précédent permet d’utiliser un canal de communication.

Cependant, certaines cartes Hilscher cifX offrent deux canaux de communication et l’API en prévoit jusqu’à quatre.

Et il est possible de gérer un nombre illimité de cartes Hilscher cifX sur la même machine.

Aussi, il est nécessaire de rendre le code réutilisable le plus simplement possible et c’est ce que réalise le paquetage « A4A.Protocols.HilscherX.Channel_Messaging » sous forme d’objet.

La spécification du paquetage ci-dessous montre :

  • l’instanciation du paquetage « Pool » avec une taille par défaut,
  • l’instanciation du paquetage « Queue » avec une taille de 1, nous y reviendrons,
  • l’instanciation du paquetage « Queue » avec une taille par défaut,
  • et un objet défini par son interface et ses données d’instance.

Dans les données d’instance on trouve le réservoir de paquets, la queue en émission, la queue par défaut en réception et les deux tâches d’émission et réception qui exercent leur activité sur les données d’instance.

J’adore cette construction ! A chaque instanciation de cet objet, les tâches sont automatiquement créées.
Un objet très actif donc.

En fonction du besoin, l’utilisateur de cet objet peut, soit déclarer sa propre queue en réception, soit utiliser celle par défaut. Pour les fonctions en mode Client / Serveur, on peut utiliser la queue de taille 1 car on n’attend que la réponse à la requête.

-----------------------------------------------------------------------
--                       Ada for Automation                          --
--                                                                   --
--              Copyright (C) 2012-2014, Stephane LOS                --
--                                                                   --
-- This library is free software; you can redistribute it and/or     --
-- modify it under the terms of the GNU General Public               --
-- License as published by the Free Software Foundation; either      --
-- version 2 of the License, or (at your option) any later version.  --
--                                                                   --
-- This library is distributed in the hope that it will be useful,   --
-- but WITHOUT ANY WARRANTY; without even the implied warranty of    --
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU --
-- General Public License for more details.                          --
--                                                                   --
-- You should have received a copy of the GNU General Public         --
-- License along with this library; if not, write to the             --
-- Free Software Foundation, Inc., 59 Temple Place - Suite 330,      --
-- Boston, MA 02111-1307, USA.                                       --
--                                                                   --
-- As a special exception, if other files instantiate generics from  --
-- this unit, or you link this unit with other files to produce an   --
-- executable, this  unit  does not  by itself cause  the resulting  --
-- executable to be covered by the GNU General Public License. This  --
-- exception does not however invalidate any other reasons why the   --
-- executable file  might be covered by the  GNU Public License.     --
-----------------------------------------------------------------------

-- <summary>
-- This package provides the binding to Hilscher cifX Device Driver,
-- a library allowing access to the cifX boards with numerous protocols.
-- </summary>
-- <description>
-- It provides :
-- - messaging infrastructure.
-- </description>
-- <group>Protocols</group>
-- <c_version>3.0.1</c_version>

with A4A.Protocols.HilscherX.cifX_Errors;
use A4A.Protocols.HilscherX.cifX_Errors;

with A4A.Protocols.HilscherX.cifX_User;
use A4A.Protocols.HilscherX.cifX_User;

with A4A.Protocols.HilscherX.Message_Queue;
with A4A.Protocols.HilscherX.Message_Pool;

package A4A.Protocols.HilscherX.Channel_Messaging is

   Default_Pool_Size  : constant := 20;
   Default_Queue_Size : constant := 10;

   package Pool_Package is new
     A4A.Protocols.HilscherX.Message_Pool (Pool_Size => Default_Pool_Size);

   package Queue_Package_Single is new
     A4A.Protocols.HilscherX.Message_Queue (Queue_Size => 1);

   package Queue_Package_Multiple is new
     A4A.Protocols.HilscherX.Message_Queue (Queue_Size => Default_Queue_Size);

   Queue_Package_Type_Single   : constant := 0;
   Queue_Package_Type_Multiple : constant := 1;

   type Instance is tagged limited private;
   type Instance_Access is access all Instance;

   procedure Initialise
     (Channel        : in out Instance;
      Channel_Handle : in Channel_Handle_Type);

   procedure Quit
     (Channel : in out Instance);

   function Is_Terminated
     (Channel : in Instance) return Boolean;

   procedure Get_Packet
     (Channel : in out Instance;
      Item    : out cifX_Packet_Access;
      Result  : out Boolean);
   -- Get a packet from the Packet Pool
   -- Returns False if the Pool is empty

   procedure Return_Packet
     (Channel : in out Instance;
      Item    : in cifX_Packet_Access);
   -- Return a packet to the Packet Pool

   procedure Send
     (Channel : in out Instance;
      Item    : in cifX_Packet_Access;
      Result  : out Boolean);
   -- Send a packet via the Packet Queue
   -- Returns False if the Queue is full

   procedure Receive
     (Channel : in out Instance;
      Item    : out cifX_Packet_Access;
      Result  : out Boolean);
   -- Receive a packet from the default receive queue
   -- Returns False if no packet was available

private

   Package_Ident : String := "A4A.Protocols.HilscherX.Channel_Messaging";

   task type Send_Msg_Task_Type
     (Channel : access Instance);

   task type Receive_Msg_Task_Type
     (Channel : access Instance);

   type Instance is tagged limited
      record

         Quit_Flag : Boolean := False;
         Init_Flag : Boolean := False;

         Send_Task_Terminated    : Boolean := False;
         Receive_Task_Terminated : Boolean := False;

         The_Channel_Handle  : Channel_Handle_Type;

         Message_Pool  : Pool_Package.Message_Pool_Type;

         Send_Queue    : Queue_Package_Multiple.Message_Queue_Type;
         Receive_Queue : Queue_Package_Multiple.Message_Queue_Type;

         Send_Msg_Task    : Send_Msg_Task_Type (Instance'Access);
         Receive_Msg_Task : Receive_Msg_Task_Type (Instance'Access);

      end record;

end A4A.Protocols.HilscherX.Channel_Messaging;

Le corps de ce paquetage reprend le principe déjà présenté dans l’article précédent, hormis le fait qu’il travaille maintenant sur les données d’instance de l’objet.

On notera cependant que le routage des paquets vers les queues de destination est implémenté.

Selon que le paquet est une réponse ou une indication, le champ Cmd dans l’en-tête du paquet est pair ou impair, l’utilisation des informations de routage est différente puisque dans un cas il faut retourner la réponse à la source de la requête et dans l’autre il faut transmettre l’indication au destinataire de celles-ci, qui n’est autre que celui qui s’est enregistré, nous verrons cela ultérieurement.

Les champs Src et Dest indiquent le type de queue, single ou multiple, ce qui est une utilisation un peu détournée de l’utilisation prévue et explicitée dans le document netX Dual Port Memory Interface.

Les champs Src_Id et Dest_Id transportent la référence à la queue de l’émetteur ou du destinataire et, comme Ada est un langage fortement typé, il est nécessaire de recourir à des conversions de type « Access / DWord ».

-----------------------------------------------------------------------
--                       Ada for Automation                          --
--                                                                   --
--              Copyright (C) 2012-2014, Stephane LOS                --
--                                                                   --
-- This library is free software; you can redistribute it and/or     --
-- modify it under the terms of the GNU General Public               --
-- License as published by the Free Software Foundation; either      --
-- version 2 of the License, or (at your option) any later version.  --
--                                                                   --
-- This library is distributed in the hope that it will be useful,   --
-- but WITHOUT ANY WARRANTY; without even the implied warranty of    --
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU --
-- General Public License for more details.                          --
--                                                                   --
-- You should have received a copy of the GNU General Public         --
-- License along with this library; if not, write to the             --
-- Free Software Foundation, Inc., 59 Temple Place - Suite 330,      --
-- Boston, MA 02111-1307, USA.                                       --
--                                                                   --
-- As a special exception, if other files instantiate generics from  --
-- this unit, or you link this unit with other files to produce an   --
-- executable, this  unit  does not  by itself cause  the resulting  --
-- executable to be covered by the GNU General Public License. This  --
-- exception does not however invalidate any other reasons why the   --
-- executable file  might be covered by the  GNU Public License.     --
-----------------------------------------------------------------------

-- <summary>
-- This package provides the binding to Hilscher cifX Device Driver,
-- a library allowing access to the cifX boards with numerous protocols.
-- </summary>
-- <description>
-- It provides :
-- - messaging infrastructure.
-- </description>
-- <group>Protocols</group>
-- <c_version>3.0.1</c_version>

with A4A.Log;

package body A4A.Protocols.HilscherX.Channel_Messaging is

   procedure Initialise
     (Channel        : in out Instance;
      Channel_Handle : in Channel_Handle_Type) is
   begin

      Channel.The_Channel_Handle := Channel_Handle;

      Channel.Message_Pool.Initialise;

      Channel.Init_Flag := True;

   end Initialise;

   procedure Quit
     (Channel : in out Instance) is
   begin
      Channel.Quit_Flag := True;
   end Quit;

   function Is_Terminated
     (Channel : in Instance) return Boolean is
   begin

      return Channel.Send_Task_Terminated and Channel.Receive_Task_Terminated;

   end Is_Terminated;

   procedure Get_Packet
     (Channel : in out Instance;
      Item    : out cifX_Packet_Access;
      Result  : out Boolean) is
   begin

      Channel.Message_Pool.Get_Packet (Item, Result);

   end Get_Packet;

   procedure Return_Packet
     (Channel : in out Instance;
      Item    : in cifX_Packet_Access) is
   begin

      Channel.Message_Pool.Return_Packet (Item);

   end Return_Packet;

   procedure Send
     (Channel : in out Instance;
      Item    : in cifX_Packet_Access;
      Result  : out Boolean) is
   begin

      Channel.Send_Queue.Put (Item, Result);

   end Send;

   procedure Receive
     (Channel : in out Instance;
      Item    : out cifX_Packet_Access;
      Result  : out Boolean) is
   begin

      Channel.Receive_Queue.Get (Item, Result);

   end Receive;

   task body Send_Msg_Task_Type is

      Packet    : cifX_Packet_Access;

      Result    : DInt;

   begin

      loop

         delay 1.0;
         exit when Channel.Init_Flag or Channel.Quit_Flag;

      end loop;

      loop

         exit when Channel.Quit_Flag;

         select

            Channel.Send_Queue.Get (Item => Packet);

            Result := Channel_Put_Packet
              (Channel_Handle => Channel.The_Channel_Handle,
               Send_Packet    => Packet.all,
               Time_Out       => 10);
            if Result /= CIFX_NO_ERROR then
               Show_Error (Result);
            end if;

            Channel.Message_Pool.Return_Packet (Item => Packet);

         or

            delay 1.0;

         end select;

      end loop;

      Channel.Send_Task_Terminated := True;

   end Send_Msg_Task_Type;

   task body Receive_Msg_Task_Type is

      My_Ident : String := Package_Ident & ".Receive_Msg_Task_Type";

      Packet     : cifX_Packet_Access;

      Result     : DInt;

      Queue_Type : DWord;
      Queue_Id   : DWord;

      Packet_Got : Boolean := False;
      Packet_Put : Boolean := False;

      Message_Queue_Single_Access : Queue_Package_Single.Message_Queue_Access;
      Message_Queue_Multiple_Access :
      Queue_Package_Multiple.Message_Queue_Access;

      procedure Dump_Packet is

         Dest_String    : String (1.. 20);
         Src_String     : String (1.. 20);
         Dest_Id_String : String (1.. 20);
         Src_Id_String  : String (1.. 20);
         Cmd_String     : String (1.. 20);

      begin

         DWord_Text_IO.Put
           (To   => Dest_String,
            Item => Packet.Header.Dest,
            Base => 16);

         DWord_Text_IO.Put
           (To   => Src_String,
            Item => Packet.Header.Src,
            Base => 16);

         DWord_Text_IO.Put
           (To   => Dest_Id_String,
            Item => Packet.Header.Dest_Id,
            Base => 16);

         DWord_Text_IO.Put
           (To   => Src_Id_String,
            Item => Packet.Header.Src_Id,
            Base => 16);

         DWord_Text_IO.Put
           (To   => Cmd_String,
            Item => Packet.Header.Cmd,
            Base => 16);

         A4A.Log.Logger.Put
           (Who  => My_Ident,
            What => "Got a message : " & CRLF
            & "Dest    : " & Dest_String & CRLF
            & "Src     : " & Src_String & CRLF
            & "Dest_Id : " & Dest_Id_String & CRLF
            & "Src_Id  : " & Src_Id_String & CRLF
            & "Cmd     : " & Cmd_String
           );

      end Dump_Packet;

   begin

      loop

         delay 1.0;
         exit when Channel.Init_Flag or Channel.Quit_Flag;

      end loop;

      loop

         exit when Channel.Quit_Flag;

         if not Packet_Got then

            Channel.Message_Pool.Get_Packet
              (Item   => Packet,
               Result => Packet_Got);

         end if;

         if not Packet_Got then

            A4A.Log.Logger.Put (Who  => My_Ident,
                                What => "Could not get packet from pool...");

         else

            Result := Channel_Get_Packet
              (Channel_Handle => Channel.The_Channel_Handle,
               Size           => cifX_Packet_Type'Size / 8,
               Recv_Packet    => Packet.all,
               Time_Out       => 1000);
            if Result = CIFX_NO_ERROR then

               Dump_Packet;

               if (Packet.Header.Cmd and 1) = 0 then

                  -- It's an indication
                  Queue_Type := Packet.Header.Dest;
                  Queue_Id := Packet.Header.Dest_Id;

               else

                  -- It's a response
                  Queue_Type := Packet.Header.Src;
                  Queue_Id := Packet.Header.Src_Id;

               end if;

               if Queue_Id /= 0 then

                  if Queue_Type = Queue_Package_Type_Single then

                     Message_Queue_Single_Access :=
                       Queue_Package_Single.To_Message_Queue (Queue_Id);

                     Message_Queue_Single_Access.Put
                       (Item   => Packet,
                        Result => Packet_Put);

                  else

                     Message_Queue_Multiple_Access :=
                       Queue_Package_Multiple.To_Message_Queue (Queue_Id);

                     Message_Queue_Multiple_Access.Put
                       (Item   => Packet,
                        Result => Packet_Put);

                  end if;

               else

                  Channel.Receive_Queue.Put
                    (Item   => Packet,
                     Result => Packet_Put);

               end if;

               Packet_Got := False;

            elsif Result = CIFX_DEV_GET_TIMEOUT
              or Result = CIFX_DEV_GET_NO_PACKET then

               A4A.Log.Logger.Put (Who  => My_Ident,
                                   What => "No packet pending.");

            else

               Show_Error (Result);

            end if;

         end if;

      end loop;

      Channel.Receive_Task_Terminated := True;

   end Receive_Msg_Task_Type;

end A4A.Protocols.HilscherX.Channel_Messaging;

Le programme de tests « Test_Channel_Messaging » ci-dessous reprend les grandes lignes de celui d’hier.

Il se déroule en deux temps, l’un en utilisant la queue de réception par défaut, l’autre en utilisant une queue de réception en propre.

Cette queue de réception en propre peut être du type « single » ou « multiple ». On utiliserait « multiple » afin de récupérer un flot d’indications par exemple.

-----------------------------------------------------------------------
--                       Ada for Automation                          --
--                                                                   --
--              Copyright (C) 2012-2014, Stephane LOS                --
--                                                                   --
-- This library is free software; you can redistribute it and/or     --
-- modify it under the terms of the GNU General Public               --
-- License as published by the Free Software Foundation; either      --
-- version 2 of the License, or (at your option) any later version.  --
--                                                                   --
-- This library is distributed in the hope that it will be useful,   --
-- but WITHOUT ANY WARRANTY; without even the implied warranty of    --
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU --
-- General Public License for more details.                          --
--                                                                   --
-- You should have received a copy of the GNU General Public         --
-- License along with this library; if not, write to the             --
-- Free Software Foundation, Inc., 59 Temple Place - Suite 330,      --
-- Boston, MA 02111-1307, USA.                                       --
--                                                                   --
-- As a special exception, if other files instantiate generics from  --
-- this unit, or you link this unit with other files to produce an   --
-- executable, this  unit  does not  by itself cause  the resulting  --
-- executable to be covered by the GNU General Public License. This  --
-- exception does not however invalidate any other reasons why the   --
-- executable file  might be covered by the  GNU Public License.     --
-----------------------------------------------------------------------


with Interfaces.C;

with Ada.Exceptions; use Ada.Exceptions;

with A4A; use A4A;

with A4A.Log;

with A4A.Protocols.HilscherX.cifX_Errors;
use A4A.Protocols.HilscherX.cifX_Errors;

with A4A.Protocols.HilscherX.cifX_User;

with A4A.Protocols.HilscherX.rcX_Public.rcX_Firmware_Identify;
use A4A.Protocols.HilscherX.rcX_Public.rcX_Firmware_Identify;

with A4A.Protocols.HilscherX.Channel_Messaging;
use A4A.Protocols.HilscherX.Channel_Messaging;

procedure Test_Channel_Messaging is

   My_Ident : String := "Test_Channel_Messaging";

   package cifX renames A4A.Protocols.HilscherX.cifX_User;

   Driver_Handle  : aliased cifX.Driver_Handle_Type;
   Channel_Handle : aliased cifX.Channel_Handle_Type;

   Result : DInt;

   Request      : cifX.cifX_Packet_Access;
   Confirmation : cifX.cifX_Packet_Access;

   cifX_Driver_Init_Done  : Boolean := False;
   cifX_Driver_Open_Done  : Boolean := False;
   cifX_Channel_Open_Done : Boolean := False;

   Fw_Ident_Req : RCX_FIRMWARE_IDENTIFY_REQ_T_Access;
   Fw_Ident_Cnf : RCX_FIRMWARE_IDENTIFY_CNF_T_Access;

   Packet_Got  : Boolean := False;
   Packet_Sent : Boolean := False;
   Answer_Got  : Boolean := False;

   My_Channel_Messaging : A4A.Protocols.HilscherX.Channel_Messaging.Instance;

   -- My_Receive_Queue : aliased Queue_Package_Single.Message_Queue_Type;
   -- My_Receive_Queue_Type : constant := Queue_Package_Type_Single;
   My_Receive_Queue : aliased Queue_Package_Multiple.Message_Queue_Type;
   My_Receive_Queue_Type : constant := Queue_Package_Type_Multiple;

   procedure cifX_Show_Error (Error : DInt) is
   begin
      A4A.Log.Logger.Put
        (Who  => My_Ident,
         What => cifX.Driver_Get_Error_Description(Error));
   end cifX_Show_Error;

   procedure cifX_Show_Firmware_Identification is
      What : String := CRLF
        & "***********************************************" & CRLF
        & "          Firmware Identification" & CRLF & CRLF
        & "Firmware Version :" & CRLF
        & "Major    : "
        & Fw_Ident_Cnf.Data.Fw_Identification.Fw_Version.Major'Img & CRLF
        & "Minor    : "
        & Fw_Ident_Cnf.Data.Fw_Identification.Fw_Version.Minor'Img & CRLF
        & "Build    : "
        & Fw_Ident_Cnf.Data.Fw_Identification.Fw_Version.Build'Img & CRLF
        & "Revision : "
        & Fw_Ident_Cnf.Data.Fw_Identification.Fw_Version.Revision'Img & CRLF
        & CRLF
        & "Firmware Name : "
        & Interfaces.C.To_Ada
        (Fw_Ident_Cnf.Data.Fw_Identification.Fw_Name.Name) & CRLF
        & CRLF
        & "Firmware Date :" & CRLF
        & "Year  : "
        & Fw_Ident_Cnf.Data.Fw_Identification.Fw_Date.Year'Img & CRLF
        & "Month : "
        & Fw_Ident_Cnf.Data.Fw_Identification.Fw_Date.Month'Img & CRLF
        & "Day   : "
        & Fw_Ident_Cnf.Data.Fw_Identification.Fw_Date.Day'Img & CRLF
        & "***********************************************" & CRLF;
   begin
      A4A.Log.Logger.Put (Who  => My_Ident,
                          What => What);
   end cifX_Show_Firmware_Identification;

   procedure Close is
   begin

      My_Channel_Messaging.Quit;

      --Wait for completion
      loop

         exit when My_Channel_Messaging.Is_Terminated;
         delay 1.0;

      end loop;

      if cifX_Channel_Open_Done then
         A4A.Log.Logger.Put (Who  => My_Ident,
                             What => "Closing Channel");
         Result := cifX.Channel_Close (Channel_Handle);
         if Result /= CIFX_NO_ERROR then
            cifX_Show_Error(Result);
         end if;
         cifX_Channel_Open_Done := False;
      end if;

      if cifX_Driver_Open_Done then
         A4A.Log.Logger.Put (Who  => My_Ident,
                             What => "Closing Driver");
         Result := cifX.Driver_Close (Driver_Handle);
         if Result /= CIFX_NO_ERROR then
            cifX_Show_Error(Result);
         end if;
         cifX_Driver_Open_Done := False;
      end if;

      if cifX_Driver_Init_Done then
         A4A.Log.Logger.Put (Who  => My_Ident,
                             What => "Deinitializing cifX Driver");
         cifX.Driver_Deinit;
         cifX_Driver_Init_Done := False;
      end if;

      A4A.Log.Logger.Put (Who  => My_Ident,
                          What => "finished !");
      A4A.Log.Quit;

   end Close;

begin

   A4A.Log.Logger.Put (Who  => My_Ident,
                       What => "Test_Messaging...");

   A4A.Log.Logger.Put (Who  => My_Ident,
                       What => "Initializing cifX Driver");
   Result := cifX.Driver_Init;
   if Result /= CIFX_NO_ERROR then
      cifX_Show_Error(Result);
   else
      cifX_Driver_Init_Done := True;
   end if;

   if cifX_Driver_Init_Done then

      A4A.Log.Logger.Put (Who  => My_Ident,
                          What => "Opening Driver");
      Result := cifX.Driver_Open (Driver_Handle'Access);
      if Result /= CIFX_NO_ERROR then
         cifX_Show_Error(Result);
      else
         cifX_Driver_Open_Done := True;
      end if;

   end if;

   if cifX_Driver_Open_Done then

      A4A.Log.Logger.Put (Who  => My_Ident,
                          What => "Opening Channel");
      Result := cifX.Channel_Open
        (Driver_Handle          => Driver_Handle,
         Board_Name             => "cifX0",
         Channel_Number         => 0,
         Channel_Handle_Access  => Channel_Handle'Access);

      if Result /= CIFX_NO_ERROR then
         cifX_Show_Error(Result);
      else
         cifX_Channel_Open_Done := True;
      end if;

   end if;

   if cifX_Channel_Open_Done then

      My_Channel_Messaging.Initialise (Channel_Handle => Channel_Handle);

   end if;

   if cifX_Channel_Open_Done then

      A4A.Log.Logger.Put (Who  => My_Ident,
                          What => "Test with default receive queue+++");
      A4A.Log.Logger.Put (Who  => My_Ident,
                          What => "Sending Request");

      My_Channel_Messaging.Get_Packet
        (Item   => Request,
         Result => Packet_Got);

      if not Packet_Got then

         A4A.Log.Logger.Put (Who  => My_Ident,
                             What =>
                               "Could not get Request packet from pool...");

      else

         Fw_Ident_Req := From_cifX_Packet (Request);

         Fw_Ident_Req.Head.Dest    := 16#20#;
         Fw_Ident_Req.Head.Src     := 0;
         Fw_Ident_Req.Head.Dest_Id := 0;
         Fw_Ident_Req.Head.Src_Id  := 0;
         Fw_Ident_Req.Head.Len     := 4;
         Fw_Ident_Req.Head.Id      := 1;
         Fw_Ident_Req.Head.State   := 0;
         Fw_Ident_Req.Head.Cmd     := RCX_FIRMWARE_IDENTIFY_REQ;
         Fw_Ident_Req.Head.Ext     := 0;
         Fw_Ident_Req.Head.Rout    := 0;

         Fw_Ident_Req.Data.Channel_Id := 0;

         My_Channel_Messaging.Send
           (Item   => Request,
            Result => Packet_Sent);

         if not Packet_Sent then

            A4A.Log.Logger.Put (Who  => My_Ident,
                                What =>
                                  "Could not put Request packet in queue...");

            My_Channel_Messaging.Return_Packet (Item => Request);

         else

            delay 3.0;

            My_Channel_Messaging.Receive
              (Item   => Confirmation,
               Result => Answer_Got);

            if Answer_Got then

               Fw_Ident_Cnf := From_cifX_Packet (Confirmation);

               cifX_Show_Firmware_Identification;

               My_Channel_Messaging.Return_Packet (Item => Confirmation);

            else

               A4A.Log.Logger.Put (Who  => My_Ident,
                                   What => "Got no answer...");

            end if;

         end if;

      end if;

   end if;

   Packet_Got  := False;
   Packet_Sent := False;
   Answer_Got  := False;

   if cifX_Channel_Open_Done then

      A4A.Log.Logger.Put (Who  => My_Ident,
                          What => "Test with own receive queue+++");
      A4A.Log.Logger.Put (Who  => My_Ident,
                          What => "Sending Request");

      My_Channel_Messaging.Get_Packet
        (Item   => Request,
         Result => Packet_Got);

      if not Packet_Got then

         A4A.Log.Logger.Put (Who  => My_Ident,
                             What =>
                               "Could not get Request packet from pool...");

      else

         Fw_Ident_Req := From_cifX_Packet (Request);

         Fw_Ident_Req.Head.Dest    := 16#20#;
         Fw_Ident_Req.Head.Src     := My_Receive_Queue_Type;
         Fw_Ident_Req.Head.Dest_Id := 0;

         Fw_Ident_Req.Head.Src_Id  :=
           -- Queue_Package_Single.From_Message_Queue
           Queue_Package_Multiple.From_Message_Queue
             (My_Receive_Queue'Unrestricted_Access);

         Fw_Ident_Req.Head.Len     := 4;
         Fw_Ident_Req.Head.Id      := 1;
         Fw_Ident_Req.Head.State   := 0;
         Fw_Ident_Req.Head.Cmd     := RCX_FIRMWARE_IDENTIFY_REQ;
         Fw_Ident_Req.Head.Ext     := 0;
         Fw_Ident_Req.Head.Rout    := 0;

         Fw_Ident_Req.Data.Channel_Id := 0;

         My_Channel_Messaging.Send
           (Item   => Request,
            Result => Packet_Sent);

         if not Packet_Sent then

            A4A.Log.Logger.Put (Who  => My_Ident,
                                What =>
                                  "Could not put Request packet in queue...");

            My_Channel_Messaging.Return_Packet (Item => Request);

         else

            delay 3.0;

            My_Receive_Queue.Get
              (Item   => Confirmation,
               Result => Answer_Got);

            if Answer_Got then

               Fw_Ident_Cnf := From_cifX_Packet (Confirmation);

               cifX_Show_Firmware_Identification;

               My_Channel_Messaging.Return_Packet (Item => Confirmation);

            else

               A4A.Log.Logger.Put (Who  => My_Ident,
                                   What => "Got no answer...");

            end if;

         end if;

      end if;

   end if;

   Close;

exception

   when Error: others =>
      A4A.Log.Logger.Put (Who  => My_Ident,
                          What => Exception_Information(Error));

      Close;

end Test_Channel_Messaging;

Et pour terminer, la trace qui s’est un peu étoffée… 😉

On remarquera l’utilisation des champs Src et Src_Id, Dest et Dest_Id pour le routage des messages.

C:\GNAT\Projects\A4A\hilscherx\exe\test_channel_messaging
2014-06-12 07:36:52.72 => Test_Channel_Messaging : Test_Messaging...
2014-06-12 07:36:52.72 => Test_Channel_Messaging : Initializing cifX Driver
2014-06-12 07:36:52.72 => Test_Channel_Messaging : Opening Driver
2014-06-12 07:36:52.72 => Test_Channel_Messaging : Opening Channel
2014-06-12 07:36:52.72 => Test_Channel_Messaging : Test with default receive queue+++
2014-06-12 07:36:52.72 => Test_Channel_Messaging : Sending Request
2014-06-12 07:36:53.75 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : Got a message :
Dest    :               16#20#
Src     :                16#0#
Dest_Id :                16#1#
Src_Id  :                16#0#
Cmd     :             16#1EB7#
2014-06-12 07:36:54.75 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-12 07:36:55.73 => Test_Channel_Messaging :
***********************************************
          Firmware Identification

Firmware Version :
Major    :  2
Minor    :  6
Build    :  7
Revision :  1

Firmware Name : EtherNet/IP Scanner

Firmware Date :
Year  :  2013
Month :  12
Day   :  3
***********************************************

2014-06-12 07:36:55.73 => Test_Channel_Messaging : Test with own receive queue+++
2014-06-12 07:36:55.73 => Test_Channel_Messaging : Sending Request
2014-06-12 07:36:55.73 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : Got a message :
Dest    :               16#20#
Src     :                16#1#
Dest_Id :                16#1#
Src_Id  :           16#28FDC0#
Cmd     :             16#1EB7#
2014-06-12 07:36:56.73 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-12 07:36:57.73 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-12 07:36:58.73 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-12 07:36:58.74 => Test_Channel_Messaging :
***********************************************
          Firmware Identification

Firmware Version :
Major    :  2
Minor    :  6
Build    :  7
Revision :  1

Firmware Name : EtherNet/IP Scanner

Firmware Date :
Year  :  2013
Month :  12
Day   :  3
***********************************************

2014-06-12 07:36:59.73 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-12 07:36:59.75 => Test_Channel_Messaging : Closing Channel
2014-06-12 07:36:59.75 => Test_Channel_Messaging : Closing Driver
2014-06-12 07:36:59.75 => Test_Channel_Messaging : Deinitializing cifX Driver
2014-06-12 07:36:59.75 => Test_Channel_Messaging : finished !
Logging_Task terminated...

[2014-06-12 09:36:59] process terminated successfully, elapsed time: 07.59s

Cordialement,
Stéphane