1. Einführung

This section introduces to the compilation HAL components, i.e. the addition of some machinists' knowledge on how to deal with the machine. It should be noted that such components do not neccessarily deal with the hardware directly. They often do, but not necessarily, e.g. there could be a component to convert between imperial and metric scales, so this section does not require to dive into the interaction with hardware.

Writing a HAL component can be a tedious process, most of it in setup calls to rtapi_ and hal_ functions and associated error checking. halcompile will write all this code for you, automatically. Compiling a HAL component is also much easier when using halcompile, whether the component is part of the LinuxCNC source tree, or outside it.

For instance, when coded in C, a simple component such as "ddt" is around 80 lines of code. The equivalent component is very short when written using the halcompile preprocessor:

Beispiel für eine einfache Komponente
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

To compile a component, if a packaged version of LinuxCNC is used, development packages have to be installed using either Synaptic from the main menu System -> Administration -> Synaptic package manager or by running one of the following commands in a terminal window:

Installation of Development packages for LinuxCNC
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. Verwendung einer Komponente

Components need to be loaded and added to a thread before it can be employed. The provided functionality can then be invoked directly and repeatedly by one of the threads or it is called by other components that have their own respective triggers.

Example HAL script for installing a component (ddt) and executing it every millisecond.
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 Grundlagen.

Um Ihre Komponente zu testen, können Sie den Beispielen im HAL Tutorial folgen.

4. Definitionen

  • component - Eine Komponente ist ein einzelnes Echtzeitmodul, das mit halcmd loadrt geladen wird. Eine .comp-Datei gibt eine Komponente an. Der Komponentenname und der Dateiname müssen übereinstimmen.

  • instance – Eine Komponente kann null oder mehr Instanzen haben. Jede Instanz einer Komponente wird gleich erstellt (sie haben alle dieselben Pins, Parameter, Funktionen und Daten), verhalten sich jedoch unabhängig, wenn ihre Pins, Parameter und Daten unterschiedliche Werte haben.

  • 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).

5. 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.

6. 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.

7. 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:

  1. Alle "#"-Zeichen und alle Zeichen ".", "_" oder "-", die unmittelbar davor stehen, werden entfernt.

  2. Alle verbleibenden "."- und "-"-Zeichen werden durch "_" ersetzt.

  3. 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, signed, unsigned oder float. Die alten Namen "s32" und "u32" können ebenfalls verwendet werden, aber "signiert" und "unsigniert" werden bevorzugt.

  • 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.

7.1. HAL-Funktionen

  • fp - Gibt an, dass die Funktion Gleitkommaberechnungen durchführt.

  • nofp - Indicates that it only performs integer calculations. If neither is specified, fp is assumed. Neither halcompile nor gcc can detect the use of floating-point calculations in functions that are tagged nofp, but the use of such operations results in undefined behavior.

7.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() und rtapi_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 Funktion int export(char *prefix, long extra_arg) auf, um die Pins, Parameter und Funktionen für prefix 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 - (default: no)
    If specified, call the function defined by EXTRA_CLEANUP from the automatically defined rtapi_app_exit or, in case of a detected error, in the automatically defined rtapi_app_main.

  • option userspace yes - (default: no)
    If specified, this file describes a non-realtime (formerly known as "userspace") component, rather than a regular (i.e., realtime) one. A non-realtime component may not have functions defined by the function directive. Instead, after all the instances are constructed, the C function void user_mainloop(void); is called. When this function returns, the component exits. Typically, user_mainloop() will use FOR_ALL_INSTS() to perform the update action for each instance, then sleep for a short time. Another common action in user_mainloop() may be to call the event handler loop of a GUI toolkit.

  • 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: "") This option is ignored if the option userspace (see above) is set to no. When linking a non-realtime component, the arguments given are inserted in the link line. Note that because compilation takes place in a temporary directory, "-L." refers to the temporary directory and not the directory where the .comp source file resides. This option can be set in the halcompile command-line with -extra-link-args="-L…..". This alternative provides a way to set extra flags in cases where the input file is a .c file rather than a .comp file.

  • option extra_compile_args "…" - (default: "") This option is ignored if the option userspace (see above) is set to no. When compiling a non-realtime component, the arguments given are inserted in the compiler command line. If the input file is a .c file this option can be set in the halcompile command-line with --extra-compile-args="-I…..". This alternative provides a way to set extra flags in cases where the input file is a .c file rather than a .comp file.

  • option homemod yes - (default: no)
    Module is a custom Homing module loaded using [EMCMOT]HOMEMOD=modulename .

  • option tpmod yes - (default: no)
    Module is a custom Trajectory Planning (tp) module loaded using [TRAJ]TPMOD=modulename .

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.

7.3. Lizenz und Urheberschaft

  • LICENSE - Specify the license of the module for the documentation and for the MODULE_LICENSE() module declaration. For example, to specify that the module’s license is GPL v2 or later:

    `license "GPL"; // indicates GPL v2 or later`

    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 - Specify the author of the module for the documentation.

7.4. 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 float, u32, s32, 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;

7.5. Kommentare

Einzeilige Kommentare im C++-Stil (//...) und mehrzeilige Kommentare im C-Stil (/* ... */) werden beide im Deklarationsabschnitt unterstützt.

8. 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

9. 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__)` - Use this macro to begin the definition of a realtime function, which was previously declared with function NAME. The function includes a parameter period which is the integer number of nanoseconds between calls to the function.

  • 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() - Use this macro to begin the definition of the function called to perform extra cleanup of the component. Note that this function must clean up all instances of the component, not just one. The "pin_name", "parameter_name", and "data" macros may not be used here.

  • 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() {} - For non-realtime components. This macro iterates over all the defined instances. Inside the body of the loop, the pin_name, parameter_name, and data macros work as they do in realtime functions.

10. 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.

11. 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.

12. Kompilieren

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.

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.

13. Kompilieren von Echtzeitkomponenten 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
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.

Oder es kann in einem Schritt verarbeitet und kompiliert werden, wobei example.ko (oder example.so für den Simulator) im aktuellen Verzeichnis verbleibt:

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 rtexample.comp

Die resultierende Manpage „example.9“ kann angezeigt werden mit

man ./example.9

oder an einen Standardspeicherort für UNIX man pages kopiert.

14. Compiling non-realtime components outside the source tree

halcompile can process, compile, install, and document non-realtime components:

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
Anmerkung
The effect of using both command-line and in-file extra-args is undefined.

15. Beispiele

15.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; }

15.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); }

15.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); }

15.4. hal_loop

component hal_loop;
pin out float example;

This fragment of a component illustrates the use of the hal_ prefix in a component name.

loop is a common name, and the hal_ prefix avoids potential name collissions with other unrelated software. For example, on RTAI realtime systems realtime code runs in the kernel, so if the component were named just loop it could easily conflict with the standard loop kernel module.

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".

15.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;

15.6. rand

This non-realtime component changes the value on its output pin to a new random value in the range (0,1) about once every 1 ms.

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();
    }
}

15.7. logic

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

15.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.

16. Verwendung der Kommandozeile

The halcompile man page gives details for invoking halcompile.

$ man halcompile

Eine kurze Zusammenfassung der Verwendung von halcompile finden Sie hier:

$ halcompile --help