Archives de catégorie : Ada4Automation

« Ada for Automation » est un cadriciel pour développer des applications d’automatisme évoluées dans le langage Ada.

A4A : Messagerie Hilscher – PROFIBUS DP V1 Class 2

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 :

C:\GNAT\Projects\A4A\hilscherx\exe\test_dpm_dpv1
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