====== OSA : Сообщения ======
===== Введение =====
Сообщения - один из способов обмена информацией между задачами. Телом сообщения может быть все, что угодно: принятые по USART или прочитанные из EEPROM данные, состояния внешних датчиков, информация о нажатых кнопках и пр. В OSA предусмотрены два типа сообщений: **указатели на сообщения** и **короткие однобайтовые сообщения**.
Первые - наиболее общие, которые позволяют обмениваться любой информацией, любого размера и содержания. Между задачами идет обмен указателями на тела сообщений.
Вторые - однобайтовые сообщения, которые могут принимать значения от 1 до 255 (0 - сообщение отсутствует). Этот тип сообщения реализован в OSA для экономии RAM. В отличие от указателя на сообщение, который занимает в памяти 2 байта (для PIC16) или 3 байта (для остальных пиков), короткое сообщение занимает 1 байт. Ниже будут рассмотрены оба типа сообщений.
Сообщение может находиться в двух состояниях: свободно и занято. Если в данный момент сообщение содержит полезную информацию (т.е. было отправлено какой-то задачей, но еще не обработано задачей, ждущей его), то сообщение считается **занятым**. Иначе - **свободным**.
~~UP~~
===== Указатели на сообщения =====
Тип указателя определен по умолчанию как //void*//. Но его можно изменить, задав константу ##[[osa:ref:description:data_types#OST_MSG|OST_MSG]]## в файле ##[[osa:ref:appendix:configuration|OSAcfg.h.]]## Например, его можно задать так:
#define OS_MSG_TYPE const char *
и передавать в сообщениях текстовые строки.
Для работы с указателем на сообщение, он должен быть создан сервисом ##[[osa:ref:allservices:OS_Msg_Create|OS_Msg_Create]]##. Задача, ожидающая сообщение, переводится в режим ожидания до тех пор, пока сообщение не будет получено. Как только сообщение приходит, задача переводится в состояние готовности и, получив управление, извлекает сообщение по указанной ссылке и очищает тело сообщения, делая его свободным.
Для отправки сообщения существуют 3 сервиса: ##[[osa:ref:allservices:OS_Msg_Send|OS_Msg_Send]]##, ##[[osa:ref:allservices:OS_Msg_Send_TO|OS_Msg_Send_TO]]## и ##[[osa:ref:allservices:OS_Msg_Send_Now|OS_Msg_Send_Now]]##.
##[[osa:ref:allservices:OS_Msg_Send|OS_Msg_Send]]## перед отправкой проверяет, свободно ли сообщение. Если нет (задача, которой сообщения отсылаются, по какой-то причине еще не обработала предыдущее), то сервис переводит задачу в состояние ожидания до тех пор, пока сообщение не освободится. Как только сообщение освободится, задача переводится в состояние готовности, и при получении управления она отправит новое сообщение.
##[[osa:ref:allservices:OS_Msg_Send_TO|OS_Msg_Send_TO]]## - то же, что и ##[[osa:ref:allservices:OS_Msg_Send|OS_Msg_Send]]##, только может выйти по таймауту, если предыдущее сообщение долго не освобождается.
##[[osa:ref:allservices:OS_Msg_Send_Now|OS_Msg_Send_Now]]## перед отправкой сообщения не обращает внимания на то, занято сообщение или свободно. Предыдущее сообщение, если оно еще не обработано, затирается новым.
Для проверки занятости сообщения есть сервис ##[[osa:ref:allservices:OS_Msg_Check|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.
// После выполнения этого сервиса сообщение освобождается.
...
}
}
~~UP~~
===== Короткие однобайтовые сообщения =====
Тип короткого сообщения по умолчанию //unsigned char//, однако, он может быть изменен в файле ##[[osa:ref:appendix:configuration|OSAcfg.h]]## заданием константы ##[[osa:ref:description:data_types#OST_SMSG|OST_SMSG]]##:
#define OS_SMSG_TYPE unsigned long // изменение типа SMSG
Если его изменять, то теряется преимущество в использовании RAM. Тем не менее, это иногда может оказаться полезным с точки зрения функционирования программы. Например, при использовании указателя на сообщение, телом которого является unsigned long, мы не можем изменять содержимое тела сообщения, пока сообщение не будет получено и обработано другой задачей (в пердыдущем примере //Message[]//). В случае с короткими сообщениями это ограничение снимается, т.к. все тело сообщения записывается в переменную сообщения.
Нельзя задавать типом короткого сообщения структуры, массивы и объединения. Короткому однобайтовому сообщени можно давать только числовой тип: char, int long, bit, а также float и double.
Во всем остальном работа с короткими сообщениями повторяет работу с указателями на сообщения.Ниже приведен пример использования короткого сообщения:
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) ...;
...
}
}
~~UP~~
===== Сервисы для работы с сообщниями =====
==== Сообщения ====
^ Сервис ^ Аргументы ^ Описание ^ Свойства ^
| **Создание** ||||
| ##[[osa:ref:allservices:OS_Msg_Create|OS_Msg_Create]]## | ''(msg_cb)'' | Создает сообщение. | {{osa:ref:attr_call_not_int.png|Нельзя вызывать из прерывания}} |
| **Отправка** ||||
| ##[[osa:ref:allservices:OS_Msg_Send|OS_Msg_Send]]## | ''(msg_cb, message)'' | Отправляем сообщение //msg_cb// (тип ##[[osa:ref:description:data_types#OST_MSG_CB|OST_MSG_CB]]##) с ожиданием освобождения | {{osa:ref:attr_call_task.png|Разрешен вызов только в контексте задачи}}{{osa:ref:attr_call_ct_sw.png|Переключает контекст}} |
| ##[[osa:ref:allservices:OS_Msg_Send_TO|OS_Msg_Send_TO]]## | ''(msg_cb, message, timeout)'' | То же, что и ##[[osa:ref:allservices:OS_Msg_Send|OS_Msg_Send]]## с выходом по таймауту | {{osa:ref:attr_call_task.png|Разрешен вызов только в контексте задачи}}{{osa:ref:attr_call_ct_sw.png|Переключает контекст}}{{osa:ref:attr_call_to.png|Использует системный таймер}} |
| ##[[osa:ref:allservices:OS_Msg_Send_Now|OS_Msg_Send_Now]]## | ''(msg_cb, message)'' | Отправляем сообщение //msg_cb// без ожидания освобождения | {{osa:ref:attr_call_can_int.png|Есть расширенный сервис с суффиксом _I для работы в прерывании}} |
| **Проверка** ||||
| ''bool ''\\ ##[[osa:ref:allservices:OS_Msg_Check|OS_Msg_Check]]## | ''(msg_cb)'' | Проверить, активно ли сообщение (присутствует ли оно). | {{osa:ref:attr_call_can_int.png|Есть расширенный сервис с суффиксом _I для работы в прерывании}} |
| ##[[osa:ref:allservices:OS_Msg_Accept|OS_Msg_Accept]]## | ''(msg_cb, os_msg_type_var)'' | Принять существующее сообщение. | {{osa:ref:attr_call_can_int.png|Есть расширенный сервис с суффиксом _I для работы в прерывании}} |
| **Ожидание** ||||
| ##[[osa:ref:allservices:OS_Msg_Wait|OS_Msg_Wait]]## | ''(msg_cb, os_msg_type_var)'' | Ожидаем сообщение msg_cb. | {{osa:ref:attr_call_task.png|Разрешен вызов только в контексте задачи}}{{osa:ref:attr_call_ct_sw.png|Переключает контекст}} |
| ##[[osa:ref:allservices:OS_Msg_Wait_TO|OS_Msg_Wait_TO]]## | ''(msg_cb, os_msg_type_var, timeout)'' | То же, что и ##[[osa:ref:allservices:OS_Msg_Wait|OS_Msg_Wait]]##, с выходом по таймауту | {{osa:ref:attr_call_task.png|Разрешен вызов только в контексте задачи}}{{osa:ref:attr_call_ct_sw.png|Переключает контекст}}{{osa:ref:attr_call_to.png|Использует системный таймер}} |
~~UP~~
==== Короткие сообщения ====
^ Сервис ^ Аргументы ^ Описание ^ Свойства ^
| **Создание** ||||
| ##[[osa:ref:allservices:OS_Smsg_Create|OS_Smsg_Create]]## | ''(smsg)'' | Создает короткое сообщение (фактически - просто обнуляет его) | |
| **Отправка** ||||
| ##[[osa:ref:allservices:OS_Smsg_Send|OS_Smsg_Send]]## | ''(smsg, smessage)'' | Отправляем сообщение //smsg// с содержимым //smessage// с ожиданием освобождения | {{osa:ref:attr_call_task.png|Разрешен вызов только в контексте задачи}}{{osa:ref:attr_call_ct_sw.png|Переключает контекст}} |
| ##[[osa:ref:allservices:OS_Smsg_Send_TO|OS_Smsg_Send_TO]]## | ''(smsg, smessage, timeout)'' | То же, что и ##[[osa:ref:allservices:OS_Smsg_Send|OS_Smsg_Send]]##, но с выходом по таймауту | {{osa:ref:attr_call_task.png|Разрешен вызов только в контексте задачи}}{{osa:ref:attr_call_ct_sw.png|Переключает контекст}}{{osa:ref:attr_call_to.png|Использует системный таймер}} |
| ##[[osa:ref:allservices:OS_Smsg_Send_Now|OS_Smsg_Send_Now]]## | ''(smsg, smessage)'' | Отправляем короткое сообщение //smsg// с содержимым //smessage// без ожидания освобождения | {{osa:ref:attr_call_can_int.png|Есть расширенный сервис с суффиксом _I для работы в прерывании}} |
| **Проверка** ||||
| ''bool ''\\ ##[[osa:ref:allservices:OS_Smsg_Check|OS_Smsg_Check]]## | ''(smsg)'' | Проверить, активно ли сообщение (присутствует ли оно). | {{osa:ref:attr_call_can_int.png|Есть расширенный сервис с суффиксом _I для работы в прерывании}} |
| ##[[osa:ref:allservices:OS_Smsg_Accept|OS_Smsg_Accept]]## | ''(smsg, os_smsg_type_var)'' | Принять существующее сообщение | {{osa:ref:attr_call_can_int.png|Есть расширенный сервис с суффиксом _I для работы в прерывании}} |
| **Ожидание** ||||
| ##[[osa:ref:allservices:OS_Smsg_Wait|OS_Smsg_Wait]]## | ''(smsg, os_smsg_type_var)'' | Ожидаем короткое сообщение //smsg//. | {{osa:ref:attr_call_task.png|Разрешен вызов только в контексте задачи}}{{osa:ref:attr_call_ct_sw.png|Переключает контекст}} |
| ##[[osa:ref:allservices:OS_Smsg_Wait_TO|OS_Smsg_Wait_TO]]## | ''(smsg, os_smsg_type_var, timeout)'' | То же, что и ##[[osa:ref:allservices:OS_Smsg_Wait|OS_Smsg_Wait]]##, с выходом по таймауту | {{osa:ref:attr_call_task.png|Разрешен вызов только в контексте задачи}}{{osa:ref:attr_call_ct_sw.png|Переключает контекст}}{{osa:ref:attr_call_to.png|Использует системный таймер}} |
~~UP~~