MQTT-Display-LaserCutter/src/laser_tracker.cpp

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;
}