Обработка событий во встроенном коде

Я хочу знать, как события используются во встроенном системном коде.

Основное намерение состоит в том, чтобы узнать, как именно устанавливаются/сбрасываются флаги событий в коде. и как определить, какая задача использует какой флаг события и какие биты флага устанавливаются/сбрасываются каждой задачей.

Пожалуйста, оставьте свое предложение или комментарии по этому поводу.

Заранее спасибо.


(изменить 1: скопировано из разъяснения в ответе ниже)

Извините, что не указали необходимые детали. На самом деле меня интересует анализ любого приложения, написанного на языке C с использованием ОС vxworks/Itron/OSEK. Например, в vxworks есть библиотека eventLib для поддержки обработки событий. Я хочу знать, как можно использовать такие системные процедуры для обработки событий в задаче. Что такое флаг события (это глобальный/локальный... или что?), как установить биты любого флага события и какая может быть возможная связь между флагами задачи и события??

Как задача может ожидать нескольких событий в режимах И и ИЛИ?? Мне попался один пример, в котором приведенный ниже сценарий выглядит опасным, но почему??

            Scenarios is ==> *[Task1 : Set(e1), Task2 : Wait(e1) and Set(e2), Task3 : Wait(e2) ]*                                             

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

                (Are there any more such scenarios possible in task-event handling which should be reviewed in code ?? ) 

Надеюсь вышеизложенной информации достаточно....


person Community    schedule 22.10.2008    source источник


Ответы (7)


Многие встроенные системы используют процедуры обработки прерываний (ISR) для обработки событий. Вы должны определить ISR для данного «флага» и сбросить этот флаг после обработки события.

Например, скажем, у вас есть устройство, выполняющее аналого-цифровое преобразование (АЦП). На устройстве у вас может быть ISR, который срабатывает каждый раз, когда ADC завершает преобразование, а затем обрабатывает его в ISR или уведомляет какую-либо другую задачу о доступности данных (если вы хотите отправить их по какому-либо протоколу связи). После того, как вы закончите это, вы сбросите флаг ADC, чтобы он мог снова сработать при следующем преобразовании.

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

person Community    schedule 22.10.2008

Этот вопрос должен предоставить больше контекста. Встроенные системы могут быть созданы с использованием широкого спектра языков, операционных систем (включая отсутствие операционной системы), фреймворков и т. д. Нет ничего универсального в том, как события создаются и обрабатываются во встроенной системе, точно так же, как нет ничего универсального в том, как события создаются. создается и обрабатывается в вычислительной технике в целом.

person Community    schedule 22.10.2008

EventLib в VxWorks похож на signal() в unix — он может указать другому потоку, что что-то произошло. Если вам нужно передать данные с событием, вы можете вместо этого использовать очереди сообщений.

События являются «глобальными» между отправителем и получателем. Поскольку каждый отправитель указывает, для какой задачи предназначено событие, в системе может быть несколько масок событий, причем каждая пара отправитель/получатель имеет свою собственную интерпретацию.

Основной пример:

 #define EVENT1       0x00000001
 #define EVENT2       0x00000002
 #define EVENT3       0x00000004
 ...
 #define EVENT_EXIT   0x80000000

 /* Spawn the event handler task (event receiver) */
 rcvTaskId = taskSpawn("tRcv",priority,0,stackSize,handleEvents,0,0,0,0,0,0,0,0,0,0);
 ...

 /* Receive thread: Loop to receive events */
 STATUS handleEvents(void)
 {
     UINT32 rcvEventMask = 0xFFFFFFFF;

     while(1)
     {
         UINT32 events = 0;

         if (eventReceive(rcvEventMask. EVENTS_WAIT_ANY, WAIT_FOREVER, &events) == OK)
         {
             /* Process events */
             if (events & EVENT1)
                 handleEvent1();
             if (events & EVENT2)
                 handleEvent2();
             ...
             if (events & EVENT_EXIT)
                 break;
         }
     }

     return OK;
 }

Отправителем события обычно является аппаратный драйвер (BSP) или другой поток. Когда происходит желаемое действие, драйвер строит маску всех соответствующих событий и отправляет их задаче-получателю.

Отправителю необходимо получить идентификатор задачи получателя. ID задачи может быть глобальным,

int RcvTaskID = ERROR;
...
eventSend(RcvTaskID, eventMask);

он может быть зарегистрирован получателем в задаче драйвера/отправителя,

static int RcvTaskID = ERROR;

void DRIVER_setRcvTaskID(int rcvTaskID)
{
    RcvTaskID = rcvTaskID;
}
...
eventSend(RcvTaskID, eventMask);

или задача драйвера/отправителя может вызвать метод API получателя для отправки события (оболочки).

static int RcvTaskID;
void RECV_sendEvents(UINT32 eventMask)
{
    eventSend(RcvTaskID, eventMask);
}
person Community    schedule 22.10.2008
comment
handleEvents - это функция, которая обрабатывает все события вашей системы? Если это так, я думаю, что это не очень полезно, поскольку вы дублируете работу, которую можно выполнить в ISR, на мой взгляд, если мы работаем с ISR ОС должны устанавливать события, а задачи всегда готовы обработать новое приходящее событие, нет необходимости в задаче, которая прослушивает события и назначает задачу для выполнения задания. - person fedi; 11.07.2016

Извините, что не указали необходимые детали. На самом деле меня интересует анализ любого приложения, написанного на языке C с использованием ОС vxworks/Itron/OSEK. Например, в vxworks есть библиотека eventLib для поддержки обработки событий. Я хочу знать, как можно использовать такие системные процедуры для обработки событий в задаче. Что такое флаг события (это глобальный/локальный... или что?), как установить биты любого флага события и какая может быть возможная связь между флагами задачи и события??

Надеюсь вышеизложенной информации достаточно....

person Community    schedule 22.10.2008
comment
Пожалуйста, удалите это и поместите уточнение в сам вопрос (вы можете отредактировать свой вопрос для этой цели). - person Ilya; 22.10.2008

Если вы спрашиваете, как устанавливать, очищать и проверять различные биты, представляющие события, этот пример может помочь. Основная стратегия состоит в том, чтобы объявить (обычно глобальную) переменную и использовать один бит для представления каждого условия.

unsigned char bit_flags = 0;

Теперь мы можем назначать события битам:

#define TIMER_EXPIRED   0x01   // 0000 0001
#define DATA_READY      0x02   // 0000 0010
#define BUFFER_OVERFLOW 0x04   // 0000 0100

И мы можем устанавливать, очищать и проверять биты с помощью побитовых операторов:

// Bitwise OR: bit_flags | 00000001 sets the first bit.
bit_flags |=  TIMER_EXPIRED;  // Set TIMER_EXPIRED bit.

// Bitwise AND w/complement clears bits: flags & 11111101 clears the 2nd bit.
bit_flags &= ~DATA_READY;     // Clear DATA_READY bit.

// Bitwise AND tests a bit.  The result is BUFFER_OVERFLOW
// if the bit is set, 0 if the bit is clear.
had_ovflow = bit_flags & BUFFER_OVERFLOW;

Мы также можем установить или очистить комбинации битов:

// Set DATA_READY and BUFFER_OVERFLOW bits.
bit_flags |=  (DATA_READY | BUFFER_OVERFLOW);

Вы часто будете видеть, как эти операции реализованы в виде макросов:

#define SET_BITS(bits, data)    data |=  (bits)
#define CLEAR_BITS(bits, data)  data &= ~(bits)
#define CHECK_BITS(bits, data)  (data & (bits))

Кроме того, примечание о прерываниях и подпрограммах обслуживания прерываний: они должны работать быстро, поэтому типичный ISR просто установит флаг, увеличит счетчик или скопирует некоторые данные и немедленно завершит работу. Затем вы можете проверить флаг и посетить мероприятие на досуге. Вероятно, вы не хотите выполнять длительные или чреватые ошибками действия в ISR.

Надеюсь, это полезно!

person Adam Liss    schedule 06.11.2008
comment
Хороший шаблон, но одно предостережение: если вы обращаетесь к одним и тем же полям как из прерываний, так и из основного цикла программы, они должны быть объявлены изменчивыми. - person naasking; 31.01.2021
comment
Хороший вопрос, спасибо! Однако будьте осторожны: volatile не означает атомарность, и нам могут понадобиться они оба, в зависимости от деталей программы. Переменная должна быть защищена мьютексом, если одна подпрограмма может изменить ее, пока другая получает к ней доступ. В противном случае они будут бороться друг с другом и могут создать тонкое состояние гонки, которое трудно отладить. Объявление переменной как volatile указывает компилятору не предполагать, что она останется постоянной, если текущий поток не изменит ее. Таким образом, вы бы сделали его изменчивым, если вам всегда нужно последнее значение, например, если вы опрашиваете его в цикле и ждете его изменения. - person Adam Liss; 03.02.2021

В одном семействе встраиваемых систем, которое я разработал (для микро PIC18Fxx с флэш-памятью ~ 128 КБ и ОЗУ 3,5 КБ), я написал библиотеку для обработки до 16 таймеров с разрешением 1/16 секунды (измеряется импульсом 16 Гц, поступающим на ЦП). ). Код настроен на определение того, находится ли какой-либо таймер в состоянии Expired или какой-либо выделенный вывод пробуждения сигнализирует, и если нет, переходит в спящий режим до истечения срока действия следующего таймера или изменения состояния входа пробуждения. Довольно удобный фрагмент кода, хотя, оглядываясь назад, я, вероятно, должен был разработать его для работы с несколькими группами из восьми таймеров, а не с одним набором из 16.

Ключевым аспектом моих процедур синхронизации, которые я считаю полезными, является то, что они в основном не управляются прерываниями; вместо этого у меня есть процедура «опроса, когда это удобно», которая обновляет таймеры счетчика 16 Гц. Хотя иногда кажется странным иметь таймеры, которые не запускаются через прерывание, работа таким образом позволяет избежать необходимости беспокоиться о прерываниях, происходящих в неурочное время. Если действие, управляемое таймером, не может произойти в прерывании (из-за вложенности стека и других ограничений), не нужно беспокоиться о таймере в прерывании — просто следите за тем, сколько времени прошло.

person Community    schedule 02.02.2011

Если вы заинтересованы в использовании управляемого событиями программирования на встроенном уровне, вам действительно следует изучить QP. Это отличная легкая структура, и если вы получите книгу Миро Самека «Практические диаграммы состояний UML в C/C++», вы найдете все, от того, как обрабатывать системные события во встроенном ядре Linux (ISR и т. д.), до обработки и создания их в сборке с помощью QP в качестве вашей среды. (здесь приведена ссылка на пример события).

person Community    schedule 08.12.2011