Bonjour,
Dans une application faisant un usage normal, voire intensif de la messagerie Hilscher, on peut éviter d’allouer puis libérer continuellement des paquets en utilisant un réservoir (Pool) de paquets.
Ce réservoir de paquets est implémenté dans le paquetage générique « A4A.Protocols.HilscherX.Message_Pool ».
On met en œuvre un type protégé qui autorise une utilisation par plusieurs tâches du Pool.
Ainsi, on instancie ce paquetage générique avec la taille souhaitée, on l’initialise avec la procédure idoine puis on peut obtenir un accès sur un paquet avec la procédure « Get_Packet », on s’en sert et enfin on le retourne au Pool avec la procédure « Return_Packet ». Si tous les paquets sont en cours d’utilisation on attend son tour.
Il est également souhaitable d’utiliser des queues pour gérer les flux de messages en émission comme en réception.
Le paquetage générique « A4A.Protocols.HilscherX.Message_Queue » constitue une implémentation possible d’une FIFO, aussi sous la forme d’un type protégé.
On pourra utiliser ces queues entre les objets initiateurs des requêtes et la tâche gérant l’émission ou entre la tâche de réception et les objets destinataires des réponses ou indications.
Après instanciation de ce paquetage, il est possible d’insérer dans la queue un paquet, ou plutôt une référence à ce paquet, avec la procédure « Put » (qui indique si cela a pu être réalisé ou pas – la queue est pleine).
On peut interroger la queue avec la procédure « Get », qui indique si la queue est vide le cas échéant, ou avec l’entrée « Get » qui permet une mise en attente de la tâche appelante si la queue est vide. La procédure est normalement utilisée par les objets en attente de réponse car elle est non bloquante.
Un exemple d’une telle infrastructure est fourni par le paquetage « A4A.Protocols.HilscherX.Messaging » dont la spécification est :
-- 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.Messaging is
procedure Quit;
procedure Initialise (Channel_Handle : in Channel_Handle_Type);
package Pool_Package is new
A4A.Protocols.HilscherX.Message_Pool (Pool_Size => 20);
Message_Pool : Pool_Package.Message_Pool_Type;
package Queue_Package is new
A4A.Protocols.HilscherX.Message_Queue (Queue_Size => 10);
Send_Queue : Queue_Package.Message_Queue_Type;
Receive_Queue : Queue_Package.Message_Queue_Type;
task Send_Msg;
task Receive_Msg;
private
Quit_Flag : Boolean := False;
Init_Flag : Boolean := False;
The_Channel_Handle : Channel_Handle_Type;
end A4A.Protocols.HilscherX.Messaging;
On y trouve :
- L’instanciation du paquetage « réservoir de paquets » et la déclaration du pool
- L’instanciation du paquetage « queue de paquets » et la déclaration des queues d’émission et réception
- La déclaration des deux tâches d’émission et réception
Le code de l’application de test est montré ci-dessous qui réalise la même opération que dans l’article précédent mais en utilisant bien sûr cette infrastructure :
-- 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 Ada.Text_IO;
with Interfaces.C;
with Ada.Exceptions; use Ada.Exceptions;
with A4A; use A4A;
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.Messaging;
use A4A.Protocols.HilscherX;
procedure Test_Messaging is
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_Put : Boolean := False;
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
Ada.Text_IO.Put_Line (What);
end cifX_Show_Firmware_Identification;
procedure Close is
begin
Messaging.Quit;
delay 5.0;
if cifX_Channel_Open_Done then
Ada.Text_IO.Put_Line (Item => "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
Ada.Text_IO.Put_Line (Item => "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
Ada.Text_IO.Put_Line (Item => "Deinitializing cifX Driver");
cifX.Driver_Deinit;
cifX_Driver_Init_Done := False;
end if;
end Close;
begin
Ada.Text_IO.Put_Line (Item => "Test_Messaging...");
Ada.Text_IO.Put_Line (Item => "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
Ada.Text_IO.Put_Line (Item => "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
Ada.Text_IO.Put_Line (Item => "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
Messaging.Initialise (Channel_Handle => Channel_Handle);
Ada.Text_IO.Put_Line (Item => "Sending Request");
Messaging.Message_Pool.Get_Packet
(Item => Request,
Result => Packet_Got);
if not Packet_Got then
Ada.Text_IO.Put_Line
("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;
Messaging.Send_Queue.Put
(Item => Request,
Result => Packet_Put);
if not Packet_Put then
Ada.Text_IO.Put_Line
("Could not put Request packet in queue...");
Messaging.Message_Pool.Return_Packet (Item => Request);
else
Messaging.Receive_Queue.Get (Item => Confirmation);
Fw_Ident_Cnf := From_cifX_Packet (Confirmation);
cifX_Show_Firmware_Identification;
Messaging.Message_Pool.Return_Packet (Item => Confirmation);
end if;
end if;
end if;
Close;
exception
when Error: others =>
Ada.Text_IO.Put_Line (Exception_Information(Error));
Close;
end Test_Messaging;
Avec un peu de chance ça tombe en marche et la trace est présentée ci-bas :
Test_Messaging...
Initializing cifX Driver
Opening Driver
Opening Channel
Sending Request
***********************************************
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
***********************************************
Closing Channel
Closing Driver
Deinitializing cifX Driver
[2014-06-11 11:19:03] process terminated successfully, elapsed time: 06.53s
De leur côté, les tâches d’émission et de réception s’exécutent parallèlement au fil du programme principal.
La tâche d’émission bloque sur l’attente d’un message dans la queue d’émission et retourne le paquet émis au pool.
La tâche de réception obtient un paquet du pool puis boucle en attente de réception d’un paquet et poste le paquet reçu dans la queue de réception.
Voilà le corps du paquetage « A4A.Protocols.HilscherX.Messaging » :
-- 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 Ada.Text_IO;
package body A4A.Protocols.HilscherX.Messaging is
procedure Quit is
begin
Quit_Flag := True;
end Quit;
procedure Initialise
(Channel_Handle : in Channel_Handle_Type) is
begin
The_Channel_Handle := Channel_Handle;
Message_Pool.Initialise;
Init_Flag := True;
end Initialise;
task body Send_Msg is
Packet : cifX_Packet_Access;
Result : DInt;
begin
loop
delay 1.0;
exit when Init_Flag or Quit_Flag;
end loop;
loop
exit when Quit_Flag;
select
Send_Queue.Get (Item => Packet);
Result := Channel_Put_Packet
(Channel_Handle => The_Channel_Handle,
Send_Packet => Packet.all,
Time_Out => 10);
if Result /= CIFX_NO_ERROR then
Show_Error (Result);
end if;
Message_Pool.Return_Packet (Item => Packet);
or
delay 1.0;
end select;
end loop;
end Send_Msg;
task body Receive_Msg is
Packet : cifX_Packet_Access;
Result : DInt;
Packet_Got : Boolean := False;
Packet_Put : Boolean := False;
begin
loop
delay 1.0;
exit when Init_Flag or Quit_Flag;
end loop;
loop
exit when Quit_Flag;
if not Packet_Got then
Message_Pool.Get_Packet
(Item => Packet,
Result => Packet_Got);
end if;
if not Packet_Got then
Ada.Text_IO.Put_Line
("Receive_Msg : Could not get packet from pool...");
else
Result := Channel_Get_Packet
(Channel_Handle => The_Channel_Handle,
Size => cifX_Packet_Type'Size / 8,
Recv_Packet => Packet.all,
Time_Out => 1000);
if Result = CIFX_NO_ERROR then
Receive_Queue.Put
(Item => Packet,
Result => Packet_Put);
Packet_Got := False;
elsif Result = CIFX_DEV_GET_TIMEOUT
or Result = CIFX_DEV_GET_NO_PACKET then
Ada.Text_IO.Put_Line
("Zut !");
else
Show_Error (Result);
end if;
end if;
end loop;
end Receive_Msg;
end A4A.Protocols.HilscherX.Messaging;
Cordialement,
Stéphane