Apple ADB Traffic Sniffing
I’m continuing work on the USB to ADB input adapter for vintage Macintosh and Apple IIgs computers, and I now have an ADB traffic sniffer that’s more-or-less working. It doesn’t (yet) send any ADB traffic, but it displays ADB traffic from the host computer and other attached devices. This will help me confirm that my ADB decoding is working correctly, and that I actually understand what the heck is happening on the ADB bus, before I start trying to inject anything onto the bus.
The image above shows ADB traffic from a Macintosh SE, at the moment when I began to move the mouse. At first the Mac was repeatedly polling the keyboard (device address 2) by asking it to “talk” register 0, which is the primary data register for an ADB device. The keyboard didn’t have any keypresses to report, so it didn’t reply. At the end of one of these transactions, the mouse pulled the ADB data line low in order to request service for itself – this is the SRQ flag shown in the traffic log. The Mac responded by polling the other ADB devices it knew about, which in this case was only device address 3, the mouse. The mouse responded to the Talk 0 command with some position update bytes. After each Talk 0 command addressed to the mouse, the host sent another Talk 0 to the keyboard, which still didn’t reply. But the mouse again asserted SRQ to request service. Eventually (not shown here), the host stopped polling the keyboard and began repeatedly polling just the mouse. If the keyboard later had new keypress data to report, it would need to assert SRQ.
Here’s a log of the same Mac’s ADB traffic, from a cold boot:
ADB Reset Addr: 0, Talk 3 Addr: 1, Talk 3 Addr: 2, Talk 3 63 08 Addr: 3, Talk 3 68 01 Addr: 4, Talk 3 Addr: 5, Talk 3 Addr: 6, Talk 3 Addr: 7, Talk 3 Addr: 8, Talk 3 Addr: 9, Talk 3 Addr: A, Talk 3 Addr: B, Talk 3 Addr: C, Talk 3 SRQ Addr: D, Talk 3 SRQ Addr: E, Talk 3 SRQ Addr: F, Talk 3 SRQ Addr: 2, Listen 3 0F FE Addr: 2, Talk 3 SRQ Addr: F, Listen 3 02 FE Addr: F, Talk 3 SRQ Addr: 3, Listen 3 SRQ Addr: 3, Talk 3 SRQ Addr: F, Listen 3 SRQ Addr: F, Talk 3 SRQ Addr: 2, Listen 3 0F FE Addr: 2, Talk 3 SRQ Addr: F, Listen 3 02 FE Addr: F, Talk 3 SRQ Addr: 3, Listen 3 SRQ Addr: 3, Talk 3 SRQ Addr: F, Listen 3 SRQ Addr: F, Talk 3 SRQ Addr: 2, Listen 3 0F FE Addr: 2, Talk 3 SRQ
The Mac begins by asking every possible device address to report the contents of register 3, the configuration register. Only addresses 2 and 3 (keyboard and mouse) replied. I’m confused by the reply data bytes shown here – I think the decoding of replies must be buggy, because the lower nibble of the upper byte (3 and 8, respectively) should have matched the device address (2 and 3). Eventually the host sends device 2 a command of Listen 3 0F FE, which tells the keyboard to modify the contents of its configuration register. The effect is to reassign the keyboard from address 2 to address F. Later, it assigns it back to 2, then back to F, then back to 2, over and over. That sure looks odd. The temporary re-assignment of device addresses at startup is part of ADB’s system for discovering address conflicts, but I don’t see why it would need to do so many reassignments. Meanwhile, somebody else (the mouse?) keeps asserting SRQ, which interrupts many of the other commands.
Here’s a log of the startup ADB traffic on an Apple IIgs, ROM 01, with only a keyboard attached:
ADB Reset Addr: 2, Flush Addr: 2, Talk 2 9F 00 Addr: 2, Talk 0 Addr: 2, Talk 0 Addr: 2, Talk 0 39 FF Addr: 2, Talk 0 Addr: 2, Talk 0 Addr: 2, Talk 0 Addr: 2, Talk 0 Addr: 2, Talk 0 Addr: 2, Talk 0 Addr: 2, Talk 0 Addr: 2, Talk 0 Addr: 2, Talk 0 Addr: 2, Talk 0 Addr: 2, Talk 0 Addr: 2, Talk 0 Addr: 2, Talk 0 Addr: 2, Talk 0 Addr: 2, Talk 0 Addr: 2, Talk 0 Addr: 2, Talk 0 Addr: 3, Listen 3 03 00 Addr: 2, Talk 0 Addr: 3, Listen 3 03 02 Addr: 2, Talk 0 Addr: 2, Flush Addr: 3, Listen 3 03 00 Addr: 2, Talk 0 Addr: 2, Talk 0 Addr: 2, Talk 0 39 FF Addr: 2, Talk 0 Addr: 2, Talk 0
Notice that the IIgs doesn’t appear to do any device address reassignment, so maybe it’s not able to handle ADB address conflicts the way the Mac does. I haven’t tried connecting two keyboards simultaneously to this IIgs, but given what I see in this log, I suspect they would both try to use ADB address 2, and neither one would work. Other interesting things here:
- The host tells the keyboard to Talk 2. This seems to be a special register in the Apple standard and extended keyboards, used to poll the current state of the modifier keys like shift and control. But the Mac doesn’t appear to use this.
- The keyboard twice responded to Talk 0 commands, with the data bytes 39 FF, even though I didn’t press any keys.
- The host repeatedly sends Listen 3 commands to the non-existent mouse, telling it to use device handler ID 0, and then handler ID 2. After reading the ADB docs, I’m unclear what this means.
PIC32 USB Starter Kit II
I’m not exactly loving the PIC32 USB Starter Kit yet. Somehow I missed the fact that this board has no external headers, except for a single super high density connector on the bottom with 132 pins. In practice, the only way to use that connector is to purchase the I/O Expansion Board, which costs more than the kit itself. Otherwise if you want to connect even a single GPIO to the outside world, you’re stuck. There isn’t even any connector for an external power source, other than USB. I ended up having to solder pins to a couple of board test points, and the unpopulated footprint for a 32 kHz crystal. This gave me exactly two GPIOs, 5V, 3.3V, and GND.
Thus far, the Microchip software experience has been not been good. The USB Starter Kit shipped with a CD containing the IDE and example projects, but they didn’t work. I got concerned when the installation instructions only mentioned Windows XP and Vista, and I couldn’t get the IDE to even recognize my board under Windows 7. It turned out that the CD contained MPLAB 8, which was discontinued several years ago, so I deleted everything and downloaded the newest MPLAB X from the Microchip web site, and separately downloaded the XC32 compiler. But all the USB Starter Kit example projects are MPLAB 8 projects, and when I converted them to MPLAB X projects, they didn’t work. After half a day of monkeying around, I finally resolved the issues, but it was a real mess.
For anyone else who may struggle with this, the main problem was that 99.9% of PIC example projects (including Microchip’s own USB Starter Kit examples) use a peripheral library called plib, which is no longer included with the MPLAB X IDE or XC32 compiler. Microchip has declared plib as “end of life”, and is trying to get everyone to use a new framework called Harmony instead, but the developer community seems to have roundly rejected Harmony as being too bloaty and high-level. To use any plib-based examples, you need to download plib separately from the IDE and the compiler, and install it. It makes sense now, but is definitely not a user-friendly process for a PIC newbie. Fortunately I think the environment is finally set up properly, so I can focus on ADB instead of struggling with the tools.
Read 16 comments and join the conversation16 Comments so far
Leave a reply. For customer support issues, please use the Customer Support link instead of writing comments.
> I’m confused by the reply data bytes shown here – I think the decoding of replies must be buggy, because the lower nibble of the upper byte (3 and 8, respectively) should have matched the device address (2 and 3).
It looks like the decoding is correct, and this is normal. The initial values stored in the config register for the device address don’t match the device address, but are randomly generated at run-time. Otherwise two keyboards that start at address 2 would reply with the exact same bit sequence at the same time, so no bus conflict would be detected, and the host wouldn’t realize there are actually two keyboards present.
There’s something I don’t understand about this SRQ service request mechanism – it seems there’s a strong possibility to deadlock the ADB bus if there are three or more devices. Whenever the host sends an ADB command, after the command byte but before any data payload bytes, any other device that wasn’t addressed by the command may interrupt by asserting SRQ (pulling the bus low, and effectively cancelling the transaction in progress). The host is then supposed to poll the other devices until it finds the one that wants service.
But what happens if devices 1 and 2 both want service, while device 3 is being addressed? They will both assert SRQ, interrupting communication with device 3, and triggering the host to poll other devices. When the host polls device 1, device 2 will again interrupt with SRQ, preventing device 1’s data from being sent. If the host polls device 2, device 1 will interrupt with SRQ. Neither device can ever transmit its data. I must be missing something here.
ADB is bizarre. I remember trying to figure out some of it back in high school, when I was trying to have two keyboards attached to my GS at the same time (with one of them remapped to a different address so I could use it for a macro system to rapidly send text for some text-based BBS games I was playing at the time).
I don’t remember much of what I learned at the time, but I remember that the documentation glossed over most of the details and there was a huge amount of stuff that wasn’t documented and
On a ROM 3 Apple IIGS you can definitely have two keyboards connected, and they work, but you get somewhat odd results if you type on both simulaneously. IIRC, the modifier keys in particular tended to get confused.
@Steve
>possibility to deadlock the ADB bus
perhaps devices wait a mandatory time slot before asserting SRQ, hard to tell because you didnt include timestamps in the dump log
ps: I warned you about microchip under previous post, but my comment got deleted/filtered? 🙁
Tim, that sounds about right. If both keyboards have the same address, the one with keypress data to report will respond to Talk requests, and the other will remain silent, but modifier key state will get confused.
rasz_pl, I didn’t intentionally filter your last comment – I checked the logs but don’t see it. Sorry!
I did observe some ADB traffic a while ago but only with a keyboard, and I never observed SRQ in action. According to the “Space Aliens Ate My Mouse” technical note (HW01), the SRQ is supposed to be asserted “after the data portion of the command” but that doesn’t seem to match what you’re seeing. Either way, it does look like the intention is that a command is supposed to still complete even if SRQ is asserted (at least if it’s talk 0), if the device to which it is sent actually has data to send. This would make sense as then the host could just poll each device in turn, getting data or not from each one, until the SRQ goes away. This is the process the TN describes.
If SRQ does come after the command byte, then the only way that could interrupt a talk 0 transaction that would otherwise have gone through is if the device to which it is addressed refuses to answer based on seeing the SRQ which I don’t think is what’s supposed to happen. My understanding is that, while SRQ is being asserted, Talk 0 should still go through to each device and each device should respond if it has data or stay silent if it does not. If a device sends data the host will re-poll it until it stops responding, then move to the next device. Are you sure talk 0 transactions are actually being interrupted? If it polls the keyboard but the keyboard has no data, and SRQ is asserted at the end of that command, then the keyboard should still stay silent and the next transmission on the line should be the host polling a device to look for the one asserting SRQ.
On the many address reassignments, I’ve seen reference to this and it’s apparently to ensure that two devices with the same default address will separate, in case they have poor randomness and happen to respond with the same random address many times in a row (it’s only 4 bits, after all)
Charles, I think you’re right about SRQ not being supposed to interrupt/cancel the transaction. I need to get out the oscilloscope to be sure, because I’m not sure I trust what my sniffer program is telling me. My hunch is that SRQ is asserted after the command byte and before the data bytes, contradicting that “Space Aliens” tech note, but that the transaction should still run to completion. This would avoid the deadlock problem I described. So maybe my sniffer program is just buggy? I never found any timing diagrams that show what happens on the bus *after* SRQ is asserted, so my understanding is incomplete.
It may be a little more expensive (~$12 through Arrow for my current preferred), and maybe even overkill, but I’ve had very good luck with toolchains for the TI ARM microcontrollers. My current toy is the TM4C129x series, a Cortex-M4F, but I’ve played with the Stellaris controllers, too, for a past job. Getting a GCC toolchain with OpenOCD is pretty trivial (can find open source toolchain projects on github).
The PIC32 is working OK for now, but if I could go back in time I might have made a different choice of microcontroller. The thing I like about the PIC32 is that it’s cheap, supports USB Host *with hubs*, and is well-documented. And by “well-documented” I don’t mean that it has a datasheet, I mean there are tons of 1st and 3rd party examples, app notes, and tutorials. That’s something that can’t be said for all the various ARM variants, which may have great hardware, but have kind of split the hobby community mindshare between them so that there’s not a ton of good info on any of them really. At least not compared to PIC, or Atmel AVR. The thing I dislike about the PIC32 is that the tools are a pain in the ass.
Another commenter suggested the SAMD21, which is probably my leading alternative if I do decide to switch. It’s an Atmel part, so I think development can be done in Atmel Studio, which I’m already familiar with. It’s not quite as cheap as the PIC32, but it’s not going to break the bank. Sparkfun sells an Arduino clone based on the SAMD21, and reportedly the Arduino IDE and libraries work with it, so that would provide a good source of example code. It supports USB Host, though I’m not certain about hubs.
The most intriguing thing about the SAMD21 is some kind of reconfigurable serial module called SERCOM, which can be turned into a UART, I2C, or SPI. I’m wondering if it could be configured to handle ADB directly in hardware. That would be awesome.
Hi Steve,
is your ADB sniffer available for sale? I’d like to see the traffic between a Mac Classic II and the LaCie FM Radio to understand the protocol.
Thank you for your answer,
Antoine
Sorry, that was just something I did during ADB/USB Wombat development to help me understand what was happening.
Ah too bad, could I ask you to build one and sell it to me, please, or no chance?
Antoine have you seen “Tashtari’s ADB Tools (also a plea for rare devices!)” thread on 68kmla? he made available his PIC based adb-protocol-analyzer on github
Thanks for the link. I may follow their results as I would like Steve’s product to analyze the protocol of the LaCie FM Radio device.
I think that Lacie radio is exactly what Tashtari did first.
Thanks to your pointers, and thanks to the help of Tashtari, the Apple IIgs can now listen to the FM stations. More info @ https://github.com/antoinevignau/source/tree/main/fmradio