3 * Copyright (c) 2020-2021 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>
54 #include <protocols/Protocols.h>
55 #include <setup_payload/AdditionalDataPayloadGenerator.h>
56 #include <support/BitFlags.h>
57 #include <support/CHIPMemString.h>
59 #if CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE
61 #include <gio/gunixfdlist.h>
68 #include <platform/Linux/BLEManagerImpl.h>
69 #include <support/CodeUtils.h>
70 #include <support/ReturnMacros.h>
71 #include <system/TLVPacketBufferBackingStore.h>
73 #include "BluezObjectIterator.h"
74 #include "BluezObjectList.h"
79 using namespace chip::Protocols;
80 using chip::Platform::CopyString;
83 namespace DeviceLayer {
86 static BluezConnection * GetBluezConnectionViaDevice(BluezEndpoint * apEndpoint);
90 class BluezEndpointObjectList : public BluezObjectList
93 explicit BluezEndpointObjectList(BluezEndpoint * apEndpoint)
95 VerifyOrReturn(apEndpoint != nullptr, ChipLogError(DeviceLayer, "apEndpoint is NULL in %s", __func__));
96 Initialize(apEndpoint->mpObjMgr);
102 static gboolean BluezAdvertisingRelease(BluezLEAdvertisement1 * aAdv, GDBusMethodInvocation * aInvocation, gpointer apClosure)
104 bool isSuccess = false;
105 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
106 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
107 VerifyOrExit(aAdv != nullptr, ChipLogError(DeviceLayer, "BluezLEAdvertisement1 is NULL in %s", __func__));
108 ChipLogDetail(DeviceLayer, "Release adv object in %s", __func__);
110 g_dbus_object_manager_server_unexport(endpoint->mpRoot, endpoint->mpAdvPath);
111 endpoint->mIsAdvertising = false;
115 return isSuccess ? TRUE : FALSE;
118 static BluezLEAdvertisement1 * BluezAdvertisingCreate(BluezEndpoint * apEndpoint)
120 BluezLEAdvertisement1 * adv = nullptr;
121 BluezObjectSkeleton * object;
122 GVariant * serviceData;
123 GVariant * serviceUUID;
125 GVariantBuilder serviceDataBuilder;
126 GVariantBuilder serviceUUIDsBuilder;
129 VerifyOrExit(apEndpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
130 if (apEndpoint->mpAdvPath == nullptr)
131 apEndpoint->mpAdvPath = g_strdup_printf("%s/advertising", apEndpoint->mpRootPath);
133 ChipLogDetail(DeviceLayer, "Create adv object at %s", apEndpoint->mpAdvPath);
134 object = bluez_object_skeleton_new(apEndpoint->mpAdvPath);
136 adv = bluez_leadvertisement1_skeleton_new();
138 g_variant_builder_init(&serviceDataBuilder, G_VARIANT_TYPE("a{sv}"));
139 g_variant_builder_init(&serviceUUIDsBuilder, G_VARIANT_TYPE("as"));
141 g_variant_builder_add(&serviceDataBuilder, "{sv}", apEndpoint->mpAdvertisingUUID,
142 g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, &apEndpoint->mDeviceIdInfo,
143 sizeof(apEndpoint->mDeviceIdInfo), sizeof(uint8_t)));
144 g_variant_builder_add(&serviceUUIDsBuilder, "s", apEndpoint->mpAdvertisingUUID);
146 if (apEndpoint->mpAdapterName != nullptr)
147 localName = g_strdup_printf("%s", apEndpoint->mpAdapterName);
149 localName = g_strdup_printf("%s%04x", CHIP_DEVICE_CONFIG_BLE_DEVICE_NAME_PREFIX, getpid() & 0xffff);
151 serviceData = g_variant_builder_end(&serviceDataBuilder);
152 serviceUUID = g_variant_builder_end(&serviceUUIDsBuilder);
154 debugStr = g_variant_print(serviceData, TRUE);
155 ChipLogDetail(DeviceLayer, "SET service data to %s", debugStr);
158 bluez_leadvertisement1_set_type_(adv, (apEndpoint->mType & BLUEZ_ADV_TYPE_CONNECTABLE) ? "peripheral" : "broadcast");
159 // empty manufacturer data
160 // empty solicit UUIDs
161 bluez_leadvertisement1_set_service_data(adv, serviceData);
164 // Setting "Discoverable" to False on the adapter and to True on the advertisement convinces
165 // Bluez to set "BR/EDR Not Supported" flag. Bluez doesn't provide API to do that explicitly
166 // and the flag is necessary to force using LE transport.
167 bluez_leadvertisement1_set_discoverable(adv, (apEndpoint->mType & BLUEZ_ADV_TYPE_SCANNABLE) ? TRUE : FALSE);
168 if (apEndpoint->mType & BLUEZ_ADV_TYPE_SCANNABLE)
169 bluez_leadvertisement1_set_discoverable_timeout(adv, UINT16_MAX);
171 // advertising name corresponding to the PID and object path, for debug purposes
172 bluez_leadvertisement1_set_local_name(adv, localName);
173 bluez_leadvertisement1_set_service_uuids(adv, serviceUUID);
175 // 0xffff means no appearance
176 bluez_leadvertisement1_set_appearance(adv, 0xffff);
178 bluez_leadvertisement1_set_duration(adv, apEndpoint->mDuration);
179 // empty duration, we don't have a clear notion what it would mean to timeslice between toble and anyone else
180 bluez_leadvertisement1_set_timeout(adv, 0);
181 // empty secondary channel for now
183 bluez_object_skeleton_set_leadvertisement1(object, adv);
184 g_signal_connect(adv, "handle-release", G_CALLBACK(BluezAdvertisingRelease), apEndpoint);
186 g_dbus_object_manager_server_export(apEndpoint->mpRoot, G_DBUS_OBJECT_SKELETON(object));
187 g_object_unref(object);
189 BLEManagerImpl::NotifyBLEPeripheralAdvConfiguredComplete(true, nullptr);
195 static void BluezAdvStartDone(GObject * aObject, GAsyncResult * aResult, gpointer apClosure)
197 BluezLEAdvertisingManager1 * advMgr = BLUEZ_LEADVERTISING_MANAGER1(aObject);
198 GError * error = nullptr;
199 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
200 gboolean success = FALSE;
202 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
204 success = bluez_leadvertising_manager1_call_register_advertisement_finish(advMgr, aResult, &error);
205 if (success == FALSE)
207 g_dbus_object_manager_server_unexport(endpoint->mpRoot, endpoint->mpAdvPath);
209 VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: RegisterAdvertisement : %s", error->message));
211 endpoint->mIsAdvertising = true;
213 ChipLogDetail(DeviceLayer, "RegisterAdvertisement complete");
216 BLEManagerImpl::NotifyBLEPeripheralAdvStartComplete(success == TRUE, nullptr);
217 if (error != nullptr)
221 static void BluezAdvStopDone(GObject * aObject, GAsyncResult * aResult, gpointer apClosure)
223 BluezLEAdvertisingManager1 * advMgr = BLUEZ_LEADVERTISING_MANAGER1(aObject);
224 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
225 GError * error = nullptr;
226 gboolean success = FALSE;
228 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
230 success = bluez_leadvertising_manager1_call_unregister_advertisement_finish(advMgr, aResult, &error);
232 if (success == FALSE)
234 g_dbus_object_manager_server_unexport(endpoint->mpRoot, endpoint->mpAdvPath);
238 endpoint->mIsAdvertising = false;
241 VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: UnregisterAdvertisement : %s", error->message));
243 ChipLogDetail(DeviceLayer, "UnregisterAdvertisement complete");
246 BLEManagerImpl::NotifyBLEPeripheralAdvStopComplete(success == TRUE, nullptr);
247 if (error != nullptr)
251 static gboolean BluezAdvSetup(BluezEndpoint * endpoint)
253 BluezLEAdvertisement1 * adv;
255 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
256 VerifyOrExit(endpoint->mIsAdvertising == FALSE, ChipLogError(DeviceLayer, "FAIL: Advertising already enabled in %s", __func__));
257 VerifyOrExit(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
259 adv = BluezAdvertisingCreate(endpoint);
260 VerifyOrExit(adv != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adv in %s", __func__));
263 return G_SOURCE_REMOVE;
266 static gboolean BluezAdvStart(BluezEndpoint * endpoint)
268 GDBusObject * adapter;
269 BluezLEAdvertisingManager1 * advMgr = nullptr;
270 GVariantBuilder optionsBuilder;
273 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
274 VerifyOrExit(!endpoint->mIsAdvertising,
275 ChipLogError(DeviceLayer, "FAIL: Advertising has already been enabled 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 g_variant_builder_init(&optionsBuilder, G_VARIANT_TYPE("a{sv}"));
285 options = g_variant_builder_end(&optionsBuilder);
287 bluez_leadvertising_manager1_call_register_advertisement(advMgr, endpoint->mpAdvPath, options, nullptr, BluezAdvStartDone,
291 return G_SOURCE_REMOVE;
294 static gboolean BluezAdvStop(BluezEndpoint * endpoint)
296 GDBusObject * adapter;
297 BluezLEAdvertisingManager1 * advMgr = nullptr;
299 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
300 VerifyOrExit(endpoint->mIsAdvertising,
301 ChipLogError(DeviceLayer, "FAIL: Advertising has already been disabled in %s", __func__));
302 VerifyOrExit(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
304 adapter = g_dbus_interface_get_object(G_DBUS_INTERFACE(endpoint->mpAdapter));
305 VerifyOrExit(adapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adapter in %s", __func__));
307 advMgr = bluez_object_get_leadvertising_manager1(BLUEZ_OBJECT(adapter));
308 VerifyOrExit(advMgr != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL advMgr in %s", __func__));
310 bluez_leadvertising_manager1_call_unregister_advertisement(advMgr, endpoint->mpAdvPath, nullptr, BluezAdvStopDone, endpoint);
313 return G_SOURCE_REMOVE;
316 static gboolean BluezCharacteristicReadValue(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
320 ChipLogDetail(DeviceLayer, "Received BluezCharacteristicReadValue");
321 val = bluez_gatt_characteristic1_get_value(aChar);
322 bluez_gatt_characteristic1_complete_read_value(aChar, aInvocation, val);
326 #if CHIP_BLUEZ_CHAR_WRITE_VALUE
327 static gboolean BluezCharacteristicWriteValue(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
328 GVariant * aValue, GVariant * aOptions, gpointer apEndpoint)
330 const uint8_t * tmpBuf;
333 bool isSuccess = false;
334 BluezConnection * conn = NULL;
336 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
337 VerifyOrExit(endpoint != NULL, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
339 VerifyOrExit(aValue != NULL, ChipLogError(DeviceLayer, "aValue is NULL in %s", __func__));
341 conn = GetBluezConnectionViaDevice(endpoint);
342 VerifyOrExit(conn != NULL,
343 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No CHIP Bluez connection"));
345 bluez_gatt_characteristic1_set_value(aChar, g_variant_ref(aValue));
347 tmpBuf = (uint8_t *) (g_variant_get_fixed_array(aValue, &len, sizeof(uint8_t)));
348 buf = (uint8_t *) (g_memdup(tmpBuf, len));
350 BLEManagerImpl::HandleRXCharWrite(conn, buf, len);
351 bluez_gatt_characteristic1_complete_write_value(aChar, aInvocation);
355 return isSuccess ? TRUE : FALSE;
359 static gboolean BluezCharacteristicWriteValueError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
360 GVariant * aValue, GVariant * aOptions, gpointer apClosure)
362 ChipLogDetail(DeviceLayer, "BluezCharacteristicWriteValueError");
363 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotSupported",
364 "Write for characteristic is unsupported");
368 static gboolean BluezCharacteristicWriteFD(GIOChannel * aChannel, GIOCondition aCond, gpointer apEndpoint)
374 bool isSuccess = false;
376 BluezConnection * conn = static_cast<BluezConnection *>(apEndpoint);
378 VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "No CHIP Bluez connection in %s", __func__));
380 VerifyOrExit(!(aCond & G_IO_HUP), ChipLogError(DeviceLayer, "INFO: socket disconnected in %s", __func__));
381 VerifyOrExit(!(aCond & (G_IO_ERR | G_IO_NVAL)), ChipLogError(DeviceLayer, "INFO: socket error in %s", __func__));
382 VerifyOrExit(aCond == G_IO_IN, ChipLogError(DeviceLayer, "FAIL: error in %s", __func__));
384 ChipLogDetail(DeviceLayer, "c1 %s mtu, %d", __func__, conn->mMtu);
386 buf = static_cast<gchar *>(g_malloc(conn->mMtu));
387 fd = g_io_channel_unix_get_fd(aChannel);
389 len = read(fd, buf, conn->mMtu);
391 VerifyOrExit(len > 0, ChipLogError(DeviceLayer, "FAIL: short read in %s (%d)", __func__, len));
393 // Casting len to size_t is safe, since we ensured that it's not negative.
394 newVal = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, buf, static_cast<size_t>(len), sizeof(uint8_t));
396 bluez_gatt_characteristic1_set_value(conn->mpC1, newVal);
397 BLEManagerImpl::HandleRXCharWrite(conn, reinterpret_cast<uint8_t *>(buf), static_cast<size_t>(len));
401 return isSuccess ? TRUE : FALSE;
404 static void Bluez_gatt_characteristic1_complete_acquire_write_with_fd(GDBusMethodInvocation * invocation, int fd, guint16 mtu)
406 GUnixFDList * fd_list = g_unix_fd_list_new();
409 index = g_unix_fd_list_append(fd_list, fd, nullptr);
411 g_dbus_method_invocation_return_value_with_unix_fd_list(invocation, g_variant_new("(@hq)", g_variant_new_handle(index), mtu),
415 static gboolean bluezCharacteristicDestroyFD(GIOChannel * aChannel, GIOCondition aCond, gpointer apClosure)
417 return G_SOURCE_REMOVE;
420 static gboolean BluezCharacteristicAcquireWrite(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
421 GVariant * aOptions, gpointer apEndpoint)
423 int fds[2] = { -1, -1 };
424 GIOChannel * channel;
426 GVariantDict options;
427 bool isSuccess = false;
428 BluezConnection * conn = nullptr;
430 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
431 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
433 conn = GetBluezConnectionViaDevice(endpoint);
434 VerifyOrExit(conn != nullptr,
435 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
437 ChipLogDetail(DeviceLayer, "BluezCharacteristicAcquireWrite is called, conn: %p", conn);
439 if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, fds) < 0)
441 errStr = strerror(errno);
442 ChipLogError(DeviceLayer, "FAIL: socketpair: %s in %s", errStr, __func__);
443 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "FD creation failed");
444 SuccessOrExit(false);
447 g_variant_dict_init(&options, aOptions);
448 if (g_variant_dict_contains(&options, "mtu") == TRUE)
450 GVariant * v = g_variant_dict_lookup_value(&options, "mtu", G_VARIANT_TYPE_UINT16);
451 conn->mMtu = g_variant_get_uint16(v);
455 ChipLogError(DeviceLayer, "FAIL: no MTU in options in %s", __func__);
456 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.InvalidArguments", "MTU negotiation failed");
457 SuccessOrExit(false);
460 channel = g_io_channel_unix_new(fds[0]);
461 g_io_channel_set_encoding(channel, nullptr, nullptr);
462 g_io_channel_set_close_on_unref(channel, TRUE);
463 g_io_channel_set_buffered(channel, FALSE);
465 conn->mC1Channel.mpChannel = channel;
466 conn->mC1Channel.mWatch = g_io_add_watch(channel, static_cast<GIOCondition>(G_IO_HUP | G_IO_IN | G_IO_ERR | G_IO_NVAL),
467 BluezCharacteristicWriteFD, conn);
469 bluez_gatt_characteristic1_set_write_acquired(aChar, TRUE);
471 Bluez_gatt_characteristic1_complete_acquire_write_with_fd(aInvocation, fds[1], conn->mMtu);
476 return isSuccess ? TRUE : FALSE;
479 static gboolean BluezCharacteristicAcquireWriteError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
482 ChipLogDetail(DeviceLayer, "BluezCharacteristicAcquireWriteError is called");
483 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotSupported",
484 "AcquireWrite for characteristic is unsupported");
488 static gboolean BluezCharacteristicAcquireNotify(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
489 GVariant * aOptions, gpointer apEndpoint)
491 int fds[2] = { -1, -1 };
492 GIOChannel * channel;
494 GVariantDict options;
495 BluezConnection * conn = nullptr;
496 bool isSuccess = false;
498 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
499 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
501 conn = GetBluezConnectionViaDevice(endpoint);
502 VerifyOrExit(conn != nullptr,
503 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
505 g_variant_dict_init(&options, aOptions);
506 if ((g_variant_dict_contains(&options, "mtu") == TRUE))
508 GVariant * v = g_variant_dict_lookup_value(&options, "mtu", G_VARIANT_TYPE_UINT16);
509 conn->mMtu = g_variant_get_uint16(v);
512 if (bluez_gatt_characteristic1_get_notifying(aChar))
514 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotPermitted", "Already notifying");
516 if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC, 0, fds) < 0)
518 errStr = strerror(errno);
519 ChipLogError(DeviceLayer, "FAIL: socketpair: %s in %s", errStr, __func__);
520 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "FD creation failed");
521 SuccessOrExit(false);
523 channel = g_io_channel_unix_new(fds[0]);
524 g_io_channel_set_encoding(channel, nullptr, nullptr);
525 g_io_channel_set_close_on_unref(channel, TRUE);
526 g_io_channel_set_buffered(channel, FALSE);
527 conn->mC2Channel.mpChannel = channel;
528 conn->mC2Channel.mWatch =
529 g_io_add_watch_full(channel, G_PRIORITY_DEFAULT_IDLE, static_cast<GIOCondition>(G_IO_HUP | G_IO_ERR | G_IO_NVAL),
530 bluezCharacteristicDestroyFD, conn, nullptr);
532 bluez_gatt_characteristic1_set_notify_acquired(aChar, TRUE);
534 // same reply as for AcquireWrite
535 Bluez_gatt_characteristic1_complete_acquire_write_with_fd(aInvocation, fds[1], conn->mMtu);
538 conn->mIsNotify = true;
539 BLEManagerImpl::HandleTXCharCCCDWrite(conn);
543 return isSuccess ? TRUE : FALSE;
546 static gboolean BluezCharacteristicAcquireNotifyError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
549 ChipLogDetail(DeviceLayer, "TRACE: AcquireNotify is called");
550 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotSupported",
551 "AcquireNotify for characteristic is unsupported");
555 static gboolean BluezCharacteristicStartNotify(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
558 bool isSuccess = false;
559 BluezConnection * conn = nullptr;
561 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
562 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
564 conn = GetBluezConnectionViaDevice(endpoint);
565 VerifyOrExit(conn != nullptr,
566 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
568 if (bluez_gatt_characteristic1_get_notifying(aChar) == TRUE)
570 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "Characteristic is already subscribed");
574 bluez_gatt_characteristic1_complete_start_notify(aChar, aInvocation);
575 bluez_gatt_characteristic1_set_notifying(aChar, TRUE);
576 conn->mIsNotify = true;
577 BLEManagerImpl::HandleTXCharCCCDWrite(conn);
582 return isSuccess ? TRUE : FALSE;
585 static gboolean BluezCharacteristicStartNotifyError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation)
587 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.NotSupported",
588 "Subscribing to characteristic is unsupported");
592 static gboolean BluezCharacteristicStopNotify(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
595 bool isSuccess = false;
596 BluezConnection * conn = nullptr;
598 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apEndpoint);
599 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
601 conn = GetBluezConnectionViaDevice(endpoint);
602 VerifyOrExit(conn != nullptr,
603 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "No Chipoble connection"));
605 if (bluez_gatt_characteristic1_get_notifying(aChar) == FALSE)
607 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "Characteristic is already unsubscribed");
611 bluez_gatt_characteristic1_complete_start_notify(aChar, aInvocation);
612 bluez_gatt_characteristic1_set_notifying(aChar, FALSE);
614 conn->mIsNotify = false;
619 return isSuccess ? TRUE : FALSE;
622 static gboolean BluezCharacteristicConfirm(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation,
625 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
626 BluezConnection * conn = GetBluezConnectionViaDevice(endpoint);
628 ChipLogDetail(Ble, "Indication confirmation, %p", conn);
629 BLEManagerImpl::HandleTXComplete(conn);
634 static gboolean BluezCharacteristicStopNotifyError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation)
636 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed",
637 "Unsubscribing from characteristic is unsupported");
641 static gboolean BluezCharacteristicConfirmError(BluezGattCharacteristic1 * aChar, GDBusMethodInvocation * aInvocation)
643 g_dbus_method_invocation_return_dbus_error(aInvocation, "org.bluez.Error.Failed", "Confirm from characteristic is unsupported");
647 static gboolean BluezIsDeviceOnAdapter(BluezDevice1 * aDevice, BluezAdapter1 * aAdapter)
649 return strcmp(bluez_device1_get_adapter(aDevice), g_dbus_proxy_get_object_path(G_DBUS_PROXY(aAdapter))) == 0 ? TRUE : FALSE;
652 static gboolean BluezIsServiceOnDevice(BluezGattService1 * aService, BluezDevice1 * aDevice)
654 return strcmp(bluez_gatt_service1_get_device(aService), g_dbus_proxy_get_object_path(G_DBUS_PROXY(aDevice))) == 0 ? TRUE
658 static gboolean BluezIsCharOnService(BluezGattCharacteristic1 * aChar, BluezGattService1 * aService)
660 ChipLogDetail(DeviceLayer, "Char1 %s", bluez_gatt_characteristic1_get_service(aChar));
661 ChipLogDetail(DeviceLayer, "Char1 %s", g_dbus_proxy_get_object_path(G_DBUS_PROXY(aService)));
662 return strcmp(bluez_gatt_characteristic1_get_service(aChar), g_dbus_proxy_get_object_path(G_DBUS_PROXY(aService))) == 0 ? TRUE
666 static void BluezConnectionInit(BluezConnection * apConn)
668 // populate the service and the characteristics
669 GList * objects = nullptr;
671 BluezEndpoint * endpoint = nullptr;
673 VerifyOrExit(apConn != nullptr, ChipLogError(DeviceLayer, "Bluez connection is NULL in %s", __func__));
675 endpoint = apConn->mpEndpoint;
676 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
678 if (!endpoint->mIsCentral)
680 apConn->mpService = BLUEZ_GATT_SERVICE1(g_object_ref(apConn->mpEndpoint->mpService));
681 apConn->mpC1 = BLUEZ_GATT_CHARACTERISTIC1(g_object_ref(endpoint->mpC1));
682 apConn->mpC2 = BLUEZ_GATT_CHARACTERISTIC1(g_object_ref(endpoint->mpC2));
686 objects = g_dbus_object_manager_get_objects(endpoint->mpObjMgr);
688 for (l = objects; l != nullptr; l = l->next)
690 BluezObject * object = BLUEZ_OBJECT(l->data);
691 BluezGattService1 * service = bluez_object_get_gatt_service1(object);
693 if (service != nullptr)
695 if ((BluezIsServiceOnDevice(service, apConn->mpDevice)) == TRUE &&
696 (strcmp(bluez_gatt_service1_get_uuid(service), CHIP_BLE_UUID_SERVICE_STRING) == 0))
698 apConn->mpService = service;
701 g_object_unref(service);
705 VerifyOrExit(apConn->mpService != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL service in %s", __func__));
707 for (l = objects; l != nullptr; l = l->next)
709 BluezObject * object = BLUEZ_OBJECT(l->data);
710 BluezGattCharacteristic1 * char1 = bluez_object_get_gatt_characteristic1(object);
712 if (char1 != nullptr)
714 if ((BluezIsCharOnService(char1, apConn->mpService) == TRUE) &&
715 (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C1_STRING) == 0))
717 apConn->mpC1 = char1;
719 else if ((BluezIsCharOnService(char1, apConn->mpService) == TRUE) &&
720 (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C2_STRING) == 0))
722 apConn->mpC2 = char1;
724 else if ((BluezIsCharOnService(char1, apConn->mpService) == TRUE) &&
725 (strcmp(bluez_gatt_characteristic1_get_uuid(char1), CHIP_PLAT_BLE_UUID_C3_STRING) == 0))
727 apConn->mpC3 = char1;
731 g_object_unref(char1);
733 if ((apConn->mpC1 != nullptr) && (apConn->mpC2 != nullptr))
740 VerifyOrExit(apConn->mpC1 != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL C1 in %s", __func__));
741 VerifyOrExit(apConn->mpC2 != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL C2 in %s", __func__));
745 if (objects != nullptr)
746 g_list_free_full(objects, g_object_unref);
749 static void BluezOTConnectionDestroy(BluezConnection * aConn)
754 g_object_unref(aConn->mpDevice);
755 if (aConn->mpService)
756 g_object_unref(aConn->mpService);
758 g_object_unref(aConn->mpC1);
760 g_object_unref(aConn->mpC2);
761 if (aConn->mpPeerAddress)
762 g_free(aConn->mpPeerAddress);
763 if (aConn->mC1Channel.mWatch > 0)
764 g_source_remove(aConn->mC1Channel.mWatch);
765 if (aConn->mC1Channel.mpChannel)
766 g_io_channel_unref(aConn->mC1Channel.mpChannel);
767 if (aConn->mC2Channel.mWatch > 0)
768 g_source_remove(aConn->mC2Channel.mWatch);
769 if (aConn->mC2Channel.mpChannel)
770 g_io_channel_unref(aConn->mC2Channel.mpChannel);
776 static BluezGattCharacteristic1 * BluezCharacteristicCreate(BluezGattService1 * aService, const char * aCharName,
777 const char * aUUID, GDBusObjectManagerServer * aRoot)
779 char * servicePath = g_strdup(g_dbus_object_get_object_path(g_dbus_interface_get_object(G_DBUS_INTERFACE(aService))));
780 char * charPath = g_strdup_printf("%s/%s", servicePath, aCharName);
781 BluezObjectSkeleton * object;
782 BluezGattCharacteristic1 * characteristic;
784 ChipLogDetail(DeviceLayer, "Create characteristic object at %s", charPath);
785 object = bluez_object_skeleton_new(charPath);
787 characteristic = bluez_gatt_characteristic1_skeleton_new();
788 bluez_gatt_characteristic1_set_uuid(characteristic, aUUID);
789 bluez_gatt_characteristic1_set_service(characteristic, servicePath);
791 bluez_object_skeleton_set_gatt_characteristic1(object, characteristic);
792 g_dbus_object_manager_server_export(aRoot, G_DBUS_OBJECT_SKELETON(object));
793 g_object_unref(object);
795 return characteristic;
798 static void BluezPeripheralRegisterAppDone(GObject * aObject, GAsyncResult * aResult, gpointer apClosure)
800 GError * error = nullptr;
801 BluezGattManager1 * gattMgr = BLUEZ_GATT_MANAGER1(aObject);
803 gboolean success = bluez_gatt_manager1_call_register_application_finish(gattMgr, aResult, &error);
805 VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: RegisterApplication : %s", error->message));
807 BLEManagerImpl::NotifyBLEPeripheralRegisterAppComplete(true, nullptr);
808 ChipLogDetail(DeviceLayer, "BluezPeripheralRegisterAppDone done");
811 if (error != nullptr)
813 BLEManagerImpl::NotifyBLEPeripheralRegisterAppComplete(false, nullptr);
818 gboolean BluezPeripheralRegisterApp(BluezEndpoint * endpoint)
820 GDBusObject * adapter;
821 BluezGattManager1 * gattMgr;
822 GVariantBuilder optionsBuilder;
825 VerifyOrExit(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
827 adapter = g_dbus_interface_get_object(G_DBUS_INTERFACE(endpoint->mpAdapter));
828 VerifyOrExit(adapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL adapter in %s", __func__));
830 gattMgr = bluez_object_get_gatt_manager1(BLUEZ_OBJECT(adapter));
831 VerifyOrExit(gattMgr != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL gattMgr in %s", __func__));
833 g_variant_builder_init(&optionsBuilder, G_VARIANT_TYPE("a{sv}"));
834 options = g_variant_builder_end(&optionsBuilder);
836 bluez_gatt_manager1_call_register_application(gattMgr, endpoint->mpRootPath, options, nullptr, BluezPeripheralRegisterAppDone,
840 return G_SOURCE_REMOVE;
843 /// Update the table of open BLE connections whevener a new device is spotted or its attributes have changed.
844 static void UpdateConnectionTable(BluezDevice1 * apDevice, BluezEndpoint & aEndpoint)
846 const gchar * objectPath = g_dbus_proxy_get_object_path(G_DBUS_PROXY(apDevice));
847 BluezConnection * connection = static_cast<BluezConnection *>(g_hash_table_lookup(aEndpoint.mpConnMap, objectPath));
849 if (connection != nullptr && !bluez_device1_get_connected(apDevice))
851 ChipLogDetail(DeviceLayer, "Bluez disconnected");
852 BLEManagerImpl::CHIPoBluez_ConnectionClosed(connection);
853 // TODO: the connection object should be released after BLEManagerImpl finishes cleaning up its resources
854 // after the disconnection. Releasing it here doesn't cause any issues, but it's error-prone.
855 BluezOTConnectionDestroy(connection);
856 g_hash_table_remove(aEndpoint.mpConnMap, objectPath);
860 if (connection == nullptr && !bluez_device1_get_connected(apDevice) && aEndpoint.mIsCentral)
865 if (connection == nullptr && bluez_device1_get_connected(apDevice) &&
866 (!aEndpoint.mIsCentral || bluez_device1_get_services_resolved(apDevice)))
868 connection = g_new0(BluezConnection, 1);
869 connection->mpPeerAddress = g_strdup(bluez_device1_get_address(apDevice));
870 connection->mpDevice = static_cast<BluezDevice1 *>(g_object_ref(apDevice));
871 connection->mpEndpoint = &aEndpoint;
872 BluezConnectionInit(connection);
873 aEndpoint.mpPeerDevicePath = g_strdup(objectPath);
874 g_hash_table_insert(aEndpoint.mpConnMap, aEndpoint.mpPeerDevicePath, connection);
876 ChipLogDetail(DeviceLayer, "New BLE connection %p, device %s, path %s", connection, connection->mpPeerAddress,
877 aEndpoint.mpPeerDevicePath);
879 BLEManagerImpl::HandleNewConnection(connection);
883 static void BluezSignalInterfacePropertiesChanged(GDBusObjectManagerClient * aManager, GDBusObjectProxy * aObject,
884 GDBusProxy * aInterface, GVariant * aChangedProperties,
885 const gchar * const * aInvalidatedProps, gpointer apClosure)
887 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
888 VerifyOrReturn(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
889 VerifyOrReturn(endpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL endpoint->mpAdapter in %s", __func__));
890 VerifyOrReturn(strcmp(g_dbus_proxy_get_interface_name(aInterface), DEVICE_INTERFACE) == 0, );
892 BluezDevice1 * device = BLUEZ_DEVICE1(aInterface);
893 VerifyOrReturn(BluezIsDeviceOnAdapter(device, endpoint->mpAdapter));
895 UpdateConnectionTable(device, *endpoint);
898 static void BluezHandleNewDevice(BluezDevice1 * device, BluezEndpoint * apEndpoint)
900 VerifyOrExit(apEndpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
901 if (apEndpoint->mIsCentral)
906 // We need to handle device connection both this function and BluezSignalInterfacePropertiesChanged
907 // When a device is connected for first time, this function will be triggerred.
908 // The future connections for the same device will trigger ``Connect'' property change.
909 // TODO: Factor common code in the two function.
910 BluezConnection * conn;
911 VerifyOrExit(bluez_device1_get_connected(device), ChipLogError(DeviceLayer, "FAIL: device is not connected"));
913 conn = static_cast<BluezConnection *>(
914 g_hash_table_lookup(apEndpoint->mpConnMap, g_dbus_proxy_get_object_path(G_DBUS_PROXY(device))));
915 VerifyOrExit(conn == nullptr,
916 ChipLogError(DeviceLayer, "FAIL: connection already tracked: conn: %x new device: %s", conn,
917 g_dbus_proxy_get_object_path(G_DBUS_PROXY(device))));
919 conn = g_new0(BluezConnection, 1);
920 conn->mpPeerAddress = g_strdup(bluez_device1_get_address(device));
921 conn->mpDevice = static_cast<BluezDevice1 *>(g_object_ref(device));
922 conn->mpEndpoint = apEndpoint;
923 BluezConnectionInit(conn);
924 apEndpoint->mpPeerDevicePath = g_strdup(g_dbus_proxy_get_object_path(G_DBUS_PROXY(device)));
925 ChipLogDetail(DeviceLayer, "Device %s (Path: %s) Connected", conn->mpPeerAddress, apEndpoint->mpPeerDevicePath);
926 g_hash_table_insert(apEndpoint->mpConnMap, g_strdup(g_dbus_proxy_get_object_path(G_DBUS_PROXY(device))), conn);
932 static void BluezSignalOnObjectAdded(GDBusObjectManager * aManager, GDBusObject * aObject, BluezEndpoint * endpoint)
934 // TODO: right now we do not handle addition/removal of adapters
935 // Primary focus here is to handle addition of a device
936 BluezDevice1 * device = bluez_object_get_device1(BLUEZ_OBJECT(aObject));
937 if (device == nullptr)
942 if (BluezIsDeviceOnAdapter(device, endpoint->mpAdapter) == TRUE)
944 BluezHandleNewDevice(device, endpoint);
947 g_object_unref(device);
950 static void BluezSignalOnObjectRemoved(GDBusObjectManager * aManager, GDBusObject * aObject, gpointer apClosure)
952 // TODO: for Device1, lookup connection, and call otPlatTobleHandleDisconnected
953 // for Adapter1: unclear, crash if this pertains to our adapter? at least null out the endpoint->mpAdapter.
954 // for Characteristic1, or GattService -- handle here via calling otPlatTobleHandleDisconnected, or ignore.
957 static BluezGattService1 * BluezServiceCreate(gpointer apClosure)
959 BluezObjectSkeleton * object;
960 BluezGattService1 * service;
961 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
963 endpoint->mpServicePath = g_strdup_printf("%s/service", endpoint->mpRootPath);
964 ChipLogDetail(DeviceLayer, "CREATE service object at %s", endpoint->mpServicePath);
965 object = bluez_object_skeleton_new(endpoint->mpServicePath);
967 service = bluez_gatt_service1_skeleton_new();
968 bluez_gatt_service1_set_uuid(service, "0xFEAF");
969 // device is only valid for remote services
970 bluez_gatt_service1_set_primary(service, TRUE);
972 // includes -- unclear whether required. Might be filled in later
973 bluez_object_skeleton_set_gatt_service1(object, service);
974 g_dbus_object_manager_server_export(endpoint->mpRoot, G_DBUS_OBJECT_SKELETON(object));
975 g_object_unref(object);
980 static void bluezObjectsSetup(BluezEndpoint * apEndpoint)
982 GList * objects = nullptr;
984 char * expectedPath = nullptr;
986 VerifyOrExit(apEndpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
988 expectedPath = g_strdup_printf("%s/hci%d", BLUEZ_PATH, apEndpoint->mAdapterId);
989 objects = g_dbus_object_manager_get_objects(apEndpoint->mpObjMgr);
991 for (l = objects; l != nullptr && apEndpoint->mpAdapter == nullptr; l = l->next)
993 BluezObject * object = BLUEZ_OBJECT(l->data);
996 interfaces = g_dbus_object_get_interfaces(G_DBUS_OBJECT(object));
998 for (ll = interfaces; ll != nullptr; ll = ll->next)
1000 if (BLUEZ_IS_ADAPTER1(ll->data))
1001 { // we found the adapter
1002 BluezAdapter1 * adapter = BLUEZ_ADAPTER1(ll->data);
1003 char * addr = const_cast<char *>(bluez_adapter1_get_address(adapter));
1004 if (apEndpoint->mpAdapterAddr == nullptr) // no adapter address provided, bind to the hci indicated by nodeid
1006 if (strcmp(g_dbus_proxy_get_object_path(G_DBUS_PROXY(adapter)), expectedPath) == 0)
1008 apEndpoint->mpAdapter = static_cast<BluezAdapter1 *>(g_object_ref(adapter));
1013 if (strcmp(apEndpoint->mpAdapterAddr, addr) == 0)
1015 apEndpoint->mpAdapter = static_cast<BluezAdapter1 *>(g_object_ref(adapter));
1020 g_list_free_full(interfaces, g_object_unref);
1022 VerifyOrExit(apEndpoint->mpAdapter != nullptr, ChipLogError(DeviceLayer, "FAIL: NULL apEndpoint->mpAdapter in %s", __func__));
1023 bluez_adapter1_set_powered(apEndpoint->mpAdapter, TRUE);
1025 // Setting "Discoverable" to False on the adapter and to True on the advertisement convinces
1026 // Bluez to set "BR/EDR Not Supported" flag. Bluez doesn't provide API to do that explicitly
1027 // and the flag is necessary to force using LE transport.
1028 bluez_adapter1_set_discoverable(apEndpoint->mpAdapter, FALSE);
1031 g_list_free_full(objects, g_object_unref);
1032 g_free(expectedPath);
1035 static BluezConnection * GetBluezConnectionViaDevice(BluezEndpoint * apEndpoint)
1037 BluezConnection * retval =
1038 static_cast<BluezConnection *>(g_hash_table_lookup(apEndpoint->mpConnMap, apEndpoint->mpPeerDevicePath));
1039 // ChipLogError(DeviceLayer, "acquire connection object %p in (%s)", retval, __func__);
1043 #if CHIP_BLUEZ_CENTRAL_SUPPORT
1044 static BluezConnection * BluezCharacteristicGetBluezConnection(BluezGattCharacteristic1 * aChar, GVariant * aOptions,
1045 BluezEndpoint * apEndpoint)
1047 BluezConnection * retval = NULL;
1048 const gchar * path = NULL;
1049 GVariantDict options;
1052 VerifyOrExit(apEndpoint != NULL, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1053 VerifyOrExit(apEndpoint->mIsCentral, );
1055 /* TODO Unfortunately StartNotify/StopNotify doesn't provide info about
1056 * peer device in call params so we need look this up ourselves.
1058 if (aOptions == NULL)
1064 objects = g_dbus_object_manager_get_objects(apEndpoint->mpObjMgr);
1065 for (l = objects; l != NULL; l = l->next)
1067 BluezDevice1 * device = bluez_object_get_device1(BLUEZ_OBJECT(l->data));
1070 if (BluezIsDeviceOnAdapter(device, apEndpoint->mpAdapter))
1072 for (ll = objects; ll != NULL; ll = ll->next)
1074 BluezGattService1 * service = bluez_object_get_gatt_service1(BLUEZ_OBJECT(ll->data));
1075 if (service != NULL)
1077 if (BluezIsServiceOnDevice(service, device))
1079 if (BluezIsCharOnService(aChar, service))
1081 retval = (BluezConnection *) g_hash_table_lookup(
1082 apEndpoint->mpConnMap, g_dbus_proxy_get_object_path(G_DBUS_PROXY(device)));
1085 g_object_unref(service);
1091 g_object_unref(device);
1097 g_list_free_full(objects, g_object_unref);
1101 g_variant_dict_init(&options, aOptions);
1103 v = g_variant_dict_lookup_value(&options, "device", G_VARIANT_TYPE_OBJECT_PATH);
1105 VerifyOrExit(v != NULL, ChipLogError(DeviceLayer, "FAIL: No device option in dictionary (%s)", __func__));
1107 path = g_variant_get_string(v, NULL);
1109 retval = (BluezConnection *) g_hash_table_lookup(apEndpoint->mpConnMap, path);
1115 #endif // CHIP_BLUEZ_CENTRAL_SUPPORT
1117 void EndpointCleanup(BluezEndpoint * apEndpoint)
1119 if (apEndpoint != nullptr)
1121 if (apEndpoint->mpOwningName != nullptr)
1123 g_free(apEndpoint->mpOwningName);
1124 apEndpoint->mpOwningName = nullptr;
1126 if (apEndpoint->mpAdapterName != nullptr)
1128 g_free(apEndpoint->mpAdapterName);
1129 apEndpoint->mpAdapterName = nullptr;
1131 if (apEndpoint->mpAdapterAddr != nullptr)
1133 g_free(apEndpoint->mpAdapterAddr);
1134 apEndpoint->mpAdapterAddr = nullptr;
1136 if (apEndpoint->mpRootPath != nullptr)
1138 g_free(apEndpoint->mpRootPath);
1139 apEndpoint->mpRootPath = nullptr;
1141 if (apEndpoint->mpAdvPath != nullptr)
1143 g_free(apEndpoint->mpAdvPath);
1144 apEndpoint->mpAdvPath = nullptr;
1146 if (apEndpoint->mpServicePath != nullptr)
1148 g_free(apEndpoint->mpServicePath);
1149 apEndpoint->mpServicePath = nullptr;
1151 if (apEndpoint->mpConnMap != nullptr)
1153 g_hash_table_destroy(apEndpoint->mpConnMap);
1154 apEndpoint->mpConnMap = nullptr;
1156 if (apEndpoint->mpAdvertisingUUID != nullptr)
1158 g_free(apEndpoint->mpAdvertisingUUID);
1159 apEndpoint->mpAdvertisingUUID = nullptr;
1161 if (apEndpoint->mpPeerDevicePath != nullptr)
1163 g_free(apEndpoint->mpPeerDevicePath);
1164 apEndpoint->mpPeerDevicePath = nullptr;
1171 int BluezObjectsCleanup(BluezEndpoint * apEndpoint)
1173 g_object_unref(apEndpoint->mpAdapter);
1174 EndpointCleanup(apEndpoint);
1178 #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING
1179 static void UpdateAdditionalDataCharacteristic(BluezGattCharacteristic1 * characteristic)
1181 if (characteristic == nullptr)
1186 // Construct the TLV for the additional data
1187 GVariant * cValue = nullptr;
1189 CHIP_ERROR err = CHIP_NO_ERROR;
1190 chip::System::PacketBufferHandle bufferHandle;
1192 char serialNumber[ConfigurationManager::kMaxSerialNumberLength + 1];
1193 size_t serialNumberSize = 0;
1194 uint16_t lifetimeCounter = 0;
1195 BitFlags<AdditionalDataFields> additionalDataFields;
1197 #if CHIP_ENABLE_ROTATING_DEVICE_ID
1198 err = ConfigurationMgr().GetSerialNumber(serialNumber, sizeof(serialNumber), serialNumberSize);
1200 err = ConfigurationMgr().GetLifetimeCounter(lifetimeCounter);
1203 additionalDataFields.Set(AdditionalDataFields::RotatingDeviceId);
1206 err = AdditionalDataPayloadGenerator().generateAdditionalDataPayload(lifetimeCounter, serialNumber, serialNumberSize,
1207 bufferHandle, additionalDataFields);
1210 data = g_memdup(bufferHandle->Start(), bufferHandle->DataLength());
1212 cValue = g_variant_new_from_data(G_VARIANT_TYPE("ay"), data, bufferHandle->DataLength(), TRUE, g_free, data);
1213 bluez_gatt_characteristic1_set_value(characteristic, cValue);
1218 if (err != CHIP_NO_ERROR)
1220 ChipLogError(DeviceLayer, "Failed to generate TLV encoded Additional Data", __func__);
1226 static void BluezPeripheralObjectsSetup(gpointer apClosure)
1229 static const char * const c1_flags[] = { "write", nullptr };
1230 static const char * const c2_flags[] = { "read", "indicate", nullptr };
1231 static const char * const c3_flags[] = { "read", nullptr };
1233 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
1234 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1236 endpoint->mpService = BluezServiceCreate(apClosure);
1237 // C1 characteristic
1239 BluezCharacteristicCreate(endpoint->mpService, g_strdup("c1"), g_strdup(CHIP_PLAT_BLE_UUID_C1_STRING), endpoint->mpRoot);
1240 bluez_gatt_characteristic1_set_flags(endpoint->mpC1, c1_flags);
1242 g_signal_connect(endpoint->mpC1, "handle-read-value", G_CALLBACK(BluezCharacteristicReadValue), apClosure);
1243 g_signal_connect(endpoint->mpC1, "handle-write-value", G_CALLBACK(BluezCharacteristicWriteValueError), NULL);
1244 g_signal_connect(endpoint->mpC1, "handle-acquire-write", G_CALLBACK(BluezCharacteristicAcquireWrite), apClosure);
1245 g_signal_connect(endpoint->mpC1, "handle-acquire-notify", G_CALLBACK(BluezCharacteristicAcquireNotifyError), NULL);
1246 g_signal_connect(endpoint->mpC1, "handle-start-notify", G_CALLBACK(BluezCharacteristicStartNotifyError), NULL);
1247 g_signal_connect(endpoint->mpC1, "handle-stop-notify", G_CALLBACK(BluezCharacteristicStopNotifyError), NULL);
1248 g_signal_connect(endpoint->mpC1, "handle-confirm", G_CALLBACK(BluezCharacteristicConfirmError), NULL);
1251 BluezCharacteristicCreate(endpoint->mpService, g_strdup("c2"), g_strdup(CHIP_PLAT_BLE_UUID_C2_STRING), endpoint->mpRoot);
1252 bluez_gatt_characteristic1_set_flags(endpoint->mpC2, c2_flags);
1253 g_signal_connect(endpoint->mpC2, "handle-read-value", G_CALLBACK(BluezCharacteristicReadValue), apClosure);
1254 g_signal_connect(endpoint->mpC2, "handle-write-value", G_CALLBACK(BluezCharacteristicWriteValueError), NULL);
1255 g_signal_connect(endpoint->mpC2, "handle-acquire-write", G_CALLBACK(BluezCharacteristicAcquireWriteError), NULL);
1256 g_signal_connect(endpoint->mpC2, "handle-acquire-notify", G_CALLBACK(BluezCharacteristicAcquireNotify), apClosure);
1257 g_signal_connect(endpoint->mpC2, "handle-start-notify", G_CALLBACK(BluezCharacteristicStartNotify), apClosure);
1258 g_signal_connect(endpoint->mpC2, "handle-stop-notify", G_CALLBACK(BluezCharacteristicStopNotify), apClosure);
1259 g_signal_connect(endpoint->mpC2, "handle-confirm", G_CALLBACK(BluezCharacteristicConfirm), apClosure);
1261 ChipLogDetail(DeviceLayer, "CHIP BTP C1 %s", bluez_gatt_characteristic1_get_service(endpoint->mpC1));
1262 ChipLogDetail(DeviceLayer, "CHIP BTP C2 %s", bluez_gatt_characteristic1_get_service(endpoint->mpC2));
1264 #if CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING
1265 ChipLogDetail(DeviceLayer, "CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING is TRUE");
1266 // Additional data characteristics
1268 BluezCharacteristicCreate(endpoint->mpService, g_strdup("c3"), g_strdup(CHIP_PLAT_BLE_UUID_C3_STRING), endpoint->mpRoot);
1269 bluez_gatt_characteristic1_set_flags(endpoint->mpC3, c3_flags);
1270 g_signal_connect(endpoint->mpC3, "handle-read-value", G_CALLBACK(BluezCharacteristicReadValue), apClosure);
1271 g_signal_connect(endpoint->mpC3, "handle-write-value", G_CALLBACK(BluezCharacteristicWriteValueError), NULL);
1272 g_signal_connect(endpoint->mpC3, "handle-acquire-write", G_CALLBACK(BluezCharacteristicAcquireWriteError), NULL);
1273 g_signal_connect(endpoint->mpC3, "handle-acquire-notify", G_CALLBACK(BluezCharacteristicAcquireNotify), apClosure);
1274 g_signal_connect(endpoint->mpC3, "handle-start-notify", G_CALLBACK(BluezCharacteristicStartNotify), apClosure);
1275 g_signal_connect(endpoint->mpC3, "handle-stop-notify", G_CALLBACK(BluezCharacteristicStopNotify), apClosure);
1276 g_signal_connect(endpoint->mpC3, "handle-confirm", G_CALLBACK(BluezCharacteristicConfirm), apClosure);
1277 // update the characteristic value
1278 UpdateAdditionalDataCharacteristic(endpoint->mpC3);
1279 ChipLogDetail(DeviceLayer, "CHIP BTP C3 %s", bluez_gatt_characteristic1_get_service(endpoint->mpC3));
1281 ChipLogDetail(DeviceLayer, "CHIP_ENABLE_ADDITIONAL_DATA_ADVERTISING is FALSE");
1289 static void BluezOnBusAcquired(GDBusConnection * aConn, const gchar * aName, gpointer apClosure)
1291 BluezEndpoint * endpoint = static_cast<BluezEndpoint *>(apClosure);
1292 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1294 ChipLogDetail(DeviceLayer, "TRACE: Bus acquired for name %s", aName);
1296 if (!endpoint->mIsCentral)
1298 endpoint->mpRootPath = g_strdup_printf("/chipoble/%04x", getpid() & 0xffff);
1299 endpoint->mpRoot = g_dbus_object_manager_server_new(endpoint->mpRootPath);
1300 g_dbus_object_manager_server_set_connection(endpoint->mpRoot, aConn);
1302 BluezPeripheralObjectsSetup(apClosure);
1309 #if CHIP_BLUEZ_NAME_MONITOR
1310 static void BluezOnNameAcquired(GDBusConnection * aConn, const gchar * aName, gpointer apClosure)
1312 ChipLogDetail(DeviceLayer, "TRACE: Owning name: Acquired %s", aName);
1315 static void BluezOnNameLost(GDBusConnection * aConn, const gchar * aName, gpointer apClosure)
1317 ChipLogDetail(DeviceLayer, "TRACE: Owning name: lost %s", aName);
1321 static int StartupEndpointBindings(BluezEndpoint * endpoint)
1323 GDBusObjectManager * manager;
1324 GError * error = nullptr;
1325 GDBusConnection * conn = nullptr;
1326 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "endpoint is NULL in %s", __func__));
1328 conn = g_bus_get_sync(G_BUS_TYPE_SYSTEM, nullptr, &error);
1329 VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "FAIL: get bus sync in %s, error: %s", __func__, error->message));
1331 if (endpoint->mpAdapterName != nullptr)
1332 endpoint->mpOwningName = g_strdup_printf("%s", endpoint->mpAdapterName);
1334 endpoint->mpOwningName = g_strdup_printf("C-%04x", getpid() & 0xffff);
1336 BluezOnBusAcquired(conn, endpoint->mpOwningName, endpoint);
1338 manager = g_dbus_object_manager_client_new_sync(
1339 conn, G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE, BLUEZ_INTERFACE, "/", bluez_object_manager_client_get_proxy_type,
1340 nullptr /* unused user data in the Proxy Type Func */, nullptr /*destroy notify */, nullptr /* cancellable */, &error);
1342 VerifyOrExit(manager != nullptr, ChipLogError(DeviceLayer, "FAIL: Error getting object manager client: %s", error->message));
1344 endpoint->mpObjMgr = manager;
1346 bluezObjectsSetup(endpoint);
1348 g_signal_connect(manager, "object-added", G_CALLBACK(BluezSignalOnObjectAdded), endpoint);
1349 g_signal_connect(manager, "object-removed", G_CALLBACK(BluezSignalOnObjectRemoved), endpoint);
1350 g_signal_connect(manager, "interface-proxy-properties-changed", G_CALLBACK(BluezSignalInterfacePropertiesChanged), endpoint);
1352 if (!MainLoop::Instance().SetCleanupFunction(BluezObjectsCleanup, endpoint))
1354 ChipLogError(DeviceLayer, "Failed to schedule cleanup function");
1358 if (error != nullptr)
1359 g_error_free(error);
1364 static gboolean BluezC2Indicate(ConnectionDataBundle * closure)
1366 BluezConnection * conn = nullptr;
1367 GError * error = nullptr;
1370 size_t len, written;
1372 VerifyOrExit(closure != nullptr, ChipLogError(DeviceLayer, "ConnectionDataBundle is NULL in %s", __func__));
1374 conn = closure->mpConn;
1375 VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__));
1376 VerifyOrExit(conn->mpC2 != nullptr, ChipLogError(DeviceLayer, "FAIL: C2 Indicate: %s", "NULL C2"));
1378 if (bluez_gatt_characteristic1_get_notify_acquired(conn->mpC2) == TRUE)
1380 buf = (char *) g_variant_get_fixed_array(closure->mpVal, &len, sizeof(uint8_t));
1381 VerifyOrExit(len <= static_cast<size_t>(std::numeric_limits<gssize>::max()),
1382 ChipLogError(DeviceLayer, "FAIL: buffer too large in %s", __func__));
1383 status = g_io_channel_write_chars(conn->mC2Channel.mpChannel, buf, static_cast<gssize>(len), &written, &error);
1384 g_variant_unref(closure->mpVal);
1385 closure->mpVal = nullptr;
1387 VerifyOrExit(status == G_IO_STATUS_NORMAL, ChipLogError(DeviceLayer, "FAIL: C2 Indicate: %s", error->message));
1391 bluez_gatt_characteristic1_set_value(conn->mpC2, closure->mpVal);
1392 closure->mpVal = nullptr;
1396 if (closure != nullptr)
1400 g_variant_unref(closure->mpVal);
1405 if (error != nullptr)
1406 g_error_free(error);
1407 return G_SOURCE_REMOVE;
1410 static ConnectionDataBundle * MakeConnectionDataBundle(BLE_CONNECTION_OBJECT apConn, const chip::System::PacketBufferHandle & apBuf)
1412 ConnectionDataBundle * bundle = g_new(ConnectionDataBundle, 1);
1413 bundle->mpConn = static_cast<BluezConnection *>(apConn);
1415 g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, apBuf->Start(), apBuf->DataLength() * sizeof(uint8_t), sizeof(uint8_t));
1419 bool SendBluezIndication(BLE_CONNECTION_OBJECT apConn, chip::System::PacketBufferHandle apBuf)
1421 bool success = false;
1423 VerifyOrExit(!apBuf.IsNull(), ChipLogError(DeviceLayer, "apBuf is NULL in %s", __func__));
1425 success = MainLoop::Instance().Schedule(BluezC2Indicate, MakeConnectionDataBundle(apConn, apBuf));
1431 static gboolean BluezDisconnect(void * apClosure)
1433 BluezConnection * conn = static_cast<BluezConnection *>(apClosure);
1434 GError * error = nullptr;
1437 VerifyOrExit(conn != nullptr, ChipLogError(DeviceLayer, "conn is NULL in %s", __func__));
1438 VerifyOrExit(conn->mpDevice != nullptr, ChipLogError(DeviceLayer, "FAIL: Disconnect: %s", "NULL Device"));
1440 ChipLogDetail(DeviceLayer, "%s peer=%s", __func__, bluez_device1_get_address(conn->mpDevice));
1442 success = bluez_device1_call_disconnect_sync(conn->mpDevice, nullptr, &error);
1443 VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: Disconnect: %s", error->message));
1446 if (error != nullptr)
1447 g_error_free(error);
1448 return G_SOURCE_REMOVE;
1451 static int CloseBleconnectionCB(void * apAppState)
1453 BluezDisconnect(apAppState);
1454 return G_SOURCE_REMOVE;
1457 bool CloseBluezConnection(BLE_CONNECTION_OBJECT apConn)
1459 return MainLoop::Instance().RunOnBluezThread(CloseBleconnectionCB, apConn);
1462 CHIP_ERROR StartBluezAdv(BluezEndpoint * apEndpoint)
1464 CHIP_ERROR err = CHIP_NO_ERROR;
1465 if (!MainLoop::Instance().Schedule(BluezAdvStart, apEndpoint))
1467 err = CHIP_ERROR_INCORRECT_STATE;
1468 ChipLogError(Ble, "Failed to schedule BluezAdvStart() on CHIPoBluez thread");
1473 CHIP_ERROR StopBluezAdv(BluezEndpoint * apEndpoint)
1475 CHIP_ERROR err = CHIP_NO_ERROR;
1476 if (!MainLoop::Instance().Schedule(BluezAdvStop, apEndpoint))
1478 err = CHIP_ERROR_INCORRECT_STATE;
1479 ChipLogError(Ble, "Failed to schedule BluezAdvStop() on CHIPoBluez thread");
1484 CHIP_ERROR BluezAdvertisementSetup(BluezEndpoint * apEndpoint)
1486 CHIP_ERROR err = CHIP_NO_ERROR;
1487 if (!MainLoop::Instance().Schedule(BluezAdvSetup, apEndpoint))
1489 err = CHIP_ERROR_INCORRECT_STATE;
1490 ChipLogError(Ble, "Failed to schedule BluezAdvertisementSetup() on CHIPoBluez thread");
1495 CHIP_ERROR BluezGattsAppRegister(BluezEndpoint * apEndpoint)
1497 CHIP_ERROR err = CHIP_NO_ERROR;
1498 if (!MainLoop::Instance().Schedule(BluezPeripheralRegisterApp, apEndpoint))
1500 err = CHIP_ERROR_INCORRECT_STATE;
1501 ChipLogError(Ble, "Failed to schedule BluezPeripheralRegisterApp() on CHIPoBluez thread");
1506 CHIP_ERROR ConfigureBluezAdv(BLEAdvConfig & aBleAdvConfig, BluezEndpoint * apEndpoint)
1508 const char * msg = nullptr;
1509 CHIP_ERROR err = CHIP_NO_ERROR;
1510 VerifyOrExit(aBleAdvConfig.mpBleName != nullptr, msg = "FAIL: BLE name is NULL");
1511 VerifyOrExit(aBleAdvConfig.mpAdvertisingUUID != nullptr, msg = "FAIL: BLE mpAdvertisingUUID is NULL in %s");
1513 apEndpoint->mpAdapterName = g_strdup(aBleAdvConfig.mpBleName);
1514 apEndpoint->mpAdvertisingUUID = g_strdup(aBleAdvConfig.mpAdvertisingUUID);
1515 apEndpoint->mAdapterId = aBleAdvConfig.mAdapterId;
1516 apEndpoint->mType = aBleAdvConfig.mType;
1517 apEndpoint->mDuration = aBleAdvConfig.mDuration;
1518 apEndpoint->mDuration = aBleAdvConfig.mDuration;
1520 err = ConfigurationMgr().GetBLEDeviceIdentificationInfo(apEndpoint->mDeviceIdInfo);
1526 ChipLogDetail(DeviceLayer, "%s in %s", msg, __func__);
1527 err = CHIP_ERROR_INCORRECT_STATE;
1532 CHIP_ERROR InitBluezBleLayer(bool aIsCentral, char * apBleAddr, BLEAdvConfig & aBleAdvConfig, BluezEndpoint *& apEndpoint)
1534 CHIP_ERROR err = CHIP_NO_ERROR;
1535 bool retval = false;
1536 BluezEndpoint * endpoint = nullptr;
1538 // initialize server endpoint
1539 endpoint = g_new0(BluezEndpoint, 1);
1540 VerifyOrExit(endpoint != nullptr, ChipLogError(DeviceLayer, "FAIL: memory allocation in %s", __func__));
1542 if (apBleAddr != nullptr)
1543 endpoint->mpAdapterAddr = g_strdup(apBleAddr);
1545 endpoint->mpAdapterAddr = nullptr;
1547 endpoint->mpConnMap = g_hash_table_new(g_str_hash, g_str_equal);
1548 endpoint->mIsCentral = aIsCentral;
1552 err = ConfigureBluezAdv(aBleAdvConfig, endpoint);
1557 endpoint->mAdapterId = aBleAdvConfig.mAdapterId;
1560 err = MainLoop::Instance().EnsureStarted();
1561 VerifyOrExit(err == CHIP_NO_ERROR, ChipLogError(DeviceLayer, "Failed to start BLE main loop"));
1563 if (!MainLoop::Instance().ScheduleAndWait(StartupEndpointBindings, endpoint))
1565 ChipLogError(DeviceLayer, "Failed to schedule endpoint initialization");
1574 apEndpoint = endpoint;
1575 ChipLogDetail(DeviceLayer, "PlatformBlueZInit init success");
1579 EndpointCleanup(endpoint);
1585 // BluezSendWriteRequest callbacks
1587 static void SendWriteRequestDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection)
1589 BluezGattCharacteristic1 * c1 = BLUEZ_GATT_CHARACTERISTIC1(aObject);
1590 GError * error = nullptr;
1591 gboolean success = bluez_gatt_characteristic1_call_write_value_finish(c1, aResult, &error);
1593 VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: BluezSendWriteRequest : %s", error->message));
1594 BLEManagerImpl::HandleWriteComplete(static_cast<BLE_CONNECTION_OBJECT>(apConnection));
1597 if (error != nullptr)
1598 g_error_free(error);
1601 static gboolean SendWriteRequestImpl(void * apConnectionData)
1603 ConnectionDataBundle * data = static_cast<ConnectionDataBundle *>(apConnectionData);
1604 GVariant * options = nullptr;
1605 GVariantBuilder optionsBuilder;
1607 VerifyOrExit(data != nullptr, ChipLogError(DeviceLayer, "ConnectionDataBundle is NULL in %s", __func__));
1608 VerifyOrExit(data->mpConn != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__));
1609 VerifyOrExit(data->mpConn->mpC1 != nullptr, ChipLogError(DeviceLayer, "C1 is NULL in %s", __func__));
1611 g_variant_builder_init(&optionsBuilder, G_VARIANT_TYPE_ARRAY);
1612 g_variant_builder_add(&optionsBuilder, "{sv}", "type", g_variant_new_string("request"));
1613 options = g_variant_builder_end(&optionsBuilder);
1615 bluez_gatt_characteristic1_call_write_value(data->mpConn->mpC1, data->mpVal, options, nullptr, SendWriteRequestDone,
1620 return G_SOURCE_REMOVE;
1623 bool BluezSendWriteRequest(BLE_CONNECTION_OBJECT apConn, chip::System::PacketBufferHandle apBuf)
1625 bool success = false;
1627 VerifyOrExit(!apBuf.IsNull(), ChipLogError(DeviceLayer, "apBuf is NULL in %s", __func__));
1629 success = MainLoop::Instance().RunOnBluezThread(SendWriteRequestImpl, MakeConnectionDataBundle(apConn, apBuf));
1635 // BluezSubscribeCharacteristic callbacks
1637 static void OnCharacteristicChanged(GDBusProxy * aInterface, GVariant * aChangedProperties, const gchar * const * aInvalidatedProps,
1638 gpointer apConnection)
1640 BLE_CONNECTION_OBJECT connection = static_cast<BLE_CONNECTION_OBJECT>(apConnection);
1641 GVariant * value = g_variant_lookup_value(aChangedProperties, "Value", G_VARIANT_TYPE_BYTESTRING);
1642 VerifyOrReturn(value != nullptr);
1645 auto buffer = g_variant_get_fixed_array(value, &bufferLen, sizeof(uint8_t));
1646 VerifyOrReturn(value != nullptr, ChipLogError(DeviceLayer, "Characteristic value has unexpected type"));
1648 BLEManagerImpl::HandleTXCharChanged(connection, static_cast<const uint8_t *>(buffer), bufferLen);
1651 static void SubscribeCharacteristicDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection)
1653 BluezGattCharacteristic1 * c2 = BLUEZ_GATT_CHARACTERISTIC1(aObject);
1654 GError * error = nullptr;
1655 gboolean success = bluez_gatt_characteristic1_call_write_value_finish(c2, aResult, &error);
1657 VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: BluezSubscribeCharacteristic : %s", error->message));
1659 // Get notifications on the TX characteristic change (e.g. indication is received)
1660 g_signal_connect(c2, "g-properties-changed", G_CALLBACK(OnCharacteristicChanged), apConnection);
1661 BLEManagerImpl::HandleSubscribeOpComplete(static_cast<BLE_CONNECTION_OBJECT>(apConnection), true);
1664 if (error != nullptr)
1665 g_error_free(error);
1668 static gboolean SubscribeCharacteristicImpl(BluezConnection * connection)
1670 VerifyOrExit(connection != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__));
1671 VerifyOrExit(connection->mpC2 != nullptr, ChipLogError(DeviceLayer, "C2 is NULL in %s", __func__));
1673 bluez_gatt_characteristic1_call_start_notify(connection->mpC2, nullptr, SubscribeCharacteristicDone, connection);
1676 return G_SOURCE_REMOVE;
1679 bool BluezSubscribeCharacteristic(BLE_CONNECTION_OBJECT apConn)
1681 return MainLoop::Instance().Schedule(SubscribeCharacteristicImpl, static_cast<BluezConnection *>(apConn));
1684 // BluezUnsubscribeCharacteristic callbacks
1686 static void UnsubscribeCharacteristicDone(GObject * aObject, GAsyncResult * aResult, gpointer apConnection)
1688 BluezGattCharacteristic1 * c2 = BLUEZ_GATT_CHARACTERISTIC1(aObject);
1689 GError * error = nullptr;
1690 gboolean success = bluez_gatt_characteristic1_call_write_value_finish(c2, aResult, &error);
1692 VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: BluezUnsubscribeCharacteristic : %s", error->message));
1694 // Stop listening to the TX characteristic changes
1695 g_signal_handlers_disconnect_by_data(c2, apConnection);
1696 BLEManagerImpl::HandleSubscribeOpComplete(static_cast<BLE_CONNECTION_OBJECT>(apConnection), false);
1699 if (error != nullptr)
1700 g_error_free(error);
1703 static gboolean UnsubscribeCharacteristicImpl(BluezConnection * connection)
1705 VerifyOrExit(connection != nullptr, ChipLogError(DeviceLayer, "BluezConnection is NULL in %s", __func__));
1706 VerifyOrExit(connection->mpC2 != nullptr, ChipLogError(DeviceLayer, "C2 is NULL in %s", __func__));
1708 bluez_gatt_characteristic1_call_start_notify(connection->mpC2, nullptr, UnsubscribeCharacteristicDone, connection);
1711 return G_SOURCE_REMOVE;
1714 bool BluezUnsubscribeCharacteristic(BLE_CONNECTION_OBJECT apConn)
1716 return MainLoop::Instance().Schedule(UnsubscribeCharacteristicImpl, static_cast<BluezConnection *>(apConn));
1719 // ConnectDevice callbacks
1721 static void ConnectDeviceDone(GObject * aObject, GAsyncResult * aResult, gpointer)
1723 BluezDevice1 * device = BLUEZ_DEVICE1(aObject);
1724 GError * error = nullptr;
1725 gboolean success = bluez_device1_call_connect_finish(device, aResult, &error);
1727 VerifyOrExit(success == TRUE, ChipLogError(DeviceLayer, "FAIL: ConnectDevice : %s", error->message));
1728 ChipLogDetail(DeviceLayer, "ConnectDevice complete");
1731 if (error != nullptr)
1732 g_error_free(error);
1735 static gboolean ConnectDeviceImpl(BluezDevice1 * device)
1737 VerifyOrExit(device != nullptr, ChipLogError(DeviceLayer, "device is NULL in %s", __func__));
1739 bluez_device1_call_connect(device, nullptr, ConnectDeviceDone, nullptr);
1740 g_object_unref(device);
1743 return G_SOURCE_REMOVE;
1746 CHIP_ERROR ConnectDevice(BluezDevice1 * apDevice)
1748 CHIP_ERROR error = CHIP_NO_ERROR;
1749 g_object_ref(apDevice);
1751 if (!MainLoop::Instance().Schedule(ConnectDeviceImpl, apDevice))
1753 ChipLogError(Ble, "Failed to schedule ConnectDeviceImpl() on CHIPoBluez thread");
1754 g_object_unref(apDevice);
1755 error = CHIP_ERROR_INCORRECT_STATE;
1761 } // namespace Internal
1762 } // namespace DeviceLayer
1764 #endif // CHIP_DEVICE_CONFIG_ENABLE_CHIPOBLE