uRPC

uRPC - web интерфейс, при помощи которого создаётся, сохраняется и загружается протокол взаимодействия устройств, основанный на правилах протокола проекта ximc. По готовому протоколу, в свою очередь, возможно загрузить готовую и работающую прошивку, wiki описание протокола, исходные коды кроссплатформенной библиотеки управления с подготовленными скриптами её сборки, графический интерфейс для всех функций библиотеки, набор врапперов для управления библиотекой из разнообразных языков программирования, примеры программ управления библиотекой из разных языков программирования, и другие дополнительные решения. В результате, после создания на web сайте протокола, можно сгенерировать набор файлов, чтобы уже через 30 минут управлять микроконтроллером через GUI. Главная цель: облегченный запуск новых электронных устройств с микроконтроллером, работающих под управлением компьютера.

Общие принципы работы URPC

Все коммуникации между ПК и микроконтроллером осуществляются по принципу клиент-сервер. При этом микроконтроллер является сервером, а ПК – клиентом. Это значит, что все коммуникации инициируются компьютером. Микроконтроллер не может отправить какие-либо данные на ПК самостоятельно, для этого ему требуется соответствующий запрос клиента (компьютера).

URPC позволяет осуществлять коммуникации двух типов:

Коммуникация посредством команд осуществляется следующим образом:

  1. Клиент (ПК) готовит данные для отправки на сервер (данный этап не является обязательным, поскольку допускаются команды, не передающие никаких данных на сервер).
  2. Клиент (ПК) отправляет запрос на выполнение команды клиенту (микроконтроллеру). В запросе также передаются входные данные
  3. После получения запроса на сервере (микроконтроллере) запускается обработчик, в котором производится обработка входных данных, собственно выполнение команды, подготовка выходных данных. По умолчанию URPC генерирует пустой обработчик, код обработчика пишется пользователем. Сразу после завершения обработчика сервер отправляет ответ клиенту вместе с набором выходных данных.
  4. Получив ответ сервера, клиент (ПК) передаёт управление пользовательской программе, которая может приступить к обработке выходных данных, полученных с сервера (допускаются команды без выходных данных).

Входные и выходные никак не зависят друг от друга и могут иметь формат. Единственное ограничение: суммарный объём всех входных данных, также как и суммарный объём всех выходных данных не должен превышать 250 байт.
Команды могут иметь входные и выходные аргументы, только входные аргументы, только выходные аргументы, а могут вообще не иметь аргументов.

Общение посредством аксессоров.

Аксессор – это специальная команда (а точнее set/get пара команд), предназначенная для работы с данными на сервере.
Отправка данных с клиента на сервер осуществляется посредством set-функции аксессора, получение данных – посредством вызова get-функции аксессора. Обе функции могут быть вызваны только клиентом (ПК).
Set-функция имеет только входные аргументы, get-функция – только выходные. Формат входных и выходных данных set и get функций одного аксессора должен быть одинаковым.
Также как и в случае команд после получения set и get запросов аксессора сервер (микроконтроллер) запускает соответствующие обработчики, содержание которых определяется пользователем.

Создание проекта

1. Задать название проекта

Придумать и задать название проекта, версию и нажать Update

2. Создать команды.

2.1. Определить команду

CID – это 4-буквенный идентификатор, который должен быть уникальным для каждой команды. CID не чувствителен к регистру, поэтому MYID и myId – это один и тот же идентификатор.

Name – это имя команды (такое же имя будет у функции вызова этой команды, а также будет включено в имена типов данных, связанных с этой командой). Рекомендуется писать имя команды в snake_case.

2.2. Добавить описание команд

После добавления команды нажать Edit и добавить описание команды на русском и английском языках в блоке Edit command properties в полях english и russian.

2.3. Добавить аргументы запроса и ответа команды

Name – имя аргумента. После генерации проекта к аргументам можно будет обращаться как к полям структуры по их именам. Рекомендуется писать имена аргументов в CamelCase.

Length – длина массива. Если оставить это поле пустым, то аргумент будет обычной переменой. Если в поле Length указать число, то данный аргумент будет представлять собой массив из Length элементов.

Суммарная длина всех аргументов команды не должна превышать 250 байт.

Обработка команд производится с учётом их размера в байтах. Поэтому для обеспечения обратной совместимости с последующими версиями протокола необходимо, чтобы размер команды оставался постоянным. Для этого рекомендуется обеспечить запас по размеру команды путём добавления массива reserved.
Пример:


typedef struct
{
  uint8_t foo;
  uint8_t reserved[41];
}
my_command_v1;
// sizeof(my_command_v1) = 1 + 41 = 42

typedef struct
{
  uint8_t foo;
  uint8_t bar[3];
  uint8_t reserved[38];
}
my_command_v1;
// sizeof(my_command_v2) = 1 + 3 + 38 = 42 = sizeof(my_command_v1)

2.4. Добавить описания аргументов на русском и английском

Для этого нужно нажать на кнопку Edit рядом с соответствующим аргументом в списке.

2.5 Добавить константы

В случае, если какой-то из аргументов будет представлять собой некоторый набор флагов, или же просто требуется определить универсальный набор констант для прошивки МК и программы для ПК, к каждому из аргументов можно создать набор констант, который будут зафиксированы в виде макроопределений в соответствующих заголовочных файлах.

Имена констант рекомендуется писать в верхнем регистре.

3. Добавить аксессоры

Чтобы добавить аксессоры, нужно перейти на главную страницу проекта. Это можно сделать, кликнув по ссылке Home слева вверху.

3.1. Определить аксессор

AID – это 3-буквенный идентификатор, который должен быть уникальным для каждого аксессора.
AID также не должен пересекаться с идентификаторами команд в формате G<AID> и S<AID>. То есть нельзя создавать аксессор с идентификатором MID, если уже определена команда с идентификатором GMID или SMID.
AID не чувствителен к регистру, поэтому MID и mId – это один и тот же идентификатор.

Name – это имя аксессора (такое же имя будет у функции вызова этого аксессора, а также будет включено в имена типов данных, связанных с этим аксессором). Рекомендуется писать имя команды в snake_case.

Если аксессор создаётся только для того, чтобы обеспечить существование хотя бы одного аксессора в проекте, в поле Name рекомендуется задать имя dummy.

3.2. Добавить описание аксессоров

После добавления аксессора нажать Edit и добавить описание аксессора на русском и английском языках в блоке Edit accessor properties в полях english и russian.

3.3. Добавить аргументы аксессора

Важно! для корректной работы аксессор должен содержать хотя бы один аргумент

Процесс добавления аргументов аксессоров аналогичен добавлению аргументов команд.

3.4. Добавить константы

Константы аргументов аксессоров аналогичны константам аргументов команд.

4. Сгенерировать исходный код проекта

Чтобы сгенерировать исходный код, нужно перейти на главную страницу проекта. Это можно сделать, кликнув по ссылке Home слева вверху.

4.1. Сгенерировать исходный код прошивки для МК

На панели справа в разделе Firmware из выпадающего списка выбрать микроконтроллер и нажать Generate.
Сохранить архив с кодом.

4.2 Сгенерировать код библиотеки

На панели справа в разделе Library нажать Generate.
Сохранить архив с кодом.

4.3 Сохранить параметры проекта

На панели справа в разделе Project нажать Save.
Сохранить JSON-файл.

PC библиотека

Описание

Результатом работы этого генератора является клиентская библиотека, основная задача которой - предоставление удобного C API для отправки запросов контроллеру и ожидание ответа от него. Сама библиотека предоставляется в виде CMake или QMake -проекта, из которого могут быть сгенерированы файлы для конечной системы сборки(проект для Microsoft Visual Studio, Code::Blocks, XCode, обычный Makefile. QMake генерирует проект для Visual Studio и обычный Makefile и т.д.) Для лучшего ознакомления с CMake рекомендуется посетить официальной сайт.

Инструкция по сборке CMake-проекта

Сборка под Windows

  1. Сгенерировать библиотеку нажатием кнопки "Generate", скачать её и распаковать архив
  2. Запустить CMake GUI
  3. Нажать кнопку "Browse Source..." и указать путь до папки с исходными кодами (в этой папке находится файл CMakeLists.txt)
  4. Нажать кнопку "Browse Build..." и указать путь к папке, в которую будут перемещены сгенерированный в ходе работы CMake
  5. файлы проекта
  6. Нажать кнопку "Configure"
  7. Выбрать в выпадающем списке появившегося окна необходимую цель генерации и дождаться окончания процесса. Заметьте, что цель генерации зависит от битности системы. Для x64 нужно выбрать "Visual Studio 12 2014 Win64"
  8. Нажать кнопку "Generate"
  9. Нажать "Finish"
Теперь у вас есть файлы проекта для интересующей вас IDE/Сборщика!

Для работы библиотеки под Windows понадобятся распространяемые пакеты Visual Studio в зависимости от версии. Пакеты для Visual Studio скачиваются с официального сайта, для VS2013, например, здесь.

Заметьте, установщик зависит от битности системы.

Сборка под linux

  1. Установить пакеты разработчика (g++, gcc, make...) через командную строку. Это можно сделать одной командой, ввести в терминале:

    sudo apt-get install build-essential

  2. Загрузить архив с библиотекой, распаковать его
  3. В директории src в распакованном архиве библиотеки запустить командную строку и выполнить cmake:

    cmake -D ENABLE_XINET=ON CMakeLists.txt

  4. В этой же директории выполнить make:
  5. make

  6. В результате сборки получилась библиотека .so. Чтобы ваши программы (и qt-отладчик) находили библиотеку, добавьте путь к библиотеке в переменную LD_LIBRARY_PATH. Например, если хотите из оболочки запустить программу, которая использует библиотеку, наберите в командной строке:
  7. export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:путь_к_директории_с_библиотекой

  8. Готово. Для использования библиотеки в ваших программах достаточно добавить заголовочный файл <имя_протокола>.h (лежит в директории с распакованным архивом библиотеки)

Генерация прошивки

Описание

На основе описания протокола этот генератор способен создать полноценную прошивку для целевого микроконтроллера, тем самым уберегая программиста от участи написания одного и того же шаблонного кода из раза в раз.

Инструкция по сборке

QT-дебаггер

Qt-отладчик генерируется с помощью кнопки Qt Debugger

Для сборки требуется: сгенерированная и собранная библиотека

Описание

По описанию протокола генератор способен создать программу-дебаггер с графическим интерфейсом. Эта программа позволяет взаимодействовать (отправлять команды, смотреть результат) с реальным и виртуальным устройством, работающим по данному протоколу. В сгенерированном архиве лежат исходные коды этой программы и проект для сборки

Инструкция по сборке qt-отладчика

Сборка под Windows

Подготовка

  1. Загрузить Qt 4.8.x с официального сайта или с нашего сервера.
  2. Установить Qt на диск C так, чтобы путь до бинарных файлов имел следующий вид C:\Qt\msvc2013\4.8.6_x64\bin\ для x64 и C:\Qt\msvc2013\4.8.6\bin\ для x32 .
  3. Прописать в системные пути: каталог C:\Qt\msvc2013\4.8.6_x64\bin\

Сборка

  1. Загрузить с сайта и распаковать архив с исходным кодом отладчика.
  2. Положить в каталог проекта файлы <имя_проекта>.dll<имя_проекта>.lib<имя_проекта>.h от предварительно скомпилированной библиотеки.
  3. Открыть CMake GUI и выбрать папку с проектом (по аналогии со сборкой библиотеки).
  4. Cконфигурировать проект для MSVC 2013(необходимо выбрать такую же платформу, как и при сборке библиотеки - Win32 или x64).
  5. Cгенерировать проект.
  6. Открыть в Visual Studio сгенерированный CMake-ом файл uRPC_debugger.vcxproj.
  7. Скомпилировать, запустить собранный файл.

Сборка под Linux

  1. Установить всё необходимое: qt4, cmake, make:

    sudo apt-get install libqt4-dev build-essential cmake

  2. В директории с распакованным архивом qt-отладчика запустить cmake:

    cmake CMakeLists.txt

  3. Не забудьте поместить заголовочный файл <имя библиотеки>.h и файл библиотеки <имя библиотеки>.so от предварительно собранной библиотеки в каталог с распакованным архивом qt-отладчика
  4. Запустить make:

    make

  5. Дождаться окончания сборки
  6. Запустить программу, предварительно добавив в переменную окружения путь к библиотеке:

    export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:`pwd`

    ./uRPC_debugger

    Заметьте, для работы с реальным устройством могут потребоваться права root.

Уточнение для Ubuntu 20.04

Ubuntu 20.04 не поддерживает Qt4. Для установки пакета нужно сначала выполнить sudo add-apt-repository ppa:rock-core/qt4 ,а уже затем sudo apt-get install libqt4-dev.

Запуск и работа с программой

Генерация документации

Описание

Результатом работы этого генератора является документация протокола в формате Textile - простого языка разметки, позволяющего пользователям описывать сложные схемы форматирования текстовых документов без использования внешних средств (WYSIWYG-редакторов, TEX, HTML и т.д.). Более подробно о синтаксисе и семантике языка Textile можно узнать в онлайн-песочнице (там же можно и потестировать сгенерированные файлы).

Инструкция по сборке

Содержимое созданных этим генератором файлов можно напрямую вставлять во все предназанченные для Textile текстовые поля Redmine(wiki, тексты сообщений, новости и т.д.).

Генерация примеров

Описание

uRPC способен генерировать примеры использования команд протокола на других языках программирования. Пока что реализовано только для Python. Результатом работы этого генератора являются два py файла: testpython.py и p(имя_протокола).py. В файле py(имя_проекта).py описаны все константы библиотеки, структуры данных и переменная lib, по которой можно вызвать любую функцию библиотеки. В файле testpython.py показан пример открытия\закрытия устройства.

Инструкция по сборке

Пример программы, использующей функции протокола, приведён в файле testpython.py. Заметьте, она начинается с импорта файла py(имя_протокола).py - этот файл должен лежать в одной папке с файлом вашей программы.

Пример вызова функции протокола из python:


        t = set_position_t()
        t.Position = 5
        lib.set_position(device_id, byref(t))

        x_pos = get_position_t()
        result = lib.get_position(device_id, byref(x_pos))
        print("Result: " + repr(result))
        if result == Result.Ok:
            print("Position: " + repr(x_pos.Position))

    
Обратите внимание на передачу аргументов: структуры передаются по ссылке, для этого используют функцию byref()