#include <algorithm>
#include "Server.h"
#include "ServerUtils.h"
#include "Utils.h"
#include "Globals.h"
#include "DBusObject.h"
#include "DBusInterface.h"
#include "GattProperty.h"
#include "GattService.h"
#include "GattUuid.h"
#include "GattCharacteristic.h"
#include "GattDescriptor.h"
#include "Logger.h"
namespace ggk {
#if defined(__GNUC__) && defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-parameter"
#endif
#if defined(__GNUC__) && !defined(__clang__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wunused-parameter"
#endif
std::shared_ptr<Server> TheServer = nullptr;
Server::Server(const std::string &serviceName, const std::string &advertisingName, const std::string &advertisingShortName,
GGKServerDataGetter getter, GGKServerDataSetter setter)
{
this->serviceName = serviceName;
std::transform(this->serviceName.begin(), this->serviceName.end(), this->serviceName.begin(), ::tolower);
this->advertisingName = advertisingName;
this->advertisingShortName = advertisingShortName;
dataGetter = getter;
dataSetter = setter;
enableBREDR = false;
enableSecureConnection = false;
enableConnectable = true;
enableAdvertising = true;
enableBondable = false;
objects.push_back(DBusObject(DBusObjectPath() + "com" + getServiceName()));
objects.back()
.gattServiceBegin("device", "180A")
.gattCharacteristicBegin("mfgr_name", "2A29", {"read"})
.onReadValue(CHARACTERISTIC_METHOD_CALLBACK_LAMBDA
{
self.methodReturnValue(pInvocation, "thenautilus", true);
})
.gattCharacteristicEnd()
.gattCharacteristicBegin("model_num", "2A24", {"read"})
.onReadValue(CHARACTERISTIC_METHOD_CALLBACK_LAMBDA
{
self.methodReturnValue(pInvocation, "thermo-store", true);
})
.gattCharacteristicEnd()
.gattServiceEnd()
.gattServiceBegin("thermo", "11111111-2222-3333-4444-000000000000")
.gattCharacteristicBegin("temperature", "11111111-2222-3333-4444-000000000001", {"read","write"})
.onReadValue(CHARACTERISTIC_METHOD_CALLBACK_LAMBDA
{
const char *fake_temp = "0";
self.methodReturnValue(pInvocation, fake_temp, true);
})
.onWriteValue(CHARACTERISTIC_METHOD_CALLBACK_LAMBDA
{
GVariant *pValue = g_variant_get_child_value(pParameters, 0);
self.setDataPointer("temperature", Utils::stringFromGVariantByteArray(pValue).c_str());
})
.gattDescriptorBegin("description", "2901", {"read"})
.onReadValue(DESCRIPTOR_METHOD_CALLBACK_LAMBDA
{
const char *pDescription = "temperature in a room";
self.methodReturnValue(pInvocation, pDescription, true);
})
.gattDescriptorEnd()
.gattCharacteristicEnd()
.gattCharacteristicBegin("time_to_next_reading", "11111111-2222-3333-4444-000000000002", {"read"})
.onReadValue(CHARACTERISTIC_METHOD_CALLBACK_LAMBDA
{
const char *time = self.getDataPointer<const char*>("time-to-next-sample", "");
self.methodReturnValue(pInvocation, time, true);
})
.gattDescriptorBegin("description", "2901", {"read"})
.onReadValue(DESCRIPTOR_METHOD_CALLBACK_LAMBDA
{
const char *pDescription = "time (in seconds) to wait before sending the next temperature reading";
self.methodReturnValue(pInvocation, pDescription, true);
})
.gattDescriptorEnd()
.gattCharacteristicEnd()
.gattServiceEnd()
;
objects.push_back(DBusObject(DBusObjectPath(), false));
DBusObject &objectManager = objects.back();
auto omInterface = std::make_shared<DBusInterface>(objectManager, "org.freedesktop.DBus.ObjectManager");
objectManager.addInterface(omInterface);
const char *pInArgs[] = { nullptr };
const char *pOutArgs = "a{oa{sa{sv}}}";
omInterface->addMethod("GetManagedObjects", pInArgs, pOutArgs, INTERFACE_METHOD_CALLBACK_LAMBDA
{
ServerUtils::getManagedObjects(pInvocation);
});
}
std::shared_ptr<const DBusInterface> Server::findInterface(const DBusObjectPath &objectPath, const std::string &interfaceName) const
{
for (const DBusObject &object : objects)
{
std::shared_ptr<const DBusInterface> pInterface = object.findInterface(objectPath, interfaceName);
if (pInterface != nullptr)
{
return pInterface;
}
}
return nullptr;
}
bool Server::callMethod(const DBusObjectPath &objectPath, const std::string &interfaceName, const std::string &methodName, GDBusConnection *pConnection, GVariant *pParameters, GDBusMethodInvocation *pInvocation, gpointer pUserData) const
{
for (const DBusObject &object : objects)
{
if (object.callMethod(objectPath, interfaceName, methodName, pConnection, pParameters, pInvocation, pUserData))
{
return true;
}
}
return false;
}
const GattProperty *Server::findProperty(const DBusObjectPath &objectPath, const std::string &interfaceName, const std::string &propertyName) const
{
std::shared_ptr<const DBusInterface> pInterface = findInterface(objectPath, interfaceName);
if (std::shared_ptr<const GattInterface> pGattInterface = TRY_GET_CONST_INTERFACE_OF_TYPE(pInterface, GattInterface))
{
return pGattInterface->findProperty(propertyName);
}
else if (std::shared_ptr<const GattService> pGattInterface = TRY_GET_CONST_INTERFACE_OF_TYPE(pInterface, GattService))
{
return pGattInterface->findProperty(propertyName);
}
else if (std::shared_ptr<const GattCharacteristic> pGattInterface = TRY_GET_CONST_INTERFACE_OF_TYPE(pInterface, GattCharacteristic))
{
return pGattInterface->findProperty(propertyName);
}
return nullptr;
}
};