3 * Copyright (c) 2020 Project CHIP Authors
5 * Licensed under the Apache License, Version 2.0 (the "License");
6 * you may not use this file except in compliance with the License.
7 * You may obtain a copy of the License at
9 * http://www.apache.org/licenses/LICENSE-2.0
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
19 * Copyright (c) 2016-2019, The OpenThread Authors.
20 * All rights reserved.
22 * Redistribution and use in source and binary forms, with or without
23 * modification, are permitted provided that the following conditions are met:
24 * 1. Redistributions of source code must retain the above copyright
25 * notice, this list of conditions and the following disclaimer.
26 * 2. Redistributions in binary form must reproduce the above copyright
27 * notice, this list of conditions and the following disclaimer in the
28 * documentation and/or other materials provided with the distribution.
29 * 3. Neither the name of the copyright holder nor the
30 * names of its contributors may be used to endorse or promote products
31 * derived from this software without specific prior written permission.
33 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
34 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
35 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
36 * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
37 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
38 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
39 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
40 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
41 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
43 * POSSIBILITY OF SUCH DAMAGE.
48 * Provides Bluez dbus implementatioon for BLE
51 #include <ble/BleUUID.h>
52 #include <ble/CHIPBleServiceData.h>
53 #include <platform/CHIPDeviceLayer.h>
55 #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
57 #include <gio/gunixfdlist.h>
64 #include "CHIPBluezHelper.h"
65 #include <support/CodeUtils.h>
70 namespace DeviceLayer {
73 static int sBluezFD[2];
74 static GMainLoop * sBluezMainLoop = nullptr;
75 static pthread_t sBluezThread;
76 static BluezConnection * GetBluezConnectionViaDevice(BluezEndpoint * apEndpoint);
78 static gboolean BluezAdvertisingRelease(BluezLEAdvertisement1 * aAdv, GDBusMethodInvocation * aInvocation, gpointer apClosure)
80 bool isSuccess = false;
81 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
82 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
83 VerifyOrExit(aAdv != nullptr, ChipLogError(DeviceLayer, "BluezLEAdvertisement1 is NULL in %s", __func__));
84 ChipLogDetail(DeviceLayer, "Release adv object in %s", __func__);
86 g_dbus_object_manager_server_unexport(endpoint->mpRoot, endpoint->mpAdvPath);
87 endpoint->mIsAdvertising = false;
91 return isSuccess ? TRUE : FALSE;
94 static BluezLEAdvertisement1 * BluezAdvertisingCreate(BluezEndpoint * apEndpoint)
96 BluezLEAdvertisement1 * adv = nullptr;
97 BluezObjectSkeleton * object;
98 GVariant * serviceData;
99 GVariant * serviceUUID;
101 GVariantBuilder serviceDataBuilder;
102 GVariantBuilder serviceUUIDsBuilder;
105 VerifyOrExit(apEndpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
106 if (apEndpoint->mpAdvPath == nullptr)
107 apEndpoint->mpAdvPath = g_strdup_printf("%s/advertising", apEndpoint->mpRootPath);
109 ChipLogDetail(DeviceLayer, "Create adv object at %s", apEndpoint->mpAdvPath);
110 object = bluez_object_skeleton_new(apEndpoint->mpAdvPath);
112 adv = bluez_leadvertisement1_skeleton_new();
114 g_variant_builder_init(&serviceDataBuilder, G_VARIANT_TYPE("a{sv}"));
115 g_variant_builder_init(&serviceUUIDsBuilder, G_VARIANT_TYPE("as"));
117 g_variant_builder_add(&serviceDataBuilder, "{sv}", apEndpoint->mpAdvertisingUUID,
118 g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, &apEndpoint->mDeviceIdInfo,
119 sizeof(apEndpoint->mDeviceIdInfo), sizeof(uint8_t)));
120 g_variant_builder_add(&serviceUUIDsBuilder, "s", apEndpoint->mpAdvertisingUUID);
122 if (apEndpoint->mpAdapterName != nullptr)
123 localName = g_strdup_printf("%s", apEndpoint->mpAdapterName);
125 localName = g_strdup_printf("%s%04x", CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX, getpid() & 0xffff);
127 serviceData = g_variant_builder_end(&serviceDataBuilder);
128 serviceUUID = g_variant_builder_end(&serviceUUIDsBuilder);
130 debugStr = g_variant_print(serviceData, TRUE);
131 ChipLogDetail(DeviceLayer, "SET service data to %s", debugStr);
134 bluez_leadvertisement1_set_type_(adv, (apEndpoint->mType & BLUEZ_ADV_TYPE_CONNECTABLE) ? "peripheral" : "broadcast");
135 // empty manufacturer data
136 // empty solicit UUIDs
137 bluez_leadvertisement1_set_service_data(adv, serviceData);
140 bluez_leadvertisement1_set_discoverable(adv, (apEndpoint->mType & BLUEZ_ADV_TYPE_SCANNABLE) ? TRUE : FALSE);
142 // advertising name corresponding to the PID and object path, for debug purposes
143 bluez_leadvertisement1_set_local_name(adv, localName);
144 bluez_leadvertisement1_set_service_uuids(adv, serviceUUID);
146 // 0xffff means no appearance
147 bluez_leadvertisement1_set_appearance(adv, 0xffff);
149 bluez_leadvertisement1_set_duration(adv, apEndpoint->mDuration);
150 // empty duration, we don't have a clear notion what it would mean to timeslice between toble and anyone else
151 bluez_leadvertisement1_set_timeout(adv, 0);
152 // empty secondary channel for now
154 bluez_object_skeleton_set_leadvertisement1(object, adv);
155 g_signal_connect(adv, "handle-release", G_CALLBACK(BluezAdvertisingRelease), apEndpoint);
157 g_dbus_object_manager_server_export(apEndpoint->mpRoot, G_DBUS_OBJECT_SKELETON(object));
158 g_object_unref(object);
160 BLEManagerImpl::NotifyBLEPeripheralAdvConfiguredComplete(true, nullptr);
166 static void BluezAdvStartDone(GObject * aObject, GAsyncResult * aResult, gpointer apClosure)
168 BluezLEAdvertisingManager1 * advMgr = BLUEZ_LEADVERTISING_MANAGER1(aObject);
169 GError * error = nullptr;
170 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
171 gboolean success = FALSE;
173 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
175 success = bluez_leadvertising_manager1_call_register_advertisement_finish(advMgr, aResult, &error);
176 if (success == FALSE)
178 g_dbus_object_manager_server_unexport(endpoint->mpRoot, endpoint->mpAdvPath);
180 VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: RegisterAdvertisement : %s", error->message));
182 endpoint->mIsAdvertising = true;
184 ChipLogDetail(DeviceLayer, "RegisterAdvertisement complete");
187 BLEManagerImpl::NotifyBLEPeripheralAdvStartComplete(success == TRUE, nullptr);
188 if (error != nullptr)
192 static void BluezAdvStopDone(GObject * aObject, GAsyncResult * aResult, gpointer apClosure)
194 BluezLEAdvertisingManager1 * advMgr = BLUEZ_LEADVERTISING_MANAGER1(aObject);
195 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
196 GError * error = nullptr;
197 gboolean success = FALSE;
199 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
201 success = bluez_leadvertising_manager1_call_unregister_advertisement_finish(advMgr, aResult, &error);
203 if (success == FALSE)
205 g_dbus_object_manager_server_unexport(endpoint->mpRoot, endpoint->mpAdvPath);
209 endpoint->mIsAdvertising = false;
212 VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: UnregisterAdvertisement : %s", error->message));
214 ChipLogDetail(DeviceLayer, "UnregisterAdvertisement complete");
217 BLEManagerImpl::NotifyBLEPeripheralAdvStopComplete(success == TRUE, nullptr);
218 if (error != nullptr)
222 static gboolean BluezAdvSetup(void * apClosure)
224 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
225 BluezLEAdvertisement1 * adv;
227 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
228 VerifyOrExit(endpoint->mIsAdvertising == FALSE, ChipLogError(DeviceLayer, "FAIL: Advertising already enabled in %s", __func__));
229 VerifyOrExit(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
231 adv = BluezAdvertisingCreate(endpoint);
232 VerifyOrExit(adv != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adv in %s", __func__));
235 return G_SOURCE_REMOVE;
238 static gboolean BluezAdvStart(void * apEndpoint)
240 GDBusObject * adapter;
241 BluezLEAdvertisingManager1 * advMgr = nullptr;
242 GVariantBuilder optionsBuilder;
244 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
246 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
247 VerifyOrExit(!endpoint->mIsAdvertising,
248 ChipLogError(DeviceLayer, "FAIL: Advertising has already been enabled in %s", __func__));
249 VerifyOrExit(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
251 adapter = g_dbus_interface_get_object(G_DBUS_INTERFACE(endpoint->mpAdapter));
252 VerifyOrExit(adapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adapter in %s", __func__));
254 advMgr = bluez_object_get_leadvertising_manager1(BLUEZ_OBJECT(adapter));
255 VerifyOrExit(advMgr != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL advMgr in %s", __func__));
257 g_variant_builder_init(&optionsBuilder, G_VARIANT_TYPE("a{sv}"));
258 options = g_variant_builder_end(&optionsBuilder);
260 bluez_leadvertising_manager1_call_register_advertisement(advMgr, endpoint->mpAdvPath, options, nullptr, BluezAdvStartDone,
264 return G_SOURCE_REMOVE;
267 static gboolean BluezAdvStop(void * apEndpoint)
269 GDBusObject * adapter;
270 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
271 BluezLEAdvertisingManager1 * advMgr = nullptr;
273 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
274 VerifyOrExit(endpoint->mIsAdvertising,
275 ChipLogError(DeviceLayer, "FAIL: Advertising has already been disabled in %s", __func__));
276 VerifyOrExit(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
278 adapter = g_dbus_interface_get_object(G_DBUS_INTERFACE(endpoint->mpAdapter));
279 VerifyOrExit(adapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adapter in %s", __func__));
281 advMgr = bluez_object_get_leadvertising_manager1(BLUEZ_OBJECT(adapter));
282 VerifyOrExit(advMgr != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL advMgr in %s", __func__));
284 bluez_leadvertising_manager1_call_unregister_advertisement(advMgr, endpoint->mpAdvPath, nullptr, BluezAdvStopDone, apEndpoint);
287 return G_SOURCE_REMOVE;
290 static gboolean BluezCharacteristicReadValue(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
294 ChipLogDetail(DeviceLayer, "Received BluezCharacteristicReadValue");
295 val = bluez_gatt_characteristic1_get_value(aChar);
296 bluez_gatt_characteristic1_complete_read_value(aChar, aInvocation, val);
300 #if CHIP_BLUEZ_CHAR_WRITE_VALUE
301 static gboolean BluezCharacteristicWriteValue(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
302 GVariant * aValue, GVariant * aOptions, gpointer apEndpoint)
304 const uint8_t * tmpBuf;
307 bool isSuccess = false;
308 BluezConnection * conn = NULL;
310 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
311 VerifyOrExit(endpoint != NULL, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
313 VerifyOrExit(aValue != NULL, ChipLogError(DeviceLayer, "aValue is NULL in %s", __func__));
315 conn = GetBluezConnectionViaDevice(endpoint);
316 VerifyOrExit(conn != NULL,
317 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No CHIP Bluez connection"));
319 bluez_gatt_characteristic1_set_value(aChar, g_variant_ref(aValue));
321 tmpBuf = (uint8_t *) (g_variant_get_fixed_array(aValue, &len, sizeof(uint8_t)));
322 buf = (uint8_t *) (g_memdup(tmpBuf, len));
324 BLEManagerImpl::HandleRXCharWrite(conn, buf, len);
325 bluez_gatt_characteristic1_complete_write_value(aChar, aInvocation);
329 return isSuccess ? TRUE : FALSE;
333 static gboolean BluezCharacteristicWriteValueError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
334 GVariant * aValue, GVariant * aOptions, gpointer apClosure)
336 ChipLogDetail(DeviceLayer, "BluezCharacteristicWriteValueError");
337 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotSupported",
338 "Write for characteristic is unsupported");
342 static gboolean BluezCharacteristicWriteFD(GIOChannel * aChannel, GIOCondition aCond, gpointer apEndpoint)
348 bool isSuccess = false;
350 BluezConnection * conn = static_cast<BluezConnection *>(apEndpoint);
352 VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "No CHIP Bluez connection in %s", __func__));
354 VerifyOrExit(!(aCond & G_IO_HUP), ChipLogError(DeviceLayer, "INFO: socket disconnected in %s", __func__));
355 VerifyOrExit(!(aCond & (G_IO_ERR | G_IO_NVAL)), ChipLogError(DeviceLayer, "INFO: socket error in %s", __func__));
356 VerifyOrExit(aCond == G_IO_IN, ChipLogError(DeviceLayer, "FAIL: error in %s", __func__));
358 ChipLogDetail(DeviceLayer, "c1 %s mtu, %d", __func__, conn->mMtu);
360 buf = static_cast<gchar *>(g_malloc(conn->mMtu));
361 fd = g_io_channel_unix_get_fd(aChannel);
363 len = read(fd, buf, conn->mMtu);
365 VerifyOrExit(len > 0, ChipLogError(DeviceLayer, "FAIL: short read in %s (%d)", __func__, len));
367 // Casting len to size_t is safe, since we ensured that it's not negative.
368 newVal = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, buf, static_cast<size_t>(len), sizeof(uint8_t));
370 bluez_gatt_characteristic1_set_value(conn->mpC1, newVal);
371 BLEManagerImpl::HandleRXCharWrite(conn, reinterpret_cast<uint8_t *>(buf), static_cast<size_t>(len));
375 return isSuccess ? TRUE : FALSE;
378 static void Bluez_gatt_characteristic1_complete_acquire_write_with_fd(GDBusMethodInvocation * invocation, int fd, guint16 mtu)
380 GUnixFDList * fd_list = g_unix_fd_list_new();
383 index = g_unix_fd_list_append(fd_list, fd, nullptr);
385 g_dbus_method_invocation_return_value_with_unix_fd_list(invocation, g_variant_new("(@hq)", g_variant_new_handle(index), mtu),
389 static gboolean bluezCharacteristicDestroyFD(GIOChannel * aChannel, GIOCondition aCond, gpointer apClosure)
391 return G_SOURCE_REMOVE;
394 static gboolean BluezCharacteristicAcquireWrite(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
395 GVariant * aOptions, gpointer apEndpoint)
397 int fds[2] = { -1, -1 };
398 GIOChannel * channel;
400 GVariantDict options;
401 bool isSuccess = false;
402 BluezConnection * conn = nullptr;
404 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
405 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
407 conn = GetBluezConnectionViaDevice(endpoint);
408 VerifyOrExit(conn != nullptr,
409 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
411 ChipLogDetail(DeviceLayer, "BluezCharacteristicAcquireWrite is called, conn: %p", conn);
413 if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, fds) < 0)
415 errStr = strerror(errno);
416 ChipLogError(DeviceLayer, "FAIL: socketpair: %s in %s", errStr, __func__);
417 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "FD creation failed");
418 SuccessOrExit(false);
421 g_variant_dict_init(&options, aOptions);
422 if (g_variant_dict_contains(&options, "mtu") == TRUE)
424 GVariant * v = g_variant_dict_lookup_value(&options, "mtu", G_VARIANT_TYPE_UINT16);
425 conn->mMtu = g_variant_get_uint16(v);
429 ChipLogError(DeviceLayer, "FAIL: no MTU in options in %s", __func__);
430 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.InvalidArguments", "MTU negotiation failed");
431 SuccessOrExit(false);
434 channel = g_io_channel_unix_new(fds[0]);
435 g_io_channel_set_encoding(channel, nullptr, nullptr);
436 g_io_channel_set_close_on_unref(channel, TRUE);
437 g_io_channel_set_buffered(channel, FALSE);
439 conn->mC1Channel.mpChannel = channel;
440 conn->mC1Channel.mWatch = g_io_add_watch(channel, static_cast<GIOCondition>(G_IO_HUP | G_IO_IN | G_IO_ERR | G_IO_NVAL),
441 BluezCharacteristicWriteFD, conn);
443 bluez_gatt_characteristic1_set_write_acquired(aChar, TRUE);
445 Bluez_gatt_characteristic1_complete_acquire_write_with_fd(aInvocation, fds[1], conn->mMtu);
450 return isSuccess ? TRUE : FALSE;
453 static gboolean BluezCharacteristicAcquireWriteError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
456 ChipLogDetail(DeviceLayer, "BluezCharacteristicAcquireWriteError is called");
457 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotSupported",
458 "AcquireWrite for characteristic is unsupported");
462 static gboolean BluezCharacteristicAcquireNotify(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
463 GVariant * aOptions, gpointer apEndpoint)
465 int fds[2] = { -1, -1 };
466 GIOChannel * channel;
468 GVariantDict options;
469 BluezConnection * conn = nullptr;
470 bool isSuccess = false;
472 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
473 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
475 conn = GetBluezConnectionViaDevice(endpoint);
476 VerifyOrExit(conn != nullptr,
477 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
479 g_variant_dict_init(&options, aOptions);
480 if ((g_variant_dict_contains(&options, "mtu") == TRUE))
482 GVariant * v = g_variant_dict_lookup_value(&options, "mtu", G_VARIANT_TYPE_UINT16);
483 conn->mMtu = g_variant_get_uint16(v);
486 if (bluez_gatt_characteristic1_get_notifying(aChar))
488 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotPermitted", "Already notifying");
490 if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, fds) < 0)
492 errStr = strerror(errno);
493 ChipLogError(DeviceLayer, "FAIL: socketpair: %s in %s", errStr, __func__);
494 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "FD creation failed");
495 SuccessOrExit(false);
497 channel = g_io_channel_unix_new(fds[0]);
498 g_io_channel_set_encoding(channel, nullptr, nullptr);
499 g_io_channel_set_close_on_unref(channel, TRUE);
500 g_io_channel_set_buffered(channel, FALSE);
501 conn->mC2Channel.mpChannel = channel;
502 conn->mC2Channel.mWatch =
503 g_io_add_watch_full(channel, G_PRIORITY_DEFAULT_IDLE, static_cast<GIOCondition>(G_IO_HUP | G_IO_ERR | G_IO_NVAL),
504 bluezCharacteristicDestroyFD, conn, nullptr);
506 bluez_gatt_characteristic1_set_notify_acquired(aChar, TRUE);
508 // same reply as for AcquireWrite
509 Bluez_gatt_characteristic1_complete_acquire_write_with_fd(aInvocation, fds[1], conn->mMtu);
512 conn->mIsNotify = true;
513 BLEManagerImpl::HandleTXCharCCCDWrite(conn);
517 return isSuccess ? TRUE : FALSE;
520 static gboolean BluezCharacteristicAcquireNotifyError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
523 ChipLogDetail(DeviceLayer, "TRACE: AcquireNotify is called");
524 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotSupported",
525 "AcquireNotify for characteristic is unsupported");
529 static gboolean BluezCharacteristicStartNotify(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
532 bool isSuccess = false;
533 BluezConnection * conn = nullptr;
535 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
536 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
538 conn = GetBluezConnectionViaDevice(endpoint);
539 VerifyOrExit(conn != nullptr,
540 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
542 if (bluez_gatt_characteristic1_get_notifying(aChar) == TRUE)
544 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "Characteristic is already subscribed");
548 bluez_gatt_characteristic1_complete_start_notify(aChar, aInvocation);
549 bluez_gatt_characteristic1_set_notifying(aChar, TRUE);
550 conn->mIsNotify = true;
551 BLEManagerImpl::HandleTXCharCCCDWrite(conn);
556 return isSuccess ? TRUE : FALSE;
559 static gboolean BluezCharacteristicStartNotifyError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation)
561 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotSupported",
562 "Subscribing to characteristic is unsupported");
566 static gboolean BluezCharacteristicStopNotify(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
569 bool isSuccess = false;
570 BluezConnection * conn = nullptr;
572 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
573 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
575 conn = GetBluezConnectionViaDevice(endpoint);
576 VerifyOrExit(conn != nullptr,
577 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
579 if (bluez_gatt_characteristic1_get_notifying(aChar) == FALSE)
581 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "Characteristic is already unsubscribed");
585 bluez_gatt_characteristic1_complete_start_notify(aChar, aInvocation);
586 bluez_gatt_characteristic1_set_notifying(aChar, FALSE);
588 conn->mIsNotify = false;
593 return isSuccess ? TRUE : FALSE;
596 static gboolean BluezCharacteristicConfirm(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
599 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
600 BluezConnection * conn = GetBluezConnectionViaDevice(endpoint);
602 ChipLogDetail(Ble, "Indication confirmation, %p", conn);
603 BLEManagerImpl::HandleTXComplete(conn);
608 static gboolean BluezCharacteristicStopNotifyError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation)
610 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed",
611 "Unsubscribing from characteristic is unsupported");
615 static gboolean BluezCharacteristicConfirmError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation)
617 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "Confirm from characteristic is unsupported");
621 static gboolean BluezIsDeviceOnAdapter(BluezDevice1 * aDevice, BluezAdapter1 * aAdapter)
623 return strcmp(bluez_device1_get_adapter(aDevice), g_dbus_proxy_get_object_path(G_DBUS_PROXY(aAdapter))) == 0 ? TRUE : FALSE;
626 static gboolean BluezIsServiceOnDevice(BluezGattService1 * aService, BluezDevice1 * aDevice)
628 return strcmp(bluez_gatt_service1_get_device(aService), g_dbus_proxy_get_object_path(G_DBUS_PROXY(aDevice))) == 0 ? TRUE
632 static gboolean BluezIsCharOnService(BluezGattCharacteristic1 * aChar, BluezGattService1 * aService)
634 ChipLogDetail(DeviceLayer, "Char1 %s", bluez_gatt_characteristic1_get_service(aChar));
635 ChipLogDetail(DeviceLayer, "Char1 %s", g_dbus_proxy_get_object_path(G_DBUS_PROXY(aService)));
636 return strcmp(bluez_gatt_characteristic1_get_service(aChar), g_dbus_proxy_get_object_path(G_DBUS_PROXY(aService))) == 0 ? TRUE
640 static void BluezConnectionInit(BluezConnection * apConn)
642 // populate the service and the characteristics
643 GList * objects = nullptr;
645 BluezEndpoint * endpoint = nullptr;
647 VerifyOrExit(apConn != nullptr, ChipLogError(DeviceLayer, "Bluez connection is NULL in %s", __func__));
649 endpoint = apConn->mpEndpoint;
650 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
652 if (!endpoint->mIsCentral)
654 apConn->mpService = BLUEZ_GATT_SERVICE1(g_object_ref(apConn->mpEndpoint->mpService));
655 apConn->mpC1 = BLUEZ_GATT_CHARACTERISTIC1(g_object_ref(endpoint->mpC1));
656 apConn->mpC2 = BLUEZ_GATT_CHARACTERISTIC1(g_object_ref(endpoint->mpC2));
660 objects = g_dbus_object_manager_get_objects(endpoint->mpObjMgr);
662 for (l = objects; l != nullptr; l = l->next)
664 BluezObject * object = BLUEZ_OBJECT(l->data);
665 BluezGattService1 * service = bluez_object_get_gatt_service1(object);
667 if (service != nullptr)
669 if ((BluezIsServiceOnDevice(service, apConn->mpDevice)) == TRUE &&
670 (strcmp(bluez_gatt_service1_get_uuid(service), CHIP_BLE_UUID_SERVICE_STRING) == 0))
672 apConn->mpService = service;
675 g_object_unref(service);
679 VerifyOrExit(apConn->mpService != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL service in %s", __func__));
681 for (l = objects; l != nullptr; l = l->next)
683 BluezObject * object = BLUEZ_OBJECT(l->data);
684 BluezGattCharacteristic1 * char1 = bluez_object_get_gatt_characteristic1(object);
686 if (char1 != nullptr)
688 if ((BluezIsCharOnService(char1, apConn->mpService) == TRUE) &&
689 (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C1_STRING) == 0))
691 apConn->mpC1 = char1;
693 else if ((BluezIsCharOnService(char1, apConn->mpService) == TRUE) &&
694 (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C2_STRING) == 0))
696 apConn->mpC2 = char1;
700 g_object_unref(char1);
702 if ((apConn->mpC1 != nullptr) && (apConn->mpC2 != nullptr))
709 VerifyOrExit(apConn->mpC1 != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL C1 in %s", __func__));
710 VerifyOrExit(apConn->mpC2 != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL C2 in %s", __func__));
714 if (objects != nullptr)
715 g_list_free_full(objects, g_object_unref);
718 static gboolean BluezConnectionInitIdle(gpointer user_data)
720 BluezConnection * conn = static_cast<BluezConnection *>(user_data);
722 ChipLogDetail(DeviceLayer, "%s", __func__);
724 BluezConnectionInit(conn);
729 static void BluezOTConnectionDestroy(BluezConnection * aConn)
734 g_object_unref(aConn->mpDevice);
735 if (aConn->mpService)
736 g_object_unref(aConn->mpService);
738 g_object_unref(aConn->mpC1);
740 g_object_unref(aConn->mpC2);
741 if (aConn->mpPeerAddress)
742 g_free(aConn->mpPeerAddress);
743 if (aConn->mC1Channel.mWatch > 0)
744 g_source_remove(aConn->mC1Channel.mWatch);
745 if (aConn->mC1Channel.mpChannel)
746 g_io_channel_unref(aConn->mC1Channel.mpChannel);
747 if (aConn->mC2Channel.mWatch > 0)
748 g_source_remove(aConn->mC2Channel.mWatch);
749 if (aConn->mC2Channel.mpChannel)
750 g_io_channel_unref(aConn->mC2Channel.mpChannel);
756 static BluezGattCharacteristic1 * BluezCharacteristicCreate(BluezGattService1 * aService, const char * aCharName,
757 const char * aUUID, GDBusObjectManagerServer * aRoot)
759 char * servicePath = g_strdup(g_dbus_object_get_object_path(g_dbus_interface_get_object(G_DBUS_INTERFACE(aService))));
760 char * charPath = g_strdup_printf("%s/%s", servicePath, aCharName);
761 BluezObjectSkeleton * object;
762 BluezGattCharacteristic1 * characteristic;
764 ChipLogDetail(DeviceLayer, "Create characteristic object at %s", charPath);
765 object = bluez_object_skeleton_new(charPath);
767 characteristic = bluez_gatt_characteristic1_skeleton_new();
768 bluez_gatt_characteristic1_set_uuid(characteristic, aUUID);
769 bluez_gatt_characteristic1_set_service(characteristic, servicePath);
771 bluez_object_skeleton_set_gatt_characteristic1(object, characteristic);
772 g_dbus_object_manager_server_export(aRoot, G_DBUS_OBJECT_SKELETON(object));
773 g_object_unref(object);
775 return characteristic;
778 static void BluezPeripheralRegisterAppDone(GObject * aObject, GAsyncResult * aResult, gpointer apClosure)
780 GError * error = nullptr;
781 BluezGattManager1 * gattMgr = BLUEZ_GATT_MANAGER1(aObject);
783 gboolean success = bluez_gatt_manager1_call_register_application_finish(gattMgr, aResult, &error);
785 VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: RegisterApplication : %s", error->message));
787 BLEManagerImpl::NotifyBLEPeripheralRegisterAppComplete(true, nullptr);
788 ChipLogDetail(DeviceLayer, "BluezPeripheralRegisterAppDone done");
791 if (error != nullptr)
793 BLEManagerImpl::NotifyBLEPeripheralRegisterAppComplete(false, nullptr);
798 gboolean BluezPeripheralRegisterApp(void * apClosure)
800 GDBusObject * adapter;
801 BluezGattManager1 * gattMgr;
802 GVariantBuilder optionsBuilder;
805 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
806 VerifyOrExit(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
808 adapter = g_dbus_interface_get_object(G_DBUS_INTERFACE(endpoint->mpAdapter));
809 VerifyOrExit(adapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adapter in %s", __func__));
811 gattMgr = bluez_object_get_gatt_manager1(BLUEZ_OBJECT(adapter));
812 VerifyOrExit(gattMgr != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL gattMgr in %s", __func__));
814 g_variant_builder_init(&optionsBuilder, G_VARIANT_TYPE("a{sv}"));
815 options = g_variant_builder_end(&optionsBuilder);
817 bluez_gatt_manager1_call_register_application(gattMgr, endpoint->mpRootPath, options, nullptr, BluezPeripheralRegisterAppDone,
821 return G_SOURCE_REMOVE;
824 /***********************************************************************
825 * GATT Characteristic object
826 ***********************************************************************/
828 static void BluezHandleAdvertisementFromDevice(BluezDevice1 * aDevice, BluezEndpoint * endpoint)
830 const char * address = bluez_device1_get_address(aDevice);
831 const char * flags = bluez_device1_get_advertising_flags(aDevice);
832 GVariant * serviceData = bluez_device1_get_service_data(aDevice);
834 GVariantIter serviceIterator;
835 GVariant * serviceEntry;
836 chip::Ble::ChipBleUUID uuid;
837 chip::Ble::ChipBLEDeviceIdentificationInfo deviceInfo;
838 char * debugStr = nullptr;
841 // service data is optional and may not be present
842 VerifyOrExit(serviceData != nullptr, );
844 ChipLogDetail(DeviceLayer, "TRACE: Device %s Advertising flags: %s", address, flags);
845 debugStr = g_variant_print(serviceData, TRUE);
846 ChipLogDetail(DeviceLayer, "TRACE: Device %s Service data: %s", address, debugStr);
848 g_variant_iter_init(&serviceIterator, serviceData);
850 while ((serviceEntry = g_variant_iter_next_value(&serviceIterator)) != nullptr)
852 GVariant * key = g_variant_get_child_value(serviceEntry, 0);
853 GVariant * val = g_variant_get_child_value(serviceEntry, 1);
854 const auto uuidStr = g_variant_get_string(key, &dataLen);
855 const void * rawData;
857 VerifyOrExit(chip::Ble::StringToUUID(uuidStr, uuid), ChipLogError(DeviceLayer, "TRACE: Invalid BLE UUID format"));
859 if (!UUIDsMatch(&uuid, &Ble::CHIP_BLE_SVC_ID))
862 rawData = g_variant_get_fixed_array(g_variant_get_variant(val), &dataLen, sizeof(uint8_t));
863 VerifyOrExit(dataLen == sizeof(deviceInfo), ChipLogError(DeviceLayer, "TRACE: Invalid BLE Device info"));
865 memcpy(&deviceInfo, rawData, dataLen);
866 ChipLogDetail(DeviceLayer, "TRACE: Found CHIP BLE Device: %" PRIu16, deviceInfo.GetDeviceDiscriminator());
868 if (endpoint->mDiscoveryRequest.mDiscriminator == deviceInfo.GetDeviceDiscriminator() &&
869 endpoint->mDiscoveryRequest.mAutoConnect)
870 ConnectDevice(aDevice);
877 static void BluezSignalInterfacePropertiesChanged(GDBusObjectManagerClient * aManager, GDBusObjectProxy * aObject,
878 GDBusProxy * aInterface, GVariant * aChangedProperties,
879 const gchar * const * aInvalidatedProps, gpointer apClosure)
882 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
883 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
884 VerifyOrExit(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
886 if (strcmp(g_dbus_proxy_get_interface_name(aInterface), DEVICE_INTERFACE) == 0)
888 BluezDevice1 * device = BLUEZ_DEVICE1(aInterface);
893 if (BluezIsDeviceOnAdapter(device, endpoint->mpAdapter))
895 BluezConnection * conn =
896 static_cast<BluezConnection *>(g_hash_table_lookup(endpoint->mpConnMap, g_dbus_proxy_get_object_path(aInterface)));
897 g_variant_iter_init(&iter, aChangedProperties);
898 while (g_variant_iter_next(&iter, "{&sv}", &key, &value))
900 if (strcmp(key, "Connected") == 0)
903 connected = g_variant_get_boolean(value);
907 ChipLogDetail(DeviceLayer, "Bluez coonnected");
908 // for a central, the connection has been already allocated. For a peripheral, it has not.
909 // todo do we need this ? we could handle all connection the same wa...
910 if (endpoint->mIsCentral)
911 SuccessOrExit(conn != nullptr);
913 if (!endpoint->mIsCentral)
915 VerifyOrExit(conn == nullptr,
916 ChipLogError(DeviceLayer, "FAIL: connection already tracked: conn: %x device: %s", conn,
917 g_dbus_proxy_get_object_path(aInterface)));
918 conn = g_new0(BluezConnection, 1);
919 conn->mpPeerAddress = g_strdup(bluez_device1_get_address(device));
920 conn->mpDevice = static_cast<BluezDevice1 *>(g_object_ref(device));
921 conn->mpEndpoint = endpoint;
922 BluezConnectionInit(conn);
923 endpoint->mpPeerDevicePath = g_strdup(g_dbus_proxy_get_object_path(aInterface));
924 ChipLogDetail(DeviceLayer, "Device %s (Path: %s) Connected", conn->mpPeerAddress,
925 endpoint->mpPeerDevicePath);
926 g_hash_table_insert(endpoint->mpConnMap, endpoint->mpPeerDevicePath, conn);
928 // for central, we do not call BluezConnectionInit until the services have been resolved
930 BLEManagerImpl::CHIPoBluez_NewConnection(conn);
934 ChipLogDetail(DeviceLayer, "Bluez disconnected");
935 BLEManagerImpl::CHIPoBluez_ConnectionClosed(conn);
936 BluezOTConnectionDestroy(conn);
937 g_hash_table_remove(endpoint->mpConnMap, g_dbus_proxy_get_object_path(aInterface));
940 else if (strcmp(key, "ServicesResolved") == 0)
943 resolved = g_variant_get_boolean(value);
945 if (endpoint->mIsCentral && conn != nullptr && resolved == TRUE)
947 /* delay to idle, this is to workaround race in handling
948 * of interface-added and properites-changed signals
949 * it looks like we cannot specify order of those
950 * handlers and currently implementation assumes
951 * that interfaces-added is called first.
953 * TODO figure out if we can avoid this
955 g_idle_add(BluezConnectionInitIdle, conn);
958 else if (strcmp(key, "RSSI") == 0)
960 /* when discovery starts we will get this one device is
961 * found even if device object was already present
963 if (endpoint->mIsCentral)
965 BluezHandleAdvertisementFromDevice(device, endpoint);
969 g_variant_unref(value);
977 static void BluezHandleNewDevice(BluezDevice1 * device, BluezEndpoint * apEndpoint)
979 VerifyOrExit(apEndpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
980 if (apEndpoint->mIsCentral)
982 BluezHandleAdvertisementFromDevice(device, apEndpoint);
986 // We need to handle device connection both this function and BluezSignalInterfacePropertiesChanged
987 // When a device is connected for first time, this function will be triggerred.
988 // The future connections for the same device will trigger ``Connect'' property change.
989 // TODO: Factor common code in the two function.
990 BluezConnection * conn;
991 VerifyOrExit(bluez_device1_get_connected(device), ChipLogError(DeviceLayer, "FAIL: device is not connected"));
993 conn = static_cast<BluezConnection *>(
994 g_hash_table_lookup(apEndpoint->mpConnMap, g_dbus_proxy_get_object_path(G_DBUS_PROXY(device))));
995 VerifyOrExit(conn == nullptr,
996 ChipLogError(DeviceLayer, "FAIL: connection already tracked: conn: %x new device: %s", conn,
997 g_dbus_proxy_get_object_path(G_DBUS_PROXY(device))));
999 conn = g_new0(BluezConnection, 1);
1000 conn->mpPeerAddress = g_strdup(bluez_device1_get_address(device));
1001 conn->mpDevice = static_cast<BluezDevice1 *>(g_object_ref(device));
1002 conn->mpEndpoint = apEndpoint;
1003 BluezConnectionInit(conn);
1004 apEndpoint->mpPeerDevicePath = g_strdup(g_dbus_proxy_get_object_path(G_DBUS_PROXY(device)));
1005 ChipLogDetail(DeviceLayer, "Device %s (Path: %s) Connected", conn->mpPeerAddress, apEndpoint->mpPeerDevicePath);
1006 g_hash_table_insert(apEndpoint->mpConnMap, g_strdup(g_dbus_proxy_get_object_path(G_DBUS_PROXY(device))), conn);
1013 static void BluezSignalOnObjectAdded(GDBusObjectManager * aManager, GDBusObject * aObject, gpointer apClosure)
1015 // TODO: right now we do not handle addition/removal of adapters
1016 // Primary focus here is to handle addition of a device
1018 BluezObject * o = BLUEZ_OBJECT(aObject);
1019 BluezDevice1 * device = bluez_object_get_device1(o);
1020 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
1021 if (device != nullptr)
1023 if (BluezIsDeviceOnAdapter(device, endpoint->mpAdapter) == TRUE)
1025 BluezHandleNewDevice(device, endpoint);
1028 g_object_unref(device);
1032 static void BluezSignalOnObjectRemoved(GDBusObjectManager * aManager, GDBusObject * aObject, gpointer apClosure)
1034 // TODO: for Device1, lookup connection, and call otPlatTobleHandleDisconnected
1035 // for Adapter1: unclear, crash if this pertains to our adapter? at least null out the endpoint->mpAdapter.
1036 // for Characteristic1, or GattService -- handle here via calling otPlatTobleHandleDisconnected, or ignore.
1039 static BluezGattService1 * BluezServiceCreate(gpointer apClosure)
1041 BluezObjectSkeleton * object;
1042 BluezGattService1 * service;
1043 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
1045 endpoint->mpServicePath = g_strdup_printf("%s/service", endpoint->mpRootPath);
1046 ChipLogDetail(DeviceLayer, "CREATE service object at %s", endpoint->mpServicePath);
1047 object = bluez_object_skeleton_new(endpoint->mpServicePath);
1049 service = bluez_gatt_service1_skeleton_new();
1050 bluez_gatt_service1_set_uuid(service, "0xFEAF");
1051 // device is only valid for remote services
1052 bluez_gatt_service1_set_primary(service, TRUE);
1054 // includes -- unclear whether required. Might be filled in later
1055 bluez_object_skeleton_set_gatt_service1(object, service);
1056 g_dbus_object_manager_server_export(endpoint->mpRoot, G_DBUS_OBJECT_SKELETON(object));
1057 g_object_unref(object);
1062 static void bluezObjectsSetup(BluezEndpoint * apEndpoint)
1064 GList * objects = nullptr;
1066 char * expectedPath = nullptr;
1068 VerifyOrExit(apEndpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1070 expectedPath = g_strdup_printf("%s/hci%d", BLUEZ_PATH, apEndpoint->mNodeId);
1071 objects = g_dbus_object_manager_get_objects(apEndpoint->mpObjMgr);
1073 for (l = objects; l != nullptr && apEndpoint->mpAdapter == nullptr; l = l->next)
1075 BluezObject * object = BLUEZ_OBJECT(l->data);
1078 interfaces = g_dbus_object_get_interfaces(G_DBUS_OBJECT(object));
1080 for (ll = interfaces; ll != nullptr; ll = ll->next)
1082 if (BLUEZ_IS_ADAPTER1(ll->data))
1083 { // we found the adapter
1084 BluezAdapter1 * adapter = BLUEZ_ADAPTER1(ll->data);
1085 char * addr = const_cast<char *>(bluez_adapter1_get_address(adapter));
1086 if (apEndpoint->mpAdapterAddr == nullptr) // no adapter address provided, bind to the hci indicated by nodeid
1088 if (strcmp(g_dbus_proxy_get_object_path(G_DBUS_PROXY(adapter)), expectedPath) == 0)
1090 apEndpoint->mpAdapter = static_cast<BluezAdapter1 *>(g_object_ref(adapter));
1095 if (strcmp(apEndpoint->mpAdapterAddr, addr) == 0)
1097 apEndpoint->mpAdapter = static_cast<BluezAdapter1 *>(g_object_ref(adapter));
1102 g_list_free_full(interfaces, g_object_unref);
1104 VerifyOrExit(apEndpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL apEndpoint->mpAdapter in %s", __func__));
1105 bluez_adapter1_set_powered(apEndpoint->mpAdapter, TRUE);
1107 // with BLE we are discoverable only when advertising so this can be
1109 bluez_adapter1_set_discoverable_timeout(apEndpoint->mpAdapter, 0);
1110 bluez_adapter1_set_discoverable(apEndpoint->mpAdapter, TRUE);
1113 g_list_free_full(objects, g_object_unref);
1114 g_free(expectedPath);
1117 static BluezConnection * GetBluezConnectionViaDevice(BluezEndpoint * apEndpoint)
1119 BluezConnection * retval =
1120 static_cast<BluezConnection *>(g_hash_table_lookup(apEndpoint->mpConnMap, apEndpoint->mpPeerDevicePath));
1121 // ChipLogError(DeviceLayer, "acquire connection object %p in (%s)", retval, __func__);
1125 #if CHIP_BLUEZ_CENTRAL_SUPPORT
1126 static BluezConnection * BluezCharacteristicGetBluezConnection(BluezGattCharacteristic1 * aChar, GVariant * aOptions,
1127 BluezEndpoint * apEndpoint)
1129 BluezConnection * retval = NULL;
1130 const gchar * path = NULL;
1131 GVariantDict options;
1134 VerifyOrExit(apEndpoint != NULL, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1135 VerifyOrExit(apEndpoint->mIsCentral, );
1137 /* TODO Unfortunately StartNotify/StopNotify doesn't provide info about
1138 * peer device in call params so we need look this up ourselves.
1140 if (aOptions == NULL)
1146 objects = g_dbus_object_manager_get_objects(apEndpoint->mpObjMgr);
1147 for (l = objects; l != NULL; l = l->next)
1149 BluezDevice1 * device = bluez_object_get_device1(BLUEZ_OBJECT(l->data));
1152 if (BluezIsDeviceOnAdapter(device, apEndpoint->mpAdapter))
1154 for (ll = objects; ll != NULL; ll = ll->next)
1156 BluezGattService1 * service = bluez_object_get_gatt_service1(BLUEZ_OBJECT(ll->data));
1157 if (service != NULL)
1159 if (BluezIsServiceOnDevice(service, device))
1161 if (BluezIsCharOnService(aChar, service))
1163 retval = (BluezConnection *) g_hash_table_lookup(
1164 apEndpoint->mpConnMap, g_dbus_proxy_get_object_path(G_DBUS_PROXY(device)));
1167 g_object_unref(service);
1173 g_object_unref(device);
1179 g_list_free_full(objects, g_object_unref);
1183 g_variant_dict_init(&options, aOptions);
1185 v = g_variant_dict_lookup_value(&options, "device", G_VARIANT_TYPE_OBJECT_PATH);
1187 VerifyOrExit(v != NULL, ChipLogError(DeviceLayer, "FAIL: No device option in dictionary (%s)", __func__));
1189 path = g_variant_get_string(v, NULL);
1191 retval = (BluezConnection *) g_hash_table_lookup(apEndpoint->mpConnMap, path);
1197 #endif // CHIP_BLUEZ_CENTRAL_SUPPORT
1199 void EndpointCleanup(BluezEndpoint * apEndpoint)
1201 if (apEndpoint != nullptr)
1203 if (apEndpoint->mpOwningName != nullptr)
1205 g_free(apEndpoint->mpOwningName);
1206 apEndpoint->mpOwningName = nullptr;
1208 if (apEndpoint->mpAdapterName != nullptr)
1210 g_free(apEndpoint->mpAdapterName);
1211 apEndpoint->mpAdapterName = nullptr;
1213 if (apEndpoint->mpAdapterAddr != nullptr)
1215 g_free(apEndpoint->mpAdapterAddr);
1216 apEndpoint->mpAdapterAddr = nullptr;
1218 if (apEndpoint->mpRootPath != nullptr)
1220 g_free(apEndpoint->mpRootPath);
1221 apEndpoint->mpRootPath = nullptr;
1223 if (apEndpoint->mpAdvPath != nullptr)
1225 g_free(apEndpoint->mpAdvPath);
1226 apEndpoint->mpAdvPath = nullptr;
1228 if (apEndpoint->mpServicePath != nullptr)
1230 g_free(apEndpoint->mpServicePath);
1231 apEndpoint->mpServicePath = nullptr;
1233 if (apEndpoint->mpConnMap != nullptr)
1235 g_hash_table_destroy(apEndpoint->mpConnMap);
1236 apEndpoint->mpConnMap = nullptr;
1238 if (apEndpoint->mpAdvertisingUUID != nullptr)
1240 g_free(apEndpoint->mpAdvertisingUUID);
1241 apEndpoint->mpAdvertisingUUID = nullptr;
1243 if (apEndpoint->mpPeerDevicePath != nullptr)
1245 g_free(apEndpoint->mpPeerDevicePath);
1246 apEndpoint->mpPeerDevicePath = nullptr;
1253 void BluezObjectsCleanup(BluezEndpoint * apEndpoint)
1255 g_object_unref(apEndpoint->mpAdapter);
1256 EndpointCleanup(apEndpoint);
1259 static void BluezPeripheralObjectsSetup(gpointer apClosure)
1262 static const char * const c1_flags[] = { "write", nullptr };
1263 static const char * const c2_flags[] = { "read", "indicate", nullptr };
1265 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
1266 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1268 endpoint->mpService = BluezServiceCreate(apClosure);
1269 // C1 characteristic
1271 BluezCharacteristicCreate(endpoint->mpService, g_strdup("c1"), g_strdup(CHIP_PLAT_BLE_UUID_C1_STRING), endpoint->mpRoot);
1272 bluez_gatt_characteristic1_set_flags(endpoint->mpC1, c1_flags);
1274 g_signal_connect(endpoint->mpC1, "handle-read-value", G_CALLBACK(BluezCharacteristicReadValue), apClosure);
1275 g_signal_connect(endpoint->mpC1, "handle-write-value", G_CALLBACK(BluezCharacteristicWriteValueError), NULL);
1276 g_signal_connect(endpoint->mpC1, "handle-acquire-write", G_CALLBACK(BluezCharacteristicAcquireWrite), apClosure);
1277 g_signal_connect(endpoint->mpC1, "handle-acquire-notify", G_CALLBACK(BluezCharacteristicAcquireNotifyError), NULL);
1278 g_signal_connect(endpoint->mpC1, "handle-start-notify", G_CALLBACK(BluezCharacteristicStartNotifyError), NULL);
1279 g_signal_connect(endpoint->mpC1, "handle-stop-notify", G_CALLBACK(BluezCharacteristicStopNotifyError), NULL);
1280 g_signal_connect(endpoint->mpC1, "handle-confirm", G_CALLBACK(BluezCharacteristicConfirmError), NULL);
1283 BluezCharacteristicCreate(endpoint->mpService, g_strdup("c2"), g_strdup(CHIP_PLAT_BLE_UUID_C2_STRING), endpoint->mpRoot);
1284 bluez_gatt_characteristic1_set_flags(endpoint->mpC2, c2_flags);
1285 g_signal_connect(endpoint->mpC2, "handle-read-value", G_CALLBACK(BluezCharacteristicReadValue), apClosure);
1286 g_signal_connect(endpoint->mpC2, "handle-write-value", G_CALLBACK(BluezCharacteristicWriteValueError), NULL);
1287 g_signal_connect(endpoint->mpC2, "handle-acquire-write", G_CALLBACK(BluezCharacteristicAcquireWriteError), NULL);
1288 g_signal_connect(endpoint->mpC2, "handle-acquire-notify", G_CALLBACK(BluezCharacteristicAcquireNotify), apClosure);
1289 g_signal_connect(endpoint->mpC2, "handle-start-notify", G_CALLBACK(BluezCharacteristicStartNotify), apClosure);
1290 g_signal_connect(endpoint->mpC2, "handle-stop-notify", G_CALLBACK(BluezCharacteristicStopNotify), apClosure);
1291 g_signal_connect(endpoint->mpC2, "handle-confirm", G_CALLBACK(BluezCharacteristicConfirm), apClosure);
1293 ChipLogDetail(DeviceLayer, "CHIP BTP C1 %s", bluez_gatt_characteristic1_get_service(endpoint->mpC1));
1294 ChipLogDetail(DeviceLayer, "CHIP BTP C2 %s", bluez_gatt_characteristic1_get_service(endpoint->mpC2));
1300 static void BluezOnBusAcquired(GDBusConnection * aConn, const gchar * aName, gpointer apClosure)
1302 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
1303 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1305 ChipLogDetail(DeviceLayer, "TRACE: Bus acquired for name %s", aName);
1307 endpoint->mpRootPath = g_strdup_printf("/chipoble/%04x", getpid() & 0xffff);
1308 endpoint->mpRoot = g_dbus_object_manager_server_new(endpoint->mpRootPath);
1309 g_dbus_object_manager_server_set_connection(endpoint->mpRoot, aConn);
1310 BluezPeripheralObjectsSetup(apClosure);
1316 #if CHIP_BLUEZ_NAME_MONITOR
1317 static void BluezOnNameAcquired(GDBusConnection * aConn, const gchar * aName, gpointer apClosure)
1319 ChipLogDetail(DeviceLayer, "TRACE: Owning name: Acquired %s", aName);
1322 static void BluezOnNameLost(GDBusConnection * aConn, const gchar * aName, gpointer apClosure)
1324 ChipLogDetail(DeviceLayer, "TRACE: Owning name: lost %s", aName);
1328 static void * BluezMainLoop(void * apClosure)
1330 GDBusObjectManager * manager;
1331 GError * error = nullptr;
1332 GDBusConnection * conn = nullptr;
1333 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
1334 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1336 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &error);
1337 VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "FAIL: get bus sync in %s, error: %s", __func__, error->message));
1339 if (endpoint->mpAdapterName != nullptr)
1340 endpoint->mpOwningName = g_strdup_printf("%s", endpoint->mpAdapterName);
1342 endpoint->mpOwningName = g_strdup_printf("C-%04x", getpid() & 0xffff);
1344 BluezOnBusAcquired(conn, endpoint->mpOwningName, apClosure);
1346 manager = g_dbus_object_manager_client_new_sync(
1347 conn, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, BLUEZ_INTERFACE, "/", bluez_object_manager_client_get_proxy_type,
1348 nullptr /* unused user data in the Proxy Type Func */, nullptr /*destroy notify */, nullptr /* cancellable */, &error);
1350 VerifyOrExit(manager != nullptr, ChipLogError(DeviceLayer, "FAIL: Error getting object manager client: %s", error->message));
1352 endpoint->mpObjMgr = manager;
1354 bluezObjectsSetup(endpoint);
1357 // reenable if we want to handle the bluetoothd restart
1358 g_signal_connect (manager,
1359 "notify::name-owner",
1360 G_CALLBACK (on_notify_name_owner),
1363 g_signal_connect(manager, "object-added", G_CALLBACK(BluezSignalOnObjectAdded), apClosure);
1364 g_signal_connect(manager, "object-removed", G_CALLBACK(BluezSignalOnObjectRemoved), apClosure);
1365 g_signal_connect(manager, "interface-proxy-properties-changed", G_CALLBACK(BluezSignalInterfacePropertiesChanged), apClosure);
1367 ChipLogDetail(DeviceLayer, "TRACE: Bluez mainloop starting %s", __func__);
1368 g_main_loop_run(sBluezMainLoop);
1369 ChipLogDetail(DeviceLayer, "TRACE: Bluez mainloop stopping %s", __func__);
1371 BluezObjectsCleanup(endpoint);
1374 if (error != nullptr)
1375 g_error_free(error);
1379 bool BluezRunOnBluezThread(int (*aCallback)(void *), void * apClosure)
1381 GMainContext * context = nullptr;
1382 const char * msg = nullptr;
1384 VerifyOrExit(sBluezMainLoop != nullptr, msg = "FAIL: NULL sBluezMainLoop");
1385 VerifyOrExit(g_main_loop_is_running(sBluezMainLoop), msg = "FAIL: sBluezMainLoop not running");
1387 context = g_main_loop_get_context(sBluezMainLoop);
1388 VerifyOrExit(context != nullptr, msg = "FAIL: NULL main context");
1389 g_main_context_invoke(context, aCallback, apClosure);
1394 ChipLogDetail(DeviceLayer, "%s in %s", msg, __func__);
1397 return msg == nullptr;
1400 static gboolean BluezC2Indicate(void * apClosure)
1402 ConnectionDataBundle * closure = nullptr;
1403 BluezConnection * conn = nullptr;
1404 GError * error = nullptr;
1407 size_t len, written;
1409 closure = static_cast<ConnectionDataBundle *>(apClosure);
1410 VerifyOrExit(closure != nullptr, ChipLogError(DeviceLayer, "ConnectionDataBundle is NULL in %s", __func__));
1412 conn = closure->mpConn;
1413 VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__));
1414 VerifyOrExit(conn->mpC2 != nullptr, ChipLogError(DeviceLayer, "FAIL: C2 Indicate: %s", "NULL C2"));
1416 if (bluez_gatt_characteristic1_get_notify_acquired(conn->mpC2) == TRUE)
1418 buf = (char *) g_variant_get_fixed_array(closure->mpVal, &len, sizeof(uint8_t));
1419 VerifyOrExit(len <= static_cast<size_t>(std::numeric_limits<gssize>::max()),
1420 ChipLogError(DeviceLayer, "FAIL: buffer too large in %s", __func__));
1421 status = g_io_channel_write_chars(conn->mC2Channel.mpChannel, buf, static_cast<gssize>(len), &written, &error);
1422 g_variant_unref(closure->mpVal);
1423 closure->mpVal = nullptr;
1425 VerifyOrExit(status == G_IO_STATUS_NORMAL, ChipLogError(DeviceLayer, "FAIL: C2 Indicate: %s", error->message));
1429 bluez_gatt_characteristic1_set_value(conn->mpC2, closure->mpVal);
1430 closure->mpVal = nullptr;
1434 if (closure != nullptr)
1438 g_variant_unref(closure->mpVal);
1443 if (error != nullptr)
1444 g_error_free(error);
1445 return G_SOURCE_REMOVE;
1448 bool SendBluezIndication(BLE_CONNECTION_OBJECT apConn, chip::System::PacketBufferHandle apBuf)
1450 ConnectionDataBundle * closure;
1451 const char * msg = nullptr;
1452 bool success = false;
1453 uint8_t * buffer = nullptr;
1456 VerifyOrExit(!apBuf.IsNull(), ChipLogError(DeviceLayer, "apBuf is NULL in %s", __func__));
1457 buffer = apBuf->Start();
1458 len = apBuf->DataLength();
1460 closure = g_new(ConnectionDataBundle, 1);
1461 closure->mpConn = static_cast<BluezConnection *>(apConn);
1463 closure->mpVal = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, buffer, len * sizeof(uint8_t), sizeof(uint8_t));
1465 success = BluezRunOnBluezThread(BluezC2Indicate, closure);
1470 ChipLogError(Ble, msg);
1476 static gboolean BluezDisconnect(void * apClosure)
1478 BluezConnection * conn = static_cast<BluezConnection *>(apClosure);
1479 GError * error = nullptr;
1482 VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "conn is NULL in %s", __func__));
1483 VerifyOrExit(conn->mpDevice != nullptr, ChipLogError(DeviceLayer, "FAIL: Disconnect: %s", "NULL Device"));
1485 ChipLogDetail(DeviceLayer, "%s peer=%s", __func__, bluez_device1_get_address(conn->mpDevice));
1487 success = bluez_device1_call_disconnect_sync(conn->mpDevice, nullptr, &error);
1488 VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: Disconnect: %s", error->message));
1491 if (error != nullptr)
1492 g_error_free(error);
1493 return G_SOURCE_REMOVE;
1496 static int CloseBleconnectionCB(void * apAppState)
1498 BluezDisconnect(apAppState);
1499 return G_SOURCE_REMOVE;
1502 bool CloseBluezConnection(BLE_CONNECTION_OBJECT apConn)
1504 return BluezRunOnBluezThread(CloseBleconnectionCB, apConn);
1507 CHIP_ERROR StartBluezAdv(BluezEndpoint * apEndpoint)
1509 CHIP_ERROR err = CHIP_NO_ERROR;
1510 if (!BluezRunOnBluezThread(BluezAdvStart, apEndpoint))
1512 err = CHIP_ERROR_INCORRECT_STATE;
1513 ChipLogError(Ble, "Failed to schedule BluezAdvStart() on CHIPoBluez thread");
1518 CHIP_ERROR StopBluezAdv(BluezEndpoint * apEndpoint)
1520 CHIP_ERROR err = CHIP_NO_ERROR;
1521 if (!BluezRunOnBluezThread(BluezAdvStop, apEndpoint))
1523 err = CHIP_ERROR_INCORRECT_STATE;
1524 ChipLogError(Ble, "Failed to schedule BluezAdvStop() on CHIPoBluez thread");
1529 CHIP_ERROR BluezAdvertisementSetup(BluezEndpoint * apEndpoint)
1531 CHIP_ERROR err = CHIP_NO_ERROR;
1532 if (!BluezRunOnBluezThread(BluezAdvSetup, apEndpoint))
1534 err = CHIP_ERROR_INCORRECT_STATE;
1535 ChipLogError(Ble, "Failed to schedule BluezAdvertisementSetup() on CHIPoBluez thread");
1540 CHIP_ERROR BluezGattsAppRegister(BluezEndpoint * apEndpoint)
1542 CHIP_ERROR err = CHIP_NO_ERROR;
1543 if (!BluezRunOnBluezThread(BluezPeripheralRegisterApp, apEndpoint))
1545 err = CHIP_ERROR_INCORRECT_STATE;
1546 ChipLogError(Ble, "Failed to schedule BluezPeripheralRegisterApp() on CHIPoBluez thread");
1551 CHIP_ERROR ConfigureBluezAdv(BLEAdvConfig & aBleAdvConfig, BluezEndpoint * apEndpoint)
1553 const char * msg = nullptr;
1554 CHIP_ERROR err = CHIP_NO_ERROR;
1555 VerifyOrExit(aBleAdvConfig.mpBleName != nullptr, msg = "FAIL: BLE name is NULL");
1556 VerifyOrExit(aBleAdvConfig.mpAdvertisingUUID != nullptr, msg = "FAIL: BLE mpAdvertisingUUID is NULL in %s");
1558 apEndpoint->mpAdapterName = g_strdup(aBleAdvConfig.mpBleName);
1559 apEndpoint->mpAdvertisingUUID = g_strdup(aBleAdvConfig.mpAdvertisingUUID);
1560 apEndpoint->mNodeId = aBleAdvConfig.mNodeId;
1561 apEndpoint->mType = aBleAdvConfig.mType;
1562 apEndpoint->mDuration = aBleAdvConfig.mDuration;
1563 apEndpoint->mDuration = aBleAdvConfig.mDuration;
1565 err = ConfigurationMgr().GetBLEDeviceIdentificationInfo(apEndpoint->mDeviceIdInfo);
1571 ChipLogDetail(DeviceLayer, "%s in %s", msg, __func__);
1572 err = CHIP_ERROR_INCORRECT_STATE;
1577 CHIP_ERROR InitBluezBleLayer(bool aIsCentral, char * apBleAddr, BLEAdvConfig & aBleAdvConfig, void *& apEndpoint)
1579 CHIP_ERROR err = CHIP_NO_ERROR;
1580 bool retval = false;
1583 BluezEndpoint * endpoint = nullptr;
1585 VerifyOrExit(pipe2(sBluezFD, O_DIRECT) == 0, ChipLogError(DeviceLayer, "FAIL: open pipe in %s", __func__));
1587 // initialize server endpoint
1588 endpoint = g_new0(BluezEndpoint, 1);
1589 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "FAIL: memory allocation in %s", __func__));
1591 if (apBleAddr != nullptr)
1592 endpoint->mpAdapterAddr = g_strdup(apBleAddr);
1594 endpoint->mpAdapterAddr = nullptr;
1596 endpoint->mpConnMap = g_hash_table_new(g_str_hash, g_str_equal);
1597 endpoint->mIsCentral = aIsCentral;
1601 err = ConfigureBluezAdv(aBleAdvConfig, endpoint);
1605 sBluezMainLoop = g_main_loop_new(nullptr, FALSE);
1606 VerifyOrExit(sBluezMainLoop != nullptr, ChipLogError(DeviceLayer, "FAIL: memory alloc in %s", __func__));
1608 pthreadErr = pthread_create(&sBluezThread, nullptr, BluezMainLoop, endpoint);
1610 VerifyOrExit(pthreadErr == 0, ChipLogError(DeviceLayer, "FAIL: pthread_create (%s) in %s", strerror(tmpErrno), __func__));
1618 apEndpoint = endpoint;
1619 ChipLogDetail(DeviceLayer, "PlatformBlueZInit init success");
1623 EndpointCleanup(endpoint);
1629 // StartDiscovery callbacks
1631 using DiscoveryTaskArg = std::pair<BluezEndpoint *, BluezDiscoveryRequest>;
1633 void StartDiscoveryDone(GObject * aObject, GAsyncResult * aResult, gpointer apEndpoint)
1635 BluezAdapter1 * adapter = BLUEZ_ADAPTER1(aObject);
1636 GError * error = nullptr;
1637 gboolean success = bluez_adapter1_call_start_discovery_finish(adapter, aResult, &error);
1639 VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: StartDiscovery : %s", error->message));
1640 ChipLogDetail(DeviceLayer, "StartDiscovery complete");
1643 if (error != nullptr)
1644 g_error_free(error);
1647 static gboolean StartDiscoveryImpl(void * apDiscoveryTaskArg)
1649 DiscoveryTaskArg * taskArg = static_cast<DiscoveryTaskArg *>(apDiscoveryTaskArg);
1650 BluezEndpoint * endpoint;
1652 VerifyOrExit(taskArg != nullptr, ChipLogError(DeviceLayer, "taskArg is NULL in %s", __func__));
1653 endpoint = taskArg->first;
1655 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1656 VerifyOrExit(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "mpAdapter is NULL in %s", __func__));
1658 endpoint->mDiscoveryRequest = taskArg->second;
1659 bluez_adapter1_call_start_discovery(endpoint->mpAdapter, nullptr, StartDiscoveryDone, endpoint);
1664 return G_SOURCE_REMOVE;
1667 CHIP_ERROR StartDiscovery(BluezEndpoint * apEndpoint, const BluezDiscoveryRequest aRequest)
1669 DiscoveryTaskArg * const taskArg = new DiscoveryTaskArg(apEndpoint, aRequest);
1670 CHIP_ERROR error = CHIP_NO_ERROR;
1672 if (!BluezRunOnBluezThread(StartDiscoveryImpl, taskArg))
1674 ChipLogError(Ble, "Failed to schedule StartDiscoveryImpl() on CHIPoBluez thread");
1676 error = CHIP_ERROR_INCORRECT_STATE;
1682 // StopDiscovery callbacks
1684 static void StopDiscoveryDone(GObject * aObject, GAsyncResult * aResult, gpointer apEndpoint)
1686 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
1687 BluezAdapter1 * adapter = BLUEZ_ADAPTER1(aObject);
1688 GError * error = nullptr;
1689 gboolean success = bluez_adapter1_call_stop_discovery_finish(adapter, aResult, &error);
1691 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1692 endpoint->mDiscoveryRequest = {};
1694 VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: StopDiscovery : %s", error->message));
1695 ChipLogDetail(DeviceLayer, "StopDiscovery complete");
1698 if (error != nullptr)
1699 g_error_free(error);
1702 static gboolean StopDiscoveryImpl(void * apEndpoint)
1704 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
1706 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1707 VerifyOrExit(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "mpAdapter is NULL in %s", __func__));
1709 bluez_adapter1_call_stop_discovery(endpoint->mpAdapter, nullptr, StopDiscoveryDone, apEndpoint);
1712 return G_SOURCE_REMOVE;
1715 CHIP_ERROR StopDiscovery(BluezEndpoint * apEndpoint)
1717 CHIP_ERROR error = CHIP_NO_ERROR;
1719 if (!BluezRunOnBluezThread(StopDiscoveryImpl, apEndpoint))
1721 ChipLogError(Ble, "Failed to schedule StopDiscoveryImpl() on CHIPoBluez thread");
1722 error = CHIP_ERROR_INCORRECT_STATE;
1728 // ConnectDevice callbacks
1730 static void ConnectDeviceDone(GObject * aObject, GAsyncResult * aResult, gpointer)
1732 BluezDevice1 * device = BLUEZ_DEVICE1(aObject);
1733 GError * error = nullptr;
1734 gboolean success = bluez_device1_call_connect_finish(device, aResult, &error);
1736 VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: ConnectDevice : %s", error->message));
1737 ChipLogDetail(DeviceLayer, "ConnectDevice complete");
1740 if (error != nullptr)
1741 g_error_free(error);
1744 static gboolean ConnectDeviceImpl(void * apDevice)
1746 BluezDevice1 * device = static_cast<BluezDevice1 *>(apDevice);
1748 VerifyOrExit(device != nullptr, ChipLogError(DeviceLayer, "device is NULL in %s", __func__));
1750 bluez_device1_call_connect(device, nullptr, ConnectDeviceDone, nullptr);
1753 return G_SOURCE_REMOVE;
1756 CHIP_ERROR ConnectDevice(BluezDevice1 * apDevice)
1758 CHIP_ERROR error = CHIP_NO_ERROR;
1760 if (!BluezRunOnBluezThread(ConnectDeviceImpl, apDevice))
1762 ChipLogError(Ble, "Failed to schedule ConnectDeviceImpl() on CHIPoBluez thread");
1763 error = CHIP_ERROR_INCORRECT_STATE;
1769 } // namespace Internal
1770 } // namespace DeviceLayer
1772 #endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE