Вся правда об ОСРВ. Статья #18. Группы флагов событий: вспомогательные службы и структуры данных

в 10:07, , рубрики: api, rtos, взаимодействие задач, группы флагов событий, микроконтроллеры, осрв, программирование микроконтроллеров, служебные вызовы, флаги событий

Вся правда об ОСРВ. Статья #18. Группы флагов событий: вспомогательные службы и структуры данных - 1

Эта статья продолжает описывать группы флагов событий.

Предыдущие статьи серии:

Статья #17. Группы флагов событий: введение и базовые службы
Статья #16. Сигналы
Статья #15. Разделы памяти: службы и структуры данных
Статья #14. Разделы памяти: введение и базовые службы
Статья #13. Структуры данных задач и неподдерживаемые вызовы API
Статья #12. Службы для работы с задачами
Статья #11. Задачи: конфигурация и введение в API
Статья #10. Планировщик: дополнительные возможности и сохранение контекста
Статья #9. Планировщик: реализация
Статья #8. Nucleus SE: внутреннее устройство и развертывание
Статья #7. Nucleus SE: введение
Статья #6. Другие сервисы ОСРВ
Статья #5. Взаимодействие между задачами и синхронизация
Статья #4. Задачи, переключение контекста и прерывания
Статья #3. Задачи и планирование
Статья #2. ОСРВ: Структура и режим реального времени
Статья #1. ОСРВ: введение.

Вспомогательные службы групп флагов событий

Nucleus RTOS имеет три вызова API, которые предоставляют вспомогательные функции для групп флагов событий: получение информации о группе, получение информации о количестве групп флагов событий в приложении и получение указателей на все группы флагов событий. Первые два вызова реализованы в Nucleus SE.

Получение информации о группе флагов событий

Этот служебный вызов возвращает информацию о группе флагов событий. Реализация этого вызова в Nucleus SE отличается от реализации в Nucleus RTOS тем, что возвращается меньше информации, так как именование объектов и порядок приостановки задач не поддерживается, а сама приостановка задач может быть деактивирована.

Вызов для получения информации о группе событий в Nucleus RTOS
Прототип служебного вызова:
STATUS NU_Event_Group_Information(NU_EVENT_GROUP *group, CHAR *name, UNSIGNED *event_flags, UNSIGNED *tasks_waiting, NU_TASK **first_task);

Параметры:
group – указатель на предоставляемый пользователем блок управления группой флагов событий;
name – указатель на 8-символьную область для имени группы флагов событий, сюда включен и терминирующий ноль;
event_flags – указатель на переменную, которая примет текущее значение указанной группы флагов событий;
tasks_waiting – указатель на переменную, которая примет количество приостановленных задач в этой группе флагов событий;
first_task – указатель на переменную типа NU_TASK, которая примет указатель на первую приостановленную задачу.

Возвращаемое значение:
NU_SUCCESS – вызов был успешно завершен;
NU_INVALID_GROUP – некорректный указатель на группу флагов событий.

Вызов для получения информации о группе событий в Nucleus SE
Этот вызов поддерживает основной функционал Nucleus RTOS API.

Прототип служебного вызова:
STATUS NUSE_Event_Group_Information(NUSE_EVENT_GROUP group, U8 *event_flags, U8 *tasks_waiting, NUSE_TASK *first_task);

Параметры:
group – индекс группы флагов событий, о которой запрашивается информация;
event_flags – указатель на переменную, которая примет текущее значение указанной группы флагов событий;
tasks_waiting – указатель на переменную которая примет количество приостановленных задач в этой группе флагов событий (ничего не возвращается, если приостановка задач деактивирована);
first_task – указатель на переменную типа NUSE_TASK, которая примет индекс первой приостановленной задачи (ничего не возвращается, если приостановка задач деактивирована).

Возвращаемое значение:
NUSE_SUCCESS – вызов был успешно завершен;
NUSE_INVALID_GROUP – некорректный индекс группы флагов событий.

Реализация получения информации о группе событий в Nucleus SE
Реализация этого вызова API довольно проста:

*event_flags = NUSE_Event_Group_Data[group];
 
#if NUSE_BLOCKING_ENABLE
 
    *tasks_waiting = NUSE_Event_Group_Blocking_Count[group];
    if (NUSE_Event_Group_Blocking_Count[group] != 0)
    {
        U8 index;
 
        for (index=0; index<NUSE_TASK_NUMBER; index++)
        {
            if ((LONIB(NUSE_Task_Status[index]) ==
                 NUSE_EVENT_SUSPEND)
                && (HINIB(NUSE_Task_Status[index]) == group))
            {
                *first_task = index;
                break;
            }
        }
    }
    else
    {
        *first_task = 0;
    }
 
#else
 
    *tasks_waiting = 0;
    *first_task = 0;
 
#endif
 
return NUSE_SUCCESS;

Функция возвращает значение группы флагов событий. Затем, если вызовы API блокировки задач активированы, возвращается количество ожидающих задач и индекс первой из них (в противном случае, этим двум параметрам присваивается нулевое значение).

Получение количества групп флагов событий

Этот служебный вызов возвращает количество групп флагов событий в приложении. В Nucleus RTOS это значение со временем меняется, и возвращаемое значение показывает текущее количество групп, а в Nucleus SE это значение определяется во время сборки и не меняется со временем.

Вызов счетчика групп флагов событий в Nucleus RTOS
Прототип служебного вызова:
UNSIGNED NU_Establised_Event_Groups(VOID);

Параметры:
Отсутствуют.

Возвращаемое значение:
Текущее количество созданных групп флагов событий.

Вызов счетчика групп флагов событий в Nucleus SE
Прототип служебного вызова:
U8 NUSE_Event_Group_Count(void);

Параметры:
Отсутствуют.

Возвращаемое значение:
Количество сконфигурированных групп флагов событий.

Реализация счетчика групп флагов событий в Nucleus SE
Реализация этого вызова API довольно тривиальна: возвращается значение символа #define NUSE_EVENT_GROUP_NUMBER.

Структуры данных

Как и все другие объекты Nucleus SE, группы флагов событий используют один или два массива структур данных (оба размещаются в ОЗУ), размер массивов зависит от числа групп, определенных в настройках.

Настоятельно рекомендую, чтобы код приложения не использовал прямой доступ к этим структурам данных, а обращался к ним через предоставляемые функции API. Это позволит избежать несовместимости с будущими версиями Nucleus SE и нежелательных побочных эффектов, а также упростит портирование приложения на Nucleus RTOS. Для лучшего понимания работы кода служебных вызовов и для отладки ниже приведен подробный обзор структур данных.

Данные в ОЗУ

Эти данные имеют следующую структуру:
NUSE_Event_Group_Data[] – массив данных типа U8, имеющих одну запись для каждой сконфигурированной группы флагов; в нем хранятся данные флагов событий.
NUSE_Event_Group_Blocking_Count[] – массив типа U8, содержащий счетчик заблокированных задач в каждой группе флагов событий. Этот массив существует, только когда активирована функциональность блокировки в API.

Эти структуры данных инициализируются нулями в функции NUSE_Init_Event_Group() при запуске Nucleus SE. Одна из следующих статей предоставит полное описание процедур запуска Nucleus SE.

Ниже приведено описание этих структур данных в файле nuse_init.c:

RAM U8 NUSE_Event_Group_Data[NUSE_EVENT_GROUP_NUMBER];
 
#if NUSE_BLOCKING_ENABLE
 
    RAM U8 NUSE_Event_Group_Blocking_Count[NUSE_EVENT_GROUP_NUMBER];
 
#endif

Данные в ПЗУ

Для реализации групп флагов событий не используются данные в ПЗУ.

Объем памяти для групп флагов событий

Как и для всех объектов ядра Nucleus SE, объем памяти, необходимый для групп флагов событий, предсказуем.

Объем данных в ПЗУ для всех групп флагов событий в приложении равен 0.

Объем памяти в ОЗУ для всех групп флагов событий при активированной функциональности блокировки API равен NUSE_EVENT_GROUP_NUMBER * 2.

В противном случае он равен NUSE_EVENT_GROUP_NUMBER.

Нереализованные вызовы API

Три вызова API для групп флагов событий, которые можно найти в Nucleus RTOS, не были реализованы в Nucleus SE.

Создание группы флагов событий

Этот вызов API создает группу флагов событий. В Nucleus SE в этом вызове нет необходимости, так как группы флагов событий создаются статически.

Прототип служебного вызова:
STATUS NU_Create_Event_Group(NU_EVENT_GROUP *group, CHAR *name);

Параметры:

group – указатель на предоставляемый пользователем блок управления группой флагов событий; используется в качестве дескриптора для управления группами флагов событий в других вызовах API;
name – указатель на 8-символьное имя группы флагов событий с включенным в эту область терминирующим нулевым байтом.

Возвращаемое значение:

NU_SUCCESS – вызов был успешно завершен;
NU_INVALID_GROUP – нулевой указатель на блок управления группы флагов событий (NULL) или уже используется.

Удаление группы флагов событий

Этот вызов API удаляет ранее созданную группу флагов событий. В Nucleus SE в этом вызове нет необходимости, так как группы флагов событий создаются статически и не могут быть удалены.

Прототип служебного вызова:

STATUS NU_Delete_Event_Group(NU_EVENT_GROUP *group);

Параметры:

group – указатель на блок управления группой флагов событий.

Возвращаемое значение:

NU_SUCCESS – вызов был успешно завершен;
NU_INVALID_GROUP – некорректный указатель на группу флагов событий.

Указатели групп флагов событий

Этот вызов API составляет последовательный список указателей на все группы флагов событий в системе. В Nucleus SE в этом вызове нет необходимости, так как группы флагов событий имеют простые индексы, а не указатели.

Прототип служебного вызова:

UNSIGNED NU_Event_Group_Pointers(NU_EVENT_GROUP *pointer_list, UNSIGNED maximum_pointers);

Параметры:

pointer_list – указатель на массив указателей NU_EVENT_GROUP, этот массив заполняется указателями на созданные в системе группы флагов событий;
maximum_pointers – максимальное количество указателей в массиве.

Возвращаемое значение:

Количество указателей NU_EVENT_GROUP в массиве.

Совместимость с Nucleus RTOS

При разработке Nucleus SE моей целью было обеспечить максимальный уровень совместимости программного кода с Nucleus RTOS. Группы флагов событий не стали исключением, и, с точки зрения разработчика, они реализованы практически так же, как и в Nucleus RTOS. Существуют некоторые несовместимости, которые я посчитал допустимыми, с учетом того, что финальный код станет более понятным и более эффективным с точки зрения объема требуемой памяти. В остальном, вызовы API Nucleus RTOS могут быть практически напрямую использованы как вызовы Nucleus SE.

Идентификаторы объектов

В Nucleus RTOS все объекты описываются структурами данных (блоками управления), имеющими определенный тип. Указатель на этот блок управления служит идентификатором группы флагов событий. Я решил, что в Nucleus SE для эффективного использования памяти необходим другой подход: все объекты ядра описываются несколькими таблицами в ОЗУ и/или ПЗУ. Размер этих таблиц определяется количеством сконфигурированных объектов каждого типа. Идентификатор конкретного объекта – индекс в этой таблице. Таким образом, я определил NUSE_EVENT_GROUP в качестве эквивалента U8, переменная этого типа (не указатель) служит в качестве идентификатора группы флагов событий. С этой небольшой несовместимостью легко справиться если код переносится с Nucleus SE на Nucleus RTOS и наоборот. Обычно над идентификаторами объектов не выполняются никакие операции, кроме перемещения и хранения.

Nucleus RTOS также поддерживает присвоение имен группам флагов событий. Эти имена используются только при отладке. Я исключил их из Nucleus SE, чтобы сэкономить память.

Количество флагов в группе

В Nucleus RTOS группы флагов событий содержат по 32 флага, в Nucleus SE я уменьшил их число до восьми, так как этого достаточно для простых приложений и позволяет сэкономить ОЗУ. Nucleus SE может быть легко модифицирована, если требуются более крупные группы флагов событий.

Функция поглощения флагов

В Nucleus RTOS присутствует функция для очистки (поглощения) флагов событий после их чтения. Я решил исключить эту функцию из Nucleus SE для упрощения системы, так как поглощение (удаление) флагов происходит, когда все заблокированные задачи получили флаги для чтения, а это было бы сложно реализовать. При необходимости, считывающая флаги задача всегда может очистить их при помощи отдельного вызова API.

Нереализованные вызовы API

Nucleus RTOS поддерживает семь служебных вызовов для работы с группами флагов событий. Из них, три не реализованы в Nucleus SE. Детали этих вызовов, а также решение об их исключении из Nucleus SE были описаны выше.
В следующей статье будут рассматриваться семафоры.

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

Автор: EasyLy

Источник

Поделиться

* - обязательные к заполнению поля