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

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

SquachMesh

Two SquachWatches in range of each other now notice, and each one draws the other's Squachy as a visitor. He walks in, they greet each other, they stand around talking, and eventually he goes home. His outfit, his shades, his nickname and whatever name his owner gave him all travelled over the air in a twenty-byte BLE advert.

This is a work in progress, and it is in this release because it works — not because it is finished. Two boards find each other reliably, a one-hour soak did not crash, and rotation still works with the radio broadcasting. It has had days of testing, not months. What is still open is listed at the bottom of these notes rather than left for somebody to discover.

It is deliberately not a network. No pairing, no connection, no acknowledgement, no retry — just a broadcast that says who is here, and anybody in earshot may or may not catch it. That is the entire protocol, and it is why it costs nothing: measured on real hardware, 68.7 adverts per second seen with advertising off against 68.6 with it on at a 1500 ms interval, over 62 alternating thirty-second arms. Advertising does not starve the scanner.

A peer is recognised inside the BLE scan callback and returns before the signature tables ever see it. Get that wrong and two of these alarm at each other in a loop.

It asks before it lets you near the switch

Broadcasting a stable identifier at strangers is the exact behaviour this device exists to catch other people's hardware doing. Offering it is defensible. Switching it on quietly would not be.

So a full-screen warning stands in front of the SquachMesh menu, and nothing transmits until it has been read and accepted. It says what goes out (a Bluetooth advert every 1.5 seconds), what is in it (a fixed address that never changes, plus your Squachy's name and outfit), and what somebody with a scanner can reconstruct from it — separate sightings of an address that never changes join up into a record of where you have been, and a custom name is a label on it.

It stands in front of the menu, not in front of the TRANSMIT row. By the time somebody is looking at a switch they are already deciding whether to flip it, and a warning read in that position reads as an obstacle. One read before there is anything to click reads as information.

Settings::meshTransmit() returns false without consent whatever the stored flag says, so the gate cannot be walked around by a preference left behind by an older build. Asked once; after that the row opens the menu directly, because re-consenting on every visit trains people to dismiss the thing without reading it.

DETECT is receive-only and broadcasts nothing. The two halves were one ON/OFF switch until it was reported broken twice, which is how they ended up separate: they have genuinely different consequences and only one of them is visible to strangers.

They talk to each other, not near each other

The two Squachys draw their standing-around dialogue from a table of matched pairs, so the reply actually replies. They used to pick from separate banks independently, and it read exactly like that — two Squachys taking turns saying unrelated true things, every line fine on its own and not one of them an answer.

Most exchanges carry a third beat, a short something the host throws back after the reply, because two-line exchanges are correct and a bit stiff. Not all of them, so the rhythm varies instead of thudding into a punchline every time.

Lines are timed by their own length now rather than a flat 4600 ms, and the next one goes up 220 ms after the last comes down. A fixed beat gave "Good." the same nine seconds as a full sentence, and the leftover was dead air.

Whoever is not talking cracks up when the other's line lands, leans in while listening and gives the ground back when it is his turn, and nods along on a squared curve — down and back, because a nod has a direction and a sine through the rest line is what somebody bored does. Both of them close a few pixels once the talking starts and stay there for the visit.

Speech bubbles grew a small tail pointing at whoever said it, but only while there are two Squachys on screen. Position answers "who is talking" right up until the bubbles start alternating every two seconds.

He also leaves between exchanges rather than mid-pair. Walking off after a question leaves the answer unsaid, which reads as a dropped connection rather than as a goodbye.

Ninety-six lines of arrival and farewell, and forty-eight exchanges.

Three bugs where two Squachys broke assumptions one Squachy never did

Both mouths moved for every line. bubbleText is a file static describing our Squachy, and the mouth flap read it directly — but the same drawing routine draws every Squachy on screen, so the host saying something set the guest chewing along with him. A body that does not own the bubble no longer gets to read it. That fixed an older one on the way past: the boot splash holds a line up and only moved its mouth if our own Squachy happened to be mid-quip somewhere off-screen.

The visitor's name has never once been drawn. It sat under his feet, guarded by a check that it fitted between his feet and the counters — and his feet are two pixels above the counters, so the check asked whether 8 was less than -2. Custom names travelled between devices, decoded correctly, and were shown to nobody. The name now takes turns with his speech bubble in the row above his head: up while he is quiet, which is most of a visit, and gone only while he is saying something.

The visitor changed outfit instead of leaving. A peer whose advert changed mid-visit morphed on screen. The guest is a copy taken on arrival, so a live swap becomes a proper handover: one walks out, the next walks in.

The emulator was lying about half of every conversation

Sixth fidelity bug found in the shim, and the worst so far. The one-shot renderer ticked screens with a synthetic clock running at 33 ms a frame while millis() still answered with wall-clock time, and the firmware reads both. say() stamps its deadline with millis() and the bubble is drawn while now is before that deadline — so past about frame sixty, the host's speech bubble could not render at all. Every still ever taken of the main screen was missing half the conversation.

The renderer pins millis() to the frame's own timestamp now, the way the two are one clock on the device.

The clip at the top of the SquachMesh section is rendered by that emulator, from this firmware's own source.

Also in this release

A payphone keypad for naming your Squachy, styled after Cyberdelia, with multi-tap letters on ITU E.161 — not the Bell layout, which had no Q or Z and made half the nicknames untypeable.

The SquachMesh menu, with a line under the two switches saying what the combination actually means, because "DETECT off, TRANSMIT on" is not self-evidently "they can see you but you cannot see them".

What is still open

Heap fragmentation is unresolved. A one-hour soak took the largest free contiguous block from about 17 KB to about 1.4 KB. Nothing crashed and rotation still worked, but it was trending down. Some allocation churn has since been removed and whether that fixed it is unverified. The diagnostics screen reports free heap and largest block.

The broadcaster role is enabled in every shipping build now, and it was disabled for a reason: its overhead was once tight enough to make the main screen's frame-buffer reallocation on rotate fail. That did not reproduce in an hour of soaking on an ST7789 board at 80 MHz. It has not been soaked on the ILI9341 boards or on AWOK. If a board starts failing to rotate, the largest-block number on the diagnostics screen is where to look.

The BLE address is the stable public one. That is what ignoring a specific peer would need, and it is also exactly what the warning screen describes. Deliberately deferred, not overlooked.

SquachMesh is no longer behind a build flag. The guarantee that shipping builds were byte-identical with and without it is gone by design — they now contain the same code.

Don't miss a new SquachWatch-CYD release

NewReleases is sending notifications on new releases.