![]() |
|
Introduction
|
|
|
|
5.1 Carte SJA 1000 pour PC.
5.2 Avantages de Java pour le protocole CAN.
5.3 CANAPI.
5.4 Application JerryCAN.
CANAPI et JerryCAN constituent un ensemble de bibliothèques et de programmes permettant d'utiliser une carte SJA 1000 pour PC. Ils sont entièrement développés en Java 2 (qui est en fait le JDK 1.2.). CANAPI est une API (Application Programming Interface, interface de programmation) permettant de gérer des trames CAN et d'utiliser la carte SJA 1000. JerryCAN est un outil permettant de recevoir et d'envoyer des trames CAN, ainsi que de contrôler la SJA 1000. Cette application se base sur CANAPI. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5.1 Carte SJA 1000 pour PC. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5.1.1 Description.Le SJA 1000 possède un unique bus Adresse - Données. La carte pour PC
simplifie l'utilisation du composant en démultiplexant le bus et en
permettant un vrai mapping en mémoire de la carte. Il devient alors
possible de l'utiliser en effectuant de simple opérations de lecture -
écriture en mémoire.
Les fichiers .h décrits ci-dessous définissent des constantes pour tous les registres un mode BasicCAN et en mode PeliCAN. Ils contiennent aussi un certain nombre de procédures utiles telles que des procédures d'initialisation, d'envoi et de réception de trames. Le terme de librairie au sens C est un peu abusif ici car tout le code source est contenu dans les fichiers .h. Cela en simplifie l'utilisation. Les procédures ont été développées et testées avec le compilateur bcc
de Borland dans sa version 4.52 sous Windows 95. Elles ne devraient pas être
utilisables sous Windows NT car elles adressent directement la mémoire.
Le fichier basiccan.h contient :
Le fichier util.h contient des fonctions utiles :
Le fichier slio.h contient de fonctions pour le SJA 1000 en mode BasicCAN permettant de calibrer des SLIOs sur le bus et de leur envoyer des ordres.
5.1.2.2 Mode PeliCANLe fichier pelican.h contient :
Le fichier utilp.h contient des fonctions utiles en PeliCAN :
5.1.3 ProgrammesLes programmes décrits dans le tableau ci-dessous utilisent les librairies. Le code source en C se trouve dans les fichiers programme.c. Les programmes ont été développées et testées avec le compilateur bcc de Borland dans sa version 4.52 sous Windows 95 (en mode DOS).
| |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5.2 Avantages de Java pour le protocole CAN. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
A priori, l'utilisation du langage de haut niveau qu'est Java pour un
développement très bas niveau peut sembler curieuse. En fait, de nombreux
arguments justifient ce choix.
Un langage de haut niveau et possédant des bibliothèques extrêmement complètes permet de ne pas réinventer la roue à chaque fois et d'avoir une productivité bien supérieure à celle que l'on pourrait avoir en C par exemple. Ceci s'inscrit dans une tendance générale du développement logiciel qui veut
qu'on n'utilise les langages de bas niveau tels que le C que lorsque c'est
absolument nécessaire (besoin de contrôler le hardware précisément, pas d'autres
langages disponibles), et que l'on s'oriente de plus en plus vers des outils de
type AGL (Atelier de Génie Logiciel).
Un des grands avantages qu'apporte langage un orienté objet est qu'il permet de créer un code qui sera plus facilement réutilisable qu'avec un langage utilisant une autre philosophie. Dans cette optique, Java va plus loin que le C++, tout en restant plus simple et plus pratique à utiliser que des langages orientés objets plus "extrêmes" tel que SmallTalk. Ces qualités ont permis la création d'une API réutilisable dans
d'autres projets nécessitants l'utilisation d'un bus CAN.
Une des qualités originelles de Java est sa portabilité, le "write once, run anywhere". CAN API ne respecte pas tout à fait cette règle puisqu'il a fallu développer une petite librairie qui permette d'accèder à la carte. En effet, cette opération étant dépendante du système d'exploitation, il n'est pas possible de l'effectuer directement à partir de Java (sinon le code ne serait plus portable). Néanmoins, il suffira de réécrire cette petite librairie sous un autre environnement pour pouvoir y utiliser immédiatement toutes les classes. Actuellement, seule une librairie pour Windows 95 a été développée.
Le choix de Java se justifie aussi par l'importance de plus en grande qu'il prend dans les applications embarquées. En effet, utiliser Java dans des téléphones portables, des autoradios, voire des cartes à puce présente l'avantage de grandement réduire les coûts de développement qui, historiquement propriétaires, nécessitaient d'être pratiquement recommencés de zéro à chaque nouvelle génération d'appareils. Le bus CAN étant lui aussi lié à l'informatique embarquée, l'utilisation de Java pour contrôler un bus CAN se justifiait tout à fait. On notera aussi qu'avec Jini\footnote{Voir http://www.sun.com/jini/}, la nouvelle technologie de Sun, créateur de Java, la tendance actuelle est de plus en plus de rendre le réseau transparent pour l'utilisateur et pour les applications. Nul doute que le CAN sera aussi de plus en plus influencé dans l'avenir par cette tendance. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5.3 CANAPI. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
CANAPI est la bibliothèque de base permettant de gérer le protocole CAN ainsi que le SJA 1000. Cette bibliothèque est composée de trois packages : canapi.can20 contient des classes d'utilisation du protocole CAN, canapi.sja1000 des classes pour utiliser le SJA 1000, et canapi.app diverses classes applicatives. Les grandes caractéristiques de cette librairie sont :
D'autre part, toute la librairie a été développée dans l'optique de pouvoir
la réutiliser pour d'autres applications.
Le package canapi.can20 contient des classes modélisant des trames respectant le protocole CAN 2.0. Dans l'implémentation actuelle, seul le protocole CAN 2.0 A est supporté, mais la conception des classes les rend facilement extensible pour qu'elles supportent aussi le protocole CAN 2.0 B. La classe ID modélise un identificateur de trame CAN. La classe représente par défaut un ID pour le protocole CAN 2.0 A. Il est possible de créer un ID à partir d'un entier (type int) ou d'une chaîne de caractères (objet de la classe String). Des méthodes utilitaires sont proposées pour ne récupérer que certains bits de l'ID. Enfin, la classe implémente aussi l'interface Comparable, ce qui permet d'utiliser ID dans des structures de données gérant le tri. Ainsi, le tri par ordre de priorités de messages à envoyer est immédiat. La classe Frame est une classe abstraite modélisant les comportements communs des deux types de trames de données, les Data Frames et les Remote Frames. Au niveau de l'implémentation, cette classe ne contient qu'un seul champ de données, un objet de la classe ID. Les deux classes DataFrame et RemoteFrame héritent de la classe Frame et rajoutent le comportement spécifique des deux types de trames. Toutes les méthodes des classes de ce package ne sont pas synchronisées, il
s'agit donc de les utiliser avec précautions dans une application
multithreadée.
Le package canapi.sja1000 contient des classes permettant d'utiliser le
SJA 1000.
Le SJA 1000 est mappé en mémoire, son utilisation passe donc par des lectures et des écritures en mémoire. Ceci pose un problème dans le cas d'une utilisation avec Java. En effet, Java est conçu pour être indépendant de la plate-forme sur laquelle s'exécute l'application. Le langage ne possède donc aucune méthode pour écrire ou lire directement à une adresse en mémoire. Pour résoudre ce problème, il est possible de passer par l'intermédiaire de JNI, Java Native Interface, qui permet d'appeler des procédures dans un autre langage que Java. La solution retenue a donc été d'écrire deux procédures en C effectuant l'une un inportb et l'autre un outportb, et de les appeler ensuite depuis les classes Java. Ces méthodes sont appelées depuis la classe abstraite \mbox{MemoryMappedDevice} qui modélise une carte mappée en mémoire. Pour ensuite effectivement avoir une classe qui représente une carte, il faut créer une classe qui hérite de cette classe et qui pourra utiliser les méthodes read et write. On notera que ces deux méthodes sont protected, il est en effet raisonnable de n'autoriser qu'une classe de type \textit{carte} à les appeler. D'autre part, ces deux méthodes implémentent un adressage relatif afin d'en faciliter l'utilisation. Cette solution possède malheureusement ses limites. En effet, la création de méthodes natives est contraire au principe de portabilité de Java. Pour utiliser les API sur une autre plate-forme, il faudra réimplémenter les méthodes C sur chaque plate-forme. D'autre part, l'implémentation actuelle de ces méthodes sous Windows 95 utilise le mode de comptabilité MS-DOS, autrement dit la librairie DLL contenant les deux méthodes n'est pas un vrai driver 32 bits. En conséquence, les API ne sont pas utilisable sous Windows NT actuellement, et pour qu'elles le deviennent, il faudra écrire un vrai driver. Autre limitation, il n'est pas
possible d'utiliser les interruptions du SJA 1000 car la gestion des
interruptions sous Windows passe obligatoirement par l'écriture d'un
driver.
Pour faire tourner CAN API sous un autre environnement que Windows, il faut réecrire le code du fichier MemoryMappedDevice.c, c'est-à-dire le code des procédures déclarées dans canapi_sja1000_MemoryMappedDevice.h. Ce dernier est généré par la commande : javah canapi.sja1000.MemoryMappedDevice Ensuite, MemoryMappedDevice.c doit être compilé sous forme d'une librairie. Sous Windows, avec Visual C++ 4 : c:\Program Files\DevStudio\Vc\bin\vcvars32.bat pour initialiser les variables du compilateur. Puis : cl -Ic:\jdk1.1.6\include -Ic:\jdk1.1.6\include\win32 -LD MemoryMappedDevice.c -Fedevice.dll pour compiler la librairie.
Revenons sur le package canapi.sja1000. La classe Sja1000 hérite de MemoryMappedDevice et représente une carte SJA 1000. Elle est abstraite et implémente toutes les méthodes communes aux deux modes de fonctionnement du SJA 1000 que sont les modes BasicCAN et PeliCAN. On a donc logiquement deux classes, nommées BasicCAN et PeliCAN, qui héritent de Sja1000 et qui représentent une carte fonctionnant respectivement en mode BasicCAN et PeliCAN.
Ces classes contiennent toutes les méthodes pour utiliser facilement le SJA 1000. Outre des méthodes pour lire un bit du registre STATUS ou lire les re\-gistres d'erreurs par exemple, les principales méthodes sont init (qui prend en paramètre un objet de configuration sur lequel nous reviendrons) pour initialiser le SJA 1000, send pour envoyer une trame et receive pour recevoir une trame. Détail important, ces méthodes en particulier, bien que fonctionnant différemment dans les modes BasicCAN ou PeliCAN, sont utilisables à partir d'une référence de type Sja1000 (grâce aux méthodes abstraites et à l'héritage virtuel... voir le code source pour les détails). A l'utilisation, cela peut se traduire par un code du style : Sja1000 sja; if (isBasic) sja = new BasicCAN(); else sja = new PeliCAN(); ... sja.send(aFrame); On se référera à la documentation Javadoc pour la liste et le détail de
toutes les méthodes.
Pour ne pas rendre la taille et la complexité de ces classes trop importante, toute la gestion de la configuration du SJA 1000 a été séparée dans d'autres classes spécialisées. Ce sont les classes SjaConfig, BasicCANConfig et PeliCANConfig, où dans le même esprit que précédemment, BasicCANConfig et PeliCANConfig héritent toutes les deux de SjaConfig. Elles contiennent tous les paramètres de configuration du SJA 1000 (Acceptance Code, Bus Timings,...) avec pour chacun une valeur par défaut. Les accesseurs, c'est-à-dire les méthodes get et set qui permettent
d'accéder aux données, effectuent le formatage nécessaire et pour les
méthodes set, les tests de validité qui permettent d'éviter de donner des
paramètres de configuration non supportés par le SJA 1000. Les objets de
ces classes sont en particulier passés en paramètre à la méthode init de
la classe Sja1000.
Le problème Un des problèmes qui se posent rapidement lors du développement d'une application évoluée utilisant une ressource telle que la carte SJA 1000 est l'accès concurrent à cette carte par plusieurs parties de l'application. Autrement dit, il est nécessaire de prévoir dès la conception l'utilisation de la librairie CAN dans un environnement multithreadé. Ce problème est encore plus flagrant en Java qui implémente la gestion des threads dans le langage lui-même, ce qui a pour conséquence que la plupart des applications Java en font un usage important. La classe SjaManager. Dans CAN API, les problèmes liés à la gestion des threads ont été résolus en centralisant toutes les opérations sur la carte SJA 1000 dans un unique thread, qui est le seul autorisé à accéder à la carte. Ce thread est implémenté par la classe SjaManager. Les deux principes de ce thread sont les suivant :
La fonction run() (En Java, on met dans la méthode run() d'une classe implémetant un thread ce qui devra être exécuté par le thread) du thread scrute régulièrement :
A l'exception de ce thread "principal", AUCUN autre thread ne doit accéder aux registres du SJA 1000, c'est à dire utiliser les classes Sja1000 (cette limitation ne s'applique bien sûr qu'aux applications multithreadées, les autres pouvant utiliser directement les classes Sja1000). Communication thread principal (SjaManager) vers les autres threads. SjaManager gère un certain nombre de propriétés avec des méthodes du type addUneProprieteListener et removeUneProprieteListener. Ces propriétés sont :
Par exemple, supposons qu'une classe veuille être informée des messages arrivés et recevoir ces messages arrivés (Voir la classe jerrycan.ReceiverPanel pour un autre exemple complet). Il lui faudra d'abord implémenter l'interface PropertyChangeListener et avoir une méthode propertyChange qui sera appelée à chaque réception d'un message. Enfin, il lui faudra s'enregistrer auprès de l'objet SjaManager pour lui indiquer qu'elle veut recevoir les messages arrivés avec la méthode addReceiveListener de SjaManager.
Communication des autres threads vers le thread principal (SjaManager). SjaManager gère des marqueurs positionnés par les autres threads, et lui indiquant les commandes à appliquer au SJA 1000 (des "command request"). Ces marqueurs sont :
Par exemple, pour envoyer une trame, il suffit d'appeler send de l'objet SjaManager avec en paramètres la trame à envoyer et, éventuellement, si l'on souhaite la confirmation de l'envoi de la trame, un objet d'une classe implémentant l'interface NeedSendConfirmation dont la méthode confirm sera appelée pour confirmer l'envoi.
5.3.3 Package canapi.app.Ce package contient des classes permettant, à partir des fonctionnalités de base du SJA 1000 telles que l'envoi et la réception d'une trame, d'effectuer des opérations plus complexes. En l'occurrence, le package contient dans l'implémentation actuelle une classe FileSender permettant d'envoyer des données plus longues que les 8 octets d'une trame de données. Cette classe prend les données soit à partir d'un fichier, soit à partir d'un objet String et les envoie sur le bus avec un ID spécifié selon la procédure suivante : toutes les trames ont une longueur (DLC) de 8 octets, sauf la dernière. Ce DLC différent de 8 permet de connaître la fin du fichier\footnote{il est possible que la dernière trame soit vide.}. Le package contient aussi un classe Slio non totalement implémentée permettant de gérer des SLIO se trouvant sur le bus. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
5.4 Application JerryCAN. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
JerryCAN est une application utilisant CANAPI. Son objectif est double :
démontrer une partie des possibilités du bus CAN, du contrôleur SJA 1000 et
de la librairie CAN API, et être utilisé comme application facilitant le
développement d'applications utilisant le bus CAN.
Un certain nombre d'options de JerryCAN peuvent être réglées dans le fichier
de configuration jerrycan.properties. Le format de ses entrées est :
nom_du_paramètre = paramètre
JerryCAN permet d'effectuer la configuration du SJA 1000 de façon simple et graphique grâce à un assistant de configuration fonctionnant sur la même philosophie que ceux que l'on trouve dans les environnements graphiques tels que Windows. Il permet de choisir le mode de fonctionnement du SJA 1000 (BasicCAN ou PeliCAN), de régler l'Acceptance Filter, les bus timings, le registre OUTPUT CONTROL qui définit les fonctions et le mode de fonctionnement des pattes TX0 et TX1, d'activer ou de désactiver la sortie de l'horloge ou le transceiver interne. Lors du lancement de JerryCAN, l'assistant de configuration est automatiquement affiché. L'utilisateur peut accepter la configuration par défaut et choisir "Terminer" ou modifier cette configuration. L'assistant utilise un modèle d'assistant général du package oberle.awt.assistant implémentant les fonctions de base telles que le passage d'un écran à l'autre ou l'affichage. Ce modèle se spécialise en créant des classes pour chaque écran de configuration ainsi qu'une classe globale, l'AssistantManager, qui va contrôler l'assistant, en vérifiant par exemple que l'utilisateur a bien entré les bonnes données avant de lui donner le droit de passer à l'écran suivant. Des modèles de création d'un assistant peuvent être trouvés dans les fichiers du le répertoire src/oberle/awt/assistant :
5.4.3 Gestion du Manager.Après la fin de l'assistant de configuration, une instance de la classe SjaManager, le manager, est créé. Le manager est démarré et le SJA 1000 initialisé, puis l'utilisateur peut commencer à utiliser JerryCAN. Il est possible d'arrêter ou de redémarrer le manager dans le menu SJA 1000. Si le manager est arrêté, la LED en bas à droite de la fenêtre principale est rouge, sinon, lorsque le manager est prêt à être utilisé, la LED est verte. Il est aussi possible de régler la vitesse du manager grâce à l'option \textit{Vitesse du Manager} dans le menu SJA 1000 qui affiche une fenêtre de réglage. Plus le manager fonctionnera vite, plus les trames seront rapidement envoyées ou moins il y aura de risques qu'un Data Overrun survienne. Néanmoins, il peut être intéressant de ralentir le manager pour libérer des ressources machines. Par défaut, le manager est réglé à sa vitesse maximale dans JerryCAN. La valeur est modifiable avec le paramètre managersleepingtime du fichier de configuration. Attention, 0 correspond à la vitesse maximale car la valeur correspond en fait à la pause en milisecondes effectuée par la boucle principale de la méthode run() de SjaManager. Il est aussi possible dans le menu SJA 1000 d'effectuer une nouvelle
configuration du SJA 1000, de le réinitialiser ou encore d'annuler tous les
envois en cours en cas de problème sur le bus par exemple.
Le menu Outils propose plusieurs choix affichant les fenêtres suivantes. Les trois premiers outils fonctionnent sur un principe de polling et proposent
un bouton Démarrer le polling / Arrêter le polling qui permet de choisir de
recevoir ou de ne pas recevoir les informations. En effet, le polling consommant
des ressources, il peut être utile de le désactiver.
Cette fenêtre permet d'afficher les trames reçues par le SJA 1000. La fenêtre du
haut affiche en permanence la dernière trame reçue, tandis que la fenêtre du bas
affiche toutes les trames reçues lors d'un clic sur le bouton Rafraîchir. Le
bouton Effacer permet de vider la liste des trames reçues. Enfin une option
Ecrire dans le fichier de log permet d'écrire toutes les trames reçues dans un
fichier dont le nom est précisé dans le fichier de propriétés de JerryCAN par le
paramètre logfile.
Cette fenêtre affiche le détail de chaque bit du registre STATUS.
Cette fenêtre affiche le détail des registres ArbitrationLostCapture
(indique l'emplacement de la dernière perte d'arbitration),
ErrorCodeCapture (donne des informations sur la dernière erreur
survenue telles que sont type ou son emplacement), ReceiveErrorCounter
(nombre d'erreurs en réception) et TransmitErrorCounter (nombre
d'erreurs en transmission).
Cette fenêtre permet d'envoyer une trame en précisant l'ID, si c'est une Remote Frame, et si ce n'est pas le cas, les données de la trame. Le format de l'ID est un nombre en hexadécimal sur trois chiffres de la forme :
5.4.4.5 Envoi d'un fichierCette fenêtre permet d'envoyer un fichier sur le bus avec l'ID précisé
dont le format est identique à celui de la fenêtre d'envoi de trame. Le
fichier est envoyé par série de trames de données de 8 octets sur le bus,
sauf la dernière trame dont la longueur est inférieure à 8
(éventuellement 0 si le nombre d'octets du fichier est un multiple de 8).
Cette dernière trame permet de repérer la fin du fichier.
Cette fenêtre permet d'envoyer un fichier sur le bus de telle sorte que, si ce fichier est un fichier S29 par exemple, il puisse être chargé par un autre noeud du bus. Le protocole d'envoi est le suivant : une Remote Frame est envoyée avec l'ID précisé par le paramètre idloader de fichier de propriétés. Ensuite le loader attend une réponse, c'est à dire une nouvelle Remote Frame avec le même ID. Lorsqu'il a reçu cette réponse, il envoie le fichier de la même manière que la fenêtre Envoi d'un fichier. En pratique, le noeud distant qui doit charger le programme ne doit envoyer la
réponse que lorsqu'il est prêt à recevoir le programme.
Il est possible d'envoyer les mails de l'utilisateur sur le bus grâce à l'option Démarrer le serveur Mail du menu Serveurs. L'utilisateur doit alors rentrer son login et son mot de passe. Le serveur de mail à consulter est précisé par le paramètre host du fichier de configuration, tandis que l'intervalle de vérification de la présence de nouveau mail est précisé par le paramètre mailsleepingtime. Lorsqu'un nouveau mail arrive, une Remote Frame est envoyée sur le bus avec l'ID précisé par le paramètre idmail. Si le serveur reçoit une réponse, c'est à dire une Remote Frame avec le même ID, il envoie un fichier contenant le mail sur le bus selon la procédure d'envoi de fichier. Il est aussi possible d'utiliser le serveur de mail comme une application autonome en exécutant la commande : java jerrycan.mail.MailWatcher user password
Cliquez pour avoir un exemple de pages générées par CAN WebServer. La classe jerrycan.web.WebServer est un serveur Web permettant d'accéder à l'état du bus depuis Internet. Ce serveur attend les connections des browsers sur le port 80 par défaut. Lorsqu'une page lui est demandée, il regarde l'état du bus et génère une page HTML en fonction des informations récupérées. CAN WebServer peut fonctionner soit en application autonome, soit intégré dans JerryCAN. Pour le lancer comme application autonome, exécuter la commande : java jerrycan.web.WebServer Dans JerryCAN, le serveur peut être démarré ou arrêté dans le menu
Serveurs.
Dans une utilisation classique, d'autant plus en laboratoire, on voit rarement les compteurs d'erreurs bouger. On peut faire une expérience intéressante en envoyant un fichier sur le bus et pendant l'envoi, couper le fil du bus. Si on a activé le polling des registres d'erreurs, on voit celui des erreurs en transmission augmenter très rapidement jusqu'à 256. D'autre part, le bit Error Status du registre STATUS est activé. Si on rebranche alors le bus, le compteur rediminue, mais plus lentement qu'il n'avait augmenté. Lorsqu'il atteint 96, le bit Error Status repasse à OK. Ce n'est qu'après avoir résolu un problème particulièrement ardu avec l'outil complexe qu'on se rend compte que i était en fait une intensité. Loi Secrète d'Ampère. | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||