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