Archives de catégorie : cifX

ISaGRAF : nouvelles Décembre 2014 – Workbench Hilscher

Bonjour,

J’ai déjà eu l’occasion de vous présenter le résultat du travail réalisé autour de la plateforme d’automatisme ISaGRAF chez Hilscher France, que ce soit sur une base PC avec les cartes de communication Hilscher cifX ici, ou sur la version modulaire sur une base netX, le netPLC, .

Bien sûr nous avons travaillé depuis et pouvons vous proposer des solutions tenues à jour.

Mais la nouvelle la plus saillante c’est que Hilscher France dispose aujourd’hui d’une version de l’atelier de développement, le Workbench ISaGRAF, personnalisée, comprenant les cibles ISaGRAF développées chez nous.

Cette version de l’atelier, proposée à un tarif préférentiel, n’est utilisable qu’avec les cibles Hilscher.

Cependant, l’atelier standard ISaGRAF peut également être utilisé si l’on dispose déjà de celui-ci.

Pour ce qui est des plateformes PC, Hilscher France propose sa propre cible ISaGRAF, intégrant la bibliothèque permettant l’accès à l’API cifX, pour toutes les versions de l’environnement Microsoft Windows® / IntervalZero RTX®.
Pour l’utilisation de cette cible, il est nécessaire d’acquérir la carte cifX avec la licence ISaGRAF.

Le client dispose ainsi d’une solution d’automatisme sur base PC :

  • performante en choisissant sa machine en fonction de la tâche à réaliser, il bénéficie de la puissance des CPU actuelles et fixe ses propres limites dans un environnement temps réel.
  • évolutive et pérenne, ISaGRAF et Hilscher sont des acteurs majeurs dans leurs domaines respectifs dont les produits évoluent pour s’adapter aux conditions du marché tout en offrant une compatibilité avec l’existant.
  • standard car le programme utilisateur est développé dans les langages normalisés IEC 61131-3.
  • ouverte puisqu’un kit de développement ISaGRAF existe pour l’élaboration de fonctions et blocs fonctions spécifiques, ou de pilotes.
  • communicante enfin grâce aux cartes de communication Hilscher cifX disponibles dans tous les formats usuels.

Je vous invite à visiter le nouveau site Hilscher, en Anglais (la peinture est encore fraîche), où vous pourrez découvrir entre autres les cartes cifX dans tous les formats et pour tous les protocoles, avec comme nouveautés les cartes double ports pour bus de terrain PROFIBUS / CANopen / DeviceNet et les versions en gamme de température étendue 0 °C .. +70 °C :
http://www.hilscher.com/

Quant au netPLC, avec ses 22 firmwares disponibles implémentant les différentes combinaisons protocolaires, il n’est pas en reste.
La « DataSheet » est disponible ici:
http://www.hf-news.fr/download/NPLC-T100_ISaGRAF/Datasheet%20netPLC_%202015-09.pdf

Nous avons aussi l’occasion de proposer quelques solutions spécifiques, l’une par exemple mettant en œuvre ISaGRAF sur le netPLC avec le protocole EtherCAT Master pour piloter des variateurs LEROY SOMER et remonter, via des messages UDP, une vingtaine de mesures à la milliseconde, temps de cycle de l’acquisition sur EtherCAT.

Une application serveur sur un PC connecté récupère les messages UDP et les archive dans des fichiers CSV pour analyse ultérieure.

Ainsi cette application permet de gérer le contrôle-commande et l’acquisition rapide à fins de caractérisation ou d’analyse.

Vous pouvez télécharger une archive du DVD des solutions ISaGRAF / Hilscher ici :
http://www.hf-news.fr/download/NPLC-T100_ISaGRAF/HILSCHER_ISaGRAF_DVD_2015_03_01.zip

Attention ! L’image est Kolossale et le débit RiKiKi…

Sur ce DVD on trouve la documentation, le logiciel de configuration standard Hilscher SYCON.net pour la configuration des interfaces de communication, ainsi que la version Hilscher France du Workbench ISaGRAF.

Vous pouvez installer cette version sur votre poste de travail sans licence, ce qui vous permettra d’évaluer l’atelier, visionner les tutoriels disponibles depuis la page d’accueil et éventuellement vous former en utilisant la cible ISaGRAF Free sous Windows qui autorise jusqu’à 3 ko de code et une communication via Modbus TCP.

Pour installer cet atelier, une connexion Internet est nécessaire car l’installateur procède au téléchargement de Microsoft Visual Studio 2010, qui sert de base à l’atelier, depuis le site Microsoft.

Cordialement,
Stéphane

A4A : Temps Réel sous Linux

Bonjour,

Sans être un expert du Temps Réel sous Linux, je suis avec intérêt son actualité et les progrès réalisés, notamment les projets de l’OSADL et Xenomai.

Pour pallier mon ignorance crasse du domaine je me suis offert quelques livres dont celui de Monsieur Christophe BLAESS qui explique de manière très pédagogique ce qu’est le temps réel, quelles sont les limites et les raisons de ces limites des systèmes considérés, Linux, Linux RT et Xenomai, fournit outils et moult exemples… Bref un « must have » !
Solutions temps réel sous Linux

En plus son site regorge d’informations, je le recommande :
http://www.blaess.fr/christophe/

J’ai aussi investi, le mot n’est pas trop fort, ça pique un peu, dans les publications suivantes qui sont toutes aussi passionnantes :

Je lorgne sur la version 2012 de ce dernier que je m’offrirai sans doute en version PDF car c’est un gros pavé à transporter.

Je dis ça pour qu’à mon anniversaire vous sachiez quoi m’offrir… 😉

Revenons au sujet de ce jour.

Si l’on exécute l’application exemple « app1 » de « Ada for Automation » sur un Linux standard, par exemple une Debian Wheezy on obtient la figure suivante :

A4A-App1-Linux-10_13_18

Dans le fond, Iceweasel navigue sur le site de Blender et lit une vidéo, le tout pour charger un peu le système.

J’ai donc exécuté l’application avec une tâche principale périodique de période 10 ms et les statistiques d’ordonnancement montrent que :

  • 28761 cycles ont démarré à t + [0 – 100µs]
  • 2087 cycles ont démarré à t + ]100µs – 1ms]
  • 397 cycles ont démarré à t + ]1ms – 10ms]
  • 3 cycles ont démarré à t + ]10ms – 20ms]

Cela convient pour de nombreuses applications d’automatisme mais on peut sans doute faire mieux.

Dans Synaptic, le logiciel qui va bien sous Debian pour installer les paquets, une recherche sur « linux rt » donne tout de suite le noyau qui convient à votre machine.

On l’installe prestement et on redémarre avec le nouveau noyau RT.

La commande « uname -a » permet de vérifier cela.

Si on exécute l’application en tant qu’utilisateur lambda on n’observe qu’un léger mieux :

A4A-App1-Linux RT-user 10_20_58

Par contre, si on exécute l’application en tant qu’administrateur (root) on passe dans une autre dimension :

A4A-App1-Linux-RT-root-10ms-10_26_24

Il faut avoir certains droits, root les a tous, pour exécuter une application en temps réel. C’est normal vu que votre application peut potentiellement utiliser toute la ressource processeur au détriment des autres tâches.

Mais on obtient alors des statistiques d’ordonnancement qui montrent que la périodicité est bien plus stable que ci-dessus.

Bien sûr, pour qualifier un système il faudrait réaliser des tests à plus long terme. Mais cet article n’a pour ambition que d’afficher les capacités Temps Réel de « Ada for Automation ».

La vue suivante montre le serveur Modbus TCP en service :

A4A-App1-Linux-RT-root-10ms-10_26_55

Et celle-ci les clients Modbus TCP, le client 2 ne trouve pas le serveur correspondant et pour cause, il n’y en a pas :

A4A-App1-Linux-RT-root-10ms-10_27_08

Quelques minutes plus tard :

A4A-App1-Linux-RT-root-10ms-10_27_30

Et ça donne quoi avec une période de 1ms ?

Hé bien ça fonctionne !

A4A-App1-Linux-RT-root-1ms-10_48_43

A4A-App1-Linux-RT-root-1ms-10_48_58

A4A-App1-Linux-RT-root-1ms-10_49_06

Évidemment, avec du Modbus TCP, avoir une tâche qui tourne à la milliseconde n’est pas raisonnable, ça ne sert pas à grand chose.

Par contre, avec les solutions de communication Hilscher ça prend un autre relief ! 🙂

Cordialement,
Stéphane

A4A : Diagnostic et accès distant

Bonjour,

Les connaisseurs du DVD des Solutions de Communications cifX, comX et netJACK, notamment ceux qui ont subi une formation de ma part ;-), se souviendront de la documentation estampillée « Diagnostic and Remote Access ».

Il y est question donc de l’accès distant et du diagnostic des cibles, entendez par là une machine équipée d’une ou plusieurs solutions de communication Hilscher.

Cette documentation expose les principes de cet accès distant et on y apprend que cela permet d’utiliser les messages standards rcX, déjà évoqués dans ces colonnes et dans la documentation « netX Dual-Port Memory », ou des appels de procédures distantes, aussi appelés Remote Procedure Calls (RPC), ces procédures étant les fonctions de l’API Hilscher cifX.

Il est ainsi possible, via communication sérielle, USB ou TCP/IP de discuter avec une cible pour la configuration ou le diagnostic de la communication.

Sur ce même DVD on trouve le « cifX TCP Server », une application qui va s’exécuter au-dessus du pilote cifX et permet ainsi à l’outil de configuration SYCON.net s’exécutant sur une autre machine de configurer et diagnostiquer la cible.

Toujours sur le DVD figurent les codes sources pour une implémentation côté Hôte, le code de l’application netHOST, et côté cible le code du « cifX TCP Server ».

Cette application « cifX TCP Server » ne doit pas être exécutée en même temps que l’application de contrôle-commande car ce n’est pas prévu ainsi et que ça va mettre eul brin.

Cependant si votre application de contrôle-commande intègre correctement cette fonctionnalité, en y mettant les verrous et routages nécessaires, il devient possible d’utiliser SYCON.net ou autre application de configuration et diagnostic comme FieldCare de Endress + Hauser en parallèle, ce qui est fort utile convenons-en.

C’est exactement ce qui est aujourd’hui réalisé dans « Ada for Automation »… Hé hé hé…
Oui, oui, ça marche sous Microsoft Windows® comme sous Linux.

Ainsi, votre application s’exécute normalement tandis que les merveilles exposées dans ces articles s’offrent à vos yeux ébahis :
cifX : FDT/DTM – Un exemple intéressant
cifX : FDT/DTM – Un exemple intéressant – E+H FieldCare

N’hésitez pas à nous solliciter.

Cordialement,
Stéphane

A4A : App2 avec PROFIBUS DP V1 Class 2

Bonjour,

Les derniers articles ont été consacrés à la mise en œuvre de la messagerie Hilscher dans « Ada for Automation » et un exemple autonome illustrant son utilisation pour gérer une communication PROFIBUS DP V1 Class 2 a été donné hier.

Pour terminer cette série, il nous restait à montrer l’intégration de cet exemple dans l’application exemple « App2 » déjà évoquée ici et .

Nous disposons donc maintenant d’un exemple complet montrant d’une part la communication cyclique avec la mémoire image process, commune quelle que soit la pile de protocole à l’œuvre, et d’autre part la communication acyclique avec donc des messages transportant des commandes ou des indications échangés avec le système et les piles de protocoles, chaque interface étant documentée dans un manuel propre.

Cette application « App2 » étend le projet « A4A_HilscherX » et partage ainsi entre autres le cœur, soit la tâche « A4A.Kernel.Main ». On ne présentera de celui-ci que les évolutions.

Nous avons vu qu’il nous faut une instance de l’objet « A4A.Protocols.HilscherX.Channel_Messaging » par canal de communication.

Aussi cet instance est fournie par le paquetage « A4A.HilscherX » importé par « A4A.Kernel.Main » :

with A4A.Protocols.HilscherX.Channel_Messaging;

package A4A.HilscherX is

   --------------------------------------------------------------------
   -- Hilscher cifX Channel Messaging objects
   --------------------------------------------------------------------

   Board1_Channel0_Messaging : aliased
     A4A.Protocols.HilscherX.Channel_Messaging.Instance;

end A4A.HilscherX;

On a donc dans « A4A.Kernel.Main » :

  • l’import du paquetage qui déclare l’instance,
  • après ouverture du canal, l’initialisation de l’instance,
  • l’appel d’une nouvelle procédure déclarée au niveau application, « A4A.Application.Cold_Start », qui permet de procéder à des initialisations avant de rentrer dans la boucle principale,
  • l’appel d’une nouvelle procédure déclarée au niveau application, « A4A.Application.Closing », qui permet de procéder à des dés-initialisations avant de sortir de la boucle principale,
  • et termine l’instance dûment.
with A4A.HilscherX;

...


         A4A.Log.Logger.Put (Who  => My_Ident,
                             What => "Initialising Channel Messaging...");

         A4A.HilscherX.Board1_Channel0_Messaging.Initialise
           (Channel_Handle => Channel_Handle);

...

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

      A4A.Application.Cold_Start;

      --------------------------------------------------------------------
      -- Main loop
      --------------------------------------------------------------------

      Main_Loop:
      loop

...

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

               A4A.Application.Closing;

...

               A4A.Log.Logger.Put
                 (Who  => My_Ident,
                  What => "Terminating Channel Messaging...");

               A4A.HilscherX.Board1_Channel0_Messaging.Quit;

L’interface entre le programme utilisateur et le noyau est définie dans « A4A/src/a4a-application.ads » :

-----------------------------------------------------------------------
--                       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.     --
-----------------------------------------------------------------------


package A4A.Application is

   --------------------------------------------------------------------
   -- User Program
   --------------------------------------------------------------------

   procedure Cold_Start;
   -- This procedure is called once during Main Task initialisation.
   -- Its purpose is to provide for first time application initialisation.

   procedure Closing;
   -- This procedure is called once during Main Task termination.
   -- It allows application to terminate cleanly.

   procedure Main_Cyclic;
   -- This is application main entry point.
   -- It is called by Main Task when in Running state.

   procedure Periodic_Run_1;
   -- This is application entry point for the periodic task 1.
   -- It is called by Periodic Task 1 when in Running state.
   
   function Program_Fault return Boolean;

private
   
   Program_Fault_Flag : Boolean := False;
   -- It is raised by exception handling in application and tested by
   -- Main Task.

end A4A.Application;

L’implémentation de ces fonctions est à la charge de l’utilisateur et pour notre programme exemple est réalisée dans « app2/src/a4a-application.adb » :

-----------------------------------------------------------------------
--                       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.Real_Time;
with Ada.Exceptions; use Ada.Exceptions;

with A4A.Log;
with A4A.Memory; use A4A.Memory;

with A4A.User_Functions; use A4A.User_Functions;

package body A4A.Application is

   procedure Cold_Start is
   begin

      Initialise;

   end Cold_Start;

   procedure Closing is
   begin

      Close;

   end Closing;

   procedure Main_Cyclic is
      My_Ident : String := "A4A.Application.Main_Cyclic";
   begin

      Map_Inputs;

      Map_HMI_Inputs;

      EH_Level;

      PROFIBUS_DPM_DPV1C2;

      Map_Outputs;

      Map_HMI_Outputs;

   exception

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

         Program_Fault_Flag := True;

   end Main_Cyclic;

   procedure Periodic_Run_1 is
      My_Ident : String := "A4A.Application.Periodic_Run_1";
   begin

      null;

   exception

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

         Program_Fault_Flag := True;

   end Periodic_Run_1;

   function Program_Fault return Boolean is
   begin
      return Program_Fault_Flag;
   end Program_Fault;

end A4A.Application;

Cette application définit les objets nécessaires dans « app2/src/a4a-user_objects.ads » :

-----------------------------------------------------------------------
--                       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 A4A.Library.Timers.TON; use A4A.Library.Timers;

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;

package A4A.User_Objects is

   --------------------------------------------------------------------
   -- User Objects creation
   --------------------------------------------------------------------

   Tempo_TON_1      : TON.Instance;
   -- My Tempo TON 1

   TON_1_Q          : Boolean := False;

   --------------------------------------------------------------------
   -- Inputs from cifX PROFIBUS DPM
   --------------------------------------------------------------------

   LT_Main_Value       : Float := 0.0;
   LT_2nd_Value        : Float := 0.0;
   LT_Main_Status      : Byte  :=   0;
   LT_2nd_Status       : Byte  :=   0;

   --------------------------------------------------------------------
   -- Outputs to cifX PROFIBUS DPM
   --------------------------------------------------------------------

   LT_Display_Value    : Float := 0.0;
   LT_Display_Status   : Byte  :=   0;

   --------------------------------------------------------------------
   -- Test PROFIBUS DPM DP V1 Class 2
   --------------------------------------------------------------------

   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;

end A4A.User_Objects;

Les fonctions utilisateurs sont spécifiées dans « app2/src/a4a-user_functions.ads » :

-----------------------------------------------------------------------
--                       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.     --
-----------------------------------------------------------------------


package A4A.User_Functions is

   --------------------------------------------------------------------
   -- User functions
   --------------------------------------------------------------------

   procedure Map_Inputs;

   procedure Map_Outputs;

   procedure Map_HMI_Inputs;

   procedure Map_HMI_Outputs;

   procedure Initialise;

   procedure Close;

   procedure PROFIBUS_DPM_DPV1C2;

   procedure EH_Level;

end A4A.User_Functions;

Et elles sont implémentées dans « app2/src/a4a-user_functions.adb » :

-----------------------------------------------------------------------
--                       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.Real_Time;

with A4A.Memory; use A4A.Memory;
with A4A.Library.Conversion; use A4A.Library.Conversion;

with A4A.Log;
with A4A.HilscherX;

with A4A.User_Objects; use A4A.User_Objects;

package body A4A.User_Functions is

   --------------------------------------------------------------------
   -- User functions
   --------------------------------------------------------------------

   procedure Map_Inputs is
   begin

      null;

   end Map_Inputs;

   procedure Map_Outputs is
   begin

      null;

   end Map_Outputs;

   procedure Map_HMI_Inputs is
   begin

      null;

   end Map_HMI_Inputs;

   procedure Map_HMI_Outputs is
   begin

      Bytes_To_Word (LSB_Byte => Hilscher_cifx0_Inputs(1),
                     MSB_Byte => Hilscher_cifx0_Inputs(0),
                     Word_out => MBTCP_IOServer_Input_Registers(1));

      Bytes_To_Word (LSB_Byte => Hilscher_cifx0_Inputs(3),
                     MSB_Byte => Hilscher_cifx0_Inputs(2),
                     Word_out => MBTCP_IOServer_Input_Registers(0));

      Bytes_To_Word (LSB_Byte => Hilscher_cifx0_Inputs(4),
                     MSB_Byte => 0,
                     Word_out => MBTCP_IOServer_Input_Registers(2));

   end Map_HMI_Outputs;

   procedure Initialise is
   begin

      Initiate_FB.Initialise
        (Channel_Access => A4A.HilscherX.Board1_Channel0_Messaging'Access);

      Abort_FB.Initialise
        (Channel_Access => A4A.HilscherX.Board1_Channel0_Messaging'Access);

      Read_FB.Initialise
        (Channel_Access => A4A.HilscherX.Board1_Channel0_Messaging'Access);

      DPV1_FB.Initialise
        (Channel_Access => A4A.HilscherX.Board1_Channel0_Messaging'Access,
         DPV1C2_Closed_Access => DPV1C2_Closed_FB'Access);

   end Initialise;

   procedure Close is
   begin

      DPV1_FB.Quit;

      --Wait for completion
      loop

         exit when DPV1_FB.Is_Terminated;
         delay 1.0;

      end loop;

   end Close;

   procedure PROFIBUS_DPM_DPV1C2 is

      My_Ident : String := "PROFIBUS_DPM_DPV1C2";

   begin

      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);


   end PROFIBUS_DPM_DPV1C2;

   procedure EH_Level is

      My_Ident : String := "EH_Level";

      Word_0 : Word := 0;
      Word_1 : Word := 0;

      DWord_0 : DWord := 0;

      Elapsed_TON_1 : Ada.Real_Time.Time_Span;
   begin

      Bytes_To_Word
        (LSB_Byte => Hilscher_cifx0_Inputs(1),
         MSB_Byte => Hilscher_cifx0_Inputs(0),
         Word_out => Word_0);

      Bytes_To_Word
        (LSB_Byte => Hilscher_cifx0_Inputs(3),
         MSB_Byte => Hilscher_cifx0_Inputs(2),
         Word_out => Word_1);

      Words_To_DWord
        (LSW_Word  => Word_1,
         MSW_Word  => Word_0,
         DWord_out => DWord_0);

      LT_Main_Value := DWord_To_Float (DWord_0);

      Tempo_TON_1.Cyclic (Start   => not TON_1_Q,
                          Preset  => Ada.Real_Time.Milliseconds (10000),
                          Elapsed => Elapsed_TON_1,
                          Q       => TON_1_Q);

      if TON_1_Q then

         A4A.Log.Logger.Put
           (Who  => My_Ident,
            What => "LT_Main_Value = " & LT_Main_Value'Img & "%");

      end if;

   end EH_Level;

end A4A.User_Functions;

On remarquera particulèrement les procédures « Initialise » et « Close », appelées respectivement par les procédures « Cold_Start » et « Closing ».

Il n’y a plus de boucle comme dans l’exemple autonome car elle est implicite, c’est la boucle principale du noyau.

En fait, une partie de ce qui se trouve dans la procédure « EH_Level » pourrait figurer dans « Map_Inputs ». Il ne s’agit que d’un exemple et l’utilisateur a toute latitude pour organiser son code comme il l’entend.

La seule interface définie avec le noyau est celle spécifiée par « A4A.Application ». Au dessus, c’est ouvert. Et bien sûr, si cela ne convient pas, le code source est également ouvert ! 😉

Ci-dessous la trace correspondante :

2014-06-18 10:28:47.51 => A4A_Console_Main : started as : C:\GNAT\Projects\A4A\app2\exe\App2_CLI.exe
2014-06-18 10:28:47.51 => A4A_Console_Main :

***********************************************

          Application Identification

Name :

    Hilscher cifX Test Application (app2)

Version :

    2014/06/17

Description :

    This is the test application 2.



The purpose of this application is to demonstrate the following capabilities :

 * Command Line or Graphical User Interface,

 * Modbus TCP Server to connect a SCADA system,

 * Hilscher cifX binding,

 * some of the functions and objects of the library.



It is supposed to be run in conjunction with a SCADA system and slave devices on a supported field bus system.

***********************************************


2014-06-18 10:28:47.51 => A4A.Kernel.Sig_Handler : Waiting Signal Interrupt... Use Ctrl+C to exit
2014-06-18 10:28:47.51 => A4A.Kernel.Main_Task : Main_Task's ID is the_main_task_01ECD318

Started at 2014-06-18 10:28:47.51
2014-06-18 10:28:47.51 => A4A.Generic_Periodic_Task : started !
2014-06-18 10:28:47.51 => A4A_Console_Main : Main Task (Status, Min, Max) : WD OK  0.000000000  0.000000000
2014-06-18 10:28:47.51 => A4A_Console_Main : DPM (COS, State, Err) :                16#0#,                16#0#,                16#0#
2014-06-18 10:28:47.51 => A4A_Console_Main : Periodic Task 1 (Status, Min, Max) : WD OK  0.000000000  0.000000000
2014-06-18 10:28:47.51 => A4A.MBTCP_Server.Periodic_Task 127.0.0.1: 1504 : started !
2014-06-18 10:28:47.51 => A4A.MBTCP_Server.Run : TCP_Listen... Server_Socket =  260
2014-06-18 10:28:47.51 => A4A.Kernel.Main_Task : Modbus TCP Server created...
2014-06-18 10:28:47.51 => A4A.Kernel.Main_Task : Initializing cifX Driver...
2014-06-18 10:28:47.51 => A4A.Kernel.Main_Task : Opening cifX Driver...
2014-06-18 10:28:47.51 => A4A.Kernel.Main_Task :

***********************************************

          Driver Information

Version     : cifXDriver V1.2.3.0

Board Count :  3

***********************************************


2014-06-18 10:28:47.51 => A4A.Kernel.Main_Task : Opening cifX Channel...
2014-06-18 10:28:47.51 => A4A.Kernel.Main_Task :

***********************************************

          Channel Information

Board_Name    : cifX1

Board Alias   : DPM

Device Number :  1250410

Serial Number :  20276



Firmware : PROFIBUS DP Master

Version  :  2. 6. 0(Build  13)

Date     :  2013- 11- 13

***********************************************


2014-06-18 10:28:47.51 => A4A.Kernel.Main_Task : Initialising Channel Messaging...
2014-06-18 10:28:47.51 => A4A.Kernel.Main_Task : Setting Flag Host Ready...
2014-06-18 10:28:47.51 => A4A.Kernel.Main_Task : Setting Flag Bus On...
2014-06-18 10:28:47.52 => A4A.Kernel.Main_Task : COM-flag not set
2014-06-18 10:28:47.52 => A4A.Kernel.Main_Task : Calling Cold_Start...
2014-06-18 10:28:47.52 => A4A.Protocols.HilscherX.Profibus_DPM.DPV1.DPV1_Task : Initialised !
2014-06-18 10:28:47.52 => A4A.Protocols.HilscherX.rcX_Public.rcX_Register_App.FB.Cyclic : Request Sent
2014-06-18 10:28:47.52 => A4A.Kernel.Main_Task : COM-flag not set
2014-06-18 10:28:48.52 => 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#487164#

Cmd     :             16#2F11#
2014-06-18 10:28:48.52 => A4A.Protocols.HilscherX.Profibus_DPM.DPV1.DPV1_Task : Got a message :             16#2F11#
2014-06-18 10:28:48.52 => A4A.Protocols.HilscherX.rcX_Public.rcX_Register_App.FB.Cyclic : Confirmation received fine
2014-06-18 10:28:48.52 => A4A.Protocols.HilscherX.Profibus_DPM.DPV1.DPV1_Task : App Registered !
2014-06-18 10:28:48.56 => A4A_Console_Main : Main Task (Status, Min, Max) : WD OK  0.000209061  0.000876352
2014-06-18 10:28:48.56 => A4A_Console_Main : DPM (COS, State, Err) :                16#7#,                16#4#,                16#0#
2014-06-18 10:28:48.56 => A4A_Console_Main : Periodic Task 1 (Status, Min, Max) : WD OK  0.000001707  0.000002133
2014-06-18 10:28:48.80 => 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#487248#

Cmd     :             16#4405#
2014-06-18 10:28:48.86 => PROFIBUS_DPM_DPV1C2 : Connected
2014-06-18 10:28:49.09 => 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#4875C8#

Cmd     :             16#4407#
2014-06-18 10:28:49.17 => PROFIBUS_DPM_DPV1C2 : Data Read
2014-06-18 10:28:49.17 => PROFIBUS_DPM_DPV1C2 : Software Revision : 01.05.00        
2014-06-18 10:28:49.31 => 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#487504#

Cmd     :             16#440D#
2014-06-18 10:28:49.36 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : Got a message :

Dest    :                16#1#

Src     :         16#8017E710#

Dest_Id :           16#487164#

Src_Id  :                16#0#

Cmd     :             16#4428#
2014-06-18 10:28:49.36 => A4A.Protocols.HilscherX.Profibus_DPM.DPV1.DPV1_Task : Got a message :             16#4428#
2014-06-18 10:28:49.36 => A4A.Protocols.HilscherX.Profibus_DPM.DPV1C2.Closed.FB.Handle_Indication : Indication received
2014-06-18 10:28:49.42 => PROFIBUS_DPM_DPV1C2 : Connection Aborted
2014-06-18 10:28:49.47 => A4A.Protocols.HilscherX.Profibus_DPM.DPV1C2.Closed.FB.Cyclic : Answer Got
2014-06-18 10:28:49.52 => A4A.Protocols.HilscherX.Profibus_DPM.DPV1C2.Closed.FB.Cyclic : Response Sent
2014-06-18 10:28:49.64 => A4A_Console_Main : Main Task (Status, Min, Max) : WD OK  0.000209061  0.000876352
2014-06-18 10:28:49.64 => A4A_Console_Main : DPM (COS, State, Err) :                16#7#,                16#4#,                16#0#
2014-06-18 10:28:49.64 => A4A_Console_Main : Periodic Task 1 (Status, Min, Max) : WD OK  0.000001706  0.000002133
2014-06-18 10:28:50.36 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-18 10:28:50.73 => A4A_Console_Main : Main Task (Status, Min, Max) : WD OK  0.000209061  0.000876352
2014-06-18 10:28:50.73 => A4A_Console_Main : DPM (COS, State, Err) :                16#7#,                16#4#,                16#0#
2014-06-18 10:28:50.73 => A4A_Console_Main : Periodic Task 1 (Status, Min, Max) : WD OK  0.000001706  0.000002134
2014-06-18 10:28:51.36 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-18 10:28:51.82 => A4A_Console_Main : Main Task (Status, Min, Max) : WD OK  0.000209061  0.000876352
2014-06-18 10:28:51.82 => A4A_Console_Main : DPM (COS, State, Err) :                16#7#,                16#4#,                16#0#
2014-06-18 10:28:51.82 => A4A_Console_Main : Periodic Task 1 (Status, Min, Max) : WD OK  0.000001706  0.000002134
2014-06-18 10:28:52.36 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-18 10:28:52.92 => A4A_Console_Main : Main Task (Status, Min, Max) : WD OK  0.000208634  0.001293195
2014-06-18 10:28:52.92 => A4A_Console_Main : DPM (COS, State, Err) :                16#7#,                16#4#,                16#0#
2014-06-18 10:28:52.92 => A4A_Console_Main : Periodic Task 1 (Status, Min, Max) : WD OK  0.000001706  0.000002134
2014-06-18 10:28:53.36 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-18 10:28:53.99 => A4A_Console_Main : Main Task (Status, Min, Max) : WD OK  0.000208634  0.001293195
2014-06-18 10:28:53.99 => A4A_Console_Main : DPM (COS, State, Err) :                16#7#,                16#4#,                16#0#
2014-06-18 10:28:53.99 => A4A_Console_Main : Periodic Task 1 (Status, Min, Max) : WD OK  0.000001280  0.000002134
2014-06-18 10:28:54.36 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-18 10:28:55.08 => A4A_Console_Main : Main Task (Status, Min, Max) : WD OK  0.000208209  0.001293195
2014-06-18 10:28:55.08 => A4A_Console_Main : DPM (COS, State, Err) :                16#7#,                16#4#,                16#0#
2014-06-18 10:28:55.08 => A4A_Console_Main : Periodic Task 1 (Status, Min, Max) : WD OK  0.000001280  0.000002134
2014-06-18 10:28:55.36 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-18 10:28:56.15 => A4A_Console_Main : Main Task (Status, Min, Max) : WD OK  0.000208209  0.001293195
2014-06-18 10:28:56.15 => A4A_Console_Main : DPM (COS, State, Err) :                16#7#,                16#4#,                16#0#
2014-06-18 10:28:56.15 => A4A_Console_Main : Periodic Task 1 (Status, Min, Max) : WD OK  0.000001280  0.000002134
2014-06-18 10:28:56.36 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-18 10:28:57.19 => A4A_Console_Main : Main Task (Status, Min, Max) : WD OK  0.000208209  0.001313674
2014-06-18 10:28:57.19 => A4A_Console_Main : DPM (COS, State, Err) :                16#7#,                16#4#,                16#0#
2014-06-18 10:28:57.19 => A4A_Console_Main : Periodic Task 1 (Status, Min, Max) : WD OK  0.000001280  0.000002134
2014-06-18 10:28:57.36 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-18 10:28:57.57 => EH_Level : LT_Main_Value =  7.19014E+01%
2014-06-18 10:28:58.24 => A4A_Console_Main : Main Task (Status, Min, Max) : WD OK  0.000208209  0.001313674
2014-06-18 10:28:58.24 => A4A_Console_Main : DPM (COS, State, Err) :                16#7#,                16#4#,                16#0#
2014-06-18 10:28:58.24 => A4A_Console_Main : Periodic Task 1 (Status, Min, Max) : WD OK  0.000001280  0.000002134
2014-06-18 10:28:58.36 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-18 10:28:58.49 => A4A.Kernel.Sig_Handler : Signal Interrupt caught !
2014-06-18 10:28:59.31 => A4A_Console_Main : Main Task (Status, Min, Max) : WD OK  0.000208209  0.001313674
2014-06-18 10:28:59.31 => A4A_Console_Main : DPM (COS, State, Err) :                16#7#,                16#4#,                16#0#
2014-06-18 10:28:59.31 => A4A_Console_Main : Periodic Task 1 (Status, Min, Max) : WD OK  0.000001280  0.000002986
2014-06-18 10:28:59.36 => A4A.Kernel.Main_Task : Stopping Watchdog...
2014-06-18 10:28:59.36 => A4A.Kernel.Main_Task : Resetting Flag Bus On...
2014-06-18 10:28:59.36 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-18 10:28:59.48 => A4A.Kernel.Main_Task : Calling Closing...
2014-06-18 10:28:59.48 => A4A.Protocols.HilscherX.rcX_Public.rcX_Unregister_App.FB.Cyclic : Request Sent
2014-06-18 10:28:59.48 => 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#487164#

Cmd     :             16#2F13#
2014-06-18 10:28:59.48 => A4A.Protocols.HilscherX.Profibus_DPM.DPV1.DPV1_Task : Got a message :             16#2F13#
2014-06-18 10:28:59.48 => A4A.Protocols.HilscherX.rcX_Public.rcX_Unregister_App.FB.Cyclic : Confirmation received fine
2014-06-18 10:28:59.48 => A4A.Protocols.HilscherX.Profibus_DPM.DPV1.DPV1_Task : App Unregistered !
2014-06-18 10:28:59.48 => A4A.Protocols.HilscherX.Profibus_DPM.DPV1.DPV1_Task : Terminated !
2014-06-18 10:28:59.51 => A4A.Generic_Periodic_Task : finished !
2014-06-18 10:28:59.67 => A4A.MBTCP_Server.Run.Close : Closing gracefully.
2014-06-18 10:28:59.67 => A4A.MBTCP_Server.Periodic_Task 127.0.0.1: 1504 : finished !
2014-06-18 10:29:00.33 => A4A_Console_Main : Main Task (Status, Min, Max) : WD OK  0.000208209  0.001313674
2014-06-18 10:29:00.33 => A4A_Console_Main : DPM (COS, State, Err) :                16#7#,                16#4#,                16#0#
2014-06-18 10:29:00.33 => A4A_Console_Main : Periodic Task 1 (Status, Min, Max) : WD OK  0.000001280  0.000002986
2014-06-18 10:29:00.48 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-18 10:29:00.50 => A4A.Kernel.Main_Task : Resetting Flag Host Ready...
2014-06-18 10:29:00.50 => A4A.Kernel.Main_Task : Terminating Channel Messaging...
2014-06-18 10:29:01.34 => A4A_Console_Main : Main Task (Status, Min, Max) : WD OK  0.000208209  0.001313674
2014-06-18 10:29:01.34 => A4A_Console_Main : DPM (COS, State, Err) :                16#7#,                16#4#,                16#0#
2014-06-18 10:29:01.34 => A4A_Console_Main : Periodic Task 1 (Status, Min, Max) : WD OK  0.000001280  0.000002986
2014-06-18 10:29:01.48 => A4A.Protocols.HilscherX.Channel_Messaging.Receive_Msg_Task_Type : No packet pending.
2014-06-18 10:29:02.35 => A4A_Console_Main : Main Task (Status, Min, Max) : WD OK  0.000208209  0.001313674
2014-06-18 10:29:02.35 => A4A_Console_Main : DPM (COS, State, Err) :                16#7#,                16#4#,                16#0#
2014-06-18 10:29:02.35 => A4A_Console_Main : Periodic Task 1 (Status, Min, Max) : WD OK  0.000001280  0.000002986
2014-06-18 10:29:02.53 => A4A.Kernel.Main_Task : Closing cifX Channel...
2014-06-18 10:29:02.53 => A4A.Kernel.Main_Task : Closing cifX Driver...
2014-06-18 10:29:02.53 => A4A.Kernel.Main_Task : Deinitializing cifX Driver...
2014-06-18 10:29:03.37 => A4A_Console_Main : Main Task (Status, Min, Max) : WD OK  0.000208209  0.001313674
2014-06-18 10:29:03.37 => A4A_Console_Main : DPM (COS, State, Err) :                16#7#,                16#4#,                16#0#
2014-06-18 10:29:03.37 => A4A_Console_Main : Periodic Task 1 (Status, Min, Max) : WD OK  0.000001280  0.000002986
2014-06-18 10:29:03.54 => A4A.Kernel.Main_Task : finished !
2014-06-18 10:29:04.38 => A4A_Console_Main : Main Task (Status, Min, Max) : WD OK  0.000208209  0.001313674
2014-06-18 10:29:04.38 => A4A_Console_Main : DPM (COS, State, Err) :                16#7#,                16#4#,                16#0#
2014-06-18 10:29:04.38 => A4A_Console_Main : Periodic Task 1 (Status, Min, Max) : WD OK  0.000001280  0.000002986
2014-06-18 10:29:04.38 => A4A_Console_Main : finished !
Logging_Task terminated...

N’hésitez pas à nous solliciter pour toute question ou projet, présentation et démonstration ou formation !

A bientôt sur le forum, par email ou au téléphone.

Cordialement,
Stéphane

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