Поиск по этому блогу

среда, 20 января 2010 г.

Многофункциональный мультимедийный ко...

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


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

мы добавим в наше мультимедийное устройство пользовательский
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


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


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


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