tornado2 - michel marie

59
Tornado2 Système de développement intégré temps réel Noyau VxWorks 5.4.2 Cible VME, ELTEC BAB-40 Wind River Systems : http://www.wrs.com News group : comp.os.vxworks Auteur : M Michel Marie

Upload: others

Post on 14-Mar-2022

3 views

Category:

Documents


0 download

TRANSCRIPT

Tornado2

Système de développement intégré temps réel

Noyau VxWorks 5.4.2

Cible VME, ELTEC BAB-40

Wind River Systems : http://www.wrs.com

News group : comp.os.vxworks

Auteur : M Michel Marie

2 Système temps réel – Tornado2 Professeur : Michel MARIE

1. Objectifs du cours :

Environnement Tornado2, outils du noyau VxWorks.

Construction d’un noyau VxWorks et téléchargement des modules sur la cible.

Utilisation des outils Tornado en développement croisé.

Configuration et contrôle des outils de synchronisation VxWorks (sémaphore binaire, mutex, sémaphores à compte).

Configuration et contrôle des outils de communication VxWorks (mémoire partagée, queues de

messages, tubes de communication « pipes »).

Mise en œuvre d’un timer pour une exécution périodique.

Création et utilisation de système de fichiers locaux (création d’une RAM disque)

Accès à un système de fichiers sur machine distante.

Utilisation des protocoles réseaux pour communiquer entre des tâches s’exécutant sur différentes machines (NFS, FTP, RPC) ; programmation réseau, les sockets.

Reconfiguration de VxWorks, linkage et démarrage du noyau sur une tâche définie par l’utilisateur.

2. Vue d’ensemble des outils de développement :

Outils de développement Tornado2 :

- Gnu : Compilateur C et C++

- Launcher : Plateforme des outils Tornado

- WindShell : Shell permettant un accès interactif avec la cible.

- CrossWind : Debugger au niveau source.

- Browser : Outil de visualisation d’informations système (état des tâches,

des sémaphores, de la pile, de la mémoire, etc…).

- Projects : Outil de création d’applications téléchargeables sur la cible et

de reconfiguration du noyau VxWorks.

- Simulator : Outil permettant de simuler l’exécution d’applications sur la

machine Host

- WindView : Debugger avec GUI permettant une analyse graphique d’une

application. La version de base de WindView n’est utilisable

qu’avec le simulateur.

- Windnavigator : Outil de visualisation graphique du code et des structures de

code d’applications écrites en langage C et C++ ( hiérarchie

des classes, appel des fonctions, etc…).

- Triggering : Outil permettant à l’utilisateur de produire des actions

spécifiques (démarrage/arrêt de WindView, exécution d’une

fonction) lorsqu’un événement ou une combinaison

d’événements est survenue.

4. Outils optionnels à Tornado :

WindNet SNMP : Outil de gestion du protocole SNMP (Simple Network Management

Protocol).

WindView : Complément à la version de base permettant d’utiliser cet outil sur une cible physique.

VxMP : Outils de développement d’applications multiprocesseurs.

VxVMI : Outils de développement d’une unité de gestion de mémoire virtuelle (MMU).

3 Système temps réel – Tornado2 Professeur : Michel MARIE

Télécharger et démarrer VxWorks

1. Mise en situation.

Pour de nombreuses cibles compatibles avec le noyau VxWorks, Wind River commercialise un BSP (Board Support Package). Dans notre cas, pour la cible ELTEC 68040 il s’agit du BAB40.

Ce BSP contient tous les fichiers de configuration de la cible, les drivers nécessaires à

l’utilisation de ses différents périphériques (ports série, port Ethernet, Timers, contrôleur de bus

VME, etc.) et un noyau VxWorks de base, à télécharger.

(fichier d:\tornado2\target\proj\projectNoyau\default\vxworks)

La liaison série entre le PC et la cible sert à configurer les paramètres strictement nécessaires au

téléchargement par le réseau Ethernet du noyau VxWorks et des modules d’application. Ces

paramètres se trouvent ensuite sauvegardés dans une NVRAM afin d’être lus par la

BOOTROM lors des futurs démarrages de la cible. Une fois VxWorks démarré la liaison série

se trouve configurée en mode terminal par défaut. Pour communiquer avec la cible via la liaison

série l’application hyperterminal est installée avec Tornado.

Commandes de configuration :

Command Description

h Help command--print a list of available boot commands.

? Same as h.

@ Boot (load and execute the file) using the current boot parameters.

p Print the current boot parameter values.

c Change the boot parameter values.

l Load the file using current boot parameters, but without executing.

g adrs Go to (execute at) hex address adrs.

d adrs[, n] Display n words of memory starting at hex address adrs. If n is omitted, the

default is 64.

t adrs1,

adrs2,

nbytes

Copy nbytes of memory, starting at adrs1, to adrs2.

e Display a synopsis of the last occurring VxWorks exception.

n netif Display the address of the network interface device netif.

La commande c permet de configurer la liaison Ethernet.

La commande @ permet de télécharger le fichier image de VxWorks puis de démarrer le noyau. Le téléchargement se fait via le réseau selon le protocole FTP. Il est par conséquent nécessaire,

avant d’activer cette commande, d’exécuter le serveur FTP installé avec tornado en précisant le

nom d’utilisateur, le mot de passe choisi et les droits sur le fichier à télécharger.

4 Système temps réel – Tornado2 Professeur : Michel MARIE

- Exemple de configuration :

[VxWorks Boot]: p

boot device : ln

processor number : 0

host name : mars

file name : c:\tornado\target\config\bab40\vxWorks

inet on ethernet (e) : 90.0.0.50

inet on backplane (b) :

host inet (h) : 90.0.0.1

gateway inet (g) :

user (u) : fred

ftp password (pw)(blank=use rsh) :secret

flags (f) : 0x0

target name (tn) : phobos

startup script (s) :

other (o) :

Redémarrer le noyau est possible soit en tapant CTRL+X dans la fenêtre du terminal X soit par la

commande reboot() de WindShell.

La liste des cibles (target) connectées au réseau est visualisable par le Launcher, Vous pouvez ainsi

sélectionner la cible de votre choix pour développer votre application.

Les cibles accessibles par le Launcher auront dûes, précédemment, être configurées à l’aide du

menu ToolsTargetServerConfigure. Il est alors nécessaire de préciser :

- Une nom décrivant la commande d’attachement

- Un nom pour le target serveur

- Des propriétés (Back End)

- Un mode de liaison (wdbrpc)

- Une adresse IP

La case à cocher « Add description to menu » permet d’ajouter une ligne associée à cette

commande d’attachement au menu TargetServer.

La commande Launch réalise alors l’attachement du PC par l’application dite Target Server

(tgtsvr) et le test de l’agent cible WDB.

Toutes les interactions de développement croisé entre les applications sur le PC (WindShell,

CrossWind, WindView, etc…) et la cible VxWorks se feront a l’aide du Target Server coté PC et

d’un agent WDB coté cible.

5 Système temps réel – Tornado2 Professeur : Michel MARIE

Une fois le PC attaché à la cible le menu du launcher devient actif :

Les icônes correspondent, dans l’ordre de gauche à droite au lancement des outils suivants :

le browser, permettant d’obtenir des informations sur la cible, la mémoire, les modules, les

objets, etc,

WindShell, démarrant une session Shell sur la cible choisie,

Crosswind, démarrant le debugger niveau source,

Simulator, démarrant le simulateur de cible,

WindView, démarrant l’outil de "debuggage" graphique,

Windnavigator, démarrant l’outil de visualisation des structures d’applications,

Triggering, démarrant l’outil de synchronisation.

2. Le Browser

La fenêtre du browser propose 7 rubriques :

La rubrique "Target information" apportant quelques informations de base sur la cible

d’attachement.

La rubrique « Module information » informant des modules téléchargés sur la cible et de

leur contenu (y compris le noyau).

La rubrique "Object information", une des plus utiles puisqu’elle permet de connaître

l’état des objets utilisés par une application, sémaphores, queues de messages, etc.

La rubrique "Spy chart" qui permet de connaître le taux d’occupation du processeur de la

cible et la répartition de cette occupation entre les tâches.

La rubrique "Stack check" donnant l’état d’utilisation de la pile des tâches actives.

La rubrique "Tasks" indiquant les tâches actives et leur état.

La rubrique "Memory usage" indiquant la quantité de mémoire vive utilisée par chaque

module ou application.

Exemples : « Target information »

« Spy chart »

Les 3 icônes du browser correspondent, dans l’ordre de gauche à droite :

Au rafraîchissement ponctuel de l’affichage.

Au rafraîchissement périodique de l’affichage.

A la configuration du rafraîchissement périodique.

6 Système temps réel – Tornado2 Professeur : Michel MARIE

3. WindShell

WindShell est un interpréteur de langage C interactif permettant :

d’accéder à l’ensemble des facilités de VxWorks,

d’invoquer chaque fonction chargée en mémoire,

de créer dynamiquement et d’examiner des variables. C’est également un interpréteur de langage Tcl interactif permettant :

de définir des commandes utilisateur,

d’automatiser des interactions avec la cible.

L’outil WindShell est activé soit à partir du menu ToolsShell, soit à partir du launcher.

Exemples :

Le Shell lit les lignes en entrée comme une file de commandes, les évalue et retourne le résultat

obtenu.

Conversion de données.

68

value = 68 = 0x44 = ‘D’

0xf5de

value = 62942 = 0xf5de = _init + 0x52

Le shell retourne le résultat en décimal puis en hexadécimal et si possible comme un caractère

constant ou une adresse symbolique plus un offset.

Calcul de données.

(14*9)/3

value = 42 = 0x2a = ‘*’

(0x1355<<3) & 0x0f0f

value = 2568 = 0xa08

Calcul avec variables et allocation dynamique.

x = va1 + va2

new symbol « x » added to symbol table

address = ……….

value = ……….

Invocation de fonctions VxWorks.

taskSpawn(tmaTache , 10 , 0 , 1000 , maTache , fd1 , 300)

value = 0x0

fd = open (fichier , 0 , 0 )

fd = …… : value = 0x0

Invocation de fonctions utilisateur.

bilan = Mafonction(dites, 33 )

bilan = ( adresse de bilan) : value = …..

Invocation de fonctions « Built-In Shell ».

i

NAME ENTRY TID PRI STATUS PC SP ERRNO DELAY

---------- ------------ -------- --- ---------- -------- -------- ------- -----

tLogTask _logTask 3e6188 0 PEND 2fd00 3e60e4 0 0

tExcTask _excTask 3e8a9c 0 PEND 2fd00 3e89fc 0 0

tWdbTask 0x24ab2 3c2f30 3 READY 2f9b2 3c2e20 0 0

tNetTask _netTask 3e1d54 50 READY 9a14 3e1cec 0 0

tFtpdTask _ftpdTask 3c6248 55 PEND 26090 3c6164 0 0

value = 0 = 0x0

Attention : Les « macros » définies pour le C préprocesseur avec la directive #define et

qui peuvent apparaître dans l’aide Tornado ne peuvent pas être utilisées dans les fonctions

« Built-In Shell».

7 Système temps réel – Tornado2 Professeur : Michel MARIE

Quelques fonctions « Built-In Shell » classées par centre d’intérêt.

Commandes de gestion des tâches

Fonction Rôle Fonction Rôle

sp crée une tâche avec options/défaut period Active une tâche périodiquement

sps Crée une tâche avec l’état

suspendu repeat N répétitions/lancement d’une

tâche

ts/tr suspend/reprend une tâche taskIdDefault Spécifie le TID pris par défaut

td Supprime une tâche

Commandes d’information sur les tâches.

Fonction Rôle Fonction Rôle

i

Affichage d’informations sur les

tâches du système tw Retourne des informations sur

l’objet par lequel une tâche se

trouve en état d’attente

iStrict Equivalent à i checkStack Affiche l’usage de la pile par une

tâche

ti Affichage d’informations

détaillées sur une tâche tt Affiche un « trace » de la pile

w Retourne des informations sur les

tâches en état d’attente

« PENDING »

taskIdFigure Retourne le TID d’une tâche à

partir de son nom

Commandes d’information système.

Fonction Rôle Fonction Rôle

devs Liste des périphériques connus

par le système ls Liste des fichiers dans le

répertoire courant

lkup Liste des symboles issus de la

table des symboles pwd Affichage du répertoire courant

lkAddr Liste les symboles trouvés à

partir de l’adresse spécifiée help Description de quelques

commandes usuelles du Shell

d Dump de la mémoire h Affiche les 20 dernières

commandes

l Désassemble et affiche un

nombre spécifié d’instructions shellHistory Modifie la dynamique de la

commande h

printErrno Décrit la dernière valeur de la

variable « error » shellPromptSet Modifie le prompt du Shell

version Affichage de la version

VxWorks printLogo Affiche le logo du Shell

Tornado

cd Change le répertoire courant

Commandes de modification du système et de «debuggage ».

Fonction Rôle Fonction Rôle

ld Charge un module sur la cible et le

lie dynamiquement au noyau

temps réel.

cret Exécuter jusqu’à la fin de la

fonction en cours

unld Efface un module de la cible et

libère la mémoire occupée bdall Efface tous les points d’arrêt

m Modification de la mémoire bd Efface un point d’arrêt

mRegs Modification des registres pour

une tâche spécifiée reboot Redémarrage de la cible

b Positionne ou affiche les points

d’arrêt bootChange Modification des paramètres

de boot sauvegardés dans la

NVRAM

8 Système temps réel – Tornado2 Professeur : Michel MARIE

bh Positionne un point d’arrêt

matériel sysSuspend Arrêt système (En mode

système uniquement – Agent

WDB externe)

s Exécution d’un pas de programme sysResume Redémarrage du système (En

mode système uniquement –

Agent WDB externe)

so Exécution d’une instruction, toute

fonction étant exécutée en 1 fois agentModeShow Retourne le mode de l’agent

Target, système ou tâche

c Redémarre jusqu’au prochain point

d’arrêt sysStatusShow Retourne l’état du contexte

système, « suspended » ou

« running »

quit ou exit Fermeture du Shell

Commandes de développement C++.

Fonction Rôle Fonction Rôle

cplusCtors Appel manuel d’un constructeur

statique CplusStratShow Retourne la stratégie du

constructeur/destructeur

courant

cplusDtors Appel manuel d’un destructeur

statique cplusXtorSet Appel d’un constructeur

« stratégie »

Commandes d’affichage d’objets.

Fonction Rôle Fonction Rôle

show Affichage

d’informations sur un

objet spécifié dans la

fenêtre du Shell

iosDrvShow Affichage de la liste des

« drivers » système

browse Affichage

d’informations sur un

objet spécifié dans la

fenêtre du Browser

iosDevShow Affichage de la liste des

« devices » système

( tubes de communication )

classShow Affichage

d’informations sur une

classe du noyau

VxWorks

iosFdShow Affichage de la liste des

« File descriptors » système

taskShow Affichage

d’information sur la

structure TCB

memPartShow Affichage des partitions et

des statistiques

semShow Affichage

d’informations sur un

sémaphore spécifié

memShow Affichage de la totalité de

l’espace libre et alloué dans

les partitions système

semPxShow Affichage

d’informations sur un

sémaphore POSIX

spécifié

smMemShow Affichage de la totalité de

l’espace libre et alloué dans

la mémoire système

wdShow Affichage

d’informations sur un

« watchdog »

smMemPartShow Affichage de la totalité de

l’espace libre et alloué dans

une partition système

msgQShow Affichage

d’informations sur une

queue de messages

moduleShow Affichage des modules

mqPxShow Affichage

d’informations sur une

queue de messages

POSIX

moduleIdFigure Retourne l’ID d’un module

à partir de son nom

9 Système temps réel – Tornado2 Professeur : Michel MARIE

taskCreateHookShow Retourne la liste des

tâches Hook create taskRegsShow Retourne le contenu des

registres de la tâche

TaskDeleteHookShow Retourne la liste des

tâches Hook delete taskWaitShow Retourne des informations

sur l’objet qui a

conditionné l’état

« PENDING » d’une tâche.

TaskSwitchHookShow Retourne la liste des

tâches Hook Switch intVecShow Retourne la table des

vecteurs d’interruption

Commandes d’affichage de l’état réseau.

Fonction Rôle Fonction Rôle

hostShow Retourne la table "Host" routestatShow Retourne les statistiques de

routage

icmpstatShow Retourne les statistiques

pour le protocole ICMP

« internet control

message protocol »

tcpstatShow Retourne les statistiques

pour le protocole TCP

ifShow Retourne l’interface

d’attachement du réseau tftpInfoShow Retourne les informations

d’état dur TFTP

inetstatShow Retourne toutes les

connexions actives pour

les sockets IP

udpstatShow Retourne les statistiques

pour le protocole UDP

ipstatShow Retourne les statistiques

pour le protocole IP

Remarque : Pour de plus amples renseignements sur ces fonctions il est préconisé d’utiliser l’aide

tornado (HelpManualsSubroutines).

Editions de commandes Shell

Le mode édition de WindShell utilise les commandes conviviales et on ne peut plus explicites de vi

d’UNIX. La commande h du shell affiche l’historique des commandes.

Quelques rappels à ce sujet !

Basic Control

h [size] Display shell history if no argument; otherwise set history buffer to size. ESC Switch to line-editing mode from regular input mode. ENTER Give line to shell and leave edit mode.

CTRL+D

Complete symbol or path name (edit mode), display synopsis of current symbol

(symbol must be complete, followed by a space), or end shell session (if the command

line is empty). [tab] Complete symbol or path name (edit mode). CTRL+H Delete a character (backspace). CTRL+U Delete entire line (edit mode). CTRL+L Redraw line (works in edit mode).

CTRL+S and

CTRL+Q . Suspend output, and resume output

CTRL+W Display HTML reference page for a routine.

Movement and Search Commands

nG Go to command number n.1

/s or ?s Search for string s backward in history, or forward. n Repeat last search.

nk or n- Get nth previous shell command.*

nj or n+ Get nth next shell command.*

nh Go left n characters (also CTRL+H).*

nl or Go right n characters.*

10 Système temps réel – Tornado2 Professeur : Michel MARIE

SPACE

nw or nW Go n words forward, or n large words. *2

ne or nE Go to end of the nth next word, or nth next large word. *

nb or nB Go back n words, or n large words.* $ Go to end of line.

0 or ^ Go to beginning of line, or first nonblank character.

fc or Fc Find character c, searching forward, or backward.

Insert and Change Commands

a or A ...ESC Append, or append at end of line (ESC ends input).

i or I ...ESC Insert, or insert at beginning of line (ESC ends input).

ns ...ESC Change n characters (ESC ends input).*

nc SPACE ...ESC Change n characters (ESC ends input).*

cw ...ESC Change word (ESC ends input).

cc or S ...ESC Change entire line (ESC ends input).

c$ or C ...ESC Change from cursor to end of line (ESC ends input).

c0 ...ESC Change from cursor to beginning of line (ESC ends input).

R ...ESC Type over characters (ESC ends input).

nrc Replace the following n characters with c.* ~ Toggle case, lower to upper or vice versa.

Delete Commands

nx Delete n characters starting at cursor.*

nX Delete n character to left of cursor.* dw Delete word. dd Delete entire line (also CTRL+U).

d$ or D Delete from cursor to end of line. d0 Delete from cursor to beginning of line.

Put and Undo Commands

p or P Put last deletion after cursor, or in front of cursor. u Undo last command.

1: The default value for n is 1.

2: words are separated by blanks or punctuation; large words are separated by blanks only.

Exécution d’une fonction utilisateur avec le Shell

Une fois le module dans lequel réside votre fonction construit sans erreur il faut le charger sur la

cible et le lier dynamiquement au noyau à partir du Shell : ld < filename.o. La commande

moduleShow permet de vérifier l’ensemble des modules présent sur la cible. On peut également le

vérifier à partir du Browser.

Pour supprimer un module et restituer la mémoire la commande unld filename.o est nécessaire.

Supposons à présent que le module utilisateur téléchargé contient une fonction appelée demo() qui

retourne un paramètre.

Deux méthodes sont alors envisageables pour exécuter cette fonction à partir du Shell :

Une première méthode consiste à exécuter la commande demo(). Le Shell est alors bloqué

jusqu’à ce que la fonction demo() retourne son paramètre, il l’affiche alors et rend la main, ceci

est perceptible par le retour du prompt.

La tâche en charge de l’exécution de la fonction demo() sera nommée tn.

Une seconde méthode consiste à exécuter la fonction demo() directement en spécifiant une

tâche à partir du Shell à l’aide de la commande sp(demo,…). La main est alors instantanément

rendue au Shell sans attendre la fin de la tâche activée ; les paramètres retournés sont perdus.

La tâche en charge de l’exécution de la fonction demo() sera nommée un.

11 Système temps réel – Tornado2 Professeur : Michel MARIE

Il peut également être intéressant de connaître la durée que nécessite l’exécution d’une tâche

particulière ; on dispose pour ceci des fonctions timex() et timexN().

- La commande timex( demo() ) retourne, si la précision du timer utilisé est suffisante par

rapport à la durée de la tâche demo(), la durée d’exécution en microsecondes de cette

tâche.

- La commande timexN( demo() ) retourne la durée moyenne d’exécution en

microsecondes de la tâche demo(), après avoir exécuté n fois cette tâche, n assurant une

précision sur la mesure meilleure que 2%.

Attention, si un module utilisateur comporte une fonction portant le même nom « nomCommande » qu’une fonction du Shell :

nomCommande active la fonction « Built-In » du Shell.

@nomCommande active la fonction utilisateur.

4. CrossWind

L’outil CrossWind est un « debugger » au niveau source dont l’intérêt principal est de positionner

des points d’arrêt dans le but de contrôler l’exécution d’un programme en visualisant dans des

fenêtres graphiques l’évolution de ses variables.

L’utilisation du debugger nécessite en première instance la création d’un projet ou l’ouverture d’un

projet existant au sein d’un espace de travail « workspace ». Un projet permet de :

Rassembler les fichiers d’une même application.

Grouper plusieurs projets au sein d’un espace de travail.

Personnaliser son noyau VxWorks

Ajouter des fonctions d’initialisation au noyau VxWorks

Définir des options de construction.

Construire des applications et des images du noyau VxWorks.

Télécharger des applications sur une cible VxWorks.

4.1. Quelques notions de terminologie

Application téléchargeable : Consiste en un ou plusieurs modules relogeables qui peuvent

être téléchargés et dynamiquement liés avec le noyau VxWorks.

Dans le cas où elle comporte plusieurs fichiers et modules, le

module est alors Nomdeprojet.out.

Application « bootable » : Consiste en une application liée à une image du noyau VxWorks.

L’application démarre alors lorsque le noyau a démarré.

Projet : Ensemble des fichiers source, des règles de construction, des

fichiers binaires utilisés pour créer une application téléchargeable,

une image du noyau ou une application « bootable ». Chaque projet

nécessite son propre répertoire.

Espace de travail «workspace » : Un espace de travail peut être considéré comme une « boîte »

de rangement pour un ou plusieurs projets, ceux-ci pouvant alors être

associés.

Composant : Consiste en une facilité Vxworks pouvant être inclue ou exclue de

l’image du noyau. De nombreux composants comportent des

paramètres qui peuvent être spécifiés.

12 Système temps réel – Tornado2 Professeur : Michel MARIE

4.2. Création d’un projet

Les commandes file New project et file Open Workspace permettent respectivement de

créer un projet ou d’ouvrir un espace de travail comportant au moins un projet précédemment

créé. Dans le premier cas la fenêtre suivante apparaît alors :

Si vous choisissez de créer une nouvelle application téléchargeable il vous est ensuite demandé

de préciser :

Le nom du projet

Son emplacement

Son espace de travail

Si vous voulez l’insérer dans un nouveau projet ou un projet existant

Le type de processeur que doit utiliser la chaîne de compilation

Si par exemple le projet créé est nommé application1 situé dans

D:\Tornado\target\proj\Application1 avec pour espace de travail Workspace0 et basé sur un

processeur MC68040 le projet créé apparaît alors comme ci-dessous :

Il est alors possible d’ajouter un fichier au projet par la commande File New en précisant dans la

fenêtre suivante le type de fichier et le projet dans lequel il doit être ajouté.

13 Système temps réel – Tornado2 Professeur : Michel MARIE

Si par contre vous choisissez de créer une image « bootable » du noyau VxWorks il vous est ensuite demandé de préciser :

Le nom du projet

Son emplacement

Son espace de travail

Si vous voulez baser l’image sur un BSP ou un projet existant

Si par exemple le projet créé est nommé image1 situé dans D:\Tornado\target\proj\image1 avec

pour espace de travail Workspace0 et basé sur le BSP BAB40 le projet créé apparaît alors comme

ci-dessous :

La rubrique VxWorks fait apparaître l’ensemble des composants de VxWorks, en caractères gras

s’ils sont inclus au noyau, en caractères « normaux » s’il sont exclus du noyau et en caractères

italiques s’ils ne sont pas utilisables avec le BSP utilisé. En sélectionnant la rubrique propriétés,

des informations sur le composant sont visualisables. Par exemple, en sélectionnant la rubrique

« BSP Memory configuration » on visualise ci-dessous le paramètre NV_RAM_SIZE indiquant

que la taille de la mémoire non volatile de la cible est de 0x0800 soit 2koctets.

14 Système temps réel – Tornado2 Professeur : Michel MARIE

4.3. Utilisation du « debugger »

Une fois que vous avez créé un projet, que vous lui avez ajouté au moins un fichier source et que

vous avez édité votre programme il faut le construire à l’aide de la commande Build, les

dépendances de votre application sont alors calculées puis une fenêtre de construction est ouverte

dans laquelle apparaissent les commandes de compilation et les éventuelles erreurs.

Si des erreurs apparaissent, un double clic sur celles-ci vous ouvre le fichier source en cause et

positionne le curseur sur la ligne de code erronée.

Lorsque plus aucune erreur ne subsiste, il reste à s’attacher à une cible « ToolsTarget server » et

à télécharger le module sur cette cible « ProjectDownload ».

L’ensemble de ces commandes peuvent également être réalisées à l’aide de la barre d’outils de

construction suivante :

Les boutons correspondent dans l’ordre de gauche à droite :

à la commande de construction,

à la commande de reconstruction totale,

à la commande de compilation,

à la commande de construction des dépendances,

à la commande d’arrêt de la construction,

à la commande de téléchargement.

Vous pouvez à présent activer le « debugger » par la commande de menu ToolsDebugger ou par

l’icône du « debugger » dans la barre d’outils du launcher précédemment présentée.

La barre d’outils du « debugger » présentée ci-dessous ou les commandes du menu Debug vous

permettront d’utiliser celui-ci pour tester une tâche.

Les boutons correspondent dans l’ordre de gauche à droite :

à la commande d’arrêt du « debugger »,

à la commande de démarrage d’une tâche,

à la commande de positionnement d’un point d’arrêt,

à la commande d’interruption du « debugger »,

à la commande de redémarrage du « debugger » jusqu’au prochain point d’arrêt,

à la commande d’exécution d’un pas (step in),

à la commande d’exécution d’un pas (step over), une fonction étant vue comme une

seule instruction,

à la commande d’exécution de la fonction en cours jusqu’à sa sortie (step out),

à la commande d’ouverture d’une fenêtre de visualisation de variables,

à la commande d’ouverture de la fenêtre de visualisation des variables locales,

à la commande d’ouverture de la fenêtre de visualisation des registres,

à la commande d’ouverture de la fenêtre de visualisation de l’état de la pile,

à la commande d’ouverture de la fenêtre de visualisation de la mémoire.

Si l’on désire tester la fonction progStart() écrite dans le fichier cobble.c il suffit, après avoir

téléchargé le module correspondant et activé le « debugger », d’activer la commande run du

« debugger ». La fenêtre suivante apparaît alors dans laquelle il faut préciser :

le nom de la fonction à tester ( point d’entrée de la tâche),

15 Système temps réel – Tornado2 Professeur : Michel MARIE

les arguments à passer à la fonction s’il y en a ( les arguments omis sont affectés par

zéro ),

si l’on désire qu’un point d’arrêt soit positionné à l’entrée de la tâche.

Le “debugger” ouvre alors le fichier source de la fonction à tester et positionne le point d’arrêt face

à la première instruction de la fonction.

Pour une utilisation plus large des points d’arrêt il est possible de les installer par la commande

« ProjectDownload ». La boîte de dialogue suivante apparaît dans laquelle il faut préciser le

point d’arrêt à l’aide de la syntaxe nom_de_fichier : numéro de ligne.

Il est également possible en activant le bouton “Advanced” de préciser des conditions d’arrêt. La

boîte de dialogue suivante permet de préciser le nombre de passages sur l’instruction avant arrêt ou

une condition sur une variable, l’arrêt sur l’instruction n’aura alors lieu que si la condition éditée est

vraie.

16 Système temps réel – Tornado2 Professeur : Michel MARIE

L’exemple suivant montre les fenêtres variables (avec visualisation de la variable structure

syncSemId), registres et mémoire (avec visualisation à partir de l’adresse 0x45eef90) ; la fenêtre de

commande du « debugger » se trouve également ouverte en bas de la recopie d’écran.

Attention : Il est seulement possible de « debugger » une tâche à la fois. Si plusieurs

tâches sont simultanément actives, il faut ouvrir une session de « debuggage » par tâche à

« debugger » et passer alternativement de l’une à l’autre à l’aide des commandes d’attachement

et de détachement.

(gdb) attach

(gdb) detach

On imagine bien que cela doit rapidement devenir inextricable !

L’ensemble des fonctions du « debugger » sont accessibles par la commande help, qui retourne

la liste des groupes de commandes.

5. Le « simulator »

Cet outil permet de tester vos applications sur une cible factice qui est en fait simulée sur la

machine host. La cible factice porte le nom vxsim, votre environnement de développement s’y

attache automatiquement lorsque vous démarrez le simulateur par l’icône appropriée ou la

commande de menu ToolsSimulator. Cependant les potentialités de cette cible factice

n’incorporent pas les outils réseau, SNMP, et Wind Foundation Classes.

Il est également possible d’obtenir une cible factice à l’image de votre cible réelle si le BSP le

permet.

Au démarrage du « simulator » la fenêtre suivante est affichée :

17 Système temps réel – Tornado2 Professeur : Michel MARIE

Lorque l’on valide ce choix, il est précisé que votre environnement doit s’attacher à la cible factice

par l’intermédiaire d’un “Target Server”.

Vous pouvez ensuite développer et tester vos applications sur cette cible factice comme sur une

cible réelle, ou presque !

6. Utilisation de « WindView »

6.1. Introduction

WindView est un outil graphique pouvant être considéré comme un analyseur logique pour système

multitâches, en l’occurrence VxWorks.

Il présente sous la forme de chronogrammes sur lesquels sont attachés des symboles, l’état des

tâches, la prise et la restitution de sémaphores, l’arrivée d’événements, l’arrivée d’interruptions, etc.

Pour chacun des événements visualisés, il est possible d’obtenir des renseignements tels que la

cause de l’événement, son contexte, l’instant d’arrivée, la priorité, etc.

De plus il est possible d’utiliser les facilités du « trigger » pour choisir une condition précise de

collecte des événements et pour spécifier la durée de l’acquisition.

6.2. Reconfigurer le noyau avec les outils « WindView »

Utiliser WindView avec le simulateur ne nécessite aucune configuration spécifique ; par contre,

pour pouvoir utiliser WindView avec une cible il faut disposer de l’outil optionnel de complèment

WindView et le noyau VxWorks doit être construit en lui incluant le composant WindView 2.0

instrumentation.

De plus, le BSP de la cible doit être pourvu d’un pilote de timer haute résolution timestamp.

En fonctionnement, l’agent WDB sur la cible se contente de remplir un buffer des événements avec

un minimum d’intrusions sur le système temps réel. Lorsque le buffer est plein, il est transféré à

l’application WindView sur le PC qui se chargera de mettre à jour la fenêtre graphique.

18 Système temps réel – Tornado2 Professeur : Michel MARIE

6.3. Utiliser WindView

Pour lancer WindView, il suffit de cliquer sur le dernier bouton de la barre d’outils du launcher ou

bien de passer par le menu, commande ToolsWindView.

La boîte de dialogue suivante apparaît :

Un choix doit être fait quant au mode de capture des événements, trois modes sont envisageables,

« context switch », « task state transition » et « additional instrumentation » :

Context Switch : dans ce mode WindView représente l’évolution du système en ne présentant que les changements de contexte, commutation de tâches, interruptions, préemption, etc. C’est

le mode de fonctionnement le plus simplifié.

Task State Transition : dans ce mode WindView ajoute aux informations précédentes les changements d’état des tâches et signale les objets qui en sont la cause (prise d’un sémaphore,

attente sur une queue de messages, etc.). Il est important de noter que dans ce mode, tout

événement qui ne cause pas une modification d’état des tâches n’est pas mentionné.

Additionnal instrumentation : c’est le plus complet des modes de fonctionnement de

WindView, toutes les informations sont collectées y compris celles qui ne modifient pas l’état

des tâches, il est alors possible de les filtrer en cochant les cases correspondant à

l’instrumentation désirée dans la fenêtre « collection configuration » précédente.

Exemple : La fenêtre suivante montre une fenêtre d’acquisition WindView en mode Additional instruments.

On distingue les tâches utilisateur tCosmos, tSchlep, tMonitor et tCrunch. Les autres tâches qui

apparaissent sont les tâches utilisées par le noyau, par exemple :

tWdbTask : Tâche de gestion de l’agent WDB.

tNetTask : Tâche de gestion du réseau.

tFtpdTask : Tâche de gestion du protocole client FTP

19 Système temps réel – Tornado2 Professeur : Michel MARIE

Il est alors possible en cochant l’option memLib d’obtenir des informations sur l’usage de la

mémoire. Pour les faire apparaître dans la fenêtre de visualisation il faut activer l’icône Analyse et

valider Memory usage. La fenêtre WindView est alors subdivisée pour faire apparaître l’usage de

la mémoire comme dans la figure ci-dessous.

Il est possible de faire apparaître une fenêtre de renseignements sur l’événement séléctionné par un

clic souris, l’exemple présenté correspond à l’activation d’un delai de 4 tics sur la tâche tCosmos.

Légende des symboles utilisés par WindView.

Quelques uns symboles rencontrées dans WindView sont présentés ci-dessous, pour les autres

consulter la rubrique d’aide Help WindView Help.

7. Le « Trigger »

Le trigger permet de détecter un événement ou une combinaison d’événements qui conditionnera

une action pouvant être le démarrage d’une acquisition Windview, son arrêt ou l’appel d’une

fonction. Le "Trigger" est activé à partir de la commande de menu

Tools Triggering ou à partir de l’icône associée.

Lors d’un démarrage du “Trigger” la fenêtre suivante est affichée

20 Système temps réel – Tornado2 Professeur : Michel MARIE

L’icône de gauche de la barre d’outils "trigger" permet de configurer les événements à détecter et

les actions associées à l’aide de la fenêtre présentée ci-dessous :

L’exemple ci-dessous correspond à l’activation de deux événements trigger qui permettront de

démarrer WindView lorsque la condition sur la variable vxTicks>1000 sera réalisée et de stopper

WindView lorsque vxTicks>1500.

Trigger 0 : Trigger 1 :

21 Système temps réel – Tornado2 Professeur : Michel MARIE

Temps réel multitâches

1. Introduction.

Le temps réel caractèrise un système pour lequel le temps de réponse peut être contrôlé. Un tel

système est dit déterministe. Le temps écoulé entre l’arrivée d’un événement et la réponse associée

est appelé latence.

Pour satisfaire ces conditions un noyau temps réel dispose de fonctionnalités permettant de faire

transiter les tâches entre différents états possibles, afin d'attribuer au mieux l'usage du processeur et

des ressources.

Différents états possibles d’une tâche.

Execution

Prêt

RetardéeAttente

Suspendue

Attente : tâche en attente d’une ressource non disponible.

Retardée : tâche en attente d’expiration d’un délai.

Suspendue : tâche suspendue pour une durée indéterminée.

Prêt : tâche dans la file d’attente du processeur par ordre de priorités puis d'arrivée.

Exécution : tâche disposant du processeur.

2. Fonctionnement de l’ordonnanceur.

Pour basculer une nouvelle tâche en exécution, le noyau doit :

- Sauvegarder le contexte de la tâche en cours d’exécution dans la structure TCB de celle-ci.

- Restaurer le contexte de la nouvelle tâche à exécuter à partir de sa structure TCB.

La structure TCB (Task Control Block) est définie par la structure de données WIND_TCB dans le

fichier taskLib.h. Elle contient les informations sur le contexte CPU, pc, sp, registres cpu, registres

fpu ainsi que sur la tâche, priorité, flags, etc…

Le noyau gère une file particulière pour chacun des états possibles des tâches.

22 Système temps réel – Tornado2 Professeur : Michel MARIE

Noyau

TCB TCBTCB

TCBTCB TCB CPU

Suspendues Prêtes Exécution

En attente Retardées

TCB

Il y a ordonnancement si :

- La tâche en exécution passe dans l’état attente, retardée ou suspendue.

- Une tâche de plus haute priorité passe dans l’état prêt ( préemption ).

- Ecoulement du time-slice si au moins une autre tâche de même priorité est prête.

Les priorités.

La priorité d’une tâche est codée sur un octet :

- 0 = priorité maximale

- 255 = priorité minimale

- 100 = priorité par défaut

VxWorks n’implémente pas la gestion dynamique des priorités. Si une tâche A n’est jamais bloquée

ou en attente ou retardée, alors une tâche B moins prioritaire ne sera jamais exécutée.

Si plusieurs tâches sont de même priorité, il est alors possible de faire fonctionner l’ordonnanceur

en mode “round robin” entre celles-ci. ( ordonnancement par priorités avec files multiples ).

3. Quelques fonctions usuelles.

Ordonnancement.

- int sysClkRateGet() Retourne la fréquence de l’horloge système en Hz, par défaut

60 Hz, soit un “tick” de 16.7 ms.

- STATUS sysClkRateSet(int tps) Fixe la fréquence d’horloge système en Hz.

- STATUS kernelTimeSlice(int ticks) Fixe le time slice en ticks ; si 0, le mode round robin

est dévalidé.

Création d’une tâche à l'état prêt.

- int = taskSpawn( char*nom , int priorité , int options , int pile , FUNCPTR entree,

int arg1,…, int arg10)

Options (les principales) :

VX_UNBREAKABLE (0x2)

VX_FP_TASK (0x8)

VX_NO_STACK_FILL (0x100)

VX_PRIVATE_ENV (0x80)

Création d’une tâche à l'état suspendue.

- STATUS = taskInit( WIND_TCB* ptcb, char* name , int priorité , int options,

23 Système temps réel – Tornado2 Professeur : Michel MARIE

char* pstack , int stacksize, FUNCPTR entree, int arg1,…, int arg10)

Activation d’une tâche créée avec taskInit.

- STATUS taskActivate(int TID)

Suppression d’une tâche.

- STATUS taskDelete(int TID) Supprime la tâche et désalloue le TCB et la pile.

- exit() Supprime la dernière tâche activée et désalloue le TCB et la pile.

- STATUS taskSafe() Protège la tâche en cours contre toute suppression.

- STATUS taskUnSafe() Enlève la précédente protection.

Identification d’une tâche.

- int taskIdSelf() Retourne le TID d’une tâche en cours d’exécution.

- int taskIdListGet(int idlist[], int Nmax) Retourne la liste des TID des tâches en cours.

- STATUS taskIdVerify(int TID) Vérifie si le TID spécifié est valide.

- char* taskName(int TID) Retourne le nom à partir du TID.

- int taskNameToId(char* name) Inverse de taskName.

- STATUS taskShow(int TID, int level) Informations sur la tâche (niveau 0, 1 ou 2).

Modification dynamique des priorités.

- STATUS taskPriorityGet(int TID, int * pprio) Retourne la priorité de la tâche.

- STATUS taskPrioritySet(int TID , int prio) Modifie la priorité de la tâche.

Contrôle des tâches.

- STATUS taskRestart(int TID) La tâche est stoppée puis relancée avec les

mêmes arguments.

- STATUS taskSuspend(int TID) La tâche est suspendue.

- STATUS taskResume(int TID) La tâche est restaurée.

- STATUS taskDelay(int ticks) La tâche est retardée pour n ticks.

- ULONG tickGet() Retourne l’état courant du compteur de ticks.

- tickSet(ULONG val) Positionne le compteur de tics.

Fonctions additionnelles de contrôle des tâches.

- STATUS taskCreateHookAdd(FUNCPTR func) Ajoute une fonction qui est appelée

à chaque création d’une tâche.

- STATUS taskCreateHookDelete(FUNCPTR func) Supprime la précédente fonction.

- STATUS taskSwitchHookAdd(FUNCPTR func) Ajoute une fonction qui est appelée

à chaque commutation de tâche.

- STATUS taskSwitchHookDelete(FUNCPTR func) Supprime la précédente fonction.

- STATUS taskDeleteHookAdd(FUNCPTR func) Ajoute une fonction qui est appelée

à chaque suppression d’une tâche.

- STATUS taskDeleteHookDelete(FUNCPTR func) Supprime la précédente fonction.

24 Système temps réel – Tornado2 Professeur : Michel MARIE

Les sémaphores

1. Introduction.

Le noyau temps réel VxWorks met à notre disposition 3 types de sémaphores:

Le sémaphore binaire utilisé pour la synchronisation.

Le sémaphore MUTEX utilisé pour l’exclusion mutuelle.

Le sémaphore à compte, d’usage moins courant, utilisé par exemple pour établir un rendez-vous.

2. Le sémaphore binaire et la synchronisation.

Une tâche, pour s’exécuter peut avoir besoin d’attendre qu’un événement survienne. La solution

consiste alors à créer un sémaphore binaire. Le sémaphore sera :

- plein si l’événement est survenu.

- vide autrement.

La tâche à synchroniser appelle semTake(), prend le sémaphore et se bloque jusqu’à ce que celui-ci

soit libéré par semGive(). La tâche ou l’interruption qui détecte l’événement appelle semGive() ce

qui libère la tâche bloquée.

Création d’un sémaphore binaire.

SEM_ID = semBCreate( int option , SEM_B_STATE valInit )

Option : ( déclarées dans semLib.h )

- SEM_Q_PRIORITY (1)

- SEM_Q_FIFO (0)

Valeur initiale :

- SEM_FULL ( 1 )

- SEM_EMPTY ( 0 )

Pour la synchronisation, le sémaphore binaire est typiquement initialisé à 0.

Prise d’un sémaphore binaire.

STATUS = semTake( SEM_ID semId , int timeOut )

Time out = temps maximum d’attente sur le sémaphore, en ticks.

- WAIT_FOREVER (-1)

- NO_WAIT (0)

Tâche en attente

jusqu'à sémaphore

donné ou time out

Tâche libérée

semTake()

retourne ERROR

Tâche libérée

semTake()

retourne OK

La tâche continue

semTake()

retourne OK

sémaphoreplein

time out

oui sémaphore donné

non

25 Système temps réel – Tornado2 Professeur : Michel MARIE

Libération d’un sémaphore binaire.

STATUS = semGive( SEM_ID semId )

Libère une des tâches en attente sur le sémaphore. Le sémaphore reste vide (0).

S’il n’y a pas de tâche en attente, le sémaphore est plein (1).

Le sémaphore

devient plein

La tâche en tête de

file d'attente devient

active, le sémaphore

reste vide

tâcheen attente

oui

non

Synchronisation de plusieurs tâches.

STATUS = semFlush( SEM_ID semId )

Libère toutes les tâches en attente sur le sémaphore.

N’affecte pas l’état du sémaphore.

Suppression d’un sémaphore binaire.

STATUS = semDelete( SEM_ID semId )

Débloque toutes les tâches en attente sur le sémaphore et détruit celui-ci.

3. Le sémaphore MUTEX pour l’exclusion mutuelle.

Le sémaphore MUTEX est nécessaire pour protéger l’accès exclusif à une ressource convoitée par

plusieurs tâches.

Contrairement au sémaphore binaire, le sémaphore MUTEX est systèmatiquement initialisé à plein

(1).

Toute tâche voulant accéder à la section protégée devra :

- Prendre le sémaphore.

- Accéder à la section critique ( la plus courte possible )

- Donner le sémaphore.

Création d’un sémaphore MUTEX.

SEM_ID = semMCreate( int options )

Options : ( déclarées dans semLib.h )

- SEM_Q_PRIORITY (1)

- SEM_Q_FIFO (0)

- SEM_DELETE_SAFE (4)

- SEM_INVERSION_SAFE (8)

Remarques :

- Ce sémaphore ne peut pas être utilisé dans une fonction interruption.

- Les options SEM_Q_FIFO et SEM_INVERSION_SAFE sont incompatibles.

- Une tâche qui prend ce sémaphore en devient le propriétaire, elle seule pourra le rendre.

- Une même tâche peut prendre ce sémaphore plusieurs fois, elle devra le restituer d’autant.

L’exemple ci-dessous présente l’intérêt de la validation de l’option SEM_INVERSION_SAFE

lorsque une tâche de faible priorité et une tâche de haute priorité accédent à une même ressource

partagée alors qu’une tâche au moins de priorité intermédiaire devient prète.

26 Système temps réel – Tornado2 Professeur : Michel MARIE

Sans option "inversion de priorité"

Avec option "inversion de priorité"

t1

t1

t2

t2

t3

t3

faible priorité

moyenne priorité

haute priorité

L’exemple ci-dessous présente l’intérêt de l’option SEM_DELETE_SAFE dans le cas de la

suppression d’une tâche propriétaire d’un sémaphore MUTEX. Les 3 tâches présentées ont la même

priorité.

t1

t2

t3

t1

t2

t3

Sans option "protection d'annulation"

Avec option "protection d'annulation"

taskDelete(t1)

taskDelete(t1)

27 Système temps réel – Tornado2 Professeur : Michel MARIE

Prise d’un sémaphore MUTEX.

STATUS = semTake( SEM_ID semId , int timeOut )

Tâche en attente

jusqu'à semaphore

donné ou time out

La tâche continue

semTake() retourne OK

Le compteur du

propriétaire est

incrémenté

La tâche continue

semTake()

retourne OK

Elle en devient

propriétaire

Propriétairedu sémaphore

Cette tâchepersonne

une autre tâche

Libération d’un sémaphore MUTEX.

STATUS = semGive( SEM_ID semId )

Le sémaphore

devient

plein (1)

Décrémentation

du compteur

propriètaire

semGive()

retourne ERROR

compteurpropriètaire

non

aucun

un

La tâche en tête

de file devient active

Elle devient propriétaire

Tâche

en attente

>1 oui

Il est toutefois possible de rendre un sémaphore MUTEX sans se soucier d’en être le propriétaire à

l’aide de la fonction semMGiveForce(). On doit généralement se limiter à l’utiliser pour la mise au

point d’applications.

STATUS = semMGiveForce( SEM_ID semId )

Suppression d’un sémaphore MUTEX.

STATUS = semDelete( SEM_ID semId )

28 Système temps réel – Tornado2 Professeur : Michel MARIE

4. Le sémaphore à compte.

- Le sémaphore à compte diffère du sémaphore binaire par la possibilité d’avoir une valeur

initiale supérieure à 1. Pour le reste il fait appel aux mêmes mécanismes et utilise les mêmes

fonctions, semTake(), semGive() et semDelete().

Création d’un sémaphore à compte.

SEM_ID = semCCreate( int option , int valeurInitiale )

Option :

- SEM_Q_PRIORITY

- SEM_Q_FIFO

5. Liste des tâches en attente sur un sémaphore.

int = semInfo( SEM_ID semId, int List[] , int nmax )

6. Le blocage de l’ordonnanceur.

Si l’action sur une ressource partagée nécessite peu de temps et doit se répéter souvent il peut être

préférable de bloquer l’ordonnanceur plutôt que d’utiliser un sémaphore. On dispose pour cela des

fonctions taskLock() et taskUnlock().

STATUS = taskLock() : bloque l’ordonnanceur.

STATUS = taskUnlock() : redémarre l’ordonnanceur.

Heureusement, si la tâche se bloque l’ordonnanceur est automatiquement redémarré.

Attention : Le blocage de l’ordonnanceur n’interrompt pas les interruptions, aussi il ne faut

pas que l’une d’entre elle puisse accéder à la même ressource partagée. Si cela est le cas il peut être

envisagé de bloquer les interruptions jusqu’à un certain niveau de priorité.

Dévalider les interruptions.

int = intLock ()

La fonction retourne une clé qui devra être passée à la fonction de déblocage des interruptions.

Restaurer les interruptions.

intUnlock ( int lockkey )

Positionner le niveau des interruptions bloquées ou restaurées par les fonctions

précédentes.

intLockLevelSet ( int newlevel)

Il est possible de lire la position de ce masque par la fonction intLockLevelGet().

29 Système temps réel – Tornado2 Professeur : Michel MARIE

Communications inter-tâches

1. Introduction.

Les systèmes multi-tâches nécessitent des outils de communication inter-tâches. Le noyau VxWorks

dispose pour ceci de bibliothèques implémentant deux types de solution :

l’usage de mémoire partagée (listes chaînées et buffer circulaires),

le passage par messages (files de messages et tubes standards).

2. L’usage de mémoire partagée (bibliothèque lstLib.h).

Ceci nécessite l’écriture d’une librairie de fonctions pour accéder à une structure de données.

Les données doivent être protégées par sémaphores.

Le noyau VxWorks met à disposition 2 librairies pour manipuler les structures de données

communes ; les listes chainées et les buffers circulaires.

La librairie lstLib contient les fonctions de manipulation des listes doublement chainées.

Suivant->

<-Précédent

Donnéesutilisateur

Suivant->

<-Précédent

Donnéesutilisateur

Premier->

Dernier->

Nombre = 2

NULL

NULL

Descripteur de liste

Elément n°1De la liste

Elément n°2De la liste

Attention, l’exclusion mutuelle et la synchronisation ne sont pas gérées par ces fonctions.

La librairie rngLib contient les fonctions de manipulation des buffers circulaires.

Buffercirculaire

m1 m2 m3

Pointeur d’écriture

Pointeur de lecture

Tâche lecteur Tâche rédacteur

Attention, la synchronisation et l’exclusion mutuelle s’il y a plus d’un lecteur/rédacteur ne sont

pas gérées par ces fonctions.

3. Le passage de messages.

VxWorks utilise les files de messages et les tubes de communication pour l’échange de messages

inter-tâches.

Ces fonctionnalités intégrent implicitement :

un buffer de type FIFO,

des mécanismes de synchronisation,

30 Système temps réel – Tornado2 Professeur : Michel MARIE

des mécanismes d’exclusion mutuelle.

Ces procédés sont conseillés car plus robustes que les mémoires partagées, celles-ci étant plutôt

réservées aux échanges inter-processeurs.

Ils peuvent être utilisés entre tâches ou entre une tâche et une routine d’interruption.

3.1. Les files de messages.

Tâche lecteurTâche rédacteur

File de messages

Sens de circulation des messages

m1m2m3

Buffer FIFO acceptant des messages de longueur variable

Créer une file de messages.

MSG_Q_ID = msgQCreate (int nbr_max_mes, int lg_max_mes,int option)

Option :

MSG_Q_FIFO

MSG_Q_PRIORITY

Envoyer un message.

STATUS = msgQSend (MSG_Q_ID msgQId, char* pbuffer, UINT nbr_bytes,

int timeOut, int priorité )

TimeOut est le temps d’attente maximum en ticks, si la file est pleine.

WAIT_FOREVER

NO_WAIT

Priorité permet à un message urgent de se retrouver en tête de file.

MSG_PRI_URGENT

MSG_PRI_NORMAL

Recevoir un message.

int = msgQReceive (MSG_Q_ID msgQId, char* pbuffer,

UINT nbr_bytes_max, int timeOut )

Nbr_bytes_max est le nombre maximum d’octets à lire d’un message. Les octets non lus sont

perdus.

Time_out est le temps d’attente maximum en ticks, si la file est vide.

WAIT_FOREVER

NO_WAIT

Supprimer une file de messages.

STATUS = msgQDelete (MSG_Q_ID msgQId)

Les tâches en attente sur la file sont libérées, msgQSend() et msgQReceive() retournent

"ERROR".

31 Système temps réel – Tornado2 Professeur : Michel MARIE

3.2. Les tubes de communication “pipes”.

Les tubes constituent un circuit virtuel d’entrée/sortie géré par un pilote "pipeDrv".

L’avantage sur les files de messages est par conséquent l’utilisation d’un système d’interface

standard (read/write ; open/close ; create/remove ; ioctl).

Créer un tube de communication.

STATUS = pipeDevCreate ( char* nom, int nbr_mes, int nbr_bytes )

Par convention, le nom d’un tube de communication s’écrit : /pipe/monpipe

Remarque : La commande du shell "devs" permet de lister les tubes créés.

Lire et écrire dans un tube de communication.

Il faut tout d’abord ouvrir le tube de communication avec la fonction open, celle-ci retourne un

descripteur de fichier qui sera utilisé pour tous les accès à ce tube.

Fd = open ( char* name, int flags, int mode )

Les flags sont associables par un OU logique :

O_RDONLY (0)

O_WRONLY (1)

O_RDWR (2)

O_CREAT (0x200)

Le mode n’existe que pour les drivers NFS, autrement il ne doit pas apparaître où 0.

Une fois le tube ouvert, la lecture et l’écriture utilisent les fonctions standards read()/write(). De

même le contrôle du tube se fera à l'aide de la fonction standard de configuration et de contrôle

ioctl().

Exemples :

Lire la taille du premier message du tube :

status = ioctl (fd, FIONREAD, &nBytesUnread);

Lire le nombre de messages disponibles dans le tube :

status = ioctl (fd, FIONMSGS, &nMessages);

Vider le tube de tous ses messages :

status = ioctl (fd, FIOFLUSH, 0);

Supprimer un tube de communication.

La suppression d’un tube de communication se fait en associant les fonctions suivantes :

char* tube =(char*)malloc(50);

strcpy( tube, "/monTube");

iosDevDelete ( iosDevFind ( tube,*tube ) )

3.4. Comparaisons queues de messages et tubes de communication “pipes”.

Avantages des queues de messages :

simplicité de positionnement d'un time_out,

gestion de messages urgents,

plus rapide.

Avantages des tubes de communication :

Utilise les fonctions d’entrée/sortie standards (open(), close(), read(), write(), ioctl).

Possibilité de rediriger la sortie à l’aide des fonctions ioTaskStdSet() et

ioGlobalStdSet().

32 Système temps réel – Tornado2 Professeur : Michel MARIE

Gestion des attentes multiples

Rappel sur les descripteurs de fichier :

Sur un système ANSI, les circuits ouverts sont référencés par un descripteur de fichier, fd. Ce

descripteur est un entier court retourné par les primitives open() ou creat() et utilisé par les autres

primitives pour spécifier le fichier visé.

A la fermeture du fichier, le descripteur est désalloué.

Trois descripteurs de fichiers sont réservés et ont une acception spécifique :

- 0 = entrée standard (clavier, port série,…),

- 1 = sortie standard (écran, port série sur terminal,…),

- 2 = sortie d’erreur standard (écran, fichier,…).

Il est possible de rediriger globalement l’un ou l’autre des descripteurs de fichiers à l’aide de la

fonction ioGlobalStdSet().

Par exemple, la commande suivante redirige la sortie standard vers un fichier ouvert de descripteur

fd_file :

ioGlobalStdSet ( 1 , fd_file )

Cette redirection peut également être opérée localement à une tâche à l’aide de la fonction

ioTaskStdSet().

Par exemple, la commande suivante redirige la sortie standard vers un fichier ouvert de descripteur

fd_file vis-à-vis de la tâche qui l’exécute ; les autres tâches ne sont pas affectées par cette

redirection :

ioTaskStdSet ( 1 , fd_file )

1. Attente sur plusieurs descripteurs de fichiers.

Les facilités apportées par la primitive select() de la librairie selectLib nous donne une méthode

d’attente sur plusieurs descripteurs de fichiers ; cette primitive ANSI est compatible avec les

systèmes Windows et UNIX.

La librairie selectLib permet entre autres :

de bloquer une tâche en attente sur plusieurs circuits,

de donner à un pilote la possibilité de détecter les tâches qui sont bloquées en attente d’une entrée/sortie sur le circuit,

de spécifier un time-out relatif à l’attente d’une tâche sur un circuit.

Fonction d'attente sur plusieurs descripteurs

int select

(

int width, /* nombre de bits à examiner dans la structure fd_set */

fd_set *pReadFds, /* structure fd_set de lecture */

fd_set *pWriteFds, /* structure fd_set d’écriture */

fd_set *pExceptFds, /* (non supporté, compatibilité UNIX) */

struct timeval *pTimeOut /* temps d’attente maximum, NULL = infini */

)

Cette fonction réalise la mise en attente de la tâche qui l’exécute jusqu’à ce qu’un des descripteurs

de fichier spécifié soit prêt.

33 Système temps réel – Tornado2 Professeur : Michel MARIE

La structure fd_set utilisée par select() est en fait un tableau de bits ou le bit d’indice n correspond

au descripteur de fichier n. Selon que l’on désire un accès en lecture et/ou en écriture on initialisera

les bits de la structure fd_set pointée par pReadFds et/ou par pWriteFds.

L’argument width doit correspondre à l’indice du plus grand des bits à tester de l’ensemble des

structures fd_set augmenté de un.

La structure timeval définie dans le fichier times.h est utilisée pour positionner un time-out lors

d’une attente en lecture ou en écriture par select().

struct timeval

{

long tv_sec; /* délai du time-out en secondes */

long tv_usec; /* délai du time-out en microsecondes */

};

La fonction select() retourne un entier dont la valeur correspond à la somme des indices des

descripteurs de fichiers prêts, ou "0" si la sortie se fait par time_out, ou -1 (ERROR) si l’exécution

de select a donné lieu à une erreur.

De plus, dans les structures fd_set passées à la fonction, seul les bits pour lesquels les descripteurs

sont prêts restent marqués à 1 après la sortie du select.

Les "macros fonctions" suivantes permettent de positionner les bits de la structure fd_set :

FD_SET ( fd, fd_set*)

FD_CLR ( fd, fd_set*)

FD_ZERO ( fd_set*)

La "macro fonction" suivante permet de tester un bit de la structure fd_set :

int FD_ISSET ( fd, fd_set*)

Exemple d’utilisation de select() pour gérer une attente en lecture sur plusieurs

descripteurs de fichier.

Fonction select :

Soit la création de deux tubes de communication ouverts en lecture/écriture :

/* Création des tubes de communication /*

pipeDevCreate(/pipe/1, 10, 100) ;

pipeDevCreate(/pipe/2, 10, 100) ;

/* Ouverture des tubes en lecture et écriture /*

fd1 = open (/pipe/1, O_RDWR, 0) ;

fd2 = open (/pipe/2, O_RDWR, 0) ;

On désire à présent bloquer une tâche en attente de lecture sur les deux tubes précédemment

ouverts. Pour cela il est nécessaire de positionner à 1, dans une structure de type fd_set, les bits

correspondant aux descripteurs de fichier des tubes précités. On utilise alors les "macros fonctions"

inclues dans la librairie selectLib permettant de manipuler les bits de la structure fd_set.

34 Système temps réel – Tornado2 Professeur : Michel MARIE

/* Mise à 1 des bits de la structure fd_set */

fd_set fdSet ;

int width ;

int result ;

char buffer1[100] ;

char buffer2[100] ;

FD_ZERO ( &fdSet ) ;

FD_SET ( fd1 , &fdSet ) ;

FD_SET ( fd2 , &fdSet ) ;

width = ( fd1 > fd2 ) ? fd1 : fd2 ;

width++ ;

Ensuite, la fonction select() se bloque jusqu’à ce qu’ un des descripteurs testés, au moins, soit prêt.

result = select( width, &fdSet, 0, 0, 0) ;

Lorsque la tâche précédente se termine, il suffit de tester les bits de la structure fdSet pour connaître

le ou les descripteur(s) de fichier actif(s).

if ( FD_ISSET ( fd1, &fdSet )>0)

{

read ( fd1, buffer1 , 100 ) ;

printf( buffer1);

}

if ( FD_ISSET ( fd2, &fdSet )>0 )

{

read ( fd2, buffer2 , 100) ;

printf( buffer2);

}

35 Système temps réel – Tornado2 Professeur : Michel MARIE

Exceptions, interruptions et timers

1. Introduction.

Un signal est d'origine interne (une exception) ou externe (une interruption). Il est émis vers une

tâche indiquant qu’un événement asynchrone est survenu.

Exception : signal d’origine interne au système, généralement lié à la détection d’une erreur

grave d’exécution. (division par zéro, accès mémoire interdit, etc…).

Interruption : signal d’origine externe au système, signalant la nécessité de réaliser une

« tâche immédiate ». (action clavier, action sur un capteur, etc…).

Les Timers : cas particulier d’un signal d’interruption émis périodiquement pour activer

une tâche. (ordonnanceur du noyau temps réel par exemple).

VxWorks dispose de 31 signaux de type exception, chacun représentant un événement particulier.

Une tâche peut attacher une capture de signal “signal handler” pour réaliser une action particulière

lorsque un événement survient. Après exécution de cette action la tâche interrompue est reprise

comme s’il ne s’était rien passé.

Fonction "normale"

{

}

Fonction "signalHandler"

{

}

signal

2. Positionner un “signal handler”.

void* signal ( int num_signal, void* handler )

num_signal : numéro du signal à capturer ( consulter sigLib.h et signal.h )

handler : fonction à invoquer lorsque le signal est capturé.

SIG_IGN si le signal doit être ignoré, SIG_DFL pour la fonction

"handler" par défaut.

Le “signal handler” doit être, au minimum déclaré comme suit :

void sigHandler (int sig )

En fait, les paramètres passés au “signal handler” sont au nombre de trois, pour accéder à ces

paramètres additionnels déclarer le “signal handler” comme suit :

void sigHandler (int sig , int code , struct sigcontext *pSigCtx )

L’argument code permet de distinguer plusieurs exceptions qui donneraient lieu au même signal.

Les codes sont répertoriés dans le fichier sigCodes.h.

L’argument pSigCtx pointe sur une structure où se trouve sauvegardé le contexte de la tâche lors de

la réception du signal.

Signal et exceptions.

Toutes les exceptions logicielles donnent lieu à un signal. Si lors d’une exception le signal est

capturé par un “signal handler”, la fonction attachée devra faire en sorte de “renflouer” la tâche

origine de l’exception.

36 Système temps réel – Tornado2 Professeur : Michel MARIE

Si le signal n’est pas capturé VxWorks suspend la tâche et retourne un message d’erreur sur la

console.

La tâche a installé

la capture du signal

SIGSEGV ?

Fonction "normale"

{

}

La tâche est suspendue

génération d'un "Log error message"Le signal

est renfloué

Typiquement une fonction de capture d’un signal d’exception appelle :

exit() : Pour terminer la tâche.

taskRestart() : Pour redémarrer la tâche.

longjmp() : Pour reprendre l’exécution de la tâche à un endroit sauvegardé

par setjmp().

3. Configurer un signal d’interruption.

Une interruption permet à des circuits périphériques de notifier au CPU qu’un événement extérieur

est survenu.

Une fonction définie par l’utilisateur peut être installée afin de s’exécuter lorsque cet événement

arrive. Cette fonction s’exécute dès réception de l’événement, elle préempte toute tâche quelle que

soit sa priorité, ce n’est pas une tâche logicielle mais une tâche immédiate.

Les fonctions qui permettent à l’utilisateur d’installer et de gérer ses propres fonctions

d’interruption se trouvent dans les librairies intLib.h et intArchLib.h.

Le principe reste identique à l’installation d’un “signal handler” d’exception, la fonction attachée au

“signal handler” se chargeant après sauvegarde des registres du CPU d’appeler une fonction de

traitement.

Le “signal handler” d’interruption peut être installé avec la fonction intConnect().

Remarque : Suivant le CPU de la cible, la pile utilisée par les interruptions est soit une pile dédiée,

soit la pile de la tâche interrompue. Dans ce second cas, si le risque existe il est nécessaire de

prévoir une pile des tâches en conséquence.

Pour le 68040, la pile des interruptions est une pile dédiée, celle-ci est controlée par

INT_STACK_SIZE dans le fichier configAll.h.

Fonctions de la librairie intLib : BOOL intContext (void)

Cette fonction retourne TRUE si le contexte d'exécution courant est le mode "interruption"

et FALSE si c'est le mode "tache".

int intCount (void)

Cette fonction retourne le nombre d'interruptions qui sont en attente de traitement.

Quelques fonctions de la librairie intArchLib : int intLevelSet( int level )

Cette fonction modifie le masque des interruptions dans le registre d'état du processeur SR.

La valeur retournée est le niveau initial du masque.

int intEnable (int level )

37 Système temps réel – Tornado2 Professeur : Michel MARIE

Cette fonction valide les interruptions pour le niveau précisé. La valeur retournée est soit

OK ou ERROR ou encore le contenu du status register selon le processeur utilisé.

int intDisable ( int level )

Cette fonction dévalide les interruptions pour le niveau précisé. La valeur retournée est soit

OK ou ERROR ou encore le contenu du status register selon le processeur utilisé.

int intCRGet (void)

Cette fonction retourne le contenu du registre des causes des interruptions.

void intCRSet(int value )

Cette fonction positionne le contenu du registre des causes des interruptions.

int intSRGet (void)

Cette fonction retourne le contenu du registre d'état du processeur "SR = Status Register".

int intSRSet ( int value )

Cette fonction positionne le contenu du registre d'état du processeur et retourne sa

précédente valeur.

STATUS intConnect

(

VOIDFUNCPTR * vector, /* adresse du vecteur */

VOIDFUNCPTR routine, /* adresse fonction d'IT */

int parameter /* paramètre passé à la fonction d'IT */

)

Cette fonction attache une fonction d'interruption à un vecteur d'interruption. FUNCPTR intHandlerCreate

(

FUNCPTR routine, /* Fonction attachée */

int parameter /* paramètre passé à la fonction */

)

Cette fonction construit un lien vers une fonction qui doit ensuite être attachée à une

interruption par intVecSet(). Elle retourne un pointeur vers le lien créé ou NULL si le lien

n'est pas réalisable.

Remarque : Cette fonction ainsi que intVecSet() et intVecBaseGet() sont utilisées en

interne par intConnect().

void intVecBaseSet

(

FUNCPTR *baseAddr /*Adresse de base de la table des vecteurs*/

)

Cette fonction positionne l'adresse de base de la table des vecteurs. Cette valeur est utilisée

par les fonctions intVecSet() et intVecGet().

FUNCPTR *intVecBaseGet (void)

Cette fonction retourne l'adresse de base de la table des vecteurs.

void intVecSet

(

FUNCPTR * vector, /* offset dans la table des vecteurs */

FUNCPTR function /* addresse à placer dans le vecteur */

)

Cette fonction place un vecteur dans la table en spécifiant son offset.

FUNCPTR intVecGet

(

FUNCPTR * vector /* offset dans la table des vecteurs */

)

Cette fonction retourne l'adresse dans la table des vecteurs en spécifiant son offset.

38 Système temps réel – Tornado2 Professeur : Michel MARIE

Macro procédures pour le traitement des vecteurs d'interruption :

IVEC_TO_INUM(int Vector)

Convertit l'adresse correspondante à un vecteur en son numéro de vecteur.

INUM_TO_IVEC(int Number)

Convertit un numéro de vecteur en l'adresse correspondante.

TRAPNUM_TO_IVEC( int trapNumber)

Convertit un numéro de vecteur TRAP en l'adresse correspondante.

Exemple :

Exemple de connection d'un vecteur d'IT unique entre plusieurs fonctions.

vector = INUM_TO_IVEC(some_int_vec_num);

oldfunc = intVecGet (vector);

newfunc = intHandlerCreate (routine, parameter);

intVecSet (vector, newfunc); /* nouvelle fonction d'IT */

...

intVecSet (vector, oldfunc); /*utilise la fonction initiale*/

...

intVecSet (vector, newfunc); /* reconnecte à la nouvelle

fonction */

4. Restrictions sur les interruptions.

Les fonctions d’interruptions sont restrictives quant aux facilités de VxWorks, en particulier :

Une interruption ne peut pas appeler semTake().

Une interruption de peut pas utiliser malloc().

Une interruption ne peut pas utiliser les fonctions standard d’entrée/sortie système (printf(), etc…).

La seule fonction d’entrée/sortie autorisée sous interruption est write().

Cas particulier : Si un signal d’exception survient au cours d’une interruption cela génére un

redémarrage “à chaud” du noyau VxWorks.

5. Timers et watchdog timers.

Les timers sont utiles pour :

Forcer des programmes utilisateur à être exécutés périodiquement : - Scrutation matérielle.

- Chien de garde pour sortie d’une opération interminable.

VxWorks contient des fonctions d’interface visant à gérer deux timers :

- Un basé sur l’horloge système.

- Un basé sur une horloge auxiliaire.

Créer un watchdog timer.

Utilisé pour exécuter une fonction après un délai spécifié. L’activation de la fonction est réalisée par

une interruption.

WDOG_ID = wdCreate ( )

Retourne un identificateur de watchdog ou NULL si erreur.

WDOG_ID spécifié dans le fichier wdLib.h.

Démarrer ou redémarrer un watchdog timer.

39 Système temps réel – Tornado2 Professeur : Michel MARIE

STATUS = wdStart (WDOG_ID wdId , int délai , FUNCPTR pFonction ,int paramètre )

Le délai doit être précisé en ticks.

Un seul paramètre peut être passé à la fonction à exécuter.

Annuler ou détruire un watchdog timer.

STATUS = wdCancel (WDOG_ID wdId )

Annule la fonction wdStart mais le watchdog existe toujours.

STATUS = wdDelete (WDOG_ID wdId )

Annule la fonction wdStart et détruit le watchdog.

Exemple, utilisation d’un watchdog timer pour sortir d’une fonction trop longue.

WDOG_ID wdId;

void fonction_appel (void)

{

wdId = wdCreate( );

FOREVER

{

wdStart ( wdId , 10*sysClkRateGet(), fonction_sortir, 0);

fonction_trop_longue();

}

}

void fonction_sortir ( int param )

{

…….

}

Utilisation de l’horloge auxiliaire.

Pour une scrutation rapide il est préconisé d’utiliser l’horloge auxiliaire du système. 5 fonctions

permettent d’utiliser cette horloge.

sysAuxClkEnable : Pour démarrer l’horloge.

sysAuxClkDisable : Pour stopper l’horloge.

sysAuxClkRateGet : Pour connaître la fréquence horloge.

sysAuxClkRateSet : Pour initialiser la fréquence horloge.

sysAuxClkConnect : Pour connecter une fonction d'IT à cette horloge.

40 Système temps réel – Tornado2 Professeur : Michel MARIE

La programmation objet C++ avec VxWorks

Tornado comprend les outils de compilation « GNU C++ ToolKit’s » et de débuggage CrossWind

permettant de développer des programmes objet.

1. Généralités du langage C++.

Pour pouvoir utiliser les fonctionnalités du langage objet il est nécessaire de déclarer à la création

de l’image du noyau VxWorks l’une des deux définitions suivantes :

INCLUDE_CPLUS : Ajoute au noyau l’intégralité des outils C++ dont dispose le système. Cette déclaration est nécessaire pendant la phase de

développement de l’application.

INCLUDE_CPLUS_MIN: Ajoute au noyau uniquement les outils C++ nécessaires à

l’application. Cette déclaration est à réaliser lors de la construction

définitive de l’application.

Les modules écrits en langage objet C++ disposent de constructeurs et de destructeurs. Il est

possible de choisir d’appeler ceux-ci soit manuellement soit automatiquement à l’aide de la fonction

cplusXtorSet( choix ).

choix = 0 : Le constructeur et le destructeur doivent-être appelés manuellement.

choix = 1 : Le constructeur est appelé automatiquement lors du chargement du module d’extension .out ld() et le destructeur est appelé automatiquement lors du

déchargement du module par unld().

Si le choix d’un appel manuel a été effectué, les fonctions cplusCtors() et cplusDtors() permettent

respectivement d’appeler le constructeur et le destructeur d’un module.

cplusCtors (monModule ) : Appel du constructeur du module monModule.

cplusCtors () : Appel du constructeur de tous les modules.

cplusDtors (monModule ) : Appel du destructeur du module monModule.

cplusDtors () : Appel du destructeur de tous les modules.

cplusCtorsLink () : Appel du constructeur de tous les modules liés au noyau.

cplusDtorsLink () : Appel du destructeur de tous les modules liés au noyau.

Attention, WindShell ne connaît ni les instructions à point, ni les instructions à flèche. Par exemple pour appeler avec l’argument 3 la fonction membre cri() de l’objet chien, instance de la

classe animal, la syntaxe est la suivante :

cri ( &chien , 3)

Wouaf , Wouaf , Wouaf

Si la fonction cri est surchargée, le Shell vous demande alors de préciser quelle fonction il doit

utiliser (pas terrible !). Exemple :

cri ( &chien , 3)

0 : animal : :cri ( int )

1 : humain : :cri ( int )

2 : inhumain : :cri ( int )

Choose the number of the symbol to use : 0

Wouaf , Wouaf , Wouaf

2. Librairie des entrées/sorties standard C++.

Il est également possible d’inclure au noyau la librairie standard des entrées/sorties formatées.

Cette librairie ajoute entre autres les objets cin, cout, cerr, clog, les opérateurs surchargés << et >>.

Pour ajouter cette librairie il faut définir INCLUDE_CPLUS_IOSTREAMS dans le noyau.

41 Système temps réel – Tornado2 Professeur : Michel MARIE

Systèmes de fichiers

1. Introduction.

Les systèmes de fichiers sur VxWorks permettent :

D’utiliser des RAM disques.

D’utiliser un système de fichiers DOS sur un disque local.

D’utiliser un système de fichier UNIX sur un disque local.

D’utiliser des circuits SCSI.(Small Computer System Interface )

Pour gérer les systèmes de fichiers il est nécessaire d’avoir :

Un “pilote ou driver” de blocs.

Lecture/écriture de fichiers.

Formatage de disque.

Des fonctions de gestion des systèmes de fichiers.

Les “pilotes” de blocs sont :

RamDrv : pour la création d’une RAM disque.

ScsiLib : pour les accés aux circuits SCSI.

Les librairies de fonctions associées sont :

dosFsLib : pour la compatibilité avec les fichiers DOS.

RawFsLib : pour la compatibilité avec UNIX.

2. Création d’une RAM disque.

BLK_DEV* = ramDevCreate (char* addr_ram, int bytes/bloc, int blocs/piste,

int nbr_blocs , int bloc_offset)

Retourne un pointeur sur une structure BLK_DEV décrivant la RAM disque.

Il est nécessaire de définir INCLUDE_RAMDRV dans la configuration du noyau VxWorks afin

d’y inclure le pilote de RAM disque ramDrv au noyau.

3. Système de fichiers DOS.

Dans ce cas le système de fichiers est hiérarchisé, les noms de fichiers sont limités au format 8.3,

les disques sont interchangeables avec les disques PC utilisant MS_DOS.

Configuration du système de fichiers DOS.

Il faut pour ceci définir INCLUDE_DOSFS dans la configuration du noyau VxWorks.

Dans le fichier configAll.h, NUM_DOSFS_FILES défini le nombre maximum de systèmes de

fichiers dos pouvant être ouverts, 20 par défaut.

Pour créer un système de fichiers DOS.

42 Système temps réel – Tornado2 Professeur : Michel MARIE

DOS_VOL_DESC* = dosFsMkfs ( char* rootDir, BLK_DEV* pDisque )

pDisque : Pointeur du type BLK_DEV sur le pilote du disque obtenu par la fonction

xxDevCreate(). La fonction retourne un pointeur sur une structure de description du système de

fichiers créé.

la fonction dosFsMkfsOptionsSet(UINT options) peut être appelée avant la précédente pour

spécifier les options de volume du disque.

Les fonctions dosFsConfigShow(char * name) et dosFsConfigGet(DOS_VOL_DESC* pdesc,

DOS_VOL_CONFIG* pResultConfig) affichent et retournent respectivement les informations de

configuration sur le système de fichiers créé.

Les commandes du Shell diskFormat(char* name) et diskInit(char* name) permettent

respectivement de formatter le disque et de réécrire le système de fichiers.

Pré-allocation d’espace sur le disque. Appel de la primitive standard

ioctl(int fd, int fonction, int arg)

Il est possible de pré-allouer un espace contigu de mémoire sur le disque pour un fichier, ceci afin

de diminuer le temps d’accès.

STATUS = ioctl ( fd , FIOCONTIG , nbr_bytes )

Cette fonction doit être appelée avant toute écriture du fichier ! Si l’espace demandé n’est pas

réalisable la fonction retourne ERROR.

Pour pré-allouer un espace non contigu la même fonction est utilisée avec la commande

FIOTRUNC.

STATUS = ioctl ( fd , FIOTRUNC , nbr_bytes )

Elle permet également de connaître la taille maximale d’espace contigu avec la commande

FIONCONTIG.

STATUS = ioctl ( fd , FIONCONTIG , &max_cont_bytes )

Ou encore de formatter le disque ou d’initialiser le système de fichier avec les commandes

FIODISKFORMAT et FIODISKINIT. De nombreuses autres commandes sont disponibles,

consulter l'aide de dosFsLib.

STATUS = ioctl ( fd , FIODISKFORMAT , 0 )

STATUS = ioctl ( fd , FIODISKINIT , 0 )

4. Pilote de système de fichier UNIX.

Il faut pour ceci définir INCLUDE_RAWFS dans la configuration du noyau VxWorks.

Dans le fichier configAll.h, NUM_RAWFS_FILES défini le nombre maximum de systèmes de

fichiers raw pouvant être ouverts, 5 par défaut.

Pour créer un système de fichier UNIX.

RAW_VOL_DESC* = rawFsDevInit ( char* nom_sys , BLK_DEV* pDisque )

pDisque : Pointeur du type BLK_DEV sur le pilote du disque obtenu par la fonction

xxDevCreate().

43 Système temps réel – Tornado2 Professeur : Michel MARIE

A partir de ce moment les fonctions de gestion du disque sont les mêmes, que ce soit un système de

fichiers DOS ou un système de fichiers UNIX.

5. Gestion de bus SCSI.

Le bus SCSI permet de connecter jusqu’à 8 périphériques différents, disque dur, lecteur CD_ROM,

etc…

Les fonctions VxWorks supportent les standards SCSI-1 et SCSI-2. Les librairies contenant ces

fonctions sont scsiLIb et scsiSeqLib.

Pour utiliser le bus SCSI plusieurs définitions sont à ajouter au fichier config.h.

- INCLUDE_SCSI : Fonctions de base du bus SCSI-1.

- INCLUDE_SCSI2 : Fonctions de base du bus SCSI-2.

- INCLUDE_SCSI_BOOT : Pour booter VxWorks sur le bus SCSI.

- INCLUDE_TAPEFS : Pour l’utilisation de SCSI-2 uniquement, accés

séquentiels.

Installation d’un périphérique SCSI.

La fonction scsiPhysDevCreate() permet d’initialiser un périphérique SCSI.

La fonction scsiBlkDevCreate() retourne un pointeur sur une structure de contrôle permettant la

gestion logique du périphérique.

Exemple : Configuration d’un disque dur.

pScsi = scsiPhysDevCreate ( pSysScsiCtrl , budId , 0 , 0 ,NONE , 0 , 0 , 0 );

pBlk = scsiBlkDevCreate ( pScsi , taille , offset );

dosFsDevInit ( “\DOS\ , pBlk , NULL );

44 Système temps réel – Tornado2 Professeur : Michel MARIE

Les communications réseau

1. Les bases réseau.

Le noyau VxWorks implémente le protocole d’échange entre machines distantes TCP/IP 4.4. Il

supporte les communications réseau au travers :

De l’interface Ethernet.

Du bus VME.

Du bus série. Les services réseau de VxWorks incluent :

L’accès aux fichiers distants.

La connexion à distance.

L’exécution de commandes à distance.

Si les machines à mettre en communication sont situées sur des réseaux différents, les données

transférées doivent être routées.

Si l’adresse de destination n’est pas sur le réseau courant l’algorithme de routage utilise une table de

routage.

Les adresses Internet :

L'adresse Internet (TCP/IP) d'une machine ou "nœud réseau" est une adresse codée sur 4 octets (IP

v4) ou dorénavant sur 16 octets (IP v6). Dans sa notation courante chaque octet est représenté dans

sa notation décimale séparé par un point, la "Dot Notation", ex: "192.168.10.33". Chaque adresse

est séparée en deux éléments, un champ réseau (numéro de réseau auquel appartient la machine,

attribué par l'Internic pour un réseau public), et un champ machine (numéro de la machine sur son

réseau). Selon leur taille, les réseaux sont repérés par 3 classes :

Classe A 0 Réseau 7 bits Machine 24 bits

Classe B 0 Réseau 14 bits Machine 16 bits1

Classe C 1 Réseau 21 bits Machine 8 bits1 0

Réseau 1.X.X.X à 127.X.X.X

Réseau 128.X.X.X à 191.X.X.X

Réseau 192.X.X.X à 223.X.X.X

La classe D (adresse réseau de 224.X.X.X à 239.X.X.X) est réservée aux adressages « multicast ».

La classe E (adresse réseau de 240.X.X.X à 247.X.X.X) est réservée aux expérimentations.

- Une adresse Internet avec le champ machine à 0 fait référence à un réseau.

- Une adresse Internet avec le champ machine entièrement à 1 est l’adresse « broadcast » qui

adresse tous les nœuds du réseau.

- Certains systèmes obsolètes utilisant l’adresse 0 comme « broadcast », il est possible de le

spécifier à l’aide de la fonction ifBroadcastSet().

- Le réseau classe A 0.0.0.0 est réservé pour les routes par défaut, tous les paquets destinés à un

réseau inconnu seront dirigés vers cette route.

- Le réseau classe A 127.0.0.0 est réservé pour le traffic IP local à la machine. Une interface

locale dite "loopback" porte en général l'adresse 127.0.0.1, utilisation du réseau en rebouclage

local.

- Si le réseau est connecté à l’Internet, son préfixe réseau doit être attribué par l’InterNIC

(Internet Network Information Center).

45 Système temps réel – Tornado2 Professeur : Michel MARIE

Certaines adresses de réseau peuvent également être librement utilisées pour un réseau privé :

classe A : 10.0.0.0

classe B : 172.16.0.0 à 172.31.0.0

classe C : 192.168.0.0 à 192.168.255.0

Aucun paquet à destination ou provenant de ces réseaux ne peut être routé sur l'internet.

D'un point de vue configuration, la séparation entre le champ machine et le champ réseau d'une

adresse IP se fait à l'aide d'un masque de réseau "NetMask", pour lequel tous les bits marqués à 1

signalent le champ réseau.

Exemple, réseau de classe C, NetMask = 255.255.255.0

2. Fonctions de manipulation des adresses internet.

Pour utiliser les fonctions de connexion réseau, les adresses IP devront faire l’objet de conversions.

VxWorks mémorise les adresses IP à points comme des entiers.

Par exemple la notation à points 90.0.0.70 est stockée en interne sous la forme 0x5a000046.

u_long inet_addr(char* inetstring) : convertit une notation à point en un entier.

int inet_Inaof(int inetAdr) : retourne le champ machine de l’adresse internet.

int inet_netof(struct in_addr inetAdr) : retourne le champ réseau de l’adresse internet.

inet_netof_string(char* inetstr, char *netstr) : retourne le champ réseau de l’adresse sous la forme d’une chaîne de caractères.

inet_ntoa_b(struct in_addr inetAdr, char* adr pStr) : convertit l’adresse Internet dans

sa notation ASCII à point.

La structure in_addr représente une machine par son adresse internet :

typedef struct in_addr {

union {

struct {

u_char s_b1,s_b2,s_b3,s_b4;

} s_un_b;

struct {

u_short s_w1,s_w2;

} s_un_w;

u_long s_addr;

} s_un;

} in_addr;

Pour associer un nom à une adresse Internet :

STATUS hostAdd (char* host_name , char* host_adresse )

Pour afficher l’ensemble des noms associés aux adresses Internet (table des adresses)

hostShow( )

Pour ajouter une route à la table de routage :

STATUS routeAdd ( char* destination , char* gateway )

Pour supprimer une route de la table de routage :

STATUS routeDelete ( char* destination , char* gateway)

Pour visualiser la table de routage :

routeShow ( char* destination , char* gateway )

Exemple :

ROUTE NET TABLE

destination gateway flags Refcnt Use Interface

46 Système temps réel – Tornado2 Professeur : Michel MARIE

150.39.0.0 147.11.54.254 3 0 0 enp0

ROUTE HOST TABLE

destination gateway flags Refcnt Use Interface

127.0.0.1 127.0.0.1 5 0 0 Io0

Les flags courants sont :

0x1 Route utilisable

0x2 La destination est une porte d’accès.

0x4 Entrée spécifique de routage.

0x10 Route créée dynamiquement (par redirection)

0x20 Route modifiée dynamiquement (par redirection)

Refcnt indique le nombre de connexions ouvertes utilisant la route.

Use est le nombre total de paquets envoyés au travers de la route.

Interface est le nom de l’interface réseau utilisé.

Pour tester les routes il est pratique d’utiliser la fonction ping.

STATUS = ping ( char* pdestination ,int nbr_paquets ,int options )

3. Connexion à distance sur une cible VxWorks.

Deux protocoles sont envisageables pour ce type de connexion :

rlogin : à partir d’un poste UNIX, définir INCLUDE_RLOGIN lors de la construction du noyau VxWorks.

telnet : utilise le protocole Internet, définir INCLUDE_TELNET lors de la

construction du noyau VxWorks.

La liaison peut être sécurisée pour restreindre les accès à l’aide d’un nom d’utilisateur et d’un mot

de passe.

Pour ceci, définir INCLUDE_SECURITY et spécifier LOGIN_USER_NAME et

LOGIN_PASSWORD.

Il est ensuite possible d’ajouter des utilisateurs avec la fonction loginUserAdd().

Attention, la connexion à distance nécessite que le Shell soit résidant à la cible, pour ceci définir INCLUDE_SHELL lors de la construction du noyau.

4. Exécution de commandes à distance.

Les programmes VxWorks peuvent invoquer des commandes RSH “Remote Shell” sur un poste

UNIX distant. Une "socket" est alors créée, VxWorks sera dès lors toujours vu comme client.

Exécution d’une commande à distance.

socket = rcmd ( char* destination ,int remote_port ,char* local_user ,char* remote_user

,char* cmd ,int* pFd )

Le "remote_port" est typiquement 514 pour le Shell.

Exemple : Utilisation de la commande Date sous UNIX.

unixDate = calloc (100,1)

socket = rcmd (“serveur_UNIX”, 514 , ”Arthur” , “Martin” , “date” , 0 )

read ( socket , unixDate , 100 )

printf ( “%s\n”, unixDate )

47 Système temps réel – Tornado2 Professeur : Michel MARIE

5. Accès à des fichiers distants.

Le noyau VxWorks intègre deux pilotes permettant les accès à des fichiers situés sur les machines

distantes.

nfsDrv,

netDrv. Les protocoles utilisables sont NFS (Network File System) et FTP (File Transfert Protocol).

5.1. Protocole NFS.

NFS est un protocole développé par Sun Microsystems. Le noyau VxWorks permet d’inclure un

client ou un serveur NFS. Le serveur NFS est inclus au noyau par défaut, pour inclure le client il

faut définir INCLUDE_NFS.

Monter un “file system” NFS.

STATUS = nfsMount (char* destination ,char* file_system ,char* local_name )

destination : nom de la machine distante.

file_system : nom du “file system” à monter (devant être exporté par la machine distante).

local_name : nom du circuit local d’accès au file system, par défaut filesystem si NULL.

Démonter un “file system” NFS.

STATUS = nfsUnmount (char* local_name )

Examiner un “file system” NFS.

nfsDevShow ( )

Authentification NFS.

nfsAuthUnixSet (char* destination ,int uid ,int gid ,int nbr_gids ,int* aup_gids )

uid : Nom d’utilisateur machine distante.

gid : Groupe d’utilisateur sur machine distante.

nbr_gids : Nombre de groupes dans aup_gids.

aup_gids : Tableau des groupes additionnels autorisés.

Exemple :

hostAdd ( “serveurNFS”,“10.83.16.10”)

nfsMount (“serveurNFS” , ”/root” , ”/nfsDev” )

nfsAuthUnixSet (“serveurNFS” , uid , gid , 0 , 0 )

fd = open(“/nfsDev/fichierx” , 2 )

………….

close ( fd )

5.2. Protocole FTP.

Le client FTP est résident à la cible puisqu’utilisé pour télécharger le noyau. Pour installer un

serveur FTP il est nécessaire de définir INCLUDE_FTP_SERVER et INCLUDE_SYM_TBL.

Le serveur FTP est sécurisé, pour entrer un nom d’utilisateur et un mot de passe à partir de vos

applications, il est nécessaire d’utiliser les fonctions loginInit() pour initialiser la table de login et

loginUserAdd() pour y ajouter un utilisateur. Le mot de passe doit auparavant être encrypté avec la

fonction loginDefaultEncrypt().

48 Système temps réel – Tornado2 Professeur : Michel MARIE

Exemple:

loginInit ();

mdpe=malloc(80);

loginDefaultEncrypt (“montsaint” , mdpe )

loginUserAdd (“michel” , mdpe )

Exemple: Echange via FTP entre un serveur VxWorks et un client UNIX.

Serveur VxWorks:

pRAM = ramDevCreate ( 0 , 512 , 0 , 400 , 0 )

dosFsMkfs ( “/RAM” , pRAM )

fd = creat (“/RAM/fichier” , 2 )

write ( fd , pData , nbr_bytes )

close ( fd )

Client UNIX:

% ftp VxServer

ftp> cd /RAM

ftp> get fichier

ftp> quit

Exemple: Echange via FTP entre un serveur VxWorks et un client VxWorks.

Serveur VxWorks:

pRAM = ramDevCreate ( 0 , 512 , 0 , 400 , 0 )

dosFsMkfs ( “/RAM” , pRAM )

fd = creat (“/RAM/fichier” , 2 )

write ( fd , pData , nbr_bytes )

close ( fd )

Client VxWorks:

netDevCreate ( “Serveur:” , “IP_Serveur” , 1 )

fd = open (“Serveur:/RAM/fichier” , 2 ,0)

pData = malloc ( nbr_bytes_max )

read ( fd , pData , nbr_bytes_max )

close ( fd )

49 Système temps réel – Tornado2 Professeur : Michel MARIE

La programmation réseau

1. Les composants réseau sur VxWorks. (Modèle DoD en 4 couches)

Ethernet SLIP/PPPMémoire partagée

TCP

IP

UDP

SocketsZbuf

API

NFS

RPC

ftprshtelnetrloginTornado

tgtsvr

pilotes réseau

Les communications réseau peuvent se faire au travers d’un transceiver Ethernet, du bus VME via

une mémoire partagée, ou d’une liaison série en utilisant un protocole SLIP, CSLIP ou PPP.

zbufAPI est un buffer utilisé pour accélérer les transactions sur le réseau.

2. Les sockets.

La socket est une interface logicielle pour le protocole Internet. Elle retourne un descripteur de

fichier qui sera utilisé par la suite pour les accès au réseau.

L’attachement de la socket au réseau se fait ensuite par un port de communication spécifié par la

fonction bind().

Le port est identifié par un numéro codé sur un entier court, les conventions d’usage des numéros de

port sur VxWorks sont :

0 à 1023 : Réservés pour les services du système ( rlogin, telnet etc…)

1024 à 5000 : Ports alloués dynamiquement.

>5000 : Ports définis par l’utilisateur.

Pour la gestion des adresses IP avec les sockets, deux structures de données sont utilisées:

La structure générique :

Struct sockaddr

{

u_short sa_family;

char sa_data[14];

};

La structure utilisée pour le protocole internet.

struct sockaddr_in

50 Système temps réel – Tornado2 Professeur : Michel MARIE

{

short sin_family;

u_short sin_port;

struct in_addr.sin_addr;

char sin_zero[8];

};

L’ordre de rangement des octets d’une adresse internet ou d’un numéro de port différe entre la

machine et le protocole réseau, certaines fonctions dites “network byte ordering” effectuent les

conversions nécessaires :

htonl() : Machine vers réseau, long.

htons() : Machine vers réseau, court.

ntohl() : Réseau vers machine, long.

ntohs() : Réseau vers machine, court.

2.1. Création d’une “socket”.

int = socket ( domaine , type , protocole )

Le domaine doit être PF_INET ou AF_INET ce qui ne change rien au fonctionnement de la

socket.

Le type est :

SOCK_DGRAM pour le protocole UDP.

SOCK_STREAM pour le protocole TCP.

Le protocole est 0.

Retourne un descripteur de socket ou ERROR.

2.2. Couplage d’une “socket” à un port de communication.

STATUS = bind ( sock , pAdr , Adr_long )

Sock : Descripteur de socket retourné par socket().

pAdr : Pointeur sur une structure sockaddr spécifiant l’adresse sur laquelle la socket

doit se coupler.

Adr_long : Taille de la structure sockaddr.

3. Programmation des sockets UDP.

UDP est un protocole sans connexion ce qui implique la perte possible de paquets. Le serveur crée

une socket et attache celle-ci à un port de communication connu. Il lit ensuite la demande du client

dans une boucle infinie et répond à ses requêtes.

Envoi de données sur une socket UDP.

Int = sendto ( sock , pBuff , buff_len , flags , pDestAdr , dest_len )

sock : Descripteur de socket retourné par socket().

pBuff : Adresse du buffer de données à envoyer.

buff_len : Longueur des données en octets.

flags : MSG_OOB (sans effet en UDP, envoi du caractère urgent en TCP),

MSG_DONTROUTE (sans consultation de la table de routage).

pDestAdr : Pointeur sur une structure sockaddr contenant l’adresse de destination.

dest_len : Taille de la structure sockaddr.

Réception de données sur une socket UDP.

Int = recvfrom ( sock , pBuff , buff_len , flags , pAdr , plen )

sock : Descripteur de socket retourné par socket().

51 Système temps réel – Tornado2 Professeur : Michel MARIE

pBuff : Adresse du buffer de stockage des données reçues.

buff_len : Longueur maximale en octets des données à lire.

flags : MSG_OOB ou MSG_PEEK (lecture sans consommation).

PAdr : Pointeur sur une structure sockaddr de stockage de l’adresse client.

plen : Pointeur sur un entier contenant la taille de la structure sockaddr.

Exemple : Serveur UDP.

#define PORT (u_short) 5001;

struct sockaddr_in monAdr;

int masocket;

bzero (&monAdr , sizeof( struct sockaddr_in ) );

monAdr.sin_family = PF_INET;

monAdr.sin_port = htons(PORT);

monAdr.sin_addr.s_addr = INADDR_ANY;

masocket = socket ( PF_INET , SOCK_DGRAM , 0);

if (masocket = = ERROR) return (ERROR);

if ( bind ( masocket , (struct sockaddr *)&monAdr, sizeof ( monAdr))<0)

{

close (masocket);

return( ERROR );

}

FOREVER

{

recvfrom ( ……..)

sendto (………)

}

4. Programmation des sockets TCP.

TCP est un protocole connecté. Il est possible d’implémenter des serveurs concurrents à l’aide

d’une socket maître et de sockets esclaves. Le serveur peut ainsi servir concuremment plusieurs

clients.

Les demandes de connexion des clients sont reçues par la socket maître qui crée alors

dynamiquement une socket esclave pour chaque client.

Après avoir créé la socket maître, fonction socket() et lui avoir attaché un port de communication,

fonction bind(), le serveur TCP définit une queue des connexions en attente d’acceptation avec la

fonction listen(). Une boucle infinie se chargera ensuite d’accepter les connexions clients, fonction

accept() et de créer une tâche de service du client.

52 Système temps réel – Tornado2 Professeur : Michel MARIE

socket

maître

socket

esclave

socket

esclave

gestion des demandes

de connexion

Création dynamique d'une socket pour chaque connexion

servie par une tâche

SERVEUR TCP CONCURRENT

Création d’une queue de connexions.

STATUS = listen ( sock , queue_len )

sock : Descripteur de socket retourné par socket().

Queue_len : Longueur de la queue de connexions, 5 max.

Acceptation d’une connexion.

int = accept ( sock , pAdr , plen )

sock : Descripteur de socket retourné par socket().

pAdr : Pointeur sur une structure sockaddr de stockage de l’adresse client.

plen : Pointeur sur un entier contenant la taille de la structure sockaddr.

Retourne un descripteur de socket esclave connectée au client ou ERROR.

Emission et réception des données.

Il est possible d’utiliser :

soit les fonctions read() / write().

soit les fonctions send() / recv().

Exemple : Serveur TCP concurrent.

master_socket = socket ( PF_INET , SOCK_STREAM , 0);

if (master_socket = = ERROR) return (ERROR);

if ( bind ( master_socket , (struct sockaddr *)&monAdr, sizeof ( monAdr))<0)

{

close (master_socket);

return( ERROR );

}

if ( listen ( master_socket , queue )<0)

{

close (master_socket);

return( ERROR );

}

FOREVER

{

53 Système temps réel – Tornado2 Professeur : Michel MARIE

slave_socket = accept( master_socket , (struct sockaddr *)&Addr_client);

taskSpawn ( …. , Service_client , slave_socket , …..);

}

Service_client ( slave_socket , …..)

{

read ( slave_socket , …..);

…..

write ( slave_socket , …..);

close ( slave_socket );

}

Le client quant à lui doit créer une socket puis effectuer une demande de connexion au serveur à

l’aide de la fonction connect().

Demande de connexion client.

STATUS = connect ( sock , pAdr , plen )

STATUS = connectWithTimeout ( sock , pAdr , plen, pTimeval )

sock : Descripteur de socket retourné par socket().

pAdr : Pointeur sur une structure sockaddr contenant l’adresse du serveur.

plen : Pointeur sur un entier contenant la taille de la structure sockaddr.

pTimeval : Pointeur sur une structure timeval fixant le time-out de connexion.

Exemple : Client TCP.

masocket = socket ( PF_INET , SOCK_STREAM , 0);

if (masocket = = ERROR) return (ERROR);

if ( connect ( masocket , (struct sockaddr *)&Adr_serveur, sizeof ( Adr_serveur))= =0)

{

close (masocket);

return( ERROR );

}

write (masocket , ……);

read ( masocket , …….);

close ( masocket );

Fermeture d’une connexion.

La fermeture par close() est immédiate et ferme la connexion en émission et en réception.

La fermeture par shutdown() permet de paramètrer les conditions de fermeture.

STATUS = shutdown ( sock , comment )

sock : Descripteur de socket retourné par socket().

comment : 0 = Fermeture de la réception

1 = Fermeture de l’émission

2 = Fermeture de l’émission et de la réception.

5. Paramétrage des sockets.

Il est possible d'accéder aux paramètres des sockets par l'intermédiaire de deux primitives :

int getsockopt( sock, level, option, pArg, taille)

int setsockopt( sock, level, option, pArg, taille)

54 Système temps réel – Tornado2 Professeur : Michel MARIE

Le paramètre LEVEL fixe le niveau d’application de l’option, pour les sockets il doit être égal à

SOL_SOCKET.

Le paramètre option définit le type d'information que l'on veut extraire, par exemple :

SO_TYPE : extraction du type de la socket,

SO_SNDBUF : fixe la taille du tampon d'émission,

SO_RCVBUF : fixe la taille du tampon de réception,

SO_SNDTIMEO : fixe le time-out d'émission,

SO_RCVTIMEO : fixe le time-out de réception,

Exemple de fonctions pour initialiser et afficher une structure sockaddr :

#include "vxWorks.h"

#include "fioLib.h"

#include "hostLib.h"

#include "inetLib.h"

#include "netinet/in.h"

#include "stdio.h"

#include "string.h"

#include "sys/socket.h"

#include "sys/types.h"

STATUS inetAddrInit(struct sockaddr_in* pAddr, char* pHost,

int port)

{

u_long inet;

bzero ((char *) pAddr, sizeof (struct sockaddr_in));

if ((inet = hostGetByName (pHost)) == ERROR)

{

if ((inet = inet_addr (pHost)) == ERROR) return (ERROR);

}

pAddr->sin_family = AF_INET;

pAddr->sin_port = htons (port);

pAddr->sin_addr.s_addr = inet;

return (OK);

}

void sockAddrShow (struct sockaddr_in * pSockAddr)

{

printf("sin_family = %d\n", pSockAddr->sin_family);

printf("sin_addr = %s\n",

inet_ntoa(pSockAddr- >sin_addr.s_addr)

printf("sin_port = %d\n", ntohs (pSockAddr->sin_port));

}

Exemple de serveur UDP-IP :

/* Serveur UDP

Affiche l'adresse IP, le numéro de port et le contenu du message.

Retourne un accusé de réception */

#include "vxWorks.h"

#include "sockLib.h"

#include "sys/socket.h"

#include "netinet/in.h"

#include "inetLib.h"

#include "ioLib.h"

55 Système temps réel – Tornado2 Professeur : Michel MARIE

#include "string.h"

#include "stdio.h"

#include "taskLib.h"

char buff[100];

typedef int SOCK_FD;

LOCAL void error (char * str);

void vxServeur (u_short port)

{

int clientAddrLength;

SOCK_FD sockFd;

struct sockaddr_in clientAddr;

struct sockaddr_in srvAddr;

char inetAddr[INET_ADDR_LEN];

u_short clientPort;

char *reply = "Accuse de reception du serveur\n";

routeAdd(10.0.2.0,10.0.1.200) ; clientAddrLength = sizeof (clientAddr);

/* Creation de la socket */

if ( (sockFd = socket (PF_INET, SOCK_DGRAM, IPPROTO_UDP)) < 0)

error ("Probleme Socket");

bzero ((char *)&srvAddr, sizeof(srvAddr));

srvAddr.sin_family = AF_INET;

srvAddr.sin_port = htons(port);

srvAddr.sin_addr.s_addr = INADDR_ANY;

if (bind(sockFd,(struct sockaddr*)&srvAddr,sizeof(srvAddr))<0)

{

close (sockFd);

error ("Probleme Bind");

}

FOREVER

{

if (recvfrom (sockFd, buff, 100, 0,(struct sockaddr*)

&clientAddr, &clientAddrLength) < 0)

{

close (sockFd);

error ("Probleme Recvfrom");

}

inet_ntoa_b (clientAddr.sin_addr, inetAddr);

clientPort = ntohl (clientAddr.sin_port);

printf("Message recu du client(port=%d, inet= %s):\n",

clientPort, inetAddr);

printf (buff);

if (sendto (sockFd, reply, strlen(reply) + 1, 0,

(struct sockaddr *) &clientAddr, clientAddrLength) < 0)

{

close (sockFd);

error ("Probleme sendto");

}

}

}

void error (char * str)

56 Système temps réel – Tornado2 Professeur : Michel MARIE

{

perror (str);

exit (1);

}

Exemple de serveur TCP-IP :

#include "vxWorks.h"

#include "sockLib.h"

#include "sys/socket.h"

#include "netinet/in.h"

#include "inetLib.h"

#include "ioLib.h"

#include "string.h"

#include "stdio.h"

#include "taskLib.h"

#include "routeLib.h"

#define MAX_MSG_SIZE 80

#define LOCAL static

typedef int SOCK_FD;

void doRequest ();

LOCAL void error ();

void vxServeur (u_long port)

{

int clientAddrLength;

SOCK_FD sockFd;

SOCK_FD newSockFd;

struct sockaddr_in clientAddr;

struct sockaddr_in srvAddr;

clientAddrLength = sizeof (clientAddr);

routeAdd("10.0.2.0","10.0.1.200");

if ( (sockFd = socket (PF_INET, SOCK_STREAM,0)) < 0 )

error ("Probleme socket");

bzero ((char *)&srvAddr, sizeof (srvAddr));

srvAddr.sin_family= AF_INET;

srvAddr.sin_port= htons (port);

srvAddr.sin_addr.s_addr = INADDR_ANY;

if(bind(sockFd,(struct sockaddr*)&srvAddr, sizeof(srvAddr))<0)

{

close (sockFd);

error ("probleme Bind");

}

if (listen (sockFd, 1) < 0)

{

close (sockFd);

error ("probleme Listen");

}

FOREVER

{

newSockFd= accept (sockFd,(struct sockaddr *) &clientAddr,

57 Système temps réel – Tornado2 Professeur : Michel MARIE

&clientAddrLength);

if (newSockFd < 0)

{

close (sockFd);

error ("Probleme Accept");

}

doRequest (newSockFd, &clientAddr);

printf ("Fermeture de la connexion par le client\n\n")

close (sockFd);

exit (0);

}

}

void doRequest(SOCK_FD sock,struct sockaddr_in* pClientAddr)

{

char* reply="Accuse de reception du serveur\n";

char buf [MAX_MSG_SIZE];

int msgSize;

char * pClientInet;

u_short clientPort;

pClientInet = inet_ntoa(pClientAddr->sin_addr);

clientPort = ntohs(pClientAddr->sin_port);

printf("Client connecte d'adresse IP %s, et de port %d\n",

pClientInet, clientPort );

FOREVER

{

msgSize = read (sock, buf, MAX_MSG_SIZE - 1);

if (msgSize < 0)

{

close (sock);

error ("Probleme Read");

}

else if (msgSize == 0)

{

close (sock);

break;

}

else

{

printf("Message de %d octets: \n%s\n", msgSize, buf);

if (write (sock, reply, strlen(reply)) < 0)

{

close (sock);

error ("Probleme Write");

}

}

}

}

LOCAL void error (pStr)

char * pStr;

{

perror (pStr);

exit (1);

}

58 Système temps réel – Tornado2 Professeur : Michel MARIE

Reconfiguration de VxWorks

Une fois la mise au point d’une application achevée, tout n’est pas fini pour autant ! En effet, un

certain nombre d’actions restent à effectuer :

Exclure les fonctionnalités du noyau inutiles à notre application afin « d’alléger » celui-ci.

Lier le code de l’application avec VxWorks.

Modifier le code de lancement de VxWorks pour démarrer sur la tâche initiale de l’application.

Ensuite l’application peut-être :

Soit téléchargée sur la cible par le réseau.

Soit « ROMEE » sur la cible.

Soit chargée à partir d’un disque local à la cible.

Certaines fonctionnalités sont interdépendantes, par exemple NFS nécessite RPC. Un programme

utilitaire c:tornado\wind\target\src\config\usrDepend.c recherche ces dépendances et inclus les

fonctionnalités que vous auriez pu éventuellement oublier ; mais je n’ose y croire !

Remarque : Pour connaître l’ensemble des fonctionnalités d’un noyau il est possible d’utiliser la

commande nm ou d’utiliser le browser pour connaître les symboles du fichier objet.

nm68k VxWorks | findstr \.o

1. Modifier le code de démarrage.

Pour indiquer la fonction à exécuter par activation d’une tâche de démarrage il faut :

Ajouter la définition INCLUDE_USER_APPL et la macro USER_APPL_INIT dans le fichier

config.h de votre BSP.

Ecrire le code de la précédente macro en spécifiant les paramètres de la tâche à activer et la fonction associée.

Exemple :

#define INCLUDE_USER_APPL

#define USER_APPL_INIT \

{ \

extern void monApplication(void) ; \

taskSpawn ( tmonApps , 60 , 0 , 3000 , (FUNCPTR)monApplication , \

0,0,0,0,0,0,0,0,0,0 ) ; \

}

2. Lier l’application avec VxWorks.

Pour cela il faut modifier le code du fichier « makefile » situé dans le répertoire du BSP comme

suit :

59 Système temps réel – Tornado2 Professeur : Michel MARIE

Tous les modules à ajouter doivent être spécifiés par une ligne commande avec

ADDED_MODULES afin d’être ajoutés à la liste des dépendances du noyau VxWorks et liés avec

celui-ci.

Les règles de fabrication du fichier objet à partir du fichier source doivent être précisées, ainsi que

l’emplacement du fichier source.

Exemple :

ADDED_MODULES = monApplication.o

|

|

|

monApplication.o : c:\tornado\Application\monApplication.c

@ $(RM) $@

$(CC) –c $(CFLAGS) c:\tornado\Application\monApplication.c

Il ne reste plus qu’à reconstruire l’image du noyau VxWorks avec la commande :

ProjectMake BAB40VxWorks TargetsVxWorks.

La commande VxWorks.st construit l’image du noyau avec le Shell résidant ainsi que la table

des symboles.

La commande VxWorks_rom.hex construit l’image du noyau ROMmable avec recopie en RAM au démarrage.

La commande VxWorks.res_rom.hex construit l’image du noyau ROMmable en résidant.

La commande VxWorks.st_rom.hex construit l’image du noyau avec le Shell résident ainsi que la table des symboles, ROMmable en résidant.

La commande VxWorks.res_rom_nosym.hex construit l’image du noyau sans table des

symboles, ROMmable en résidant.