#pragma once #include #include #include "clock_model.h" #include "event_bus.h" #include "service.h" #include "settings.h" namespace roro { // Holds wall-clock time. Sources (GNSS in M2, NTP in M1, mesh in M4) call set(). class ClockService : public Service { public: ClockService(const Settings& settings, EventBus& bus) : settings_(settings) { bus.subscribe(EventType::SettingChanged, [this](const Event& e) { if (e.a == static_cast(Setting::Timezone)) applyTimezone(); }); } const char* name() const override { return "clock"; } void start() override { applyTimezone(); } bool set(int64_t utcSeconds, TimeSource source) { if (!model_.set(utcSeconds, source, millis())) return false; // The system's own clock too (F1, Q137): the card's files are dated from it, and NTP was // the only thing setting it. NTP has just done so itself. if (source != TimeSource::Ntp) { timeval now = {static_cast(utcSeconds), 0}; settimeofday(&now, nullptr); } return true; } const ClockModel& model() const { return model_; } // UTC seconds, or -1 if the clock isn't set. int64_t utcNow() const { return model_.isSet() ? model_.utcNow(millis()) : -1; } // Local "YYYY-MM-DD" once set; otherwise empty (Logs then go to undated files). std::string localDate() const { return model_.isSet() ? ClockModel::formatLocalDate(model_.utcNow(millis())) : ""; } // Days since 1970-01-01 (UTC), or -1 if the clock isn't set. int today() const { return model_.isSet() ? static_cast(model_.utcNow(millis()) / 86400) : -1; } // "14:05" once set; otherwise "--:--". std::string displayTime() const { return model_.isSet() ? ClockModel::formatLocalTime(model_.utcNow(millis())) : "--:--"; } private: void applyTimezone() { ClockModel::applyTimezone(settings_.getString(Setting::Timezone).c_str()); } const Settings& settings_; ClockModel model_; }; } // namespace roro