[Перевод] KeybJr – универсальное подключение клавиатуры к PCjr

zkezqzro6zevpknzozpbrnnk-f4.jpeg


В качестве продолжения своей предыдущей статьи об IBM PC и его особенностях я решил реализовать KeybJr — небольшой открытый проект, позволяющий подключать к PCjr клавиатуру через проводное соединение или ИК-порт. Натолкнуло меня на это отсутствие в системе возможности для подключения нормальной клавиатуры за исключением редких и дорогостоящих сторонних решений.

А ведь Junior, в наши дни ставший уже чисто гиковским устройством, представляет собой не более чем раритетное украшение, который не будет работать без родной клавиатуры. Будь то оригинальная чиклетная «Freeboard» или ее последующая разновидность с более традиционной раскладкой, оба варианта оставляют желать лучшего, когда дело доходит до хлипкой работы их скрипучих резиновых колпачков. И если вы даже отыщете такую, но горестно обнаружите в ней потекшие батареи, то почему бы не подключить к PCjr клавиатуру Model M?

Подключение XT/AT-клавиатуры со 101 клавишей через ИК-интерфейс в режиме эмуляции XT:

В текущей ревизии KeybJr позволяет подключать XT, AT, PS/2 или старые USB-клавиатуры. Нажатия клавиш обрабатываются согласно ожиданиям PCjr, после чего передаются ему как через ИК-интерфейс, так и по проводному соединению. Подключается клавиатура через гнездо «K» сзади, что избавляет от необходимости ее нахождения в радиусе видимости ИК-приемника.

Тем не менее посредством ИК-интерфейса KeybJr может соединить подходящую клавиатуру с PCjr, у которого контакты гнезда повреждены — то есть, когда оригинальные и дорогие клавиатурные адаптеры не работают. Причем олдскульные пользователи могут помнить, насколько легко контактные штыри Junior сгибались и отламывались.

Чтобы вписать проект KeybJr в одни выходные, я выбрал популярную и недорогую платформу — Arduino Uno и ее клона на базе ATmega328P.

zkezqzro6zevpknzozpbrnnk-f4.jpeg

Внутренне это Arduino, но она не требует оригинальной платы и отлично функционирует в виде простой «dead-bug» схемы

Сам проект можно скачать в виде исходного кода, совместимого с Arduino IDE, либо как двоичный файл, содержащий необходимый загрузчик, код и настройки битов блокировки, который затем можно записать через специальный программатор или ICSP-разъем ATmega328P. Структурно исходный код довольно понятен. В зависимости от используемого протокола вызывается либо простой обработчик прерываний для XT-клавиатуры, либо форк библиотеки PS2KeyAdvanced для AT. PS/2 или USB-клавиатуры (в сочетании с адаптером).

После этого клавиатура начинает опрашиваться, и программа выполняет необходимый перевод скан-кода, согласно техническому руководству PCjr. Далее код стробирует ИК-светодиоды и при необходимости отправляет данные по кабелю. Затем весь цикл повторяется.

Тем не менее, поскольку при передаче в коде используется прямой доступ к портам AVR с целью реализации ускоренной техники bit-banging вместо ардуиновской digitalWrite() (клавиатура во время передачи блокируется, а значит работать должна максимально быстро), то любые отклонения цепи для портов ввода-вывода, использованные в схеме, должны быть адресованы в коде заранее.

c-ycbvkp5hbraja8bfa-97uwfts.png

Эта схема представляет собой просто голый ATmega328p с внешним тактовым генератором 16МГц. Ее можно запитать напрямую от PCjr, через USB-порт, стабилизатор 5В и т.д.

Имейте ввиду, что некоторые очень редкие и старые XT-клавиатуры, например первые ревизии IBM Model F (использовалась в 5150 или XT), после подачи питания могут потребовать «аппаратного сброса» через линию контакта DIN №3 (/RESET). В схеме это не отражено, но если такое случится — подключите эту линию к PD7 на ATmega (контакт 13 на DIP), и KeybJR при включении/перезагрузке микроконтроллера сделает все остальное.

Если же вы используете AT, PS/2 или старую USB-клавиатуру через адаптер, то Keybjr задействует библиотеку PS2KeyAdvanced, которая поддерживает внешний код. Протокол PS/2 по умолчанию двунаправленный, однако, ради простоты и удобства я управляю клавиатурой в синхронном режиме. Это значит, что во время передачи сигнала на Junior прерывания клавиатуры и сигнал clock блокируются во избежании проблем с таймингом.

После этого обработанное нажатие клавиши стирается из внутреннего буфера клавиатуры, и цикл повторяется. А сигнал нажатой клавиши, полученный с клавиатуры PS/2, через таблицу перевода преобразуется в XT-совместимый скан-код. Все дело в том, что PCjr ожидает скан-код XT, пусть даже передаваемый в виде иного сигнала или в отличающемся для некоторых нажатий клавиш формате.

-rwi2ptst65ifjfawrxpacoapuu.jpeg

Прототипирование на плате Arduino

Техническое руководство неплохо описывает, в какой форме PCjr ожидает ввод с клавиатуры. Принцип передачи через ИК-приемник и проводное соединение почти одинаков и предполагает лишь пару отличий. Каждый бит данных кодируется в двухфазном импульсе длиной 440 миллисекунд. Логическая 1 устанавливается в первой половине (220 мс) импульса и сбрасывается во второй. Логический 0 ожидает 220 мс, устанавливается на последующие 220 мс и после этого сбрасывается.

При передаче данных по кабелю вход инвертируется, то есть 5 вольт представляют логический 0. В случае же ИК-передачи двухфазная продолжительность остается такой же, то есть 220 + 220 мс. Но при этом вместо установки цифрового выхода на всю продолжительность полуфазы ИК-приемник для каждой установки ожидает стробирования квадратной волной на частоте 40КГц с коэффициентом заполнения 50% в течение 62.5 мс, после чего полуфазу завершает простой продолжительностью 157.5 мс.

addtmtm8dxepuyu94_slbuof4f0.png

Инфракрасное стробирование в течение 62.5 мс, происходящее во время передачи каждого бита данных

При использовании этого протокола передачи сигнала отправка одного нажатия или отпускания клавиши (каждое из которых представлено один байтом скан-кода) на PCjr включает один стартовый бит, 8 бит данных скан-кода, где первым идет младший байт, бит четности и одиннадцать пустых стоп-бит. Их задача просто дать NMI время на обработку всего этого в обработчике прерываний (INT 48).

Каждое валидное нажатие клавиши — это байт значения в диапазоне от 1 до 0x3A, плюс 0x54 обозначает клавишу Fn, а 0x55 фантомную клавишу, то есть команду для PCjr отбросить содержимое буфера. То же касается и отпускания клавиш, о котором сигнализирует break code, только для них устанавливается старший бит — то есть ИЛИ с 0x80.

После этого скан-коды XT нельзя непосредственно отправить PCjr без дополнительной подготовки, поскольку тогда правильно будет обработана только буквенно-цифровая часть. Дело в том, что в PCjr для обработки нажатий функциональных клавиш, навигационных, Pause/Break, Printscreen и так далее используется клавиша Fn. Даже конкретные скан-коды, согласующиеся между XT и AT, необходимо передавать на Junior нестандартным способом. Речь идет, к примеру, об обратном слэше (Alt+прямой слэш), тильде (Alt+правая скобка), точке (Shift+Delete) и так далее.

mqjvmrbvmcyhynd8avfjq9rhch0.jpeg
Вместо использования ИК-порта плата подключена к гнезду «K»

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

Основная проблема в том, что ввиду своего дизайна PCjr в случае занятости системы даже при подключении оригинальной клавиатуры будет терять сигналы нажатых клавиш, например во время обращения к диску или последовательному интерфейсу. В связи с этим KeybJr пытается конвертировать для PCjr все возможные нажатия, так что, естественно, не стоит ожидать, что будут работать клавиши SysRq, Windows, контекстного меню, веб или мультимедиа. По дизайну правые и левые Control/Alt не различаются, а F11 и F12 вообще не будут регистрироваться.

При перезагрузке системы обратной связи на клавиатуру не поступает, и она об этом событии не узнаёт. Поэтому, если вы используете не XT-клавиатуру, то состояния CapsLock и ScrollLock (светодиоды) при перезагрузке системы (а также при отключении, если вы запитываете KeybJr от внешнего источника питания, а не от PCjr) рассинхронизируются.

В качестве примера еще добавлю, если вы включите Caps Lock или Scroll Lock и перезагрузите или отключите питание KeybJr, не отключая PCjr, то светодиоды погаснут, но система будет работать так, будто они активны. Здесь есть одно исключение: состояние NumLock будет сохранено. Дело в том, что эту клавишу KeybJr обрабатывает внутренне, а не передает в виде кода системе. Почему я так сделал? Все просто, потому что PCjr клавишу NumLock не поддерживает.

Также перед подачей питания на микросхему убедитесь в надежном подключении клавиатуры. KeybJr не поддерживает подключение нагорячую, и соответствующий протокол AT/XT должен выбираться до подачи питания (для этого пин PD4 остается висеть в воздухе либо замыкается на GND с помощью перемычки и т.п.) или, хотя бы, после сброса микроконтроллера кнопкой.

Схему я успешно протестировал на старой USB-клавиатуре Microsoft, а именно Chicony PS/2, LogoStar (Copam) K-450 с переключением XT/AT, а также на оригинальной XT-клавиатуре IBM Model F. Если у вас вдруг возникнут сложности при использовании KeybJr с USB-клавиатурой, то попробуйте взять более старую, которая с большей вероятностью будет поддерживать протокол PS/2. Проверить это можно с помощью переходника USB-PS/2 на компьютере, оснащенным портом PS/2.

На этом, дорогие друзья, все!

oug5kh6sjydt9llengsiebnp40w.png

© Habrahabr.ru