Skip to content

Probe-to-Photon, buttons bound, live-tab layout fixed - #7

Merged
PrimeBuild-pc merged 3 commits into
mainfrom
feat/probe-to-photon
Aug 21, 2026
Merged

Probe-to-Photon, buttons bound, live-tab layout fixed#7
PrimeBuild-pc merged 3 commits into
mainfrom
feat/probe-to-photon

Conversation

@PrimeBuild-pc

Copy link
Copy Markdown
Owner

Firmware v1.5 adds a second, separate measurement mode. The Probe-to-PC path is byte-identical to v1.4 and v1.3probeISR(), the t₀/t₁ block, the TRIG/H handshake, runCalibration(), serviceProbeRearm(), every filter and the OLED freeze are untouched. The diff from v1.4 removes six lines: three version strings, one comment, the if (probeFlag) that became } else if (probeFlag), and the OLED refresh guard that now also checks the optical mode.

Probe-to-Photon

t₀ is the same probe contact on D2; t₁ is the first A0 reading past a calibrated threshold. Nothing is transmitted between them, so calibOffset is not subtracted — there is no round-trip. The dashboard flips its own black target to white when Windows reports the click; the Teensy finds out by looking at the light.

Calibration happens on a centred full-screen target, because two baselines taken from different parts of the screen describe different patches of backlight. One button opens it; entering test mode repeats it so the threshold can never be stale. Baselines closer than 60 ADC counts refuse to arm, and the failure reports the numbers it actually measured. The direction is derived, so a module whose ADC value falls as light rises works with no setting.

The two modes never mix: OPT: is a different token from LAT:, the firmware keeps separate statistics, runs.mode records which produced a run, and the Compare tab says so when a comparison spans both.

Buttons

Bound now that the 10/10 hardware test has passed: BTN1 enters and leaves test mode, BTN2 clears the live run outside it. The firmware still only reports; the dashboard decides and refuses a press that would disturb a run. Both call the same entry points the GUI and the keyboard use. New preference, on by default: ask before BTN2 clears a run.

Fixed

  • The live tab's right column scrolls. With the optical panel showing it was taller than a laptop screen, putting Enter test mode below the bottom edge with no way to reach it.
  • "Access denied" on the COM port at startup. The serial reader thread is joined on close so Windows really releases the handle, and the automatic connection retries quietly instead of opening a modal. A connection the user asks for still reports its errors.

Honest about the sensor

The KY-018 is a photoresistor whose own response is in the milliseconds — the same order as the quantity being measured. Probe-to-Photon is documented as a relative indicator, one setup against itself, and explicitly not an absolute click-to-photon benchmark. The dashboard's own repaint is inside the measured interval, and that is stated rather than hidden.

The 2N2222A and the 220 Ω resistors stay unused and unwired. The mouse stays untouched: removable copper tape on the outside of the button is still the only mouse-side modification.

Migration

Schema v3 adds runs.mode, the three optical columns and samples.raw_optical in place. Existing runs read as probe_to_pc — the only mode that existed when they were written.

Verification

293 tests, 88% coverage of the non-GUI code. New tests/test_photon.py (29) covers the wire format, that an OPT: line can never decode as a LAT: one, the threshold maths in both directions, the refusal when the baselines are too close, and the v2→v3 migration. tests/test_button_actions.py (13) covers the refusal rules and the confirmation preference. Lint is two findings better than the base.

The firmware is not compiled in CI — no Teensyduino available — but it passes a bracket-balance and definition-order check, and the Probe-to-PC diff is additive only.

🤖 Generated with Claude Code

@chatgpt-codex-connector

Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Firmware v1.5 (firmware/latency_tester_photon_v1_5/) adds a second,
separate measurement mode. The Probe-to-PC path is byte-identical to
v1.4 and v1.3: probeISR(), the t0/t1 block, the TRIG/'H' handshake,
runCalibration(), serviceProbeRearm(), every filter and the OLED freeze
are untouched. The diff from v1.4 removes six lines: three version
strings, one comment, the `if (probeFlag)` that became
`} else if (probeFlag)`, and the OLED refresh guard that now also checks
the optical mode.

Probe-to-Photon: t0 is the same probe contact on D2, t1 is the first A0
reading past a calibrated threshold. Nothing is transmitted between
them, so calibOffset is not subtracted -- there is no round-trip. The
dashboard flips its own black target to white when Windows reports the
click; the Teensy finds out by looking at the light.

Calibration happens on a centred full-screen target, because two
baselines taken from different parts of the screen describe different
patches of backlight. One button opens it; entering test mode repeats it
so the threshold can never be stale. Baselines closer than 60 ADC counts
refuse to arm, and the failure reports the numbers it measured. The
direction is derived, so a module whose ADC value falls as light rises
works with no setting.

The two modes never mix: OPT: is a different token from LAT:, the
firmware keeps separate statistics, runs.mode records which produced a
run, and the Compare tab says so when a comparison spans both.

BTN1 and BTN2 are bound now that the 10/10 hardware test has passed:
BTN1 enters and leaves test mode, BTN2 clears the live run outside it.
The firmware still only reports; the dashboard decides and refuses a
press that would disturb a run. Both call the same entry points the GUI
and the keyboard use. New preference, on by default: ask before BTN2
clears a run.

Also fixed:
- The live tab's right column scrolls. With the optical panel showing it
  was taller than a laptop screen, putting "Enter test mode" below the
  bottom edge with no way to reach it.
- "Access denied" on the COM port at startup: the serial reader thread is
  joined on close so Windows really releases the handle, and the
  automatic connection retries quietly instead of opening a modal.

The KY-018 is documented as what it is: a photoresistor whose own
response is in the milliseconds, so Probe-to-Photon is a relative
indicator, not an absolute click-to-photon benchmark. The 2N2222A and the
220 ohm resistors stay unused and unwired, and the mouse stays
untouched -- removable copper tape on the outside of the button is still
the only mouse-side modification.

Schema v3 adds runs.mode, the three optical columns and
samples.raw_optical in place; existing runs read as probe_to_pc.

293 tests, 88% coverage of the non-GUI code.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Comment thread latency_tester/app.py
if (not self.serial.connected or self.test_mode
or self.cal_window is not None):
return
from .views.testmode import OpticalCalibrationWindow
The target was a 260 px square, and the calibration window and the test
overlay laid it out differently. A KY-018 held against the glass with
elastic bands does not hit a square that small, so both baselines came
back reading the surrounding black and the calibration failed with dark
and bright a few counts apart -- correctly refusing, but for a reason
nothing on screen explained.

One `place_target()` now draws a 620x440 block dead centre, and both
windows call it, so a baseline always comes from the patch of screen the
measurement will use.

A failed calibration no longer closes itself. It stays up with a live
LIGHT reading refreshed every 150 ms instead of once a second, which is
the only way to aim a sensor you cannot see through: move it until the
number swings between the black and the white phase. Enter retries
without closing, Esc gives up.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@PrimeBuild-pc
PrimeBuild-pc merged commit 03d0c5e into main Aug 21, 2026
6 checks passed
@PrimeBuild-pc
PrimeBuild-pc deleted the feat/probe-to-photon branch August 21, 2026 16:08
Every component is built, wired and verified on the bench, so the README
says so instead of hedging. The 2N2222A and the four 220 ohm resistors go
from "unused / reserved" to "not needed, do not buy": they were on an
early parts list and never found a role -- the probe method switches
nothing, and Probe-to-Photon reads a sensor that was already wired.
Leaving them documented as "reserved" implied a plan that does not exist.

Adds the measured comparison the mode was built for: 40 clicks, ~16 ms
median in Probe-to-Photon against ~3 ms for the same mouse in
Probe-to-PC. The ~13 ms difference is the repaint, the compositor, the
GPU queue, the panel *and* the KY-018's own response together -- written
that way on purpose, because reading it as "my monitor adds 13 ms" is
the mistake this sensor invites.

Roadmap section: a 3D-printed enclosure, including a mount that holds the
probe steady, since probe alignment is the largest error source in the
method. Nothing else is planned.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants