Насколько я могу судить, на Хабре да и не только, наблюдается всплеск интереса к микроконтроллерам — устройствам на базе ARM процессоров и другим не совсем обычным железкам. Рынок отвечает симметрично. Для удовлетворения возникшего спроса появились Arduino, Biggle Board, Raspberry Pi и множество других полезных штуковин.
С начала этого года прошло всего ничего, а на Хабре появились сразу две статьи о применении Java платформы на Rasprerry Pi «Raspberry Pi и чашечку Java, пожалуйста!» и «Raspberry PI и JAVA: пристальный взгляд». Вполне естественно, что в экспериментах использовалась привычная всем Java SE, порт которой под ARM появился около двух лет назад. Мало кто знает, что Java ME не почила с миром вместе с эрой кнопочных телефонов от Nokia. Она живет полноценной жизнью в новом мире — мире встроенных систем. О применении Java ME на Raspberry Pi я и хочу сегодня рассказать.
Oracle Java ME Embedded — это полноценный Java runtime, оптимизированный для устройств с ARM архитектурой и систем с ограниченными аппаратными возможностями. Java ME показывает себя во всей красе на платформах со слабыми вычислительными мощностями и небольшими ресурсами оперативной памяти, которые работают с сетевыми сервисами. Например, такими, как беспроводные модули, модули позиционирования, «умные» счетчики ресурсов, датчики мониторинга окружающей среды, вендинг-машины, телемедицина и, конечно, «умные» дома.
Использование Oracle Java ME в ваших проектах дает ряд интересных возможностей. Во первых, главное преимущество Java — «write once, run everywhere» теперь работает и в случае встроенных устройств. Во вторых, в платформу интегрирована система управления жизненным циклом приложений и его удаленного обновления на устройстве (AMS — application management system). В третьих, вы получаете специальный API для доступа к периферии (DAAPI — Device Access API). В четвертых, бесплатные инструменты разработки, что для встроенных систем случай нечастый (Java ME SDK для NetBeans и Eclipse). А также набор интегрированных в платформу стандартных сервисов: File I/O (JSR 75), Wireless Messaging (JSR 120), Web Services (JSR 172), Security and Trust Services Subset (SATSA – JSR 177), Location (JSR 179), XML (JSR 280).
Oracle Java ME Embedded Product Stack
Как вы уже поняли, Oracle Java ME Embedded — продукт кросс-платформенный и поддерживает ряд устройств с ARM архитектурой. Текущая версия релиза Oracle Java ME 3.3 — 3.4. Платформа портирована на Cortex-M3/RTX (KEIL Evaluation Board), ARM11/Linux (Raspberry Pi Model B), ARM9/BREW MP (Qualcomm IoE development), X86/Windows (эмулятор). Выше перечислены референсные имплементации платформы, выпущенные Oracle. Возможно портирование платформы на другие устройства при возникновении таких потребностей у конечных пользователей.
Официально минимально возможная конфигурация Oracle Java ME Embedded требует всего 130 KB RAM, 350 KB ROM. Хотя, если вы придете на встречу Java User Group в Москве 30 января http://jug.msk.ru, вы будете удивлены, насколько маленькой может быть платформа, если над ней поработать напильником. Александр Мироненко alexanderVmironenko расскажет, как он «запихнул» Java в 32кб! RAM. Полная, стандартная конфигурация требует больше памяти: 700кб RAM и 2000кb ROM, что по современным меркам все равно кажется смешным.
Всем хочется, чтобы вокруг все были умными. С умными людьми приятно общаться, а в умном доме комфортно жить. Наверное, поэтому большая часть проектов с Arduido и Raspberry Pi имеют ярко выраженную направленность на прокачку скилов нашего жилища. Типичная задача — мониторинг температуры.
Для мониторинга температуры мы сначала использовали датчики с интерфейсом SPI. Но впоследствии выяснилось, что датчики с I2C гораздо дешевле. Для изготовления термометра из Raspberry Pi и Oracle Java ME Embedded 3.3 нам потребуется цифровой термодатчик Dalas Semiconductor DS1621 в корпусе DIP8. Вот здесь можно купить его за 173 рубля http://www.electronshik.ru/item/ds1621-232961.
Подключаем его к GPIO выводам нашей платы
DS1621 | Raspberry GPIO pins |
pin1 | SDA (GPIO 2) |
pin2 | SCL (GPIO 3) |
pin4 | GND |
pin8 | 3.3v |
Если почитать Datasheet на DS1621, можно узнать, что адрес датчика на шине конфигурируется с помощью пинов 5-6-7 в нашем примере мы установим их все в 1 замкнув на питание.
Считаем, что Raspbian у вас уже стоит и он обновлен.
Для того, чтобы у нас была возможность работать с интерфейсом I2C на Raspberry Pi. Необходимо загрузить соответствующий модуль.
Добавляем две строчки в /etc/modules
i2c-bcm2708
i2c-dev
Перегружаем плату.
Устанавливаем утилиты для работы с I2C
sudo apt-get install i2c-tools
Определяем адрес нашего устройства на шине I2C
sudo i2cdetect -y 1
Адрес нашего датчика 4f (запомним это число)
Скачиваем стабильную версию Oracle Java ME Embedded 3.3 for Raspberry Pi Model B. В версии 3.4 добавилась только поддержка платформы Qualcomm IoE. Предварительно принимаем лицензионное соглашение. http://www.oracle.com/technetwork/java/embedded/downloads/javame/index.html?ssSourceSiteId=ocomen
Копируем runtime на Raspberry и разворачиваем в удобное место.
Например в ~/JavaME/
И от root запускаем AMS (Application Management System)
sudo ~/JavaME/bin/usertest.sh
C Raspberry Pi закончили.
Устанавливаем Java ME SDK и плагин для NetBeans или Eclipse на ваш компьютер. http://www.oracle.com/technetwork/java/javame/javamobile/download/sdk/default-303768.html
Добавляем нашу Малинку в качестве устройства для развертывания мидлета.
В меню NetBeans выбираем Tools/Java ME/Device selector
В окошке Device selector нажимаем Ctrl-D и создаем новое устройство. Для этого просто прописываем адрес нашей платы жмем Далее и если все в порядке, выбираем уровень протоколирования.
Создаем проект Java ME/ Embedded application
IDE создаст для нас скелет Java ME приложения, которое наследуется от класса MIDlet и состоит из трех методов: startApp(), pauseApp() и destroyApp(boolean unconditional). Метод startApp() запустится при старте мидлета, в нем, для простоты, мы и напишем код нашего приложения.
Java ME Embedded предоставляет нам высокоуровневый API общения с переферией — DAAPI (Deveice Access API). Для работы с I2C нам нужно создать конфигурацию устройства, передать ее в фабрику PeripheralManager.open() и если все провода в порядке и Java запущена от root, мы получим экземпляр класса I2CDevice(), который даст нам возможность общаться с датчиком.
Ниже пример кода Java ME приложения, если что-то не понятно задавайте вопросы в комментариях, приходите в офис Oracle в Санкт-Петербурге или 30-го января на http://jug.msk.ru
Чтобы запустить этот код на устройстве, нажмите правую кнопку мыши на вашей вашем проекте в NetBeans, выберите Run with… и в открывшемся окне Quick Project Run выберите вашу Raspberry. Или в свойствах проекта выберите во вкладке Platform выберите в качестве Device ваше устройство, тогда NetBeans будет деплоить приложение на Rapberry Pi по умолчанию при старте проекта.
Теперь вы знаете температуру в комнате :)
Полезные ссылки:
Java ME Embedded 3.3 for Raspberry Pi
Java ME SDK 3.4
Java ME Embedded 3.3 Getting Started Guide for the Reference Platform (Raspberry Pi)
Термодатчик DS1621 Datasheet
import com.oracle.deviceaccess.PeripheralManager;
import com.oracle.deviceaccess.i2cbus.I2CDevice;
import com.oracle.deviceaccess.i2cbus.I2CDeviceConfig;
import java.io.IOException;
import javax.microedition.midlet.*;
public class IMlet extends MIDlet {
private final int CFG_ADDRESS = 0x4f; //Адрес датчика
private final int FREQ = 100000; //Частота шины из Datasheet
private final int ADDRESS_SIZE = 7; //Размер адреса из Datasheet
private final int BUS_ID = 1; // Внутренний идентификатор шины в Java ME Embedded из Getting Started Guide
// Адреса регистров и значения конфигурационных параметров датчика DS1621 подробнее в Datasheet
private final int REG_READ_TEMP = 0xAA;
private final int RT_ADDR_SIZE = 0x01;
private final int READ_TEMP_SIZE = 0x02;
private final int READ_TEMP_VAL = 0x00;
private final int REG_ACC_CONF = 0xAC;
private final int ACC_CONF_VAL = 0x00;
private final int REG_START_CONV = 0xEE;
private final int REG_STOP_CONV = 0x22;
public void startApp() {
// Создаем конфиг
I2CDeviceConfig config = new I2CDeviceConfig(BUS_ID, CFG_ADDRESS, ADDRESS_SIZE, FREQ);
I2CDevice device = null;
try {
// Открываем устройство
device = (I2CDevice) PeripheralManager.open(config);
// Конфигурируем датчика на непрерывное измерение температуры
write(device, new byte[]{(byte) REG_ACC_CONF, (byte) ACC_CONF_VAL});
write(device, new byte[]{(byte) REG_START_CONV});
// Читаем температуру
byte temp[] = new byte[READ_TEMP_SIZE];
device.read(REG_READ_TEMP, RT_ADDR_SIZE, temp, 0, READ_TEMP_SIZE);
// Profit!
System.out.println("Temperature is:" + temp[0]);
} catch (Exception ex) { // Никогда так не делайте, только для Habrahabr
ex.printStackTrace();
} finally {
// Закрываем устройство
if(device != null) {
try {
device.close();
} catch (IOException ex) {
ex.printStackTrace();
}
// Скажем приложению, что ему нужно самоуничтожится
notifyDestroyed();
}
}
}
public void pauseApp() {
}
public void destroyApp(boolean unconditional) {
}
private void write(I2CDevice i2c, byte[] buffer) {
try {
i2c.begin();
i2c.write(buffer, 0, buffer.length);
i2c.end();
} catch (IOException ex) {
System.out.println("[I2CThermometerTest] configure exception: " + ex.getMessage());
} catch (Exception ex) {
System.out.println("[I2CThermometerTest] Peripherial not available exception: " + ex.getMessage());
}
}
}
Автор: alexbel