blob: 7c9ac5dacd735ac8c38093c1ba55ae665da24c01 [file] [log] [blame]
/*
*
* Copyright (c) 2017 Nest Labs, Inc.
* All rights reserved.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @file
* This file provides Weave over Bluez Peripheral implementation, which uses Bluez DBUS APIs.
*
*/
#include "BluezHelperCode.h"
#include "BluezBleDelegates.h"
#if CONFIG_BLE_PLATFORM_BLUEZ
extern nl::Ble::Platform::BlueZ::BluezBlePlatformDelegate *getBluezPlatformDelegate();
namespace nl {
namespace Ble {
namespace Platform {
namespace BlueZ {
static BluezServerEndpoint *gBluezServerEndpoint;
static GMainLoop *gBluezMainLoop;
static DBusConnection *gBluezDbusConn;
static Adapter *gDefaultAdapter;
static bool gAdapterFound = false;
static void WeaveRegisterSetup(DBusMessageIter *iter, void *bluezData)
{
DBusMessageIter dict;
const char *path = ADVERTISING_PATH;
gboolean success = FALSE;
const char * msg = NULL;
success = dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
VerifyOrExit(success == TRUE, msg = "Fail to append basic in WeaveRegisterSetup");
success = dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
DBUS_TYPE_STRING_AS_STRING
DBUS_TYPE_VARIANT_AS_STRING
DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
VerifyOrExit(success == TRUE, msg = "Fail to open container in WeaveRegisterSetup");
success = dbus_message_iter_close_container(iter, &dict);
VerifyOrExit(success == TRUE, msg = "Fail to close container in WeaveRegisterSetup");
exit:
if ((success != TRUE) && (msg != NULL))
{
WeaveLogDetail(Ble, msg);
}
}
static void WeaveRegisterReply(DBusMessage *message, void *bluezData)
{
DBusConnection *dbusConn = static_cast<DBusConnection *>(bluezData);
DBusError error;
dbus_error_init(&error);
if (TRUE == dbus_set_error_from_message(&error, message))
{
WeaveLogDetail(Ble, "Fail to register weave advertisement in WeaveRegisterReply: %s", error.name);
dbus_error_free(&error);
if (FALSE == g_dbus_unregister_interface(dbusConn, ADVERTISING_PATH, ADVERTISING_INTERFACE))
{
WeaveLogDetail(Ble, "Fail to unregister weave advertisement in WeaveRegisterReply");
}
}
else
{
WeaveLogDetail(Ble, "Weave advertisement object registered");
}
}
static gboolean WeaveAdvertisingGetType(const GDBusPropertyTable *property, DBusMessageIter *iter, void *bluezData)
{
gboolean success = dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &(gBluezServerEndpoint->advertisingType));
if (FALSE == success)
{
WeaveLogDetail(Ble, "Fail to get advertising type in WeaveAdvertisingGetType");
}
return success;
}
static gboolean GetWeaveUUIDs(const GDBusPropertyTable *property, DBusMessageIter *iter, void *bluezData)
{
const char * msg = NULL;
gboolean success = FALSE;
DBusMessageIter dbusArray;
success = dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "as", &dbusArray);
VerifyOrExit(success == TRUE, msg = "Fail to open container in GetWeaveUUIDs");
success = dbus_message_iter_append_basic(&dbusArray, DBUS_TYPE_STRING, &(gBluezServerEndpoint->advertisingUUID));
VerifyOrExit(success == TRUE, msg = "Fail to append basic in GetWeaveUUIDs");
success = dbus_message_iter_close_container(iter, &dbusArray);
VerifyOrExit(success == TRUE, msg = "Fail to close container in GetWeaveUUIDs");
exit:
if ((success != TRUE) && (msg != NULL))
{
WeaveLogDetail(Ble, msg);
}
return success;
}
static gboolean WeaveNameCheck(const GDBusPropertyTable *property, void *bluezData)
{
gboolean success = FALSE;
if (NULL != gBluezServerEndpoint->adapterName)
{
success = TRUE;
}
return success;
}
static gboolean WeaveGetName(const GDBusPropertyTable *property, DBusMessageIter *iter, void *bluezData)
{
gboolean success = dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &(gBluezServerEndpoint->adapterName));
if (FALSE == success)
{
WeaveLogDetail(Ble, "Fail to get Weave Local name in WeaveGetName");
}
return success;
}
static DBusMessage *WeaveDestroyAdvertising(DBusConnection *dbusConn, DBusMessage *dbusMsg, void *bluezData)
{
if (FALSE == g_dbus_unregister_interface(dbusConn, ADVERTISING_PATH, ADVERTISING_INTERFACE))
{
WeaveLogDetail(Ble, "Fail to destroy advertising object in WeaveDestroyAdvertising");
}
return dbus_message_new_method_return(dbusMsg);
}
static const GDBusMethodTable weaveAdvertisingMethods[] = {
{"Release", WeaveDestroyAdvertising, (GDBusMethodFlags)0, 0, NULL, NULL},
{ }
};
static const GDBusPropertyTable weaveAdvertisingProperties[] = {
{ "Type", "s", WeaveAdvertisingGetType },
{ "ServiceUUIDs", "as", GetWeaveUUIDs, NULL, NULL },
{ "LocalName", "s", WeaveGetName, NULL, WeaveNameCheck },
{ }
};
gboolean AdvertisingRegister(DBusConnection *dbusConn, GDBusProxy *proxy)
{
gboolean success = FALSE;
const char * msg = NULL;
success = g_dbus_register_interface(dbusConn, ADVERTISING_PATH, ADVERTISING_INTERFACE, weaveAdvertisingMethods, NULL, weaveAdvertisingProperties, NULL, NULL);
VerifyOrExit(success == TRUE, msg = "Failed to register advertising object in AdvertisingRegister");
success = g_dbus_proxy_method_call(proxy, "RegisterAdvertisement", WeaveRegisterSetup, WeaveRegisterReply, dbusConn, NULL);
VerifyOrExit(success == TRUE, msg = "Failed to call RegisterAdvertisement in AdvertisingRegister");
exit:
if ((success != TRUE) && (msg != NULL))
{
WeaveLogDetail(Ble, msg);
}
return success;
}
static DBusMessage *WeaveDestroyProfile(DBusConnection *dbusConn, DBusMessage *dbusMsg, void *bluezData)
{
if (FALSE == g_dbus_unregister_interface(dbusConn, WEAVE_PATH, PROFILE_INTERFACE))
{
WeaveLogDetail(Ble, "Failed to destroy advertising object in WeaveDestroyProfile");
}
return dbus_message_new_method_return(dbusMsg);
}
static void RegisterWeaveAppSetup(DBusMessageIter *iter, void *bluezData)
{
DBusMessageIter dict;
const char *path = "/";
gboolean success = FALSE;
const char * msg = NULL;
success = dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
VerifyOrExit(success == TRUE, msg = "Fail to append basic in RegisterWeaveAppSetup");
success = dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
DBUS_TYPE_STRING_AS_STRING
DBUS_TYPE_VARIANT_AS_STRING
DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
&dict);
VerifyOrExit(success == TRUE, msg = "Fail to open container in RegisterWeaveAppSetup");
success = dbus_message_iter_close_container(iter, &dict);
VerifyOrExit(success == TRUE, msg = "Fail to close container in RegisterWeaveAppSetup");
exit:
if ((success != TRUE) && (msg != NULL))
{
WeaveLogDetail(Ble, msg);
}
}
static void RegisterWeaveAppReply(DBusMessage *message, void *bluezData)
{
DBusError error;
dbus_error_init(&error);
if (TRUE == dbus_set_error_from_message(&error, message)) {
WeaveLogDetail(Ble, "Failed to setup weave application in RegisterWeaveAppReply: %s", error.name);
dbus_error_free(&error);
}
}
static const GDBusMethodTable weaveAppMethods[] = {
{"Release", WeaveDestroyProfile, GDBusMethodFlags(0), 0, NULL, NULL },
{ }
};
static const GDBusPropertyTable weaveAppProperties[] = {
{ "UUIDs", "as", GetWeaveUUIDs },
{ }
};
gboolean SetupWeaveApp(DBusConnection *dbusConn, GDBusProxy *proxy)
{
gboolean success = FALSE;
const char * msg = NULL;
success = g_dbus_register_interface(dbusConn, WEAVE_PATH, PROFILE_INTERFACE, weaveAppMethods, NULL, weaveAppProperties, NULL, NULL);
VerifyOrExit(success == TRUE, msg = "Fail in register interface in SetupWeaveApp");
success = g_dbus_proxy_method_call(proxy, "RegisterApplication", RegisterWeaveAppSetup, RegisterWeaveAppReply, NULL, NULL);
if (FALSE == success)
{
msg = "Fail to call RegisterApplication in SetupWeaveApp";
g_dbus_unregister_interface(dbusConn, WEAVE_PATH, PROFILE_INTERFACE);
ExitNow();
}
exit:
if ((success != TRUE) && (msg != NULL))
{
WeaveLogDetail(Ble, msg);
}
return success;
}
static void WeaveCharacteristicDestroy(void *bluezData)
{
Characteristic *WeaveCharacteristic = static_cast<Characteristic *>(bluezData);
if(NULL != WeaveCharacteristic)
{
if (NULL != WeaveCharacteristic->path)
{
g_free(WeaveCharacteristic->path);
}
if (NULL != WeaveCharacteristic->servicePath)
{
g_free(WeaveCharacteristic->servicePath);
}
if(NULL != WeaveCharacteristic->uuid)
{
g_free(WeaveCharacteristic->uuid);
}
if(NULL != WeaveCharacteristic->flags)
{
g_strfreev(WeaveCharacteristic->flags);
}
g_free(WeaveCharacteristic);
}
}
static gboolean WeaveServiceGetUUID(const GDBusPropertyTable *property, DBusMessageIter *iter, void *bluezData)
{
Service *weaveService = static_cast<Service *>(bluezData);
gboolean success = dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &weaveService->uuid);
if (FALSE == success)
{
WeaveLogDetail(Ble, "Failed to get weave service uuid property in WeaveServiceGetUUID");
}
return success;
}
static gboolean WeaveServiceGetPrimary(const GDBusPropertyTable *property, DBusMessageIter *iter, void *bluezData)
{
Service *weaveService = static_cast<Service *>(bluezData);
dbus_bool_t servicePrimary;
gboolean success = FALSE;
const char * msg = NULL;
VerifyOrExit(weaveService != NULL, msg = "weaveService is NULL in WeaveServiceGetPrimary");
servicePrimary = weaveService->isPrimary ? TRUE : FALSE;
success = dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &servicePrimary);
VerifyOrExit(success == TRUE, msg = "Failed to get weave service primary property in WeaveServiceGetPrimary");
exit:
if ((success != TRUE) && (msg != NULL))
{
WeaveLogDetail(Ble, msg);
}
return success;
}
static const GDBusPropertyTable serviceProperties[] = {
{ "UUID", "s", WeaveServiceGetUUID },
{ "Primary", "b", WeaveServiceGetPrimary },
{ }
};
static void ServiceDestroy(void *bluezData)
{
Service *weaveService = static_cast<Service *>(bluezData);
if (NULL != weaveService)
{
if (NULL != weaveService->path)
g_free(weaveService->path);
if (NULL != weaveService->uuid)
g_free(weaveService->uuid);
g_free(weaveService);
}
}
gboolean RegisterWeaveService(DBusConnection *dbusConn)
{
gboolean success = FALSE;
const char * msg = NULL;
Service *weaveService;
weaveService = g_new0(Service, 1);
VerifyOrExit(weaveService != NULL, msg = "weaveService is NULL in RegisterWeaveService");
weaveService->dbusConn = dbusConn;
weaveService->path = g_strdup_printf("%s/WeaveService%p", WEAVE_PATH, weaveService);
weaveService->isPrimary = true;
weaveService->uuid = g_strdup(UUID_WEAVE);
success = g_dbus_register_interface(dbusConn, weaveService->path,
SERVICE_INTERFACE, NULL, NULL,
serviceProperties, weaveService,
ServiceDestroy);
if (FALSE == success)
{
msg = "Failed to register weave service";
ServiceDestroy(weaveService);
weaveService = NULL;
}
gBluezServerEndpoint->weaveService = weaveService;
exit:
if ((success != TRUE) && (msg != NULL))
{
WeaveLogDetail(Ble, msg);
}
return success;
}
static gboolean CharacteristicGetUUID(const GDBusPropertyTable *property, DBusMessageIter *iter, void *bluezData)
{
Characteristic *characteristic = static_cast<Characteristic *>(bluezData);
const char * msg = NULL;
gboolean success = FALSE;
VerifyOrExit(characteristic != NULL, msg = "characteristic is NULL in CharacteristicGetUUID");
success = dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &characteristic->uuid);
VerifyOrExit(success == TRUE, msg = "Fail to append basic in CharacteristicGetUUID");
exit:
if ((success != TRUE) && (msg != NULL))
{
WeaveLogDetail(Ble, msg);
}
return success;
}
static gboolean CharacteristicGetService(const GDBusPropertyTable *property, DBusMessageIter *iter, void *bluezData)
{
Characteristic *characteristic = static_cast<Characteristic *>(bluezData);
const char * msg = NULL;
gboolean success = FALSE;
VerifyOrExit(characteristic != NULL, msg = "characteristic is NULL in CharacteristicGetService");
success = dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &characteristic->servicePath);
VerifyOrExit(success == TRUE, msg = "Fail to append basic in CharacteristicGetService");
exit:
if ((success != TRUE) && (msg != NULL))
{
WeaveLogDetail(Ble, msg);
}
return success;
}
static gboolean CharacteristicGetValue(const GDBusPropertyTable *property, DBusMessageIter *iter, void *bluezData)
{
Characteristic *characteristic = static_cast<Characteristic *>(bluezData);
DBusMessageIter array;
const char * msg = NULL;
gboolean success = FALSE;
VerifyOrExit(characteristic != NULL, msg = "characteristic is NULL in CharacteristicGetValue");
success = dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "y", &array);
VerifyOrExit(success == TRUE, msg = "Fail to open container in CharacteristicGetValue");
success = dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, &characteristic->value, characteristic->valueLen);
VerifyOrExit(success == TRUE, msg = "Fail to append array in CharacteristicGetValue");
success = dbus_message_iter_close_container(iter, &array);
VerifyOrExit(success == TRUE, msg = "Fail to close container in CharacteristicGetValue");
exit:
if ((success != TRUE) && (msg != NULL))
{
WeaveLogDetail(Ble, msg);
}
return success;
}
static gboolean CharacteristicGetNotifying(const GDBusPropertyTable *property, DBusMessageIter *iter, void *bluezData)
{
Characteristic *characteristic = static_cast<Characteristic *>(bluezData);
dbus_bool_t characteristicNotify;
const char * msg = NULL;
gboolean success = FALSE;
VerifyOrExit(characteristic != NULL, msg = "characteristic is NULL in CharacteristicGetNotifying");
characteristicNotify = characteristic->isNotifying ? TRUE : FALSE;
success = dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &characteristicNotify);
VerifyOrExit(success == TRUE, msg = "Fail to append basic in CharacteristicGetNotifying");
exit:
if ((success != TRUE) && (msg != NULL))
{
WeaveLogDetail(Ble, msg);
}
return success;
}
static gboolean CharacteristicGetFlags(const GDBusPropertyTable *property, DBusMessageIter *iter, void *bluezData)
{
Characteristic *characteristic = static_cast<Characteristic *>(bluezData);
int flagIndex = 0;
DBusMessageIter array;
const char * msg = NULL;
gboolean success = FALSE;
VerifyOrExit(characteristic != NULL, msg = "characteristic is NULL in CharacteristicGetFlags");
success = dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &array);
VerifyOrExit(success == TRUE, msg = "Fail to open container in CharacteristicGetFlags");
while (characteristic->flags[flagIndex])
{
success = dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &characteristic->flags[flagIndex]);
VerifyOrExit(success == TRUE, msg = "Fail to append array in CharacteristicGetFlags");
flagIndex++;
}
success = dbus_message_iter_close_container(iter, &array);
VerifyOrExit(success == TRUE, msg = "Fail to close container in CharacteristicGetFlags");
exit:
if ((success != TRUE) && (msg != NULL))
{
WeaveLogDetail(Ble, msg);
}
return success;
}
static DBusMessage *CharacteristicRead(DBusConnection *dbusConn, DBusMessage *dbusMsg, void *bluezData)
{
Characteristic *characteristic = static_cast<Characteristic *>(bluezData);
DBusMessage *readReply;
DBusMessageIter iter, array;
const char * msg = NULL;
gboolean success = FALSE;
readReply = g_dbus_create_reply(dbusMsg, DBUS_TYPE_INVALID);
dbus_message_iter_init_append(readReply, &iter);
VerifyOrExit(characteristic != NULL, msg = "characteristic is NULL in CharacteristicRead");
success = dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "y", &array);
VerifyOrExit(success == TRUE, msg = "Fail to open container in CharacteristicRead");
success = dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE, &(characteristic->value), characteristic->valueLen);
VerifyOrExit(success == TRUE, msg = "Fail to append fixed array in CharacteristicRead");
success = dbus_message_iter_close_container(&iter, &array);
VerifyOrExit(success == TRUE, msg = "Fail to close container in CharacteristicRead");
exit:
if ((success != TRUE) && (NULL != msg))
{
WeaveLogDetail(Ble, msg);
}
return readReply;
}
static DBusMessage *CharacteristicWrite(DBusConnection *dbusConn, DBusMessage *dbusMsg,
void *bluezData)
{
Characteristic *characteristic = static_cast<Characteristic *>(bluezData);
DBusMessageIter iter;
dbus_message_iter_init(dbusMsg, &iter);
const char * msg = NULL;
DBusMessageIter array;
DBusMessage *writeReply = NULL;
VerifyOrExit(characteristic != NULL, msg = "characteristic is NULL in CharacteristicWrite");
if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
{
msg = "Fail to get arg type in CharacteristicWrite";
writeReply = g_dbus_create_error(dbusMsg, "org.bluez.Error.InvalidArguments", NULL);
ExitNow();
}
dbus_message_iter_recurse(&iter, &array);
dbus_message_iter_get_fixed_array(&array, &(characteristic->value), &(characteristic->valueLen));
g_dbus_emit_property_changed(dbusConn, characteristic->path, CHARACTERISTIC_INTERFACE, "Value");
if (strcmp(characteristic->uuid, UUID_WEAVE_C1) == 0)
{
WoBLEz_WriteReceived(gBluezServerEndpoint, gBluezServerEndpoint->weaveC1->value, gBluezServerEndpoint->weaveC1->valueLen);
}
writeReply = g_dbus_create_reply(dbusMsg, DBUS_TYPE_INVALID);
exit:
if (NULL != msg)
{
WeaveLogDetail(Ble, msg);
}
return writeReply;
}
static DBusMessage *CharacteristicStartNotify(DBusConnection *dbusConn, DBusMessage *dbusMsg, void *bluezData)
{
Characteristic *characteristic = static_cast<Characteristic *>(bluezData);
const char * msg = NULL;
DBusMessage *notifyReply = NULL;
VerifyOrExit(characteristic != NULL, msg = "characteristic is NULL in CharacteristicStartNotify");
VerifyOrExit(!characteristic->isNotifying, msg = "Notifying has been enabled in CharacteristicStartNotify");
characteristic->isNotifying = true;
g_dbus_emit_property_changed(dbusConn, characteristic->path, CHARACTERISTIC_INTERFACE, "Notifying");
WeaveLogDetail(Ble, "Characteristic path %s notification enabled", characteristic->path);
if (strcmp(characteristic->uuid, UUID_WEAVE_C2) == 0)
{
WoBLEz_SubscriptionChange(gBluezServerEndpoint);
}
notifyReply = g_dbus_create_reply(dbusMsg, DBUS_TYPE_INVALID);
exit:
if (NULL != msg)
{
WeaveLogDetail(Ble, msg);
}
return notifyReply;
}
static DBusMessage *CharacteristicStopNotify(DBusConnection *dbusConn, DBusMessage *dbusMsg, void *bluezData)
{
Characteristic *characteristic = static_cast<Characteristic *>(bluezData);
const char * msg = NULL;
DBusMessage *notifyReply = NULL;
VerifyOrExit(characteristic != NULL, msg = "characteristic is NULL in CharacteristicStopNotify");
VerifyOrExit(characteristic->isNotifying, msg = "Notifying has been disabled in CharacteristicStopNotify");
characteristic->isNotifying = false;
g_dbus_emit_property_changed(dbusConn, characteristic->path, CHARACTERISTIC_INTERFACE, "Notifying");
WeaveLogDetail(Ble, "Characteristic path %s notification disabled", characteristic->path);
notifyReply = g_dbus_create_reply(dbusMsg, DBUS_TYPE_INVALID);
exit:
if (NULL != msg)
{
WeaveLogDetail(Ble, msg);
}
return notifyReply;
}
static DBusMessage *CharacteristicIndicationConf(DBusConnection *dbusConn, DBusMessage *dbusMsg, void *bluezData)
{
Characteristic *characteristic = static_cast<Characteristic *>(bluezData);
WeaveLogDetail(Ble, "Indication confirmation received at %s", characteristic->path);
WoBLEz_IndicationConfirmation(gBluezServerEndpoint);
return g_dbus_create_reply(dbusMsg, DBUS_TYPE_INVALID);
}
static const GDBusPropertyTable WeaveCharacteristicProperties[] = {
{ "UUID", "s", CharacteristicGetUUID, NULL, NULL },
{ "Service", "o", CharacteristicGetService, NULL, NULL },
{ "Value", "ay", CharacteristicGetValue, NULL, NULL },
{ "Notifying", "b", CharacteristicGetNotifying, NULL, NULL },
{ "Flags", "as", CharacteristicGetFlags, NULL, NULL },
{ }
};
static const GDBusMethodTable weaveCharacteristicMethods[] = {
{"ReadValue", CharacteristicRead, G_DBUS_METHOD_FLAG_ASYNC, 0, GDBUS_ARGS({ "options", "a{sv}" }), GDBUS_ARGS({ "value", "ay" }) },
{"WriteValue", CharacteristicWrite, G_DBUS_METHOD_FLAG_ASYNC, 0, GDBUS_ARGS({ "value", "ay" },{ "options", "a{sv}" }), NULL },
{"StartNotify", CharacteristicStartNotify, G_DBUS_METHOD_FLAG_ASYNC, 0, NULL, NULL },
{"StopNotify", CharacteristicStopNotify, G_DBUS_METHOD_FLAG_ASYNC, 0, NULL, NULL},
{"Confirm", CharacteristicIndicationConf, G_DBUS_METHOD_FLAG_ASYNC, 0, NULL, NULL},
{ }
};
Characteristic * RegisterWeaveCharacteristic(DBusConnection *dbusConn, const char *uuid, const char *flags)
{
Characteristic *weaveCharacteristic = NULL;
gboolean success = FALSE;
const char * msg = NULL;
weaveCharacteristic = g_new0(Characteristic, 1);
VerifyOrExit(weaveCharacteristic != NULL, msg = "no memory allocated for characteristic in RegisterWeaveCharacteristic");
weaveCharacteristic->dbusConn = dbusConn;
weaveCharacteristic->uuid = g_strdup(uuid);
weaveCharacteristic->value = NULL;
weaveCharacteristic->path = g_strdup_printf("%s/weaveCharacteristic%p", gBluezServerEndpoint->weaveService->path, weaveCharacteristic);
weaveCharacteristic->servicePath = g_strdup_printf("%s",gBluezServerEndpoint->weaveService->path);
weaveCharacteristic->flags = g_strsplit(flags, ",", -1);
success = g_dbus_register_interface(dbusConn, weaveCharacteristic->path, CHARACTERISTIC_INTERFACE,
weaveCharacteristicMethods, NULL, WeaveCharacteristicProperties,
weaveCharacteristic, WeaveCharacteristicDestroy);
if (FALSE == success)
{
msg = "Failed to register weaveCharacteristic object in RegisterWeaveCharacteristic";
WeaveCharacteristicDestroy(weaveCharacteristic);
weaveCharacteristic = NULL;
}
exit:
if ((success != TRUE) && (msg != NULL))
{
WeaveLogDetail(Ble, msg);
}
return weaveCharacteristic;
}
static void WeaveConnectHandler(DBusConnection *connection, void *bluezData)
{
WoBLEz_NewConnection(gBluezServerEndpoint);
}
static void WeaveDisconnectHandler(DBusConnection *connection, void *bluezData)
{
WoBLEz_ConnectionClosed(gBluezServerEndpoint);
}
static void WeaveAdapterAdded(GDBusProxy *proxy)
{
Adapter *adapter;
DBusMessageIter iter;
const char *str;
gAdapterFound = false;
if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
return;
dbus_message_iter_get_basic(&iter, &str);
if (!strcasecmp(str, gBluezServerEndpoint->adapterAddr))
{
adapter = static_cast<Adapter *>(g_new0(Adapter, 1));
adapter->adapterProxy = proxy;
gDefaultAdapter = adapter;
gAdapterFound = true;
}
}
static void WeaveProfileAdded(GDBusProxy *proxy)
{
if (!gAdapterFound)
return;
gDefaultAdapter->profileProxy = proxy;
}
static void WeaveAdvertisingAdded(GDBusProxy *proxy)
{
if (!gAdapterFound)
return;
gDefaultAdapter->advertisingProxy = proxy;
}
static void WeaveProxyAdded(GDBusProxy *proxy, void *bluezData)
{
const char *interface;
interface = g_dbus_proxy_get_interface(proxy);
if (!strcmp(interface, ADAPTER_INTERFACE))
{
WeaveAdapterAdded(proxy);
}
else if (!strcmp(interface, PROFILE_INTERFACE))
{
WeaveProfileAdded(proxy);
}
else if (!strcmp(interface, ADVERTISING_MANAGER_INTERFACE))
{
WeaveAdvertisingAdded(proxy);
}
}
static void WeaveProxyDeleted(GDBusProxy *proxy, void *bluezData)
{
const char *interface;
interface = g_dbus_proxy_get_interface(proxy);
if (!strcmp(interface, ADAPTER_INTERFACE))
{
if (gDefaultAdapter && gDefaultAdapter->adapterProxy == proxy)
{
g_free(gDefaultAdapter);
gDefaultAdapter = NULL;
}
}
}
static void PowerCb(const DBusError *error, void *bluezData)
{
WEAVE_ERROR err = WEAVE_NO_ERROR;
gboolean success = FALSE;
VerifyOrExit(!dbus_error_is_set(error), err = WEAVE_ERROR_INCORRECT_STATE);
success = RegisterWeaveService(gBluezDbusConn);
VerifyOrExit(success == TRUE, err = WEAVE_ERROR_INCORRECT_STATE);
gBluezServerEndpoint->weaveC1 = RegisterWeaveCharacteristic(gBluezDbusConn, UUID_WEAVE_C1, FLAGS_WEAVE_C1);
VerifyOrExit(gBluezServerEndpoint->weaveC1 != NULL, err = WEAVE_ERROR_NO_MEMORY);
WeaveLogDetail(Ble, "weave C1 uuid: %s, path: %s", gBluezServerEndpoint->weaveC1->uuid, gBluezServerEndpoint->weaveC1->path);
gBluezServerEndpoint->weaveC2 = RegisterWeaveCharacteristic(gBluezDbusConn, UUID_WEAVE_C2, FLAGS_WEAVE_C2);
VerifyOrExit(gBluezServerEndpoint->weaveC2 != NULL, err = WEAVE_ERROR_NO_MEMORY);
WeaveLogDetail(Ble, "weave C2 uuid: %s, path: %s", gBluezServerEndpoint->weaveC2->uuid,gBluezServerEndpoint->weaveC2->path);
success = SetupWeaveApp(gBluezDbusConn, gDefaultAdapter->profileProxy);
VerifyOrExit(success == TRUE, err = WEAVE_ERROR_INCORRECT_STATE);
success = AdvertisingRegister(gBluezDbusConn, gDefaultAdapter->advertisingProxy);
VerifyOrExit(success == TRUE, err = WEAVE_ERROR_INCORRECT_STATE);
exit:
if (err != WEAVE_NO_ERROR)
{
WeaveLogDetail(Ble, "PowerCb failed: %d", err);
}
}
static void BluezClientReady(GDBusClient *weaveClient, void *bluezData)
{
dbus_bool_t powered = TRUE;
gboolean err = g_dbus_proxy_set_property_basic(gDefaultAdapter->adapterProxy, "Powered", DBUS_TYPE_BOOLEAN, &powered, PowerCb, NULL, NULL);
if (FALSE == err)
{
WeaveLogDetail(Ble, "Fail to set Power property in BluezClientReady");
}
return;
}
uint16_t GetMTUWeaveCb(BLE_CONNECTION_OBJECT connObj)
{
uint16_t mtu = HCI_MAX_MTU;
WeaveLogDetail(Ble, "GetMTU: %d", mtu);
return mtu;
}
void ExitMainLoop(void)
{
g_main_loop_quit(gBluezMainLoop);
}
bool RunBluezIOThread(char *aBleName, char *aBleAddress)
{
GDBusClient *weaveClient = NULL;
const char * msg = NULL;
gboolean success = FALSE;
WEAVE_ERROR err = WEAVE_NO_ERROR;
const char *advertisingType = "peripheral";
BluezBlePlatformDelegate *bleDelegate = getBluezPlatformDelegate();
VerifyOrExit(bleDelegate != NULL, err = WEAVE_ERROR_NO_MEMORY);
bleDelegate->SetSendIndicationCallback(WoBLEz_SendIndication);
bleDelegate->SetGetMTUCallback(GetMTUWeaveCb);
gBluezServerEndpoint = (BluezServerEndpoint *)g_new0(BluezServerEndpoint, 1);
VerifyOrExit(gBluezServerEndpoint != NULL, err = WEAVE_ERROR_NO_MEMORY);
gBluezServerEndpoint->adapterName = g_strdup(aBleName);
gBluezServerEndpoint->adapterAddr = aBleAddress;
gBluezServerEndpoint->advertisingUUID = g_strdup(UUID_WEAVE_SHORT);
gBluezServerEndpoint->advertisingType = g_strdup(advertisingType);
gBluezMainLoop = g_main_loop_new(NULL, FALSE);
gBluezDbusConn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
VerifyOrExit(gBluezDbusConn != NULL, err = WEAVE_ERROR_NO_MEMORY);
success = g_dbus_attach_object_manager(gBluezDbusConn);
VerifyOrExit(success == TRUE, msg = "Fail to attach object manager in RunBluezIOThread");
weaveClient = g_dbus_client_new(gBluezDbusConn, BLUEZ_INTERFACE, BLUEZ_PATH);
VerifyOrExit(weaveClient != NULL, err = WEAVE_ERROR_NO_MEMORY);
success = g_dbus_client_set_proxy_handlers(weaveClient, WeaveProxyAdded, WeaveProxyDeleted, NULL, NULL);
VerifyOrExit(success == TRUE, msg = "Fail to set weave proxy handler in RunBluezIOThread");
success = g_dbus_client_set_ready_watch(weaveClient, BluezClientReady, NULL);
VerifyOrExit(success == TRUE, msg = "Fail to set weave ready watch in RunBluezIOThread");
success = g_dbus_client_set_connect_watch(weaveClient, WeaveConnectHandler, NULL);
VerifyOrExit(success == TRUE, msg = "Fail to set weave connect watch in RunBluezIOThread");
success = g_dbus_client_set_disconnect_watch(weaveClient, WeaveDisconnectHandler, NULL);
VerifyOrExit(success == TRUE, msg = "Fail to set weave disconnect watch in RunBluezIOThread");
g_main_loop_run(gBluezMainLoop);
exit:
if (err != WEAVE_NO_ERROR)
{
WeaveLogDetail(Ble, "RunBluezIOThread failed: %d", err);
}
if ((success != TRUE) && (msg != NULL))
{
WeaveLogDetail(Ble, msg);
}
if (NULL != gBluezServerEndpoint)
{
if (NULL != gBluezServerEndpoint->weaveService)
{
ServiceDestroy(gBluezServerEndpoint->weaveService);
gBluezServerEndpoint->weaveService = NULL;
}
if (NULL != gBluezServerEndpoint->weaveC1)
{
WeaveCharacteristicDestroy(gBluezServerEndpoint->weaveC1);
gBluezServerEndpoint->weaveC1 = NULL;
}
if (NULL != gBluezServerEndpoint->weaveC2)
{
WeaveCharacteristicDestroy(gBluezServerEndpoint->weaveC2);
gBluezServerEndpoint->weaveC2 = NULL;
}
if (NULL != gBluezServerEndpoint->adapterName)
{
g_free(gBluezServerEndpoint->adapterName);
gBluezServerEndpoint->adapterName = NULL;
}
if (NULL != gBluezServerEndpoint->advertisingUUID)
{
g_free(gBluezServerEndpoint->advertisingUUID);
gBluezServerEndpoint->advertisingUUID = NULL;
}
if (NULL != gBluezServerEndpoint->advertisingType)
{
g_free(gBluezServerEndpoint->advertisingType);
gBluezServerEndpoint->advertisingType = NULL;
}
g_free(gBluezServerEndpoint);
gBluezServerEndpoint = NULL;
}
if (NULL != weaveClient)
{
g_dbus_client_unref(weaveClient);
}
if (NULL != gBluezDbusConn)
{
dbus_connection_unref(gBluezDbusConn);
}
if (NULL != gBluezMainLoop)
{
g_main_loop_unref(gBluezMainLoop);
}
return false;
}
} /* namespace Bluez */
} /* namespace Platform */
} /* namespace Ble */
} /* namespace nl */
#endif /* CONFIG_BLE_PLATFORM_BLUEZ */