Bonjour,
Les articles précédents avaient pour objectif de présenter l’infrastructure mise en œuvre dans « Ada for Automation » pour la gestion de la messagerie Hilscher.
Cette messagerie permet comme on l’a vu d’accéder à toute la fonctionnalité acyclique offerte par le système et les piles de protocoles pour la configuration, le paramétrage et le diagnostic.
L’exemple d’utilisation du jour reprend la manipulation déjà décrite dans l’article :
cifX : Mise en œuvre : API – Messages – PROFIBUS DP V1 Class 2
Après avoir initialisé le pilote, ouvert celui-ci ainsi que le canal de communication, le programme ci-dessous :
- initie une connexion DP V1 Class 2
- lit une donnée, en l’occurrence la version du firmware,
- termine la connexion,
- attend l’indication de la fermeture de la connexion et y répond,
- puis termine proprement.
Les blocs fonctions DPV1C2 Initiate, Read, et Abort sont du même tonneau que décrit ici :
A4A : Infrastructure Messagerie Hilscher cifX – Layer 3
Tandis que pour la gestion de l’indication de fermeture c’est décrit là hier :
A4A : Infrastructure Messagerie Hilscher cifX – Layer 3 – Indications
Voici donc le code du jour qui utilise 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 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.Channel_Messaging;
use A4A.Protocols.HilscherX.Channel_Messaging;
with A4A.Protocols.HilscherX.Profibus_DPM.DPV1;
with A4A.Protocols.HilscherX.Profibus_DPM.DPV1C2.Initiate.FB;
with A4A.Protocols.HilscherX.Profibus_DPM.DPV1C2.Abort_Req.FB;
with A4A.Protocols.HilscherX.Profibus_DPM.DPV1C2.Read.FB;
with A4A.Protocols.HilscherX.Profibus_DPM.DPV1C2.Closed.FB;
use A4A.Protocols.HilscherX.Profibus_DPM;
procedure Test_DPM_DPV1 is
My_Ident : String := "Test_Profibus_DPM_DPV1";
package cifX renames A4A.Protocols.HilscherX.cifX_User;
My_Board : String := "DPM";
-- My_Board : String := "cifX1";
Driver_Handle : aliased cifX.Driver_Handle_Type;
Channel_Handle : aliased cifX.Channel_Handle_Type;
Result : DInt;
cifX_Driver_Init_Done : Boolean := False;
cifX_Driver_Open_Done : Boolean := False;
cifX_Channel_Open_Done : Boolean := False;
My_Channel_Messaging : aliased
A4A.Protocols.HilscherX.Channel_Messaging.Instance;
DPV1_FB : DPV1.Instance;
Initiate_FB : DPV1C2.Initiate.FB.Instance;
Remote_Address : DWord := 2;
Do_Initiate : Boolean := False;
Initiate_Done : Boolean := False;
Initiate_Error : Boolean := False;
Initiate_Cnf_Pos_Data : DPV1C2.Initiate.PROFIBUS_FSPMM2_INITIATE_CNF_POS_T;
Abort_FB : DPV1C2.Abort_Req.FB.Instance;
Do_Abort : Boolean := False;
Abort_Done : Boolean := False;
Abort_Error : Boolean := False;
Abort_Cnf_Data : DPV1C2.Abort_Req.PROFIBUS_FSPMM2_ABORT_CNF_T;
Read_FB : DPV1C2.Read.FB.Instance;
-- Software revision from E+H Level Meter
Slot : DWord := 1;
Index : DWord := 73;
Length : DWord := 16;
Do_Read : Boolean := False;
Read_Done : Boolean := False;
Read_Error : Boolean := False;
Read_Cnf_Pos_Data : DPV1C2.Read.PROFIBUS_FSPMM2_READ_CNF_POS_T;
Software_Revision : String (1 .. 16);
DPV1C2_Closed_FB : aliased DPV1C2.Closed.FB.Instance;
Closed_Indication_Got : Boolean := False;
Closed_Indication_Data : DPV1C2.Closed.PROFIBUS_FSPMM2_CLOSED_IND_T;
type Block_Status is
(X00,
-- Initial
X01,
-- Initiate DPV1C2 connection
X02,
-- Read data from slave
X03,
-- Abort connection
X04,
-- Wait for Closed Indication
X05
-- Terminate
);
Status : Block_Status := X00;
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 Close is
begin
DPV1_FB.Quit;
--Wait for completion
loop
exit when DPV1_FB.Is_Terminated;
delay 1.0;
end loop;
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 => My_Board,
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);
Initiate_FB.Initialise
(Channel_Access => My_Channel_Messaging'Unrestricted_Access);
Abort_FB.Initialise
(Channel_Access => My_Channel_Messaging'Unrestricted_Access);
Read_FB.Initialise
(Channel_Access => My_Channel_Messaging'Unrestricted_Access);
DPV1_FB.Initialise
(Channel_Access => My_Channel_Messaging'Unrestricted_Access,
DPV1C2_Closed_Access => DPV1C2_Closed_FB'Unrestricted_Access);
loop
case Status is
when X00 => -- Initial state
if DPV1_FB.Is_Ready then
Status := X01;
end if;
when X01 => -- Initiating DPV1C2 connection
if Initiate_Done then
if Initiate_Error then
A4A.Log.Logger.Put
(Who => My_Ident,
What => "Connection failed");
Status := X05;
else
A4A.Log.Logger.Put
(Who => My_Ident,
What => "Connected");
Initiate_Cnf_Pos_Data := Initiate_FB.Get_Data_Pos;
Status := X02;
end if;
end if;
when X02 => -- Reading data from slave
if Read_Done then
if Read_Error then
A4A.Log.Logger.Put
(Who => My_Ident,
What => "Read failed");
else
A4A.Log.Logger.Put
(Who => My_Ident,
What => "Data Read");
Read_Cnf_Pos_Data := Read_FB.Get_Data_Pos;
for I in Software_Revision'Range loop
exit when Read_Cnf_Pos_Data.Data (I) = 0;
Software_Revision (I) :=
Character'Val (Read_Cnf_Pos_Data.Data (I));
end loop;
A4A.Log.Logger.Put
(Who => My_Ident,
What => "Software Revision : " & Software_Revision);
end if;
Status := X03;
end if;
when X03 => -- Aborting connection
if Abort_Done then
if Abort_Error then
A4A.Log.Logger.Put
(Who => My_Ident,
What => "Connection Abortion failed");
Status := X05;
else
A4A.Log.Logger.Put
(Who => My_Ident,
What => "Connection Aborted");
Abort_Cnf_Data := Abort_FB.Get_Data;
Status := X04;
end if;
end if;
when X04 => -- Waiting for Closed Indication
if Closed_Indication_Got then
Closed_Indication_Data := DPV1C2_Closed_FB.Get_Data;
if Closed_Indication_Data.CRef =
Initiate_Cnf_Pos_Data.Com_Ref then
DPV1C2_Closed_FB.Answer;
Status := X05;
end if;
end if;
when X05 => -- Terminating
null;
end case;
Do_Initiate := (Status = X01);
Initiate_FB.Cyclic
(Do_Command => Do_Initiate,
Remote_Address => Remote_Address,
Done => Initiate_Done,
Error => Initiate_Error);
Do_Read := (Status = X02);
Read_FB.Cyclic
(Do_Command => Do_Read,
Com_Ref => Initiate_Cnf_Pos_Data.Com_Ref,
Slot => Slot,
Index => Index,
Length => Length,
Done => Read_Done,
Error => Read_Error);
Do_Abort := (Status = X03);
Abort_FB.Cyclic
(Do_Command => Do_Abort,
Com_Ref => Initiate_Cnf_Pos_Data.Com_Ref,
Done => Abort_Done,
Error => Abort_Error);
DPV1C2_Closed_FB.Cyclic
(Got_Indication => Closed_Indication_Got);
exit when
((Status = X05) and DPV1C2_Closed_FB.Is_Ready)
or DPV1_FB.Is_Faulty;
end loop;
-- Let's see if other indications get caught
delay 5.0;
end if;
Close;
exception
when Error: others =>
A4A.Log.Logger.Put (Who => My_Ident,
What => Exception_Information(Error));
Close;
end Test_DPM_DPV1;
Et la trace vraiment bavarde mais c’est didactique :
2014-06-16 09:57:26.68 => Test_Profibus_DPM_DPV1 : Test_Messaging...
2014-06-16 09:57:26.68 => Test_Profibus_DPM_DPV1 : Initializing cifX Driver
2014-06-16 09:57:26.68 => Test_Profibus_DPM_DPV1 : Opening Driver
2014-06-16 09:57:26.68 => Test_Profibus_DPM_DPV1 : Opening Channel
2014-06-16 09:57:26.68 => A4A.Protocols.HilscherX.Profibus_DPM.DPV1.DPV1_Task : Initialised !
2014-06-16 09:57:26.68 => A4A.Protocols.HilscherX.rcX_Public.rcX_Register_App.FB.Cyclic : Request Sent
2014-06-16 09:57:27.85 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : Got a message :
Dest : 16#20#
Src : 16#1#
Dest_Id : 16#0#
Src_Id : 16#28F97C#
Cmd : 16#2F11#
2014-06-16 09:57:27.86 => A4A.Protocols.HilscherX.Profibus_DPM.DPV1.DPV1_Task : Got a message : 16#2F11#
2014-06-16 09:57:27.86 => A4A.Protocols.HilscherX.rcX_Public.rcX_Register_App.FB.Cyclic : Confirmation received fine
2014-06-16 09:57:27.86 => A4A.Protocols.HilscherX.Profibus_DPM.DPV1.DPV1_Task : App Registered !
2014-06-16 09:57:27.99 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : Got a message :
Dest : 16#20#
Src : 16#0#
Dest_Id : 16#0#
Src_Id : 16#28FA48#
Cmd : 16#4405#
2014-06-16 09:57:27.99 => Test_Profibus_DPM_DPV1 : Connected
2014-06-16 09:57:28.16 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : Got a message :
Dest : 16#20#
Src : 16#0#
Dest_Id : 16#0#
Src_Id : 16#28FC8C#
Cmd : 16#4407#
2014-06-16 09:57:28.16 => Test_Profibus_DPM_DPV1 : Data Read
2014-06-16 09:57:28.16 => Test_Profibus_DPM_DPV1 : Software Revision : 01.05.00
2014-06-16 09:57:28.25 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : Got a message :
Dest : 16#20#
Src : 16#0#
Dest_Id : 16#0#
Src_Id : 16#28FBE8#
Cmd : 16#440D#
2014-06-16 09:57:28.25 => Test_Profibus_DPM_DPV1 : Connection Aborted
2014-06-16 09:57:28.35 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : Got a message :
Dest : 16#1#
Src : 16#8017E710#
Dest_Id : 16#28F97C#
Src_Id : 16#0#
Cmd : 16#4428#
2014-06-16 09:57:28.35 => A4A.Protocols.HilscherX.Profibus_DPM.DPV1.DPV1_Task : Got a message : 16#4428#
2014-06-16 09:57:28.35 => A4A.Protocols.HilscherX.Profibus_DPM.DPV1C2.Closed.FB.Handle_Indication : Indication received
2014-06-16 09:57:28.35 => A4A.Protocols.HilscherX.Profibus_DPM.DPV1C2.Closed.FB.Cyclic : Answer Got
2014-06-16 09:57:28.35 => A4A.Protocols.HilscherX.Profibus_DPM.DPV1C2.Closed.FB.Cyclic : Response Sent
2014-06-16 09:57:29.35 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-16 09:57:30.35 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-16 09:57:31.35 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-16 09:57:32.35 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-16 09:57:33.35 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-16 09:57:33.46 => A4A.Protocols.HilscherX.rcX_Public.rcX_Unregister_App.FB.Cyclic : Request Sent
2014-06-16 09:57:33.46 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : Got a message :
Dest : 16#20#
Src : 16#1#
Dest_Id : 16#0#
Src_Id : 16#28F97C#
Cmd : 16#2F13#
2014-06-16 09:57:33.46 => A4A.Protocols.HilscherX.Profibus_DPM.DPV1.DPV1_Task : Got a message : 16#2F13#
2014-06-16 09:57:33.46 => A4A.Protocols.HilscherX.rcX_Public.rcX_Unregister_App.FB.Cyclic : Confirmation received fine
2014-06-16 09:57:33.46 => A4A.Protocols.HilscherX.Profibus_DPM.DPV1.DPV1_Task : App Unregistered !
2014-06-16 09:57:33.46 => A4A.Protocols.HilscherX.Profibus_DPM.DPV1.DPV1_Task : Terminated !
2014-06-16 09:57:34.46 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-16 09:57:35.46 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-16 09:57:35.49 => Test_Profibus_DPM_DPV1 : Closing Channel
2014-06-16 09:57:35.49 => Test_Profibus_DPM_DPV1 : Closing Driver
2014-06-16 09:57:35.49 => Test_Profibus_DPM_DPV1 : Deinitializing cifX Driver
2014-06-16 09:57:35.49 => Test_Profibus_DPM_DPV1 : Finished !
Logging_Task terminated...
[2014-06-16 11:57:35] process terminated successfully, elapsed time: 09.57s
Et la révision du firmware de mon radar Endress + Hauser est donc :
Software Revision : 01.05.00
Edifiant non ? 😉
Cordialement,
Stéphane