====== 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.]]## Например, его можно задать так:
<code cpp>
#define OS_MSG_TYPE    const char *
</code>

и передавать в сообщениях текстовые строки.

Для работы с указателем на сообщение, он должен быть создан сервисом ##[[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]]##, который возвращает ноль, если сообщение свободно.

Ниже приведен пример использования указателя на сообщение:
<code cpp>
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.
        // После выполнения этого сервиса сообщение освобождается.
        ...
    }
}
</code>


~~UP~~

===== Короткие однобайтовые сообщения =====

Тип короткого сообщения по умолчанию //unsigned char//, однако, он может быть изменен в файле ##[[osa:ref:appendix:configuration|OSAcfg.h]]## заданием константы ##[[osa:ref:description:data_types#OST_SMSG|OST_SMSG]]##:
<code cpp>
#define OS_SMSG_TYPE    unsigned long  // изменение типа SMSG
</code>

Если его изменять, то теряется преимущество в использовании RAM. Тем не менее, это иногда может оказаться полезным с точки зрения функционирования программы. Например, при использовании указателя на сообщение, телом которого является unsigned long, мы не можем изменять содержимое тела сообщения, пока сообщение не будет получено и обработано другой задачей (в пердыдущем примере //Message[]//). В случае с короткими сообщениями это ограничение снимается, т.к. все тело сообщения записывается в переменную сообщения.

<note>
Нельзя задавать типом короткого сообщения структуры, массивы и объединения. Короткому однобайтовому сообщени можно давать только числовой тип: char, int long, bit, а также float и double.
</note>


Во всем остальном работа с короткими сообщениями повторяет работу с указателями на сообщения.Ниже приведен пример использования короткого сообщения:

<code cpp>
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) ...;
        ...
    }
}
</code>

~~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~~