summaryrefslogtreecommitdiff
path: root/docs/src/hal/comp_fr.txt
blob: 50343019d1d232eaa5eca9fbc27006a357b7e389 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
:lang: fr
:toc:

= comp: outil pour créer les modules HAL

[[cha:comp-hal-component-generator]] (((Comp HAL Component Generator)))

== Introduction

Écrire un composant de HAL peut se révéler être une tâche ennuyeuse,
la plupart de cette tâche consiste à appeler des fonctions _rtapi_ et
_hal_ et à contrôler les erreurs associées à ces fonctions. _comp_ va
écrire tout ce code pour vous, automatiquement.

Compiler un composant de HAL est également beaucoup plus simple en
utilisant _comp_ , que le composant fasse partie de l'arborescence
de LinuxCNC, ou qu'il en soit extérieur.

Par exemple, cette portion des blocs _ddt_, codée en C, fait environ 80 lignes
de code, alors que le composant équivalent est vraiment très court quand il est
créé en utilisant le préprocesseur _comp_.

.Exemple pour comp [[code:exemple-comp]]
----
component ddt "Calcule la dérivée de la fonction d'entrée";
pin in float in;
pin out float out;
variable float old;
function _;
license "GPLv2 or later";
;;
float tmp = in;
out = (tmp - old) / fperiod;
old = tmp;
----

== Installation

Si une version pré-installée de LinuxCNC est utilisée, il sera nécessaire
d'installer les paquets de développement en passant par Synaptic depuis le menu
_Système → Administration → Gestionnaire de paquets Synaptic_ ou en utilisant
la commande suivante dans un terminal:

.Installation des paquets de développement
----
sudo apt-get install linuxcnc-dev
----

== Définitions

component::
     Un composant est un simple module temps réel, qui se charge avec
    _halcmd loadrt_. Un fichier _.comp_ spécifie un seul composant.

instance::
     Un composant peut avoir zéro ou plusieurs instances. Chaque instance
    d'un composant est créée égale (elles ont toutes les mêmes pins, les
    mêmes paramètres, les mêmes fonctions et les mêmes données) mais elle
    se comporte de manière différente quand leurs pins, leurs paramètres et
    leur données ont des valeurs différentes.

singleton::
     Il est possible pour un composant d'être un _singleton_ (composant
    dont il n'existe qu'une seule instance), dans ce cas, exactement une
    seule instance est créée. Il est rarement logique d'écrire un composant
    _singleton_ , à moins qu'il n'y ait qu'un seul objet de ce type dans le
    système
    (par exemple, un composant ayant pour but de fournir une pin avec le
    temps Unix courant, ou un pilote matériel pour le haut parleur interne
    du PC)

== Création d'instance

Pour un singleton, une seule instance est créée quand le composant est
chargé.

Pour un non-singleton, le paramètre _count_ du module détermine
combien d'instances seront créées.

== Paramètres implicites

Le paramètres _period_ est implicitement passé aux fonctions, c'est la durée,
en nanosecondes, de la dernière période d'exécution du comp. Les fonctions qui
utilisent des flottants peuvent aussi se référer à _fperiod_, qui est la durée
en secondes, soit (period*1e-9). Cela peut être utile pour les comps ayant
besoin de l'information de timming.

== Syntaxe

Un fichier _.comp_ commence par un certain nombre de déclarations,
puis par un délimiteur constitué de deux points virgule _;;_ seuls sur leur
propre ligne et enfin du code C implémentant les fonctions du module.

Déclarations d'include:

* _component HALNAME (DOC);_
* _pin PINDIRECTION TYPE HALNAME ([SIZE]|[MAXSIZE : CONDSIZE]) (if CONDITION) (= STARTVALUE) (DOC);_
* _param PARAMDIRECTION TYPE HALNAME ([SIZE]|[MAXSIZE : CONDSIZE]) (if CONDITION) (= STARTVALUE) (DOC);_
* _function HALNAME (fp | nofp) (DOC);_
* _option OPT (VALUE);_
* _variable CTYPE NAME ([SIZE]);_
* _description DOC;_
* _see_also DOC;_
* _license LICENSE;_
* _author AUTHOR;_

Les parenthèses indiquent un item optionnel. Une barre verticale
indique une alternative. Les mots en _MAJUSCULES_ indiquent une variable
texte, comme ci-dessous:

NAME::
    Un identifiant C standard.

STARREDNAME::
    Un identifiant C, précédé ou non d'une _*_. Cette syntaxe est utilisée
    pour déclarer les variables qui sont des pointeurs. Noter qu'à cause de la
    grammaire, il ne doit pas y avoir d'espace entre _*_ et le nom de la
    variable.

HALNAME::
    Un identifiant étendu. Lorsqu'ils sont utilisés pour créer un identifiant
    de HAL, tous les caractères soulignés sont remplacés par des tirets,
    tous les points et les virgules de fin, sont supprimés, ainsi *ce_nom_*
    est remplacé par *ce-nom*, si le nom est `"_"`, alors le point final est
    enlevé aussi, ainsi `"function_"` donne un nom de fonction HAL tel que
    `"component.<num>"` au lieu de `"component.<num>."`

S'il est présent, le préfixe _hal__  est enlevé du début d'un nom de
composant lors de la création des pins, des paramètres et des fonctions.

Dans l'identifiant de HAL pour une pin ou un paramètre, _#_ indique un
membre de tableau, il doit être utilisé conjointement avec une
déclaration _[SIZE]_. Les _hash marks_ sont remplacées par des nombres
de 0-barrés équivalents aux nombres de caractères #.

Quand ils sont utilisés pour créer des identifiants C, les changements
de caractères suivants sont appliqués au HALNAME:

 . Tous les caractères "`#`" sont enlevés ainsi que tous les caractères
   "`.`",  "`_`" ou "`-`" immédiatement devant eux.
 . Dans un nom, tous les caractères "`.`" et "`-`" sont remplacés par "`_`".
 . Les caractères "`__`" répétitifs sont remplacés par un seul caractère "`_`". 

Un "`_`" final est maintenu, de sorte que les identifiants de HAL, qui
autrement seraient en conflit avec les noms ou mots clé réservés (par
exemple: _min_), puissent être utilisés.

[width="90%", options="header"]
|========================================
|HALNAME | Identifiant C | Identifiant HAL
|x_y_z   | x_y_z         | x-y-z
|x-y.z   | x_y_z         | x-y.z
|x_y_z_  | x_y_z_        | x-y-z
|x.##.y  | x_y(MM)       | x.MM.z
|x.##    | x(MM)         | x.MM
|========================================

if CONDITION::
     Une expression impliquant la _personnalité_ d'une variable non nulle
    quand la variable ou le paramètre doit être
    créé.

SIZE::
     Un nombre donnant la taille d'un tableau. Les items des tableaux sont
    numérotés de 0 à _SIZE_-1.

MAXSIZE : CONDSIZE::
     Un nombre donnant la taille maximum d'un tableau, suivi d'une
    expression impliquant la _personnalité_ d'une variable et qui aura
    toujours une valeur inférieure à _MAXSIZE_. Quand le tableau est créé
    sa taille est égale à _CONDSIZE_.

DOC::
     Une chaine qui documente l'item. La chaine doit être au format C,
    entre guillemets, comme _"Sélectionnez le front désiré: TRUE pour
    descendant, FALSE pour montant"_ ou au format Python triples
    guillemets, pouvant inclure des 
    caractères newlines et des guillemets, comme:
        param rw bit zot=TRUE    
    La chaine de documentation est en format _groff -man_. Pour plus
    d'informations sur ce format de markup, voyez _groff_man(7)_ . Souvenez
    vous que comp interprète backslash comme Echap dans les
    chaines, ainsi par exemple pour passer le mot _example_ en font
    italique, écrivez _\\fIexample\\fB_.

TYPE::
     Un des types de HAL: _bit_, _signed_ (signé), _unsigned_ (non signé)
    ou _float_ (flottant). Les anciens noms _s32_ et _u32_ peuvent encore
    être utilisés, mais _signed_ et _unsigned_ sont préférables.

PINDIRECTION::
     Une des ces directions: _in_, _out_, ou _io_ . Le composant pourra
    positionner la valeur d'une pin de sortie, il
    pourra lire la valeur sur une pin d'entrée et il pourra lire ou
    positionner la valeur d'une pin _io_.

PARAMDIRECTION::
     Une des valeurs suivantes: _r_ ou _rw_. Le composant pourra
    positionner la valeur d'un paramètre _r_ et il pourra positionner ou
    lire la valeur d'un paramètre rw.

STARTVALUE::
     Spécifie la valeur initiale d'une pin ou d'un paramètre. Si il n'est
    pas spécifié, alors la valeur par défaut est _0_ ou _FALSE_, selon le
    type de l'item.

=== Fonctions HAL

fp::
    Indique que la fonction effectuera ses calculs en virgule flottante.

nofp::
     Indique que la fonction effectuera ses calculs sur des entiers. Si il
    n'est pas spécifié, _fp_  est utilisé. Ni comp ni gcc ne peuvent
    détecter l'utilisation de
    calculs en virgule flottante dans les fonctions marquées _nofp_.

=== Options

Selon le nom de l'option OPT, les valeurs VALUE varient. Les options
actuellement définies sont les suivantes:

OPT, VALUE:
    option singleton yes;;
        (défaut: no)
        Ne crée pas le paramètre numéro de module et crée toujours une seule
        instance. Avec _singleton_, les items sont nommés
        _composant-name.item-name_ et sans _singleton_, les items des
        différentes instances sont nommés _composant-name.<num>.item-name_.
    
    option default_count ;;
        _number_ (défaut: 1)
        Normalement, le paramètre _count_ par défaut est 0. Si spécifié,
        _count_ remplace la valeur par défaut.
    
    option count_function yes;;
        (défaut: no)
        Normalement, le numéro des instances à créer est specifié dans le
        paramètre _count_ du module, si _count_function_ est spécifié, la
        valeur retournée par la fonction _int get_count(void)_ est 
        utilisée à la place de la valeur par défaut et le paramètre _count_ 
        du module n'est pas défini.
    
    option rtapi_app no;;
        (défaut: yes)
        Normalement, les fonctions _rtapi_app_main_ et _rtapi_app_exit_ sont
        définies automatiquement. Avec _option rtapi_app no_, elles ne le
        seront pas et doivent être fournies dans le code C.
        
        Quand vous implémentez votre propre _rtapi_app_main_, appellez la
        fonction _int export(char _prefix, long extra_arg)_ pour enregistrer
        les pins, paramètres et fonctions pour _préfix_er.
    
    option data ;;
        _type_ (défaut: none) deprecated
        If specified, each instance of the component will have an associated
        data block of _type_ (which can be a simple type like _float_ or the
        name of a type created with _typedef_).
        
        In new components, _variable_ should be used instead.
    
    option extra_setup yes;;
        (défaut: no)
    
    option extra_cleanup yes;;
        (défaut: no)
        Si spécifié, appelle la fonction définie par _EXTRA_CLEANUP_
        depuis la fonction définie automatiquement _rtapi_app_exit_, 
        ou une erreur est détectée dans la fonction automatiquement 
        définie _rtapi_app_main_.
    
    option userspace yes;;
        (défaut: no)
        Si spécifié, ce fichier décrit un composant d'espace utilisateur,
        plutôt que le réel. Un composant d'espace utilisateur peut ne pas avoir 
        de fonction définie par la directive de fonction. Au lieu de cela, 
        après que toutes les instances soient construites, la fonction C 
        _user_mainloop()_  est appelée. Dès la fin de cette fonction, le 
        composant se termine. 
        En règle générale, _user_mainloop()_ va utiliser _FOR_ALL_INSTS()_ 
        pour effectuer la mise à  jour pour chaque action, puis attendre un
        court instant. Une autre action commune dans _user_mainloop()_ peut 
        être d'appeler le gestionnaire de boucles d'événements d'une 
        interface graphique.
    
    option userinit yes;;
        (défaut: no)
        Si spécifiée, la fonction _userinit(argc,argv)_ est appelée avant
        _rtapi_app_main()_ (et cela avant l'appel de _hal_init()_ ). Cette
        fonction peut traiter les arguments de la ligne de commande
        ou exécuter d'autres actions. Son type de retour est _void_; elle peut
        appeler _exit()_  et si elle le veut, se terminer sans créer de 
        composant HAL (par exemple, parce que les arguments de la ligne de 
        commande sont invalides).
    
    Si aucune option VALUE n'est spécifiée, alors c'est équivalent à
    spécifier la valeur _… yes_ . Le résultat consécutif à l'assignation
    d'une valeur inappropriée à
    une option est indéterminé. Le résultat consécutif à n'utiliser aucune
    autre option est indéfini.

=== Licence et auteur

LICENSE::
     Spécifie la license du module, pour la documentation et pour le module
    déclaré dans MODULE_LICENSE().

AUTHOR::
    Spécifie l'auteur du module, pour la documentation

=== Stockage des données *par instance*

variable ::
    _CTYPE NAME_;

variable ::
    _CTYPE NAME_[_SIZE_];

variable ::
    _CTYPE NAME = default_;

variable ::
    _CTYPE NAME_[_SIZE_] = _default_;
    Déclare la variable _par-instance_ _NAME_ de type _CTYPE_,
    optionnellement comme un tableau de _SIZE_ items et optionnellement
    avec une valeur par default. Les items sans _default_ sont initialisés
    _all-bits-zero_. _CTYPE_ est un simple mot de type C, comme _float_,
    _u32_, _s32_, etc. 
    Les variables d'un tableau sont mises entre crochets.

=== Commentaires

Les commentaires de style C++ une ligne (_// …_) et de style C
multi-lignes (_/_ … _/_) sont supportés tous les deux dans la section
déclaration.

== Restrictions sur les fichiers comp

Bien que HAL permette à une pin, un paramètre et une fonction d'avoir
le même nom, comp ne le permet pas.

Les noms de variable et de fonction qui ne doivent pas être utilisés ou
qui posent problème sont les suivants:

* Tous noms commençant par ___comp__.

* _comp_id_

* _fperiod_

* _rtapi_app_main_

* _rtapi_app_exit_

* _extra_setup_

* _extra_cleanup_


== Conventions des macros

En se basant sur les déclarations des items de section, _comp_ crée
une structure C appellée _structure d'état_ . Cependant, au lieu de
faire référence aux membres de cette structure
 (par exemple: _*(inst->name)_ ), il leur sera généralement fait
référence en utilisant les macros
ci-dessous. Certains détails de la structure d'état et de ces macros
peuvent différer d'une version de _comp_ à la suivante.

FUNCTION(name)::
     Cette macro s'utilise au début de la définition d'une fonction temps
    réel qui aura été précédemment déclarée avec _function NAME_.
    function inclus un paramètre _period_ qui est le nombre entier de
    nanosecondes entre les appels à la
    fonction.

EXTRA_SETUP()::
     Cette macro s'utilise au début de la définition de la fonction appelée
    pour exécuter les réglages complémentaires à cette instance. Une valeur
    de retour négative Unix _errno_ indique un défaut (par exemple: _elle
    retourne -EBUSY_  comme défaut à la réservation d'un port
    d'entrées/sorties), une
    valeur égale à 0 indique le succés.

EXTRA_CLEANUP()::
     Cette macro s'utilise au début de la définition de la fonction appelée
    pour exécuter un nettoyage (cleanup) du composant. Noter que cette
    fonction doit nettoyer toutes les instances du composant, pas juste un.
    Les macros _pin_name_, _parameter_name_ et _data_ ne doivent pas être
    utilisées ici.

pin_name ou parameter_name::
      Pour chaque pin, _pin_name_ ou pour chaque paramètre,
    _parameter_name_  il y a une macro qui permet d'utiliser le nom seul
    pour faire référence à la pin ou au paramètre.
    Quand _pin_name_ ou _parameter_name_ sont des tableaux, la macro est
    de la forme _pin_name(idx)_ ou _param_name(idx)_ dans laquelle _idx_ 
    est l'index dans le tableau de pins. Quand le tableau est de taille
     variable, il est seulement légal de faire référence aux items par
    leurs _condsize_.
+
    Quand un item est conditionnel, il est seulement légal de faire
    référence à cet item quand ses conditions sont évaluées à des
    valeurs différentes de zéro.

variable_name::
     Pour chaque variable, _il y a une macro variable_name_  qui permet au
    nom seul d'être utilisé pour faire référence à la
     variable. Quand _variable_name_ est un tableau, le style normal de C
    est utilisé: _variable_name[idx]_

data::
     Si l'_option data_ est spécifiée, cette macro permet l'accès à
    l'instance de la donnée.

fperiod::
     Le nombre de secondes en virgule flottante entre les appels à cette
    fonction temps réel.

FOR_ALL_INSTS() {*…*}::
    Pour les composants de l'espace utilisateur. Cette macro utilise
    la variable *struct state _inst_ pour itérer au dessus de toutes 
    les instances définies. Dans le corps 
    de la boucle, les macros _pin_name_, _parameter_name_ et _data_
    travaillent comme elles le font dans les fonctions temps réel.

== Composants avec une seule fonction

Si un composant a seulement une fonction et que la chaine _FUNCTION_
n'apparaît nulle part après _;;_, alors la portion après _;;_ est
considérée comme étant le corps d'un composant simple fonction.

== Personnalité du composant

Si un composant a n'importe combien de pins ou de paramètres avec un
if condition ou _[maxsize : condsize]_, il est appelé un
composant avec personnalité. La personnalité de chaque instance
est spécifiée quand le module
est chargé. La personnalité peut être utilisée pour créer les pins
seulement quand c'est nécessaire. Par exemple, la personnalité peut
être utilisée dans un composant logique, pour donner un nombre variable
de broches d'entrée à chaque porte logique et permettre la sélection de
 n'importe quelle fonction de logique booléenne de base _and_, _or_ et
_xor_.

== Compiler un fichier _.comp_ dans l'arborescence

Placer le fichier _.comp_ dans le répertoire _linuxcnc/src/hal/components_
et lancer/relancer _make_. Les fichiers Comp sont automatiquement
détectés par le système de compilation.

Si un fichier _.comp_ est un pilote de périphérique, il peut être
placé dans _linuxcnc/src/hal/components_  et il y sera construit excepté si
LinuxCNC est configuré en mode
simulation.

== Compiler un composant temps réel hors de l'arborescence[[sec:Compiler-composants-rt]]
(((Compiling realtime components outside the source tree)))

_comp_ peut traiter, compiler et installer un composant temps réel en
une
 seule étape, en plaçant _rtexample.ko_ dans le répertoire du module
temps réel de LinuxCNC:

    comp --install rtexample.comp

Ou il peut aussi être traité et compilé en une seule étape en laissant
_example.ko_ (ou _example.so_ pour la simulation) dans le répertoire
courant:

    comp --compile rtexample.comp

Ou il peut simplement être traité en laissant _example.c_ dans le
répertoire courant:

    comp rtexample.comp

_comp_ peut aussi compiler et installer un composant écrit en C, en
utilisant _les options --install_ et _--compile_ comme ci-dessous:

    comp --install rtexample2.c

La documentation au format man peut être créée à partir des
informations de la section _declaration_:

    comp --document rtexample.comp

La manpage résultante, _exemple.9_ peut être lue avec:

    man ./exemple.9

ou copiée à un emplacement standard pour une page de manuel.

== Compiler un composant de l'espace utilisateur hors de l'arborescence

_comp_ peut traiter, compiler et installer un document de l'espace
utilisateur:

    comp usrexample.comp

Cela fonctionne seulement pour les fichiers _.comp_ mais pas pour les
fichiers _.c_.

== Exemples

=== constant

Ce composant fonctionne comme dans _blocks_, y compris la valeur par
défaut à 1.0. La déclaration _function __ crée les fonctions nommées
_constant.0_, etc.

    component constant;

=== sincos

Ce composant calcule le sinus et le cosinus d'un angle entré en
radians. Il a différentes possibilités comme les sorties _sinus_ et
_cosinus_ de siggen, parce que l'entrée est un angle au lieu d'être
librement basé sur un paramètre _frequency_.

Les pins sont déclarées avec les noms _sin__ et _cos__ dans le code
source pour que ça n'interfère pas avec les fonctions _sin()_ et
_cos()_. Les pins de HAL sont toujours appelées _sincos.<num>.sin_.

    component sincos;

=== out8

Ce composant est un pilote pour une carte imaginaire appelée _out8_,
qui a 8 pins de sortie digitales qui sont traitées comme une simple
valeur sur 8 bits. Il peut y avoir un nombre quelconque de ces cartes
dans le système et elles peuvent avoir des adresses variées. La pin est
appelée _out__ parce que _out_ est un identifiant utilisé dans
_<asm/io.h>_. Il illustre l'utilisation de _EXTRA_SETUP_ et de
_EXTRA_CLEANUP_ pour sa requête de région d'entrées/sorties et libère
cette région en
cas d'erreur ou quand le module est déchargé.


[source,c]
----
component out8;
pin out unsigned out_ "Output value; only low 8 bits are used";
param r unsigned ioaddr;

function _;

option count_function;
option extra_setup;
option extra_cleanup;
option constructable no;

license "GPL";
;;
#include <asm/io.h>

#define MAX 8
int io[MAX] = {0,};
RTAPI_MP_ARRAY_INT(io, MAX, "I/O addresses of out8 boards");

int get_count(void) {
    int i = 0;
    for(i=0; i<MAX && io[i]; i++) { /* Nothing */ }
    return i;
}

EXTRA_SETUP() {
    if(!rtapi_request_region(io[extra_arg], 1, "out8")) {
	// set this I/O port to 0 so that EXTRA_CLEANUP does not release the IO
	// ports that were never requested.
        io[extra_arg] = 0; 
        return -EBUSY;
    }
    ioaddr = io[extra_arg];
    return 0;
}

EXTRA_CLEANUP() {
    int i;
    for(i=0; i < MAX && io[i]; i++) {
        rtapi_release_region(io[i], 1);
    }
}

FUNCTION(_) { outb(out_, ioaddr); }
----

=== hal_loop

    component hal_loop;

Ce fragment de composant illustre l'utilisation du préfixe _hal__ dans
un nom de composant. _loop_ est le nom d'un module standard du kernel
Linux, donc un composant _loop_ ne pourrait pas être chargé si le
module loop de Linux est également
présent.

Quand il le charge, halcmd montre un composant appelé _hal_loop_.
Cependant, les pins affichées par halcmd sont _loop.0.example_ et non
_hal-loop.0.example_.

=== arraydemo

Ce composant temps réel illustre l'utilisation d'un tableau de taille
fixe:

    component arraydemo "Registre à décalage 4-bits";

=== rand

Ce composant de l'espace utilisateur modifie la valeur de ses pins de
sortie vers une nouvelle valeur aléatoire dans l'étendue (0,1) à chaque 1ms.

[source,c]
----
component rand;
option userspace;

pin out float out;
license "GPL";
;;
#include <unistd.h>

void user_mainloop(void) {
    while(1) {
        usleep(1000);
        FOR_ALL_INSTS() out = drand48();
    }
}
----

=== logic

Ce composant temps réel montre l'utilisation de la personnalité pour
créer un tableau de taille variable et des pins optionnelles.

[source,c]
----
component logic "LinuxCNC HAL component providing experimental logic functions";
pin in bit in-##[16 : personality & 0xff];
pin out bit and if personality & 0x100;
pin out bit or if personality & 0x200;
pin out bit xor if personality & 0x400;
function _ nofp;
description """
Experimental general logic function component.  Can perform and, or
and xor of up to 16 inputs.  Determine the proper value for personality
by adding:
.IP \\(bu 4
The number of input pins, usually from 2 to 16
.IP \\(bu
256 (0x100)  if the and output is desired
.IP \\(bu
512 (0x200)  if the or output is desired
.IP \\(bu
1024 (0x400)  if the xor (exclusive or) output is desired""";
license "GPL";
;;
FUNCTION(_) {
    int i, a=1, o=0, x=0;
    for(i=0; i < (personality & 0xff); i++) {
        if(in(i)) { o = 1; x = !x; }
        else { a = 0; }
    }
    if(personality & 0x100) and = a;
    if(personality & 0x200) or = o;
    if(personality & 0x400) xor = x;
}
----

Une ligne de chargement typique pourrait être:
----
    loadrt logic count=3 personality=0x102,0x305,0x503
----

qui créerait les pins suivantes:

 - Une porte AND à 2 entrées: logic.0.and, logic.0.in-00, logic.0.in-01
 - des portes AND et OR à 5 entrées: logic.1.and, logic.1.or,
   logic.1.in-00, logic.1.in-01, logic.1.in-02, logic.1.in-03,
   logic.1.in-04, 
 - des portes AND et XOR à 3 entrées: logic.2.and, logic.2.xor,
   logic.2.in-00, logic.2.in-01, logic.2.in-02