DovesLapTimer 4.3.0
GPS-based lap timing Arduino library — go-karts to race cars
Loading...
Searching...
No Matches
SprintTimer.h
Go to the documentation of this file.
1
50#ifndef _DOVES_SPRINT_TIMER_H
51#define _DOVES_SPRINT_TIMER_H
52
53#include <Arduino.h>
54#include "GeoMath.h"
55#include "CrossingEngine.h"
56#include "DovesLapTimer.h" // DIR_UNKNOWN, GPS_* validation constants
57
58// The maximum number of split (sector) lines between start and finish.
59#define SPRINT_MAX_SPLITS 2
60
62public:
63 SprintTimer(double crossingThresholdMeters = 7, Stream *debugSerial = NULL);
64
76 int loop(double currentLat, double currentLng, float currentAltitudeMeters, float currentSpeedKnots);
80 void updateCurrentTime(unsigned long currentTimeMilliseconds);
84 void reset();
85
87 // Configuration
88
92 void setStartLine(double pointALat, double pointALng, double pointBLat, double pointBLng);
97 void setFinishLine(double pointALat, double pointALng, double pointBLat, double pointBLng);
101 void setSector2Line(double pointALat, double pointALng, double pointBLat, double pointBLng);
106 void setSector3Line(double pointALat, double pointALng, double pointBLat, double pointBLng);
107
108 bool isStartLineConfigured() const;
109 bool isFinishLineConfigured() const;
114 bool areSectorLinesConfigured() const;
115
118
120 // Run-native surface
121
123 bool isRunActive() const;
125 int getRuns() const;
127 int getCancelledRunCount() const;
129 unsigned long getCurrentRunTime() const;
130 unsigned long getLastRunTime() const;
131 unsigned long getBestRunTime() const;
133 int getBestRunNumber() const;
134 float getCurrentRunDistance() const;
135 float getLastRunDistance() const;
136 float getBestRunDistance() const;
137
139 // Duck-typed DovesLapTimer surface (laps == runs)
140
142 bool getRaceStarted() const;
144 bool getCrossing() const;
145 int getLaps() const { return getRuns(); }
146 unsigned long getCurrentLapTime() const { return getCurrentRunTime(); }
147 unsigned long getLastLapTime() const { return getLastRunTime(); }
148 unsigned long getBestLapTime() const { return getBestRunTime(); }
149 int getBestLapNumber() const { return getBestRunNumber(); }
151 float getLastLapDistance() const { return getLastRunDistance(); }
152 float getBestLapDistance() const { return getBestRunDistance(); }
153 float getTotalDistanceTraveled() const;
158 float getPaceDifference() const;
159 float getCurrentSpeedKmh() const;
160 float getCurrentSpeedMph() const;
161
165 int getCurrentSector() const;
166 unsigned long getCurrentLapSector1Time() const;
167 unsigned long getCurrentLapSector2Time() const;
168 unsigned long getCurrentLapSector3Time() const;
169 unsigned long getBestSector1Time() const;
170 unsigned long getBestSector2Time() const;
171 unsigned long getBestSector3Time() const;
172 int getBestSector1LapNumber() const;
173 int getBestSector2LapNumber() const;
174 int getBestSector3LapNumber() const;
179 unsigned long getOptimalLapTime() const;
180
182 unsigned int getRejectedCrossingCount() const;
183
184 // Direction (not applicable point-to-point)
185 int getDirection() const { return DIR_UNKNOWN; }
186 bool isDirectionResolved() const { return false; }
187
188private:
189#ifdef DOVES_DISABLE_DEBUG
190 // Compile-time debug kill switch: the runtime _serial null-check still
191 // keeps every debug string and print call-site in flash on production
192 // builds that never attach a debug Stream. Defining DOVES_DISABLE_DEBUG
193 // (e.g. -DDOVES_DISABLE_DEBUG in build flags) replaces the debug
194 // templates with empty inlines so the compiler drops it all — several
195 // KB on a fully-featured firmware. Debug behavior is unchanged when
196 // the macro is not defined.
197 template<typename... Args> void debug_print(Args&&...) {}
198 template<typename... Args> void debug_println(Args&&...) {}
199#else
200 template<typename... Args>
201 void debug_print(Args&&... args) {
202 if(_serial) { _serial->print(std::forward<Args>(args)...); }
203 }
204 template<typename... Args>
205 void debug_println(Args&&... args) {
206 if(_serial) { _serial->println(std::forward<Args>(args)...); }
207 }
208#endif
209
211 int _expectedSegments() const;
213 int _segmentClosedBySector(int sectorLabel) const;
214 void _handleStartCrossing(unsigned long crossingTime, double crossingOdometer);
215 void _handleFinishCrossing(unsigned long crossingTime, double crossingOdometer);
216 void _handleSplitCrossing(int sectorLabel, unsigned long crossingTime);
217 void _updateBestSegments();
218
219 Stream *_serial;
220 double _crossingThresholdMeters;
221
222 // One engine per line: independent buffers, so zones may overlap and all
223 // lines stay hot on every fix. This is the deliberate opposite of
224 // DovesLapTimer's shared-buffer design — see the header comment.
225 CrossingEngine _startEngine;
226 CrossingEngine _finishEngine;
227 CrossingEngine _sector2Engine;
228 CrossingEngine _sector3Engine;
229
230 // Line endpoints + configuration + in-zone flags
231 double _startALat = 0, _startALng = 0, _startBLat = 0, _startBLng = 0;
232 double _finishALat = 0, _finishALng = 0, _finishBLat = 0, _finishBLng = 0;
233 double _sector2ALat = 0, _sector2ALng = 0, _sector2BLat = 0, _sector2BLng = 0;
234 double _sector3ALat = 0, _sector3ALng = 0, _sector3BLat = 0, _sector3BLng = 0;
235 bool _startLineConfigured = false;
236 bool _finishLineConfigured = false;
237 bool _sector2LineConfigured = false;
238 bool _sector3LineConfigured = false;
239 bool _crossingStart = false;
240 bool _crossingFinish = false;
241 bool _crossingSector2 = false;
242 bool _crossingSector3 = false;
243
244 // Vehicle state (same intake pipeline as DovesLapTimer::loop)
245 unsigned long _millisecondsSinceMidnight = 0;
246 float _totalDistanceTraveled = 0;
247 double _positionPrevLat = 0;
248 double _positionPrevLng = 0;
249 float _positionPrevAlt = 0;
250 bool _firstPositionReceived = false;
251 int _consecutiveJumpCount = 0;
252 float _currentSpeedKmh = 0;
253 crossingPointBufferEntry _prevFix = {0, 0, 0, 0, 0};
254 bool _hasPrevFix = false;
255
256 // Run state
257 bool _raceStarted = false; // any run ever started this session
258 bool _runActive = false; // RUNNING vs WAITING
259 int _runs = 0;
260 int _cancelledRuns = 0;
261 unsigned long _currentRunStartTime = 0;
262 double _currentRunOdometerStart = 0;
263 unsigned long _lastRunTime = 0;
264 float _lastRunDistance = 0;
265 unsigned long _bestRunTime = 0;
266 float _bestRunDistance = 0;
267 int _bestRunNumber = 0;
268
269 // Segment (split) state for the run in progress
270 int _currentSegment = 0; // 0 = WAITING, 1..N while RUNNING
271 unsigned long _segmentStartTime = 0;
272 bool _segmentOrderValid = true;
273 unsigned long _currentRunSegTime[SPRINT_MAX_SPLITS + 1] = {0, 0, 0};
274
275 // Best segment times across runs (valid, in-order runs only)
276 unsigned long _bestSegTime[SPRINT_MAX_SPLITS + 1] = {0, 0, 0};
277 int _bestSegRunNumber[SPRINT_MAX_SPLITS + 1] = {0, 0, 0};
278};
279
280#endif
#define DIR_UNKNOWN
Definition DovesLapTimer.h:55
#define SPRINT_MAX_SPLITS
Definition SprintTimer.h:59
double crossingThresholdMeters
Definition basic_oled_example.ino:75
void loop()
Definition basic_oled_example.ino:116
Definition CrossingEngine.h:81
Definition SprintTimer.h:61
float getTotalDistanceTraveled() const
Definition SprintTimer.cpp:433
unsigned long getLastLapTime() const
Definition SprintTimer.h:147
void reset()
Reset all run/timing state to zero. Configured lines are kept.
Definition SprintTimer.cpp:335
int getDirection() const
Definition SprintTimer.h:185
unsigned long getCurrentLapSector3Time() const
Definition SprintTimer.cpp:473
float getBestLapDistance() const
Definition SprintTimer.h:152
int getRuns() const
Completed run count this session.
Definition SprintTimer.cpp:389
unsigned long getBestSector1Time() const
Definition SprintTimer.cpp:477
float getCurrentSpeedKmh() const
Definition SprintTimer.cpp:453
void setStartLine(double pointALat, double pointALng, double pointBLat, double pointBLng)
Sets the START line (a run begins when it is crossed).
Definition SprintTimer.cpp:273
int getBestSector3LapNumber() const
Definition SprintTimer.cpp:497
void updateCurrentTime(unsigned long currentTimeMilliseconds)
Updates the current GPS time since midnight (milliseconds).
Definition SprintTimer.cpp:137
unsigned long getBestSector3Time() const
Definition SprintTimer.cpp:485
unsigned long getCurrentLapTime() const
Definition SprintTimer.h:146
float getLastRunDistance() const
Definition SprintTimer.cpp:417
bool isDirectionResolved() const
Definition SprintTimer.h:186
int getBestSector2LapNumber() const
Definition SprintTimer.cpp:493
void setFinishLine(double pointALat, double pointALng, double pointBLat, double pointBLng)
Sets the FINISH line (a run completes when it is crossed while a run is active).
Definition SprintTimer.cpp:282
bool areSectorLinesConfigured() const
True when at least one split line is configured (note: NOT the circuit timer's both-or-nothing rule —...
Definition SprintTimer.cpp:317
float getBestRunDistance() const
Definition SprintTimer.cpp:421
unsigned long getOptimalLapTime() const
Sum of best segment times (theoretical best run). 0 unless at least one split is configured and every...
Definition SprintTimer.cpp:501
float getCurrentLapDistance() const
Definition SprintTimer.h:150
float getPaceDifference() const
Pace delta vs the best run in ms per meter (see DovesLapTimer::getPaceDifference)....
Definition SprintTimer.cpp:437
bool isFinishLineConfigured() const
Definition SprintTimer.cpp:313
float getCurrentRunDistance() const
Definition SprintTimer.cpp:413
bool getCrossing() const
True while inside any configured line's crossing zone.
Definition SprintTimer.cpp:429
void setSector2Line(double pointALat, double pointALng, double pointBLat, double pointBLng)
Sets the optional sector 2 split line (closes segment 1).
Definition SprintTimer.cpp:291
bool getRaceStarted() const
True once any run has ever started this session.
Definition SprintTimer.cpp:425
int getLaps() const
Definition SprintTimer.h:145
void forceLinearInterpolation()
Definition SprintTimer.cpp:321
int getBestRunNumber() const
1-based run number that set the best time (0 = none yet).
Definition SprintTimer.cpp:409
unsigned long getCurrentRunTime() const
Elapsed ms of the run in progress, 0 while WAITING.
Definition SprintTimer.cpp:397
bool isStartLineConfigured() const
Definition SprintTimer.cpp:309
float getLastLapDistance() const
Definition SprintTimer.h:151
void forceCatmullRomInterpolation()
Definition SprintTimer.cpp:328
float getCurrentSpeedMph() const
Definition SprintTimer.cpp:457
unsigned long getBestLapTime() const
Definition SprintTimer.h:148
int getCancelledRunCount() const
Runs cancelled by re-crossing the start line mid-run.
Definition SprintTimer.cpp:393
void setSector3Line(double pointALat, double pointALng, double pointBLat, double pointBLng)
Sets the optional sector 3 split line (closes the segment after sector 2's, or segment 1 if sector 2 ...
Definition SprintTimer.cpp:300
int getBestLapNumber() const
Definition SprintTimer.h:149
bool isRunActive() const
True while a run is in progress (between start and finish).
Definition SprintTimer.cpp:385
unsigned long getLastRunTime() const
Definition SprintTimer.cpp:401
unsigned long getBestSector2Time() const
Definition SprintTimer.cpp:481
int getCurrentSector() const
Current segment (1..N) while a run is active, 0 while WAITING.
Definition SprintTimer.cpp:461
int getBestSector1LapNumber() const
Definition SprintTimer.cpp:489
unsigned long getCurrentLapSector1Time() const
Definition SprintTimer.cpp:465
unsigned long getBestRunTime() const
Definition SprintTimer.cpp:405
unsigned int getRejectedCrossingCount() const
Total zone exits whose interpolation was rejected, all lines.
Definition SprintTimer.cpp:516
unsigned long getCurrentLapSector2Time() const
Definition SprintTimer.cpp:469
Definition CrossingEngine.h:73