Многофункциональный мультимедийный компьютер: Часть 5

В этой статье цикла Многофункциональный мультимедийный компьютер мы добавим в наше мультимедийное устройство пользовательский Web-интерфейс. Автор рассматривает проблемы разработки как интерфейса, так и самого ПО, а также показывает интересное применение локального браузера вместо удаленного.

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

  1. 1.Возможность удаленного управления устройством через любой подходящий Web-браузер.
  2. Локальный пользовательский интерфейс через браузер ELinks или Links2.

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

Для первой функции в подготовленном вами устройстве уже есть большая часть необходимого: настроены и запущены Web-сервер (thttpd) и основное приложение (ibmslides), поэтому все, что нужно — интерфейс управления на стороне приложения и способ соединить этот интерфейс с Web-сервером.

С пользой применяем CGI

Эта задача легко решается применением CGI-программы, которая вызывается Web-сервером и передает данные в основную программу через именованный канал. Для этого требуется не так уж много кода, поэтому я решил реализовать такую CGI-программу внутри самого приложения ibmslides. В файле Makefile в исходном коде будет видно, что командой make install программа ibmslides теперь устанавливается в каталог /web/cgi-bin/admin.cgi. В файле main.c проверяет переменную argv[0] и узнает, каким способом была запущена программа. Если найдена подстрока «cgi», то делается вывод, что программа запущена как CGI; в этом случае она считывает ввод и работает с именованным каналом /tmp/slidepipe.

Это работает при условии, что используется тот конфигурационный файл /etc/thttpd.conf, который я приводил в последней статье. Если каталог CGI-скриптов с */cgi-bin/* был изменен на какой-либо другой, то для запуска программы на выполнение нужно, чтобы она имела расширение cgi.

Я не буду в подробностях рассказывать о механизме получения и обработки CGI-данных из Web-форм, так как некоторое время назад я уже рассказывал об этом в статье «Миграция с x86 на PowerPC, часть 4». В этом коде используется та же самая технология, просто она применена немного по-другому. Интересно, что Web-страница не генерируется напрямую, а CGI-программа взаимодействует через именованный канал с главным приложением и передает управляющие и информационные данные через этот канал.

Заглянув в файл cgi.c, вы увидите весь код в его величии. «Основной» процесс ibmslides запускает второй (дочерний) процесс, который «слушает» именованный канал. Когда поступает какая-нибудь интересная информация, дочерний процесс выполняет требуемую задачу, действуя в адресном пространстве главной программы. CGI-часть программы imbslides запускается только тогда, когда нажимают на ссылку на Web-странице; она анализирует ваши действия на этой Web-странице и генерирует соответствующие строки, которые пересылает своей другой половине по именованному каналу.

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

Листинг 1. Сборка и установка программы-примера.

                
# make
# make install
# cp index.html /web

Теперь укажем в браузере адрес http://a.b.c.d/ (где a.b.c.d — IP-адрес нашего мультимедийного устройства), и можно будет попробовать некоторые простые функции удаленного управления этим устройством.

Более сложные фокусы

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

Самый очевидный пример полезного применения этой возможности — инфракрасный пульт дистанционного управления. В Linux® функции кодирования и декодирования информации, передающейся через инфракрасный канал, реализуются посредством ПО LIRC . LIRC состоит из нескольких модулей. На самом нижнем уровне работают загружаемые модули ядра, которые получают доступ к различному оборудованию для работы с инфракрасной связью. Выше этого уровня находится демон lircd, который декодирует получаемые данные инфракрасного протокола. Нередко поверх lircd запускают также демон lircmd, который преобразует декодированные данные в события пользовательского интерфейса, например, в движения мыши или нажатие и отпускание клавиш. Однако вполне возможно написать собственную программу, которая будет ждать данных от lircd и делать с ними что-нибудь полезное.

Кстати, Mac mini изначально не поддерживает инфракрасную связь, поэтому, возможно, на этой платформе легче будет реализовать управление через Bluetooth — принципы реализации останутся теми же.

Хитроумный читатель может вообразить возможность управлять группами мультимедийных устройств через канал при помощи точек монтирования NFS. К сожалению, тут мне придется развеять ваши мечты: невозможно передавать данные с одного компьютера на другой через именованные каналы по NFS. Хотя за идею вам пятерка. Если вам все же нужна такая функция, используйте не именованный канал, а сокет. Однако придется также написать приложение для удаленного компьютера, которое будет работать с этим сокетом. Лучше применить универсальный Web-интерфейс, по крайней мере, для домашнего устройства.

Юзабилити? Что это такое?

Сейчас самое время поговорить о коммерческих аспектах вопроса. Я хотел бы обратить ваше внимание на то, что просто дать устройству Web-интерфейс еще не значит сделать его удобным для пользователя. По современным канонам считается, что потребитель сейчас понимает концепцию Интернета и гиперссылок, а следовательно, добавление Web-интерфейса автоматически делает устройство понятным и дружественным к пользователю, и работать с ним проще, чем щелкать орехи. В этом утверждении есть немалая доля истины, но я, с вашего позволения, продолжу это сравнение и скажу, что в таком случае это австралийские орехи (суть в том, что австралийские орехи можно расколоть только давлением в 20 килограмм на квадратный сантиметр).

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

Если вы собираетесь выпустить устройство с сетевыми функциями TCP/IP, я крайне рекомендую вам подумать о реализации запасного механизма, через который ваши клиенты смогут проверить, что остальные части сети работают корректно.

Автоматическое обнаружение и настройка устройств TCP/IP

Достижение удобства эксплуатации — многосторонняя задача. Три основные проблемы следующие:

  • Связь (возможность взаимодействия между A и B)
  • Обнаружение (автоматическое определение того, что B существует, и где конкретно)
  • Перечисление услуг (автоматическое определение возможностей B и по какому протоколу в B нужно передавать команды)

Начнем с проблемы связи. В этом цикле статей я не раз отправлял вас по IP-адресу a.b.c.d (конкретный адрес я не указываю, так как он зависит от настроек вашей сети) и допускал, что вы умеете определять IP-адрес компьютера, например, на странице машрутизатора со списком выданных IP-адресов. Мне это сойдет с рук, потому что предполагается, что вы — либо разработчик, которому не нужно это объяснять, либо читаете статью просто для развлечения, и все равно не будете пытаться реализовать такой проект, поэтому и неважно, что вы не сможете определить IP-адрес.

Большинство домашних пользователей и малых компаний подключат ваше устройство к простому маршрутизатору, предназначенному для разделения высокоскоростного подключения к Интернету. В таком маршрутизаторе будет сервер DHCP, который выдает IP-адреса компьютерам локальной подсети. К сожалению, с такими устройствами могут обнаружиться самые разнообразные проблемы, особенно при подключении встраиваемой системы. Кажется, что производители с особым нездоровым наслаждением делают так, чтобы устройство максимально не соответствовало стандартам RFC и, тем не менее, все равно работало с Windows® или Mac OS.

Как быть, если ваше устройство не может получить IP-адрес от сервера DHCP? В таких случаях либо сервер не работает нормально, либо он несовместим, либо же просто отсутствует. Стандартное решение — вручную задать IP-адрес, маску подсети и шлюз. Если IP-адрес не удастся получить от сервера DHCP, то будут использованы эти данные. В идеале они должны настраиваться пользователем.

С вашим устройством должен поставляться перекрестный Ethernet-кабель для удаленного устранения проблем. Если вы сомневаетесь в работоспособности устройства, то убедиться можно так: попросить пользователя отключить свой компьютер и ваше устройство от сети, соединить их напрямую данным кабелем, и перезагрузить оба компьютера.

Какой диапазон IP-адресов использовать в таких случаях? Современные операционные системы по умолчанию реализуют схему APIPA («автоматическое присваивание частного IP-адреса») , чтобы в нерегулируемом сетевом окружении без сервера DHCP могли осуществляться хотя бы базовые функции связи. Вкратце, согласно APIPA, в случае невозможности получить IP-адрес, устройство назначает само себе случайный адрес из диапазона 169.254.0.1—169.254.255.254. Предполагается, что устройство при помоши ARP проверяет, что выбранный случайный адрес еще не занят. На практике я видел устройства, которые выбирали IP-адрес на основе других факторов, например, 16 младших битов MAC-адреса. Устройство просто предполагает, что конфликт адресов не произойдет, что безопасно в режиме тестирования при прямом подключении одного компьютера к другому, но в других случаях это может быть небезопасно…

Определение возможностей устройства

Теперь ваше устройство каким-либо образом подключено к сети, и к нему можно подключиться с другого компьютера в той же сети. Здесь, однако, возникают две следующие проблемы: обнаружение устройства и определение его возможностей. Цель протокола обнаружения следующая: когда к сети подключается новое устройство, на рабочем столе пользователя должен появиться его значок, и при двойном щелчке по нему должен вызываться встроенный Web-интерфейс устройства либо другой соответствующий интерфейс.

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

Протокол UPnP (Universal Plug'n'Play) должен был стать венцом технологий обнаружения, но по моему мнению, он слишком сложен и не обеспечивает простоты взаимодействия между системами. По этому поводу я пять лет назад написал язвительную статью. Изучив уже сейчас сайт UPnP, я понял, что почти ни одна из проблем не была устранена. Еще один такой протокол — Apple Bonjour. Он имеет свою долю на рынке, но его поддержка в основном имеется лишь в сетевых принтерах. Есть и несколько других протоколов — делайте ваш выбор в зависимости от сферы применения. UPnP — единственный протокол, имеющий встроенную в Windows поддержку, но у большинства пользователей он отключен по причине безопасности.

Помимо универсальных протоколов обнаружения вы можете написать и свою закрытую систему. Так работает, например, ПО для Kuro Box, которое я использовал в уже упоминавшейся серии статей Миграция с x86 на PowerPC. Вкратце: вы пишете закрытое приложение для всех необходимых операционных систем. Это приложение посылает во всю сеть специальный широковещательный пакет. Когда ваше устройство получает такой пакет, оно выжидает в течение некоторого (случайно определяемого) времени, чтобы избежать конфликтов, и отвечает «привет, я здесь» компьютеру, отправившему пакет. Компьютер получает этот ответный пакет и затем по собственному протоколу подключается к устройству.

Некоторые маршрутизаторы можно «обнаружить» интересным способом: они эмулируют DNS — если вы введете в браузере «router», то маршрутизатор перехватывает этот DNS-запрос (а не передает его реальным DNS-серверам) и возвращает свой IP-адрес. Для устройств, таких как наше, этот вариант не подходит, но идея интересная и может вам пригодиться.

Локальный интерфейс — просто разновидность удаленного

Оставим пока удаленное управление и перейдем к локальному пользовательскому интерфейсу. Давным-давно в начале этого цикла статей я лирично рассказывал о том, как важно выбирать для каждой задачи подходящий интерфейс. Я также упомянул, что один хитрый, но редко используемый способ получения одинакового интерфейса при удаленной и локальной работе — встроить в устройство браузер. Так как Web-интерфейс мы уже настроили, то им можно воспользоваться, просто установив в устройство браузер.

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

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

Выбор браузеров велик, но скорее всего, такой полнофункциональный комбайн как Firefox не нужен. Подобные браузеры относительно долго запускаются, что раздражает пользователя — когда пользователь нажимает кнопку устройства, команда должна выполняться по возможности немедленно. Одно из решений этой проблемы — постоянно держать браузер в памяти, и просто показывать его окно, когда потребуется, но имеется серьезный недостаток: браузер занимает оперативную память и/или файл подкачки.

Два небольших браузера

ELinks и Links2. Оба они произошли от старого доброго браузера lynx, оба элегантны и компактны, и оба хорошо подходят для встраиваемого применения. Однако их сфера работы несколько различается: ELinks — текстовый браузер, подходит для очень ограниченных систем без графического дисплея. Я бы порекомендовал использовать специально адаптированную версию ELinks, если у вашего устройства несколько экранов и браузер должен работать, скажем, на маленьком монохромном или текстовом экране. Для больших графических дисплеев, как в нашем случае, больше подходит Links2. Работа с ним будет больше напоминать то, что видит удаленный пользователь через обычный браузер.

Компилировать ELinks нет необходимости, так как он входил в комплект дистрибутива, который мы установили в первой статье. Но если вы хотите установить более свежую версию, распакуйте архив с исходным кодом и выполните команды:

Листинг 2. Установка браузера ELinks

                
# ./configure
# make
# make install

Чтобы скомпилировать Links2, просто распакуйте архив с исходным кодом и выполните команды:

Листинг 3. Установка браузера Links2

                
# ./configure --enable-graphics
# make
# make install

Скрипт configure автоматически определит поддержку в вашей системе фреймбуфера, SDL и X.

Я изменил программу ibmslides так, чтобы при щелчке мышью (левой кнопкой, если на вашей мыши их несколько) осуществлялась попытка запуска /usr/local/bin/links, а если эта программа отсутствует, то /usr/bin/elinks. Слайд-шоу на время работы браузера ставится на паузу, иначе бы код отрисовки изображений переписывал содержимое экрана и мешал окну браузера. Работа слайд-шоу продолжается после выхода из браузера.

Командная строка для запуска Links2 следующая:

Листинг 4. Запуск браузера Links2

                
/usr/local/bin/links -g http://127.0.0.1/ -mode 1024x768 -enable-javascript 1

Так браузер принудительно запускается в графическом режиме.

Ждите следующей статьи!

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

Оставьте комментарий