Эмуляция сотового телефона… на сотовом телефоне

Многие помнят серию телефонов Siemens 65-75, выпущенную примерно 20 лет назад. На их основе мы проведем необычный эксперимент, написав небольшую управляющую библиотеку на языке C и модифицировав код одной из утилит, встроенных в ОС Linux. Подробности смотрите в статье.

❯ 1. Аппаратная часть


В серию телефонов Siemens 75 вошли такие модели, как C75, ME75 и CX75. Дизайн корпуса и другие характеристики отличаются. Однако их основные элементы во многом были схожи. Например, дисплей с разрешением 132х176. Для работы над этим проектом в ящике с различными электронными отходами были обнаружены остатки аналогичного телефона. Хотя изделие находилось в очень плохом состоянии более 20 лет и гравировка стерлась, мы считаем, что это копия мобильного телефона C75 - BenQ позднего выпуска. Родные процессоры в мобильниках уже давно мертвы. Еще не так давно можно было реанимировать процессор, нагрев плату паяльным феном, но сейчас осталась лишь мертвая плата и корпус. Поэтому мы решили перехватить информацию на уровне отображения.

Прежде всего нас интересует сама выставка. Поэтому давайте сначала разберем устройство:

Любая наука стоит «на плечах гигантов», поэтому повторять тип дисплея на этом телефоне я не буду. Вы можете узнать сами, Игорь Кизим объясняет это в статье 2013 года.

У меня уже есть опыт использования этого дисплея. Этот дисплей я подключил к микроконтроллеру ATmega8 с помощью библиотеки, взятой из статьи Игоря. Однако, поскольку это было более 5 лет назад, я решил сначала проверить, правильно ли работает этот дисплей. Почему я составил план Игоря? Его основные функции: Установлен стабилитрон для питания дисплея (5В -> 2,9В) и резистор для понижения логического уровня (5В -> 3,3В). Однако для питания диодных лент подсветки требуется другое напряжение (12В). Блокировать дополнительный инвертор мне не хотелось, поэтому я убрал подсветку и заменил диоды на те, которые могут работать напрямую от 5В, подключенные параллельно, а не последовательно. Таким образом мне удалось избавиться от лишнего шнура питания, но качество подсветки несколько ухудшилось.

Теперь у вас есть две линии питания (+5 В, GND) и пять сигнальных линий с логическим уровнем 3,3 В.

Однако контроллера ATmega8 у меня под рукой не оказалось, а у ATmega328 был китайский клон Arduino Uno. Я искал библиотеку Arduino для этого дисплея и нашел это. Однако он предназначен для ESP8266. У меня возникла идея заменить SPI в функции send_to_lcd с программного на аппаратный, но вот так:


В результате все, что мне нужно было сделать, это портировать оригинальную библиотеку Игоря (Igyosha) на Uno и заменить функции назначения текстового редактора (например, LCD_CLK=0) на digitalWrite(LCD_CLK, LOW) Arduino. Библиотека запустилась без проблем.

Поскольку он использует программное моделирование SPI, вы можете назначать контакты GPIO произвольно (за исключением контактов, занятых RX TX). В итоге я оставил библиотеку Arduino Uno в основной ветке Github для этого дисплея.

Результат запуска программы и скорость, с которой работает SPI, можно наглядно увидеть на видео:


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

Проверено: дисплей работает. Это означает, что наши идеи в конечном итоге воплотятся в жизнь.

❯ 2. Подключаем Orange Pi GPIO


Как вы можете видеть в предыдущем фрагменте, скорость рисования черепашья. Это неудивительно. Контроллер работает на частоте всего 16 МГц, а также использует программный SPI для вывода изображения. Эту ситуацию следует исправить использованием более мощного и производительного контроллера. Именно тогда я наткнулся на статью Хоши, живущего в Хавровске.

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

Следовательно, вы не можете запустить код Хоши без изменений. В своей статье он работает с GPIO через библиотеку чипсета bcm2835. Этот чипсет отсутствует на плате и не может быть подключен к библиотеке. Я начал искать способ подключить GPIO к моему чипсету h3. Оказывается, для этого требуется библиотека WiringPi (на данный момент не поддерживается официальным автором). Однако простой установки через apt-get недостаточно. Оригинал устанавливался под Raspberry. Через некоторое время я нашел исправление для этой библиотеки от zhaoley. Я собрал его с помощью сборки (ветка h3) и обнаружил, что он работает на моей плате. После запуска сборки библиотека будет установлена ​​в вашей системе, и вы сможете вызывать ее из любого места (например, используйте sudo gpio readall для проверки контактов).

Назначение контактов GPIO «оранжевого цвета» назначается по определению, как и в Arduino:

Также обратите внимание на следующее: В схеме Ijuryosha AVR использовались логические уровни +5 В, но на Orange Pi разъем GPIO сразу работает на уровнях +3,3 В. Поэтому я удалил резисторный делитель. В результате конструкция выглядит следующим образом:

Однако аппаратный SPI не удалось реализовать сразу. Итак, чтобы перепроверить возможности дисплея, я снова взял библиотеку Игоря из AVR и портировал ее на WiringPi. К счастью, никаких особых изменений не потребовалось, достаточно поменять в коде LOW и HIGH на 0 и 1 соответственно. Функция задержки WiringPi также аналогична функции задержки Arduino. Также на этом этапе библиотека лишилась почти всех графических функций по отрисовке примитивов, кроме отрисовки отдельного кадра напрямую из буфера.
затем я скомпилировал программу через gcc (gcc –o example example.c –lwiringPi) и запустил ее с терминала.

Результаты можно увидеть на видео:


Однако разницы по сравнению с Arduino мало. Рендеринг теперь стал быстрее, но незначительно. Это неудивительно. Метод передачи SPI (Send_to_lcd) вызывается чаще всего, но он по-прежнему встроен в программное обеспечение, поэтому никакого прироста скорости вы не увидите. Сам GPIO очень медленный, его скорость сравнима со скоростью обычного Arduino. Поэтому нам нужно использовать аппаратный SPI, чтобы исправить ситуацию.

❯ 3. Подключаем аппаратный SPI


Вы также можете использовать библиотеку WiringPi для замены программного SPI на аппаратный. То есть из файла WiringPiSPI.h используйте функции WiringPiSPISetup и WiringPiSPIDataRW. Эти функции могут быть немного сложными. Однако этот SPI необходимо включить, прежде чем его можно будет использовать. Кроме того, в Интернете нет информации о том, как это сделать конкретно на ПК Orange Pi, но я смог найти некоторые направления для изучения. После некоторого поиска в Google я обнаружил, что spi можно включить, отредактировав файл /boot/armbianEnv.txt (относящийся к версии системы Armbian_23.11.1_Orangepipc_jammy_current_6.1.63_xfce_desktop.img).

Вам необходимо добавить следующую строку:

при следующей перезагрузке sudo в /dev/ появится spidev0.0. Это можно проверить, выполнив команду ls /dev | греп спи. Если вы видите spidev0.0, библиотека WiringPiSPI выберет его. Теперь вам нужно подключить контакты дисплея CS, CLK и DATA к выводу SPI0, как это сделал Хоши. Распиновка (40 контактов) идеально соответствует Raspberry Pi. Оставьте контакты RS и RESET в обычном состоянии GPIO.

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

Я столкнулся с проблемой буферизации пакетов SPI. Это устройство может отправлять только 4 килобайта данных за пакет. Поскольку используется 16-битный цвет, эта страница занимает примерно 44 КБ (132*176*2). Решение состоит в том, чтобы увеличить буфер SPI, и хотя это возможно, я не хотел полагаться на этот метод. Поэтому в своем коде я просто разбил страницу на 11 пакетов:

затем я использовал memcpy для копирования каждого пакета в буфер перед его отправкой. Это, кстати, необходимо еще и потому, что в процессе передачи буфер побайтно очищается и выходные данные заменяются входными данными из буфера RX (вывод MOSI).

Эта библиотека также позволяет регулировать скорость от 500 КГц до предела в 32 МГц. Это делается во время инициализации int fd =wiringPiSPISetup(0, 32000000); Установите канал 0 и скорость 32 МГц.

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

Обратите внимание: Спасение утонувшего сотового телефона. Силикагель или овсянка помогут.

Это можно увидеть на видео:


В первой половине видео показана часть области отображения, отправленная за одну передачу (4096 байт). Это примерно 1/10 от общей площади экрана. Скорость шины установлена ​​на 500 кГц. Во второй половине передаются все 11 областей и скорость шины составляет 32 МГц. Другими словами, скорость передачи составляет примерно 20 Мбит/сек. В данном случае, я думаю, вы достигли верхнего предела общей производительности сборки.

❯ 4. Выводим статичный bmp кадр


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

Я сделал ту же фотографию, что и господин Хоши, и получил почти такие же результаты. Подводными камнями были:

  1. Необходимо поменять 2 байта. Этот пункт был в кодексе Хоши. Или добавьте или удалите один дополнительный байт в начале пакета, чтобы сдвинуть весь массив.

  2. Исходное изображение было сохранено в 16-битном формате BMP с помощью Adobe Photoshop. Однако, как выяснилось после просмотра в HEX-редакторе, белый цвет у меня получился FF 7F вместо FF FF, в результате чего он выглядел как бирюзовый, а остальные цвета тоже были искажены:

Это произошло потому, что редактор сохраняет BMP-файл в режиме X1R5G5B5 (с альфа-каналом), а дисплей использует R5G6B5, то есть зеленый занимает на 1 бит больше. Таким образом, когда вы передаете изображение на дисплей, не только исчезает один из наиболее значимых битов, но и один цветовой канал подвергается двоичному сдвигу на единицу, искажая всю палитру. После сохранения изображения в нужном режиме значение белого было заменено на FF FF, потери 1 бита данных не было, и оно отрисовывалось в обычном цвете.

На этом мы закончили сборку библиотеки для работы с дисплеем, и начинается самое интересное: отображение живого видеопотока.

❯ 5. Пишем ПО для захвата экрана


Кроме того, вышеупомянутый автор выполняет рендеринг с использованием интерполяции из кадрового буфера ОС Linux /dev/fb0. Когда я попытался запустить его код, ничего хорошего не произошло. В моем случае из-за несовпадения данных фреймбуфер отображался в виде черной сетки, и мне нужно было интерполировать изображение не по всему рабочему столу, а по определенной области рабочего стола экран.

слева: рендеринг из /dev/fb0. Справа: рендеринг со скриншота.

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

Я решил присмотреться к встроенной в ОС утилите xfce4-screenshooter. Эта утилита позволяет делать снимки экрана с помощью командной строки и многое другое. Однако функции указания и сохранения диапазона не было, а каждый раз указывать диапазон мышкой было неудобно. Поэтому я форкнул код этой утилиты. И в дополнение к ПОЛНОЭКРАННОМУ, ОКНОМУ и ОБЛАСТИ я добавил аргумент ФИКСИРОВАННЫЙ в параметры командной строки. Это сохранит область экрана, специально записанную в вашем коде, в файл.

для облегчения разработки мне пришлось установить xubuntu на виртуальную машину с x86, доработать исходный код и скомпилировать его, тогда как на Orange Pi пришлось компилировать непосредственно на Armbian. Эта утилита создана с использованием xdt-autogen. Сначала используйте ./autogen.sh, затем установите необходимые библиотеки (через apt-install), затем используйте make для установки библиотек, установленных в вашей системе, с помощью make install. Замените существующий снимок экрана исправленной версией. После этого вы можете вывести готовый скриншот нужного вам размера в файл с помощью всего одной команды Терминала. Исходный код скриншота используется для определения путей к файлам, форматов и т д.

однако у этого решения есть и недостатки. Ваша программа создания снимков экрана, вероятно, работает, сначала делая снимок всего корневого окна (рабочего стола), а затем обрезая его до нужного размера. В то же время рендеринг может в какой-то момент приостановиться. Вся процедура съемки занимает немалое количество времени. На рабочем столе xubuntu это заняло около 50-100 мс. На Orange Pi это заняло около 100-400 мс. Захват видео обычно представляет собой сложную для процессора процедуру. Так что понижение разрешения рабочего стола помогло, но незначительно. В идеале вам следует копировать изображения непосредственно из памяти экрана с помощью низкоуровневого кода, а не из пользовательской среды с помощью функций gdk. Кроме того, в самом коде скриншотов указано, что рекомендуемая задержка между скриншотами должна составлять не менее 200 мс. Так это уже ограничение 5 FPS. Это нормально, если вы просто смотрите на вывод консоли, но я обнаружил, что этого недостаточно для видеопотоков.

примечание. Редактирование: через некоторое время после написания статьи мне удалось решить эту проблему, используя программное обеспечение jsmpeg-vnc вместо снимков экрана. С его помощью вы получите более 50 FPS, плюс в него встроена функция обрезки кадра до нужного размера.

Это программное обеспечение отправляет потоки MPEG (транслирует видеосигнал) по протоколу WebSocket, поэтому вы можете кодировать только нужную вам область, не передавая весь рабочий стол. Затем кадр можно декодировать и отправить непосредственно на контроллер, избегая важной задачи его отображения на экране и создания снимка экрана. Если это интересно, мы объясним это более подробно в следующей статье.


также сохранение в bmp осуществляется через встроенные инструменты gdk, поэтому сохранить программу в 16-битном формате мне не удалось. Поскольку он хранился в 24-битном формате, мне пришлось написать код с использованием двоичных сдвигов для преобразования цветовой палитры:

сначала содержимое скриншота копируется в массив байтов (uint8_t) в порядке приоритета. Сдвиг используется для преобразования цвета 24 бит -> 16 бит (порядок байтов также обратный). Сравните первый байт красного цвета с 5 байтами, затем второй байт зеленого цвета с 3 байтами и сдвиньте результат в начало. Затем сравните следующий бит зеленого байта и переместите его в конец, затем сравните синий байт и переместите его в середину. Поэтому я переместил палитру с цвета KKKKKKKK ZZZZZZZZ SSSSSSS на цвет, который принимает дисплей, ZZZSSSSS KKKKKZZZZ. Я использовал цветное изображение для отладки и следовал инструкциям, чтобы проверить, правильно ли отображаются цвета или нужно сместить цветовые каналы на определенное количество ячеек.

Затем я запустил снимок экрана в цикле через вызов терминала и отобразил изображение на экране. Это можно увидеть на видео:


конечно, этот пункт программы нуждается в доработке. Ссылки на файлы заголовков для библиотек gdk и x11 кэшируют изображения на жестком диске. Это может привести к некоторому улучшению производительности. И чтобы добиться идеального поведения, все это нужно было бы переписать на уровне ядра ОС, чтобы превратить доморощенную библиотеку в драйвер для устройства. Однако текущий прогресс программы выглядит следующим образом:

  • инструмент создания скриншотов вызывается через терминал и сохраняет кадр в кэш.bmp;

  • Файл Cache.bmp будет открыт, и его содержимое будет отправлено на дисплей.

Причем основное подтормаживание происходит на этапе снятия скриншотов, а не записи/чтения на диск. Чтобы получить FPS выше 5, необходимо заменить скриншот xfce4 другим программным обеспечением. Но мы идем дальше.

❯ 6. Эмуляция сотового телефона


Эмулятор телефона CX75 был создан около 20 лет назад и входил в состав официального программного пакета для разработки Java-приложений посредством WTK/JDK 2.0. Он пролежал на моем жестком диске около 15 лет, затем я загрузил его для этой задачи. Поделитесь файлом, если кто-то хочет запустить его на своем компьютере.

Требуется JDK 6u45 и Windows XP. Насколько я помню, эмулятор вылетал даже при запуске в Windows 7, но на Win 10 я не проводил дальнейшего тестирования. Итак, он загружается через виртуальную машину с WinXP.

Эмулятор полностью реализует возможности прошивки телефона 75 серии, включая возможность установки Java-игр и подключения веб-камеры для фотосъемки. Единственное, ваш интернет, скорее всего, перестанет работать, потому что технология WAP больше не доступна.

Эмулятор выглядит в системном окне так: Управлять им можно с клавиатуры (джойстик — стрелки и Enter, клавиши — цифры или тачпад) или нажатием виртуальных кнопок.

он создает изображение 132x176 четко определенного размера, поэтому интерполяция не требуется. Далее вам необходимо перенести образ с вашей виртуальной машины на машину с Linux. Можно было использовать вино, но не уверен, что эмулятор будет работать корректно. Поэтому на XP работает. Если вы хотите перенести изображения, не придумывайте ничего нового и используйте TightVNC.

В Windows установите сервер, а в Armbian — клиент через apt-get xtightvncviewer.

Далее запустите клиент-сервер и установите необходимую область отображения на экране. FPS в этом случае тоже примерно равен 5 кадрам, поэтому дисплей будет рендериться точно с такой же скоростью.

И это момент, когда все началось. Разместите эмулятор телефона на области экрана самого телефона

видео:


Таким образом, видеопоток проходит через следующие слои:

  • Эмулятор CX75 (программа на языке C x86, но порт прошивки, совместимой с ARM);

  • Windows XP (виртуальная машина);

  • Windows 10 (через виртуализацию, но виртуализацию можно пропустить, выведя напрямую в VNC из XP);

  • Графический интерфейс Armbian xfce4 (через VNC);

  • кэш изображения.bmp (через xfce4-screenshooter);

  • Показать C75 (через Wired Pi + Wired PiSPI).


Для эмуляции клавиатуры достаточно припаять контактные площадки к USB-контроллеру клавиатуры согласно схеме подключения:

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

❯ 7. Заключение


Результаты проекта:

В ходе работы была исследована возможность использования GPIO, SPI, GTK3, VNC, преобразования цвета и других возможностей компьютерных и микроконтроллерных систем.

Подготовьте файл проекта для WiringPi.

Спасибо за внимание.


  • Написано специально для читателей Timeweb Cloud и Pikabu. Подпишитесь на наш блог, чтобы не пропустить новый и интересный материал.

  • Также подпишитесь на наш эксклюзивный канал в Telegram, посвященный техническим, информативным и юмористическим вопросам об IT, технологиях и электронике. Это будет интересно.

  • Облачный сервис Timeweb Cloud — это реферальная ссылка, которая помогает поддерживать проект.

[мое]PythonTimeweb Эмулятор ИТ-электроники для мобильных телефонов Видео на YouTube Длинная запись 8

Больше интересных статей здесь: Гаджеты.

Источник статьи: Эмуляция сотового телефона… на сотовом телефоне.