Перенос переднего стека технологий на портативную игровую консоль

внешний интерфейс JavaScript внешний фреймворк
Перенос переднего стека технологий на портативную игровую консоль

Как интерфейсные инженеры, код, который мы пишем, может жить только в браузере, апплете или процессе Node, что, кажется, стало здравым смыслом. Но разве это предел наших возможностей? В этой статье вы адаптируете интерфейсный набор инструментов для портативной игровой консоли с объемом памяти всего 32 МБ и разрешением 320x240, а также увидите новые возможности стека веб-технологий.

На этот раз наша цель — получить только ностальгический портативный компьютер Miyoo с 400-мегагерцовым одноядерным процессором и 32-мегабайтной памятью. Хотя он совершенно не сравним с текущими мобильными телефонами iOS и Android, он вполне может удовлетворить потребности игры в симуляторы классических игровых платформ, таких как Xiaobawang, GBA, аркадные и другие симуляторы классических игровых платформ, в небольшом и изысканном размере, а цена составляет также чрезвычайно низкий. Вот его сравнение с iPad mini:

Итак, что считается трансплантацией стека передовых технологий? В моем личном понимании это включает как минимум следующие части:

  • среда сборки- Набор инструментов для сборки приложений
  • Время выполнения- Встроенный JS-движок
  • среда отладки- Поддержка IDE или редактора

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

  • Создайте цепочку инструментов Docker
  • Прогулка по Hello World
  • Заголовок для пайки и вход в последовательный порт
  • Пользовательский драйвер ядра Linux
  • Портирование JS-движка
  • Поддержка отладчика VSCode

Давайте рок!

Создайте цепочку инструментов Docker

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

Miyoo — это портативный компьютер, настроенный небольшой отечественной компанией на базе чипа Allwinner F1C500S, его операционная система по умолчанию — ОС Melis с закрытым исходным кодом, которая продается за рубежом под именами Bittboy и Pocket Go и хорошо известна. Систем с закрытым исходным кодом, естественно, недостаточно для любителей, поэтому сообщество реконструировало их. Старший Ситу из Тайваня (Steward Fu) успешно портировал Linux на этот КПК, но, к сожалению, прекратил разработку по личным причинам. Теперь система с открытым исходным кодом этой игровой консолиMiyooCFWОснованное на самом раннем портированном ядре Linux 4.14 от Situ, оно поддерживается сообществом.

Поэтому наша целевая система не является ни iOS, ни Android, аАутентичный линукс! Как скомпилировать приложение для встроенного Linux? Нам нужен набор базовых инструментов, состоящий из компиляторов, ассемблеров, линкеров и т.д.набор инструментов, чтобы создать пригодный для использования двоичный файл ARM.

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

Мы знаем, что контейнеры Docker можно понимать как более легкие виртуальные машины. нам нужно только одно предложениеdocker runКоманда может запускать контейнер и подключать к нему внешние ресурсы, такие как файлы и сети. Очевидно, что сейчас нам нужен контейнер Docker [который может компилировать встроенные приложения Linux], чего можно добиться, создав базовый образ Docker для запуска контейнера. Образы Docker легко распространять между платформами, поэтому просто создайте и загрузите образ, и базовая среда разработки готова.

Итак, что должно быть включено в этот образ Docker? Очевидно, это набор инструментов для компиляции встроенных приложений. Situ предоставил сообществу набор предварительно скомпилированных пакетов набора инструментов для Debian 9, просто распакуйте его в/opt/miyooкаталог, а затем установите некоторые общие зависимости, чтобы завершить создание образа. Этот процесс можно автоматизировать с помощью Dockerfile, который выглядит следующим образом:

FROM debian:9
ADD toolchain.tar.gz /opt
ENV PATH="${PATH}:/opt/miyoo/bin"
ENV ARCH="arm"
ENV CROSS_COMPILE="arm-miyoo-linux-uclibcgnueabi-"
RUN apt-get update && apt-get install -y \
    build-essential \
    bc \
    libncurses5-dev \
    libncursesw5-dev \
    libssl-dev \
    && rm -rf /var/lib/apt/lists/*
WORKDIR /root

Так что просто используйтеdocker buildкомандой, мы можем создать чистый встроенный образ для разработки из чистого образа Debian. Так как же собрать файл с зеркалом? Предположим, мы делаемmiyoo_sdkобраз, затем просто смонтируйте каталог локальной файловой системы в контейнер, запущенный на основе образа. нравится:

docker run -it --rm -v `pwd`:/root miyoo_sdk

Вкратце смысл этой команды таков:

  • docker runна основеmiyoo_sdkзеркало начать одинвременныйконтейнер
  • -vСмонтируйте текущий каталог в контейнер/rootВниз
  • -itДавайте используем текущий терминал для входа в оболочку, которая управляет контейнером.
  • --rmСделать контейнер одноразовым, помимо изменения текущего каталога,не оставлять следов

Итак, мы на самом деле основаны на Docker,Скомпилировал исходный код в файловой системе Mac прямо в контейнере. Это не имеет ни побочных эффектов, ни других операций по передаче данных. Я считаю, что для все более сложной проблемы зависимости интерфейсной цепочки инструментов это тоже решение, и есть возможность написать отдельную статью.

Прогулка по Hello World

После создания образа Docker мы можем использовать его в контейнере.arm-linux-gccтакой компилятор. Итак, как скомпилировать Hello World? Пока не время знакомить с JS-движком, давайте напишем простой пример на языке C, чтобы убедиться, что все работает правильно.

Встроенные устройства Linux часто используют библиотеку SDL для визуализации базового графического интерфейса. Самый простой пример: похож ли он на Canvas, знакомый студентам, изучающим интерфейс?

#include <stdio.h>
#include <SDL.h>

int main(int argc, char* args[])
{
  printf("Init!\n");
  SDL_Surface* screen;
  screen = SDL_SetVideoMode(320, 240, 16, SDL_HWSURFACE | SDL_DOUBLEBUF);
  SDL_ShowCursor(0);
  // 填充红色
  SDL_FillRect(screen, &screen->clip_rect, SDL_MapRGB(screen->format, 0xff, 0x00, 0x00));
  // 交换一次缓冲区
  SDL_Flip(screen);
  SDL_Delay(10000);
  SDL_Quit();
  return 0;
}

Этот исходный код C можно скомпилировать из нашей среды Docker. Но явно приложения малого масштаба не стоит напрямую стучатьgccСборку лучше автоматизировать с кучей таких параметров (обратите внимание, что отступ должен быть таб):

all:
    arm-linux-gcc main.c -o demo.out -ggdb -lSDL -I/opt/miyoo/arm-miyoo-linux-uclibcgnueabi/sysroot/usr/include/SDL
clean:
    rm -rf demo.out

Помимо входа в оболочку контейнера Docker, мы также можем использовать-dПараметры для простого создания «безголовых» контейнеров, которые помогают компилировать в фоновом режиме. как требуется для сборки этого Makefilemakeкоманду, вы можете сделать это одной строкой в ​​терминале Mac:

docker run -d --rm -v `pwd`:/root miyoo_sdk make

Это создастdemo.outбинарный файл. Скопируйте этот файл размером 12 КБ на TF-карту Miyoo./appsПосле входа в каталог откройте его с помощью установщика программы, который поставляется с Miyoo, и вы увидите такой результат:

Это показывает, что набор инструментов компиляции Docker работает правильно! Но этого мало, ключевой вопрос сейчас в том, что нашиprintfКуда это делось?

Заголовок для пайки и вход в последовательный порт

Базовые знания Unix говорят нам, что выходные данные процесса записываются в стандартный выходной файл stdout по умолчанию. Обычно эти выходные данные записываются в буферы потоковой передачи, которые затем передаются на терминал. Но где терминал для встраиваемых устройств? Обычно эти журналы записываются в так называемую последовательную консоль. И данные такого рода консоли могут взаимодействовать с ПК через очень старый передатчик UART, просто нужно подключить соединение трех цепей.

Поэтому нам нужно найти способ подключить интерфейс UART Miyoo, чтобы мы могли войти в его Shell на компьютере. В связи с этим СтюартПрипаяйте разъем UARTЭта статья является очень хорошим справочником. Меня особенно впечатлил один из них:

Производитель очень внимателен, особенно вытащил GND, UART1 RX, UART1 TX (сверху вниз), чтобы предоставить разработчикам удобный интерфейс разработки.

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

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

Видите на картинке три контакта в правом верхнем углу материнской платы? Это три интерфейса UART (я его еще не паял, просто надел на него штыревые разъемы). Это GND, RX и TX сверху вниз.Просто припаяйте к ним контактные разъемы, подключите провода к преобразователю UART в USB, и вы можете войти в него на Mac. Порядок подключения такой:

  • GND Miyoo подключен к GND преобразователя
  • RX Miyoo на TX конвертера
  • TX Miyoo на RX конвертера

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

После пайки используйте мультиметр, чтобы измерить, соединены ли паяные соединения. Вы еще помните, как соединяли красную и черную проверочные ручки мультиметра на школьном уроке физики... Во всяком случае, я это давно забыл, и сейчас учу. Фактические измеренные значения сопротивления от RX и TX до GND составляют около 600 Ом, что означает, что соединение гладкое.

С адаптером эффект после подключения следующий:

Наконец, я сделал отверстие в задней крышке, чтобы можно было вставить машину обратно, вот так:

После завершения этого аппаратного преобразования, как реализовать подключение к программному обеспечению? Для этого требуется программное обеспечение, которое может войти в последовательный порт. Все в Unix является файлом, поэтому нам просто нужно найти/devФайл последовательного порта в каталоге, а затем откройте файл с программным обеспечением последовательной связи. screen — это встроенное программное обеспечение сеанса командной строки для Mac, но его использование более проблематично.Здесь пользователям Mac рекомендуется использовать более удобный minicom. После подключения вы можете увидеть вывод журнала входа в систему следующим образом:

[    1.000000] devtmpfs: mounted
[    1.010000] Freeing unused kernel memory: 1024K
[    1.130000] EXT4-fs (mmcblk0p2): re-mounted. Opts: data=ordered
[    1.230000] FAT-fs (mmcblk0p4): Volume was not properly unmounted. Some data may be corrupt. Ple.
[    1.250000] Adding 262140k swap on /dev/mmcblk0p3.  Priority:-2 extents:1 across:262140k SS
Starting logging: OK
read-only file system detected...done
Starting system message bus: dbus-daemon[72]: Failed to start message bus: Failed to open socket: Fd
done
Starting network: ip: socket: Function not implemented
ip: socket: Function not implemented
FAIL

Welcome to Miyoo
miyoo login: 

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

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

  • Прежде всего, с точки зрения программного обеспечения, я неоднократно подтверждал конфигурацию программного обеспечения последовательной связи и разбирал соответствующий процесс настройки при запуске Linux.Я смонтировал раздел rootfs в формате EXT4 машины на Mac и подтвердил это. ./etc/inittabнастройка и запускается/etc/mainВсе сценарии действительны, что исключает проблемы с программным обеспечением на стороне устройства.
  • Затем на оборудовании я подтвердил, что в схеме нет виртуальной пайки, и поэкспериментировал с использованием Raspberry Pi для связи с Mac через последовательный порт, подтвердив, что в это время терминал можно нормально использовать, и проблема периферийное оборудование было исключено.
  • Наконец, я обнаружил, что при общении с Raspberry Pi кнопка на боковой панели Mac может вызывать мигание индикаторов RX и TX адаптера. Но когда Miyoo подключен, передатчик TX на стороне Mac будет мигать только при нажатии кнопки, а сигнал, который должен быть возвращен через RX, не будет получен. Так что предположительно проблема с линией RX этого интерфейса. После того, как я подробно разобрался с явлением и спросил Ситу, я получил ответ: UART используется совместно с гарнитурой, а ядро ​​Linux необходимо перекомпилировать.

Ну, на самом деле я столкнулся с физической схемой на всем пути отладки.аппаратная проблема. Затем измените ядро ​​Linux.

Пользовательский драйвер ядра Linux

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

Во-первых, мы должны хотя бы уметь компилировать ядро. Обратите внимание, что ядро ​​отличается от встроенной системы Linux. Полная встраиваемая система Linux должна примерно включать следующие части:

  • Kernel- Содержит основные подсистемы операционной системы, а также необходимые аппаратные драйверы
  • Rootfs- Корневая файловая система - это примерно куча бинарных приложений, размещенных в корневом каталоге.
  • UBoot- Загрузчик, который сам по себе эквивалентен очень простой операционной системе

Мы просто хотим отключить звуковой драйвер, поэтому просто перекомпилируйте ядро. Ядро скомпилировано в образ с именем zImage. Пользовательский опыт этого процесса на самом деле ничем не отличается от компиляции обычного проекта C, то есть сначала настраиваются параметры компиляции и переменные среды, а затемmakeПросто сделать:

make miyoo_defconfig
make zImage

В Docker на моем MacBook Pro компиляция ядра заняла примерно 12 минут. Вот картинка в память о ядре Linux, скомпилированном впервые в моей карьере:

После того, как компиляция была пройдена, я был очень рад напрямую попробовать модифицировать драйвер ядра (обратите внимание, что я не тестировал первое скомпилированное ядро ​​на реальной машине, это предзнаменование). После некоторых исследований я обнаружил, что аппаратное обеспечение встроенного Linux описывается своего рода кодом DSL, называемым деревом устройств, и модификация этого DSL должна привести к тому, что ядро ​​не будет поддерживать определенное оборудование. Итак, я нашел звуковую часть дерева устройств Miyoo, закомментировал ее, попытался скомпилировать файл описания дерева устройств без звука и установил его.

Затем, когда машина запускается, экран становится черным.

...

Кажется, конфигурация дерева устройств не работает, и я подумал о том, чтобы напрямую изменить исходный код C аудиодрайвера. это проект ядра/sound/soc/suniv/miyoo.c, код на Си внутри не выглядит сложным, но я перепробовал не менее семи-восьми методов модификации, но собрать нормальный образ не получается: иногда это может решить проблему, что UART не может войти, иногда нет, и проблема с черным экраном так и не решена. Почему звуковой драйвер влияет на видеовыход, меня очень беспокоило, и в какой-то момент я усомнился в своем наборе инструментов.

В итоге я пришел к шокирующему выводу:

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

...

Итак, я изменил код ядра версии сообщества, экран загорается плавно, и проблема решена.

Однако версию ядра для сообщества поддерживают иностранцы, в их привычках определения клавиш A и B противоположны (студенты, которые играли в американскую версию PSP в молодости, должны знать, что я имею в виду). ). Поэтому я снова начал подбрасывать, пытаясь поменять местами А и Б.

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

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

В результате я пришел к еще одному шокирующему выводу:

В этом коде неправильно написано имя переменной. Переменными этого свопа являются не A и B, а A и X.

...

Кажется, у меня действительно нет таланта писать ядро ​​​​Linux, поэтому давайте вернемся и честно портируем движок JS.

Портирование JS-движка

Получив уровень ядра, мы можем легко войти в консоль Miyoo. Имя пользователя root, пароля нет. После стольких обходных путей я был очень взволнован, когда успешно вошел в систему в первый раз. Скриншоты на память:

Далее, портирование движка JS прикладного уровня мне знакомо. Вот наш старый другQuickJSДвижок, представляющий собой ультраминиатюрный встроенный JS-движок, даже совместим со многими функциями ES2020. Поскольку у него нет сторонних зависимостей, его несложно перенести на Miyoo.CROSS_PREFIX=arm-miyoo-linux-uclibcgnueabi-, вы можете использовать кросс-компилятор для его компиляции.

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

  • malloc_usable_sizeНе поддерживается, это повлияет на получение данных измерения памяти, но JS все еще может успешно работать. Кстати, с точки зрения исходного кода, эта возможность не поддерживается в WASM. Так что на самом деле кто-то уже скомпилировал QuickJS в WASM и поиграл в матрешку JS в JS.
  • fenv.hотсутствует, что должно повлиять на округление поплавков, но измеренное значениеMath.ceilиMath.floorнет эффекта. Оставь его в покое, дело не в том, что его все равно нельзя использовать (Эй)

Эту небольшую проблему можно решить, просто исправив соответствующий код. После успешной компиляции скопируйте его в раздел rootfs/usr/binкаталог, вы можете использовать его в Miyoo's ShellqjsТеперь команда запускает JS. Наконец-то это круто, смотрите, как я возвращаюсь на родную площадку, трещу и пишу JS-тест:

import { setTimeout } from 'os'

const wait = timeout =>
  new Promise(resolve => setTimeout(resolve, timeout))

let i = 0
;(async () => {
  while (true) {
    await wait(2000)
    console.log(`Hello World ${i}!`)
    i++
  }
})()

Скриншот тому доказательство, я действительно бегал в Miyoo:

Но как выводить результат работы этого JS-кода на реальную машину? Мы знаем, что в Linux по умолчанию/dev/consoleсистемная консоль и/dev/tty1виртуальный терминал, поэтому до тех пор, покаinittabреброconsole::respawn:/etc/mainизменить наtty1::respawn:/etc/main, вы можете вывести на графический виртуальный терминал. нравится:

Поддержка отладчика VSCode

JS может работать, а логи можно читать, так какой велосипед вам нужен? Конечно, он поддерживает точку останова для него! Я всегда думал, что отладку точки останова нужно делать с помощью тяжелого движка, такого как V8 с Chrome, но что меня удивило, так это то, что сообщество реализовало форк, поддерживающий отладчик для QuickJS, так что в качестве внешнего интерфейса отладчика нужен только VSCode. , Может отлаживать код среды выполнения движка QuickJS. Благодаря удаленной функции VSCode у этой штуки есть много места для воображения.

Этот шаг поддержки самый простой в полном тексте. Т.к. я делал проверку только на Маке, и компиляция прошла один раз, сказать нечего. Эффект такой:

Отладчик VSCode, который вы видите на картинке, — это не V8, а серьезный движок QuickJS. Я также использовал VSCode для отладки кода Dart и C++, в то время я не думал о том, как такой набор отладчиков может быть подключен к стороннему языку. После поиска я обнаружил, что Microsoft даже разработала общий протокол отладки под названием Debug Adapter Protocol между редакторами и любым сторонним языком, что весьма поучительно. Оказывается, я думаю, что система отладки языка программирования очень высокого уровня также может быть абстрагирована и структурирована с помощью таких концепций, как точки останова и исключения, и может быть разработан общий протокол. Накопление Microsoft в инженерном дизайне и документации действительно не охвачено.Мне это нравится.

Теперь я скомпилировал эту версию QuickJS, которая поддерживает отладку VSCode, для Miyoo, но я не занимался фактической отладкой — с уроком копания дыр для себя при настройке драйвера ядра, я, естественно, не осмеливаюсь сейчас встать. работает (закрывает лицо)

Пока возможности этого эксперимента в основном проверены. Соответствующий образ Docker я также опубликовал на GitHub, см.MiyooSDK. Все обмены также приветствуются.

постскриптум

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

  • USB-связь пока не поддерживается, а вход по SSH невозможен.
  • Средство визуализации графического интерфейса для C еще не реализовано для JS.
  • Нет верхнего фреймворка для переноса JS

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

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

Вот вопрос, на таобао есть много магазинов, которые продают наладонники от имени системы Ситу, и эти бизнесы не имеют к нему никакого отношения. Хотя я по-прежнему настоятельно рекомендую всем купить этот портативный компьютер Miyoo для развлечения или технических исследований, который стоит всего более 100 юаней, у меня все еще есть некоторые эмоции. Так называемый человек, наполненный Луо Ци, не разводил шелковичных червей, возможно, так оно и было.

От создания наборов инструментов до пайки печатных плат и настройки ядра Linux и JS-движка — у этих технологий есть свои барьеры. Но забавные цели всегда делают нас более мотивированными для преодоления всевозможных трудностей на полпути. Я считаю, что интерес и энтузиазм всегда больше всего стимулируют любознательность, а ненасытное стремление к знаниям может заставить нас продолжать идти по горам. В конце концов, что говорит известная поговорка, которую упомянул глава банды Цяо?

Stay Hungry. Stay Foolish.

Я в первую очередь фронтенд-разработчик. Если вас интересуют веб-редакторы, рендеринг WebGL, дизайн гибридной архитектуры или мысли компьютерных энтузиастов, добро пожаловать на меня :)

#вдохновение