В какой-то момент, на нашем замечательном COVID карантине, появилось свободное время и посмотреть на одноплатные компьютеры, которых сейчас уйма всяких разных. Однако, работать с ними именно из Java оказалось достаточно большой проблемой, т.к. экосистема – оставляла желать лучшего. Нет, я не про запуск Java на одноплатных компьютерах, а про работу с периферией в лице сенсоров, датчиков и прочих устройств.
В результате блуждания по поисковикам, было найдено несколько возможностей:
А как же “Write once and run anywhere?”, спросит читатель. А вот никак и точка.
“Моргать светодиодом” хотелось, но Си было вспоминать лень, Питон учить не хотелось еще больше, а вся мощная экосистема java, которая имеется на текущий момент оставалась за бортом и не давала покоя. Плюс академический интерес.
Несмотря на то, что мир за пределами JVM представлял для меня темный лес, то задача выглядела интересно. Да и учетом того, что современные одноплатники уже начали переходить на 64 бит, имеют большие тактовые частоты и несколько ядер. Имеют на борту такие объемы Memory/Storage, за которые не то, что программист, геймер каких то 15 лет назад продал бы душу “кремневому дьяволу”, то условия и возможности современного железа достаточно сильно поменялись...
И с этим хотелось что-то сделать...
Пройдя с нуля по тем же самым граблям, что и три библиотеки описанные выше, была поставлена себе задача:
Для JVM mode был выбран неплохая библиотека JNA (да, там под капотом нативный libffi), о которой на хабре написано, включая и подводные камни работы с библиотекой. С последующей миграцией на Project Panama, как только проект выйдет из инкубатора.
Для Native, тут без вариантов – GraalVM.
В результате архитектура стала выглядеть так:
Не буду описывать весь путь по граблям из плохой документации(либо ее полного отсутствия в случае GraalVM), длительного поиска в гугле, большого количества просмотров исходников из других языков и множества других проблем, задачу, на уровне прототипа(или альфа версии библиотеки) решить удалось.
По крайней мере, в результате проверок, на Raspberry Pi Zero W и Raspberry Pi на Raspberry Pi OS 32/64 bits(который Debian) и Orange Pi Zero на Armbian, все прекрасно работает на тестовых примерах. В теории, т.к. там используется голый kernel 4.8+ будет работать из коробки на любом Linux и потенциально Android(который вроде как тот же линукс).
Данные интерфейсы мапятся в 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 программиста стала выглядеть так:
Сама библиотека доступна тут: https://github.com/java-embedded-framework/jef/
И да, не надо меня пинать за громкое название библиотеки. Ничего лучше на ум не пришло.
Если вы java-программист, берите и используете библиотеку, если необходимо.
Свой академический интерес я удовлетворил.
Дальше пока тупик. Нужна community, нужны требования, хотелки. Нужны желающие, которые готовы так же поучаствовать в развитии библиотеки, драйверов конечных устройств, документации, тестов и прочего.
Да, есть желание развивать драйвера для конечных чипов. Да, есть желание написать генерализированную тулу с веб интерфейсом, которая позволит управлять “железом” например через Rest, но пока это слабо движется в виду отсутствия потребителей.
Но главная цель достигнута – из java работать на одноплатниках легко и просто и был получен неоценимый опыт. Получен опыт Linux/POSIX, работы с “железными протоколами”, работы с регистрами устройств. Выйти из ограничений виртуальной машины вполне возможно и там доступен новый чудный мир который возможно интегрировать в java-приложение.
На сим откланиваюсь. Спасибо всем кто прочитал статью. Если интересны какие то детали, пишите в комментариях.
P.S. В рамках статьи не упомянута native часть, ее так же нет в исходниках на github, если у community есть интерес по поводу GraalVM и как писать native приложения на java с подключением линуксовских библиотек, то раскрою тему в рамках отдельной статьи.
В результате блуждания по поисковикам, было найдено несколько возможностей:
- Oracle Java ME – проект, скорее мертв, чем жив. Давным-давно, в 2006 году, Oracle прибило его гвоздями к Raspberry Pi Model B/STM32429I-EVAL/32746GDISCOVERY с минимальными требованиями по железу того времени. И так выглядит скорее заброшенным, то похоже не полетел.
- Pi4j – неплохой проект от Robert Savage, который развивается до сих пор. Однако это просто враппер на WiringPi, который автор забросил и “прибитый” гвоздями к определенным платам. Сейчас на сколько я вижу, идут попытки отойти от этого.
- Diozero – так же неплохой проект от Matthew Lewis, однако как и предыдущие два, “прибит” гвоздями к определенным SoC или платам.
- 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.
В результате архитектура стала выглядеть так:
Не буду описывать весь путь по граблям из плохой документации(либо ее полного отсутствия в случае 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 программиста стала выглядеть так:
Сама библиотека доступна тут: https://github.com/java-embedded-framework/jef/
И да, не надо меня пинать за громкое название библиотеки. Ничего лучше на ум не пришло.
Что дальше?
Если вы дочитали до этого момента, то значит вам это действительно интересно.Если вы java-программист, берите и используете библиотеку, если необходимо.
Свой академический интерес я удовлетворил.
Дальше пока тупик. Нужна community, нужны требования, хотелки. Нужны желающие, которые готовы так же поучаствовать в развитии библиотеки, драйверов конечных устройств, документации, тестов и прочего.
Да, есть желание развивать драйвера для конечных чипов. Да, есть желание написать генерализированную тулу с веб интерфейсом, которая позволит управлять “железом” например через Rest, но пока это слабо движется в виду отсутствия потребителей.
Но главная цель достигнута – из java работать на одноплатниках легко и просто и был получен неоценимый опыт. Получен опыт Linux/POSIX, работы с “железными протоколами”, работы с регистрами устройств. Выйти из ограничений виртуальной машины вполне возможно и там доступен новый чудный мир который возможно интегрировать в java-приложение.
На сим откланиваюсь. Спасибо всем кто прочитал статью. Если интересны какие то детали, пишите в комментариях.
P.S. В рамках статьи не упомянута native часть, ее так же нет в исходниках на github, если у community есть интерес по поводу GraalVM и как писать native приложения на java с подключением линуксовских библиотек, то раскрою тему в рамках отдельной статьи.
Java на одноплатниках: легко и просто
Привет, уважаемый читатель! В какой-то момент, на нашем замечательном COVID карантине, появилось свободное время и посмотреть на одноплатные компьютеры, которых сейчас уйма всяких разных. Однако,...
habr.com