1. Einführung
In diesem Abschnitt wird die Zusammenstellung von HAL-Komponenten vorgestellt, d. h. die Hinzufügung einiger Kenntnisse der Maschinenbediener über den Umgang mit der Maschine. Es ist zu beachten, dass solche Komponenten nicht unbedingt direkt mit der Hardware zu tun haben. Sie tun es oft, aber nicht notwendigerweise, z.B. könnte es eine Komponente geben, die zwischen imperialen und metrischen Maßstäben umrechnet, so dass es in diesem Abschnitt nicht erforderlich ist, auf die Interaktion mit der Hardware einzugehen.
Das Schreiben einer HAL-Komponente kann ein langwieriger Prozess sein, die meisten davon in Setup-Aufrufe zu rtapi_ und hal_ Funktionen und damit verbundene Fehlerprüfung. halcompile wird all diesen Code für Sie schreiben, automatisch. Das Kompilieren einer HAL-Komponente ist auch viel einfacher, wenn man halcompile benutzt, egal ob die Komponente Teil des LinuxCNC-Source-Trees ist, oder außerhalb davon.
Eine einfache Komponente wie "ddt", die in C kodiert ist, umfasst beispielsweise etwa 80 Zeilen Code. Die entsprechende Komponente ist sehr kurz, wenn sie mit dem Präprozessor "halcompile" geschrieben wird:
component ddt "Compute the derivative of the input function"; pin in real in; pin out real out; variable rtapi_real old; function _; license "GPL"; // indicates GPL v2 or later ;; rtapi_real tmp = in; out_set((tmp - old) / fperiod); old = tmp;
2. Installation
Um eine Komponente zu kompilieren, wenn eine gepackte Version von LinuxCNC verwendet wird, müssen Entwicklungspakete installiert werden, indem man entweder Synaptic aus dem Hauptmenü System → Administration → Synaptic package manager benutzt oder einen der folgenden Befehle in einem Terminalfenster ausführt:
sudo apt install linuxcnc-dev # oder sudo apt install linuxcnc-uspace-dev
Eine andere Methode ist die Verwendung des Synaptic-Paketmanagers aus dem Anwendungsmenü, um die Pakete linuxcnc-dev oder linuxcnc-uspace-dev zu installieren.
3. Kompilieren
3.1. Mittendrin im Quellcode
Legen Sie die .comp-Datei in das Quellverzeichnis linuxcnc/src/hal/components und führen Sie make erneut aus. Comp-Dateien werden vom Build-System automatisch erkannt.
Wenn eine .comp-Datei ein Treiber für Hardware ist, kann sie in linuxcnc/src/hal/drivers abgelegt werden und wird gebaut, es sei denn, LinuxCNC ist als Nicht-Echtzeit-Simulator konfiguriert.
3.2. Echtzeit-Komponenten außerhalb des Quellbaums
halcompile kann eine Echtzeitkomponente in einem einzigen Schritt verarbeiten, kompilieren und installieren, wobei rtexample.ko im LinuxCNC-Echtzeitmodulverzeichnis platziert wird:
[sudo] halcompile --install rtexample.comp
|
Note
|
sudo (für Root-Rechte) wird benötigt, wenn Sie LinuxCNC aus einem Deb-Paket installieren. Wenn Sie einen Run-In-Place (RIP) Build verwenden, sollten Root-Rechte nicht erforderlich sein. |
Or, it can process and compile in one step, leaving example.ko (or example.so for uspace) in the current directory:
halcompile --compile rtexample.comp
Oder es kann einfach verarbeitet werden, wobei die Datei example.c im aktuellen Verzeichnis verbleibt:
halcompile rtexample.comp
halcompile kann auch eine in C geschriebene Komponente kompilieren und installieren, indem es die oben gezeigten Optionen --install und --compile verwendet:
[sudo] halcompile --install rtexample2.c
Die Dokumentation im man-Format kann auch aus den Informationen im Deklarationsabschnitt erstellt werden:
halcompile --document -o example.9 rtexample.comp
Die resultierende Manpage „example.9“ kann angezeigt werden mit
man ./example.9
oder an einen Standardspeicherort für UNIX man pages kopiert.
3.3. Kompilieren von Nicht-Echtzeitkomponenten außerhalb des Quellbaums
halcompile kann Nicht-Echtzeit-Komponenten verarbeiten, kompilieren, installieren und dokumentieren:
halcompile non-rt-example.comp halcompile --compile non-rt-example.comp [sudo] halcompile --install non-rt-example.comp halcompile --document non-rt-example.comp
Bei einigen Bibliotheken (z. B. Modbus) kann es erforderlich sein, zusätzliche Compiler- und Linker-Argumente hinzuzufügen, damit der Compiler die Bibliotheken finden und linken kann. Im Falle von .comp-Dateien kann dies über "option"-Anweisungen in der .comp-Datei erfolgen. Für .c-Dateien ist dies nicht möglich, so dass stattdessen die Parameter --extra-compile-args und --extra-link-args verwendet werden können. Als Beispiel kann diese Befehlszeile verwendet werden, um die Komponente vfdb_vfd.c out-of-tree zu kompilieren.
halcompile --userspace --install --extra-compile-args="-I/usr/include/modbus" --extra-link-args="-lm -lmodbus -llinuxcncini" vfdb_vfd.c
|
Note
|
Die Auswirkung der Verwendung von extra-args in der Befehlszeile und in der Datei ist undefiniert. |
4. Verwendung einer Komponente
Die Komponenten müssen geladen und zu einem Thread hinzugefügt werden, bevor sie eingesetzt werden können. Die bereitgestellte Funktionalität kann dann direkt und wiederholt von einem der Threads aufgerufen werden oder sie wird von anderen Komponenten aufgerufen, die ihre eigenen Auslöser haben.
loadrt threads name1=servo-thread period1=1000000 loadrt ddt addf ddt.0 servo-thread
Weitere Informationen zu loadrt and addf sind bei den HAL Grundlagen zu finden.
Um Ihre Komponente zu testen, können Sie den Beispielen im HAL Tutorial folgen.
5. Definitionen
-
component - A component is a single real-time module, which is loaded with
Halcmd loadrt. One.compfile specifies one component. The component name and file name must match. -
instance - A component can have zero or more instances. Each instance of a component is created equal (they all have the same pins, parameters, functions, and data) but behave independently when their pins, parameters, and data have different values.
-
singleton - It is possible for a component to be a "singleton", in which case exactly one instance is created. It seldom makes sense to write a singleton component, unless there can literally only be a single object of that kind in the system (for instance, a component whose purpose is to provide a pin with the current UNIX time, or a hardware driver for the internal PC speaker).
6. Erstellung einer Instanz
Bei einem Singleton wird eine Instanz erstellt, wenn die Komponente geladen wird.
Bei einem Nicht-Singleton bestimmt der Modulparameter "count", wie viele nummerierte Instanzen erstellt werden. Wenn count nicht angegeben wird, bestimmt der Modulparameter names, wie viele benannte Instanzen erstellt werden. Wenn weder count noch names angegeben werden, wird eine einzige nummerierte Instanz erstellt.
7. Implizite Parameter
Den Funktionen wird implizit der Parameter period übergeben, der die Zeit in Nanosekunden der letzten Periode zur Ausführung der Komponente angibt. Funktionen, die Fließkommazahlen verwenden, können sich auch auf den Parameter fperiod beziehen, der die Fließkommazeit in Sekunden oder (period*1e-9) angibt. Dies kann in Komponenten nützlich sein, die Zeitinformationen benötigen. Siehe auch die nachfolgend beschriebene Option period.
8. Syntax
Eine .comp'-Datei besteht aus einer Reihe von Deklarationen, gefolgt von ;; auf einer eigenen Zeile, gefolgt von C Code, der die Funktionen des Moduls implementiert.
Die Erklärungen umfassen:
-
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 STARREDNAME ([SIZE]);
-
description DOC;
-
examples DOC;
-
notes DOC;
-
see_also DOC;'
-
license LICENSE;
-
author AUTHOR;
-
include HEADERFILE;
Klammern kennzeichnen optionale Elemente. Ein senkrechter Strich kennzeichnet Alternativen. Wörter in "GROSSBUCHSTABEN" kennzeichnen variablen Text, wie folgt:
-
NAME - Ein Standard-C-Bezeichner
-
STARREDNAME' - Ein C-Bezeichner mit null oder mehr * vor dem Namen. Diese Syntax kann verwendet werden, um Instanzvariablen zu deklarieren, die Zeiger sind. Beachten Sie, dass aufgrund der Grammatik kein Leerzeichen zwischen dem * und dem Variablennamen stehen darf.
-
HALNAME - Ein erweiterter Bezeichner. Bei der Erstellung eines HAL-Bezeichners werden alle Unterstriche durch Bindestriche ersetzt, und alle nachgestellten Bindestriche oder Punkte werden entfernt, so dass "this_name_" in "dieser-Name" umgewandelt wird, und wenn der Name "_" ist, wird auch ein nachgestellter Punkt entfernt, so dass "function _" einen HAL-Funktionsnamen wie "component" ergibt. " <num>statt "Komponente. <num>."
Falls vorhanden, wird beim Erstellen von Pins, Parametern und Funktionen das Präfix hal_ am Anfang des Komponentennamens entfernt.
Im HAL-Bezeichner für einen Pin oder Parameter kennzeichnet # ein Arrayelement und muss in Verbindung mit einer [SIZE]-Deklaration verwendet werden. Die Rautenzeichen werden durch eine 0-aufgefüllte Zahl ersetzt mit der gleichen Länge wie die Anzahl der #-Zeichen.
Wenn Sie einen C-Bezeichner erstellen, werden die folgenden Änderungen am HALNAME vorgenommen:
-
Alle "#"-Zeichen und alle Zeichen ".", "_" oder "-", die unmittelbar davor stehen, werden entfernt.
-
Alle verbleibenden "."- und "-"-Zeichen werden durch "_" ersetzt.
-
Wiederholte „_“-Zeichen werden in ein einzelnes „\_“-Zeichen geändert.
Ein nachgestelltes "_" wird beibehalten, damit HAL-Kennungen, die sonst mit reservierten Namen oder Schlüsselwörtern (z. B. "min") kollidieren würden, verwendet werden können.
| HALNAME | C Bezeichner (engl. identifier) | HAL-Bezeichner (engl. identifier) |
|---|---|---|
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 |
|
Note
|
Two declarations that claim the same HAL identifier — x_y_z and x_y_z_ in the table above — are rejected by halcompile; they would otherwise be refused by HAL at loadrt. An array claims one identifier per element, so x_# with [4] and x_0 collide, and a function claims <name>.time, <name>.tmax and <name>.tmax-increased as well, since those are created alongside it. Pins and parameters share one namespace; functions have their own. An if condition does not exempt a declaration.
|
-
if CONDITION (engl. für Bedingung)- Ein Ausdruck mit der Variablen Persönlichkeit, die ungleich Null ist, wenn der Pin oder Parameter erstellt werden soll.
-
SIZE - A number that gives the size of an array, at most 256. The array items are numbered from 0 to SIZE-1.
-
MAXSIZE : CONDSIZE - A number that gives the maximum size of the array, at most 256, followed by an expression involving the variable personality and which always evaluates to less than MAXSIZE. When the array is created its size will be CONDSIZE.
-
DOC - Eine Zeichenfolge, die das Element dokumentiert. Die Zeichenfolge kann eine "doppelt in Anführungszeichen" gesetzte Zeichenfolge im C-Stil sein, z. B.:
"Wählt die gewünschte Flanke aus: TRUE bedeutet fallend, FALSE bedeutet steigend"
oder eine "dreifach in Anführungszeichen" gesetzte Zeichenfolge im Python-Stil, die eingebettete Zeilenumbrüche und Anführungszeichen enthalten kann, z. B.:
"""Die Wirkung dieses Parameters, auch bekannt als "der Orb von Zot", ist in mindestens zwei Absätzen zu erklären. Hoffentlich haben Ihnen diese Absätze geholfen, "zot" besser zu verstehen."""
Einer Zeichenkette kann auch das Literalzeichen r vorangestellt werden; in diesem Fall wird die Zeichenkette wie eine Python-Rohzeichenkette interpretiert.
The documentation string is in "asciidoc" format. For more information on this markup format, see ascidoctor(1) and https://asciidoctor.org.
-
TYPE - One of the HAL types:
bool,sint,uintorreal. -
PINDIRECTION - One of the following:
in,out, orio. A component sets a value for an out pin, it reads a value from aninpin, and it may read or set the value of aniopin. -
PARAMDIRECTION - One of the following:
rorrw. A component sets a value for a r parameter, and it may read or set the value of a rw parameter. -
STARTVALUE - Specifies the initial value of a pin or parameter. If it is not specified, then the default is
0orFALSE, depending on the type of the item. -
HEADERFILE - Der Name einer Headerdatei, entweder in doppelten Anführungszeichen (include "myfile.h";) oder in spitzen Klammern (include <systemfile.h>;). Die Header-Datei wird (unter Verwendung der #include von C) am Anfang der Datei vor Pin- und Parameterdeklarationen eingefügt.
|
Note
|
Transitionally, You should retire all 32-bit pins and params and upgrade to sint and uint. Please beware of local variable truncation in the upgrade process. The proper variable types matching for all HAL types are:
|
8.1. Optionen
Die derzeit definierten Optionen sind:
-
option singleton yes - (Voreinstellung: no)
Erzeugt keinen count-Modulparameter und immer eine einzelne Instanz. Mit singleton werden die Elemente Komponentenname.Elementname genannt und ohne singleton werden die Elemente für nummerierte Instanzen Komponentenname.<num>.Elementname genannt. -
option default_count number' - (Standardwert: 1)
Normalerweise ist der Modulparameter count auf 1 voreingestellt. Ist er angegeben, so wird count stattdessen auf diesen Wert gesetzt. -
option count_function yes - (default: no)
Normally, the number of instances to create is specified in the module parameter count; if count_function is specified, the value returned by the function int get_count(void) is used instead, and the count module parameter is not defined. In userspace components, names= is not supported with count_function. -
option rtapi_app no - (Voreinstellung: yes)
Normalerweise werden die Funktionenrtapi_app_main()undrtapi_app_exit()automatisch definiert. Bei option rtapi_app no sind sie es nicht und müssen im C-Code bereitgestellt werden. Verwenden Sie die folgenden Prototypen:`int rtapi_app_main(void);` `void rtapi_app_exit(void);`
Wenn Sie Ihre eigene
rtapi_app_main()implementieren, rufen Sie die Funktionint export(char *prefix, long extra_arg)auf, um die Pins, Parameter und Funktionen fürprefixzu registrieren. -
option data TYPE - (default: none) deprecated
If specified, each instance of the component will have an associated data block of type TYPE (which can be a simple type like real or the name of a type created with typedef). In new components, variable should be used instead. -
option extra_setup yes - (Voreinstellung: no)
Wenn angegeben, wird die durch EXTRA_SETUP definierte Funktion für jede Instanz aufgerufen. Bei Verwendung der automatisch definierten rtapi_app_main ist extra_arg die Nummer dieser Instanz. -
option extra_cleanup yes' - (Voreinstellung: no)
Wenn angegeben, wird die durch EXTRA_CLEANUP definierte Funktion aus dem automatisch definierten rtapi_app_exit oder, im Falle eines erkannten Fehlers, im automatisch definierten rtapi_app_main aufgerufen. -
option post_export yes - (default: no)
If specified, call the function defined by POST_EXPORT for each instance. If using the automatically defined rtapi_app_main, extra_arg is the number of this instance. -
option userspace yes - (Voreinstellung: no)
Falls angegeben, beschreibt diese Datei eine Nicht-Echtzeit-Komponente (früher bekannt als "Userspace") und nicht eine reguläre (d.h. Echtzeit-) Komponente. Eine Nicht-Echtzeit-Komponente kann keine Funktionen haben, die durch die function-Direktive definiert sind. Stattdessen wird, nachdem alle Instanzen konstruiert sind, die C-Funktionvoid user_mainloop(void);aufgerufen. Wenn diese Funktion zurückkehrt, wird die Komponente beendet. Normalerweise verwendet user_mainloop() FOR_ALL_INSTS(), um die Aktualisierungsaktion für jede Instanz durchzuführen, und schläft dann für eine kurze Zeit. Eine andere übliche Aktion in user_mainloop() kann der Aufruf der Event-Handler-Schleife eines GUI-Toolkits sein. -
option userinit yes - (Voreinstellung: no)
Diese Option wird ignoriert, wenn die Option userspace (siehe oben) auf no gesetzt ist. Wenn userinit angegeben ist, wird die Funktion userinit(argc,argv) vor rtapi_app_main() (und damit vor dem Aufruf von hal_init() ) aufgerufen. Diese Funktion kann die Kommandozeilenargumente verarbeiten oder andere Aktionen ausführen. Ihr Rückgabetyp ist void; sie kann exit() aufrufen, wenn sie beenden will, anstatt eine HAL-Komponente zu erstellen (z.B. weil die Kommandozeilenargumente ungültig waren). -
option extra_link_args "…" - (Voreinstellung: "")
Diese Option wird ignoriert, wenn die Option Userspace (siehe oben) auf no gesetzt ist. Beim Linken einer Nicht-Echtzeitkomponente werden die angegebenen Argumente in die Linkzeile eingefügt. Da die Kompilierung in einem temporären Verzeichnis stattfindet, bezieht sich "-L." auf das temporäre Verzeichnis und nicht auf das Verzeichnis, in dem sich die .comp-Quelldatei befindet. Diese Option kann in der halcompile Befehlszeile mit -extra-link-args="-L….." gesetzt werden. Diese Alternative bietet eine Möglichkeit, zusätzliche Flags in Fällen zu setzen, in denen die Eingabedatei eine .c-Datei und keine .comp-Datei ist. -
option extra_compile_args "…" - (Voreinstellung: "")
Diese Option wird ignoriert, wenn die Option userspace (siehe oben) auf no gesetzt ist. Beim Kompilieren einer Nicht-Echtzeit-Komponente werden die angegebenen Argumente in die Compiler-Befehlszeile eingefügt. Wenn die Eingabedatei eine .c-Datei ist, kann diese Option in der halcompile-Befehlszeile mit --extra-compile-args="-I….." gesetzt werden. Diese Alternative bietet eine Möglichkeit, zusätzliche Flags zu setzen, wenn die Eingabedatei eine .c-Datei und keine .comp-Datei ist. -
option homemod yes - (Voreinstellung: no)
Modul ist ein benutzerdefiniertes Homing-Modul, das mit `[EMCMOT]HOMEMOD=`Modulname geladen wird. -
option tpmod yes - (Voreinstellung: no)
Modul ist ein benutzerdefiniertes Trajektorienplanungsmodul (tp), das mit[TRAJ]TPMOD=_Modulname geladen wird. -
option period no – (Standard: yes)
Steuert den impliziten Parameter period der in der Komponente definierten Funktion(en). Eine Standardfunktion hat einen impliziten Parameter period. Viele Komponenten verwenden den Parameter period jedoch nicht, was eine Compiler-Warnung „unused parameter“ verursachen würde. Das Setzen von option period no erzeugt eine Funktionsdeklaration ohne den Parameter period und verhindert so die Warnung. Das Setzen dieser Option verhindert außerdem die Definition von fperiod, da diese von period abhängt.
Wenn der VALUE (engl. für Wert) einer Option nicht angegeben wird, ist dies gleichbedeutend mit der Angabe von option … yes.
Das Ergebnis der Zuweisung eines unangemessenen Wertes zu einer Option ist undefiniert
Das Ergebnis der Verwendung einer anderen Option ist undefiniert.
8.2. Lizenz und Urheberschaft
-
LICENSE- Geben Sie die Lizenz des Moduls für die Dokumentation und für die MODULE_LICENSE()-Moduldeklaration an. Zum Beispiel, um anzugeben, dass die Lizenz des Moduls GPL v2 oder höher ist:`license "GPL"; // bedeutet GPL v2 oder höher`
Weitere Informationen über die Bedeutung von MODULE_LICENSE() und zusätzliche Lizenzbezeichner finden Sie in <linux/module.h> oder in der Handbuchseite zu rtapi_module_param(3).
Diese Erklärung ist erforderlich.
-
AUTHOR- Geben Sie den Autor des Moduls für die Dokumentation an.
8.3. Datenspeicherung pro Instanz
-
variable CTYPE STARREDNAME; + variable CTYPE STARREDNAME[SIZE]; + variable CTYPE STARREDNAME = DEFAULT; + variable CTYPE STARREDNAME[SIZE] = DEFAULT;Declare a per-instance variable STARREDNAME of type CTYPE, optionally as an array of SIZE items, and optionally with a default value DEFAULT. Items with no DEFAULT are initialized to all-bits-zero. CTYPE is a simple one-word C type, such as
rtapi_real,rtapi_uint,rtapi_sint,int, etc. Access to array variables uses square brackets.
Wenn eine Variable ein Zeigertyp sein soll, darf zwischen dem "*" und dem Variablennamen kein Leerzeichen stehen. Daher ist das Folgende akzeptabel:
variable int *example;
Aber die folgenden sind es nicht:
variable int* badexample; variable int * badexample;
8.4. Kommentare
Einzeilige Kommentare im C++-Stil (//...) und mehrzeilige Kommentare im C-Stil (/* ... */) werden beide im Deklarationsabschnitt unterstützt.
9. Einschränkungen
Obwohl HAL erlaubt, dass ein Pin, ein Parameter und eine Funktion denselben Namen haben können, ist dies bei halcompile nicht der Fall.
Zu den Variablen- und Funktionsnamen, die nicht verwendet werden können oder zu Problemen führen können, gehören:
-
Alles, was mit _comp beginnt.
-
comp_id
-
fperiod
-
rtapi_app_main
-
rtapi_app_exit
-
extra_setup
-
extra_cleanup
-
post_export
10. Bequemlichkeits-Makros
Based on the items in the declaration section, halcompile creates a C structure called struct __comp_state. However, instead of referring to the members of this structure (e.g., *(inst\->name)), they will generally be referred to using the macros below. The details of struct __comp_state and these macros may change from one version of halcompile to the next.
-
FUNCTION(`__name__)` - Verwenden Sie dieses Makro, um die Definition einer Echtzeitfunktion zu beginnen, die zuvor mit function NAME deklariert wurde. Die Funktion enthält einen Parameter period, der die ganzzahlige Anzahl von Nanosekunden zwischen Aufrufen der Funktion angibt. Siehe auch zuvor beschriebene Option period. -
EXTRA_SETUP()- Verwenden Sie dieses Makro, um die Definition der Funktion zu beginnen, die aufgerufen wird, um eine zusätzliche Einrichtung dieser Instanz durchzuführen. Geben Sie einen negativen UNIX-errno-Wert zurück, um einen Fehler anzuzeigen (z.B. return -EBUSY, wenn die Reservierung eines I/O-Ports fehlgeschlagen ist), oder 0, um einen Erfolg anzuzeigen. -
EXTRA_CLEANUP()- Verwenden Sie dieses Makro zu Beginn der Definition derjenigen Funktion, die eine Erweiterung des Aufräumen der Komponente implementiert. Beachten Sie, dass diese Funktion alle Instanzen der Komponente aufräumen muss, nicht nur eine. Die Makros "pin_name", "parameter_name" und "data" dürfen hier nicht verwendet werden. -
POST_EXPORT()- Use this macro to begin the definition of the function called to perform extra setup after all pins and parameters have been created for this instance. This function is called just before the export() function returns. You can use the POST_EXPORT() function to preset parameter values you otherwise would not be able to set. Return a negative UNIX errno value to indicate failure, or 0 to indicate success.
Note: POST_EXPORT() should not change personality. If you need to adapt personality, then you must do so in EXTRA_SETUP(), which runs before pins and parameters are created. -
pin_name oder parameter_name - Für jeden Pin pin_name oder Parameter parameter_name gibt es ein Makro, mit dem der Name allein verwendet werden kann, um auf den Pin oder Parameter zu verweisen. Wenn pin_name oder parameter_name ein Array ist, hat das Makro die Form pin_name(idx) oder param_name(idx), wobei idx der Index im Pin-Array ist. Handelt es sich bei dem Array um ein Array mit variabler Größe, ist es nur zulässig, um auf Elemente bis zu seiner condsize zu verweisen.
Wenn es sich um eine bedingte Position handelt, kann nur auf sie verwiesen werden, wenn ihre "Bedingung" einen Wert ungleich Null ergibt.
-
variable_name - Für jede Variable variable_name gibt es ein Makro, das es erlaubt, den Namen allein zu verwenden, um auf die Variable zu verweisen. Wenn variable_name ein Array ist, wird das normale C-Subskript verwendet: variable_name[idx].
-
data - Wenn "option data" angegeben ist, ermöglicht dieses Makro den Zugriff auf die Instanzdaten.
-
fperiod - Die Gleitkommazahl von Sekunden zwischen Aufrufen dieser Echtzeitfunktion. Siehe auch die zuvor beschriebene Option period.
-
FOR_ALL_INSTS() `{…}- Für Nicht-Echtzeit-Komponenten. Dieses Makro iteriert über alle definierten Instanzen. Innerhalb des Schleifenkörpers arbeiten die Makros pin_name, parameter_name und data wie in Echtzeitfunktionen.
11. Komponenten mit einer Funktion
Wenn eine Komponente nur eine Funktion hat und die Zeichenkette "FUNCTION" nirgendwo nach ;; auftaucht, dann wird der Teil nach ;; als der Körper der einzigen Funktion der Komponente angesehen. Siehe Simple Comp für ein Beispiel hierfür.
12. Komponenten-Persönlichkeit
Wenn eine Komponente Pins oder Parameter mit einer "if-Bedingung" oder "[maxsize : condsize]" hat, wird sie als Komponente mit "Persönlichkeit" bezeichnet. Die "Persönlichkeit" jeder Instanz wird beim Laden des Moduls festgelegt. Die "Persönlichkeit" kann verwendet werden, um Pins nur bei Bedarf zu erstellen. So wird die "Persönlichkeit" beispielsweise in der Komponente logic (engl. für Logik) verwendet, um eine variable Anzahl von Eingangspins für jedes Logikgatter und die Auswahl einer der grundlegenden booleschen Logikfunktionen und, oder und xor zu ermöglichen.
Die Standardanzahl der erlaubten "personality"-Elemente ist eine Kompilierzeiteinstellung (64). Die Vorgabe gilt für zahlreiche in der Distribution enthaltene Komponenten, die mit halcompile erstellt werden.
Um die zulässige Anzahl von Persönlichkeitselementen für benutzerdefinierte Komponenten zu ändern, verwenden Sie die Option --personalities mit halcompile. Zum Beispiel, um bis zu 128 Persönlichkeitszeiten zu erlauben:
[sudo] halcompile --personalities=128 --install ...
Bei der Verwendung von Komponenten mit Persönlichkeit ist es üblich, ein Persönlichkeitselement für jede angegebene Komponenteninstanz anzugeben. Beispiel für 3 Instanzen der Logikkomponente:
loadrt logic names=and4,or3,nand5, personality=0x104,0x203,0x805
|
Note
|
Wenn eine loadrt-Zeile mehr Instanzen als Persönlichkeiten angibt, wird den Instanzen mit nicht angegebenen Persönlichkeiten eine Persönlichkeit von 0 zugewiesen. Wenn die angeforderte Anzahl von Instanzen die Anzahl der erlaubten Persönlichkeiten übersteigt, werden die Persönlichkeiten durch Indexierung modulo der Anzahl der erlaubten Persönlichkeiten zugewiesen. Es wird eine Meldung über solche Zuweisungen ausgegeben. |
|
Note
|
If a component uses personality, then it should generally check its value. The value of personality is zero if the personality=N argument is not provided to loadrt. Pins and params whose personality constraint evaluates to zero are not created, and their memory remains NULL. Unconditionally accessing such a pin or param dereferences a NULL pointer and crashes the realtime process. You can use a test in EXTRA_SETUP() to test the acceptable values of personality for your component. You should return -EINVAL if your conditions are not met. Example testing personality:
|
13. Beispiele
13.1. Konstante
Beachten Sie, dass die Deklaration "function _" Funktionen mit dem Namen "constant.0" usw. erzeugt. Der Dateiname muss mit dem Komponentennamen übereinstimmen.
component constant;
pin out real out;
param r real value = 1.0;
option period no;
function _;
license "GPL"; // indicates GPL v2 or later
;;
FUNCTION(_) { out_set(value); }
13.2. sincos
Diese Komponente berechnet den Sinus und Kosinus eines Eingangswinkels im Bogenmaß. Sie hat andere Fähigkeiten als die "Sinus"- und "Kosinus"-Ausgänge von siggen, weil die Eingabe ein Winkel ist und nicht frei auf der Grundlage eines "Frequenz"-Parameters läuft.
Die Pins werden im Quellcode mit den Namen sin_ und cos_ deklariert, damit sie nicht mit den Funktionen sin() und cos() interferieren. Die HAL-Pins heißen weiterhin sincos.<num>.sin.
component sincos;
pin out real sin_;
pin out real cos_;
pin in real theta;
option period no;
function _;
license "GPL"; // indicates GPL v2 or later
;;
#include <rtapi_math.h>
FUNCTION(_) {
sin__set(sin(theta));
cos__set(cos(theta));
}
13.3. out8
This component is a driver for a fictional card called "out8", which has 8 pins of digital output which are treated as a single 8-bit value. There can be a varying number of such cards in the system, and they can be at various addresses. The pin is called out_ because out is an identifier used in <rtapi_io.h>. It illustrates the use of POST_EXPORT and EXTRA_CLEANUP to request an I/O region and then free it in case of error or when the module is unloaded.
component out8;
pin out uint out_ "Output value; only low 8 bits are used";
param r uint ioaddr;
function _;
option period no;
option count_function;
option post_export yes;
option extra_cleanup;
option constructable no;
license "GPL"; // indicates GPL v2 or later
;;
#include <rtapi_io.h>
#define MAXOUT 8
int io[MAXOUT] = {};
RTAPI_MP_ARRAY_INT(io, MAXOUT, "I/O addresses of out8 boards");
int get_count(void) {
int i = 0;
for(i = 0; i < MAXOUT && io[i]; i++) { /* Nothing */ }
return i;
}
POST_EXPORT() {
(void)prefix;
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;
}
// This can only be done when the param has been created and that can only
// be done in POST_EXPORT. Note the EXTRA_SETUP runs *before* the parameter
// is created and can therefore not set the parameter value.
ioaddr_set(io[extra_arg]);
return 0;
}
EXTRA_CLEANUP() {
for(int i = 0; i < MAXOUT && io[i]; i++) {
rtapi_release_region(io[i], 1);
}
}
FUNCTION(_) { rtapi_outb(out_, ioaddr); }
13.4. hal_loop
component hal_loop;
pin out real example;
Dieses Fragment einer Komponente veranschaulicht die Verwendung des Präfixes "hal_" in einem Komponentennamen.
loop ist ein gebräuchlicher Name (in der englischsprachig dominierten Programmierung), und das Präfix hal_ vermeidet mögliche Namenskollisionen mit anderer, nicht verwandter Software. Zum Beispiel läuft auf RTAI-Echtzeitsystemen Echtzeitcode im Kernel, wenn die Komponente also nur "loop" heißen würde, könnte sie leicht mit dem Standard-Kernelmodul "loop" in Konflikt geraten.
Nach dem Laden zeigt halcmd show comp eine Komponente namens hal_loop an. Der von "halcmd show pin" angezeigte Pin ist jedoch "loop.0.example" und nicht "hal-loop.0.example".
13.5. arraydemo
Diese Echtzeitkomponente veranschaulicht die Verwendung von Arrays fester Größe:
component arraydemo "4-bit Shift register";
pin in bool in;
pin out bool out-# [4];
option period no;
function _;
license "GPL"; // indicates GPL v2 or later
;;
for(int i = 3; i > 0; i--) {
out_set(i, out(i-1));
}
out_set(0, in);
13.6. rand
Diese Nicht-Echtzeit-Komponente ändert den Wert an ihrem Ausgangspin etwa alle 1 ms auf einen neuen Zufallswert im Bereich (0,1).
component rand;
option userspace;
pin out real out;
license "GPL"; // indicates GPL v2 or later
;;
#include <unistd.h>
void user_mainloop(void) {
while(1) {
usleep(1000);
FOR_ALL_INSTS() out_set(drand48());
}
}
13.7. Logik (unter Nutzung einer "Personality")
Diese Echtzeitkomponente zeigt, wie man "Persönlichkeit" verwendet, um Arrays variabler Größe und optionale Pins zu erstellen.
component logic "LinuxCNC HAL component providing experimental logic functions";
pin in bool in-##[16 : personality & 0xff];
pin out bool and if personality & 0x100;
pin out bool or if personality & 0x200;
pin out bool xor if personality & 0x400;
option period no;
function _;
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:
* 4 - The number of input pins, usually from 2 to 16
* 256 (0x100) - if the 'and' output is desired
* 512 (0x200) - if the 'or' output is desired
* 1024 (0x400) - if the 'xor' (exclusive or) output is desired
""";
license "GPL"; // indicates GPL v2 or later
;;
FUNCTION(_) {
rtapi_bool a = 1;
rtapi_bool o = 0;
rtapi_bool x = 0;
for(int i = 0; i < (personality & 0xff); i++) {
if(in(i)) {
o = 1;
x = !x;
} else {
a = 0;
}
}
if(personality & 0x100) and_set(a);
if(personality & 0x200) or_set(o);
if(personality & 0x400) xor_set(x);
}
Eine typische Zeile zur Belegung dieses Bauteil könnte lauten
loadrt logic count=3 personality=0x102,0x305,0x503
wodurch die folgenden Pins erstellt werden:
-
A 2-input AND gate:
logic.0.and,logic.0.in-00,logic.0.in-01 -
5-input AND and OR gates:
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, -
3-input AND and XOR gates:
logic.2.and,logic.2.xor,logic.2.in-00,logic.2.in-01,logic.2.in-02
13.8. Allgemeine Funktionen
Dieses Beispiel zeigt, wie man Funktionen von der Hauptfunktion aus aufruft. Es zeigt auch, wie die Referenz von HAL-Pins an diese Funktionen übergeben werden kann.
component example;
pin in sint in;
pin out bool out1;
pin out bool out2;
option period no;
function _;
license "GPL";
;;
// general pin set true function
void doset(hal_bool_t p) {
hal_set_bool(p, 1);
}
// general pin set false function
void unset(hal_bool_t p) {
hal_set_bool(p, 0);
}
//main function
FUNCTION(_) {
rtapi_sint inval = in;
if (inval < 0) {
doset(out1_ptr);
unset(out2_ptr);
} else if (inval > 0) {
unset(out1_ptr);
doset(out2_ptr);
} else {
unset(out1_ptr);
unset(out2_ptr);
}
}
This component uses two general function to manipulate a HAL bool pin referenced to it.
14. Verwendung der Kommandozeile
Die Manpage zu halcompile enthält Details zum Aufruf von halcompile.
$ man halcompile
Eine kurze Zusammenfassung der Verwendung von halcompile finden Sie hier:
$ halcompile --help