Analyzing “Smart” Ink Cartridges
It’s late at night, and you’re racing against the clock to print that last-minute document for tomorrow’s big presentation. You enter the print command, but your printer refuses to do anything besides blinking its red LED. Many people seem to share my frustrating experience, so much so that malfunctioning printers have become an Internet meme.
My printer would force me to replace individual cartridges when they were empty, although I probably didn’t even need that color for what I wanted to print. And even if I did, why can the printer just randomly decide to stop working?
After spending a fortune on (original) ink cartridges and wondering how they can be (allegedly) empty so fast, I wondered: “How does the printer know?”. I imagine it would be difficult to measure the actual ink content, so it must be based on the resulting print quality or some sort of counter with a hard-coded threshold. Moreover, this information must be stored on the cartridge itself somehow, because the printer seems to remember the ink levels of individual cartridges.
This led me down the rabbit hole of analyzing my “smart” ink cartridges which contain active electronics that talk to the printer. Each cartridge contains a little PCB, which contains a single chip, presumably a microcontroller, an LED and two passives.
On the bottom side of the PCB (which normally faces outwards on the cartridge), there are four exposed pads. Looking down into an empty cartridge slot, you can see that these pads make contact to a 4-pin connector within the printer.
To analyze what that chip is doing, I needed to somehow sniff the traffic between the printer and the cartridges. To do this, I soldered wires to the exposed pads and routed them to the top of the cartridge, making the signals accessible when the cartridge is inserted.
Electrically, the four pins form a simple, serial bus shared by all cartridges. Two pins are for power, one is a clock signal and the other one seems to be a bidirectional data signal. I analyzed the signals using a logic analyzer.
The clock seems to be free-running at around 100 kHz. Each 100 ms, the printer sends requests to each of its five cartridges, with 1 ms in between each cartridge request. When the following measurement was taken, no cartridges were inserted.
Inserting the cartridges back in and zooming in into the signals, we can start to analyze the actual message format.
The printer seems to use the following command to poll the status of the cartridges:
0110 1111 0111 <ink_id>
where <ink_id>
is one of 1100
,
1110
, 0010
, 1001
or
0110
for yellow, PGBK, cyan, magenta and black,
respectively.
The cartridges seem to respond with a packet consisting of their
<ink_id>
followed by an unidentified nibble. This
may be the ink level, but I didn’t see any correlation between this
value and whether or not the cartridge was full.
Also, exactly 20 ms after the start of each polling “burst” from the printer, there is some more activity on the bus. It seems like the printer sends another command to the cartridges,
0110 1111 1110 <ink_id>
where the cartridges respond with their <ink_id>
.
Strangely, I only observed this for yellow, PGBK and BK. For cyan and
magenta, I saw a different request,
0110 1111 1001 <ink_id> 0011 0010
which remained unanswered by the cartridge.
While I did not manage to fully decode the data format, I am sure that with some more investigation and some more cartridges to try with, the protocol could be reverse-engineered. Moreover, a dynamic analyis approach might be worth a try to find other commands or functionality. In a test setup, a microcontroller could iterate through a set of possible commands or responses (e.g., 12 bit wide) and send them to the device under test (cartridge or printer), as well as record its response.