Предыдущая часть цикла Alljoyn: взгляд embedded разработчика. Часть 1: знакомство
Продолжаем повествование о том как получить «реальную железку», работающую по протоколу AllJoyn. Конечной целью цикла является получение прототипа «умной Wi-Fi лампочки». Причем именно «прототипа», потому что реализации силовой части нашей лампочки мы касаться не станем, так как это отдельная большая тема, не имеющая отношения к фреймворкам и способам управления. Потому ограничимся светодиодом на отладочной плате SAMD21-XPRO.
Прежде чем начать портирование фреймворка на микроконтроллер, разберемся со вспомогательными средствами, которые окажут нам неоценимую помощь в процессе разработки. В принципе, AllJoyn — кроссплатформенный фреймворк и Вы вольны использовать удобный именно Вам вариант операционной системы. Я использовал Linux (Ubuntu) — просто потому, что он мне привычнее.
Качаем исходники, компилируем, пробуем
Для этого следуем указаниям пункта 4.1 инструкции с официального сайта. Правда, данная инструкция предлагает использовать Git для скачивания исходников, но при таком способе фреймворк у меня отказался компилироваться (ситуация могла с тех пор измениться), поэтому я скачивал исходники по одной папке с официального сайта, и раскладывал их в соответствии с требуемой структурой. Исходники я поместил в домашнюю папку в каталог alljoyn/lsf.
Необходимо получить следующую структуру файлов:
~/alljoyn/lsf
|------ core
| |------ service_framework (пункт Lighting Service Framework Source)
| |------ ajtcl (пункт Thin Core Source)
| |------ alljoyn (пункт Standard Core Source)
|------ base_tcl
|------ base (пункт Base Services Source)
Для компиляции нам потребуется дополнительные программы. Ставим их:
sudo apt-get install build-essential libgtk2.0-dev libssl-dev xsltproc ia32-libs libxml2-dev
sudo apt-get install python
sudo apt-get install scons
sudo apt-get install libssl-dev
Переходим в папку service_framework и собираем проект:
cd ~/alljoyn/lsf/core/service_framework
scons WS=off
Я не большой знаток линукса, но в процессе работы с ним у меня сложилось стойкое ощущение, что двух одинаковых решений одной задачи на разных компьютерах не бывает и всегда в каждом конкретном случае найдутся какие-то нюансы. Лично у меня было долгое хождение по мукам прежде чем всё успешно собралось, но описывать свои похождения в рамках данной статьи большого смысла не вижу. Так что дерзайте и в конце концов Вы увидите следующее:
scons: Reading SConscript files ...
BULLSEYE_BIN not specified
Using OpenSSL crypto
GTEST_DIR not specified skipping common unit test build
BULLSEYE_BIN not specified
GTEST_DIR not specified skipping About Service unit test build
GTEST_DIR not specified skipping alljoyn_core unit test build
GTEST_DIR not specified skipping LSF unit test build
scons: done reading SConscript files.
scons: Building targets ...
...
scons: done building targets.
В результате там накомпилируется много-много всего. Нам понадобится 3 программы:
- lamp_service — имитатор «умной лампочки» (далее по тексту я частенько буду называть эту программу «лампочкой»). Испольует Thin (облегченную) версию фреймворка. Именно эту программу мы будем портировать на микроконтроллер Atmel SAMD21 в третьей части цикла. Так же данная программа лежит в основе Android приложения Luminaire. Находится в папке ~/alljoyn/lsf/core/service_framework/build/linux/thin_core_library/lamp_service/bin
- lighting_controller_service — это Router для нашего Thin устройства (читай теоретическую часть в первой части). Лежит в папке ~/alljoyn/lsf/core/service_framework/build/linux/standard_core_library/lighting_controller_service/bin
- lighting_controller_client_sample — это «контрольная панель» с которой мы будем управлять нашей лампочкой. Именно эта программа лежит в основе Android приложения LSF, которое упоминалось в прошлой статье. Находится в папке ~/alljoyn/lsf/core/service_framework/build/linux/standard_core_library/lighting_controller_client/samples
Таким образом, мы теперь можем «заумные» картинки из прошлой статьи представить в более предметном виде:
Теперь включим WireShark, запустим lamp_service и понаблюдаем что же происходит:
cd ~/alljoyn/lsf/core/service_framework/build/linux/thin_core_library/lamp_service/bin
./lamp_service
Чтобы не утонуть в потоке сетевого трафика, добавим фильтр в WireShark udp.port == 5353 || udp.port == 9956
Видим, что лампочка шлёт в сеть свои презентационные данные в поисках Router, используя все три доступные ей способа (multicast 224.0.0.113:9956, multicast 224.0.0.251:5353, broadcast:9956). В данном случае эти попытки тщетны, так как Router в сети отсутствует. Лампочка периодически посылает эти пакеты в сеть, после чего на некоторое время «замолкает» (до 40 секунд).
Рассмотрим для интереса содержимое одного из пакетов. Разглядывать будем широковещательный AllJoyn пакет. Он хоть и является устаревшим форматом (о чем говорится в первой статье), но выглядит менее громоздко по сравнению с MDNS и потому проще для понимания. В MDNS используется похожий принцип.
Идентификатор шины может использоваться Router'ом (а может и не использоваться) для того, что бы решить будет ли Router «дружить» с нашим устройством. С кем ему дружить определяет разработчик при написании кода Router'а. IP адрес и порт используются для указания Router'у данных TCP-соединения. В нашем случае мы видим, что лампочка подняла TCP-сервер на порту 9955.
Добавим Router
В принципе, не важно, находится ли Router физически на том же устройстве, что и lamp_service или на разных. Но если запустить lighting_controller_service (это специализированный Router для нашего случая) на том же самом компе, то они соединятся внутри машины, поэтому через сетевую карточку обмен не пойдет и WireShark его не зафиксирует. Чтобы визуализировать обмен, запустим lighting_controller_service на другом компе.
Как видим на этот раз «крики лампочки» не остались неуслышанными, и Router, предварительно «выслушав» лампочку по UDP, подключился к ней по TCP и произвел довольно длительный процесс обмена более детальной информацией. В принципе, для успешного использования фреймворка вовсе не обязательно разбираться в тонкостях этого обмена, так как он лежит на плечах разработчиков альянса и поставляется в готовом виде. Но если приглядеться, то можно увидеть использование DBus подобного протокола со всякими BusHello, Introspect и пр. Забегая немного вперед, отмечу что далее в процессе обмена при желании используется всякие методы аутентификации, шифрования и т.п. В результате AllJoyn напоминает этакого Франкенштейна, состоящего из частей различных протоколов и технологий. Но это лирика, повторюсь, в теории, погружаться слишком глубоко не требуется (хотя нас эта участь не миновала, так как в процессе работы пришлось изрядно походить по граблям).
Про AllJoyn и WireShark
WireShark в Windows понимает Alljoyn и умеет его красиво парсить, разбивая на отдельные поля — неоценимая помощь при отладке. К сожалению, в Ubuntu WireShark не знает этого протокола, что огорчает. Так как у меня Ubuntu установлена на виртуальной машине под виндой, то я сделал проброс линуксовой сетевой карточки во внешнюю сеть (это позволяет сделать VMWare Workstantion). В результате, у меня WireShark в винде, видит весь линуксовы обмен. Именно поэтому в данной статье часть скриншотов сделаны в Ubuntu, а часть в Windows.
Для AllJoyn можно настроит два фильтра:
ajns — AllJoyn Name Service — это уже не раз упоминавшийся, устаревший формат широковещательных посылок по UDP в порт 9956, с помощью которых AllJoyn-устройства находят друг друга в сети.
aj — AllJoyn — это протокол обмена, осуществляющийся по TCP. Распарсенные пакеты видны на предыдущей картинке.
Для AllJoyn можно настроит два фильтра:
ajns — AllJoyn Name Service — это уже не раз упоминавшийся, устаревший формат широковещательных посылок по UDP в порт 9956, с помощью которых AllJoyn-устройства находят друг друга в сети.
aj — AllJoyn — это протокол обмена, осуществляющийся по TCP. Распарсенные пакеты видны на предыдущей картинке.
После того как лампочка «сдружилась» с Router'ом по TCP, она (лампочка) перестаёт «шуметь» по UDP. Теперь за неё это делает Router, предлагая свои услуги панелям управления. Процесс происходит в общем-то аналогично — Router мультикастово и/или бродкастово извещает по локальной сети о существовании лампочки (или лампочек). Если панель управления заинтересовалась, она подключается по TCP. И вот тут важное отличие: Router не перестает «шуметь» по UDP для того, чтобы другие панели тоже могли присоединиться в случае необходимости.
Собственно, теперь становится понятна такая замысловатая организация обмена. Router — это программа на «серьезном» железе, с нормальной реализацией TCP/IP стека и поддержкой большого числа одновременных соединений. В то время как требования к лампочке снижаются — от микроконтроллера и стека требуется лишь возможность поддержки одного UDP-сокета и одного TCP-соединения.
Представим вышесказанное в виде комикса:
Подключаем «панель управления»
Последнее на сегодня упражнение — это увидеть в действии 4-й этап из картинки выше. Для этого запускаем нашу панель управления. Используем для этого отдельный экземпляр терминала. Опять же не важно на каком именно физическом устройстве будет запущена наша панель:
$ cd ~/alljoyn/lsf/core/service_framework/build/linux/standard_core_library/lighting_controller_client/samples
$ ./lighting_controller_client_sample
В результате, если всё сделано правильно, панель должна обнаружить нашу лампочку:
Тут же мы видим 32-х битный уникальный идентификатор лампочки, который транслировался по UDP. К сожалению, при подготовке данной статьи запускались различные экземпляры lamp_service, поэтому значения этого идентификатора на скриншотах не совпадают — просто поверьте на слово, что это он.
Помимо обнаружения, lighting_controller_client_sample позволяет производить множество манипуляция с лампочкой (запрос параметров, установка значений и пр.). При желании, можно с ней «поиграться», но я эту часть опущу, чтобы не раздувать статью до неприличных масштабов. Предупрежу только, что интерфейс у программки далеко не дружественный… но это одно из самых незначительных препятствий на тернистом пути AllJoyn-первопроходца.
На этом теоретическую, техническую и моральную подготовку будем считать оконченной и в третьей (вероятно, заключительной) части цикла приступим к реализации «умной лампочки» в железе и съемке результата для youtube.
Приложение А. Соответствие linux программ и мобильные приложений
Собранные и используемые сегодня программы однозначно перекликаются с мобильными Android приложениями, о которых говорилось в первой статье. Закрепим этот момент:
Приложение Luminaire соответствует программе lamp_service. Его мы и будем портировать на микроконтроллер в третьей части.
Приложение LSF Sample App соответсвует программе lighting_controller_client_sample. С его помощью осуществляется управление нашей лампочкой.
Приложение Б. Постановка задачи для третьей части цикла
В результате наших изысканий мы хотим получить физическое устройство (отладка с микроконтроллером и Wi-Fi модулем), которое будет обнаруживаться и управляться с наших контрольных панелей (мобильного телефона с установленным LSF Sample App и программой в линуксе lighting_controller_client_sample). В качестве Router'а будем использовать программу lighting_controller_service, запущенную на компьютере с линуксом.
На сегодня это всё, надеюсь было интересно. До новых встреч.