From 06f646aec4dbce64d28bae1be6111bd833f8e79e Mon Sep 17 00:00:00 2001 From: Paul Nettle Date: Fri, 25 Aug 2017 09:30:39 -0500 Subject: Initial version 1.0 --- src/DBusInterface.cpp | 202 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 202 insertions(+) create mode 100644 src/DBusInterface.cpp (limited to 'src/DBusInterface.cpp') diff --git a/src/DBusInterface.cpp b/src/DBusInterface.cpp new file mode 100644 index 0000000..d96171e --- /dev/null +++ b/src/DBusInterface.cpp @@ -0,0 +1,202 @@ +// 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 +// >> +// +// This is an abstraction layer for a D-Bus interface, the base class for all interfaces. +// +// >> +// >>> DISCUSSION +// >> +// +// Not sure what a D-Bus Interface is? Well, chedk the Readme for resources, but here's the TL;DR: +// +// A D-Bus interface is a contract (similar to programming language interfaces.) An interface defines a set of methods and +// properties for others to use. +// +// Interfaces are identified by their name, such as "org.freedesktop.DBus.Properties". In fact, if an object on the bus is found +// to have that interface, then you know that it provides an interface to access its properties via the methods "Get", "GetAll" and +// "Set". To see the details for this interface (and all of the D-Bus defined interfaces), see: +// +// https://dbus.freedesktop.org/doc/dbus-specification.html +// +// We're also interested in working with BlueZ which has their own set of interfaces. One example is "org.bluez.GattManager1" which +// is the interface used to create and register GATT services with BlueZ. +// +// Remember, interfaces are not implementations; they're just contracts to provide an implementation. That means some interfaces +// are intended for us to implement. One example is "org.bluez.GattService1" which defines the interface that we must conform to +// so that others (likely BlueZ) can access our GATT service(s). For more information on these, have a look at: +// +// https://git.kernel.org/pub/scm/bluetooth/bluez.git/plain/doc/gatt-api.txt +// +// Our interfaces also store a collection of events. Here, an event is much like a timer in modern UIs, which repeatedly fires +// after a defined time. A practical example of an event would be a BLE server that provides a Battery service. By adding a timer +// to the interface for this service, the server could wake up every minute to check the battery level and if it has changed, send +// a notifications to clients over BLE with the new battery level. This saves a lot of additional code on the server's part. +// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#include "DBusInterface.h" +#include "GattProperty.h" +#include "DBusObject.h" +#include "Logger.h" + +// +// Construction +// + +DBusInterface::DBusInterface(DBusObject &owner, const std::string &name) +: owner(owner), name(name) +{ +} + +DBusInterface::~DBusInterface() +{ +} + +// +// Interface name +// + +// Returns the name of this interface (ex: "org.freedesktop.DBus.Properties") +const std::string &DBusInterface::getName() const +{ + return name; +} + +// Sets the name of the interface (ex: "org.freedesktop.DBus.Properties") +DBusInterface &DBusInterface::setName(const std::string &name) +{ + this->name = name; + return *this; +} + +// +// Owner information +// + +// Returns the owner (DBusObject) of this interface +DBusObject &DBusInterface::getOwner() const +{ + return owner; +} + +// Returns the path node of this interface's owner +DBusObjectPath DBusInterface::getPathNode() const +{ + return owner.getPathNode(); +} + +// Returns the full path of this interface's owner +DBusObjectPath DBusInterface::getPath() const +{ + return owner.getPath(); +} + +// +// D-Bus interface methods +// + +// Add a named method to this interface +// +// This method returns a reference to `this` in order to enable chaining inside the server description. +DBusInterface &DBusInterface::addMethod(const std::string &name, const char *pInArgs[], const char *pOutArgs, DBusMethod::Callback callback) +{ + methods.push_back(DBusMethod(this, name, pInArgs, pOutArgs, callback)); + return *this; +} + +// Calls a named method on this interface +// +// This method returns false if the method could not be found, otherwise it returns true. Note that the return value is not related +// to the result of the method call itself (methods do not return values.) +// +// NOTE: Subclasses are encouraged to override this method in order to support different callback types that are specific to +// their subclass type. +bool DBusInterface::callMethod(const std::string &methodName, GDBusConnection *pConnection, GVariant *pParameters, GDBusMethodInvocation *pInvocation, gpointer pUserData) const +{ + for (const DBusMethod &method : methods) + { + if (methodName == method.getName()) + { + method.call(pConnection, getPath(), getName(), methodName, pParameters, pInvocation, pUserData); + return true; + } + } + + return false; +} + +// Add an event to this interface +// +// For details on events, see TickEvent.cpp. +// +// This method returns a reference to `this` in order to enable chaining inside the server description. +// +// NOTE: Subclasses are encouraged to overload this method in order to support different callback types that are specific to +// their subclass type. In addition, they should return their own type. This simplifies the server description by allowing +// calls to chain. +DBusInterface &DBusInterface::onEvent(int tickFrequency, void *pUserData, TickEvent::Callback callback) +{ + events.push_back(TickEvent(this, tickFrequency, callback, pUserData)); + return *this; +} + +// Ticks each event within this interface +// +// For details on events, see TickEvent.cpp. +// +// NOTE: Subclasses are encouraged to override this method in order to support different callback types that are specific to +// their subclass type. +void DBusInterface::tickEvents(GDBusConnection *pConnection, void *pUserData) const +{ + for (const TickEvent &event : events) + { + event.tick(getPath(), pConnection, pUserData); + } +} + +// Internal method used to generate introspection XML used to describe our services on D-Bus +std::string DBusInterface::generateIntrospectionXML(int depth) const +{ + std::string prefix; + prefix.insert(0, depth * 2, ' '); + + std::string xml = std::string(); + + if (methods.empty()) + { + xml += prefix + "\n"; + } + else + { + xml += prefix + "\n"; + + // Describe our methods + for (const DBusMethod &method : methods) + { + xml += method.generateIntrospectionXML(depth + 1); + } + + xml += prefix + "\n"; + } + + return xml; +} -- cgit v1.2.3