1. Вступ
У цьому розділі представлено компоненти компілятора HAL, тобто додаток знань деяких механіків про те, як працювати з машиною. Слід зазначити, що такі компоненти не обов’язково безпосередньо пов’язані з апаратним забезпеченням. Часто це так, але не обов’язково, наприклад, може бути компонент для перетворення між імперською та метричною системами вимірювання, тому цей розділ не вимагає заглиблюватися у взаємодію з апаратним забезпеченням.
Написання компонента HAL може бути нудним процесом, більша частина якого полягає у викликах функцій rtapi_ та hal_ та пов’язаній з цим перевірці помилок. halcompile автоматично напише весь цей код за вас. Компіляція компонента HAL також набагато простіша при використанні halcompile, незалежно від того, чи є компонент частиною дерева джерел LinuxCNC, чи знаходиться поза ним.
Наприклад, простий компонент, такий як "ddt", написаний на C, займає близько 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. Встановлення
Щоб скомпілювати компонент, якщо використовується пакетна версія LinuxCNC, пакети розробки необхідно встановити за допомогою Synaptic з головного меню «Система → Адміністрування → Менеджер пакетів Synaptic» або запустивши одну з наступних команд у терміналі:
sudo apt install linuxcnc-dev # або 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
Документацію в ручному форматі також можна створити з інформації в розділі оголошення:
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. Використання компонента
Компоненти потрібно завантажити та додати до потоку, перш ніж їх можна буде використовувати. Надану функціональність можна потім викликати безпосередньо та повторно одним із потоків, або її викликають інші компоненти, які мають власні відповідні тригери.
loadrt threads name1=servo-thread period1=1000000 loadrt ddt addf ddt.0 servo-thread
Більше інформації про loadrt та addf можна знайти у Основи HAL.
Щоб протестувати свій компонент, ви можете скористатися прикладами з HAL Tutorial.
5. Визначення
-
component - A component is a single real-time module, which is loaded with
Halcmd loadrt. One.compfile specifies one component. The component name and file name must match. -
instance - A component can have zero or more instances. Each instance of a component is created equal (they all have the same pins, parameters, functions, and data) but behave independently when their pins, parameters, and data have different values.
-
singleton - It is possible for a component to be a "singleton", in which case exactly one instance is created. It seldom makes sense to write a singleton component, unless there can literally only be a single object of that kind in the system (for instance, a component whose purpose is to provide a pin with the current UNIX time, or a hardware driver for the internal PC speaker).
6. Створення екземпляра
Для синглтона один екземпляр створюється під час завантаження компонента.
Для не-однозаписового об’єкта параметр модуля «count» визначає, скільки пронумерованих екземплярів буде створено. Якщо «count» не вказано, параметр модуля «names» визначає, скільки іменованих екземплярів буде створено. Якщо не вказано ні «count», ні «names», створюється один пронумерований екземпляр.
7. Неявні параметри
Функціям неявно передається параметр «period», який є часом у наносекундах від останнього періоду виконання компонента. Функції, що використовують плаваючу точку, також можуть посилатися на «fperiod», який є часом у секундах з плаваючою точкою, або (period*1e-9). Це може бути корисно в компонентах, які потребують інформації про час. Див. також «option period» нижче.
8. Синтаксис
Файл .comp складається з кількох оголошень, за якими йде ;; в окремому рядку, а потім код на C, що реалізує функції модуля.
Декларації включають:
-
component HALNAME (DOC);
-
pin PIN-НАПРЯМОК ТИПУ HALNAME ([РОЗМІР]|[МАКСИМУМ: РОЗМІР УМОВИ]) (якщо УМОВА) (= ПОЧАТКОВЕЗНАЧЕННЯ) (DOC);
-
param НАПРЯМОК_ПАРАМЕТРУ ТИП HALNAME ([РОЗМІР]|[МАКСИМУМ: РОЗМІР_УМОВИ]) (якщо УМОВА) (= ПОЧАТКОВЕ_ЗНАЧЕННЯ) (DOC) ;
-
function HALNAME (fp | nofp) (DOC);
-
option OPT (VALUE);
-
variable CTYPE STARREDNAME ([SIZE]);
-
опис DOC;
-
приклади DOC;
-
нотатки DOC;
-
див. також DOC;
-
ліцензія LICENSE;
-
автор AUTHOR;
-
включають HEADERFILE;
Дужки позначають додаткові елементи. Вертикальна риски позначають альтернативні варіанти. Слова, написані «ВЕЛИКИМИ ЛІТЕРАМИ», позначають змінний текст, як показано нижче:
-
NAME – стандартний ідентифікатор C
-
STARREDNAME - Ідентифікатор C з нулем або більше символів * перед ним. Цей синтаксис можна використовувати для оголошення змінних екземпляру, які є покажчиками. Зверніть увагу, що через граматику між символом * та іменем змінної не може бути пробілів.
-
«HALNAME» — розширений ідентифікатор. При використанні для створення ідентифікатора HAL усі підкреслення замінюються на тире, а всі кінцеві тире або крапки видаляються, так що «this_name_» перетворюється на «this-name», а якщо ім’я «_», то кінцева крапка також видаляється, так що «function _» дає ім’я функції HAL, наприклад «component. <num>» замість «component.<num>»
Якщо присутній, префікс hal_ видаляється з початку назви компонента під час створення виводів, параметрів та функцій.
В ідентифікаторі HAL для контакту або параметра символ # позначає елемент масиву і повинен використовуватися разом з оголошенням «[SIZE]». Символи сітки замінюються числом, доповненим нулями, довжина якого дорівнює кількості символів #.
Під час використання для створення ідентифікатора C до HALNAME застосовуються такі зміни:
-
Будь-які символи "#" та будь-які символи ".", "_" або "-" безпосередньо перед ними вилучається.
-
Будь-які символи "." та "-" замінюються на "_".
-
Повторювані символи "_" замінюються на один символ "\_".
Заключний символ "_" зберігається, щоб можна було використовувати ідентифікатори HAL, які в іншому випадку конфліктували б із зарезервованими іменами або ключовими словами (наприклад, min).
| ІМ’Я ХАЛЬМАНА | Ідентифікатор 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, взятий у потрійні лапки, який може містити вбудовані символи нового рядка та лапок, наприклад:
"""Для пояснення впливу цього параметра, також відомого як "сфера зота", знадобиться щонайменше два абзаци. Сподіваюся, ці абзаци допомогли вам зрозуміти "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,uintorreal. -
PINDIRECTION - One of the following:
in,out, orio. A component sets a value for an out pin, it reads a value from aninpin, and it may read or set the value of aniopin. -
PARAMDIRECTION - One of the following:
rorrw. A component sets a value for a r parameter, and it may read or set the value of a rw parameter. -
STARTVALUE - Specifies the initial value of a pin or parameter. If it is not specified, then the default is
0orFALSE, depending on the type of the item. -
HEADERFILE - Ім’я файлу заголовка, вказане в подвійних лапках (
include "myfile.h";) або в кутових дужках (include <systemfile.h>;). Файл заголовка буде включений (за допомогою #include мови C) у верхній частині файлу, перед оголошеннями контактів і параметрів.
|
Note
|
Transitionally, You should retire all 32-bit pins and params and upgrade to sint and uint. Please beware of local variable truncation in the upgrade process. The proper variable types matching for all HAL types are:
|
8.1. Опції
Наразі визначені такі опції:
-
option singleton yes - (за замовчуванням: no)
Не створювати параметр модуля count і завжди створювати один екземпляр. З singleton елементи називаються component-name.item-name, а без singleton елементи для пронумерованих екземплярів називаються component-name.<num>.item-name. -
option default_count number - (default: 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 - (за замовчуванням: ні)
Якщо вказано, викликати функцію, визначену параметром EXTRA_SETUP, для кожного екземпляра. Якщо використовується автоматично визначений параметр rtapi_app_main, extra_arg – це номер цього екземпляра. -
option extra_cleanup yes - (за замовчуванням: ні)
Якщо вказано, викликати функцію, визначену параметром 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»), а не звичайний (тобто в режимі реального часу) компонент. Компонент, що не працює в режимі реального часу, може не мати функцій, визначених директивою function. Натомість, після створення всіх екземплярів, викликається функція Cvoid user_mainloop(void);. Коли ця функція повертається, компонент завершується. Зазвичай, user_mainloop() використовує FOR_ALL_INSTS() для виконання дії оновлення для кожного екземпляра, а потім короткочасно переходить у режим очікування. Іншою поширеною дією в user_mainloop() може бути виклик циклу обробки подій інструментарію графічного інтерфейсу користувача. -
option userinit yes - (за замовчуванням: no)
Ця опція ігнорується, якщо опція userspace (див. вище) встановлена на 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 - (за замовчуванням: ні)
Модуль — це користувацький модуль самонаведення, що завантажується за допомогою `[EMCMOT]HOMEMOD=`modulename . -
option tpmod yes - (за замовчуванням: ні)
Модуль – це користувацький модуль планування траєкторії (tp), що завантажується за допомогою `[TRAJ]TPMOD=`modulename . -
«option period no» — (за замовчуванням: yes)
Керує неявним параметром «period» функції (функцій), визначеної (визначених) у компоненті. Стандартна функція має неявний параметр «period». Багато компонентів не використовують параметр «period», що спричиняє попередження компілятора про «невикористаний параметр». Встановлення «option period no» створює оголошення функції, в якому опускається параметр «period», що запобігає попередженню. Встановлення цієї опції також запобігає визначенню «fperiod», оскільки воно залежить від «period».
Якщо значення опції не вказано, це еквівалентно вказівці «опція … так».
Результат присвоєння опції невідповідного значення є невизначеним.
Результат використання будь-якої іншої опції є невизначеним.
8.2. Ліцензія та авторство
-
LICENSE- Вкажіть ліцензію модуля для документації та для оголошення модуля MODULE_LICENSE(). Наприклад, щоб вказати, що ліцензія модуля — GPL версії 2 або пізнішої версії:`ліцензія "GPL"; // вказує на GPL версії 2 або пізнішої версії`
Для отримання додаткової інформації про значення 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. Коментарі
Однорядкові коментарі в стилі 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, який є цілим числом наносекунд між викликами функції. Див. також option period вище. -
EXTRA_SETUP()– Використовуйте цей макрос для початку визначення функції, яка викликається для виконання додаткового налаштування цього екземпляра. Повертає від’ємне значення UNIX errno для позначення помилки (наприклад, 'return -EBUSY. -
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» або «parameter_name» є масивом, макрос має вигляд «pin_name(idx)» або «param_name(idx)», де «idx» є індексом у масиві контактів. Коли масив є масивом змінного розміру, дозволено посилатися лише на елементи до його «condsize».
Коли елемент є умовним елементом, посилання на нього допустиме лише тоді, коли його «умова» оцінюється як ненульове значення.
-
variable_name - Для кожної змінної variable_name існує макрос, який дозволяє використовувати ім’я самостійно для посилання на змінну. Коли variable_name є масивом, використовується звичайний індекс у стилі C: variable_name[idx].
-
data – Якщо вказано "option data", цей макрос дозволяє доступ до даних екземпляра.
-
fperiod – кількість секунд у форматі з плаваючою комою між викликами цієї функції реального часу. Див. також option period вище.
-
FOR_ALL_INSTS() {…}- Для компонентів, що не працюють у режимі реального часу. Цей макрос повторює всі визначені екземпляри. Усередині тіла циклу макроси «pin_name», «parameter_name» та «data» працюють так само, як і в функціях реального часу.
11. Компоненти з однією функцією
Якщо компонент має тільки одну функцію і рядок «FUNCTION» не з’являється ніде після «;;», то частина після «;;» вважається тілом єдиної функції компонента. Дивіться Simple Comp для прикладу цього.
12. Компонент особистості
Якщо компонент має будь-які виводи або параметри з «умовою if» або «[maxsize : condsize]», він називається компонентом з «особистістю». «Особистість» кожного екземпляра визначається під час завантаження модуля. «Особистість» може використовуватися для створення виводів тільки за потреби. Наприклад, особистість використовується в компоненті «логіка», щоб забезпечити змінну кількість вхідних контактів для кожного логічного вентиля і дозволити вибір будь-якої з основних булевих логічних функцій «and», «or» і «xor».
Кількість дозволених елементів «персоналізації» за замовчуванням встановлюється під час компіляції (64). Значення за замовчуванням застосовується до численних компонентів, що входять до дистрибутиву та зібрані за допомогою halcompile.
Щоб змінити дозволену кількість елементів особистості для компонентів, створених користувачем, використовуйте опцію --personalities з 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:
|
13. Приклади
13.1. постійний
Зверніть увагу, що оголошення "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. синхронізація
Цей компонент обчислює синус і косинус вхідного кута в радіанах. Він має інші можливості, ніж виходи «синус» і «косинус» siggen, оскільки вхідним параметром є кут, а не «частота», що змінюється вільно.
Виводи оголошені у вихідному коді з іменами 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. демо-масиву
Цей компонент реального часу ілюструє використання масивів фіксованого розміру:
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. ранд
Цей компонент, що не працює в реальному часі, змінює значення на своєму вихідному контакті на нове випадкове значення в діапазоні (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. логіка (використовуючи особистість)
Цей компонент реального часу показує, як використовувати "персоналізацію" для створення масивів змінного розміру та додаткових виводів.
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
що створює такі піни:
-
2-входовий елемент І:
логіка 0.і,логіка 0.в-00,логіка 0.в-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, -
3-входові елементи І та Виключаюче АБО:
logic.2.and,logic.2.xor,logic.2.in-00,logic.2.in-01,logic.2.in-02
13.8. Загальні функції
У цьому прикладі показано, як викликати функції з функції main. Також показано, як передавати посилання на виводи HAL цим функціям.
component example;
pin in sint in;
pin out bool out1;
pin out bool out2;
номер періоду опції;
функція _;
ліцензія "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