1. Вступ
У цьому розділі представлено компоненти компілятора HAL, тобто додаток знань деяких механіків про те, як працювати з машиною. Слід зазначити, що такі компоненти не обов’язково безпосередньо пов’язані з апаратним забезпеченням. Часто це так, але не обов’язково, наприклад, може бути компонент для перетворення між імперською та метричною системами вимірювання, тому цей розділ не вимагає заглиблюватися у взаємодію з апаратним забезпеченням.
Написання компонента HAL може бути нудним процесом, більша частина якого полягає у викликах функцій rtapi_ та hal_ та пов’язаній з цим перевірці помилок. halcompile автоматично напише весь цей код за вас. Компіляція компонента HAL також набагато простіша при використанні halcompile, незалежно від того, чи є компонент частиною дерева джерел LinuxCNC, чи знаходиться поза ним.
Наприклад, простий компонент, такий як "ddt", написаний на C, займає близько 80 рядків коду. Еквівалентний компонент дуже короткий, якщо його написати за допомогою препроцесора halcompile:
component ddt "Обчисліть похідну вхідної функції";
pin in float in;
pin out float out;
variable double old;
option period no;
function _;
ліцензія "GPL"; // вказує на GPL версії 2 або пізнішої версії
;;
float tmp = in;
out = (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-права не потрібні. |
Або ж він може обробляти та компілюватися за один крок, залишаючи example.ko (або example.so для симулятора) у поточному каталозі:
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. Визначення
-
компонент – Компонент – це окремий модуль реального часу, який завантажується за допомогою
Halcmd loadrt. Один файл.compвизначає один компонент. Назва компонента та назва файлу повинні збігатися. -
інстанція - Компонент може мати нуль або більше інстанцій. Кожна інстанція компонента створюється однаковою (всі вони мають однакові контакти, параметри, функції та дані), але поводиться незалежно, коли їхні контакти, параметри та дані мають різні значення.
-
singleton - Компонент може бути «singleton», і в цьому випадку створюється тільки один екземпляр. Рідко має сенс писати компонент «singleton», якщо тільки в системі не може бути буквально тільки один об’єкт такого типу (наприклад, компонент, призначенням якого є надання контакту поточного часу UNIX, або драйвер апаратного забезпечення для внутрішнього динаміка ПК).
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 |
-
if CONDITION - Вираз, що включає змінну «personality», яка не дорівнює нулю на момент створення виводу або параметра.
-
SIZE - Число, яке визначає розмір масиву. Елементи масиву нумеруються від 0 до SIZE-1.
-
MAXSIZE : CONDSIZE - Число, яке визначає максимальний розмір масиву, за яким слідує вираз, що містить змінну «personality» і який завжди обчислюється як менше за «MAXSIZE». При створенні масиву його розмір буде дорівнювати «CONDSIZE».
-
DOC - Рядок, що документує елемент. Рядок може бути рядком у стилі C, взятим у подвійні лапки, наприклад:
"Вибирає потрібне ребро: TRUE означає падіння, FALSE означає зростання"або рядок у стилі Python, взятий у потрійні лапки, який може містити вбудовані символи нового рядка та лапок, наприклад:
"""Для пояснення впливу цього параметра, також відомого як "сфера зота", знадобиться щонайменше два абзаци. Сподіваюся, ці абзаци допомогли вам зрозуміти "zot" better."""Або рядку може передувати літерал r, і в цьому випадку рядок інтерпретується як необроблений рядок Python.
Строка документації має формат «groff -man». Більш детальну інформацію про цей формат розмітки дивіться у «groff_man(7)». Пам’ятайте, що «halcompile» інтерпретує символи «\» у строках, тому, наприклад, щоб встановити курсив для слова «example», напишіть:
"\\fIexample\\fB"У цьому випадку r-рядки особливо корисні, оскільки зворотні скісну риску в r-рядку не потрібно подвоювати:
r"\fIexample\fB" -
TYPE - Один із типів HAL: bit, s32, u32, s64, u64 або float. Для s32 та u32 також можна використовувати назви signed та unsigned, але перевага надається s32 та u32.
-
PINDIRECTION - Одне з наступного: «in», «out» або «io». Компонент встановлює значення для виводу «out», зчитує значення з виводу «in», а також може зчитувати або встановлювати значення виводу «io».
-
PARAMDIRECTION - Одне з наступного: r або rw. Компонент встановлює значення для параметра r, і він може зчитувати або встановлювати значення параметра rw.
-
STARTVALUE - Вказує початкове значення виводу або параметра. Якщо його не вказано, значення за замовчуванням — «0» або «FALSE», залежно від типу елемента.
-
HEADERFILE - Ім’я файлу заголовка, вказане в подвійних лапках (
include "myfile.h";) або в кутових дужках (include <systemfile.h>;). Файл заголовка буде включений (за допомогою #include мови C) у верхній частині файлу, перед оголошеннями контактів і параметрів.
8.1. Функції HAL
-
fp - Вказує на те, що функція виконує обчислення з плаваючою комою.
-
nofp - Вказує, що виконуються тільки цілочисельні обчислення. Якщо не вказано ні того, ні іншого, припускається fp. Ні halcompile, ні gcc не можуть виявити використання обчислень з плаваючою комою у функціях, позначених nofp, але використання таких операцій призводить до невизначеної поведінки.
8.2. Опції
Наразі визначені такі опції:
-
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)
Зазвичай кількість екземплярів, що створюються, вказується в параметрі модуля «count»; якщо вказано «count_function», замість цього використовується значення, яке повертає функція «int get_count(void)», а параметр модуля «count» не визначається. -
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 - (за замовчуванням: немає) застаріле
Якщо вказано, кожен екземпляр компонента матиме пов’язаний блок даних типу TYPE (який може бути простим типом, таким як float, або назвою типу, створеного за допомогою typedef). У нових компонентах слід використовувати variable. -
option extra_setup yes - (за замовчуванням: ні)
Якщо вказано, викликати функцію, визначену параметром EXTRA_SETUP, для кожного екземпляра. Якщо використовується автоматично визначений параметр rtapi_app_main, extra_arg – це номер цього екземпляра. -
option extra_cleanup yes - (за замовчуванням: ні)
Якщо вказано, викликати функцію, визначену параметром EXTRA_CLEANUP, з автоматично визначеного rtapi_app_exit або, у разі виявлення помилки, з автоматично визначеного rtapi_app_main. -
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.3. Ліцензія та авторство
-
LICENSE- Вкажіть ліцензію модуля для документації та для оголошення модуля MODULE_LICENSE(). Наприклад, щоб вказати, що ліцензія модуля — GPL версії 2 або пізнішої версії:`ліцензія "GPL"; // вказує на GPL версії 2 або пізнішої версії`Для отримання додаткової інформації про значення MODULE_LICENSE() та додаткові ідентифікатори ліцензій див. <linux/module.h> або сторінку довідки rtapi_module_param(3).
Ця декларація обов’язкова.
-
AUTHOR- Вкажіть автора модуля для документації.
8.4. Зберігання даних для кожного екземпляра
-
variable CTYPE STARREDNAME; + variable CTYPE STARREDNAME[SIZE]; + variable CTYPE STARREDNAME = DEFAULT; + variable CTYPE STARREDNAME[SIZE] = DEFAULT;Оголосіть змінну STARREDNAME типу CTYPE для кожного екземпляра, опціонально як масив елементів SIZE і опціонально з типовим значенням DEFAULT. Елементи без DEFAULT ініціалізуються з усіма бітами, що дорівнюють нулю. «CTYPE» — це простий однослівний тип C, такий як «float», «u32», «s32», «int» тощо. Для доступу до змінних масиву використовуються квадратні дужки.
Якщо змінна має бути типу вказівника, між символом "*" та іменем змінної не може бути пробілу. Тому прийнятним є наступне:
variable int *example;
Але наступні не є такими:
variable int* badexample;
variable int * badexample;
8.5. Коментарі
Однорядкові коментарі в стилі C++ (//...) та багаторядкові коментарі в стилі C (/* ... */) підтримуються в розділі оголошення.
9. Обмеження
Хоча HAL дозволяє виводу, параметру та функції мати однакову назву, «halcompile» цього не дозволяє.
Назви змінних та функцій, які не можна використовувати або які можуть спричинити проблеми, включають:
-
Будь-що, що починається з _comp.
-
comp_id
-
fperiod
-
rtapi_app_main
-
rtapi_app_exit
-
extra_setup
-
extra_cleanup
10. Зручні макроси
На основі елементів у розділі декларації «halcompile» створює структуру C під назвою «struct comp_state». Однак замість посилання на члени цієї структури (наприклад, «*(inst->name)»), на них зазвичай посилаються за допомогою макросів, наведених нижче. Деталі «struct comp_state» та цих макросів можуть змінюватися від однієї версії «halcompile» до іншої.
-
FUNCTION(`__name__)` - Використовуйте цей макрос, щоб розпочати визначення функції реального часу, яка була раніше оголошена за допомогою function NAME. Функція включає параметр period, який є цілим числом наносекунд між викликами функції. Див. також option period вище. -
EXTRA_SETUP()– Використовуйте цей макрос для початку визначення функції, яка викликається для виконання додаткового налаштування цього екземпляра. Повертає від’ємне значення UNIX errno для позначення помилки (наприклад, 'return -EBUSY. -
EXTRA_CLEANUP()- Використовуйте цей макрос, щоб розпочати визначення функції, яка викликається для виконання додаткового очищення компонента. Зверніть увагу, що ця функція повинна очистити всі екземпляри компонента, а не тільки один. Макроси «pin_name», «parameter_name» та «data» тут не можуть використовуватися. -
«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. Якщо запитувана кількість екземплярів перевищує кількість дозволених особистостей, особистості присвоюються шляхом індексації за модулем кількості дозволених особистостей. Виводиться повідомлення, що вказує на такі присвоєння. |
13. Приклади
13.1. постійний
Зверніть увагу, що оголошення "function _" створює функції з іменем "constant.0" тощо. Ім’я файлу має збігатися з іменем компонента.
component constant; pin out float out; param r float value = 1.0; option period no; function _; ліцензія "GPL"; // вказує на GPL версії 2 або пізнішої версії ;; FUNCTION(_) { out = value; }
13.2. синхронізація
Цей компонент обчислює синус і косинус вхідного кута в радіанах. Він має інші можливості, ніж виходи «синус» і «косинус» siggen, оскільки вхідним параметром є кут, а не «частота», що змінюється вільно.
Виводи оголошені у вихідному коді з іменами sin_ та cos_, щоб вони не заважали функціям sin() та cos(). Виводи HAL все ще називаються sincos.<num>.sin.
component sincos; pin out float sin_; pin out float cos_; pin in float theta; option period no; function _; ліцензія "GPL"; // вказує на GPL версії 2 або пізнішої версії ;; #включають <rtapi_math.h> FUNCTION(_) { sin_ = sin(theta); cos_ = cos(theta); }
13.3. out8
Цей компонент є драйвером для «фіктивної» карти під назвою «out8», яка має 8 виводів цифрового виходу, що обробляються як одне 8-бітне значення. У системі може бути різна кількість таких карт, і вони можуть знаходитися за різними адресами. Контакт називається «out_», оскільки «out» є ідентифікатором, що використовується в «<asm/io.h>». Він ілюструє використання «EXTRA_SETUP» та «EXTRA_CLEANUP» для запиту області вводу-виводу, а потім її звільнення у разі помилки або коли модуль вивантажується.
component out8; pin out unsigned out_ "Вихідне значення; використовуються лише молодші 8 бітів"; param r unsigned ioaddr; function _; option period no; option count_function; option extra_setup; option extra_cleanup; option constructable no; ліцензія "GPL"; // вказує на GPL версії 2 або пізнішої версії ;; #include <asm/io.h> #define MAX 8 int io[MAX] = {0,}; RTAPI_MP_ARRAY_INT(io, MAX, "Адреси вводу/виводу плат out8"); int get_count(void) { int i = 0; for(i=0; i<MAX && io[i]; i++) { /* Nothing */ } return i; } EXTRA_SETUP() { if(!rtapi_request_region(io[extra_arg], 1, "out8")) { // встановити цей порт вводу/виводу на 0, щоб EXTRA_CLEANUP не звільняв ввод-вивод // порти, які ніколи не запитувалися. 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;
Цей фрагмент компонента ілюструє використання префікса 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 bit in; pin out bit out-# [4]; option period no; function _ nofp; ліцензія "GPL"; // вказує на GPL версії 2 або пізнішої версії ;; int i; for(i=3; i>0; i--) out(i) = out(i-1); out(0) = in;
13.6. ранд
Цей компонент, що не працює в реальному часі, змінює значення на своєму вихідному контакті на нове випадкове значення в діапазоні (0,1) приблизно раз на 1 мс.
component rand; option userspace; pin out float out; ліцензія "GPL"; // вказує на GPL версії 2 або пізнішої версії ;; #include <unistd.h> void user_mainloop(void) { while(1) { usleep(1000); FOR_ALL_INSTS() out = drand48(); } }
13.7. логіка (використовуючи особистість)
Цей компонент реального часу показує, як використовувати "персоналізацію" для створення масивів змінного розміру та додаткових виводів.
логіка компонента "Компонент LinuxCNC HAL, що забезпечує експериментальні логічні функції"; вивід в біт in-##[16 : personality & 0xff]; вивід з біту and якщо personality & 0x100; вивід з біту or якщо personality & 0x200; вивід з біту xor якщо personality & 0x400; опція period no; функція _ nofp; опис """ Експериментальний загальний компонент «логічної функції». Може виконувати «and», «or» та «xor» до 16 входів. Визначте правильне значення для «personality», додавши: .IP \\(bu 4 Кількість вхідних контактів, зазвичай від 2 до 16 .IP \\(bu 256 (0x100) якщо бажаний вихід «and» .IP \\(bu 512 (0x200) якщо бажаний вихід «or» .IP \\(bu 1024 (0x400) якщо бажаний вихід «xor» (виключне або)"""; ліцензія "GPL"; // вказує на GPL v2 або пізнішу версію ;; ФУНКЦІЯ(_) { 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; }
Типова лінія навантаження для цього компонента може бути
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 цим функціям.
приклад компонента; pin in s32 in; pin out bit out1; pin out bit out2; номер періоду опції; функція _; ліцензія "GPL"; ;; // загальний набір виводів, функція true void set(hal_bit_t *p){ *p = 1; } // загальна функція встановлення виводів false void unset(hal_bit_t *p){ *p = 0; } //основна функція FUNCTION(_) { if (in < 0){ set(&out1); unset(&out2); }else if (in >0){ unset(&out2); set(&out2); }else{ unset(&out1); unset(&out2); } }
Цей компонент використовує дві загальні функції для маніпулювання бітовим виводом HAL, на який посилається.
14. Використання командного рядка
Сторінка довідки halcompile містить детальну інформацію про виклик halcompile.
$ man halcompile
Короткий опис використання halcompile наведено таким чином:
$ halcompile --help