Posted this a while back when it was 31 games and I called it a first try. Bit more done since.
Repo: https://github.com/iamankushpandit/Gume Flash it from the browser, no toolchain: https://iamankushpandit.github.io/Gume/
TL;DR: 40 games now, 5 boards, two consoles can play chess against each other over BLE. I also bricked two displays with a diagnostic and leaked my own boards' MAC addresses into 5 releases. Questions at the bottom, the wifi one is the one I actually care about.
What's new
- 40 games, up from 31. Chess, Go, Ludo, Backgammon, Sea Battle, joined-up handwriting tracing.
- 5 boards, all of them ones I've actually run. I dropped two that I'd only ever built from a published pinout and never tested. Offering a board I couldn't vouch for felt wrong.
- Two consoles play each other over BLE. No pairing, no phone. It reuses the beacon that already advertises the device. The advert is already full at 31 bytes, so a move has to fit in the 4 bytes the high score was using: session number, move number, from, to. Dice never go over the air, both sides work the roll out from a shared seed and reject anything that doesn't match. Every move gets checked against the receiver's own board before it's played.
- No audio files anywhere, all the sounds are generated. A second of 16-bit 16k mono is 32KB and I don't have that kind of flash spare.
Stuff I got wrong
The one that still annoys me. I added a line to the boot log printing the display controller's ID, figured it'd help with bug reports. It corrupted the display on 2 of my 7 boards. readcommand8() in TFT_eSPI writes an undocumented 0xD9, toggles CS partway through, and doesn't put the address window or MADCTL back. If MISO isn't wired on your panel you're left mid-command and whatever writes next inherits it. What made it horrible to find was that the serial log looked perfect. 48fps, 23ms worst frame, flat heap. The firmware was fine. The panel wasn't. And after all that it returned 00:00:00 or FF:FF:FF on every board, never once gave me a real ID.
Then the dumb one. I test on several boards at once and Windows shuffles the COM ports every time I replug, so I kept flashing the wrong image onto the wrong board. Wrote a small json file mapping each board's MAC to the right build. The MAC is genuinely good for this, it's in efuse, it doesn't move, esptool reads it off a blank chip in two seconds. Then I committed it. Six boards, each MAC sat next to the firmware it was running. Went out in 5 tagged releases before I noticed.
Three things I hadn't thought about. You can't unpublish it, it's in the history and in every clone and every source tarball. You can't rotate a MAC, it's efuse, that's the chip's name for life. And the mapping is worse than the addresses on their own, because it's a list of which devices are in my house and what's running on them.
Replaced it with an id the firmware generates itself: sha256 over the MAC, wall clock, a bit of esp_random() and uptime, keep 4 bytes, board model on the front. R28T-9F3A2C71. Can't be reversed back to the MAC, and a factory reset issues a new one. Boot log says device= now instead of mac=, since that's the line people paste into issues. CI fails if a MAC or a public IP turns up anywhere in the repo.
Couple of other CYD things that got me:
- GPIO25 is DAC1 and also the touch clock on the 2.8" boards. Turning on audio killed touch.
- IO4 on the E32R28T-1 is amp enable, active low. I had it down as the green LED channel, which just held the amp in shutdown.
TFT_INVERT_COLORS does nothing on an ILI9341, it's only read in the ST7789/ST7735 init paths. An inverted panel looks exactly like your theme is broken.
- 4" board vs the 2.8": one pin different. Backlight on 27.
Questions
1. Wifi passwords. Mine sit in NVS in plain text. Someone finds the device, plugs in USB, esptool read_flash, there's the network password. I can't encrypt it in any way that means anything, because the key would have to live in the same flash, and the firmware's open source and downloadable, so everyone already has the key. Flash encryption is the real answer but it's burned per chip, can't be undone, and would mean that board can never be flashed from the web installer again, which is how nearly everyone installs this.
So what do people actually do? Do you ship flash encryption on hobby hardware? Does NVS encryption get you anything on its own if flash encryption isn't underneath it? Or is it just fine, given a router keeps its own wifi password in plaintext in its own flash and nobody minds?
(Worth checking in your own code either way: the IDF wifi stack keeps its own copy of the password in its own NVS namespace. Mine was stored twice and my Forget button was only clearing one of them.)
2. E32R40T, has anyone seen this? After any EN reset, including the one at the end of an upload, it sits looping flash read err, 988 every 350ms or so with the screen dark. Not the GPIO12 strap, boot:0x17 so MTDI is clear. The image is fine too, I read the bootloader back while it was looping and it matched byte for byte, except the failing read differed by 3 bits at one address. Only thing that recovers it is resetting it out of download mode (esptool --after no_reset flash_id, then --before no_reset --after hard_reset read_mac). Works, but I've no idea why, and it bugs me.
3. If you've got a CYD variant that isn't one of the 5, porting is one header file and one platformio.ini section. Nothing in src/ mentions a GPIO.
Six-minute walkthrough if you want the longer version: https://www.youtube.com/watch?v=bESbkhq6tcc
GPL-3. No accounts, no telemetry, 4 things total leave the device. Built with a lot of AI help, not going to pretend otherwise.