Decoding Capsure USB
After my initial tinkering and playing with the RM200 Capsure colorimeter I wanted to be able to experiment with firmware tweaks, also having to use the X-Rite Windows app, using fiddler to hack the packets connecting to their servers each time I switched firmwares wasn't ideal, so it was time to try to decode the interface to see if it's possible to talk to the handset directly without the app and server connection...
So fire up Wireshark, run the sync app, connect the device, and wade through the data, and we can see the packets going backwards and forwards. I run a full re-sync and firmware update and have a chunky log to decode later.
Here we can see URB_BULK in and out, here is a two byte command 0x78 0x12 going out, on endpoint 0x02. On the return we then have:
A chunk of info coming back. I try writing the same using python but figure out that there's a step before where it sends an URB_CONTROL message:
So once this is figured out (it takes the length of the message) I can replicate these simple commands in python and start working through one by one adding them into a python utility. Here sending the urb_control 151, the length and then the data packet to endpoint 0x81:
and then working through the ones I can figure out start adding little utility functions:
Next... I figure out there's an image uploaded at the start of a sync... it uploads the familiar circular arrows sync image. That seems like a low risk way to practice uploading a chunk of content (i.e. more than 2-4 bytes) since it'll need spreading over multiple packets and takes a header and follow up messages....
So what to send....
Yeah ok. it's not actually running Doom.. but yes, I can successfully send an image to the handset. Hmm now if I can just keep sending images I can.....
😁 Rollin.
Ok. enough sillyness.
I start working through the firmware upload process so I can flip between the firmwares directly, after much stress, and setbacks, and a few what look like "brickings" of the handset, I finally have my experimental firmware upload working. I don't understand what all of the packets mean yet, so just cargo-cult that part of the script, the real uploader seems to pause on USB interrupts during the upload but I can't figure out how to get those configured so for now rely of a few random sleeps.
During the process it's clear the "chip id" is the information used to differentiate models, but in use, the id has to have a checksum byte which isn't always output, so I add a function to calculate that, allowing arbitrary chipids to be used for experimentation.
Now. During firmware upload, it flips into a bootloader, so I find I can just trigger that separately and get into and use the bootloader menu.
Clicking "menu" and we see some interesting/fun options!
Unfortunately "Top Secret" doesn't do anything interesting and is a lot less exciting than it sounds. But here we can view the NAND flash memory, and in there see the serial number and chip id.
Several functions e.g. "Backup/restore" take a password.... turns out the "1001" in the bootloader is that. 😂
Now that's *interesting* and I'll dig into that in the next update.
The current scripts and commands can be seen in the python on codeberg. Obviously, caveat emptor using that, but it seems that if something goes wrong with a firmware update, then often just powering off and getting into the bootloader is enough to get things going again. (more on this in the flash update post which will follow)
The next project was manipulating the onboard flash which needs another write-up. Spoiler there were more brickings, one of which appeared fatal, and dismantling this unit seems to have broken something 😭.
I'll add the next writeup in the next few days.
Teaser.... A RM200 cosmetic showing a QC colour picker: