Обработка событий во встроенном коде - PullRequest
1 голос
/ 22 октября 2008

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

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

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

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


(редактировать 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 ?? ) 

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

Ответы [ 7 ]

2 голосов
/ 22 октября 2008

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

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

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

1 голос
/ 22 октября 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) или другой поток. Когда происходит желаемое действие, драйвер создает маску всех соответствующих событий и отправляет их в задачу получателя.

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

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);
}
1 голос
/ 22 октября 2008

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

0 голосов
/ 09 декабря 2011

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

0 голосов
/ 02 февраля 2011

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

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

0 голосов
/ 06 ноября 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))

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

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

0 голосов
/ 22 октября 2008

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

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

...