Вся правда про ОСРВ. Групи прапорів подій: введення і базові служби

Групи прапорів подій вже згадувалися раніше в одній з попередніх статей (#5). В Nucleus SE вони схожі на сигнали, але є більш гнучкими. Вони надають маловитратний і гнучкий спосіб передачі простих повідомлень між завданнями.

Використання прапорів подій

В Nucleus SE прапори подій визначаються на етапі складання. Максимальна кількість груп прапорів подій у програмі – 16. Якщо групи прапорів подій не визначені, то код, що відноситься до структур даних і службовим викликам груп прапорів подій, не буде включений в додаток.

Група прапорів подій – набір з восьми бітових прапорів, доступ до яких регулюється таким чином, щоб одним прапором могли безпечно користуватися кілька завдань. Одна задача може встановити або скинути будь-яку комбінацію прапорів подій. Інша задача може прочитати групу прапорів у будь-який час, а також може дочекатися певній послідовності прапорів (за опитуванням або з припиненням).

Налаштування груп прапорів подій

 

Кількість груп прапорів подій

Як і в більшості об’єктів Nucleus SE, налаштування груп прапорів подій визначається директивами #define в nuse_config.h. Основним параметром є NUSE_EVENT_GROUP_NUMBER, який визначає, скільки груп прапорів подій буде визначено в додатку. За замовчуванням цей параметр встановлено в 0 (тобто групи прапорів подій не використовуються) і може мати будь-яке значення аж до 16. Некоректне значення приведе до помилки при компіляції, яка буде згенерована перевіркою в nuse_config_check.h (вона включається nuse_config.c, а значить компілюється разом з цим модулем), в результаті спрацює директива #error. Вибір ненульового значення служить головним активатором груп прапорів подій. Цей параметр використовується при визначенні структур даних і від його значення залежить їх розмір (більш докладно про це в наступних статтях). Крім того, ненульове значення активує налаштування API.

Активація викликів API

Кожна функція API (службовий виклик) в Nucleus SE активується директиви #define в nuse_config.h. Для груп прапорів подій до них відносяться:
NUSE_EVENT_GROUP_SET
NUSE_EVENT_GROUP_RETRIEVE
NUSE_EVENT_GROUP_INFORMATION
NUSE_EVENT_GROUP_COUNT

За замовчуванням, їм присвоєно значення FALSE, таким чином, відключаючи кожен службовий виклик і блокуючи включення реалізує їх коду. Для налаштування груп прапорів подій потрібно вибрати необхідні виклики API і присвоїти відповідним директивам значення TRUE.

Нижче наведено витяг із файлу nuse_config.h за замовчуванням.

#define NUSE_EVENT_GROUP_NUMBER 0 /* Number of event groups
 in the system - 0-16 */
#define NUSE_EVENT_GROUP_SET FALSE /* Service call enabler */
#define NUSE_EVENT_GROUP_RETRIEVE FALSE /* Service call enabler */
#define NUSE_EVENT_GROUP_INFORMATION FALSE /* Service call enabler */
#define NUSE_EVENT_GROUP_COUNT FALSE /* Service call enabler */

Активована функція API при відсутності у додатку груп прапорів подій призведе до помилки компіляції (крім NUSE_Event_Group_Count(), яка дозволена завжди). Якщо ваш код використовує виклик API, який не був активований, виникне помилка компонування, так як реалізує код не був включений в додаток.

Службові виклики прапорів подій

Nucleus RTOS підтримує сім службових виклик, які надають наступний функціонал:
• Установка прапорів подій. В Nucleus SE реалізовано функції NUSE_Event_Group_Set().
• Зчитування прапорів подій. В Nucleus SE реалізовано в NUSE_Event_Group_Retrieve().
• Надання інформації про конкретної групі прапорів подій. В Nucleus SE реалізовано в NUSE_Event_Group_Information().
• Повернення кількості сконфігурованих на даний момент груп прапорів подій у додатку. В Nucleus SE реалізовано в NUSE_Event_Group_Count().
• Додавання нової групи прапорів подій в додаток. В Nucleus SE не реалізовано.
• Видалення групи прапорів подій з програми. В Nucleus SE не реалізовано.
• Повернення покажчиків на всі групи прапорів подій у додатку. В Nucleus SE не реалізовано.

Читайте також  Як вибрати мову програмування для створення Андроїд — додатку

Реалізація кожного з цих службових викликів докладно розглянуто нижче.

Варто зауважити, що функції скидання немає ні в Nucleus RTOS, ні в Nucleus SE. Це зроблено навмисно. Функція скидання передбачає переважання особливого стану прапорів. Для груп прапорів подій єдиним «особливим» станом є обнуління всіх прапорів, яке може бути виконане за допомогою NUSE_Event_Group_Set().

Службові виклики установки і зчитування груп прапорів подій

Фундаментальні операції, які можуть бути виконані над групою прапорів подій – установка значення одного і більше прапорів, а також зчитування поточних значень прапорів. Nucleus RTOS і Nucleus SE надають чотири базових виклику API для цих операцій.

Оскільки прапори подій є бітами, їх краще візуалізувати у вигляді двійкових чисел. Так як стандарт З історично не підтримує подання двійкових символів (тільки вісімкових і шістнадцяткових), Nucleus SE має корисний заголовковий файл nuse_binary.h, який містить символи #define виду b01010101 для всіх 256 8-бітних значень.

Установка прапорів подій

Службовий виклик Nucleus RTOS API для встановлення прапорів дуже гнучкий і дозволяє встановлювати і очищати значення прапорів за допомогою операцій І та АБО. Nucleus SE надає аналогічний функціонал, але призупинення завдань є необов’язковою.

Виклик для встановлення прапорів в Nucleus RTOS
Прототип службового виклику:
STATUS NU_Set_Events(NU_EVENT_GROUP *group, UNSIGNED event_flags, OPTION operation);

Параметри:
group – вказівник на наданий користувачем блок управління групою прапорів подій;
event_flags – значення бітової маски групи прапорів;
operation – виконувана операція, NU_OR (для встановлення прапорів) або NU_AND (для очищення прапорів).

Значення, що повертається:
NU_SUCCESS – виклик був успішно завершений;
NU_INVALID_GROUP – некоректний вказівник на групу прапорів подій;
NU_INVALID_OPERATION – зазначена операція відрізняється від NU_OR і NU_AND.

Виклик для встановлення прапорів в Nucleus SE
Цей виклик API підтримує основний функціонал Nucleus RTOS API.

Прототип службового виклику:
STATUS NUSE_Event_Group_Set(NUSE_EVENT_GROUP group, U8 event_flags, OPTION operation);

Параметри:
group – індекс (ID) групи подій, прапори якої встановлюються/очищаються;
event_flags – значення бітової максі групи прапорів;
operation – виконувана операція, NUSE_OR (для встановлення прапорів) або NUSE_AND (для очищення прапорів).

Значення, що повертається:
NUSE_SUCCESS – виклик був успішно завершений;
NUSE_INVALID_GROUP – некоректний індекс групи прапорів подій;
NUSE_INVALID_OPERATION – зазначена операція відрізняється від NUSE_OR і NUSE_AND.

Реалізація встановлення прапорів подій в Nucleus SE
Початковий код функції API NUSE_Event_Group_Set() є загальним (після перевірки параметрів), незалежно від того, активована підтримка API викликів блокування (припинення завдань) чи ні. Логіка досить проста:

NUSE_CS_Enter();
if (operation == NUSE_OR)
{
 NUSE_Event_Group_Data[group] |= event_flags;
}
else /* NUSE_AND */
{
 NUSE_Event_Group_Data[group] &= event_flags;
}

Бітова маска event_flags накладається (за допомогою операції І або АБО) на значення обраної групи прапорів подій.

Читайте також  Blue pill (синя таблетка) STM32F103 як ПЛК

Залишився код включається тільки при активованій блокування завдань:

#if NUSE_BLOCKING_ENABLE
 while (NUSE_Event_Group_Blocking_Count[group] != 0)
{
 U8 index; /* check whether any tasks are blocked */
 /* on this event group */
 for (index=0; index<NUSE_TASK_NUMBER; index++)
{
 if ((LONIB(NUSE_Task_Status[index]) ==
NUSE_EVENT_SUSPEND)
 && (HINIB(NUSE_Task_Status[index]) == group))
{
 NUSE_Task_Blocking_Return[index] = NUSE_SUCCESS;
 NUSE_Task_Status[index] = NUSE_READY;
break;
}
}
NUSE_Event_Group_Blocking_Count[group]--;
}
 #if NUSE_SCHEDULER_TYPE == NUSE_PRIORITY_SCHEDULER
NUSE_Reschedule(NUSE_NO_TASK);
#endif
#endif
NUSE_CS_Exit();
return NUSE_SUCCESS;

Якщо які-небудь завдання припинені (для читання) з цієї групи прапорів, вони поновлюються. Коли перед ними відкривається можливість продовжити виконання (це залежить від планувальника), вони можуть визначити, чи задоволені умови їх відновлення чи ні (див. читання прапорів подій).

Читання прапорів подій

Службові виклики Nucleus RTOS API для читання дуже гнучкі і дозволяють припиняти завдання на невизначений час або з певним таймаутом, якщо операція не може бути виконана негайно (наприклад, якщо ви спробуєте вважати певну послідовність прапорів подій, яка не представляє поточний стан). Nucleus SE надає ті ж функції, тільки призупинення завдання опціональна, а таймаут не реалізований.

Виклик для читання прапорів в Nucleus RTOS
Прототип службового виклику:
STATUS NU_Retrieve_Events(NU_EVENT_GROUP *group, UNSIGNED requested_events, OPTION operation, UNSIGNED *retrieved_events, UNSIGNED suspend);

Параметри:
group – вказівник на наданий користувачем блок управління групою прапорів подій;
requested_events – бітова маска, що визначає зчитуються прапори;
operation – доступні чотири операції: NU_AND, NU_AND_CONSUME, NU_OR і NU_OR_CONSUME. Операції NU_AND і NU_AND_CONSUME вказують, що всі необхідні запитувані прапори. Операції NU_OR і NU_OR_CONSUME вказують, що досить одного або декількох із запитаних прапорів. Параметр CONSUME автоматично очищає існуючі прапори після успішного запиту;
retrieved_events – вказівник на сховище для значень прочитуваних прапорів подій;
suspend – специфікація для припинення завдань; може приймати значення NU_NO_SUSPEND або NU_SUSPEND, або значення таймауту в тактах системного таймера (від 1 до 4,294,967,293).

Значення, що повертається:
NU_SUCCESS – виклик був успішно завершений;
NU_NOT_PRESENT – зазначена операція не повернула події (подій у випадку NU_OR і не всі події в разі NU_AND);
NU_INVALID_GROUP – некоректний вказівник на групу прапорів подій;
NU_INVALID_OPERATION – зазначена операція була некоректна;
NU_INVALID_POINTER – нульовий покажчик на сховище прапорів подій (NULL);
NU_INVALID_SUSPEND – спроба виконати призупинення з не пов’язаного з завданням потоку;
NU_TIMEOUT – необхідна комбінація прапорів подій не встановилася навіть після зазначеного часу очікування;
NU_GROUP_DELETED – група прапорів подій була вилучена, в той час як завдання була припинена.

Виклик для читання прапорів в Nucleus SE
Цей виклик API підтримує основний функціонал Nucleus RTOS API.

Прототип службового виклику:
STATUS NUSE_Event_Group_Retrieve(NUSE_EVENT_GROUP group, U8 requested_events, OPTION operation, U8 *retrieved_events, U8 suspend);

Параметри:
group – індекс (ID) зчитується групи прапорів подій;
requested_events – бітова маска, що визначає зчитуються прапори;
operation – специфікація, яка вказує на кількість необхідних прапорів: NUSE OR (деякі прапори) або NUSE AND (всі прапори);
retrieved_events – вказівник на сховище для дійсних значень лічених прапорів подій (при операції NUSE_AND це буде те ж, що передане в параметрі requested_events);
suspend – специфікація для припинення завдання, може приймати значення NUSE_NO_SUSPEND або NUSE_SUSPEND.

Читайте також  Бензинові велосипеди або дивний пошук продуктів (e-commerce)

Значення, що повертається:
NUSE_SUCCESS – виклик був успішно завершений;
NUSE_NOT_PRESENT – зазначена операція не повернула події (подій у випадку NUSE_OR і не всі події в разі NUSE_AND);
NUSE_INVALID_GROUP – некоректний індекс групи прапорів подій;
NUSE_INVALID_OPERATION – зазначена операція відрізняється від NUSE_OR або NUSE_AND;
NUSE_INVALID_POINTER – нульовий покажчик на сховище лічених прапорів подій (NULL);
NUSE_INVALID_SUSPEND – спроба виконати призупинення з не пов’язаного з завданням потоку або при відключеній підтримки блокуючих викликів API.

Реалізація зчитування прапорів подій в Nucleus SE
Варіант коду функції API NUSE_Event_Group_Retrieve() (після перевірки параметрів) вибирається під час умовної компіляції в залежності від того, активована підтримка API викликів блокування (припинення) завдань чи ні. Розглянемо ці два варіанти окремо.

Якщо блокування відключена, повний код цього виклику API буде мати наступний вигляд:

temp_events = NUSE_Event_Group_Data[group] & requested_events;
if (operation == NUSE_OR)
{
 if (temp_events != 0)
{
 return_value = NUSE_SUCCESS;
}
else
{
 return_value = NUSE_NOT_PRESENT;
}
}
else /* operation == NUSE_AND */
{
 if (temp_events == requested_events)
{
 return_value = NUSE_SUCCESS;
}
else
{
 return_value = NUSE_NOT_PRESENT;
}
}

Необхідні прапори подій вибираються з вказаної групи прапорів подій. Значення порівнюється з необхідними подіями, враховуючи операцію І/АБО, а також зворотний результат і безпосередні значення запитуваних прапорів.

Якщо блокування завдань активована, код стає більш складним:

do
{
 temp_events = NUSE_Event_Group_Data[group] & requested_events;
 if (operation == NUSE_OR)
{
 if (temp_events != 0)
{
 return_value = NUSE_SUCCESS;
}
else
{
 return_value = NUSE_NOT_PRESENT;
}
}
 else /* operation == NUSE_AND */
{
 if (temp_events == requested_events)
{
 return_value = NUSE_SUCCESS;
}
else
{
 return_value = NUSE_NOT_PRESENT;
}
}
 if (return_value == NUSE_SUCCESS)
{
 suspend = NUSE_NO_SUSPEND;
}
else
{
 if (suspend == NUSE_SUSPEND) /* block task */
{
NUSE_Event_Group_Blocking_Count[group]++;
 NUSE_Suspend_Task(NUSE_Task_Active, (group << 4) |
NUSE_EVENT_SUSPEND);
 return_value =
NUSE_Task_Blocking_Return[NUSE_Task_Active];
 if (return_value != NUSE_SUCCESS)
{
 suspend = NUSE_NO_SUSPEND;
}
}
}
} while (suspend == NUSE_SUSPEND);

Код поміщений в цикл do…while, який працює, поки параметр” suspend має значення NUSE_SUSPEND.

Запитувані прапори подій зчитуються також, як і при виклику без блокування. Якщо зчитування не пройшло успішно і параметр” suspend має значення NUSE_NO_SUSPEND, виклику API присвоюється значення NUSE_NOT_PRESENT. Якщо параметру suspend було присвоєно значення NUSE_SUSPEND, завдання призупиняється. При поверненні (коли завдання відновлюється), якщо обчислене значення NUSE_SUCCESS, вказує, що задача була відновлена, тому що прапори подій у цій групі були встановлені або очищені, — цикл починається з початку, прапори зчитуються і перевіряються. Оскільки не існує функції API для скидання груп прапорів подій, це є єдиною причиною для поновлення завдання, але процес перевірки NUSE_Task_Blocking_Return[] був залишений в системі для сумісності управління блокуванням з іншими типами об’єктів.

У наступній статті будуть описані додаткові виклики API, пов’язані з групами прапорів подій, а також їх структури даних.

Про автора: Колін Уоллс вже більше тридцяти років працює у сфері електронної промисловості, значну частину часу приділяючи вбудованому. Зараз він — інженер в області вбудованого в Mentor Embedded (підрозділ Mentor Graphics). Колін Уоллс часто виступає на конференціях і семінарах, автор численних технічних статей і двох книг по вбудованому. Живе у Великобританії. Професійний блог Коліна, e-mail: colin_walls@mentor.com.

Степан Лютий

Обожнюю технології в сучасному світі. Хоча частенько і замислююся над тим, як далеко вони нас заведуть. Не те, щоб я прям і знаюся на ядрах, пікселях, коллайдерах і інших парсеках. Просто приходжу в захват від того, що може в творчому пориві вигадати людський розум.

Вам також сподобається...

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *