Сообщения - один из способов обмена информацией между задачами. Телом сообщения может быть все, что угодно: принятые по USART или прочитанные из EEPROM данные, состояния внешних датчиков, информация о нажатых кнопках и пр. В OSA предусмотрены два типа сообщений: указатели на сообщения и короткие однобайтовые сообщения.
Первые - наиболее общие, которые позволяют обмениваться любой информацией, любого размера и содержания. Между задачами идет обмен указателями на тела сообщений. Вторые - однобайтовые сообщения, которые могут принимать значения от 1 до 255 (0 - сообщение отсутствует). Этот тип сообщения реализован в OSA для экономии RAM. В отличие от указателя на сообщение, который занимает в памяти 2 байта (для PIC16) или 3 байта (для остальных пиков), короткое сообщение занимает 1 байт. Ниже будут рассмотрены оба типа сообщений.
Сообщение может находиться в двух состояниях: свободно и занято. Если в данный момент сообщение содержит полезную информацию (т.е. было отправлено какой-то задачей, но еще не обработано задачей, ждущей его), то сообщение считается занятым. Иначе - свободным.
Тип указателя определен по умолчанию как void*. Но его можно изменить, задав константу OST_MSG в файле OSAcfg.h. Например, его можно задать так:
#define OS_MSG_TYPE const char *
и передавать в сообщениях текстовые строки.
Для работы с указателем на сообщение, он должен быть создан сервисом OS_Msg_Create. Задача, ожидающая сообщение, переводится в режим ожидания до тех пор, пока сообщение не будет получено. Как только сообщение приходит, задача переводится в состояние готовности и, получив управление, извлекает сообщение по указанной ссылке и очищает тело сообщения, делая его свободным.
Для отправки сообщения существуют 3 сервиса: OS_Msg_Send, OS_Msg_Send_TO и OS_Msg_Send_Now.
OS_Msg_Send перед отправкой проверяет, свободно ли сообщение. Если нет (задача, которой сообщения отсылаются, по какой-то причине еще не обработала предыдущее), то сервис переводит задачу в состояние ожидания до тех пор, пока сообщение не освободится. Как только сообщение освободится, задача переводится в состояние готовности, и при получении управления она отправит новое сообщение.
OS_Msg_Send_TO - то же, что и OS_Msg_Send, только может выйти по таймауту, если предыдущее сообщение долго не освобождается.
OS_Msg_Send_Now перед отправкой сообщения не обращает внимания на то, занято сообщение или свободно. Предыдущее сообщение, если оно еще не обработано, затирается новым.
Для проверки занятости сообщения есть сервис OS_Msg_Check, который возвращает ноль, если сообщение свободно.
Ниже приведен пример использования указателя на сообщение:
OST_MSG_CB msg_cb; void Task_USARTReceive (void) { static char BUF[10]; // Буфер для приема данных по UART static char Message[10]; // Тело сообщения OS_Msg_Create(msg_cb); // Создаем сообщение перед работой с ним for (;;){ ... // Получаем данные и пишем их в буфер BUF ... // Проверяем, обработалось ли предыдущее сообщение OS_Cond_Wait(!OS_Msg_Check(msg_cb)); // Когда попали сюда, му уже уверены, что предыдущее сообщение // обработано и Message[] уже не содержит никакой полезной информации // Теперь копируем данные из буфера в тело сообщения Message[] memcpy(Message, BUF, 10); // и отправляем сообщение OS_Msg_Send(msg_cb, (OST_MSG)Message); ... } } . . . void Task_Work (void) { OST_MSG msg; for (;;) { OS_Msg_Wait(msg_cb, msg); // Здесь msg уже является указателем на Message // из задачи Task_USARTReceive. // После выполнения этого сервиса сообщение освобождается. ... } }
Тип короткого сообщения по умолчанию unsigned char, однако, он может быть изменен в файле OSAcfg.h заданием константы OST_SMSG:
#define OS_SMSG_TYPE unsigned long // изменение типа SMSG
Если его изменять, то теряется преимущество в использовании RAM. Тем не менее, это иногда может оказаться полезным с точки зрения функционирования программы. Например, при использовании указателя на сообщение, телом которого является unsigned long, мы не можем изменять содержимое тела сообщения, пока сообщение не будет получено и обработано другой задачей (в пердыдущем примере Message[]). В случае с короткими сообщениями это ограничение снимается, т.к. все тело сообщения записывается в переменную сообщения.
Во всем остальном работа с короткими сообщениями повторяет работу с указателями на сообщения.Ниже приведен пример использования короткого сообщения:
OST_SMSG smsg_Buttons; . . . void Task_Buttons (void) { OS_Smsg_Create(smsg_Buttons); for (;;) { . . . if (!RB0 || !RB1 || !RB2) OS_Smsg_Send(smsg_Buttons, (OST_SMSG)PORTB & 0x07); ... } } ... void Task_Work (void) { OST_SMSG smsg; for (;;) { OS_Smsg_Wait(smsg_Buttons, smsg); // Обработка нажатой кнопки if (smsg & 0x01) ...; if (smsg & 0x02) ...; if (smsg & 0x04) ...; ... } }
Сервис | Аргументы | Описание | Свойства |
---|---|---|---|
Создание | |||
OS_Msg_Create | (msg_cb) | Создает сообщение. | |
Отправка | |||
OS_Msg_Send | (msg_cb, message) | Отправляем сообщение msg_cb (тип OST_MSG_CB) с ожиданием освобождения | |
OS_Msg_Send_TO | (msg_cb, message, timeout) | То же, что и OS_Msg_Send с выходом по таймауту | |
OS_Msg_Send_Now | (msg_cb, message) | Отправляем сообщение msg_cb без ожидания освобождения | |
Проверка | |||
bool OS_Msg_Check | (msg_cb) | Проверить, активно ли сообщение (присутствует ли оно). | |
OS_Msg_Accept | (msg_cb, os_msg_type_var) | Принять существующее сообщение. | |
Ожидание | |||
OS_Msg_Wait | (msg_cb, os_msg_type_var) | Ожидаем сообщение msg_cb. | |
OS_Msg_Wait_TO | (msg_cb, os_msg_type_var, timeout) | То же, что и OS_Msg_Wait, с выходом по таймауту |
Сервис | Аргументы | Описание | Свойства |
---|---|---|---|
Создание | |||
OS_Smsg_Create | (smsg) | Создает короткое сообщение (фактически - просто обнуляет его) | |
Отправка | |||
OS_Smsg_Send | (smsg, smessage) | Отправляем сообщение smsg с содержимым smessage с ожиданием освобождения | |
OS_Smsg_Send_TO | (smsg, smessage, timeout) | То же, что и OS_Smsg_Send, но с выходом по таймауту | |
OS_Smsg_Send_Now | (smsg, smessage) | Отправляем короткое сообщение smsg с содержимым smessage без ожидания освобождения | |
Проверка | |||
bool OS_Smsg_Check | (smsg) | Проверить, активно ли сообщение (присутствует ли оно). | |
OS_Smsg_Accept | (smsg, os_smsg_type_var) | Принять существующее сообщение | |
Ожидание | |||
OS_Smsg_Wait | (smsg, os_smsg_type_var) | Ожидаем короткое сообщение smsg. | |
OS_Smsg_Wait_TO | (smsg, os_smsg_type_var, timeout) | То же, что и OS_Smsg_Wait, с выходом по таймауту |