Ask the Screen
The last couple of days I spent at the bench with a Uniden SDS150, chasing what should have been a five-minute question: what colors does this radio draw its screen in? I already knew where every screen area sits, that’s the screen map, and the serial protocol will stream you the text of the display all day long, that’s covered in the protocol notes. Text plus geometry plus color is a faithful redraw of the scanner’s screen anywhere you want one. The protocol hands you two of the three. The third took two days, and this post is the story of getting it. The full tables live in colors.md.
The short version: the colors are not in the protocol at all, and getting them anyway meant treating the scanner’s own screen as the interface of record. That trick, reading the answer off the glass because the API refuses to say, is older than the radio, and it works exactly as well as it ever did.
The protocol answers everything except the question
I read every field the remote command protocol exposes, looking for a color. There is exactly one color-adjacent thing in the whole thing: a backlight setting left over from the BCD436HP era, vestigial on this model, which reads OFF and always will. Everything else, nothing.
The colors live on the radio, reachable only through its menus, under Display Options and then Customize. Every screen area gets its own little menu with a text color and a back color, and the picker screen shows the current value as a name plus RGB = xxxxxxh. Which means the colors are readable after all, if you’re willing to be a little shameless about it: drive the menus with simulated key presses and read each picker off the screen. All 315 areas across the seven screen layouts takes about three minutes forty-five of key presses. The tool does it one layout at a time in about thirty seconds.
The spec is testimony; the radio is evidence
Whether the radio draws colors at all is a global setting, and unlike the colors themselves it is readable over serial: the COLOR_MODE field of the GST reply. The published spec labels that field “Waterfall display only.” That’s wrong. It tracks the global display mode with the waterfall never opened, and I verified it by selecting each of the three modes in turn and reading GST in between. Anything rendering this screen has to read COLOR_MODE first, because in two of the three modes every color below is stored but ignored, and the honest rendering is plain white on black or black on white.
I don’t point out the mislabel to dunk on whoever wrote the spec. I point it out because that one bad label would have hidden the single color fact the protocol does expose. Specs are testimony. The device is evidence. When they disagree, believe the device.
147 colors that are almost CSS
The picker offers 147 colors, alphabetical from Aliceblue to Yellowgreen, and the list wraps: step past Yellowgreen and you’re back at Aliceblue, so nothing is ever more than 73 clicks away. All 147 values are distinct, so a name maps cleanly to a color and back. And there is nowhere to type a hex value. The picker is the only way in, so those 147 are the whole vocabulary.
An earlier version of my notes said the palette “maps straight onto web colors.” I wrote that, and it’s wrong in two directions. The names read like CSS named colors, but the values drift by as much as seven per channel: the scanner’s Steelblue is #4280AD against the web’s #4682B4, its Darksalmon is #E79473 against #E9967A, and even Gold and Orangered miss by one. The names aren’t all CSS either. Seven of them are not CSS names at all, eight CSS names are missing, including every British “grey” spelling, and one value flatly contradicts its name; the full list is in the oddities file. Across the palette there are 54 distinct levels per channel, so the display quantizes color somehow, but it isn’t a clean RGB565 grid, because only 63 of the 147 values land on one. I never worked out the scheme, and it probably doesn’t matter. What matters is that a name here labels the scanner’s color, not the web’s. Render “Steelblue” with the web’s value and you’re wrong in all three channels, and nothing will ever tell you.
The knob is the API
So how do you set a color remotely? You’d reach for MSV, the protocol’s own command for writing a value into whatever menu item the scanner is sitting on. It’s refused in a color picker, by name and by index alike: “rejected in its current mode.” The only thing that moves a picker is the knob, one color per click, which is why writing a color takes seconds instead of milliseconds, and why the wraparound matters: worst case is 73 steps, not 146. Pressing enter commits the color and closes the picker. Backing out with the menu key abandons everything the knob did, which is the property that makes a read-only verification walk safe to run.
You can’t cheat by asking for the menu listing either, because MSI truncates without saying so. A layout editor holding fifty areas lists twenty. The picker lists 26 of its 147 colors. The Customize menu lists nothing at all. An early attempt trusted the picker’s listing and would have silently mis-stepped; silent truncation is the nastiest kind of lie an interface can tell, because everything looks fine right up until it isn’t. So the rule the tool lives by now: when the listing can lie, ask the screen, every single step.
If that sounds familiar, it should. In the late 90s, plenty of “web-enabled” mainframe applications were the same move: the business logic was unreachable, so middleware logged into a green-screen IBM 3270 session and read fields off known row-and-column positions. The industry called it screen scraping and was mildly embarrassed by it, and plenty of those scrapers outlived the “real” integrations that were supposed to replace them, because the screen, unlike the API, has to be right. Yes, it’s kludgy. A quarter century later I’m doing the same thing to a handheld scanner, and I’m not embarrassed at all.
Two sources, one bug
On day two I found the shortcut. The radio’s memory card carries a file called profile.cfg, and inside it are 46 tab-separated DispColors records holding runs of six-digit hex pairs, one pair per area, text color and background. They total exactly 315, and they split by layout as 40, 50, 45, 45, 45, 40, 50, the seven layouts’ area counts. One 15 KB text file against nearly four minutes of simulated key presses. Whoever at Uniden decided that file should be plain, human-readable text has my sincere thanks; that’s the kind of unglamorous engineering choice that pays strangers dividends for decades.
The catch is the one that governs everything about the card: it’s mass storage or serial, never both. While you read the file, the radio is a disk and answers nothing, so the card can tell you what the colors are but never what the screen is doing right now.
Here’s the thing about a second source, though: it doesn’t just confirm the first one, it audits it. The card and my menu walk disagreed on exactly one area out of 315. The walk said 212 areas had white text; the card said 211 white and one Blue. A third read of the radio settled it, and the card was right. The walk had misrecorded a single area, and that one wrong value had already metastasized into a wrong generalization, because my notes claimed two layouts were identical and they differ in exactly that area. One plausible source is how an error calcifies into documentation. Two independent sources is how it gets caught.
What seven colors are for
After all that, how much of the 147-color vocabulary does the radio actually use? Seven. Every one of the 315 backgrounds is black. Text is white in 211 of them. The rest encode something, and it’s genuinely good design: color tracks depth in the scanner’s memory hierarchy, warm to bright. Systems are Orangered, departments are Darkorange, channels are Gold, channel options are Darksalmon. Glance at any line on the screen and its color tells you what level of the hierarchy you’re looking at before you’ve read a word. That’s the part worth reproducing in any UI that redraws this screen, and credit to Uniden’s designers for it.
Then there are the two loners. One area on the simple trunk layout is Blue. One area on the detail trunk layout is Tomato. Each color appears exactly once on the whole radio, neither fits the hierarchy, and they mark the only two places where otherwise-identical layouts disagree. Are they part of the design, or somebody’s stray edit that stuck? I’ve confirmed one layout matches factory settings by restoring it to stock; the trunk layouts are still an open question, and it’s the question a fresh-from-the-box radio would answer in two minutes.
The radio kept its colors out of the protocol. It couldn’t keep them off the screen.