Документ описывает упрощенный протокол взаимодействия вычислительных устройств, предназначенный главным образом для взаимодействия между устройствами со слабыми ресурсами между собой с использованием любых каналов связи, способных передавать текстовую информацию (COM, TCP/IP и т. д.). В рамках протокола предполагается коммуникация между устройствами по принципу точка-точка, одно из устройств считается управляющим, другое управляемым, однако различия между ними не велики. Так же в рамках описания форматов сообщений указываются передающее и принимающее устройства (передающее устройство инициирует процесс обмена сообщениями, при этом им может быть как управляющее, так и управляемое устройство в зависимости от ситуации). Управляемое устройство может быть хабом, при этом оно объединяет несколько других устройств.
Устройства взаимодействуют между собой путем двухстороннего обмена текстовыми сообщениями Каждое сообщение — строка символов в кодировке UTF-8. Сообщения разделяются символом перевода строки с кодом 10 ("\n" в языке С).
Сообщения состоят из нескольких элементов, первый из которых называется заголовком, остальные аргументами. Элементы сообщения разделяются символом с кодом 124 "|". Сами элементы сообщений не должны содержать символы "\n" и "|".
Пример сообщения:
info|Argument 1|Argument 2|Argument 3\n
Сами элементы сообщений не должны содержать символов «\n» и «|».
Для выполнения ряда наиболее распространенных действий зарезервирован ряд заголовков, назначение которых описано ниже. Остальные заголовки могут использоваться в зависимости от необходимости.
Информационное сообщение. Заголовок — info. Предназначено для передачи информации, не требующей специальной обработки (например, отладочная информация) и предназначенной для передачи ее человеку (разработчику или оператору). Сообщение не требует ответа от принимающего устройства. Аргументы сообщения — текстовые строки, содержащие информацию, предназначенную для прочтения человеком.
Сообщение готовности к работе. Заголовок — ready. Может использоваться устройством для уведомления другого устройства о готовности к работе, например, после окончания загрузки устройства. Аргументы отсутствуют.
Запрос идентификации устройства. Заголовок — identify. Аргументы отсутствуют. Принимающее устройство должно в течении 5 секунд вернуть ответное сообщение с заголовком deviceinfo со следующими аргументами:
1. Уникальный идентификатор устройства в виде текстового шестнадцатеричного представления UUID "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" или "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".
2. Человеко-читаемое название (не должно быть в формате UUID).
Запрос идентификации устройства-хаба. Заголовок — identify. Аргументы отсутствуют. Принимающее устройство должно в течении 5 секунд вернуть ответное сообщение с заголовком deviceinfo со следующими аргументами:
1. Специальный идентификатор "#hub".
2. Уникальный идентификатор устройства в виде текстового шестнадцатеричного представления UUID "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" или "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".
3. Человеко-читаемое название.
Перечисление подключенных к хабу устройств. Заголовок — identify_hub. В ответ передаются сообщения device_info со следующими аргументами:
1. Уникальный идентификатор устройства в виде текстового шестнадцатеричного представления UUID "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}" или "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx".
2. Человеко-читаемое название.
Сообщение синхронизации. Заголовок — sync. Предназначено для уведомления принимающего устройства о том, что передающее устройство находится в рабочем состоянии. Используется для безопасного синхронного вызова функций, в остальное время возможно использование разработчиком для собственных целей. Аргументы отсутствуют.
Команда. Заголовок — call. Первый аргумент — название команды (любое кроме зарезервированных, описанных в разделе "Зарезервированные названия команд"). Остальные аргументы сообщения — аргументы команды. В процессе работы может передаваться регулярное сообщение sync (рекомендуется для нестабильных каналов связи). Принимающее устройство по окончании выполнения должно вернуть сообщение с заголовком ok в случае успешного завершения (аргументы содержат возвращаемые значения) или err в случае неудачи (аргументы на усмотрение разработчика).
Измерение. Заголовок — meas. Аргументы сообщения (в порядке следования):
1 — название датчика.
2 и далее — значение. (см. Форматы данных сенсоров)
Сообщение об изменении состояния устройства. Сообщение — statechanged. Передается устройством, когда происходит изменение его состояния. Аргументы:
1. Название команды или "#" (см. раздел "Состояние устройства").
2. Номер аргумента команды (начиная с 1) или название дополнительного параметра устройства.
3. Новое значение.
Широковещательное уведомление о готовности сервера (для сетей ptp, поддерживающих широковещательные запросы, например, UDP запрос в локальной IP сети). Заголовок — server_ready. Аргументы не требуются, но возможны, если это необходимо для идентификации сервера. Устройства, принявшие сообщение, могут идентифицировать сервер (по аргументам или, например, адресу отправителя в IP сети) и подключиться к нему.
Широковещательный запрос на поиск устройства (для сетей ptp, поддерживающих широковещательные запросы, например, UDP запрос в локальной IP сети). Заголовок — find_device. Аргумент — имя или идентификатор устройства, возможны дополнительные аргументы, если это необходимо для идентификации сервера. Устройство с указанным именем или адресом, принявшее сообщение, может идентифицировать сервер (по аргументам или, например, адресу отправителя в IP сети) и подключиться к нему.
Отправка сообщений устройству, находящемуся за хабом, происходит аналогично отправке сообщений самому устройству, но к каждому сообщению добавляется в начало два аргумента: специальный идентификатор "#hub" и идентификатор целевого устройства в виде текстового шестнадцатеричного представления UUID "{xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx}". Аналогичным образом приходят ответные сообщения.
Название |
Параметры |
Описание и возвращаемые значения |
---|---|---|
#sensors |
отсутствуют |
Запрос списка датчиков. Возвращаемое значение — список датчиков (формат описан ниже в разделе "Формат описания датчиков") |
#controls |
отсутствуют |
Запрос описания интерфейса управления. Возвращаемое значение — писание интерфейса управления (формат описан ниже в разделе "Формат описания интерфейса") |
#state |
отсутствуют |
Запрос состояния устройства (см. раздел "Состояние устройства") |
|
|
|
При расширении списка зарезервированных команд в дальнейшем их названию будут начинаться с "#".
Описание датчиков представляет собой xml или json документ, которому соответствует список датчиков с атрибутами. Для каждого датчика указывается название, тип и ограничения. Имя сенсора ($name) уникально в пределах устройства. Атрибут сенсора "type" описывает формат передаваемого значения в сообщении. Форматы передаваемых значений описаны ниже в разделе Форматы данных сенсоров.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:annotation>
<xs:documentation xml:lang="ru">
Sensors definition schema for ArduinoRpc library.
</xs:documentation>
</xs:annotation>
<xs:element name="sensors">
<xs:complexType>
<xs:sequence>
<xs:element name="sensor" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="constraints" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:anyAttribute namespace="##local" processContents="lax"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="name" type="xs:string"/>
<xs:attribute name="type">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="single"/>
<xs:enumeration value="single_lt"/>
<xs:enumeration value="single_gt"/>
<xs:enumeration value="text"/>
<xs:enumeration value="packet"/>
<xs:enumeration value="packet_lt"/>
<xs:enumeration value="packet_gt"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
<sensors>
<sensor name="$name" type="$type">
<constraints key1="$value1" key2="$value2"/>
</sensor>
<sensor><!--sensor definition--></sensor>
</sensors>
{"$schema":"http://json-schema.org/draft-04/schema#","type":"object","properties":{"sensors":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"type":{"type":"string","enum":["single","single_lt","single_gt","text","packet","packet_lt","packet_gt"]},"constraints":{"type":"object","properties":{"*":{"type":"string"}}}},"required":["name","type"]}}},"required":["sensors"]}
{"sensors" : [
{
"name" : "$name",
"type" : "$type",
"constraints" :
{
"$key1" : "$value1",
"$key2" : "$value2"
}
},
{
//sensor definition
}
]}
В различных форматах могут использоваться метки локального и глобального времени. Локальное время — время в миллисекундах, измеряемое на устройстве от какой-то фиксированной точки (но не известной). Например — от момента включения устройства. Глобальное время — количество миллисекунд, прошедшее с 01.01.1970г. Использование глобального времени возможно при наличии на устройстве часов реального времени.
Каждый формат данных описывает структуру самих данных и способ передачи в сообщении "meas".
Тип сенсора |
Описание |
---|---|
single |
Набор числовых значений с плавающей точкой, передающихся текстом, представляющих собой один многомерный отсчет. В сообщении каждое отдельное число передается как один аргумент сообщения. В описании сенсора в "constraints" может присутствовать параметр "dims", в котором указывается размерность значений (>=1, по-умолчанию 1). Пример — передача координаты (x,y,z) meas|coords|12.0|16.3|67.9 |
single_lt |
Метка локального времени и набор числовых значений с плавающей точкой, передающихся текстом, представляющих собой один многомерный отсчет. В остальном тип аналогичен типу "single". Пример — передача координаты (x,y,z) meas|coords_lt|123456|12.0|16.3|67.9 123456 — метка времени, далее 3 координаты |
single_gt |
Метка глобального времени и набор числовых значений с плавающей точкой, передающихся текстом, представляющих собой один многомерный отсчет. В остальном тип аналогичен типу "single". Пример — аналогично single_lt |
text |
1 или более аргументов сообщения, содержащих текст |
packet |
Массив одиночных значений типа "бинарный формат с плавающей запятой одинарной точности" по стандарту IEEE 754 (в языке С — тип float), закодированный в base64. В описании сенсора в "constraints" может присутствовать параметр "dims", в котором указывается размерность значений (>=1, по-умолчанию 1). В описании сенсора в "constraints" может присутствовать параметр "fixed_size", в котором указывается количество значений в пакете. При этом "количество элементов в пакете" = "количество значений" * "размерность". В противном случае размер пакета может меняться в процессе работы устройства, однако количество элементов в массиве должно быть кратно размерности значений. При этом "количество значений" = "количество элементов" / "размерность". Пример — передача координат (x,y,z) meas|coords|AABAQWZmgkHNzIdCAABQQc3MNEHNzKxB 2 значения по 3 координаты (12.0;16.3;67.9), (13.0;11.3;21.6) |
packet_lt |
Метка локального времени и массив одиночных значений типа "бинарный формат с плавающей запятой одинарной точности" по стандарту IEEE 754 (в языке С — тип float), закодированный в base64. В остальном тип аналогичен типу "packet". Пример — передача координат (x,y,z) meas|coords|123456|AABAQWZmgkHNzIdCAABQQc3MNEHNzKxB 123456 — метка времени, далее 2 значения по 3 координаты (12.0;16.3;67.9), (13.0;11.3;21.6) |
packet_gt |
Метка глобального времени и массив одиночных значений типа "бинарный формат с плавающей запятой одинарной точности" по стандарту IEEE 754 (в языке С — тип float), закодированный в base64. В остальном тип аналогичен типу "packet". Пример — аналогично packet_lt |
Элементы управления устройством объединены в группы, предназначенные для группировки самих элементов управления и дочерних групп. Размещение задается параметром "layout", принимающим значение "v" (по вертикали) или "h" (по горизонтали). Если не задано — по умолчанию по вертикали.
Команда ($cmd) для элемента управления уникальна в пределах интерфейса устройства и фактически может являться идентификатором элемента управления.
Атрибут "sync" указывает, нужно ли в процессе команды передавать ежесекундное сообщение "sync" для синхронизации (0 — не нужно, 1 — нужно, 1 по-умолчанию). Рекомендуется передавать сообщение в случае, если канал связи между устройствами не надежен и не имеет собственных средств поддержки соединения.
Если параметры для элемента управления не заданы, отображается кнопка, при нажатии отправляется команда без параметров. Если задан один параметр, генерируется один элемент UI в зависимости от типа параметра, при взаимодействии с которым отправляется команда. Если задан один параметр, но присутствует атрибут "force_button" со значением "1", или если параметров несколько, генерируется набор элементов UI согласно заданному размещению, соответствующих типам параметров, и кнопка, при нажатии на которую отправляется команда. Параметры команды добавляются в порядке следования в описании.
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:annotation>
<xs:documentation xml:lang="ru">
Controls definition schema for ArduinoRpc library.
</xs:documentation>
</xs:annotation>
<xs:simpleType name="LayoutType">
<xs:restriction base="xs:string">
<xs:enumeration value="v"/>
<xs:enumeration value="h"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="BoolType">
<xs:restriction base="xs:string">
<xs:enumeration value="0"/>
<xs:enumeration value="1"/>
</xs:restriction>
</xs:simpleType>
<xs:element name="controls">
<xs:complexType>
<xs:sequence>
<xs:element name="group" minOccurs="0" maxOccurs="unbounded" type="GroupType"/>
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:complexType name="GroupType">
<xs:sequence>
<xs:element name="group" type="GroupType" minOccurs="0" maxOccurs="unbounded"/>
<xs:element name="control" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="param" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:sequence>
<xs:element name="constraints" minOccurs="0" maxOccurs="1">
<xs:complexType>
<xs:anyAttribute namespace="##local" processContents="lax"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="title" type="xs:string"/>
<xs:attribute name="type">
<xs:simpleType>
<xs:restriction base="xs:string">
<xs:enumeration value="checkbox"/>
<xs:enumeration value="text_edit"/>
<xs:enumeration value="select"/>
<xs:enumeration value="slider"/>
<xs:enumeration value="dial"/>
</xs:restriction>
</xs:simpleType>
</xs:attribute>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="title" type="xs:string"/>
<xs:attribute name="command" type="xs:string"/>
<xs:attribute name="layout" type="LayoutType"/>
<xs:attribute name="sync" type="BoolType"/>
<xs:attribute name="force_button" type="BoolType"/>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="title" type="xs:string"/>
<xs:attribute name="layout" type="LayoutType"/>
</xs:complexType>
</xs:schema>
<controls>
<group title="$title" layout="v|h">
<group title="$title" layout="v|h">
<control title="$title" command="$cmd" layout="v|h" sync="1|0">
<param title="$title" type="$type">
<constraints key1="$value1" key2="$value2"/>
</param>
<param><!--param definition--></param>
</control>
<control><!-- control definition--></control>
</group>
<control><!--command definition--></control>
<group><!--group definition--></group>
</group>
</controls>
{"$schema":"http://json-schema.org/draft-04/schema#","definitions":{"group":{"type":"object","properties":{"element_type":{"type":"string","enum":["group"]},"layout":{"type":"string","enum":["v","h"]},"title":{"type":"string","minLength":1},"elements":{"type":"array","items":{"anyOf":[{"$ref":"#/definitions/group"},{"$ref":"#/definitions/control"}]}}},"required":["element_type","title"],"additionalProperties":false},"control":{"type":"object","properties":{"element_type":{"type":"string","enum":["control"]},"layout":{"type":"string","enum":["v","h"]},"title":{"type":"string","minLength":1},"command":{"type":"string","minLength":1},"sync":{"type":"string","enum":["0","1"]},"params":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string","minLength":1},"type":{"type":"string","enum":["checkbox","text_edit","select","slider","dial"]},"constraints":{"type":"object","properties":{},"additionalProperties":true}},"required":["title","type"],"additionalProperties":false}}},"required":["element_type","title","command"],"additionalProperties":false}},"type":"object","properties":{"controls":{"$ref":"#/definitions/group"}},"required":["controls"],"additionalProperties":false}
{"controls" : {
"element_type" : "group",
"title" : "$title",
"layout" : "v|h",
"elements" :
[
{
"element_type" : "group"
//group definition
},
{
"element_type" : "control",
"title" : "$title",
"layout" : "v|h",
"command" : "$command",
"sync": true|false
"params" : [
{
"title" : "$title",
"type" : "$type",
"constraints" :
{
"$key1" : "$value1",
"$key2" : "$value2"
}
}
]
}
]
}}
Тип параметра |
Возможные ограничения |
Элемент UI |
checkbox |
onValue — значение, передаваемое, когда чекбокс включен (по умолчанию "1") offValue — значение, передаваемое, когда чекбокс выключен (по умолчанию "0") |
Чекбокс, checkable кпопка |
text_edit |
|
Поле ввода (с кнопкой отправки справа, если параметр у контрола один) |
select |
values — список значений, разделенных символом ";" (если отсутствует, всегда отправляется "0") |
Выпадающий список |
slider |
min — минимальное значение (по умолчанию 0) max — минимальное значение (по умолчанию 1023) step — величина шаг (по умолчанию 1) layout — вид слайдера ("h" — горизонтальный, "v" - вертикальный) |
Слайдер |
dial |
min — минимальное значение (по умолчанию 0) max — минимальное значение (по умолчанию 1023) step — величина шаг (по умолчанию 1) |
"Крутилка" |
Состояние управляющего интерфейса устройства описывает текущие значения параметров команд устройства и значения дополнительных параметров, не связанных с интерфейсом управления. При изменении состояния устройство оповещает об этом подключенного клиента при помощи специального сообщения "statechanged". Аргументы сообщения струппированы по 3. Первым аргументом в группе идет команда, параметр которой изменился, или "#", если изменился дополнительный параметр, не связанный ни с какой командой. В первом случае вторым аргументом в группе идет номер аргумента команды (начиная с 1), во втором — название дополнительного параметра. Третий аргумент в группе — значение параметра. При запросе всего состояния устройства при помощи зарезервированной команды "#state" возвращается все состояние устройства в одном сообщении с заголовком "ok" и аргументами, сгруппированными по 3 по аналогии с сообщением "statechanged".