LinuxCNC Documentation
This page is 97% translated. Untranslated text is shown in English.

1. Введение

Этот раздел знакомит с компиляцией компонентов HAL, т. е. добавляет некоторые знания станочников о том, как обращаться с станком. Следует отметить, что такие компоненты не обязательно связаны с аппаратным обеспечением напрямую. Часто так и происходит, но не обязательно, например, может быть компонент для преобразования между британскими и метрическими шкалами, поэтому в этом разделе не требуется углубляться во взаимодействие с оборудованием.

Написание компонента HAL может оказаться утомительным процессом, большая часть которого связана с вызовами функций rtapi_ и hal_ и связанной с ними проверкой ошибок. halcompile автоматически напишет за вас весь этот код. Компилировать компонент HAL также намного проще при использовании halcompile, независимо от того, является ли компонент частью исходного дерева LinuxCNC или вне его.

Например, при кодировании на C простой компонент, такой как "ddt", занимает около 80 строк кода. Эквивалентный компонент очень короткий, если написан с использованием препроцессора halcompile:

Пример простого компонента
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. Installing

Чтобы скомпилировать компонент, если используется упакованная версия LinuxCNC, пакеты разработки необходимо установить либо с помощью Synaptic из главного меню System → Administration → Synaptic package manager, либо выполнив одну из следующих команд в окне терминала. :

Установка пакетов разработки для LinuxCNC
sudo apt install linuxcnc-dev
# or
sudo apt install linuxcnc-uspace-dev

Другой метод — использовать менеджер пакетов Synaptic из меню «Приложения» для установки пакетов linuxcnc-dev или linuxcnc-uspace-dev.

3. Компиляция

3.1. Внутри дерева исходников

Поместите файл .comp в исходный каталог linuxcnc/src/hal/components и повторно запустите make. Файлы Comp автоматически обнаруживаются системой сборки.

Если файл .comp является драйвером для оборудования, его можно поместить в linuxcnc/src/hal/drivers и он будет создан, если только LinuxCNC не настроен как симулятор не в реальном времени.

3.2. Компоненты реального времени вне дерева исходного кода

halcompile может обрабатывать, компилировать и устанавливать компонент реального времени за один шаг, помещая rtexample.ko в каталог модулей реального времени LinuxCNC:

[sudo] halcompile --install rtexample.comp
Note
sudo (для прав root) необходим при использовании LinuxCNC из установки пакета deb. При использовании сборки Run-In-Place (RIP) права root не требуются.

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

Или он может просто обработать, оставив example.c в текущем каталоге:

halcompile rtexample.comp

halcompile также может скомпилировать и установить компонент, написанный на C, используя параметры --install и --compile, показанные выше:

[sudo] halcompile --install rtexample2.c

Документация в формате man также может быть создана на основе информации в разделе объявлений:

halcompile --document -o example.9 rtexample.comp

Полученную справочную страницу example.9 можно просмотреть с помощью

man ./example.9

или скопировать в стандартное место для страниц руководства.

3.3. Компоненты не реального времени вне дерева исходного кода

halcompile может обрабатывать, компилировать, устанавливать и документировать компоненты, не работающие в реальном времени:

halcompile non-rt-example.comp
halcompile --compile non-rt-example.comp
[sudo] halcompile --install non-rt-example.comp
halcompile --document non-rt-example.comp

Для некоторых библиотек (например, modbus) может потребоваться добавить дополнительные аргументы компилятора и компоновщика, чтобы компилятор мог найти и связать библиотеки. В случае файлов .comp это можно сделать с помощью операторов "option" в файле .comp. Для файлов .c это невозможно, поэтому вместо этого можно использовать параметры --extra-compile-args и --extra-link-args. Например, эту командную строку можно использовать для компиляции компонента vfdb_vfd.c вне дерева.

halcompile --userspace --install --extra-compile-args="-I/usr/include/modbus" --extra-link-args="-lm -lmodbus -llinuxcncini" vfdb_vfd.c
Note
Эффект от использования дополнительных аргументов как в командной строке, так и в файле не определен.

4. Использование компонента

Компоненты необходимо загрузить и добавить в поток, прежде чем его можно будет использовать. Предоставленная функциональность может затем напрямую и неоднократно вызываться одним из потоков или другими компонентами, имеющими свои собственные триггеры.

Пример сценария HAL для установки компонента (ddt) и его выполнения каждую миллисекунду.
loadrt threads name1=servo-thread period1=1000000
loadrt ddt
addf ddt.0 servo-thread

Дополнительную информацию о loadrt и addf можно найти в HAL Основы.

Чтобы протестировать свой компонент, вы можете следовать примерам в HAL Учебник.

5. Определения

  • 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. Создание экземпляра

Для singleton один экземпляр создается при загрузке компонента.

Для не-singleton параметр модуля count определяет, сколько пронумерованных экземпляров будет создано. Если count не указано, параметр модуля names определяет, сколько именованных экземпляров будет создано. Если не указано ни количество, ни имена, создается один пронумерованный экземпляр.

7. Неявные параметры

Функциям неявно передается параметр period, который представляет собой время в наносекундах последнего периода выполнения компонента. Функции, использующие числа с плавающей запятой, также могут ссылаться на f period, который представляет собой время с плавающей запятой в секундах, или (период*1e-9). Это может быть полезно в компонентах, которым требуется информация о времени. См. также «период опции» ниже.

8. Syntax

Файл .comp состоит из некоего количества деклараций, за которыми следует ;; в отдельной строке, за которой следует код C, реализующий функции модуля.

Декларации включают в себя:

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

Круглые скобки указывают на необязательные элементы. Вертикальная черта обозначает альтернативы. Слова, написанные ЗАГЛАВНЫМИ буквами, обозначают изменяемый текст следующим образом:

  • NAME - Стандартный идентификатор C

  • STARREDNAME - Идентификатор C с нулем или более * перед ним. Этот синтаксис можно использовать для объявления переменных экземпляра, которые являются указателями. Обратите внимание, что из-за грамматики между * и именем переменной может отсутствовать пробел.

  • HALNAME - Расширенный идентификатор. При использовании для создания идентификатора HAL все подчеркивания заменяются дефисами, а любые конечные дефисы или точки удаляются, так что "this_name_" будет преобразовано в "this-name", а если имя "_", то завершающая точка также удаляется, так что "function _" дает имя функции HAL, например "component.<num>" вместо "component.<num>."

    Если он присутствует, префикс hal_ удаляется из начала имени компонента при создании контактов, параметров и функций.

В идентификаторе HAL для контакта или параметра # обозначает элемент массива и должен использоваться вместе с объявлением [SIZE]. Хэш-метки заменяются числом, дополненным 0, той же длины, что и количество символов #.

При использовании для создания идентификатора C к HALNAME применяются следующие изменения:

  1. Любые символы «#», а также любые символы ".", "_" или "-" непосредственно перед ними удаляются.

  2. Все оставшиеся "." и символы "-" заменяются на "_".

  3. Повторяющиеся символы "_" заменяются одним символом "\_".

Завершающий символ "_" сохраняется, поэтому можно использовать идентификаторы HAL, которые в противном случае могли бы конфликтовать с зарезервированными именами или ключевыми словами (например, min).

HALNAME C идентификатор HAL Идентификатор

x_y_z

x_y_z

x-y-z

x-y.z

x_y_z

x-y.z

x_y_z_

x_y_z_

x-y-z

x.##.y

x_y(MM)

x.MM.z

x.##

x(MM)

x.MM

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 — выражение, включающее переменную personality, которая не равна нулю, когда необходимо создать вывод или параметр.

  • 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 - Строка, документирующая элемент. Строка может быть строкой в стиле C с "двойными кавычками", например:

    "Выбирает желаемые параметры импульса: TRUE означает срез, FALSE означает фронт"

    или строку в "тройных кавычках" в стиле Python, которая может включать встроенные символы новой строки и кавычки, такие как:

    """The effect of this parameter, also known as "the orb of zot",
    will require at least two paragraphs to explain.
    
    Hopefully these paragraphs have allowed you to understand "zot"
    better."""

    Или строке может предшествовать буквальный символ r, и в этом случае строка интерпретируется как необработанная строка Python.

    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, uint or real.

  • 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 - One of the following: r or rw. 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 0 or FALSE, depending on the type of the item.

  • HEADERFILE - Имя заголовочного файла в двойных кавычках (include "myfile.h";) или в угловых скобках (include <systemfile.h>;). Файл заголовка будет включен (с использованием #include языка C) в начало файла, перед объявлениями контактов и параметров.

Note

Transitionally, si32 and ui32 are supported as pin and param types. These read the lower 32-bit value (truncating!) and write 32-bit (properly sign-extended for the underlying type). The underlying values are always correct.

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:

HAL type C type Description

bool

rtapi_bool

Boolean value

real

rtapi_real

Floating point value

sint

rtapi_sint

Signed integer value

uint

rtapi_uint

Unsigned integer value

8.1. Варианты

В настоящее время определены следующие параметры:

  • option singleton yes - (по умолчанию: нет)
    Не создавайте параметр модуля count и всегда создавайте один экземпляр. При использовании singleton элементы называются component-name.item-name, а без singleton элементы для пронумерованных экземпляров называются component-name.<num>.item-name.

  • option default_count number - (по умолчанию: 1)
    Обычно параметр модуля count по умолчанию равен 1. Если он указан, тогда count по умолчанию принимает указанное значение.

  • 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 - (по умолчанию: yes)
    Обычно функции rtapi_app_main() и rtapi_app_exit() определяются автоматически. При option rtapi_app no они отсутствуют и должны быть указаны в коде C. Используйте следующие прототипы:

    `int rtapi_app_main(void);`
    
    `void rtapi_app_exit(void);`

    При реализации собственного rtapi_app_main() вызовите функцию int export(char *prefix, long extra_arg), чтобы зарегистрировать контакты, параметры и функции для prefix.

  • 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 - (по умолчанию: no)
    Если указано, вызовите функцию, определенную EXTRA_SETUP, для каждого экземпляра. При использовании автоматически определенного rtapi_app_main extra_arg — это номер этого экземпляра.

  • option extra_cleanup yes - (по умолчанию: no)
    Если указано, вызовите функцию, определенную EXTRA_CLEANUP, из автоматически определенного rtapi_app_exit или, в случае обнаружения ошибки, из автоматически определенного rtapi_app_main.

  • 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 - (по умолчанию: no)
    Если указано, этот файл описывает компонент не реального времени (ранее известный как "userspace"), а не обычный (т. е. realtime). Компонент, не работающий в режиме реального времени, может не иметь функций, определенных директивой function. Вместо этого, после создания всех экземпляров, вызывается функция C void user_mainloop(void);. Когда эта функция возвращает значение, компонент завершает работу. Обычно user_mainloop() использует FOR_ALL_INSTS() для выполнения действия обновления для каждого экземпляра, а затем на короткое время переходит в режим сна. Другим распространенным действием в user_mainloop() может быть вызов цикла обработчика событий набора инструментов ГИП.

  • option userinit yes - (по умолчанию: no)
    Эта опция игнорируется, если для опции пространство пользователя (см. выше) установлено значение нет. Если указан userinit, функция userinit(argc,argv) вызывается перед rtapi_app_main() (и, следовательно, перед вызовом hal_init()). Эта функция может обрабатывать аргументы командной строки или выполнять другие действия. Тип возвращаемого значения — void; он может вызвать exit(), если хочет завершить работу, а не создать компонент HAL (например, из-за недопустимых аргументов командной строки).

  • option extra_link_args "…​" - (по умолчанию: "")
    Эта опция игнорируется, если для опции userspace (см. выше) установлено no. При линковании компонента, не работающего в реальном времени, указанные аргументы вставляются в строку ссылки. Обратите внимание: поскольку компиляция происходит во временном каталоге "-L". относится к временному каталогу, а не к каталогу, в котором находится исходный файл .comp. Эту опцию можно установить в командной строке halcompile с помощью -extra-link-args="-L…​..". Эта альтернатива позволяет установить дополнительные флаги в тех случаях, когда входной файл представляет собой файл .c, а не файл .comp.

  • option extra_compile_args "…​" - (по умолчанию: "")
    Эта опция игнорируется, если для опции userspace (см. выше) установлено значение no. При компиляции компонента, не работающего в реальном времени, указанные аргументы вставляются в командную строку компилятора. Если входной файл представляет собой файл .c, этот параметр можно установить в командной строке halcompile с помощью --extra-compile-args="-I…​..". Эта альтернатива позволяет установить дополнительные флаги в тех случаях, когда входной файл представляет собой файл .c, а не файл .comp.

  • option homemod yes - (по умолчанию: no)
    Модуль — это пользовательский модуль Homing, загружаемый с помощью `[EMCMOT]HOMEMOD=`modulename .

  • option tpmod yes - (по умолчанию: no)
    Модуль — это пользовательский модуль Trajectory Planning (tp), загружаемый с помощью `[TRAJ]TPMOD=`modulename .

  • option period no - (default: yes)
    Control the implicit period parameter of the function(s) defined in the component. A standard function has an implicit parameter period. Many components do no use the period parameter and would cause a "unused parameter" compiler warning. Setting option period no creates a function declaration omitting the period parameter preventing the warning. Setting this option will also prevent fperiod from being defined, as it depends on period.

Если VALUE опции не указано, это эквивалентно указанию option … yes.
Результат присвоения опции неподходящего значения не определен.
Результат использования любой другой опции не определен.

8.2. Лицензия и авторство

  • LICENSE — укажите лицензию модуля для документации и для объявления модуля MODULE_LICENSE(). Например, чтобы указать, что лицензия модуля — GPL v2 или новее:

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

    Дополнительную информацию о значении MODULE_LICENSE() и дополнительных идентификаторах лицензий см. в разделе «<linux/module.h>» или на странице руководства «rtapi_module_param(3)».

    Это заявление обязательно.

  • AUTHOR - Укажите автора модуля для документации.

8.3. Поэкземплярное хранилище данных

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

Если переменная должна иметь тип указателя, между знаком "*" и именем переменной не может быть пробела. Поэтому допустимо следующее:

variable int *example;

А это не допустимо:

variable int* badexample;
variable int * badexample;

8.4. Comments

В разделе объявлений поддерживаются однострочные комментарии в стиле C++ (//...) и многострочные комментарии в стиле C (/* ... */).

9. Ограничения

Хотя HAL позволяет контакту, параметру и функции иметь одно и то же имя, «halcompile» этого не делает.

Имена переменных и функций, которые нельзя использовать или которые могут вызвать проблемы, включают:

  • Все, что начинается с _comp.

  • comp_id

  • fperiod

  • rtapi_app_main

  • rtapi_app_exit

  • extra_setup

  • extra_cleanup

  • post_export

10. Удобные макросы

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__)` — используйте этот макрос, чтобы начать определение функции реального времени, которая ранее была объявлена с помощью function NAME. Функция включает параметр period, который представляет собой целое число наносекунд между вызовами функции. См. также «период опции» выше.

  • EXTRA_SETUP() — используйте этот макрос, чтобы начать определение функции, вызываемой для выполнения дополнительной настройки этого экземпляра. Возвращает отрицательное значение UNIX errno, чтобы указать на ошибку (например, return -EBUSY, если не удалось зарезервировать порт ввода-вывода), или 0, чтобы указать на успех.

  • EXTRA_CLEANUP() — используйте этот макрос, чтобы начать определение функции, вызываемой для дополнительной очистки компонента. Обратите внимание, что эта функция должна очищать все экземпляры компонента, а не только один. Макросы «pin_name», «parameter_name» и «data» здесь использовать нельзя.

  • 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 или parameter_name — для каждого контакта имя_контакта или параметра имя_параметра существует макрос, который позволяет использовать имя отдельно для ссылки на контакт или параметр. Если pin_name или parameter_name представляет собой массив, макрос имеет форму pin_name(idx) или param_name(idx), где idx — это индекс в массиве контактов. Когда массив представляет собой массив переменного размера, разрешено ссылаться только на элементы до его condsize.

    Если элемент является условным элементом, ссылаться на него можно только в том случае, если его условие оценено как ненулевое значение.

  • variable_name — для каждой переменной variable_name существует макрос, который позволяет использовать имя отдельно для ссылки на переменную. Когда variable_name представляет собой массив, используется обычный индекс в стиле C: variable_name[idx].

  • data — если указаны "option data", этот макрос разрешает доступ к данным экземпляра.

  • fperiod — число секунд с плавающей запятой между вызовами этой функции реального времени. См. также «период опции» выше.

  • FOR_ALL_INSTS() {…​} — для компонентов, не работающих в режиме реального времени. Этот макрос перебирает все определенные экземпляры. Внутри тела цикла макросы pin_name, parameter_name и data работают так же, как и в функциях реального времени.

11. Компоненты с одной функцией

Если компонент имеет только одну функцию и строка "FUNCTION" не появляется нигде после ;;, то часть после ;; все это считается телом единственной функции компонента. Пример этого см. в Simple Comp.

12. Индивидуальность компонента

Если компонент имеет какие-либо контакты или параметры с условием "if" или "[maxsize : condsize]", он называется компонентом с "индивидуальностью". Индивидуальность каждого экземпляра определяется при загрузке модуля. Индивидуальность можно использовать для создания контактов только при необходимости. Например, в логическом компоненте используется индивидуальность, чтобы обеспечить переменное количество входных контактов для каждого логического элемента и обеспечить выбор любой из основных логических функций и, или и xor.

Число разрешенных элементов индивидуальности по умолчанию устанавливается во время компиляции (64). Значение по умолчанию применяется к многочисленным компонентам, включенным в дистрибутив, созданным с использованием halcompile.

Чтобы изменить разрешенное количество элементов индивидуальности для пользовательских компонентов, используйте опцию --personality с halcompile. Например, чтобы разрешить до 128 индивидуальных раз:

  [sudo] halcompile --personalities=128 --install ...

При использовании компонентов с индивидуальностью обычно указывается элемент индивидуальности для каждого указанного экземпляра компонента. Пример для 3 экземпляров логического компонента:

loadrt logic names=and4,or3,nand5, personality=0x104,0x203,0x805
Note
Если в строке loadrt указано больше экземпляров, чем индивидуальностей, экземплярам с неуказанными индивидуальностями присваивается индивидуальность 0. Если запрошенное количество экземпляров превышает количество разрешенных индивидуальностей, индивидуальность назначаются путем индексации по модулю количества разрешенных индивидуальностей. Печатается сообщение, обозначающее такие назначения.
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:

EXTRA_SETUP(){
    // Silence warnings for the unused arguments.
    (void)prefix;
    (void)extra_arg;
    if (personality < 1) {
        rtapi_print_msg(RTAPI_MSG_ERR,
            "mycomp: personality must be >= 1 (use personality=N to set the number of channels)\n");
        return -EINVAL;
    }
    return 0;
}

13. Examples

13.1. constant

Обратите внимание, что объявление "function _" создает функции с именем "constant.0" и т. д. Имя файла должно совпадать с именем компонента.

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

Этот компонент вычисляет синус и косинус входного угла в радианах. Он имеет другие возможности, чем выходы "sine" и "cosine" siggen, потому что вход представляет собой угол, а не работает свободно на основе параметра "frequency".

В исходном коде выводы объявлены с именами sin_ и cos_, чтобы они не мешали функциям sin() и cos(). Контакты HAL по-прежнему называются 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;

Этот фрагмент компонента иллюстрирует использование префикса hal_ в имени компонента.

loop — это общее имя, а префикс hal_ позволяет избежать потенциальных конфликтов имен с другим несвязанным программным обеспечением. Например, в системах реального времени RTAI код реального времени выполняется в ядре, поэтому, если бы компонент назывался просто loop, он мог бы легко конфликтовать со стандартным модулем ядра loop.

При загрузке halcmd show comp покажет компонент под названием hal_loop. Однако вывод, отображаемый halcmd show pin, будет loop.0.example, а не hal-loop.0.example.

13.5. arraydemo

Этот компонент реального времени иллюстрирует использование массивов фиксированного размера:

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

Этот компонент, работающий не в реальном времени, меняет значение на своем выходном контакте на новое случайное значение в диапазоне (0,1) примерно раз в 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. logic (using personality)

Этот компонент реального времени показывает, как использовать "индивидуальность" для создания массивов переменного размера и дополнительных выводов.

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

Типичная линия нагрузки для этого компонента может быть такой

loadrt logic count=3 personality=0x102,0x305,0x503

который создает следующие контакты:

  • Элемент И с двумя входами: logic.0.and, logic.0.in-00, logic.0.in-01

  • Элемент И с 5-ю входами и элементы ИЛИ: 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,

  • Элементы И с тремя входами и элементы Исключающее ИЛИ: logic.2.and, logic.2.xor, logic.2.in-00, logic.2.in-01, logic.2.in-02

13.8. Общие функции

В этом примере показано, как вызывать функции из основной функции. Он также показывает, как передать ссылку на контакты HAL этим функциям.

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. Использование командной строки

Страница руководства halcompile содержит подробную информацию о вызове halcompile.

$ man halcompile

Краткое описание использования halcompile представлено следующим образом:

$ halcompile --help