214 lines
7.8 KiB
C++
214 lines
7.8 KiB
C++
// =============================================================================
|
|
// laser_tracker.cpp - Implementierung
|
|
// =============================================================================
|
|
|
|
#include "laser_tracker.h"
|
|
|
|
// Globale Instanz
|
|
LaserTracker laserTracker;
|
|
|
|
// ---------------------------------------------------------------------------
|
|
LaserTracker::LaserTracker()
|
|
: _debouncedActive(false)
|
|
, _pendingActive(false)
|
|
, _debounceRunning(false)
|
|
, _debounceStartMs(0)
|
|
, _state(SessionState::INACTIVE)
|
|
, _sessionStartMs(0)
|
|
, _sessionStartTime(0)
|
|
, _netStartMs(0)
|
|
, _sessionNetSec(0)
|
|
, _sessionNetMin(0)
|
|
, _totalMinutesBase(0.0f)
|
|
, _lastSessionSec(0)
|
|
, _sessionEndPending(false)
|
|
{}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
void LaserTracker::begin() {
|
|
pinMode(LASER_SIGNAL_PIN, INPUT_PULLUP);
|
|
|
|
// NVS-Gesamtzeit laden (via SettingsManager)
|
|
_totalMinutesBase = settings.get().totalMinutes;
|
|
|
|
resetSession();
|
|
Serial.printf("[LaserTracker] begin - Pin=%d totalMin=%.2f gratis=%ds pol=%s\n",
|
|
LASER_SIGNAL_PIN,
|
|
_totalMinutesBase,
|
|
gratisSeconds(),
|
|
(settings.get().signalPolarity == SIGNAL_POL_HIGH_ACTIVE) ? "HIGH" : "LOW");
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
void LaserTracker::loop() {
|
|
bool raw = readRaw();
|
|
|
|
// ------- Debounce -------------------------------------------------------
|
|
if (raw != _pendingActive) {
|
|
_pendingActive = raw;
|
|
_debounceRunning = true;
|
|
_debounceStartMs = millis();
|
|
}
|
|
|
|
if (_debounceRunning &&
|
|
(millis() - _debounceStartMs) >= (uint32_t)LASER_DEBOUNCE_MS) {
|
|
_debounceRunning = false;
|
|
if (_pendingActive != _debouncedActive) {
|
|
_debouncedActive = _pendingActive;
|
|
if (_debouncedActive) {
|
|
onSessionStart();
|
|
} else {
|
|
onSessionEnd();
|
|
}
|
|
}
|
|
}
|
|
|
|
// ------- Session-Zustandsmaschine (Timer-Uebergaenge) -----------------
|
|
if (_state == SessionState::GRATIS) {
|
|
uint32_t elapsed = (millis() - _sessionStartMs) / 1000;
|
|
if (elapsed >= (uint32_t)gratisSeconds()) {
|
|
_state = SessionState::NET_COUNTING;
|
|
_netStartMs = millis();
|
|
Serial.println("[LaserTracker] GRATIS abgelaufen -> NET_COUNTING");
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Ereignis: Laser AN (nach Debounce)
|
|
void LaserTracker::onSessionStart() {
|
|
_state = SessionState::GRATIS;
|
|
_sessionStartMs = millis();
|
|
_sessionStartTime = time(nullptr);
|
|
_netStartMs = 0;
|
|
Serial.println("[LaserTracker] SessionStart -> GRATIS");
|
|
}
|
|
|
|
time_t LaserTracker::getSessionStartTime() const {
|
|
return _sessionStartTime;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Ereignis: Laser AUS (nach Debounce)
|
|
void LaserTracker::onSessionEnd() {
|
|
// Gesamte Session-Dauer (inkl. Gratiszeit) -> NVS
|
|
int totalSessionSec = (int)((millis() - _sessionStartMs) / 1000);
|
|
|
|
if (_state == SessionState::NET_COUNTING) {
|
|
int netSec = (int)((millis() - _netStartMs) / 1000);
|
|
_sessionNetSec += netSec; // Display: nur Netto (ohne Gratis)
|
|
_sessionNetMin += (netSec + 59) / 60; // Ceiling pro Session
|
|
_lastSessionSec = netSec;
|
|
_totalMinutesBase += totalSessionSec / 60.0f; // NVS: Netto + Gratis
|
|
|
|
// NVS via SettingsManager speichern
|
|
settings.saveTotalMinutes(_totalMinutesBase);
|
|
|
|
Serial.printf("[LaserTracker] SessionEnd: gesamt=%ds netto=%ds "
|
|
"sessionNetSec=%d total=%.2fmin\n",
|
|
totalSessionSec, netSec, _sessionNetSec, _totalMinutesBase);
|
|
} else if (_state == SessionState::GRATIS) {
|
|
// Laser ging aus bevor Gratiszeit ablief -> nur Gratiszeit in NVS, keine Session
|
|
_lastSessionSec = 0;
|
|
_totalMinutesBase += totalSessionSec / 60.0f;
|
|
|
|
settings.saveTotalMinutes(_totalMinutesBase);
|
|
|
|
Serial.printf("[LaserTracker] SessionEnd: nur Gratiszeit gesamt=%ds "
|
|
"total=%.2fmin\n", totalSessionSec, _totalMinutesBase);
|
|
}
|
|
_state = SessionState::INACTIVE;
|
|
_sessionEndPending = true; // Fuer consumeSessionEnd() in main
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Laufende Netto-Sekunden der aktuellen Session (live, waehrend NET_COUNTING)
|
|
int LaserTracker::currentSessionNetSec() const {
|
|
if (_state != SessionState::NET_COUNTING) return 0;
|
|
return (int)((millis() - _netStartMs) / 1000);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
int LaserTracker::getAllSessionsSumMinutes() const {
|
|
// Pro Session aufgerundete Minuten + laufende Session (ebenfalls Ceiling)
|
|
int liveSec = currentSessionNetSec();
|
|
int liveMin = (liveSec > 0) ? (liveSec + 59) / 60 : 0;
|
|
return _sessionNetMin + liveMin;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
int LaserTracker::getCountdownRemaining() const {
|
|
if (_state != SessionState::GRATIS) return 0;
|
|
int elapsed = (int)((millis() - _sessionStartMs) / 1000);
|
|
int rem = gratisSeconds() - elapsed;
|
|
return (rem > 0) ? rem : 0;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
bool LaserTracker::isActive() const {
|
|
return _debouncedActive;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
float LaserTracker::getTotalMinutes() const {
|
|
return _totalMinutesBase + (_sessionNetSec + currentSessionNetSec()) / 60.0f;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
int LaserTracker::getLastSessionSeconds() const {
|
|
return _lastSessionSec;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
int LaserTracker::getRunningSessionSeconds() const {
|
|
return currentSessionNetSec();
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
void LaserTracker::resetSession() {
|
|
_sessionNetSec = 0;
|
|
_sessionNetMin = 0;
|
|
Serial.println("[LaserTracker] Session zurueckgesetzt (NVS unveraendert)");
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
void LaserTracker::resetTotal() {
|
|
_totalMinutesBase = 0.0f;
|
|
settings.saveTotalMinutes(0.0f);
|
|
resetSession();
|
|
Serial.println("[LaserTracker] Gesamtzeit und Session auf 0 gesetzt");
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
void LaserTracker::printToSerial() const {
|
|
const char* stateStr = "INACTIVE";
|
|
if (_state == SessionState::GRATIS) stateStr = "GRATIS";
|
|
if (_state == SessionState::NET_COUNTING) stateStr = "NET_COUNTING";
|
|
|
|
Serial.printf("[LaserTracker] state=%-12s active=%d sessionMin=%d "
|
|
"countdown=%ds totalMin=%.2f\n",
|
|
stateStr, _debouncedActive, getAllSessionsSumMinutes(),
|
|
getCountdownRemaining(), getTotalMinutes());
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// Einmalig true wenn eine Session gerade beendet wurde (consume-Semantik)
|
|
bool LaserTracker::consumeSessionEnd() {
|
|
if (_sessionEndPending) {
|
|
_sessionEndPending = false;
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
bool LaserTracker::readRaw() const {
|
|
bool pinHigh = digitalRead(LASER_SIGNAL_PIN);
|
|
// SIGNAL_POL_HIGH_ACTIVE: HIGH = Laser AN
|
|
// SIGNAL_POL_LOW_ACTIVE: LOW = Laser AN (INPUT_PULLUP Standard)
|
|
return (settings.get().signalPolarity == SIGNAL_POL_HIGH_ACTIVE) ? pinHigh : !pinHigh;
|
|
}
|
|
|
|
int LaserTracker::gratisSeconds() const {
|
|
return (int)settings.get().gratisSeconds;
|
|
} |