Java на одноплатниках: легко и просто

Kate

Administrator
Команда форума
В какой-то момент, на нашем замечательном COVID карантине, появилось свободное время и посмотреть на одноплатные компьютеры, которых сейчас уйма всяких разных. Однако, работать с ними именно из Java оказалось достаточно большой проблемой, т.к. экосистема – оставляла желать лучшего. Нет, я не про запуск Java на одноплатных компьютерах, а про работу с периферией в лице сенсоров, датчиков и прочих устройств.

В результате блуждания по поисковикам, было найдено несколько возможностей:

  1. Oracle Java ME – проект, скорее мертв, чем жив. Давным-давно, в 2006 году, Oracle прибило его гвоздями к Raspberry Pi Model B/STM32429I-EVAL/32746GDISCOVERY с минимальными требованиями по железу того времени. И так выглядит скорее заброшенным, то похоже не полетел.
  2. Pi4j – неплохой проект от Robert Savage, который развивается до сих пор. Однако это просто враппер на WiringPi, который автор забросил и “прибитый” гвоздями к определенным платам. Сейчас на сколько я вижу, идут попытки отойти от этого.
  3. Diozero – так же неплохой проект от Matthew Lewis, однако как и предыдущие два, “прибит” гвоздями к определенным SoC или платам.
  4. UPD 1: DeviceIO от того же Оракла. Поддержка I2C/SPI для любого linux. GPIO так же, но через depricated sysfs. Работа с памятью для BCM2835 only. (за наводку спасибо qvas)
Если я что-то упустил, пишите в комментариях.

А как же “Write once and run anywhere?”, спросит читатель. А вот никак и точка.

“Моргать светодиодом” хотелось, но Си было вспоминать лень, Питон учить не хотелось еще больше, а вся мощная экосистема java, которая имеется на текущий момент оставалась за бортом и не давала покоя. Плюс академический интерес.

Несмотря на то, что мир за пределами JVM представлял для меня темный лес, то задача выглядела интересно. Да и учетом того, что современные одноплатники уже начали переходить на 64 бит, имеют большие тактовые частоты и несколько ядер. Имеют на борту такие объемы Memory/Storage, за которые не то, что программист, геймер каких то 15 лет назад продал бы душу “кремневому дьяволу”, то условия и возможности современного железа достаточно сильно поменялись...

И с этим хотелось что-то сделать...

Пройдя с нуля по тем же самым граблям, что и три библиотеки описанные выше, была поставлена себе задача:

  • нужна библиотека, которая не несет на борту дополнительного самописного нативного кода
  • библиотека работает на любом Linux, любого одноплатника (при наличии там драйверов)
  • библиотека поддерживает SPI/I2C/Serial/GPIO
  • библиотека работает как в JVM mode, так и Native. В результате чего ее можно будет использовать в экосистемах тех же Spring и Quarkus.

Архитектура​

Чтобы добиться требуемого, надо было научиться работать с Linux/POSIX из java, научиться компиляться в native из которого работать с том же Linux/POSIX, что на первый взгляд представлялось проблемой. Однако, через некоторое время, проблема была решена.

Для JVM mode был выбран неплохая библиотека JNA (да, там под капотом нативный libffi), о которой на хабре написано, включая и подводные камни работы с библиотекой. С последующей миграцией на Project Panama, как только проект выйдет из инкубатора.

Для Native, тут без вариантов – GraalVM.

В результате архитектура стала выглядеть так:

93bb85884340ce0a4209f303600e35f0.png

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

По крайней мере, в результате проверок, на Raspberry Pi Zero W и Raspberry Pi на Raspberry Pi OS 32/64 bits(который Debian) и Orange Pi Zero на Armbian, все прекрасно работает на тестовых примерах. В теории, т.к. там используется голый kernel 4.8+ будет работать из коробки на любом Linux и потенциально Android(который вроде как тот же линукс).

API и использование​

Я не буду описывать, что такое I2C/SPI/Serial и GPIO, материалов в google больше, чем достаточно. В рамках данного поста опишу просто как это использовать.

Данные интерфейсы мапятся в device files вида /dev/i2c*, /dev/spi*, /dev/serial* (тут бывают варианты) доступ к которым был реализован через API:

I2CBus.java

SpiBus.java

SerialPort.java

C GPIO ситуация несколько другая. С kernel 4.8 в Linux появилось возможность нормально взаимодействовать со всеми PIN-ами через device files, а не через sysfs. В результате чего, пины доступны всегда. Правда, стоит заметить, что нашелся и side effect, некоторые пины процессора, определяются линуксом как unused, но могут использоваться системой. Любая попытка обращения к ним приводит к полному зависанию системы. Спасает обычного пользователя тут одно - обычно эти пины на плату не выведены.

Подергать пины, поморгать светодиодом можно с помощью GpioManager.java.

Более полные примеры работы можно найти в тестовых примерах.

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

В результате архитектура библиотеки для java программиста стала выглядеть так:

f96b8a02d096aaeff39976aec9eabf3e.png

Сама библиотека доступна тут: https://github.com/java-embedded-framework/jef/

И да, не надо меня пинать за громкое название библиотеки. Ничего лучше на ум не пришло.

Что дальше?​

Если вы дочитали до этого момента, то значит вам это действительно интересно.

Если вы java-программист, берите и используете библиотеку, если необходимо.

Свой академический интерес я удовлетворил.

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

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

Но главная цель достигнута – из java работать на одноплатниках легко и просто и был получен неоценимый опыт. Получен опыт Linux/POSIX, работы с “железными протоколами”, работы с регистрами устройств. Выйти из ограничений виртуальной машины вполне возможно и там доступен новый чудный мир который возможно интегрировать в java-приложение.

На сим откланиваюсь. Спасибо всем кто прочитал статью. Если интересны какие то детали, пишите в комментариях.

P.S. В рамках статьи не упомянута native часть, ее так же нет в исходниках на github, если у community есть интерес по поводу GraalVM и как писать native приложения на java с подключением линуксовских библиотек, то раскрою тему в рамках отдельной статьи.

 
Сверху