r/steammachine • u/ehodapp • 3h ago
Discussion I read the JSAUX faceplate's flash chip. Their official clock could chew through a typical chip's rated life in 28 hours
TL;DR: I read the JSAUX pixel matrix faceplate's flash chip directly. No file system, no wear leveling, every new picture, brightness change and built-in pick rewrites the same spots. Their own clock and stats screens send a new picture every second, which at a typical chip's rating is about 28 hours of use. Don't buy one until JSAUX releases the firmware or ships a fix, and if you have one, stay off those screens.
This is the third one of these, so quick recap. In my first post I was pretty stoked. I'd taken it apart, written a Decky plugin for it, and figured anything I couldn't do yet was just stuff I hadn't figured out, and that it'd all get way cooler once JSAUX posted the source like the product page kind of promises ("supports open-source code"). I bought it because like pretty much every other open hardware thing I own, I figured I'd eventually write my own firmware and make it do whatever I want. I also said whether all the flash writing wears it out "depends on firmware nobody can see yet".
In the second one I hit a wall. Controller chip with the markings sanded off, no bootloader on any pad, a command that looks a hell of a lot like a firmware loader, and support telling me they're "unable to disclose specific information at this time." JSAUX then replied on r/JSAUX that "static images and the app's built-in displays don't require flash writes", that only GIFs over 20 KB use flash, and that "the current hardware doesn't support firmware updates." A few days later they announced the app gets open-sourced once Steam approves it. Just the app.
Well my clip finally showed up from China, so last night I hooked the 2 MB flash chip up to a Raspberry Pi and dumped it before and after every single command I could send the panel. So now I've actually seen the flash. Short version, it's pretty bad.
The "static images don't write flash" thing just isn't true. Every new picture you send gets written to the flash chip, static or animated, any size, and it always erases the same few spots starting at the same addresses. Changing the brightness rewrites the settings area. Picking one of the built-in animations rewrites it too, and makes the panel forget the picture it had, so going back to it is another full write. There's no wear leveling at all, nothing spreads it around. And all of its settings live in one sector that gets rewritten on every upload, every brightness change and every switch to a built-in. When it can't read or write its settings there anymore, does it adjust? Does it just die? Who knows! (Credit where it's due, a failed or corrupted upload never touches the old picture, so they got that part right.)
To be fair, plenty of cheap gadgets rewrite the same flash sector forever and it doesn't really matter because they do it a few times a day. This one ships with official software that redraws the clock and system stats screens as a brand new picture and sends it about once a second (the clock has a blinking colon and a seconds marker, so every one of those is a new picture and the panel can't just skip it). Flash like this is typically rated around 100,000 writes. I couldn't find a datasheet for this exact chip so that's an assumption, but at 100k that's roughly 28 hours of running their clock or stats screen. Chips usually outlast their rating, so think of that as a floor more than a death date, and what wears out is where it keeps the picture and settings, not necessarily the whole panel... but it's the same few spots getting hammered every second and nothing about the design accounts for it.
The obvious fix is firmware that lets you draw on the display directly without saving every frame. I'd love to write it. I've been working with the GabeCubeAura dev for a while now (I've got a pile of PRs in there) and we've been going back and forth on what to even do about this, because right now the answer for anything live on the faceplate is basically "use it less". The guy who made OpenRGB wants it in OpenRGB too, but in his words "having it save every frame to flash is too limiting to be useful."
So I went after the firmware. I put a debug probe on every test pad on the board I could reach and nothing answers. I haven't been able to confirm a lock, but it looks exactly the way a permanently locked chip would: no debug interface answers on any test pad, and the markings were sanded off so you can't look up what it is. It's possible it's just a really cheap chip with nothing to lock. It's also possible they locked it, which is literally just a checkbox when it gets flashed at the factory. Given the sanded chip and how weird they've been about sharing source, I'd say that is very much on the table.
And "the firmware can't be updated"? I don't buy it. There's a command (0x03) the official app never sends that accepts a whole data transfer and pops up a "download failed" icon when it times out. That has every sign of a firmware upload path. If they really can't update it, the units already out there never get a fix for the wear. If they can, it's on them to ship one if they won't release the source.
So here's what I'm asking JSAUX for, and why I'm posting here instead of emailing them again:
- Publish the serial protocol. I already reversed most of it (PROTOCOL.md), it costs them nothing.
- Release the app source like they said they would. Steam approval has nothing to do with putting code on GitHub.
- Release the firmware, or at the very least ship an update with a frame command that doesn't write to flash, and a way to install it before these self destruct.
If you've got one of these and want it to last, please say something to JSAUX, in their sub, through support, wherever. Until then, if you use their app I'd stay off the clock and system stats screens. Static art and the built-in animations are fine, and my Pixel Faceplate plugin only sends a new picture when you launch a game or go back to the menu.
Everything I measured, with the dumps and how to repeat it, is here: github.com/hodapp/pixel-faceplate/tree/main/flash. I invite anyone who wants to check my work or thinks I'm being dramatic to take a look.
Anyway, I'd honestly love to be wrong about any of this. If someone from JSAUX wants to tell me how it actually works, or better yet, release some source... I'm all ears.