TinyFrame
TinyFrame — это простая библиотека для создания и анализа фреймов данных, отправляемых через последовательный интерфейс (например, UART, telnet, сокет). Код написан с использованием --std=gnu99
и в основном совместим с --std=gnu89
.
Библиотека предоставляет высокоуровневый интерфейс для обмена сообщениями между двумя участниками. Многопользовательские сеансы, прослушиватели ответов, контрольные суммы, тайм-ауты — всё это обрабатывается библиотекой.
TinyFrame подходит для широкого спектра приложений, включая связь между микроконтроллерами, в качестве протокола для приложений на базе FTDI или для обмена данными через UDP-пакеты.
Библиотека позволяет регистрировать прослушиватели (функции обратного вызова) для ожидания:
TinyFrame является реентерабельным и поддерживает создание нескольких экземпляров с ограничением, что их структура (размеры полей и тип контрольной суммы) одинакова. Существует поддержка добавления многопоточного доступа к общему экземпляру с помощью мьютекса.
В папке utils/
также есть вспомогательные функции для создания и разбора полезных нагрузок сообщений.
Порты
TinyFrame был портирован на несколько языков:
Обратите внимание, что большинство портов являются экспериментальными и могут содержать различные ошибки или отсутствующие функции. Тестировщики приветствуются :)
Функциональный обзор
Основная функциональность TinyFrame объясняется здесь. Для получения подробной информации, такой как функции API, рекомендуется прочитать комментарии к документации в заголовочном файле.
Структура фрейма
Каждый фрейм состоит из заголовка и полезной нагрузки. Обе части могут быть защищены контрольной суммой, гарантируя, что фрейм с искажённым заголовком (например, с повреждённым полем длины) или повреждённой полезной нагрузкой будет отклонён.
Заголовок фрейма содержит идентификатор фрейма и тип сообщения. Идентификатор фрейма увеличивается с каждым новым сообщением. Самый старший бит поля ID установлен в 1 для одного участника и в 0 для другого, чтобы избежать конфликта.
Идентификатор фрейма можно повторно использовать в ответе, чтобы связать два сообщения вместе. Значения поля типа определяются пользователем.
Все поля во фрейме имеют настраиваемый размер. Изменяя поле в конфигурационном файле, например TF_LEN_BYTES
(1, 2 или 4), библиотека автоматически переключается между uint8_t
, uint16_t
и uint32_t
для всех функций, работающих с этим полем.
,-----+-----+-----+------+------------+- - - -+-------------,
| SOF | ID | LEN | TYPE | HEAD_CKSUM | DATA | DATA_CKSUM |
| 0-1 | 1-4 | 1-4 | 1-4 | 0-4 | ... | 0-4 | <- size (bytes)
'-----+-----+-----+------+------------+- - - -+-------------'
SOF ......... начало фрейма, обычно 0x01 (необязательно, настраивается)
ID ......... идентификатор фрейма (старший бит — бит участника)
LEN ......... количество байтов данных во фрейме
TYPE ........ тип сообщения (можно использовать любые значения)
HEAD_CKSUM .. контрольная сумма заголовка
DATA ........ LEN байт данных
DATA_CKSUM .. контрольная сумма данных (опускается, если LEN равен 0)
Прослушиватели сообщений
TinyFrame основан на концепции прослушивателей сообщений. Прослушиватель — это функция обратного вызова, ожидающая получения сообщения определённого типа или идентификатора.
Существует 3 типа прослушивателей в порядке приоритета:
Прослушиватели идентификаторов можно зарегистрировать автоматически при отправке сообщения. Все прослушиватели также можно регистрировать и удалять вручную.
Прослушиватели идентификаторов используются для получения ответа на запрос. При регистрации прослушивателя идентификатора можно прикрепить пользовательские данные, которые будут доступны для функции обратного вызова прослушивателя. Эти данные (void *
) могут быть любой переменной контекста приложения. Слушатели могут быть назначены с таймаутом. Когда срок действия слушателя истекает, перед его удалением
вызывается обратный вызов с данными полезной нагрузки NULL, чтобы позволить пользователю free()
любые
прикреплённые пользовательские данные. Это происходит только в том случае, если пользовательские данные не равны NULL.
Обратные вызовы слушателей возвращают значения перечисления TF_Result
:
TF_CLOSE
— сообщение принято, удалите слушатель;TF_STAY
— сообщение принято, оставайтесь зарегистрированным;TF_RENEW
— то же самое, что и TF_STAY
, но срок действия ID слушателя обновляется;TF_NEXT
— сообщение НЕ принято, сохраните слушатель и передайте сообщение следующему
слушателю, способному его обработать.TinyFrame использует два буфера данных: небольшой буфер передачи и больший буфер приёма. Буфер передачи используется для подготовки байтов к отправке, либо сразу, либо по кругу, если буфер недостаточно велик. Буфер должен содержать только весь заголовок фрейма, поэтому, например, 32 байта должно быть достаточно для коротких сообщений.
Используя функции отправки *_Multipart()
, можно дополнительно разделить заголовок фрейма и полезную нагрузку на несколько вызовов функций, позволяя приложению, например, генерировать
полезную нагрузку «на лету».
В отличие от буфера передачи, буфер приёма должен быть достаточно большим, чтобы вместить весь фрейм. Это связано с тем, что окончательная контрольная сумма должна быть проверена до обработки фрейма.
Если требуются фреймы больше размера возможного буфера приёма (например, во встраиваемых системах с небольшой оперативной памятью), рекомендуется реализовать механизм транспортировки нескольких сообщений на более высоком уровне и отправлять данные порциями.
TF_
.TF_Integration.example.c
и TF_Config.example.c
, чтобы узнать, как настроить и интегрировать библиотеку.TF_Init()
с TF_MASTER
или TF_SLAVE
в качестве аргумента. Это создаёт дескриптор. Используйте TF_InitStatic()
, чтобы избежать использования malloc().tf.userdata
/ tf.usertag
.TF_WriteImpl()
, объявленный в нижней части заголовочного файла как extern
. Эта функция используется TF_Send()
и другими для записи байтов в ваш UART (или другой физический уровень). Фрейм может быть отправлен целиком или несколькими частями в зависимости от его размера.TF_AcceptChar(tf, byte)
, чтобы передать данные чтения в TF. TF_Accept(tf, bytes, count)
примет несколько байтов.TF_Tick()
. Период вызова определяет длину одного тика. Он используется для тайм-аута парсера в случае, если он застревает в плохом состоянии (например, получая частичный фрейм), а также может тайм-аут ID слушателей.TF_AddTypeListener()
или TF_AddGenericListener()
.TF_Send()
, TF_Query()
, TF_SendSimple()
, TF_QuerySimple()
. Функции запроса принимают обратный вызов слушателя (указатель на функцию), который будет добавлен в качестве ID слушателя и ожидает ответа.*_Multipart()
вышеуказанных функций отправки для полезных нагрузок, созданных в нескольких вызовах функций. Полезная нагрузка отправляется позже путём вызова TF_Multipart_Payload()
, и фрейм закрывается с помощью TF_Multipart_Close()
.TF_CKSUM_CUSTOM8
, 16 или 32 и реализуйте три функции контрольной суммы.TF_Respond()
с объектом msg, который вы получили, заменив указатель data
(и len
) ответом.TF_ResetParser()
. Его также можно сбросить автоматически после тайм-аута, настроенного в файле конфигурации.msg->data
, чтобы позволить пользователю освободить пользовательские данные. Поэтому это необходимо.Вы можете оставить комментарий после Вход в систему
Неприемлемый контент может быть отображен здесь и не будет показан на странице. Вы можете проверить и изменить его с помощью соответствующей функции редактирования.
Если вы подтверждаете, что содержание не содержит непристойной лексики/перенаправления на рекламу/насилия/вульгарной порнографии/нарушений/пиратства/ложного/незначительного или незаконного контента, связанного с национальными законами и предписаниями, вы можете нажать «Отправить» для подачи апелляции, и мы обработаем ее как можно скорее.
Комментарии ( 0 )