So, with all the code written, and a pixel-perfect QR code on the screen, the question was once again: will it scan?
Disappointment. The ZXing Android app wouldn't recognize the code, even though it had little problems with its twin on the flat TFT screen of my PC.
Since the pixels were, as far as I could tell, identical, I figured this must be due to image quality. The code was displayed on an old fish-bowl style CRT monitor, which means it's bulging a little. Perhaps this was throwing off alignment of the reader. Another hypothesis was blooming: white pixels tend to “glow” around the edges, possibly bleeding into black pixels and making them be registered as white by the reader.
I tried to remedy both of these by doing some postprocessing. I started by taking a photo of the screen using my Canon PowerShot S90 digital camera, which is a tad better than the camera in my Nexus 5 phone. Then I opened that in Gimp, sharpened it, and applied the Lens Distortion filter to make a mostly straight-looking copy.
Then I tried reading from this image using Zbar, a command line barcode reader. It wouldn't recognize it. I also tried libdecodeqr following this AskUbuntu question, but no dice. Time to hack up my own.
Based on previous success with the app, I grabbed the ZXing source code from GitHub and wrote a Java program to load the PNG file and feed it to the library. The idea was that this would let me debug things and figure out why it wasn't recognizing the QR code.
The first problem was that ZXing was throwing a NotFoundException without a stack trace. It turns out that the library is optimized for mobile, memory-constrained devices; there is only one instance of the exception that gets reused every time, and stack traces are suppressed. This was easily fixed by hacking up the library code. Now at least I got an answer: it was failing to detect the alignment patterns, the three big squares on the corners.
Diving into the code, I added some print statements to output the location of potential alignment patterns detected in the image. It found four: the three correct ones, and a spurious one in the bottom right corner. This candidate was chosen as the correct one for reasons that eluded me, but I worked around it by removing any candidate found in the bottom right quadrant of the image. Remember, I wasn't trying to build a general-purpose QR code reader; I just wanted to see if this particular code could be scanned before I put all my eggs into its basket.
With the correct alignment patterns, the library got a lot further: it correctly read the version and format info, and subsequently threw a ChecksumException. I printed the data bytes that it had read, expecting mostly ff bytes with the occasional error. Instead, I got this sort of garbage:
99 99 00 66 85 00 00 00 60 00 7f fd 00 00 9d 1e 40 ff 1b 00 49 00 02 ff ff 00 00 02 60 40 ff 00 f7 ff 00 4f 00 00 00 ff 99 00 f6 00 00 00 01 00 00 9a 00 00 00 00 9d 00 ff 37 ff 00 ff ff 00 ff 00 ff 00 ff ff 00 ff 40 ff 40 ff ff 00 ff ..
Clearly, no amount of error correction could have fixed that mess. I figured that, in order to make this thing robust and reliable, I would have to resort to larger pixels: representing one module in the QR code as 2×2 pixels on the screen of the Beeb. Doing the math, I worked out that I could use at most a Version 24 QR code, able to contain slightly over 1 kB of data. Not as much as the 3 kB of the Version 40, but still good enough.
Unfortunately, I had been writing much of my code under the assumption that the version would not need to be changed, so there were hard-coded numbers all over the place. I turned back to the BBC Micro and started replacing them by variables. First, with the correct values for Version 40 so I could verify that the output didn't change; then I would replace them by the appropriate values for a Version 24 code, and change the pixel-plotting routine to output 2×2 pixels instead. I was halfway through this process when disaster struck.
When saving the program to tape as a matter of routine, the computer unexpectedly printed:
RECORD then RETURN
“Index”? Excuse me? I rewound the tape, wanting to try again, but found that the machine was no longer responding to my keystrokes. Somewhat nervous, I pressed the BREAK key, essentially rebooting the OS, and typed OLD to recover the program from its original memory location. Phew, that worked, it was still intact. I tried saving again, but this time, the counter didn't even start running. I really didn't want to hard reset the machine, because I assumed that the failed save would have corrupted the tape, so the computer's RAM was the only place where the QR program still lived.
A few more tries, a few more reboots, nothing helped. Until, suddenly during a SAVE command, the screen got garbled and seemingly random pixels scrolled across the screen. I pressed BREAK again, expecting to end up at the BASIC prompt again, but instead was dumped into the ViewSheet spreadsheet program. I had no idea that this machine even had that ROM chip installed. The fact that I booted into it seemed like a severe case of memory corruption. I guessed, correctly, that *BASIC would get me back to BASIC mode, but by now OLD didn't work anymore, and my program was definitively gone from the computer's memory.
Now what? Let's cold-boot the machine and see what can be recovered from tape. But it seemed that the poor old thing was too far gone for that… instead of booting, it gave a continuous tone from its speaker, didn't show anything on the screen, and didn't respond to the BREAK key. I tried powercycling it literally hundreds of times, each time getting a slightly different tone and sometimes getting the keyboard LEDs to light up, but I couldn't get the machine to boot anymore. It seemed that my trusty old pal had finally given up the ghost.
I had hoped to make the QR code program send itself across to the PC as a maiden voyage. I'm quite confident that (perhaps with even larger pixels) I could have made it work. Then I could post a YouTube video of a data transfer in progress, to help explain to my family what I've been up to in the past few weeks. I could publish the code on GitHub, annotate it, explain it in detail on this blog. Maybe it would even be useful to someone, although I didn't expect it to. I don't think any of that is going to happen anymore.
But of course, this QR code program was just a means to an end. The point of this project was to transfer all the old programs I wrote as a kid. Those programs are still there, sitting on a stack of 5 1/4" floppy disks on my desk, so close and yet so far away. If the machine would have worked again, I would have typed a simpler program, too small to need saving, to try and transfer them via sound signals. That, too, isn't going to happen anymore. Even if I could fix the computer itself, the disk drive also seems to be broken since the machine won't even boot when it's plugged in.
Fortunately, there is another way: a controller board like the KryoFlux can be used in conjunction with a PC style 5 1/4" drive to rescue data off of virtually any type of disk. I just ordered a KryoFlux board, and placed a bid on eBay on a compatible floppy drive. Fortunately, working drives for PCs seem to grow on trees still. The game is not over.
But for my old BBC Microcomputer, it is. The very device that launched my career as a software engineer will never run again. When I'm done mourning it, I'll probably take it to an electronics recycling facility. May it rest in peace.