// Copyright 2017 Paul Nettle. // // This file is part of Gobbledegook. // // Gobbledegook is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // Gobbledegook is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with Gobbledegook. If not, see . // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ // // >> // >>> INSIDE THIS FILE // >> // // A TIckEvent is an event that is triggered on a regular timer interval. // // >> // >>> DISCUSSION // >> // // Tick events are used within the Server's description in Server.cpp. As you might expect, they are useful for updating data on a // regular basis or performing other periodic tasks. One example usage might be checking the battery level every 60 seconds and if // it has changed since the last update, send out a notification to subscribers. // // The frequency at which events fire is dependent upon two values: the driving timer's tick frequency multiplied by the tick // freuency of the TickEvent itself. // // The tick event's frequency is set when a tick event is added via the `onEvent()` method to the server description. // // The driving timer's frequency is a one-second-resolution low-frequency timer with a default of one second. To modify this, see // `kPeriodicTimerFrequencySeconds` at the top of Init.cpp. Note that the periodic timer (which drives tick events) is intentionally // a low-frequency timer. Higher frequency timers would lend themselves to using more battery on both, the server and client. // // When using a TickEvent, be careful not to demand too much of your client. Notifiations that are too frequent may place undue // stress on their battery to receive and process the updates. // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ #pragma once #include #include #include "DBusObjectPath.h" #include "Logger.h" namespace ggk { // --------------------------------------------------------------------------------------------------------------------------------- // Forward declarations // --------------------------------------------------------------------------------------------------------------------------------- struct DBusInterface; // --------------------------------------------------------------------------------------------------------------------------------- // Implementation // --------------------------------------------------------------------------------------------------------------------------------- struct TickEvent { // // Types // // A tick event callback, which is called whenever the TickEvent fires typedef void (*Callback)(const DBusInterface &self, const TickEvent &event, GDBusConnection *pConnection, void *pUserData); // Construct a TickEvent that will fire after a specified 'tickFrequency' number of ticks of the periodic timer. // // Note that the actual time between a callback's execution is the event's 'tickFrequency' multiplied by the time between each // periodic timer tick. TickEvent(const DBusInterface *pOwner, int tickFrequency, Callback callback, void *pUserData) : pOwner(pOwner), elapsedTicks(0), tickFrequency(tickFrequency), callback(callback), pUserData(pUserData) { } // // Accessors // // Returns the elapsed ticks since the last event firing int getElapsedTicks() const { return elapsedTicks; } // Sets the elapsed ticks since the last event firing void setElapsedTicks(int elapsed) { elapsedTicks = elapsed; } // Returns the tick frequency between schedule tick events int getTickFrequency() const { return tickFrequency; } // Sets the tick frequency between schedule tick events void setTickFrequency(int frequency) { tickFrequency = frequency; } // Returns the user data pointer associated to this TickEvent void *getUserData() { return pUserData; } // Sets the user data pointer associated to this TickEvent void setUserData(void *pUserData) { this->pUserData = pUserData; } // Gets the callback for the TickEvent Callback getCallback() const { return callback; } // Sets the callback for the TickEvent void setCallback(Callback callback) { this->callback = callback; } // // Tick management // // Perform a single tick of a TickEvent // // A TickEvent is ticked each time the periodic timer fires. The TickEvent only fires after `tickFrequency` ticks. As a result, // the `callback` is only called after a period of time equal to the time between firings of the periodic timer, multiplied by // `tickFrequency`. // // Returns true if event fires, false otherwise template void tick(const DBusObjectPath &path, GDBusConnection *pConnection, void *pUserData) const { elapsedTicks += 1; if (elapsedTicks >= tickFrequency) { if (nullptr != callback) { Logger::debug(SSTR << "Ticking at path '" << path << "'"); callback(*static_cast(pOwner), *this, pConnection, pUserData); } elapsedTicks = 0; } } private: // // Data members // const DBusInterface *pOwner; mutable int elapsedTicks; int tickFrequency; Callback callback; void *pUserData; }; }; // namespace ggk