More HID Hijinks
HID, Human Interface Device. Previous HID hijinks include PS2 to Mac Keyboard and mouse for both pre-ADB (used on Mac 128k through Mac Plus), and ADB. This is the other direction. Use ADB keyboard and mouse on modern USB capable computers. And a pre-ADB keyboard version as well!
This is a "shield" board for Digispark devices. Digisparks are basically an ATtiny85 8bit processor on a board with a USB connector, and bit-bangs USB. This project implements ADB host support on the attiny85, and provides a composite USB device consisting of both keyboard and mouse to the USB host.
For simplicity, I used the Arduino IDE for development, along with the digispark support. I started with the digispark keyboard library but it's kind of awful. The biggest problem was the lack of control over the key buffer sent from the device to the host. Only one key down at a time, limited meta key support, and when a key is released, all keys are up. Also, no support for composite keyboard/mouse devices. I ended up needing to do some modifications to the library and generate my own descriptor.
The ADB host has a 470ohm pullup on the signalling line. Initially, I was hoping to get away with using the attiny's internal pullups, but after some experimentation, that ended up causing the pullup line to come back up too slowly, causing timing issues on the bus. Ultimately, I ended up installing a 470ohm resistor on the shield board.
Pre-ADB also has a pullup, although the internal pullup resistor on the attiny was just fine for that, so the pre-adb shield has no external resistor.
As you can see in the picture, the first pass at the shield board put the adb connector on top, which seemed logical at the time. After getting the board, I realized there's an awful lot of space wasted between the two boards, so in the second revision I flipped the connector to the other side of the board to make it more compact. The connector is still taller than the headers joining the board, so I needed some extra long male headers, but it does end up being a pretty compact package. In the second revision I also added pads for a surface mount resistor.
The host ADB implementation allows both a keyboard and mouse on the ADB bus, and recognizes SRQ signals to know which one wants to talk. Initially, it just polled both devices, which worked, but SRQ support is much more efficient and lower latency. Without SRQ support, if there's only one device connected, each polling of the device would have to wait for a timeout. Timeouts can't be cached and just ignore that device, since in ADB if a device has nothing to send, it just won't send anything.
The implementation does not renumber the devices though, so it won't support more than one keyboard or more than one mouse. At most one keyboard, and/or one mouse is all it does.
The keyboard LEDs all work, which are all controlled by the USB host. So when capslock is pressed, the keydown event is sent to the USB host, which then sends the device a command to turn on the LED, which is then translated into an ADB Listen request to tell the keyboard to turn on the capslock LED. So that ends up being a fairly good test to ensure everything is in sync.
The major difference between older keyboard protocols such as ADB and USB is ADB signals every key up event and every key down event. USB on the other hand, just reports what keys are currently down. If the 'a' and 'b' keys are held down, the USB keyboard will tell the host 'a' and 'b' are down. Then if 'a' is released, the keyboard will tell the host that 'b' is down (still). It is inferred that 'a' was released because it is no longer in the list. So a USB adapter needs to keep state and remove the appropriate keys from the list whenever a key is released.
Another difference is in USB keyboards, the capslock key state is controlled by the USB host, not the keyboard. USB capslock keys don't typically latch down like they used to, because the latch means the state is tracked on the keyboard. USB keyboards expect that when you press the capslock key, you get both a keydown and a key up event (well, not actually key up, but it is released). The host then keeps track of whether the capslock is "active" or not. ADB keyboards have the latching capslock key, which sends a keydown event when it is down/active, and a keyup event when it is released/inactive. For the adapter, I ended up translating every state change of the capslock key into a key down/key up operation for the USB side, to make the host happy.
Update: Here's the revised pre-adb keyboard adapter next to the ADB one. The rj11 connector still needs longer than normal header pins.
A note about digispark clones: digispark clones are cheap and plentiful on ebay, but I've found they don't all follow the same layout. I got a couple clone boards where the spacing between the 6pin and 3pin connectors was not the same, and digispark shields wouldn't fit properly.
Also, the clones often come with male pins for the connectors, where the digistump digispark comes with female headers.
Updated October 12 2016