Эрланг Для Интернета Вещей

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

Разработка приложений для таких конструкторов практически ничем не отличается от обычной серверной разработки, за исключением того, что все же нужно учитывать ограничения по ресурсам.



Эрланг для Интернета вещей

По мере роста производительности и возможностей практика использования интерпретируемых языков высокого уровня, таких как Lua, Python, JS, для разработки приложений набирает все больше оборотов.

Некоторые языки постепенно проникают в своих «младших братьев» — микроконтроллеров, хотя и в весьма ограниченном варианте.

На это есть несколько причин:

  • быстрое прототипирование — при всем уважении к языку Си, на котором в основном ведется разработка для микроконтроллеров, лаконичным его назвать очень сложно.

    Языки высокого уровня позволяют писать меньше кода и упрощают внесение изменений в уже написанное, что очень важно на этапе прототипирования;

  • автоматическое управление памятью и абстрагирование механизмов сложных вычислений – думаю, в комментариях нет необходимости; оба ручных процесса при достаточном объёме проекта превращаются в источник множества головной боли;
  • упрощенная отладка и тестирование — интерпретируемый код легче проверить на рабочей станции перед полевым тестированием;
  • борьба со сложностью — зачастую высокая производительность порождает естественное прагматичное желание запихнуть в устройство больше предварительной обработки и анализа, что не добавляет простоты разработке.

Увы, за все удобства приходится платить.

В этом случае цена за удобство — ценнейшие ресурсы, производительность и размер кода (во многих случаях приходится носить с собой довольно большую среду исполнения).

Поэтому полевое использование языков высокого уровня в SoC и SoM — вещь неоднозначная и местами компромиссная.

Для разработки мы используем язык Erlang, применяя его как по прямому назначению (создание серверных приложений и плоскостей управления), так и весьма необычным образом — веб-приложений.

Поэтому идея использования инфраструктуры этого языка для создания IoT-решений возникла задолго до появления плат, на которых среда выполнения Erlang могла бы работать без проблем.

Было много причин использовать Erlang, наиболее убедительными из которых были:

  • Erlang очень полезен для анализа и создания двоичных последовательностей.

    Сопоставление шаблонов в сочетании с обработкой битовых данных позволяет очень быстро и лаконично реализовать двоичные протоколы;

  • отсутствие глобальных переменных и неизменяемость большинства данных — позволяет писать и, что не менее важно, поддерживать надежные приложения, в которых сложно случайно изменить что-то не так;
  • облегченные процессы обработки сообщений, очень похожие на те, с которыми приходится иметь дело разработчикам встраиваемых систем.

    По сути, это процедура инициализации и процедура, обрабатывающая входящие сообщения в бесконечном цикле, изменяя внутреннее состояние.

    Очень похоже на Arduino, только процессов может быть много и они работают параллельно, кроме того, в промежутке между сообщениями процедуру обработки можно менять на лету (горячая перезагрузка кода), что может быть очень удобно, когда вам нужно исправить мелкие ошибки или скорректировать поведение;

  • изолированная среда и автоматическое выделение памяти, думаю, не нуждаются в пояснениях;
  • кроссплатформенность – байт-код для среды выполнения ERTS можно скомпилировать на машине разработчика, а затем без проблем перенести на целевое устройство;
  • отличное средство самоанализа — возможность подключиться к работающему приложению по сети и посмотреть, почему оно тормозит, зачастую бывает очень полезна.

Первой производственной платой, на которой мы попробовали Erlang, была Карамбола 2 Литовские разработчики 8устройств , собранный на популярном чипе AR9331. К сожалению, первая версия этой платы не имела достаточного количества флэш-памяти для размещения среды выполнения.

Но вторая версия уже вполне могла вместить и ERTS, и небольшое приложение.



Эрланг для Интернета вещей

Установка проводилась классическим для данного типа устройств методом - созданием образа OpenWRT, содержащего Erlang, с последующей прошивкой его во флэш-память устройства.

Первый запуск среды, увы, привел к разочарованию — все зависло.

Причины этого я уже выступил на конференции InoThings 2018 , но, увы, как позже выяснилось, он ввёл коллег в заблуждение, ошибочно назвав источник такого поведения.

Я расскажу вам кратко.

При работе с файлами виртуальная машина ERTS использует тип off_t , размер которого в раздаче рассчитывается при автоконфигурации сборки (если она есть на целевой платформе) или подставляется из среды кросс-компиляции, как это произошло в случае с OpenWRT. Непонятно почему, но в настройках процессоров MIPS и производных файл конфигурации сборки содержит вдвое больший размер, чем есть на самом деле.

Проблема не возникла бы, если бы код виртуальной машины не использовал такие директивы препроцессора, как

  
   

#if SIZEOF_OFF_T == 4

и банальная проверка в коде (подозреваю, что конечный результат компиляции будет таким же, но на проверку сил не хватило):

if (sizeof(off_t) == 4) {

В результате ERTS собрался на первой итерации при попытке прочитать файл при запуске.

~/.

erlang.cookie (разновидность пароля для идентификации при взаимодействии с сетью) успешно получил мусор в высших рангах и с треском вылетел.

Корректирующий пластырь а пакет с предпоследней версией ERTS для OpenWRT можно скачать с сайта GitHub .

В остальном никаких проблем пока не наблюдалось, все работало как положено.

Второй аппаратной платформой, на которой мы опробовали Erlang, стал конструктор LinkIt Смарт 7688 от Медиатек и SeeedStudio , специально разработанный для быстрого прототипирования и изучения основ.

Эта плата просто апофеоз разврата по ресурсам - частота ядра MIPS выросла в полтора раза, больше оперативной памяти (для ERTS это важно, GC не спит) и больше флэш-памяти, а также как наличие карты MicroSD и возможность использования сопроцессора Atmel Atmega 32U4 в Дуэт-версии для работы с периферией.



Эрланг для Интернета вещей

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

Платформа поставляется с программным обеспечением с собственным веб-интерфейсом, а также библиотеками Python и NodeJS для разработки.

Косистема сборки не изменилась — это по-прежнему OpenWRT. Если по каким-то причинам все это многообразие вам кажется ненужным, то в упомянутом репозитории есть пакеты, содержащие минимальный набор необходимых компонентов .

После сборки образ флэш-памяти записывается на устройство и после перезагрузки можно смело пользоваться REPL. Чтобы создавать приложения на Erlang для IoT, необходимо решить одну архитектурную проблему.

Язык проектировался и разрабатывался с прицелом на то, чтобы служить плоскостью управления, то есть уровнем управления, тогда как работа с аппаратным обеспечением должна была осуществляться через FFI. Для этого существует три типа взаимодействия:

  1. порты — это отдельно запущенные процессы, написанные на каком-либо языке, взаимодействие с которыми происходит через потоки ввода/вывода.

    Они могут перезапуститься при падении, но из-за способа взаимодействия их коммуникативная производительность невысока (однако нам этого будет достаточно);

  2. Функции NIF выглядят как стандартные функции языка, но их вызов приводит к выполнению скомпилированного кода в пространстве времени выполнения.

    В случае ошибки они могут перетащить всю виртуальную машину.

  3. C-узел — когда работа целиком выполняется в отдельном процессе, а взаимодействие осуществляется как с отдельно запущенной средой выполнения по сети.

    Мы не будем рассматривать этот вариант из-за достаточно больших накладных расходов в пределах одного слабого устройства.

Дилемма такая: мы можем занести в FFI только транспортные вещи (т.е.

поддержку GPIO, I2C, SPI, PWM, UART и т.д.), а взаимодействие напрямую с датчиками и другими устройствами реализовать в Erlang, или наоборот, переместить драйверы устройств полностью помещаются в код внешних модулей, оставляя приложению возможность получать необработанные данные и обрабатывать их; в этом случае, возможно, имеет смысл использовать уже написанный код. Мы решили использовать первый вариант. На это есть несколько причин:

  • потому что мы можем;
  • Как я уже упоминал, Erlang поставляется с достаточно мощными инструментами для сборки и разборки двоичных последовательностей, с достаточно простой математикой, позволяющей не беспокоиться о защите от переполнения и прочей магии, используемой для обработки результатов.

    Не то чтобы эта магия пугала, но она оказывает шокирующее действие на неофитов;

  • интуитивно казалось, что драйверы на языке высокого уровня будут проще и надежнее (сбой процесса перезапустит супервизор, что приведет к повторной инициализации управляемого устройства).

Поэтому библиотека нашлась довольно быстро.

ЭрлангАЛЕ , который содержал уже реализованную поддержку GPIO, I2C и SPI через интерфейсы ядра, а о них, в свою очередь, уже позаботились разработчики аппаратной платформы.

Библиотека для работы с UART у нас уже был проверенный, плюс мы подключили его как дополнительный эрлексек — приложение, позволяющее создавать процессы ОС и управлять ими.

Все перечисленные приложения использовали порты (отдельно запускаемые бинарные процессы) для работы с железом и ОС, что требовало поддержки кросс-компиляции для языков C и C++, для чего было написано достаточно причудливый сценарий оболочки , который настраивает среду сборки для использования необходимых компиляторов.

Для тестирования принятых решений мы собрали простое устройство из LinkIt Smart 7866, двух I2C-устройств (датчика температуры и давления BMP280 и OLED-дисплея размером 128 на 64 пикселя) и USB-GPS-модуля, передающего данные через UART. GPIO проверялся на светодиоде на плате, он работает, а подключение SPI-дисплея показалось на данном этапе лишним усложнением.



Эрланг для Интернета вещей

В результате получается довольно компактное и простое приложение, источник Вы можете посмотреть это на Github. Я не буду углубляться в фрагменты кода, а попытаюсь дать обзор того, как работает приложение.

Драйвера для всех устройств реализованы как процессы gen_server, это удобно, поскольку позволяет добавлять в состояние дополнительные параметры и, иногда, состояние устройства.

Последнее можно увидеть на примере uart_gps — данные от UART поступают асинхронно и анализируются Парсер NMEA0183 и результаты записываются в состояние процесса, откуда они извлекаются по запросу.

Основной цикл приложения описан в модуле gps_temp_display - каждую секунду процесс считывает данные GPS, запрашивает состояние температуры и давления у BMP280 и отображает их на OLED-дисплее.

Ради интереса можно посмотреть драйверы дисплея И датчик БМП280 — всё получилось довольно лаконично, 150-170 строк на модуль.

В целом вышеописанная задача (написание кода драйвера, объединение всего в одно приложение, сборка и тестирование) заняла около четырех вечеров, в среднем два часа, т.е.

строго говоря – пара рабочих дней.

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

Конечно, наши попытки использовать Erlang для встраиваемых систем далеко не единственные.

В этом плане есть несколько интересных проектов:

  • нервы-project.org — направлен на создание встроенной экосистемы на базе Elixir;
  • www.grisp.org — еще более радикальный подход, который предполагает запуск ERTS непосредственно на оборудовании (голая система Erlang);
  • github.com/bettio/AtomVM И github.com/cloudozer/ling — попытки создать компактную версию ERTS, подходящую для использования в микроконтроллерах и слабых SoC/SoM.
Теги: #iot #Разработка для Интернета вещей #Сделай сам или Сделай сам #Интернет вещей #Функциональное программирование #erlang #mips #mips #mediatek #iot Platform #linkit smart
Вместе с данным постом часто просматривают: