What problem are you trying to solve?
Circuit racing — especially endurance karting — involves mandatory service stops:
pit lane entry/exit, refuelling windows, tyre changes. A lap timer that can only
detect the start/finish line and race sectors has no way to:
- Notify the driver/display when they enter or exit the pit lane
- Time how long a service stop took
- Log which type of service was performed
Currently users must maintain separate crossing-line detection logic using the
same underlying haversine/side-of-line math that DovesLapTimer already implements.
This is boilerplate duplication.
The library's crossing detection infrastructure (insideLineThreshold,
pointOnSideOfLine, side-change confirmation) is exactly the right foundation
for service sector detection — it just needs to be exposed for non-race lines.
Proposed solution
Add "service sector" as a first-class line type alongside race sectors.
DATA TYPES:
struct serviceSectorStruct {
double lat1, lon1; // line endpoint A
double lat2, lon2; // line endpoint B
bool isEntrance; // true = entry line, false = exit line
uint8_t serviceType; // one of the SERVICE_TYPE_* constants
};
// Type discriminators for sector_crossed_callback context
#define SECTOR_TYPE_RACE 0
#define SECTOR_TYPE_SERVICE 1
#define SECTOR_TYPE_OTHER 2
// Service types
#define SERVICE_TYPE_PITLANE_START 0
#define SERVICE_TYPE_PITLANE_END 1
#define SERVICE_TYPE_FUEL_START 2
#define SERVICE_TYPE_FUEL_END 3
#define SERVICE_TYPE_TYRES_START 4
#define SERVICE_TYPE_TYRES_END 5
#define SERVICE_TYPE_OTHER_START 6
#define SERVICE_TYPE_OTHER_END 7
API:
// Register callback: fires when any service sector line is confirmed crossed
typedef void (*ServiceCallbackFunction)(uint8_t serviceType, bool isEntry);
void setServiceSectorCallback(ServiceCallbackFunction cb);
// Public state readable by display code
bool inServiceSector = false;
unsigned long lastServiceSectorTime = 0; // ms duration of last completed stop
// Config: max 8 service sectors (avoids heap pressure from unbounded array)
serviceSectorStruct* serviceSector = nullptr;
int numberOfServiceSectors = 0;
DETECTION LOGIC:
For each registered service sector line, per GPS fix:
1. insideLineThreshold() — quick reject if far from line
2. pointOnSideOfLine() — determine which side driver is on
3. Per-sector side history serviceSideLastSeen[8] — confirmed crossing
only when side changes from a non-zero previous side
4. Update inServiceSector and serviceSectorStartTime on entry
5. Compute lastServiceSectorTime = now - serviceSectorStartTime on exit
6. Fire callback(serviceType, isEntrance)
Service sector detection is independent of race sector crossing state —
both can be checked in the same loop() call without interference.
ARCHITECTURE NOTE:
For consistency with the shared _detectLineCrossing() zone state machine
added in v4.1, service sectors should ideally go through the same pipeline.
The main consideration is buffer sharing — service sectors are unlikely to
coincide with race sector crossings, but the architecture should be explicit
about this (separate flags, or confirmed non-overlapping zones in the track
config).
Alternatives considered
-
User implements their own crossing logic — current workaround. Requires
duplicating insideLineThreshold, pointOnSideOfLine, and side-history logic.
-
Treat service sectors as race sectors — mixes race and non-race timing in
the same sectorTimes[] array, polluting race stats with pit durations.
-
Separate library — over-engineered for what is ultimately reusing the same
crossing detection math that already lives in DovesLapTimer.
What problem are you trying to solve?
Circuit racing — especially endurance karting — involves mandatory service stops:
pit lane entry/exit, refuelling windows, tyre changes. A lap timer that can only
detect the start/finish line and race sectors has no way to:
Currently users must maintain separate crossing-line detection logic using the
same underlying haversine/side-of-line math that DovesLapTimer already implements.
This is boilerplate duplication.
The library's crossing detection infrastructure (insideLineThreshold,
pointOnSideOfLine, side-change confirmation) is exactly the right foundation
for service sector detection — it just needs to be exposed for non-race lines.
Proposed solution
Add "service sector" as a first-class line type alongside race sectors.
DATA TYPES:
API:
DETECTION LOGIC:
For each registered service sector line, per GPS fix:
1. insideLineThreshold() — quick reject if far from line
2. pointOnSideOfLine() — determine which side driver is on
3. Per-sector side history
serviceSideLastSeen[8]— confirmed crossingonly when side changes from a non-zero previous side
4. Update inServiceSector and serviceSectorStartTime on entry
5. Compute lastServiceSectorTime = now - serviceSectorStartTime on exit
6. Fire callback(serviceType, isEntrance)
Service sector detection is independent of race sector crossing state —
both can be checked in the same loop() call without interference.
ARCHITECTURE NOTE:
For consistency with the shared _detectLineCrossing() zone state machine
added in v4.1, service sectors should ideally go through the same pipeline.
The main consideration is buffer sharing — service sectors are unlikely to
coincide with race sector crossings, but the architecture should be explicit
about this (separate flags, or confirmed non-overlapping zones in the track
config).
Alternatives considered
User implements their own crossing logic — current workaround. Requires
duplicating insideLineThreshold, pointOnSideOfLine, and side-history logic.
Treat service sectors as race sectors — mixes race and non-race timing in
the same sectorTimes[] array, polluting race stats with pit durations.
Separate library — over-engineered for what is ultimately reusing the same
crossing detection math that already lives in DovesLapTimer.