Programming with printers: Don't.
I worked on a project to build a printer driver for the 3DS. I now have a violent hatred of printers.
25th August 2023
At the beginning of this month, I thought it would be a fun project to create a network printing driver for the Nintendo 3DS. Suffice to say, I experienced significantly less enjoyment than was expected.
As you might already know, the 3DS is a handheld video game console launched in 2011 - a successor to the DS line of handhelds, with the gimmick of 3D visuals without glasses (which works if you love migraines). More specifically to this project however, it has robust wireless internet connection capabilities, and a bustling homebrew hobbyist software development scene - with libraries and tools that makes writing code for the platform a seemingly straight-forward enterprise.
So how do you enter the world of network printing I hear you ask? Well, let me introduce you to the Internet Printing Protocol (IPP). Knowing the URI of a network printer (the exact path for some reason depending on the printer model), you can send a HTTP request to complete print-related operations. A typical set of operations for a print job involves:
- Requesting a list of the file formats provided by the printer
- Submitting a file as a print job in one of those formats, with the appropriate IPP header
- Receiving status back from the printer to check whether the operation was successful
Assembling an IPP request is relatively simple, it’s just that the supported file formats tend to vary drastically depending on printer, and that the IPP response will usually report that a print job was successful purely based on the IPP header, without examining whether the passed file is valid.
For my trusty, if cheap, HP LaserJet specifically, all the printer seemed to do was make a clunk sound when a request was submitted, where the IPP response returned to the system would state that the print job was successfully submitted. And it was difficult enough to even get to that stage - it only supported an obscure pseudo-PDF standard created by HP called PCLm, used to specify very specific types of PDF that only contain raster graphics. Every single PDF I tried: clunk. Implementing a custom raster graphics text generator using a bitmap font (this took forever): clunk.
But fear ye not, there was another protocol for me to massacre! Just bombard Port 9100 with the plain text you wish to print over TCP. This did not work either.
This whole project was made all the more difficult by the challenges that lie in debugging software on the 3DS. The 3DS firmware I was using included a useful GDB server built-in: I wanted to see what the printer was returning back to the system, so all I had to do was set breakpoints over the terminal on my PC, query the memory addresses where the data was stored, convert this to decimal, calculate the end address for this data using a calculator, convert this back to hexadecimal, and dump the contents of this address range. This was a massive chore, especially considering that the debugger would stop and the 3DS would have to be restarted if I made any typo over the terminal.
The lessons from this? I could argue that this is a case-study in how consistent open-source standards and robust status-reporting mechanisms always tend provide a better experience for developers and users alike, but I am too angry, so all I will conclude is that printers continue to be awful, and I cannot rely on a 2011 handheld video game console to print out all my university essays.
The 3DS printing project code is on GitHub.