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

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

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

Parentheses indicate optional items. A vertical bar indicates alternatives. Words in CAPITALS indicate variable text, as follows:

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

In the HAL identifier for a pin or parameter, # denotes an array item, and must be used in conjunction with a [SIZE] declaration. The hash marks are replaced with a 0-padded number with the same length as the number of # characters.

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 - An expression involving the variable personality which is nonzero when the pin or parameter should be created.

  • SIZE - Eine Zahl, um die Größe eines Arrays anzugeben. Die Array-Elemente sind von 0 bis SIZE-1 nummeriert.

  • MAXSIZE : CONDSIZE - A number that gives the maximum size of the array, 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 "groff -man" format. For more information on this markup format, see groff_man(7). Remember that halcompile interprets backslash escapes in strings, so for instance to set the italic font for the word example, write:

    "\\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 - One of the HAL types: bit, signed, unsigned, or float. The old names s32 and u32 may also be used, but signed and unsigned are preferred.

  • PINDIRECTION - One of the following: in, out, or io. A component sets a value for an out pin, it reads a value from an in pin, and it may read or set the value of an io pin.

  • 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 - Specifies the initial value of a pin or parameter. If it is not specified, then the default is 0 or FALSE, 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.

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

8.2. Optionen

Die derzeit definierten Optionen sind:

  • option singleton yes - (default: no) Do not create a count module parameter, and always create a single instance. With singleton, items are named component-name.item-name and without singleton, items for numbered instances are named component-name.<num>.item-name.

  • 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 - (default: yes) Normally, the functions rtapi_app_main() and rtapi_app_exit() are automatically defined. With option rtapi_app no, they are not, and must be provided in the C code. Use the following prototypes:

    `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 - (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 float or the name of a type created with typedef). In new components, variable should be used instead.

  • option extra_setup yes - (default: no)
    If specified, call the function defined by EXTRA_SETUP for each instance. If using the automatically defined rtapi_app_main, extra_arg is the number of this instance.

  • 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 - (default: no)
    This option is ignored if the option userspace (see above) is set to no. If userinit is specified, the function userinit(argc,argv) is called before rtapi_app_main() (and thus before the call to hal_init() ). This function may process the commandline arguments or take other actions. Its return type is void; it may call exit() if it wishes to terminate rather than create a HAL component (e.g., because the commandline arguments were invalid).

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

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

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

If a variable is to be of a pointer type, there may not be any space between the "*" and the variable name. Therefore, the following is acceptable:

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

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__)` - 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 or parameter_name - For each pin pin_name or param parameter_name there is a macro which allows the name to be used on its own to refer to the pin or parameter. When pin_name or parameter_name is an array, the macro is of the form pin_name(idx) or param_name(idx), where idx is the index into the pin array. When the array is a variable-sized array, it is only legal to refer to items up to its condsize.

    Wenn es sich um eine bedingte Position handelt, kann nur auf sie verwiesen werden, wenn ihre "Bedingung" einen Wert ungleich Null ergibt.

  • variable_name - For each variable variable_name there is a macro which allows the name to be used on its own to refer to the variable. When variable_name is an array, the normal C-style subscript is used: 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.

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 --personality mit halcompile. Zum Beispiel, um bis zu 128 Persönlichkeitszeiten zu erlauben:

  [sudo] halcompile --personality=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

This component computes the sine and cosine of an input angle in radians. It has different capabilities than the "sine" and "cosine" outputs of siggen, because the input is an angle, rather than running freely based on a "frequency" parameter.

The pins are declared with the names sin_ and cos_ in the source code so that they do not interfere with the functions sin() and cos(). The HAL pins are still called 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

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 <asm/io.h>. It illustrates the use of EXTRA_SETUP 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 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;

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

When loaded, halcmd show comp will show a component called hal_loop. However, the pin shown by halcmd show pin will be loop.0.example, not 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

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

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

The halcompile man page gives details for invoking halcompile.

$ man halcompile

Eine kurze Zusammenfassung der Verwendung von halcompile finden Sie hier:

$ halcompile --help