What problem are you trying to solve?
When a sector line or start/finish line is confirmed crossed, user code needs to
react immediately: update the display, log to SD, start an
animation. Today, the only feedback mechanism is the int return value of loop()
(0 = near a line, -1 = not near). This requires the user to:
- Poll loop() return value every iteration
- Track state themselves to know WHICH line was crossed (they get "near a line",
not "which sector")
- Compute direction context themselves
The user's update code is likely more complex than the lap timer itself. A callback
system lets the library deliver the right event to the right handler at the right
moment — after interpolation completes, not during buffering.
A second pain point: the callback fires AFTER interpolation, so it's the
authoritative signal that a valid crossing happened. If the user instead polls
loop() == 0, they don't know whether they're in the approach zone (still
buffering) or post-interpolation (confirmed).
Proposed solution
Add a user-registerable callback that fires once per confirmed sector crossing,
with rich context parameters.
CALLBACK TYPE:
typedef void (*SectorCrossedCallback)(
int currentSector, // sector the driver just ENTERED (0 = just started lap, 1/2/3)
int lastSector, // sector the driver just COMPLETED
uint8_t sectorType // SECTOR_TYPE_RACE / SECTOR_TYPE_SERVICE / SECTOR_TYPE_OTHER
);
void setSectorCrossedCallback(SectorCrossedCallback cb);
FIRING RULES:
- Fires only when LINE_DETECT_COMPLETED is returned and crossingTime != 0
(valid interpolated crossing confirmed)
- Never fires during LINE_DETECT_IN_ZONE (approach buffering phase)
- Fires before the crossing buffer is reset, so the callback can read
any state that was updated as part of the crossing
- Fires for BOTH start/finish AND sector lines (sectorType discriminates)
COMPANION: Service sector callback (see Issue #30):
typedef void (*ServiceSectorCallback)(uint8_t serviceType, bool isEntry);
void setServiceSectorCallback(ServiceSectorCallback cb);
WHY SEPARATE CALLBACKS?
Race sector crossings and service sector events have different contexts.
Race callbacks tell you lap progress; service callbacks tell you operational
status. Mixing them in one callback requires the user to switch on sectorType
constantly. Two clean callbacks is more ergonomic.
EXAMPLE USAGE:
lapTimer.setSectorCrossedCallback([](int cur, int last, uint8_t type) {
Serial.printf("Sector %d complete, entering %d\n", last, cur);
display.showSectorSplit(last, lapTimer.sectorTimes[last]);
});
Alternatives considered
-
loop() return value (current approach) — tells caller "near a line" but NOT
which line, and NOT whether it was approach or confirmed crossing. Caller
must maintain its own state machine to detect the transition.
-
Polling boolean flags (e.g. getCrossing()) — same problem: no event,
no which-line context, still need user-side state machine.
-
Single callback with all crossing types — workable but forces switch(sectorType)
in every callback. Two callbacks is cleaner separation of concerns.
-
Return struct from loop() instead of int — breaks API compatibility; also
still requires the caller to detect the confirmed-vs-buffering transition.
What problem are you trying to solve?
When a sector line or start/finish line is confirmed crossed, user code needs to
react immediately: update the display, log to SD, start an
animation. Today, the only feedback mechanism is the int return value of loop()
(0 = near a line, -1 = not near). This requires the user to:
not "which sector")
The user's update code is likely more complex than the lap timer itself. A callback
system lets the library deliver the right event to the right handler at the right
moment — after interpolation completes, not during buffering.
A second pain point: the callback fires AFTER interpolation, so it's the
authoritative signal that a valid crossing happened. If the user instead polls
loop() == 0, they don't know whether they're in the approach zone (still
buffering) or post-interpolation (confirmed).
Proposed solution
Add a user-registerable callback that fires once per confirmed sector crossing,
with rich context parameters.
CALLBACK TYPE:
FIRING RULES:
(valid interpolated crossing confirmed)
any state that was updated as part of the crossing
COMPANION: Service sector callback (see Issue #30):
WHY SEPARATE CALLBACKS?
Race sector crossings and service sector events have different contexts.
Race callbacks tell you lap progress; service callbacks tell you operational
status. Mixing them in one callback requires the user to switch on sectorType
constantly. Two clean callbacks is more ergonomic.
EXAMPLE USAGE:
Alternatives considered
loop() return value (current approach) — tells caller "near a line" but NOT
which line, and NOT whether it was approach or confirmed crossing. Caller
must maintain its own state machine to detect the transition.
Polling boolean flags (e.g. getCrossing()) — same problem: no event,
no which-line context, still need user-side state machine.
Single callback with all crossing types — workable but forces switch(sectorType)
in every callback. Two callbacks is cleaner separation of concerns.
Return struct from loop() instead of int — breaks API compatibility; also
still requires the caller to detect the confirmed-vs-buffering transition.