Устройство представляет собой объект с идентификатором и названием, обрабатывающий команды и передающий данные с датчиков. Идентификатор устройства представляет собой UUID и является глобально-уникальным. Команды, передаваемые устройству, имеют название и список позиционных аргументов. Сенсоры имеют тип и ограничения, к которым относится, например, размерность.
Интерфейс управления и датчики описываются двумя строками, содержащими xml-документы. Устройства взаимодействуют между собой с использованием текстового протокола, описанного в документе "Описание протокола взаимодействия между устройствами ptp".
Для упрощения разработки устройств под платформу Arduino была разработана библиотека ARpc. Библиотека состоит из одного класса ARpc, предназначенного для парсинга потока данных и обработки сообщений. Так как библиотека не привязана к конкретному каналу передачи данных, чтение и запись данных в канал осуществляется вне библиотеки. Для использования библиотеки необходимо определить две callback-функции - одну для обработки команд, другую для записи данных в канал передачи данных от устройства.
Для примера использования библиотеки разработаем тестовое устройство, миганиющее светодиодом и генерирующее двумерный гармонический сигнал (sin+cos).
Сенсоры устройства:
1. blinks_count - счетчик миганий светодиродом, одномерный.
2. sin_x - двумерный гармонический сигнал (одно измерение - sin, второе - cos).
Команды, обрабатываемые устройством:
1. blink - мигнуть светодиодом и сгенерировать измерение blinks_count с новым значением счетчика.
2. get_blinks_count - сгенерировать измерение blinks_count с текущим значением счетчика.
Код программы с комментариями:
#include <ARpc.h>
int ledPin=13;//пин светодиода
unsigned int blinksCount=0;//число миганий
const char *deviceName="led_blink_test";//имя устройства
const char *deviceId="{f84526c1-5e88-4315-81f8-f7da45daa09d}";//идентификатор устройства
//Описание интерфейса управления
const char *interfaceStr="<controls><group title=\"Device controls\">"
"<control command=\"blink\" sync=\"0\" title=\"blink\">"//команда blink
"<param type=\"slider\" title=\"delay\"><constraints max=\"1000\" min=\"100\"/></param>"//параметр - время горения в мс
"</control>"
"<control command=\"get_blinks_count\" title=\"get_blinks_count\"/>"//команда get_blinks_count
"</group></controls>";
//Описание датчиков
const char *sensorsDef="<sensors>"
"<sensor name=\"blinks_count\" type=\"single\"/>"//датчик blinks_count
"<sensor name=\"sin_x\" type=\"single\"><constraints dims=\"2\"/></sensor>"//датчик sin_x (двумерный)
"</sensors>";
//callback-функция для обработки команд, вызывается библиотекой ARpc
void processCommand(const char *cmd,const char *args[],int argsCount,ARpc *parser)
{
if(strcmp(cmd,"blink")==0&&argsCount>=1)//команда blink, проверяем что есть аргумент
{
int dl=String(args[0]).toInt();//аргумент - время горения светодиода в мс
//правим - от 100 до 1000 мс
if(dl<100)dl=100;
else if(dl>1000)dl=1000;
//мигаем
blink(dl);
//инкрементируем число миганий
++blinksCount;
//выдаем измерение
parser->writeMeasurement("blinks_count",String(blinksCount).c_str());
//сообщаем об успешном выполнении команды
parser->writeOk();
}
else if(strcmp(cmd,"get_blinks_count")==0)//команда get_blinks_count
{
//выдаем измерение
parser->writeMeasurement("blinks_count",String(blinksCount).c_str());
//сообщаем об успешном выполнении команды
parser->writeOk();
}
else parser->writeErr("Unknown cmd");//неизвестная команда
}
//callback-функция для отправки данных "на другой конец провода"
void arpcWriteCallback(const char *str)
{
Serial.print(str);//пишем в Serial
}
//объект парсера ARpc, 300 - объем буфера для сообщения
ARpc parser(300,&processCommand,&arpcWriteCallback,deviceId,deviceName);
//setup
void setup()
{
Serial.begin(9600);//запускаем Serial
pinMode(ledPin,OUTPUT);//настраиваем пин для мигания
parser.setControlsInterface(interfaceStr);//указываем строку с описанием интерфейса управления
parser.setSensorsDescription(sensorsDef);//указываем строку с описанием сенсоров
}
//мигание светодиодом
void blink(int dl)
{
digitalWrite(ledPin,HIGH);
delay(dl);
digitalWrite(ledPin,LOW);
}
//генерация отсчетов sin и cos
int t=0;
void writeSinVal()
{
//Генерируем строку со значениями, разделенными символом "|"
String sinVal;
sinVal+=String(sin(0.1*t));
sinVal+="|";
sinVal+=String(cos(0.1*t));
//отправляем измерение
parser.writeMeasurement("sin_x",sinVal.c_str());
//увеличиваем "время"
++t;
}
void loop()
{
//проверяем, нет ли данных в Serial
while(Serial.available())
parser.putChar(Serial.read());//если данные есть, записываем побайтово в объект парсера
writeSinVal();//генерируем следующий отсчет sin и cos
delay(500);//пауза пол-секунды
}