github skizzophrenic/SquachWatch-CYD v1.5.22
SquachWatch-CYD v1.5.22

latest releases: v1.40.0, v1.39.0, v1.38.0...
one month ago

A spectrum around the alert

The alert screen gets a frame: one full spectrum wrapped exactly once around the perimeter, rotating. Every hue is on screen at all times, so the border never goes dark and never reads as switched off.

The walk is what makes it join up. The colour is a function of distance travelled around the outer rectangle, continuous from zero back round to the start, so the hue at the last pixel of the left edge meets the hue at the first pixel of the top. Each step paints two pixels inward, which means the four corners get painted twice — and they agree, because both visits carry the same distance.

It walks between six saturated stops rather than computing a hue. RGB332 has eight levels of red, eight of green, and four of blue — that is the entire blue axis — and a calculated sweep bands badly against it because most of the intermediate hues it asks for round onto the same handful of reachable values. The same construction the main screen's headline rainbow already uses.

Drawn after the glitch static, deliberately. The static is meant to read as interference in the content; a frame that breaks up along with it stops reading as a frame at all.

Chosen from five animated candidates rendered by the emulator. The other four — a comet, a breathing ring, twin counter-rotating comets, and a double spectrum with a counter-travelling ripple — are in the history if they are ever wanted back.

The header strip gets a bevel, and it nearly did not

Built from the strip's own colour rather than Win95 grey, because the strip is a coloured title bar and grey chrome around it would read as a second unrelated widget sitting behind the type name.

It is inset by the border width, which was not optional. Drawn at the corner the frame paints straight over the strip's lit top edge and both side edges, leaving only the bottom shadow — which is not a bevel. The first render looked almost unchanged and the obvious conclusion was "too subtle" rather than "being erased".

It also had to be pushed twice as hard as the IGNORE button's. That one has five distinct greys to build from; a bevel made out of a single colour only has what lightening and darkening can reach from that colour, and on a mid purple through RGB332 the gentle version came back as almost nothing.

IGNORE moved out to eight pixels from the edge. The margin has to clear the border, not the screen: with a three-pixel frame a four-pixel margin left exactly one pixel of gap, which reads as a collision. Paid for out of the label-to-button gap rather than the button, so CARD SKIMMER — the longest type name that still fits the Bangers face at 151px — keeps its margin on the narrow rotation.

The device now records its own death

A board panicked during a drive. Everything that survived was the word PANIC. Not when, not why, not whether the heap was exhausted, not which screen was up. That is barely a bug report, and it is all the firmware could offer.

So a breadcrumb now goes into RTC memory once a second: uptime, free heap, largest contiguous block, lifetime detection count as a proxy for how busy the air was, and the current screen. After a panic, the diagnostics screen shows it.

RTC_NOINIT_ATTR is the whole trick — it survives a software reset without being zeroed on the way back up, which is exactly what a post-mortem needs and what an ordinary variable cannot do. A magic word separates a real breadcrumb from whatever happened to be in RTC RAM after a cold boot.

Once a second costs no flash wear, unlike writing to NVS, and a second of resolution is enough for the question being asked. "Died at forty-one minutes with nine hundred bytes of largest block, on the main screen" and "died at three minutes with a healthy heap" are different bugs, and nothing available before this could tell them apart.

It changes no behaviour whatsoever — only what is knowable afterwards. A blank where the report goes means a clean boot rather than a missing feature.

Also

Every speech bubble the emulator has ever rendered was drawn mid-pop. A flat four-pixel sliver with no room for the text inside it. The pop animation was the one thing in the mascot's file reading millis() rather than the frame time everything else is driven by — and the one-shot renderer advances frame time itself while leaving millis() on the wall clock, so it draws seventy-five frames of animation in rather less than the 220ms the pop lasts. Hardware was always correct, which is precisely what makes it worth hunting: it only ever lied to the instrument. Fifth of its family, after the four found in the emulator audit two releases ago.

Two scale units that look interchangeable and are not. The mascot's normal draw derives its scale from the height it is handed; the cameo draw takes an absolute one. Passing the same number to both — which reads as the same intent — draws two mascots of visibly different sizes. The scale actually used is now readable, so anything standing beside him reads it instead of recomputing it and hoping the arithmetic stays in step.

Unlisted development builds. Pushing an experimental firmware to the web flasher no longer requires cutting a release: a manual workflow run publishes an extra, unlisted entry alongside the real boards. The first attempt at this replaced the public flasher's firmware for every board with an unreleased build and took the version picker offline for about ten minutes, because a Pages deploy is wholesale and there is no such thing as a partial one. It now restores the released site first and adds the development build beside it, so the only thing such a run contributes is its own binary.

Work in progress you may notice in the source. There is a good deal of code in this tree behind a SQUACH_MESH build flag — peer discovery between two devices, and a keypad for naming the mascot. None of it is compiled into any shipping build, and that is checked rather than claimed: the shipping binary contains no symbols from it at all.

The actually-useful part

  • Added: an animated spectrum frame around the alert screen
  • Added: a bevelled header strip on the alert screen, in the detection's own colour
  • Added: a crash report on the diagnostics screen — uptime, heap, largest block and screen at the moment of the last panic
  • Changed: the alert screen's IGNORE button sits eight pixels from the edge, clear of the new frame
  • Fixed: the emulator rendered every speech bubble mid-animation, as a flat sliver
  • Fixed: the mascot's two draw paths took scales in different units, so anything drawn beside him came out the wrong size
  • Fixed: a development deploy could replace the public flasher's firmware and remove its version picker

Don't miss a new SquachWatch-CYD release

NewReleases is sending notifications on new releases.