пятница, 17 октября 2014 г.

Java ME на Freescale FRDM-K64F

The statements and opinions expressed here are my own and do not necessarily represent those of Oracle Corporation.
Всё, что написано ниже, я выдумал, предаваясь фантазиям. Воспринимайте это как шутку.

Главное

Вышел early-access релиз Java ME Embedded для девелоперской платы Freescale FRDM-K64F.
Если у вас есть такой дружок, можно, ознакомившись с краткой инструкцией по быстрому старту, сконфигурировать устройство для запуска на нём мидлетов и немного поиграться. Я тут попишу немного про подключение к устройству, написание небольшого демо-приложения с раскрытием структуры проекта и работу с device acces API, ок?
Главное - это в процессе конфигурирования не забыть в конце файла jwc_properties.ini прописать сетевые параметры устройства, чтобы потом можно было подключить его к device-manager'у из состава Java ME SDK, соответствующую версию EA 8.1 которого тоже необходимо предварительно скачать и установить. В принципе, если у нас в системе установлены USB-драйверы устройства, то мы сможем подключаться к нему и по COM-интерфейсу, но это будет работать заметно медленнее.

Подключение к устройству

Ну, ладно. Microsd-карточку с преднастроенными параметрами в плату воткнули, нужную версию файла java.bin на flash-устройство, которым девайс определился в системе положили, попробуем подключиться и посмотреть, что у нас есть. Сделать это можно несколькими способами:
  • Способ первый - тру-хардкор-коммандлайн для бородатых ребят. В каталоге с установленной Java ME SDK ищем файл toolkit-lib\lib\proxy.jar. Можно, кстати, взять его и из дистрибутива платформы для K64, там он лежит в каталоге util. Ну, и применяем из командной строки к нему такой подход: java -jar proxy.jar -socket X.X.X.X -debug, где вместо X.X.X.X требуется подставить ip-адрес устройства, который мы предусмотрительно прописали в файле jwc_properties.ini. После этого можно каким-нибудь клиентом типа putty в RAW-режиме подключиться на localhost:65002 и узреть там примерно следующее: 
    Это так называемая ams-консоль, через которую можно и по устройству пошариться, и мидлетами поуправлять. 
  • Способ второй - с кнопочками. Опять же идём в каталог Java ME SDK и запускаем bin\device-manager.exe. Тут же в системном трее появится значок, дважды кликнув на который, вы увидите окно, в котором по нажатию кнопки Add можно будет вписать IP-адрес очередного устройства (или же по COM-порту подключиться, избрав не наш путь). Устройство получит не особо о чём-то говорящее имя вроде EmbeddedExternalDeviceX, и проверить его можно, если кликнуть по тому же значку device-manager'а в системном трее правой кнопкой и выбрать пункт Registered devices. Если же хочется его поменять, то рекомендую открыть файл в домашнем каталоге пользователя, из-под учётной записи которого запускается Java ME SDK, что-то типа такого вот C:\Users\%ИМЯ_ПОЛЬЗОВАТЕЛЯ%\javame-sdk\%ВЕРСИЯ_SDK%\device-detection\connections.xml и поправить в нём поле <void property="deviceName"> <string>%ИМЯ_УСТРОЙСТВА%</string></void> соответствующей борды. Легко найти. У меня оно переименовано в fsk64 теперь выглядит так: 
    Сконфигурировав подключение, запускаем из каталога Java ME SDK бинарник эмулятора с такими ключами:
    bin\emulator.exe -Xjam -Xdevice:fsk64,
    после чего радуемся открытому окну, в меню которого можно почитать логи и поуправлять устройством. Кстати, данный способ не лишает нас радостей и ams-консоли. После запуска этого эмулятора мы так же можем подсоединиться на localhost:65002 и сделать всё, что нужно.
  • Способ третий - самый ленивый и является продолжением второго. Ставим NetBeans (так уж получилось, что на настоящий момент эта IDE лучше вех интегрируется с JavaME), указываем в настройках Tools - Java Platforms путь до нашей Java ME SDK и создаём Java ME проект, в свойствах которого указываем необходимость запуска приложение на девайсе fsk64:

Напишем что-нибудь

Девайс оборудован несколькими кнопками, LED-индикаторами и акселерометром. К этим устройствам можно обращаться через Java ME DAAPI. Писать я буду примитивный детектор тряски, собирающий показания с акселерометра и зажигающий индикатор при изменении показателей в пределах погрешности. Полезным будет почитать datasheet акселерометра и ознакомиться вот с этими исходниками.
Чтобы получить список всех устройств на борту платы, не прибегая к чтению спецификаций, можно задействовать примерно такой код:

Iterator l = DeviceManager.list();
while(l.hasNext())
{
   DeviceDescriptor d = (DeviceDescriptor) l.next();
   System.out.println(d.getName()+"; "+d.getID()+"; "+d.getConfiguration());
}

Получив на выходе что-то типа списка:

PC2; 101; jdk.dio.counter.PulseCounterConfig@9f3ec512
PC1; 100; jdk.dio.counter.PulseCounterConfig@9820de3e
PWM1; 301; jdk.dio.pwm.PWMChannelConfig@2a63e1f7
ADC5_PTC10; 505; jdk.dio.adc.ADCChannelConfig@fd339546
FXOS8700CQ; 300; jdk.dio.i2cbus.I2CDeviceConfig@11e7c3f
ADC4_PTC11; 504; jdk.dio.adc.ADCChannelConfig@fd16fc55
ADC3_PTB11; 503; jdk.dio.adc.ADCChannelConfig@fcfa6364
ADC2_PTB10; 502; jdk.dio.adc.ADCChannelConfig@fcddca73
SPI_Slave; 12; jdk.dio.spibus.SPIDeviceConfig@279b1931
ADC1_PTB3; 501; jdk.dio.adc.ADCChannelConfig@fcc13182
ADC0_PTB2; 500; jdk.dio.adc.ADCChannelConfig@fca49891
UART3; 40; jdk.dio.uart.UARTConfig@30605d5
DAC0; 700; jdk.dio.dac.DACChannelConfig@3350d998
LEDS; 8; jdk.dio.gpio.GPIOPortConfig@e16b5918
SW3; 6; jdk.dio.gpio.GPIOPinConfig@a53bead
SW2; 5; jdk.dio.gpio.GPIOPinConfig@a56fc99
LED3; 3; jdk.dio.gpio.GPIOPinConfig@34faede4
LED2; 2; jdk.dio.gpio.GPIOPinConfig@34fb3292
LED1; 1; jdk.dio.gpio.GPIOPinConfig@34fafb7d

Мы будем работать с двумя устройствами: снимать показания с акселерометра FXOS8700CQ и при изменении данных показаний зажжём светодиод LED3.
Весь код проекта традиционно лежит на гитхабе.
Вот как это выглядит в жизни:

четверг, 25 сентября 2014 г.

JTHarness и его TestSuites

The statements and opinions expressed here are my own and do not necessarily represent those of Oracle Corporation.
Всё нижеописанное - выдумка автора и противоречит здравому смыслу и взглядам компаний всего мира.

Что? Зачем?

Java ME тут тестирую волею судеб, саму платформу то есть. Тестирование происходит путём написания приложения, работающего на поддерживаемой платформе. А как протестировать приложение или библиотеку, которая крутится где-то на удалённой железке? Нужно же и разместить его там, и запустить, и результаты выполнения получить. Для таких дел пацаны и запилили ME Framework, а на его основе – JT Harness. Ща понапишем чего-нибудь, используя эти штуковины.
Вообще, JTHarness – это такое говно мамонта теперь OpenSource-проект со страничкой на java.net, однако там почему-то нет последних известий о переводе его на mercurial-репозиторий, а вот, например, в здешних обновлениях – есть. На всякий случай – ссылки на репозиторий и страницу, с которой можно скачать все версии данного продукта, а то они, конечно, гуглятся, но внутри данных проектов расположены как-то неочевидно.

Разработаем первый тест

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

Соберём всё в кучу

Для начала ознакомимся с документиком по диагонали. А для верности высосем его себе. Помимо него есть мануал посвежей. Также на всякий случай сохранённый.
Из софта нам понадобится JDK, JT Harness и Java ME SDK (на момент 09.2014 реализована только на платформе MS Windows). Выкачиваем, устанавливаем, пляшем.
Я возьму себе версию JTHarness 4.4.1, чтобы не натыкаться на свежие баги. Распаковываем этот архив куда-нибудь и изучаем золотые слова из мануала:
Процесс выполнения набора тестов.
Распаковалось. Хорошо. Можно посмотреть на примеры в папке Examples, содержащей внутри себя Entrylevel-туфту, а можно пилить и собственный TestSuite. Для написания своего набора тестов придётся проделать следующие процедуры:
  1. Создать директорию, где мы будем копить тесты, их исходники, описания и прочую шелупонь;
  2. Создать описание набора тестов;
  3. Подготовить библиотеки для запуска JTHarness и удовлетворения всяческих зависимостей;
  4. Подготовить директорию classes;
  5. Написать тест(ы);
  6. Скомпилировать;
  7. Запустить и посмотреть, как оно там.
Этим и займёмся.

Подготовка директории для набора тестов

Тут всё очень просто – создаём директорию с названием нашего TestSuite, а в ней – поддиректории:
  • tests, для складирования исходных кодов наших тестов, они понадобятся для того, чтобы круто выглядеть в отчётах, демонстрируя, что же именно у нас попадало;
  • lib, для всяких зависимостей, а также основной библиотеки javatest.jar;
  • classes, для скомпилированных классов-тестов, потому что глупенький JTHarness будет собирать из них пакеты для пересылки на тестируемую платформу, а ещё туда придётся вытащить классы-зависимости из библиотек, расположенных в директории lib.
На этом пока всё. Нормальные пацаны ещё частенько src и doc создают, но нам этого пока не нужно.

Создание описания набора тестов
Это файл с именем testsuite.jtt, содержащий в себе описание теста, точнее имена соответствующих используемых классов. Думаю, написание таких классов оставим на будущее, а пока, согласно рекомендациям в документе, наполним файл следующим содержимым:
# Test Suite properties file for DemoTCK test suite 
# with tag-style tests
name=My Test Suite
id=1.0
finder=com.sun.javatest.finder.TagTestFinder
script=com.sun.javatest.lib.StdTestScript
interview=com.sun.javatest.interview.SimpleInterviewParameters
Типа, у нас тут всё по дефолту.

Собираем JAR-файлы 

В каталог lib необходимо положить javatest.jar и jh.jar из скачанного дистрибутива JT Harness. Это сейчас, в примитивном тесте. А вообще, туда придётся складывать все библиотеки, использованные при написании тестов.

Подготавливаем директорию classes

Вообще, в мануале предлагают экспортировать туда используемые class-файлы из библиотеки javatest.jar вот такой командой:
jar -xvf ..\lib\javatest.jar com\sun\javatest\Test.class
com\sun\javatest\Status.class
Но я ленив, и просто пропишу в дальнейшем в classpath теста путь до целой библиотеки.

Пишем сам тест

Исходники теста необходимо положить в каталог tests (или там же прямо их и писать). Откомпилированный результат - в каталоге classes. В качестве примера я засвинячил коварный тест, который псевдослучайным образом то, хрипя, заваливается набок, то успешно проходит. Подлый исходник прилагаю картинкой:
Исходник теста
Тут нужно обратить внимание на закомментированную секцию перед объявлением класса. В ней указаны инструкции для JT Harness, чтобы он распознал тест из исходника. А вот и таблица из оригинального мануала, которую мне лень переводить:
Расшифровка параметров
Почти всё. Мы, в принципе, готовы к компиляции и запуску, однако встаёт один вопрос -- как организовать работу со всем этим хозяйством. Можно положить сорцы в каталог tests и компилировать/перекладывать руками, а можно и какой-нибудь системой автоматической сборки воспользоваться. Я решил угореть по Maven. Собственно, каноничная структура проекта такова:
Золотые слова
У меня же, получается, будет отдельный Maven-проект со своими зависимостями, который при вызове mvn prepare-package будет по кусочкам собирать TestSuite в каталоге target. Залил эту фигню на Гитхаб, где и буду далее над ней издеваться. На текущий момент - вот, что представляет собой вышеописанное:
https://github.com/savermyas/JTHarnessSimpleTest/releases/tag/v1.0
Интересного там пока не очень много:
- Скрипт, выкачивающий архивы JTHarness и инсталлирующий их в локальный Maven-репозиторий (в сетевых-то репах этого добра нет, хехехе) - install_dependency.sh
- Описание проекта pom.xml. Всего пара интересных мест - это сборка проекта в каталоге target:

и запуск JavaTest с необходимыми параметрами:
После того, как откроется основное окно JTHarness, необходимо настроить запуск теста, указав путь до бинарника Java. Это делается следующим образом: Configure -> Edit configuration -> Java Virtual Machine. Ну, а потом можно кликать по кнопке запуска тестов, наслаждаясь случайным результатом.
Понятно, что представленный пример тривиален, и из него совершенно невозможно выжать то, для чего нужен этот JTHarness. А нужен он для распределённого запуска тестов, снятия результатов тестирования с удалённых устройств, сбора информации в одном месте, генерации отчётов и прочих штуковин, которые будут рассмотрены в будущем.