luc desruelle's Blogue

Navigateur communautaire
annuler
Affichage des résultats de 
Rechercher plutôt 
Vouliez-vous dire : 

Re: VI dynamique, HAL en Objet, plugins via classes dans PPLs ou code externe entre 2 exe LabVIEW

Desruelle_luc
Trusted Enthusiast

Le code source est disponible dans le post. Vous pouvez me contacter pour vous aider à mettre en place une solution de plugin ou d'abstraction (type HAL). Bonne lecture et A bientôt.

 

C’est tout un programme, qui me vient en tête, à la suite de plusieurs discussions sur les méthodes de chargement d’un code « externe » à une application et sur les plugins.

Le but n’est pas de décrire en détail l’ensemble des techniques, mais d’évoquer les différentes possibilités.

Dans une application « classique », le code de niveau principal (Main.vi) a des sous-VI qui sont des dépendances appelées statiquement. Lors de la création de la spécification de construction, il suffit de sélectionner le code source de niveau principal, pour que l’ensemble des dépendances soient ajoutées dans le fichier binaire de l’exécutable.

 

Pour « charger du code externe », il existe plusieurs méthodes (comme toujours). De la plus simple, à la plus complexe, toutes avec des avantages et des inconvénients, évidement, comme toujours.

Il est possible d’envisager :

 

Chargement d’un code dynamique

Le chargement d’un code dynamique, qui n’est donc pas une dépendance statique du VI Main (Top-level), et qui sera inclus dans la spécification de construction de l’exécutable. Par cette méthode, le sous-VI sera directement « visible / utilisable » par le code principal. Il suffit de le charger en mémoire pour l’utiliser.

 

1 run dynamique.png

 

Cette technique est simple, et elle permet de charger un code « sur besoin », « sur demande ». Si le code ne peut pas s’exécuter sur la machine, il y aura une erreur lors du chargement. Cette technique est assez limitée car elle ne permet pas de modifier le code externe sans regénérer l’exécutable. Le but est de limiter un temps de chargement, de limiter les « impacts » d’une partie de code qui n’est pas forcement utilisée.

 

2 always included.png

 

 

Plugin

Un plugin est un outil qui permet d’ajouter des fonctions supplémentaires à un logiciel principal. Il est qualifié aussi de module d’extension ou add-on (voir définition sur internet).

 

Code dynamique .VI

Avec LabVIEW, une évolution simple de la première méthode décrite est d’avoir le chargement d’un code dynamique dont le code source « .VI » est externe à l’application. Le code n’est ainsi pas dans la spécification de construction de l’exécutable, le code dynamique n’est donc pas ajouté dans le fichier binaire de l’exécutable. Le code source est donc « à côté » de l’exécutable. Cette technique permet d’avoir un noyau qui est l’exécutable et qui va utiliser un plugin ou un code qui est modifiable. L’avantage est que le « noyau » est indépendant des évolutions de code des plugins. L’inconvénient de cette technique est de partager directement le fichier du code source (le fichier du .VI). Donc cette technique ne permet pas de protéger le code, qui est directement modifiable (cybersécurité) ou peut être récupéré (protection intellectuelle). Cela n’est pas forcement un problème dans un laboratoire qui veut charger le driver de communication avec un multimètre. Mais cette technique peut être un problème sur un plugin d’intelligence artificiel (AI) qu’une industrie désire actualiser régulièrement, mais en conservant « le secret de développement ».

 

OOP en couche d’abstraction (Abstration Layer OOP)

Une techniquement similaire en programmation Objet (OOP) va permettre de développer une « couche d’abstraction » (Abstraction Layer) avec le chargement / remplacement d’un code via une classe fille en dynamic dispatch.

3 classes.png

 

Cette technique est « classique » en programmation objet.

Une première solution consiste à charger toutes les classes dans le fichier binaire de l’exécutable. J'ai illustré cette technique dans un exemple qui permet de piloter 1 carte d'acquisition mais avec 2 drivers différents.

Dans cet exemple, il y a :

  • Une class Deformation avec 2 enfants ConditionneurExterne et CarteSpecifique
  • 1 méthode configuration, avec dans chaque class enfant une méthode en dynamic dispatch pour la fenêtre de configuration spécifique, qui sera donc appelée lors de la définition de l’objet de la carte utilisée
  • Idem pour les méthodes acquisition, méthode acquisition en dynamic dispatch
  • Les données spécifiques à une carte sont donc dans la donnée privée de la class de l’enfant.

 

Le post de cet exemple est disponible ici : exemple de code OOP HAL avec LabVIEW

 

Le projet UML est le suivant

Desruelle_luc_0-1614536010148.png

Le projet LabVIEW contient toutes les classes (mère et enfants)

Desruelle_luc_1-1614536055291.png

 

 

Une deuxième approche « plugin » est de charger les classes filles avec un code source (lvclass) « en dehors » de l’exécutable. Il faut passer le chemin de la classe pour la charger.

 

4 chargement class.png

Avec cette technique l’avantage est de pouvoir réellement définir une abstraction, dans laquelle l’applicatif définit une couche intermédiaire via des méthodes (la classe mère) qui seront redéfinies lors du chargement de la classe fille sélectionnée et chargée dynamiquement.

 

5 2 HAL Objet.png

Exemple de code objet pour avoir une abstraction, avec les classes filles intégrées dans le fichier binaire de l’exécutable.

 

Zoom sur la couche d'abstraction matérielle abrégé HAL pour hardware abstraction layer avec LabVIEW

En  développement informatique, une couche d'abstraction matérielle (abrégé HAL pour hardware abstraction layer) est un  couche intermédiaire entre le logiciel applicatif et le matériel . Cette couche offre des fonctions standardisées de manipulation du matériel tout en cachant les détails techniques de la mise en œuvre. C'est une fonctionnalité importante des systèmes qui utilisent différents types de matériel car en cas d’évolution seule la couche d'abstraction matérielle nécessite adaptation. (source Wikipedia).

 

En développement informatique avec LabVIEW, la couche d’abstraction matérielle est réalisée en programmation Objet. La classe mère, directement appelée par l’application principale, va être l’interface de programmation qui fournit des fonctions génériques (les méthodes de la classe mère). La classe fille, dans un dossier « en dehors de l’exécutable, va être chargée dynamiquement en fonction du matériel et va redéfinir les méthodes génériques pour être spécifique au matériel utilisé.

 

VI Server entre 2 exécutables LabVIEW

Cette fonctionnalité est une petite parenthèse dans les méthodes pour appeler du code externe à un exécutable. L’idée est de déclencher du code d’un exécutable depuis un autre exécutable.

 

Sous LabVIEW il est possible de faire communiquer « facilement » deux exécutables en utilisant le VI Server en accès distant, ou remote.

 

Dans l’exécutable à piloter "RemoteHMI.exe", il faut activer le serveur TCP et le port de communication (par exemple le 11112), via le fichier ini de l’applicatif dans la section du RunTime LabVIEW

 

 

[RemoteHMI]
server.tcp.enabled=True
server.tcp.port=11112

 

 

 

Cela permet d’avoir accès à toutes les fonctions du VI server à distance, comme si nous étions dans le même exécutable

 

6 executable pilotage remote VIServer.png

Cette fonctionnalité est très utile pour piloter un système depuis un autre exécutable, et ainsi séparer la partie commande de la partie pilotage.

 

Plugins via des classes dans PPL (OOP + lvlibp)

Les méthodes de chargement de code source directement accessible présentent 2 problèmes : la sécurité de garantir que le code ne sera pas modifié et la propriété intellectuelle de ne pas vouloir qu’une personne analyse le code.

 

Pour résoudre les problématiques, l’idée est de charger le code depuis une bibliothèque protégée. Sous LabVIEW nous utilisons des « lvlibp », ou terme PPL pour l’anglais (Packed Project Libraries d’extension lvlibp).

 

En français des bibliothèques de projet empaquetées : Les bibliothèques de projet empaquetées LabVIEW sont des bibliothèques de projet  qui regroupent plusieurs fichiers en un seul fichier ayant l'extension .lvlibp. Lorsque vous ouvrez une bibliothèque empaquetée, vous ne voyez que les VIs LabVIEW exportés, donc le code en accès public et pas le code protégé.

 

7 lvlib lvlibp.png

Bibliothèques de projet empaquetées sous Windows

8 windows lvlibp.png

 

Lorsque vous utilisez cette technique de plugin depuis des classes filles en dynamic dispatch, votre exécutable doit contenir la classe mère (Objet) qui va décrire les méthodes utilisables. Elle porte également le nom d’interface.

 

1) création de la lvlib contenant la classe mère interface (lvclass), puis générer la lvlibp

11 deformation.png

 

2) Les classes filles seront séparément réalisées en programmation objet (.lvclass) et seront distribuées dans des PPLs, ou bibliothèques de projet empaquetées ou .lvlibp. Afin de permettre l’appel des classes filles, depuis les lvlibp par la classe mère dans l’exécutable, il est indispensable de générer la classe mère ou interface dans une lvlibp, et de l’inclure dans les bibliothèques de projet empaquetées (PPLs ou lvlibp) des classes filles.

12 deformation projet.png

 

3) Code de l'application principale

Le code va utiliser la lvlipb de la classe mère ou interface (la même qu'utilisée dans les classes enfants)

13 LVOOP.png

 

Il faut charger les "plugins" ou classes enfants. Les classes sont dans des lvlibp. Il faut utiliser le code 

Desruelle_luc_7-1614535264653.png  qualified name specifies the qualified name of the exported file in the packed library. 

 

Un exemple de code suivant permet de charger les plugins, en chargeant une classe enfant dans une lvlibp

10 open external Class.png

 

Il faut typer la classe ainsi chargée dynamiquement dans la classe spécifique.

Desruelle_luc_8-1614535356154.png

 

 

Un exemple de code de plugin par un

14 chargement OOP plugin.png

 

 

 

Exemple de mesure de déformation via une couche HAL avec un projet plugin utilisant des PPLs

En utilisant la programmation objet, avec les classes dans des PPLs, et en chargeant dynamiquement le code via des Plugins, nous obtenons une couche d'abstraction. 

Voici un exemple de mesure de déformation à partir de 2 types de carte qui ne sont pas compatibles. Le but est d'avoir une abstraction matérielle (abrégé HAL pour hardware abstraction layer) afin de séparer le code du programme (le noyau) du driver des cartes d'acquisition.

La couche HAL est un  couche intermédiaire entre le logiciel applicatif et le matériel . Cette couche offre des fonctions standardisées de manipulation du matériel tout en cachant les détails techniques de la mise en œuvre. 

 

Architecture projet plugin avec PPLs pour présenter une couche HALArchitecture projet plugin avec PPLs pour présenter une couche HAL

 

Le code source est disponible dans le post. Vous pouvez me contacter pour vous aider à mettre en place une solution de plugin ou d'abstraction (type HAL).

Bonne lecture et A bientôt.

Luc

banniere Luc Livre NXG Champion.png

Luc Desruelle | Mon profil | Mon blog LabVIEW | Auteur livre LabVIEW : Programmation et applications - G Web
Certified LabVIEW Architect (CLA) & Certified TestStand Developper (CTD) | LabVIEW Champion

MESULOG - LinkedIn site | NERYS - NERYS Group
| directeur CEO MESULOG
| CODIR - NERYS group

Commentaires
Bennus
Member

Bonjour Luc,

 

tout d'abord félicitations pour cet article.

 

J'ai voulu implémenter la solution présentée, en stockant les objets plugins créés à la demande dans une FGV.

Cette FGV stocke un tableau d'objets de type Interface.

Lorsque je souhaite récupérer les objets de ma FGV, ceux-ci sont du type Interface et non plugin, et ils utilisent donc les méthodes de la classe Interface au lieux de celles des classes plugin.

 

Auriez vous une piste pour résoudre ce problème ?

 

Cordialement,

 

Benoît C.
Certified LabVIEW Developer
Desruelle_luc
Trusted Enthusiast

Bonjour et merci.

Les objets plugin sont donc des classes LabVIEW. (?)

Avez-vous tenté de convertir les objets classes interfaces en plugin? -> more generic class (ou more specific) je ne sais pas qui hérite.

non?

pas évident de répondre à ta question. Je n'ai pas beaucoup d'éléments de code, pour comprendre et te répondre.

bonne journée Benoît et à bientôt 

A+ Luc

banniere Luc Livre NXG Champion.png

Luc Desruelle | Mon profil | Mon blog LabVIEW | Auteur livre LabVIEW : Programmation et applications - G Web
Certified LabVIEW Architect (CLA) & Certified TestStand Developper (CTD) | LabVIEW Champion

MESULOG - LinkedIn site | NERYS - NERYS Group
| directeur CEO MESULOG
| CODIR - NERYS group

Bennus
Member

Effectivement, pas facile à expliquer.

je vais essayer de détailler :

 - je développe un framework de test pour TestStand, qui pilote notamment plusieurs alimentations

 - je souhaite avoir un gestionnaire central pour toutes mes alimentations : on lui passe un alias d'alim, et il sait avec laquelle travailler

 - j'ai une classe "interface", qui est virtuelle, qui spécifie les méthodes des classes enfants alimentations

 - j'ai deux classes "alimentation" ( A et B) qui héritent de la classe interface. Chaque classe représente une alimentation différente -> ces classes sont mes classes plugins

 

Mon gestionnaire d'alimentations stocke les références des objets de type "alimentations" via un tableau d'objets de type "interface", pour pouvoir travailler avec des alimentations différentes.

Le gestionnaire d'alimentation est une classe, dont la référence est stockée dans une FGV dans une lvlibp.

 

Mon problème est le suivant : lorsque je veux récupérer une référence vers un objet de type "plugin", je récupère une référence vers un objet de type "Interface" qui utilise systématiquement les méthodes de la classe "interface" au lieu d'utiliser celles des classes plugins.

 

J'espère que c'est un peu plus clair

Benoît C.
Certified LabVIEW Developer
Bennus
Member

Finalement j'ai pu trouver la source de mon erreur, qui venait d'un Switch Case mal câblé...

Encore merci pour l'article qui m'a permis de mettre en œuvre la solution que je voulais

Benoît C.
Certified LabVIEW Developer