// 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 our abstraction layer for GATT interfaces, used by GattService, GattCharacteristic & GattDescriptor
//
// >>
// >>> DISCUSSION
// >>
//
// See the discussion at the top of GattInterface.cpp
// ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
#pragma once
#include
#include
#include
#include "TickEvent.h"
#include "DBusInterface.h"
#include "GattProperty.h"
#include "GattUuid.h"
#include "Server.h"
#include "Utils.h"
namespace ggk {
// ---------------------------------------------------------------------------------------------------------------------------------
// Forward declarations
// ---------------------------------------------------------------------------------------------------------------------------------
struct GattInterface;
struct DBusObject;
// ---------------------------------------------------------------------------------------------------------------------------------
// Pure virtual representation of a Bluetooth GATT Interface, the base class for Services, Characteristics and Descriptors
// ---------------------------------------------------------------------------------------------------------------------------------
struct GattInterface : DBusInterface
{
// Standard constructor
GattInterface(DBusObject &owner, const std::string &name);
virtual ~GattInterface();
// Returns a string identifying the type of interface
virtual const std::string getInterfaceType() const = 0;
//
// GATT Characteristic properties
//
// Returns the list of GATT properties
const std::list &getProperties() const;
// Add a `GattProperty` to the interface
//
// There are helper methods for adding properties for common types as well as a generalized helper method for adding a
// `GattProperty` of a generic GVariant * type.
template
T &addProperty(const GattProperty &property)
{
properties.push_back(property);
return *static_cast(this);
}
// Add a named property with a GVariant *
//
// There are helper methods for common types (UUIDs, strings, boolean, etc.) Use this method when no helper method exists for
// the type you want to use. There is also a helper method for adding a named property of a pre-built `GattProperty`.
template
T &addProperty(const std::string &name, GVariant *pValue, GDBusInterfaceGetPropertyFunc getter = nullptr, GDBusInterfaceSetPropertyFunc setter = nullptr)
{
return addProperty(GattProperty(name, pValue, getter, setter));
}
// Helper method for adding a named property with a `GattUuid`
template
T &addProperty(const std::string &name, const GattUuid &uuid, GDBusInterfaceGetPropertyFunc getter = nullptr, GDBusInterfaceSetPropertyFunc setter = nullptr)
{
return addProperty(GattProperty(name, Utils::gvariantFromString(uuid.toString128().c_str()), getter, setter));
}
// Helper method for adding a named property with a `DBusObjectPath`
template
T &addProperty(const std::string &name, const DBusObjectPath &path, GDBusInterfaceGetPropertyFunc getter = nullptr, GDBusInterfaceSetPropertyFunc setter = nullptr)
{
return addProperty(GattProperty(name, Utils::gvariantFromObject(path), getter, setter));
}
// Helper method for adding a named property with a std::strings
template
T &addProperty(const std::string &name, const std::string &str, GDBusInterfaceGetPropertyFunc getter = nullptr, GDBusInterfaceSetPropertyFunc setter = nullptr)
{
return addProperty(GattProperty(name, Utils::gvariantFromString(str), getter, setter));
}
// Helper method for adding a named property with an array of std::strings
template
T &addProperty(const std::string &name, const std::vector &arr, GDBusInterfaceGetPropertyFunc getter = nullptr, GDBusInterfaceSetPropertyFunc setter = nullptr)
{
return addProperty(GattProperty(name, Utils::gvariantFromStringArray(arr), getter, setter));
}
// Helper method for adding a named property with an array of C strings
template
T &addProperty(const std::string &name, const std::vector &arr, GDBusInterfaceGetPropertyFunc getter = nullptr, GDBusInterfaceSetPropertyFunc setter = nullptr)
{
return addProperty(GattProperty(name, Utils::gvariantFromStringArray(arr), getter, setter));
}
// Helper method for adding a named property with a given C string
template
T &addProperty(const std::string &name, const char *pStr, GDBusInterfaceGetPropertyFunc getter = nullptr, GDBusInterfaceSetPropertyFunc setter = nullptr)
{
return addProperty(GattProperty(name, Utils::gvariantFromString(pStr), getter, setter));
}
// Helper method for adding a named property with a given boolean value
template
T &addProperty(const std::string &name, bool value, GDBusInterfaceGetPropertyFunc getter = nullptr, GDBusInterfaceSetPropertyFunc setter = nullptr)
{
return addProperty(GattProperty(name, Utils::gvariantFromBoolean(value), getter, setter));
}
// Return a data value from the server's registered data getter (GGKServerDataGetter)
//
// This method is for use with non-pointer types. For pointer types, use `getDataPointer()` instead.
//
// This method is intended to be used in the server description. An example usage would be:
//
// uint8_t batteryLevel = self.getDataValue("battery/level", 0);
template
T getDataValue(const char *pName, const T defaultValue) const
{
const void *pData = TheServer->getDataGetter()(pName);
return nullptr == pData ? defaultValue : *static_cast(pData);
}
// Return a data pointer from the server's registered data getter (GGKServerDataGetter)
//
// This method is for use with pointer types. For non-pointer types, use `getDataValue()` instead.
//
// This method is intended to be used in the server description. An example usage would be:
//
// const char *pTextString = self.getDataPointer("text/string", "");
template
T getDataPointer(const char *pName, const T defaultValue) const
{
const void *pData = TheServer->getDataGetter()(pName);
return nullptr == pData ? defaultValue : static_cast(pData);
}
// Sends a data value from the server back to the application through the server's registered data setter
// (GGKServerDataSetter)
//
// This method is for use with non-pointer types. For pointer types, use `setDataPointer()` instead.
//
// This method is intended to be used in the server description. An example usage would be:
//
// self.setDataValue("battery/level", batteryLevel);
template
bool setDataValue(const char *pName, const T value) const
{
return TheServer->getDataSetter()(pName, static_cast(&value)) != 0;
}
// Sends a data pointer from the server back to the application through the server's registered data setter
// (GGKServerDataSetter)
//
// This method is for use with pointer types. For non-pointer types, use `setDataValue()` instead.
//
// This method is intended to be used in the server description. An example usage would be:
//
// self.setDataPointer("text/string", stringFromGVariantByteArray(pAyBuffer).c_str());
template
bool setDataPointer(const char *pName, const T pointer) const
{
return TheServer->getDataSetter()(pName, static_cast(pointer)) != 0;
}
// When responding to a ReadValue method, we need to return a GVariant value in the form "(ay)" (a tuple containing an array of
// bytes). This method will simplify this slightly by wrapping a GVariant of the type "ay" and wrapping it in a tuple before
// sending it off as the method response.
//
// This is the generalized form that accepts a GVariant *. There is a templated helper method (`methodReturnValue()`) that accepts
// common types.
void methodReturnVariant(GDBusMethodInvocation *pInvocation, GVariant *pVariant, bool wrapInTuple = false) const;
// When responding to a ReadValue method, we need to return a GVariant value in the form "(ay)" (a tuple containing an array of
// bytes). This method will simplify this slightly by wrapping a GVariant of the type "ay" and wrapping it in a tuple before
// sending it off as the method response.
//
// This is a templated helper method that only works with common types. For a more generic form which can be used for custom
// types, see `methodReturnVariant()'.
template
void methodReturnValue(GDBusMethodInvocation *pInvocation, T value, bool wrapInTuple = false) const
{
GVariant *pVariant = Utils::gvariantFromByteArray(value);
methodReturnVariant(pInvocation, pVariant, wrapInTuple);
}
// Locates a `GattProperty` within the interface
//
// This method returns a pointer to the property or nullptr if not found
const GattProperty *findProperty(const std::string &name) const;
// Internal method used to generate introspection XML used to describe our services on D-Bus
virtual std::string generateIntrospectionXML(int depth) const;
protected:
std::list properties;
};
}; // namespace ggk