Рубрики
Без рубрики

Создание системы мониторинга винного погреба – Часть 2. Создание собственной библиотеки Java

Эта статья является частью 2 моей серии о том, как я создал систему мониторинга винных погребов с использованием #java и… С тегом raspberry pi, java, компиляция.

Эта статья является частью 2 моей серии о том, как я создал систему мониторинга винных погребов с использованием #java и #raspberry pi. Вы можете прочитать здесь первую статью о настройке.

В прошлый раз мы остановились, как только смогли связаться с нашим датчиком, используя какой-то код на языке Си. Сегодня мы создадим мост между C и Java и создадим jar, который мы сможем использовать позже в качестве драйвера для нашего датчика. Мы также рассмотрим, как это сделать с помощью действий Github, чтобы избежать необходимости компиляции на самой малине.

Эта статья предназначена для того, чтобы объяснить, что я сделал шаг за шагом. Взгляните на окончательное хранилище , если вы хотите получить полную картину!

Создание моста Java

В прошлый раз мы видели, что, повторно используя драйвер от Adafruit, мы смогли связаться с нашим датчиком, используя следующий код C:

То, что мы хотим сделать сейчас, – это иметь возможность вызывать то же самое, но с Java. Для этого мы будем использовать Собственный интерфейс Java .

Что мы будем делать, так это следующее:

  • Скомпилируйте код C в виде библиотеки (возможно, вы привыкли к этому слову.dll, или .so для систем Linux. Мы назовем эту библиотеку libdht11 .
  • Мы скажем Java использовать эту библиотеку
  • Мы создадим метод Java, который будет использовать эту библиотеку. Метод, который мы хотим, отправит запрос в DHT11 и вернет 2 поплавка. Мы сможем распознать этот метод, потому что он будет использовать ключевое слово native .

Вот как это выглядит:

Чтобы использовать это сейчас, нам придется немного жонглировать.

Сначала мы говорим Java создать файл заголовка C на основе этого файла Java:

$ cd src/main/java; 
$ javac -h . nl/lengrand/cellar/Dht11Driver.java

Это приведет к созданию файла драйвера nl_lengrand_cellar_Dht11.h . Этот файл описывает интерфейс между нашим кодом на языке Си и нашей Java. Соглашение об именовании файлов основано на именовании пакетов java и имени класса, которое мы использовали.

Затем мы реализуем логику для этого файла .h в соответствующем Драйвер Dht.c файл.

Этот код C может быть немного запутанным, но, по сути, вот что мы делаем:

  • Мы вызываем нашу функцию pi_2_dht_read .
  • Мы выделяем массив с плавающей точкой размером 2 таким образом, чтобы Java понимала
  • Мы устанавливаем результат вызова в массив float и завершаем его обратно

Обратите внимание, что мы должны импортировать.файл заголовка h, который мы создали на последнем шаге, а также файл jni.h , поступающий из нашего JDK, который сделает массив JNI с плавающей точкой, а также другие необходимые инструменты доступными для нас.

Примечание: Этот код очень простой, мы жестко закодировали pin-код, на котором размещен DHT11, и возвращаем массив с плавающей точкой, где мы могли бы решить вернуть объект. Мы, несомненно, сможем улучшить это позже.

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

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

  • Нам нужно включить библиотеки из Java, чтобы иметь возможность использовать JNI.
  • Нам также необходимо включить наши файлы моста.
  • Мы будем использовать опцию -shared для создания собственной библиотеки.
$ INCLUDES = -I. -I../java -Iadafruit/Raspberry_Pi_2 -I$(JAVA_HOME)/include -I$(JAVA_HOME)/include/linux
$ HEADERS = ../../../target/headers/nl_lengrand_cellar_Dht11Driver.h adafruit/common_dht_read.h adafruit/Raspberry_Pi_2/pi_2_mmio.h adafruit/Raspberry_Pi_2/pi_2_dht_read.h
$ FILES = adafruit/common_dht_read.c adafruit/Raspberry_Pi_2/pi_2_mmio.c adafruit/Raspberry_Pi_2/pi_2_dht_read.c Dht11Driver.c
$ OUT = libdht11

$ gcc -shared -fPIC -o $(OUT).so $(INCLUDES) $(FILES)

Примечание: Эта компиляция должна происходить на малине!

Если мы запустим этот код, он сгенерирует libdht11.so файл!

Наконец, мы создаем некоторый Java-код, чтобы проверить, работает ли наш мост JNI так, как ожидалось!

Запускаем наш Java-код. Мы можем общаться с нашим DHT11!

Вот и все! Нам только что удалось позвонить в наш DHT11 с Java!

Итак, это первый шаг, но для этого требуется много ручного труда. Давайте сделаем это более устойчивым.

Автоматизация цепочки инструментов

Создание файла создания для библиотеки

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

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

Встраивание собственной библиотеки в банку

По умолчанию созданная нами собственная библиотека должна быть размещена где-то в системе, к которой ип сможет получить доступ (типичным местоположением может быть /usr/lib в linux).

Мне не нравится этот вариант, потому что он заставит меня снова взаимодействовать с моей малиной каждый раз, когда я создаю новую версию своей библиотеки. В идеале я бы хотел, чтобы моя библиотека dll была включена в мой файл Jar!

К счастью, Адам Генрих создал для этого вспомогательный класс Java. Вы можете прочитать больше об этом в этой замечательной статье!

Все, что нам нужно сделать, это изменить наш Dht11Driver.java класс для использования собственных утилит.

Собирая все это вместе с помощью Maven

Давайте создадим pom.xml это сделает все, что нам нужно, по порядку только в одной команде. Вот что нам нужно, чтобы произошло:

  • Создайте файл заголовка JNI из нашего драйвера Java
  • Скомпилируйте собственную библиотеку на основе всех исходных файлов
  • Скомпилируйте Java весь наш Java-код!
  • Создайте толстую банку, в которую будет встроено все, что нам нужно для использования библиотеки
  • При необходимости создайте новую версию Jar и опубликуйте ее в Интернете

Вот как это выглядит:

Некоторые интересные факты:

  • maven-компилятор-плагин с аргументом -h генерирует наш файл заголовка.
  • Как только это будет сделано, мы используем exec-maven-плагин для запуска файла Makefile, который мы создали ранее.
  • Мы используем плагин maven-assembly-plugin для создания толстой банки, в которую будет встроена наша собственная библиотека.
  • Обратите внимание, что мы даем ему основной класс, поэтому мы можем легко протестировать библиотеку на малине, загрузив банку и просто запустив — кг-карта – начало: код –>
$ java -jar cellar-driver-1.1-jar-with-dependencies.jar 

Мне нравится использовать Github для управления публикациями, потому что это позволяет мне иметь хорошую банку, доступную вместе с моим репозиторием Github .

Снимок экрана пакета, доступный в моем репозитории Github

Перекрестная компиляция и использование непрерывной интеграции

Мы достигли всего, чего хотели, но не совсем где мы хотели:)! Действительно, даже если все работает так, как ожидалось, мы все равно вынуждены запускать все на raspberry (помните, что мы используем собственную библиотеку, зависящую от платформы!).

Это имеет несколько недостатков:

  • Это заставляет меня подключаться по ssh к моему pi каждый раз, когда я меняю код
  • Pi намного медленнее, чем мой ноутбук для компиляции.
  • Я не могу легко протестировать свою цепочку, потому что попытка скомпилировать код C завершается сбоем на моем Mac. Библиотеки совместимы только с архитектурой ARM.

Пересекать – компиляция библиотек

Вот где кросс-компиляция n вступает в игру! Кросс-компиляция в основном позволит мне скомпилировать библиотеку на моем MAC (даже если я не смогу ее запустить) в формате, который будет предназначен для моей малины.

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

К счастью, некоторые удивительные люди создали набор инструментов, готовый для нас к использованию! В этом случае мы будем использовать хорошие пакеты от abitronix ! Использовать их на самом деле довольно просто

  • Найдите, какая малина у вас есть, и загрузите для нее правильный пакет
  • Распакуйте пакет в вашей локальной системе
  • Обновите свой LD_LIBRARY_PATH по пути и ПУТЬ чтобы набор инструментов был доступен для вашей системы
  • Запустите файл Makefile, но в этом случае замените gcc (который является вашим локальным компилятором C) на arm-linux-gnueabihf-gcc . В моем случае мне просто нужно было обновить свой Makefile .
  • Прибыль!

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

Внедрение Непрерывной Интеграции

Теперь давайте скомпилируем все в облаке! Этот последний шаг сам по себе не требуется но у него есть несколько приятных преимуществ:

  • Наличие единого файла со всеми настройками позволяет в будущем легче воспроизводить его на других системах
  • Мне больше не нужна цепочка инструментов в моей локальной системе.
  • Поскольку все запускается автоматически, я могу сосредоточиться на кодировании!

Для этого мы будем использовать недавно выпущенные Действия Github .

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

Я приглашаю вас прочитать документацию для полного обзора происходящего, но в двух словах:

  • Главное – это последний призыв к мвн-Б развертывать
  • Мы используем действия/настройка-java@v1 для настройки Java для нас
  • Большинство команд перед Maven – это набор инструментов для кросс-компиляции, описанный в последней части
  • Мы используем действия/upload-артефакт@v1 для создания архива с выводами при каждом запуске нашего CI

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

Примечание: В качестве дополнительного бонуса, сборка на Github выполняется на самом деле быстрее, чем на моем локальном MBP! Кроме того, этот рабочий процесс на самом деле довольно глуп, потому что он не использует кэширование, это, вероятно, следует улучшить в долгосрочной перспективе.

Вывод

Вот и все! В этой статье нам удалось создать мост, чтобы драйверы наших клиентов можно было использовать с Java. Нам также удалось создать банку, которая включает в себя собственные библиотеки, что позволяет нам не слишком много возиться с малиной. И в качестве дополнительного бонуса мы автоматически генерируем наши результаты на Github и даже публикуем ваши банки там в виде пакетов! Это будет очень полезно для нас в следующий раз, когда мы создадим наш сервер!

Оригинал: “https://dev.to/jlengrand/building-a-wine-cellar-monitoring-system-part-2-creating-a-native-java-library-a3c”