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 "Berechne die Ableitung der Eingangsfunktion";
pin in float in;
pin out float out;
variable double old;
function _;
license "GPL"; // gibt GPL v2 oder höher an
;;
float tmp = in;
out = (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. Compiling
3.1. Inside the source tree
Place the .comp
file in the source directory linuxcnc/src/hal/components
and re-run make
. Comp files are automatically detected by the build system.
If a .comp
file is a driver for hardware, it may be placed in linuxcnc/src/hal/drivers
and will be built unless LinuxCNC is configured as a non-realtime simulator.
3.2. Realtime components outside the source tree
halcompile can process, compile, and install a realtime component in a single step, placing rtexample.ko
in the LinuxCNC realtime module directory:
[sudo] halcompile --install rtexample.comp
Anmerkung
|
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 the simulator) in the current directory:
halcompile --compile rtexample.comp
Or it can simply process, leaving example.c
in the current directory:
halcompile rtexample.comp
halcompile can also compile and install a component written in C, using the --install
and --compile
options shown above:
[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. Non-realtime components outside the source tree
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
For some libraries (for example modbus) it might be necessary to add extra compiler and linker arguments to enable the compiler to find and link the libraries. In the case of .comp files this can be done via "option" statements in the .comp
file. For .c
files this is not possible so the --extra-compile-args
and --extra-link-args
parameters can be used instead. As an example, this command line can be used to compile the vfdb_vfd.c
component out-of-tree.
halcompile --userspace --install --extra-compile-args="-I/usr/include/modbus" --extra-link-args="-lm -lmodbus -llinuxcncini" vfdb_vfd.c
Anmerkung
|
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
More information on loadrt
and addf
can be found in the HAL Basics.
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.comp
file 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.
8. Syntax
A .comp
file consists of a number of declarations, followed by ;;
on a line of its own, followed by C code implementing the module’s functions.
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 |
-
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 - Eine Zahl, um die Größe eines Arrays anzugeben. Die Array-Elemente sind von 0 bis SIZE-1 nummeriert.
-
MAXSIZE : CONDSIZE - Gibt die maximale Größe des Arrays an, gefolgt von einem Ausdruck, der die Variable personality einbezieht und der immer weniger als MAXSIZE ergibt. Wenn das Array erstellt wird, hat es die Größe 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.
Die Dokumentationszeichenfolge hat das Format "groff -man". Für weitere Informationen über dieses Format siehe groff_man(7). Denken Sie daran, dass halcompile Backslash-Escapes in Zeichenketten interpretiert, so dass Sie zum Beispiel die kursive Schriftart für das Wort Beispiel einstellen können:
"\\fIBeispiel\\fB"
In diesem Fall sind r-Zeichenfolgen besonders nützlich, da die Backslashes in einer r-Zeichenfolge nicht verdoppelt werden müssen:
r"\fI-Beispiel\fB"
-
TYPE - Einer der HAL-Typen: bit, s32, u32, s64, u64 or float. Die Namen signed (engl. für "mit Vorzeichen") und unsigned können ebenfalls verwendet werden statt s32 oder u32, aber letzteres wird lieber gesehen.
-
PINDIRECTION - Eine der folgenden Optionen: in, out oder io. Eine Komponente legt einen Wert für einen Out-Pin fest, liest einen Wert von einem "In"-Pin und kann den Wert eines "io"-Pins lesen oder festlegen.
-
PARAMDIRECTION - Eine der folgenden: r oder rw. Eine Komponente legt einen Wert für einen r-Parameter fest und kann den Wert eines rw-Parameters lesen oder festlegen.
-
STARTVALUE - Gibt den Anfangswert eines Pins oder Parameters an. Wenn nicht anders angegeben, ist der Standardwert "0" oder "FALSE", abhängig vom Typ des Elements.
-
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.
8.1. HAL-Funktionen
-
fp - Gibt an, dass die Funktion Gleitkommaberechnungen durchführt.
-
nofp - Gibt an, dass nur Ganzzahlberechnungen durchgeführt werden. Wenn keines von beiden angegeben ist, wird fp angenommen. Weder halcompile noch gcc können die Verwendung von Fließkommaberechnungen in Funktionen, die mit nofp gekennzeichnet sind, erkennen, aber die Verwendung solcher Operationen führt zu undefiniertem Verhalten.
8.2. Optionen
Die derzeit definierten Optionen sind:
-
option singleton yes - (Standardwert: 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 - (Voreinstellung: no) Normalerweise wird die Anzahl der zu erstellenden Instanzen im Modulparameter count angegeben; wenn count_function angegeben ist, wird stattdessen der von der Funktion int get_count(void) zurückgegebene Wert verwendet, und der Modulparameter count ist nicht definiert.
-
option rtapi_app no - (Voreinstellung: yes) Normalerweise werden die Funktionen
rtapi_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ürprefix
zu registrieren. -
option data TYPE - (Voreinstellung: none) veraltet
Wenn angegeben, hat jede Instanz der Komponente einen zugehörigen Datenblock des Typs TYPE (der ein einfacher Typ wie float oder der Name eines mit typedef erstellten Typs sein kann). In neuen Komponenten sollte stattdessen variable verwendet werden. -
option extra_setup yes - (Standard: 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 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 - (Standard: 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 "…" - (default: "") 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 "…" - (default: "") 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 - (Standard: no)
Modul ist ein benutzerdefiniertes Homing-Modul, das mit[EMCMOT]HOMEMOD=
Modulname geladen wird. -
option tpmod yes - (Standard: no)
Modul ist ein benutzerdefiniertes Trajektorienplanungsmodul (tp), das mit[TRAJ]TPMOD
=_Modulname geladen wird.
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.3. 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.4. Datenspeicherung pro Instanz
-
variable CTYPE STARREDNAME; + variable CTYPE STARREDNAME[SIZE]; + variable CTYPE STARREDNAME = DEFAULT; + variable CTYPE STARREDNAME[SIZE] = DEFAULT;
Deklarieren Sie eine Instanzvariable STARREDNAME vom Typ CTYPE, optional als Array von SIZE-Elementen und optional mit einem Standardwert DEFAULT. Elemente ohne DEFAULT werden auf alle Bits-Null initialisiert. CTYPE ist ein einfacher Ein-Wort-C-Typ, wie
float
,u32
,s32
,int
, etc. Der Zugriff auf Array-Variablen erfolgt über eckige Klammern.
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.5. 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
10. Bequemlichkeits-Makros
Basierend auf den Elementen im Deklarationsabschnitt erzeugt halcompile eine C-Struktur namens struct __comp_state
. Anstatt jedoch auf die Mitglieder dieser Struktur zu verweisen (z.B. *(inst->name)
), werden sie im Allgemeinen mit den untenstehenden Makros angesprochen. Die Details von struct __comp_state
und diesen Makros können sich von einer Version von halcompile zur nächsten ändern.
-
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. -
EXTRA_SETUP()
- Use this macro to begin the definition of the function called to perform extra setup of this instance. Return a negative UNIX errno value to indicate failure (e.g., return -EBUSY on failure to reserve an I/O port), or 0 to indicate success. -
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. -
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.
-
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
If a component has only one function and the string "FUNCTION"
does not appear anywhere after ;;
, then the portion after ;;
is all taken to be the body of the component’s single function. See the Simple Comp for an example of this.
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
Anmerkung
|
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. |
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 float out; param r float value = 1.0; function _; license "GPL"; // bedeutet GPL v2 oder höher ;; FUNCTION(_) { out = 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 float sin_; pin out float cos_; pin in float theta; function _; license "GPL"; // bedeutet GPL v2 oder höher ;; #include <rtapi_math.h> FUNCTION(_) { sin_ = sin(theta); cos_ = cos(theta); }
13.3. out8
Bei dieser Komponente handelt es sich um einen Treiber für eine "fiktive" Karte mit der Bezeichnung "out8", die über 8 Pins mit digitalen Ausgängen verfügt, die als ein einziger 8-Bit-Wert behandelt werden. Es kann eine unterschiedliche Anzahl solcher Karten im System geben, und sie können sich an verschiedenen Adressen befinden. Der Pin wird out_ genannt, weil out ein in <asm/io.h> verwendeter Bezeichner ist. Er veranschaulicht die Verwendung von EXTRA_SETUP und EXTRA_CLEANUP, um einen E/A-Bereich anzufordern und ihn dann im Fehlerfall oder beim Entladen des Moduls wieder freizugeben.
component out8; pin out unsigned out_ "Ausgabewert; es werden nur niedrige 8 Bit verwendet"; param r unsigned ioaddr; function _; option count_function; option extra_setup; option extra_cleanup; option constructable no; license "GPL"; // bedeutet GPL v2 oder höher ;; #include <asm/io.h> #define MAX 8 int io[MAX] = {0,}; RTAPI_MP_ARRAY_INT(io, MAX, "E/A-Adressen der out8-Karten"); int get_count(void) { int i = 0; for(i=0; i<MAX && io[i]; i++) { /* Nichts */ } return i; } EXTRA_SETUP() { if(!rtapi_request_region(io[extra_arg], 1, "out8")) { // Setze diesen I/O-Port auf 0, damit EXTRA_CLEANUP die IO-Ports nicht freigibt, // die nie angefordert wurden. 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); }
13.4. hal_loop
component hal_loop; pin out float 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-Schieberegister"; pin in bit in; pin out bit out-# [4]; funktion _ nofp; licencse "GPL"; // bedeutet GPL v2 oder höher ;; int i; for(i=3; i>0; i--) out(i) = out(i-1); out(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 float out; license "GPL"; // bedeutet GPL v2 oder höher ;; #include <unistd.h> void user_mainloop(void) { while(1) { usleep(1000); FOR_ALL_INSTS() out = drand48(); } }
13.7. logic (using personality)
Diese Echtzeitkomponente zeigt, wie man "Persönlichkeit" verwendet, um Arrays variabler Größe und optionale Pins zu erstellen.
component logic "LinuxCNC HAL Komponente mit experimentellen Logikfunktionen"; 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 """ Experimentelle allgemeine 'Logikfunktion' Komponente. Kann 'und', 'oder' und 'xor' von bis zu 16 Eingängen durchführen. Bestimmen Sie den richtigen Wert für 'Persönlichkeit' durch Hinzufügen: .IP \\(bu 4 Die Anzahl der Eingangsstifte, in der Regel von 2 bis 16 .IP \\(bu 256 (0x100), wenn der 'und'-Ausgang gewünscht ist .IP \\(bu 512 (0x200), wenn der 'oder'-Ausgang erwünscht ist IP \\(bu 1024 (0x400), wenn die 'xor'-Ausgabe (exklusives oder) gewünscht ist"""; license "GPL"; // bedeutet GPL v2 or höher ;; 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; }
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 s32 in; pin out bit out1; pin out bit out2; function _; license "GPL"; ;; // allgemeine Pin Set True Funktion void set(hal_bit_t *p){ *p = 1; } // allgemeine Pin Set False Funktion void unset(hal_bit_t *p){ *p = 0; } //Haupt-Funktion (engl. main) FUNCTION(_) { if (in < 0){ set(&out1); unset(&out2); }else if (in >0){ unset(&out2); set(&out2); }else{ unset(&out1); unset(&out2); } }
Diese Komponente verwendet zwei allgemeine Funktionen, um einen HAL-Bit-Pin zu manipulieren, auf den sie referenziert ist.
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