Новая нить повествования
Моё путешествие оказалось довольно долгим, и сегодня уже третья годовщина с момента начала серии статей Edge of Emulation. Когда я впервые работал над эмуляцией сканера штрихкодов Barcode Taisen Bardigun в 2017 году, я понятия не имел, сколько ещё смогу всего сделать. Моя цель заключалась в завершении списка, исследовании и документировании по одному устройству за раз, но я не знал, есть ли вообще у меня нужные навыки для выполнения этой задачи. За последние несколько лет я столкнулся с большим количеством трудностей и множеством различных проблем. Тем не менее, мне как-то удалось преодолеть все эти препятствия благодаря уделённому времени, решимости и помощи друзей и коллег. Некоторые устройства очень просты, и для их правильной эмуляции требовалось всего один-два дня. Однако другие были упрямы и трудны. Тема этой статьи доставила мне особую головную боль.
В начале 2000-х японская швейная компания Jaguar выпустила машину с одной очень любопытной функцией. Шаблоны шитья не были встроены в саму швейную машину Jaguar JN-100 (так же известную как «nuyell»); вместо этого она с помощью Link Cable подключалась к Game Boy и получала инструкции. Программное обеспечение, называвшееся Raku x Raku Mishin, поставлялось на обычном чёрном картридже Game Boy и занималось передачей данных на JN-100. Пользователи могли программировать машину, чтобы она шила различные узоры, петлицы, символы каны, буквы и даже короткие контуры, создаваемые пользователем. Американская компания Singer («Зингер») увидела в JN-100 потенциал для бизнеса; позже две стороны пришли к соглашению о выпуске в США почти точной копии машины под собственным брендом компании Singer IZEK 1500. В 2001 году Jaguar создала вторую модель под названием JN-2000 (или «nuotto»), которая могла похвастаться повышенной скоростью шитья и специальным устройством для вышивания под названием EM-2000. JN-2000 имела обратную совместимость с картриджем Game Boy для JN-100, однако для новых функций вышивания JN-2000 были выпущены три дополнительные программы. Хотя Jaguar обрела заметный успех со своими продуктами, в США модель Singer IZEK-1500 не стала особо популярной. Были планы выпустить новую версию, тоже с поддержкой вышивки, но «Зингер» так их полностью и не реализовала. Поэтому возможности JN-2000 по вышиванию графики Mario на одежде можно было использовать только в Японии.
Кому-то может показаться смехотворной идея совмещения Game Boy и швейных машинок, но, тем не менее, все три модели были исторически важны как для области видеоигр, так и домашнего шитья. Хотя уже задолго до этого промышленные швейные машины обладали возможностями программируемого шитья, потребительский рынок отставал от них в функциональности и цене. Это сегодня дешёвое цифровое шитьё является нормой, но на рубеже веков Jaguar совершила своего рода революцию, предоставив потребителям доступное и простое в работе оборудование. Использование в качестве основного интерфейса Game Boy снижало сложность (всего несколько кнопок, меню могут быть цветными и можно отображать любой объём информации, даже обучающие руководства). Кроме того, компания экономила благодаря использованию известных компонентов, ведь ей не пришлось разрабатывать оборудование с нуля. Более того, нередко инструкции на швейные машины подаются с внешних источников. Современные швейные машины часто подключаются к PC по USB для передачи дизайна вышивок, а будущее, возможно, за приложениями для смартфонов, передающих данные по Bluetooth. Как бы то ни было, портативная консоль Nintendo стала первым (и единственным?) таким устройством, совместно работающим с швейной машиной; она сделала свой вклад в дело популяризации цифрового шитья и вышивания. Хоть это и кажется странным союзом, на практике оба устройства работали довольно неплохо.
Но даже при всё этом, такие швейные машины остаются одними из самых экзотических и удивительных аксессуаров для Game Boy. Они демонстрируют, насколько далеко скромный Game Boy может выйти за границы видеоигр. К сожалению, хотя мы многое знаем из истории машин Jaguar и Singer, подробности их работы десятилетиями оставались загадкой. Когда я узнал о них, то не мог удержаться от стремления узнать, какие секреты хранятся внутри. Строго говоря, ни швейные машины, ни их ПО не являются видеоиграми. Тем не менее, они слишком важны с культурной точки зрения, чтобы их игнорировать. Чтобы их история со временем не исчезла, я решил поучаствовать в их сохранении. Мне уже удалось эмулировать довольно безумные проекты на Game Boy: игрушки с инфракрасным распознаванием движений, картриджи с питанием от Солнца, фигурки в стиле Amiibo и роботы. Но эмуляция швейной машины? Это нечто совершенно иное. Чтобы заниматься этим, нужно сойти с ума, правда?
Иголка в стоге сена
Для исследования этих машин требуется физический доступ, что, в свою очередь, означает дополнительные траты. Ведь было три различные модели (JN-100, JN-2000, IZEK 1500), к тому же, каждая сама по себе стоит приличных сумм. Модели JN-100 и IZEK 1500 нечасто встречаются, но найти их можно, однако некоторые сложности приводят к повышению их цен. IZEK 1500 обычно продаётся примерно за 150-250 долларов, но если к самой машине добавляются оригинальные материалы, например, VHS-кассета с инструкциями, ПО для Game Boy или даже коробка, то её ценность возрастает на сотни долларов. Доставка, даже в пределах одной страны, требует ещё 25-50 долларов. JN-100 на японских сайтах обычно продаётся гораздо дешевле. Многие имеют пометку «сломано» и могут стоить по 20-50 долларов. Однако международная доставка запросто может удвоить или утроить эту сумму.
По-настоящему редкой является JN-2000, ведь она, скорее всего, продавалась гораздо меньшими тиражами. Аукционы на десятки первых двух машины проходят почти каждые несколько месяцев, но модель JN-2000 продаётся за год всего с десяток раз. Ущерб кошельку коллекционера сильно разнится — от 30 до 160, 400 или даже 1500 долларов, в зависимости от комплектности. За самую дорогую, которую я видел, просили 5100 долларов. В комплект входили: совершенно новая JN-2000, EM-2000, две копии Raku x Raku Cut Shuu/Moji и одна копия Mario Family (которая, вероятно, является самым редким ПО для Game Boy Color). Не нужно говорить, что для покупки всех трёх швейных машин потребовалось много денег, терпения и удачи. К счастью, я импортировал обе модели Jaguar сильно задолго до эпидемии COVID-19. Вирус помешал многим видам перевозок, ограничив возможные варианты поставки и повысив тарифы (иногда в разы — да, я имею в виду тебя, DHL).
Как говорилось выше, Jaguar JN-100 и Singer IZEK-1500 во всех аспектах являются почти идеальными копиями друг друга. Единственные очевидные различия заключаются в кабелях питания (убирающийся в JN-100 и подключаемый в IZEK-1500) и цветовых гаммах. JN-100 поставлялась в шести цветовых вариантах, а IZEK-1500 имеет только синюю расцветку. У обеих машин есть полупрозрачные пластмассовые детали, навевающие воспоминания об эстетике iMac G3. JN-2000 имеет совершенно иной стиль корпуса, похожий на другие продукты Singer, например, многие модели Futura. Она имеет и полностью прозрачные пластмассовые детали, хотя изготавливалась только в красном цвете. На платформе машины есть пустое гнездо, куда во время шитья вставляется Game Boy. Наиболее примечательно то, что часть JN-2000 сдвигается и открывается порт, к которому подключается устройство для вышивания EM-2000. Во все три модели встроен кабель Link Cable.
Слева направо: IZEK 1500, JN-2000, JN-100. Было непросто разместить всю банду у меня на столе.
Всего для этих машин было написано 5 видов совместимого ПО. Первое — Raku x Raku Mishin — поставлялся со всеми JN-100. Его основное предназначение — шаблоны для шитья и пользовательские узоры, петлицы, некоторые символы латиницы, символы каны и часть символов кандзи. Когда IZEK-1500 появилась в США, название ПО изменилось на «Sewing Machine Operating Software», но базовые функции остались такими же. Однако вместо каны и кандзи был расширен алфавит латиницы и добавлены новые стили (курсивные и контурные буквы). Похоже, существует и европейская версия, но подробностей о ней мало. Raku x Raku Moji справлялась с вышиванием катаканы, хираганы, некоторых символов и букв латиницы и множества символов кандзи. В отличие от вышивки Raku x Raku Mishin, их структура была сложной и состояла из сотен стежков, а не из 20-30. Raku x Raku Cut Shuu способна вышивать милые и стандартные рисунки — ракету, цветы и различных мультяшных животных. Последний картридж — Jaguar Mishin Sashi Senyou Soft: Mario Family — почти такой же, однако вся графика в нём имеет тематику игр про Марио. В нём есть принцесса Пич, Марио, Луиджи, Варио, Йоши и несколько других персонажей, однако, на удивление, отсутствует Баузер.
Эти картриджи GBC — одни из самых редких. Чтобы купить Mario Family в полной комплектации, придётся брать в банке небольшой кредит…
Мои исследования этих швейных машин начались ровно год назад, в начале мая 2019 года. Обычно на взлом устройства я трачу всего несколько недель. Максимум мне нужно было несколько месяцев на анализы и выполнение тестов, прежде чем я разберусь во всём. На самом деле я думал, что смогу справиться с основным объёмом работы за один-два выходных. Если бы всё пошло по плану, то эта статья была бы написана в 2019 году. К сожалению, я потратил намного больше, чем пару дней. Эти швейные машины стали для меня головоломкой, с которой никогда раньше не приходилось иметь дело, и много раз они ставили меня в тупик. Хоть я и не могу назвать их самыми сложными для реверс-инжиниринга устройствами, они определённо стали самыми утомительными. Я думал, что это будет пара пустяков, но столкнулся с гораздо более трудным случаем.
Шить или не шить
Singer IZEK 1500 купить было проще всего, поэтому её я начал изучать первой. Для начала я создал очень простой ROM-хак Sewing Machine Operation Software, который после прерывания последовательного интерфейса записывал все передаваемые по нему данные. Любопытно, что я не увидел никаких значимых данных, а только повторяющиеся паттерны из двух значений: 0x00
и 0xFF
. Пропустив ROM через отладчик эмулятора GBE+, я увидел, что не каждая передача данных должна вызывать прерывание последовательного интерфейса; следовательно, ROM-хаку не хватало важной информации. В отличие от всех остальных аксессуаров Game Boy, IZEK 1500 переключается между передачей данных при помощи внутренней и внешней синхронизации. По сути, при общении с Game Boy она переключается между master и slave (и консоль тоже переключается, всегда в противоположный режим, чтобы соответствовать машине). Передача данных из Game Boy в IZEK 1500 всегда выполняется через внешнюю синхронизацию, поэтому швейная машина контролирует скорость передачи битов. При такой передаче ПО отключает прерывания последовательного интерфейса, однако GBE+ прекрасно их видит и выводит в лог.
Захваченные эмулятором данные походили на передаваемый швейной машине пакет с инструкциями о том, как шить узор. Я сразу же увидел, что он имеет заголовок, за которым идёт тело, содержащее нечто, напоминавшее пары координат XY для точек шитья; в самом конце была некая контрольная сумма. Насколько я мог тогда судить, узор реализовывался простым сдвигом точки шитья вверх, вниз, влево или вправо на разные величины. Чтобы GBE+ правильно эмулировал эти швейные машины, ему нужно было воссоздать такое шитьё в виде пикселей на экране. Для этого достаточно лишь взять координаты XY из данных пакетов и начать рисовать линии, так ведь? Довольно легко и беспроблемно. Никаких сложностей.
Первая пара узоров, помеченная как A-001
до A-010
была линиями, которые двигались прямо вниз и иногда меняли координату X для создания диагоналей. Я скопировал часть кода отрисовки линий из моего рендерера NDS 3D, передал ему координаты из пакета и сохранил результат в файл BMP. Выходные данные этих узоров соответствовали предыдущим, показанным на экране Game Boy. Однако когда дело дошло до остальных узоров, всё быстро начало ломаться. Главным примером этих ошибок стал узор B-007
. Вместо того, чтобы идти зигзагами, как другие, он ровно шёл вбок, а потом вертикально вверх. Я обрабатывал каждую координату Y как положительную, чтобы двигаться вниз, потому что не знал, как IZEK 1500 обрабатывает отрицательные числа. Всё должно было оказаться довольно очевидным, допустим, у отрицательных чисел бит 7 имеет значение, а у всех положительных — нет. Но ничего подобного не было.
Вот тот самый узор.
---------------------------------------------------------
КООРДИНАТА X | КООРДИНАТА Y | ДВИЖЕНИЕ
---------------------------------------------------------
0x01 | 0x0D | ВНИЗ
0x01 | 0x0C | ВНИЗ
0x01 | 0x14 | ВПРАВО
0x0E | 0x1C | ВВЕРХ
0x0E | 0x14 | ВПРАВО
0x1B | 0x0C | ВНИЗ
0x1B | 0x0C | ВНИЗ
0x1B | 0x14 | ВЛЕВО
0x01 | 0x0D | ВНИЗ
---------------------------------------------------------
А вот сырые данные, передаваемые консолью Game Boy.
Я взял тестовый кусок ткани и наблюдал за каждым движением, чтобы проверить, что должна делать каждая пара XY. Довольно легко заметить, что координаты X ведут себя нормально, постепенно смещаясь слева направо при увеличении, а затем резко сдвигаясь назад влево, чтобы начать узор заново. Однако координаты Y вели себя как-то иначе. Поначалу кажется, что они движутся вкривь и вкось, хотя это не особо неожиданно, учитывая, что узор движется немного вверх и вниз. Однако когда я начал своё расследование, координаты Y выглядели для меня очень странно. Важная деталь заключалась в том, что координаты X работают относительно абсолютных позиций, а координаты Y ведут себя иначе. Ширина узора может быть только такой (от 0x00
до 0x1F
), потому что игла физически движется только на такое расстояние. Длина узора продолжается, пока хватает подаваемой в машину ткани.
Правильно интерпретировать координаты Y было довольно трудно. В мире логики значения наподобие 0x08
перемещали бы ткань вниз на 8 единиц измерения, 0x18
перемещало бы ткань вверх на 8 единиц, а 0x00
оставляло бы её на месте. В идеале система выглядела бы как 5-битная версия обратного хода. Выглядит вполне понятно, правда? Разница в направлении вверх и вниз заключалась бы во включении/отключении бита 4, а ноль сохранял бы текущую позицию по вертикали. По крайней мере, я этого ожидал. Однако с реальностью иметь дело гораздо сложнее. Пример в узоре B-007 представлял собой пару вертикальных линий, но координата Y никогда даже не приближается к нулевому значению. В крайнем случае можно было бы предположить, что горизонтальная линия будет представлена двумя разными координатами X и двумя координатами Y с одинаковым значением, но было совершенно иначе.
Я был так занят тем, как должны по-моему выглядеть координаты, что не смог заметить, как они ведут себя на самом деле. Я потратил месяцы на придумывание всевозможных безумных правил описания того, как машины создают горизонтальные, диагональные и вертикальные линии для всех остальных узоров. Было потрачено много часов на формулирование каждого возможного случая координат X и Y и типов линий, которые они должны отрисовывать. Оглядываясь назад, могу сказать, что пропустил несколько очевидных подсказок, которые могли бы упростить мою работу.
Однажды, когда я изучал все придуманные мной правила, я заметил нечто очень любопытное о горизонтальных линиях. Похоже было, что все они используют в качестве координаты Y 0x14
. Зачем использовать это значение для обозначения отсутствия сдвига по вертикали? Зачем использовать это значение вместо нуля? Меня озарила ещё одна мысль: что если значения меньше 0x14
выполняют сдвиг вниз, а значения выше него — сдвиг вверх? Внезапно почти все узоры обрели смысл. Так как GBE+ получал любой перехваченный им узор, передаваемый по последовательному интерфейсу, и отрисовывал его в файл BMP, я мог очень быстро оценить результаты визуально. Со старыми усложнёнными правилами только малая доля узоров выглядела правильно, а многие были ошибочными. После изменения кода в соответствии с новым открытием, почти все узоры начали рисоваться правильно. Последней задачей стало вычисление правильных длин для каждой координаты Y. В конечном итоге я пришёл к такой схеме:
0x00 Сдвиг вниз на 1.25мм
0x01 Сдвиг вниз на 1.1875мм
0x02 Сдвиг вниз на 1.125мм
0x03 Сдвиг вниз на 1.0625мм
0x04 Сдвиг вниз на 1.0мм
0x05 Сдвиг вниз на 0.9375мм
0x06 Сдвиг вниз на 0.875мм
0x07 Сдвиг вниз на 0.8125мм
0x08 Сдвиг вниз на 0.75мм
0x09 Сдвиг вниз на 0.6875мм
0x0A Сдвиг вниз на 0.625мм
0x0B Сдвиг вниз на 0.5625мм
0x0C Сдвиг вниз на 0.5мм
0x0D Сдвиг вниз на 0.4375мм
0x0E Сдвиг вниз на 0.375мм
0x0F Сдвиг вниз на 0.3125мм
0x10 Сдвиг вниз на 0.25мм
0x11 Сдвиг вниз на 0.1875мм
0x12 Сдвиг вниз на 0.125мм
0x13 Сдвиг вниз на 0.0625мм
0x14 Без изменений
0x15 Сдвиг вверх на 0.0625мм
0x16 Сдвиг вверх на 0.125мм
0x17 Сдвиг вверх на 0.1875мм
0x18 Сдвиг вверх на 0.25мм
0x19 Сдвиг вверх на 0.3125мм
0x1A Сдвиг вверх на 0.375мм
0x1B Сдвиг вверх на 0.4375мм
0x1C Сдвиг вверх на 0.5мм
0x1D Сдвиг вверх на 0.5625мм
0x1E Сдвиг вверх на 0.625мм
0x1F Сдвиг вверх на 0.6875мм
0x20 Сдвиг вверх на 0.75мм
Благодаря определению этих значений Y я раскрыл ещё одну странность координат XY. Для любой координаты X координата Y, управляющая вертикальным движением, находится в последней предыдущей отправленной координате Y, а не в следующей. Чтобы продемонстрировать это, вернёмся к узору B-007
: первая горизонтальная линия, идущая вправо, не использует значения XY из 0x01, 0x14
. Лучше читать это как 0x0E, 0x14
, где значение X обозначает движение вправо, а значение Y означает отсутствие вертикального движения. Возможно, лучше классифицировать их как значения YX, но как бы то ни было, сырые байты координат с точки зрения человека немного «рассогласованы».
Преобразовать эту информацию в пиксели было довольно легко. Каждое значение X обозначает 1 пиксель. Для значений Y 0x14
равно нулю, а каждое значение выше него просто сдвигается на 1 пиксель вверх, а каждое значение ниже сдвигается на 1 пиксель вниз. При такой схеме в GBE+ можно без малейших проблем отрисовывать самые сложные узоры: лебедей, цветы и сердечки. Даже пользовательские паттерны прекрасно отрисовывались. Определение логики координат XY вызвало у меня много головной боли. Просто скажу, что эти три машины выполняют всё совершенно тупо. Нет ничего интуитивно понятного в использовании 0x14
в качестве замены нуля. Нет ничего понятного в использовании предыдущей координаты Y вместо следующей. Возможно, кто-то скажет, что так изнутри устроены многие швейные машины, или что так обычно реализуется общение с устройствами, или что так спроектированы некоторые микроконтроллеры. На самом деле я вижу и понимаю стоящую за этим логику, только меня это не волнует. Это тупо и для меня всегда будет оставаться тупым.
Как бы то ни было, после того, как все узоры начали работать правильно, я перешёл к тестированию букв. Эта функция работала в GBE+ только частично. Странно, но в выходном файле BMP, который я использовал для отладки, отображалась только первая пара букв. Например, если попытаться вышить «ABCD», то отобразятся только «AB». После тщательного изучения данных, передаваемых из Game Boy, я осознал, что GBE+ не обрабатывал важнейшую часть формата пакетов. Когда Game Boy передаёт пакет швейной машине, его длина может составлять только 128 байт. Однако для вышивания длинной последовательности букв требуется несколько сотен координат XY (так как многие их части содержат двойные или тройные стежки). Для отправки такого количества координат XY требуется передача нескольких пакетов, а GBE+ обрабатывал только первый обнаруженный пакет. После внесения изменений GBE+ научился парсить дополнительные пакеты, благодаря чему исправилось вышивание не только букв, но и петлиц.
Примеры узоров из Raku x Raku Mishin/Sewing Machine Operation Software
Примеры более сложного шитья, несколько букв и петлиц. Очевидно, петлицы были не очень качественными и на настоящих машинах.
Соревнования по текстилю
Протестировав ROM-ы и Sewing Machine Operation Software, и Raku x Raku Mishin, я был удовлетворён тем, что GBE+ способен достоверно эмулировать Singer IZEK 1500 и Jaguar JN-100. Но это была только половина дела, ведь полной загадкой оставалась Jaguar JN-2000 и её устройство для вышивания. Учитывая то, насколько сложной может быть вышивка, я мог только представить, насколько трудно будет разбираться с EM-2000. Серьёзной проблемой, мешающей дальнейшему прогрессу, стало отсутствие у меня EM-2000. Когда я находил их на сайтах, они продавались только в комплекте с JN-2000, из-за чего цена становилась сильно больше 1000 долларов. Аукцион с разумной ценой нашёлся только после того, как я завершил исследования этих машин. Не нужно говорить, что у меня не было нужного оборудования.
Тем не менее, EM-2000 во многом походила на некоторые устройства для вышивания, которые примерно в то же время Singer выпускала для отдельных моделей Futura. Если не считать расцветки, два устройства выглядели одинаково. Я заподозрил, что устройство для вышивания Futura может быть совместимым с JN-2000. В конце концов, Singer IZEK 1500 была копипастой JN-100; возможно, эти две компании делились друг с другом и другими моделями. Когда мне доставили устройство для вышивания Futura, оно не помещалось в разъём JN-2000, потому что на нём было два куска пластмассы, мешающих соединению. Спустя час ручной обработки наждачной бумагой я удалил пластмассовые ограничители и мне удалось вставить устройство Futura в JN-2000. К сожалению, оно оказалось совершенно несовместимым. Ни одно ПО не могло распознать подключение устройства для вышивания.
Слева — EM-2000. Справа — устройство для вышивания Futura. Они похожи, как близнецы. Одинаковый размер, одна форма. К сожалению, только одно из них совместимо с JN-2000.
Не имея возможности протестировать устройство напрямую, я мог только выполнить реверс-инжиниринг ПО и протокола, который Game Boy использовал для вышивания. Первая задача заключалась в том, чтобы определить, как JN-2000 сообщает Game Boy о том, подключено ли EM-2000. До и после отправки пакета швейной машине Game Boy передаёт байты активности соединения, чтобы непрерывно проверять наличие подключения. Швейные машины должны возвращать своё текущее состояние в виде одного байта. Ответ в виде нуля позволяет нормально работать большинству функций IZEK 1500 и JN-100, но Raku x Raku Moji, Raku x Raku Cut Shuu и Mario Family жалуются при этом на отсутствие EM-2000. Ранее я случайно выяснил, что если задать бит 1 байта состояния, то ПО считает, что EM-2000 подключено. Попробовав другие случайные значения, я выяснил, что 0x06
и 0x07
позволяют ПО продолжать выполнение без ошибок. Похоже, что первое значение сообщает о подключении маленьких пялец, а второе — о подключении больших пялец. С большими пяльцами можно вышивать только некоторые узоры.
Использование верного байта состояния вместо отображения ошибки включало передачу данных. Передаваемые из Game Boy данные очень походили на другие пакеты, используемые в IZEK 1500 и JN-100. Однако формат данных координат был очевидно другим. В отличие от другой довольно запутанной системы координат, координаты вышивания оказались очень простыми для понимания. Лишь взглянув на числа, я почти сразу понял, как всё работает. Значение 0x05
перемещает точку сшивания на 5 единиц вправо для координат X или на 5 единиц вниз для координат Y. Значение 0x45
перемещает точку сшивания на 5 единиц влево для координат X и на 5 единиц вверх для координат Y. Если бит 6 установлен, то координаты X и Y движутся в одном направлении, в противном случае — в другом. Кроме того, координаты XY не перепутаны. По сравнению с IZEK 1500 и JN-100 всё стало намного проще!
Соединяя линии между этими координатами, GBE+ смог отрисовать многие из узоров. К сожалению, почти все они имели серьёзные проблемы с рендерингом, части вышивки были разбросаны хаотично. У Марио было сдвинуто лицо, у принцессы Пич его вообще не было, а Луиджи просто состоял из кучи закорючек. В каждом из случаев правильной выглядела только первая часть, а затем всё стабильно ломалось. При выполнении вышивки узоры разбиваются на несколько непрерывных сегментов. Чаще всего большая часть узора может быть вышита из одной точки в следующую, это напоминает рисование по контуру. Однако иногда невозможно сшить отдельные сегменты без полного перехода к новой позиции, не соединённой со старой. Примером этого являются глаза многих персонажей, разделённые объекты (пузырьки, окружающие дельфина), и цветные области, чётко отделённые контурами или другими цветами. По сути, JN-2000 прекращает сшивание, когда устройство для вышивания перемещается в новую позицию. GBE+ считает всё одной непрерывной линией и никогда не перемещается в новую позицию. Внутри некоторых передаваемых JN-2000 пакетов есть разделы, описывающе способ перемещения в новую область. Они начинаются с байта 0xBE
, а заканчиваются байтом 0xBD
. Данные выглядят примерно так:
0xBE НАЧАЛО
0xEB БАЙТ 1
0xFF БАЙТ 2
0xBA БАЙТ 3
0x00 БАЙТ 4
0xFF БАЙТ 5
0x00 БАЙТ 6
0x00 БАЙТ 7
0x00 БАЙТ 8
0x00 БАЙТ 9
0xBD КОНЕЦ
Сначала я подумал, что эти данные описывают какое-то 16-битное число, в котором первым идёт младший байт (Least Significant Byte, LSB). То есть первые два байта образуют шестнадцатеричное число 0xFFEB
. По той же самой логике второе 16-битное число должно иметь вид 0x00BA
. Если считать, что эти 16-битные числа являются сдвигами по X и Y, первое число может быть чем-то типа отрицательного значения X (сдвига влево), а второе — положительным значением Y (сдвигом вниз). Однако при изучении остальных данных я понял, что байтов нечётное количество. Данных достаточно на четыре 16-битных чисел и ещё одно 8-битное значение-остаток. Эта часть меня очень сбивала с толку несколько дней. Исходя из показанных выше данных, кажется, что третье 16-битное значение должно быть 0x00FF
, а четвёртое 16-битное значение — 0x0000
. Последний байт остаётся «висеть» без пары.
Когда я просматривал различные наборы данных сдвига, настал один из тех моментов, когда в голову внезапно приходит идея. Что если в показанных выше данных пятый байт просто является своего рода разделителем для следующих 16-битных сдвигов по X и Y? Это бы объяснило, почему Game Boy передаёт нечётное количество байт. У других узоров было множество сдвигов, и когда я проверил логи, то обнаружил, что после каждого сдвига по X и Y есть байт 0xFF
. В показанных выше данных последние сдвиги по X и Y равны нулю, что означает отсутствие движения. После внесения небольших изменений в код GBE+ эмулятор начал правильно парсить все координаты сдвига. Единственное, что было не так — перевёрнутые направления вверх и вниз.
0xFFEB СДВИГ ПО X №1 СДВИГ ВЛЕВО 21
0x00BA СДВИГ ПО Y №1 СДВИГ ВВЕРХ 1860x0000 СДВИГ ПО X №2 НЕТ ДВИЖЕНИЯ
0x0000 СДВИГ ПО Y №2 НЕТ ДВИЖЕНИЯ
Но некоторые узоры всё равно оставались искажёнными. После определённых сдвигов координаты шитья X и Y перемешивались, что приводило к созданию линий, идущих во множестве разных направлений. Передаваемые JN-2000 пакеты имеют длину всего 128 байт, и иногда данные сдвига приходится разбивать на два пакета. Обрабатывать такие ситуации оказалось непросто. Все три швейные машины используют байт 0xB9
, чтобы сообщить о начале пакета и 0xBB
, чтобы сообщить о конце другого. Нужно проверять, являются ли эти байты частью управления пакетами или на самом деле они часть данных сдвига.
Последней проблемой оставались начальные координаты X и Y. Все узоры вышивки на самом деле являются несколькими узорами, объединёнными в последовательность. Например, Mario Family сначала вышивает зелёные части Йоши, а затем переходит к ботинкам и шипам на спине, поток к седлу, белому животу и, наконец, к общему контуру. Принцип заключается в вышивании частей с одинаковым цветом. Программа просит пользователя выбрать новую нитку и отправлят отдельные передачи машине JN-2000. Первый пакет каждой передачи сообщает начальные позиции X и Y. Они никак не связаны с предыдущими точками шитья или координатами сдвига, потому что пользователь может передавать любую часть узора в произвольном порядке или полностью пропускать части (например, если в качестве основы используется белая ткань, то пользователь может захотеть пропустить вышивание перчаток Марио). Если используются неверные начальные координаты, то рисунок не совпадёт, как должен при отрисовке каждого сегмента.
Здесь показано, как должны работать начальные значения X и Y. Каждый сегмент вышивается по отдельности, но все они правильно выравниваются.
Начальные координаты X и Y тоже являются 16-битными LSB-значениями. Это абсолютные значения, то есть они сообщают, где точно нужно начинать вышивание в пределах пялец. Пользователи могут сами выбирать начальную точку через ПО, а Game Boy передаст соответствующие данные. Манипулируя этой функцией, мне удалось записать максимальные и минимальные значения X и Y, определив таким образом, как работают их координаты. Правая сторона задаётся как 0xFFF
, левая — как 0xFED0
. Верх задаётся как 0xFFFF
, низ — как 0xFE30
. Благодаря этим размерам GBE+ может указать правильную начальную точку каждого узора. Это, в свою очередь, наконец-то решило все проблемы выхода за границы при вышивании.
Наконец-то всё выглядит идеально!
Сшиваем всё вместе
Пока эмуляция этих швейных машин заключалась только в том, что GBE+ выводил файл изображения после завершения обработки последнего пакета, отправленного программным обеспечением. Такой подход хоть и удобен для отладки и экспериментов, совершенно не приспособлен для обычных пользователей. Хотя он, строго говоря, выполняет поставленную задачу. мне всегда казалось что эмуляция нужна для исследований, а не просто для воссоздания и наблюдений. Чтобы действительно передать все ощущения от работы с чем-то типа IZEK-1500, пользователям нужно взаимодействовать с устройством и контролировать выходные данные в реальном времени. Всё это возвращает нас к вопросу: как же эмулировать швейную машину?
В моей предыдущей статье об игрушках Cyber Drive Zoids я использовал отдельный экран для отрисовки небольшого анимированного робота, имитирующего модель, хоть и довольно приблизительно. На самом деле, источником вдохновения для создания этого отдельного экрана в Cyber Drive Zoids стала работа со швейными машинами, просто я закончил тот проект первым. Принцип заключается в том, чтобы использовать отдельный экран в роли своего рода блокнота для рисования. Курсор перемещается, и после простого нажатия одной кнопки начинают появляться вышивки и узоры. Вспомогательный интерфейс в виде меню помогает динамически изменять различные опции, например, цвет нитей, толщину нитей, скорость шитья, сохранение изображения, очистка изображения и подключение/отключение эмулируемого EM-2000.
Конечные результаты оказались довольно приятными и сильно напоминали виртуальную швейную машину. Думаю, очень важно то, что на отдельном экране демонстрируется, как швейные машины выполняют шитьё. Например, на нём показывается, как двигалось бы устройство EM-2000 в реальности при создании вышивок. Большинство из нас никогда не смогут увидеть эти устройства вживую, не говоря уже о создаваемых ими узорах. Однако теперь любой может посмотреть, из-за чего же они стали так популярны.
Хоть на этих картриджах и не настоящие игры, вы всё равно можете с ними поиграть!
Незакреплённые концы
Перед завершением статьи я бы хотел уделить время развенчанию некоторых заблуждений относительно швейных машин. Во-первых, единственная швейная машина, способная выполнять сложную вышивку — это JN-2000. Нельзя использовать IZEK-1500 или JN-100 вместе с Mario Family, например, потому что они несовместимы с EM-2000. В их платформе нет разъёма под устройство для вышивания. Зато любопытно, что у картриджей Raku x Raku Mishin и Sewing Machine Operation Software есть сообщения об ошибке, говорящие о том, что EM-2000 подключено, несмотря на то, что сделать это скорее всего невозможно (по крайней мере, без серьёзных модификаций машин). Это намекает на то, что EM-2000 уже разрабатывалась на момент выпуска JN-100; кроме того, вероятно, что IZEK хотела создать собственную модель на основании JN-2000.
Во-вторых, нужно сказать, что несмотря на предварительную демонстрацию в Game Boy узора каждой вышивки JN-2000, пиксель-арт является только приближенным изображением реальной вышивки. Часть деталей просто не помещается на экран размером 160×144. Например, на изображении принцессы Пич в Game Boy нет бровей, ресниц, оборок на платье рядом с шеей и промежутка между её перчатками и рукавами платья. Во многих случаях вышивка оказывается намного сложнее, чем показано в ПО, особенно в случае некоторых узоров из Raku x Raku Cut Shuu. Как бы то ни было, готовые результаты намного сильнее впечатляют, чем их образцы на экране Game Boy.
В-третьих, да, эти швейные машины на самом деле работали! Я очень часто встречаю такую странную реакцию, когда люди узнают об этих моделях (разве стали бы Jaguar или Singer продавать такие дорогие, но неисправные изделия?) Все три машины на самом деле довольно хороши и способны работать без Game Boy, однако в этом случае они ограничены шитьём по прямым. Они без малейших проблем справлялись со всем, о чём заявляли производители.
Заключение
Работа с этими швейными машинами оказалась тяжёлой задачей. Они были довольно большим наказанием, но в конечном итоге мне кажется, что результат стоил всего этого труда. Каждая из них добавила уникальную главу в историю видеоигр, которые, я надеюсь, мы больше никогда не потеряем. Прошло уже 20 лет с тех пор, когда JN-100 впервые познакомила мир с шитьём через Game Boy, поэтому я считаю, что годовщину этого достижения лучше всего отпраздновать при помощи эмуляции.
Меня уже и раньше удивляли экзотические периферийные игровые устройства, но должен признать — JN-100, JN-2000 и IZEK-1500 пока являются самыми впечатляющими из моих примеров. Услышав о чём-то подобном, можно подумать, что это безумие, и покачать головой. Швейная машина с управлением через Game Boy? Я вспоминаю, как MAME наконец удалось эмулировать автомат для попкорна Sonic The Hedgehog; тогда я подумал, что это был совершенно сумасшедший пример упорства в сохранении истории видеоигр. С тех пор я мечтал совершить нечто подобное — вернуть к жизни большую, неуклюжую, странную железяку, дорогую и которую трудно найти. Кажется, я наконец-то достиг своей цели.
У меня ощущение, что я только недавно начал писать эти статьи, но на самом деле прошло уже три года! Могу с гордостью сказать, что почти все дополнительные устройства, непосредственно влиявшие на геймплей и программирование ПО в коммерческих играх DMG и GBC, в той или иной степени эмулированы! Непокорённым остаётся только один примечательный аксессуар для DMG (первого Game Boy). Когда я начинал работу в 2017 году, было бесчисленное количество неизвестных, а по крайней мере семь устройств не исследовались в течение десятилетий. Надеюсь, что я внёс свой небольшой вклад в улучшение ситуации с эмуляцией Game Boy, и что эти статьи серии Edge of Emulation вдохновят людей на поиск других областей истории видеоигр, которые остались забытыми и требуют сохранения. Несмотря на всё сказанное, мой путь далёко от завершения. Похоже, мой список TODO не становится короче. В 2020 году я буду перескакивать от одного устройства к другому, и уже выбрал для себя новый крупный проект: AGS-006, или Play-Yan. Если мне повезёт, то я смогу что-нибудь рассказать через несколько ближайших месяцев.