2 * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
19 #include "bluetooth/bluetooth_gatt_server.h"
20 #include "bluetooth/bluetooth_gatt_server_service.h"
21 #include "bluetooth/bluetooth_instance.h"
22 #include "bluetooth/bluetooth_util.h"
23 #include "bluetooth/uuid.h"
25 #include "common/logger.h"
26 #include "common/platform_result.h"
27 #include "common/tools.h"
29 using namespace extension::bluetooth::util;
30 using common::PlatformResult;
31 using common::ErrorCode;
37 const std::string kUuid = "uuid";
38 const std::string kServiceUuid = "serviceUuid";
39 const std::string kIsPrimary = "isPrimary";
40 const std::string kCharacteristics = "characteristics";
42 const std::string kServices = "services";
43 const std::string kDescriptors = "descriptors";
44 const std::string kIsBroadcast = "isBroadcast";
45 const std::string kHasExtendedProperties = "hasExtendedProperties";
46 const std::string kIsNotify = "isNotify";
47 const std::string kIsIndication = "isIndication";
48 const std::string kIsReadable = "isReadable";
49 const std::string kIsSignedWrite = "isSignedWrite";
50 const std::string kIsWritable = "isWritable";
51 const std::string kIsWriteNoResponse = "isWriteNoResponse";
52 const std::string kReadPermission = "readPermission";
53 const std::string kWritePermission = "writePermission";
54 const std::string kEncryptedReadPermission = "encryptedReadPermission";
55 const std::string kEncryptedWritePermission = "encryptedWritePermission";
56 const std::string kEncryptedSignedReadPermission = "encryptedSignedReadPermission";
57 const std::string kEncryptedSignedWritePermission = "encryptedSignedWritePermission";
59 const std::string kId = "_id";
60 const std::string kIdsToRemoveFromNativeLayer = "idsToRemoveFromNativeLayer";
61 const std::string kClientAddress = "clientAddress";
62 const std::string kRequestId = "requestId";
63 const std::string kValue = "value";
64 const std::string kOffset = "offset";
65 const std::string kReplyRequired = "replyRequired";
66 const std::string kRequestType = "requestType";
67 const std::string kReadRequestType = "readRequestType";
68 const std::string kWriteRequestType = "writeRequestType";
69 const std::string kStatusCode = "statusCode";
70 const std::string kData = "data";
71 const std::string kReadCallback = "readCallback";
72 const std::string kWriteCallback = "writeCallback";
73 const std::string kNotifyId = "notifyId";
74 const std::string kOnNotificationFail = "onnotificationfail";
75 const std::string kOnNotificationFinish = "onnotificationfinish";
76 const std::string kOnNotificationSuccess = "onnotificationsuccess";
77 const std::string kType = "type";
78 const std::string kClient = "client";
80 int GetPermissionsInt(const picojson::value& permissions) {
81 ScopeLogger("permissions: %s", permissions.serialize().c_str());
84 if (permissions.get(kReadPermission).get<bool>()) {
85 ret |= BT_GATT_PERMISSION_READ;
87 if (permissions.get(kWritePermission).get<bool>()) {
88 ret |= BT_GATT_PERMISSION_WRITE;
90 if (permissions.get(kEncryptedReadPermission).get<bool>()) {
91 ret |= BT_GATT_PERMISSION_ENCRYPT_READ;
93 if (permissions.get(kEncryptedWritePermission).get<bool>()) {
94 ret |= BT_GATT_PERMISSION_ENCRYPT_WRITE;
96 if (permissions.get(kEncryptedSignedReadPermission).get<bool>()) {
97 ret |= BT_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_READ;
99 if (permissions.get(kEncryptedSignedWritePermission).get<bool>()) {
100 ret |= BT_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_WRITE;
103 LoggerD("Permissions: %x", static_cast<unsigned int>(ret));
107 int GetPropertiesInt(const picojson::value& properties) {
108 ScopeLogger("properties: %s", properties.serialize().c_str());
111 if (properties.get(kIsBroadcast).get<bool>()) {
112 ret |= BT_GATT_PROPERTY_BROADCAST;
114 if (properties.get(kIsReadable).get<bool>()) {
115 ret |= BT_GATT_PROPERTY_READ;
117 if (properties.get(kIsWriteNoResponse).get<bool>()) {
118 ret |= BT_GATT_PROPERTY_WRITE_WITHOUT_RESPONSE;
120 if (properties.get(kIsWritable).get<bool>()) {
121 ret |= BT_GATT_PROPERTY_WRITE;
123 if (properties.get(kIsNotify).get<bool>()) {
124 ret |= BT_GATT_PROPERTY_NOTIFY;
126 if (properties.get(kIsIndication).get<bool>()) {
127 ret |= BT_GATT_PROPERTY_INDICATE;
129 if (properties.get(kIsSignedWrite).get<bool>()) {
130 ret |= BT_GATT_PROPERTY_AUTHENTICATED_SIGNED_WRITES;
132 if (properties.get(kHasExtendedProperties).get<bool>()) {
133 ret |= BT_GATT_PROPERTY_EXTENDED_PROPERTIES;
136 LoggerD("Properties: %x", static_cast<unsigned int>(ret));
142 bool BluetoothGATTServerService::DestroyService(int total, int index, bt_gatt_h handle,
144 ScopeLogger("total: %d, index: %d, handle: %p", total, index, handle);
147 * Undocumented behavior of native Bluetooth API:
148 * bt_gatt_service_destroy() destroys not only the service, but also all
149 * its components (included services, characteristics, descriptors)
152 auto ret = bt_gatt_service_destroy(handle);
153 if (BT_ERROR_NONE != ret) {
154 LoggerE("bt_gatt_service_destroy(): %d (%s)", ret, get_error_message(ret));
156 LoggerD("bt_gatt_service_destroy(): success");
161 bool BluetoothGATTServerService::DestroyCharacteristic(int total, int index, bt_gatt_h handle,
163 ScopeLogger("total: %d, index: %d, handle: %p", total, index, handle);
165 auto ret = bt_gatt_characteristic_destroy(handle);
166 if (BT_ERROR_NONE != ret) {
167 LoggerE("bt_gatt_characteristic_destroy(): %d (%s)", ret, get_error_message(ret));
169 LoggerD("bt_gatt_characteristic_destroy(): success");
174 bool BluetoothGATTServerService::DestroyDescriptor(int total, int index, bt_gatt_h handle,
176 ScopeLogger("total: %d, index: %d, handle: %p", total, index, handle);
178 auto ret = bt_gatt_descriptor_destroy(handle);
179 if (BT_ERROR_NONE != ret) {
180 LoggerE("bt_gatt_descriptor_destroy(): %d (%s)", ret, get_error_message(ret));
182 LoggerD("bt_gatt_descriptor_destroy(): success");
187 BluetoothGATTServerService::BluetoothGATTServerService(BluetoothInstance& instance)
188 : instance_{instance}, rw_request_callback_data_{instance, callback_names_} {
192 BluetoothGATTServerService::~BluetoothGATTServerService() {
196 common::PlatformResult BluetoothGATTServerService::AddDescriptors(
197 const picojson::array& descriptors_init, bt_gatt_h characteristic_handle,
198 std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects) {
199 ScopeLogger("descriptors_init length: %zu", descriptors_init.size());
202 * This function expects valid input.
203 * If it gets descriptors missing any: uuid, permission,
204 * or with one of these with a wrong type, the application will crash.
207 for (const auto& descriptor_init_data : descriptors_init) {
208 const auto& uuid_str = descriptor_init_data.get(kUuid).get<std::string>();
210 * Native APIs don't support 32-bit UUIDs. We convert any UUID to its 128-bit
211 * form to assure, it will be accepted by the native API.
213 * We assume, UUID::create() returns a valid object, because the input is valid.
215 auto uuid = UUID::create(uuid_str);
216 int permissions = GetPermissionsInt(descriptor_init_data);
217 bt_gatt_h descriptor_handle = nullptr;
219 int ret = bt_gatt_descriptor_create(uuid->uuid_128_bit.c_str(), permissions, nullptr, 0,
221 if (BT_ERROR_NONE != ret) {
222 LoggerE("bt_gatt_descriptor_create() failed: %d (%s)", ret, get_error_message(ret));
223 return BluetoothErrorToPlatformResult(ret, "Failed to create a descriptor");
225 LoggerD("bt_gatt_descriptor_create(): success");
227 ret = bt_gatt_characteristic_add_descriptor(characteristic_handle, descriptor_handle);
228 if (BT_ERROR_NONE != ret) {
229 LoggerE("bt_gatt_characteristic_add_descriptor() failed: %d (%s)", ret,
230 get_error_message(ret));
231 DestroyDescriptor(0, 0, descriptor_handle, nullptr);
232 return BluetoothErrorToPlatformResult(ret, "Failed to add descriptor to characteristic");
234 LoggerD("bt_gatt_characteristic_add_descriptor(): success");
236 const auto _id = static_cast<int>(descriptor_init_data.get(kId).get<double>());
237 new_gatt_objects.push_back({_id, descriptor_handle});
240 return common::PlatformResult();
243 common::PlatformResult BluetoothGATTServerService::AddCharacteristics(
244 const picojson::array& characteristics_init, bt_gatt_h service_handle,
245 std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects) {
246 ScopeLogger("characteristics_init length: %zu", characteristics_init.size());
249 * This function expects valid input.
250 * If it gets characteristics missing any: uuid, permission, property,
251 * or with any of these with a wrong type, the application will crash.
254 for (const auto& characteristic_init_data : characteristics_init) {
255 const auto& uuid_str = characteristic_init_data.get(kUuid).get<std::string>();
257 * Native APIs don't support 32-bit UUIDs. We convert any UUID to its 128-bit
258 * form to assure, it will be accepted by the native API.
260 * We assume, UUID::create() returns a valid object, because the input is valid.
262 auto uuid = UUID::create(uuid_str);
264 int permissions = GetPermissionsInt(characteristic_init_data);
265 int properties = GetPropertiesInt(characteristic_init_data);
266 bt_gatt_h characteristic_handle = nullptr;
268 int ret = bt_gatt_characteristic_create(uuid->uuid_128_bit.c_str(), permissions, properties,
269 nullptr, 0, &characteristic_handle);
270 if (BT_ERROR_NONE != ret) {
271 LoggerE("bt_gatt_characteristic_create() failed: %d (%s)", ret, get_error_message(ret));
272 return BluetoothErrorToPlatformResult(ret, "Failed to create a characteristic");
274 LoggerD("bt_gatt_characteristic_create(): success");
276 if (characteristic_init_data.get(kDescriptors).is<picojson::array>()) {
277 const auto& descriptors = characteristic_init_data.get(kDescriptors).get<picojson::array>();
278 auto result = AddDescriptors(descriptors, characteristic_handle, new_gatt_objects);
280 DestroyCharacteristic(0, 0, characteristic_handle, nullptr);
285 ret = bt_gatt_service_add_characteristic(service_handle, characteristic_handle);
286 if (BT_ERROR_NONE != ret) {
287 LoggerE("bt_gatt_service_add_characteristic() failed: %d (%s)", ret, get_error_message(ret));
288 DestroyCharacteristic(0, 0, characteristic_handle, nullptr);
289 return BluetoothErrorToPlatformResult(ret, "Failed to add a characteristic to a service");
291 LoggerD("bt_gatt_service_add_characteristic(): success");
293 const auto _id = static_cast<int>(characteristic_init_data.get(kId).get<double>());
294 new_gatt_objects.push_back({_id, characteristic_handle});
297 return common::PlatformResult();
300 common::PlatformResult BluetoothGATTServerService::AddIncludedServices(
301 const picojson::array& included_services_init, bt_gatt_h parent_service_handle,
302 std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects) {
303 ScopeLogger("included_services_init length: %zu", included_services_init.size());
306 * This function expects valid input.
307 * If it gets included_services missing a uuid
308 * or with any of these with a wrong type, the application will crash.
311 for (const auto& service_init_data : included_services_init) {
312 bt_gatt_h included_service_handle = nullptr;
313 auto result = CreateService(service_init_data, &included_service_handle, new_gatt_objects);
315 LoggerE("Failed to create included service");
319 int ret = bt_gatt_service_add_included_service(parent_service_handle, included_service_handle);
320 if (BT_ERROR_NONE != ret) {
321 LoggerE("bt_gatt_service_add_included_service() failed: %d (%s)", ret,
322 get_error_message(ret));
323 DestroyService(0, 0, included_service_handle, nullptr);
324 return BluetoothErrorToPlatformResult(ret, "Failed to add included service");
326 LoggerD("bt_gatt_service_add_included_service(): success");
328 const auto _id = static_cast<int>(service_init_data.get(kId).get<double>());
329 new_gatt_objects.push_back({_id, parent_service_handle});
332 return common::PlatformResult();
335 common::PlatformResult BluetoothGATTServerService::CreateService(
336 const picojson::value& service_init, bt_gatt_h* new_service_handle,
337 std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects) {
338 ScopeLogger("service_init: %s", service_init.serialize().c_str());
340 * This function expects valid input.
341 * If it gets service_init without any of the expected members or with a member of
342 * a wrong type, the application will crash.
345 const auto& uuid_str = service_init.get(kServiceUuid).get<std::string>();
347 * Native APIs don't support 32-bit UUIDs. We convert any UUID to its 128-bit
348 * form to assure, it will be accepted by the native API.
350 * We assume, UUID::create() returns a valid object, because the input is valid.
352 auto uuid = UUID::create(uuid_str);
353 bool primary = service_init.get(kIsPrimary).get<bool>();
354 bt_gatt_service_type_e type =
355 primary ? BT_GATT_SERVICE_TYPE_PRIMARY : BT_GATT_SERVICE_TYPE_SECONDARY;
356 bt_gatt_h service_handle = nullptr;
358 int err = bt_gatt_service_create(uuid->uuid_128_bit.c_str(), type, &service_handle);
359 if (BT_ERROR_NONE != err) {
360 LoggerE("bt_gatt_service_create error: %d (%s)", err, get_error_message(err));
361 return BluetoothErrorToPlatformResult(err, "Failed to create GATT service");
363 LoggerD("bt_gatt_service_create(): success");
365 if (service_init.get(kServices).is<picojson::array>()) {
366 const auto& services = service_init.get(kServices).get<picojson::array>();
367 auto result = AddIncludedServices(services, service_handle, new_gatt_objects);
369 DestroyService(0, 0, service_handle, nullptr);
374 if (service_init.get(kCharacteristics).is<picojson::array>()) {
375 const auto& characteristics = service_init.get(kCharacteristics).get<picojson::array>();
376 auto result = AddCharacteristics(characteristics, service_handle, new_gatt_objects);
378 DestroyService(0, 0, service_handle, nullptr);
383 const auto _id = static_cast<int>(service_init.get(kId).get<double>());
384 new_gatt_objects.push_back({_id, service_handle});
386 *new_service_handle = service_handle;
388 return common::PlatformResult();
391 common::PlatformResult BluetoothGATTServerService::RegisterService(
392 bt_gatt_h service_handle, bt_gatt_server_h server,
393 const std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects) {
396 int ret = bt_gatt_server_register_service(server, service_handle);
397 if (BT_ERROR_NONE != ret) {
398 LoggerE("bt_gatt_server_register_service() failed: %d (%s)", ret, get_error_message(ret));
399 return BluetoothErrorToPlatformResult(ret, "Failed to register GATT service");
402 gatt_objects_.insert(new_gatt_objects.begin(), new_gatt_objects.end());
404 return common::PlatformResult();
407 common::PlatformResult BluetoothGATTServerService::UnregisterService(const picojson::value& args,
408 bt_gatt_server_h server) {
411 auto _id = static_cast<int>(args.get(kId).get<double>());
412 LoggerD("Unregistering service with _id: %d", _id);
414 auto service_handle = gatt_objects_[_id];
417 * Undocumented behavior of native Bluetooth API:
418 * bt_gatt_server_unregister_service() not only unregisters the service,
419 * but also calls bt_gatt_destroy_service() on its handle, destroying
420 * the corresponding service object and all its components (included services,
421 * characteristics, descriptors).
423 auto ret = bt_gatt_server_unregister_service(server, service_handle);
424 if (BT_ERROR_NONE != ret) {
425 LoggerE("bt_gatt_server_unregister_service() failed: %d (%s)", ret, get_error_message(ret));
426 return BluetoothErrorToPlatformResult(ret, "Failed to unregister GATT service");
428 LoggerD("bt_gatt_server_unregister_service(): SUCCESS");
430 gatt_objects_.erase(_id);
432 auto ids_to_remove = args.get(kIdsToRemoveFromNativeLayer).get<picojson::array>();
433 for (const auto& to_remove : ids_to_remove) {
434 const auto id_to_remove = static_cast<int>(to_remove.get<double>());
436 auto handle_to_remove = gatt_objects_[id_to_remove];
437 LoggerD("Erasing gatt object with _id: %d", id_to_remove);
438 callback_names_.erase(std::make_pair(handle_to_remove, kReadCallback));
439 callback_names_.erase(std::make_pair(handle_to_remove, kWriteCallback));
440 gatt_objects_.erase(id_to_remove);
443 return common::PlatformResult{};
446 PlatformResult BluetoothGATTServerService::SetReadValueRequestCallback(
447 const picojson::value& args) {
450 auto _id = static_cast<int>(args.get(kId).get<double>());
451 LoggerD("Setting read value request callback for a GATT entity with _id: %d", _id);
453 auto gatt_handle = gatt_objects_[_id];
454 callback_names_[std::make_pair(gatt_handle, kReadCallback)] =
455 "ReadValueRequestCallback_" + std::to_string(_id);
457 auto read_value_request_callback = [](const char* remote_address, int request_id,
458 bt_gatt_server_h server, bt_gatt_h gatt_handle, int offset,
459 void* user_data) -> void {
460 ScopeLogger("ReadValueRequestCallback called. remote_address: %s, request_id: %d, offset: %d",
461 remote_address, request_id, offset);
462 auto rw_callback_data = static_cast<ReadWriteRequestCallbackData*>(user_data);
464 // We create a copy of this value, because remote_address pointer will be invalid
465 // when the job will be executed in the worker
466 auto remote_address_copy = std::string{remote_address};
468 rw_callback_data->instance_.GetWorker().add_job(
469 [remote_address_copy, request_id, server, gatt_handle, offset, rw_callback_data] {
470 ScopeLogger("Async call: SetReadValueRequestCallback");
472 auto read_value_request = picojson::value{picojson::object{}};
473 auto& read_value_request_obj = read_value_request.get<picojson::object>();
474 read_value_request_obj[kClientAddress] = picojson::value{remote_address_copy};
475 read_value_request_obj[kRequestId] = picojson::value{static_cast<double>(request_id)};
476 read_value_request_obj[kRequestType] = picojson::value{kReadRequestType};
477 read_value_request_obj[kOffset] = picojson::value{static_cast<double>(offset)};
478 const auto callback_name =
479 rw_callback_data->callback_names_map_[std::make_pair(gatt_handle, kReadCallback)];
480 LoggerD("Firing read value request event: %s: %s", callback_name.c_str(),
481 read_value_request.serialize().c_str());
482 rw_callback_data->instance_.FireEvent(callback_name, read_value_request);
486 auto ret = bt_gatt_server_set_read_value_requested_cb(gatt_handle, read_value_request_callback,
487 &rw_request_callback_data_);
488 if (BT_ERROR_NONE != ret) {
489 LoggerE("bt_gatt_server_set_read_value_requested_cb() failed: %d (%s)", ret,
490 get_error_message(ret));
491 return BluetoothErrorToPlatformResult(ret, "Failed to set read value request callback");
494 LoggerD("bt_gatt_server_set_read_value_requested_cb(): SUCCESS");
495 return common::PlatformResult{};
498 PlatformResult BluetoothGATTServerService::SetWriteValueRequestCallback(
499 const picojson::value& args) {
502 auto _id = static_cast<int>(args.get(kId).get<double>());
503 LoggerD("Setting write value request callback for a GATT entity with _id: %d", _id);
505 auto gatt_handle = gatt_objects_[_id];
506 callback_names_[std::make_pair(gatt_handle, kWriteCallback)] =
507 "WriteValueRequestCallback_" + std::to_string(_id);
509 auto write_value_request_callback = [](
510 const char* remote_address, int request_id, bt_gatt_server_h server, bt_gatt_h gatt_handle,
511 bool response_needed, int offset, const char* value, int len, void* user_data) -> void {
513 "WriteValueRequestCallback called. remote_address: %s, request_id: %d, response_needed: "
514 "%d, offset: %d, value: %s, len: %d",
515 remote_address, request_id, response_needed, offset, value, len);
516 auto rw_callback_data = static_cast<ReadWriteRequestCallbackData*>(user_data);
518 // We create a copy of value and remote_address
519 auto remote_address_copy = std::string{remote_address};
520 auto value_copy = std::string{value};
521 rw_callback_data->instance_.GetWorker().add_job([remote_address_copy, request_id, server,
522 gatt_handle, response_needed, offset,
523 value_copy, rw_callback_data] {
524 ScopeLogger("Async call: SetWriteValueRequestCallback");
526 auto write_value_request = picojson::value{picojson::object{}};
527 auto& write_value_request_obj = write_value_request.get<picojson::object>();
528 write_value_request_obj[kClientAddress] = picojson::value{remote_address_copy};
529 write_value_request_obj[kRequestId] = picojson::value{static_cast<double>(request_id)};
530 write_value_request_obj[kRequestType] = picojson::value{kWriteRequestType};
531 write_value_request_obj[kReplyRequired] = picojson::value{response_needed};
532 write_value_request_obj[kOffset] = picojson::value{static_cast<double>(offset)};
534 write_value_request_obj[kValue] = picojson::value{picojson::array{}};
535 auto& value_byte_array = write_value_request_obj[kValue].get<picojson::array>();
536 for (auto c : value_copy) {
537 value_byte_array.push_back(picojson::value{static_cast<double>(c)});
539 const auto callback_name =
540 rw_callback_data->callback_names_map_[std::make_pair(gatt_handle, kWriteCallback)];
541 LoggerD("Firing write value request event: %s: %s", callback_name.c_str(),
542 write_value_request.serialize().c_str());
543 rw_callback_data->instance_.FireEvent(callback_name, write_value_request);
547 auto ret = bt_gatt_server_set_write_value_requested_cb(gatt_handle, write_value_request_callback,
548 &rw_request_callback_data_);
549 if (BT_ERROR_NONE != ret) {
550 LoggerE("bt_gatt_server_set_write_value_requested_cb() failed: %d (%s)", ret,
551 get_error_message(ret));
552 return BluetoothErrorToPlatformResult(ret, "Failed to set write value request callback");
555 LoggerD("bt_gatt_server_set_write_value_requested_cb(): SUCCESS");
556 return common::PlatformResult{};
559 PlatformResult BluetoothGATTServerService::SendResponse(const picojson::value& args) {
560 ScopeLogger("Response: %s", args.serialize().c_str());
562 auto _id = static_cast<int>(args.get(kId).get<double>());
563 auto request_id = static_cast<int>(args.get(kRequestId).get<double>());
564 auto request_type_str = args.get(kRequestType).get<std::string>();
565 auto request_type = (request_type_str == kReadRequestType) ? BT_GATT_REQUEST_TYPE_READ
566 : BT_GATT_REQUEST_TYPE_WRITE;
567 auto offset = static_cast<int>(args.get(kOffset).get<double>());
568 auto status_code = static_cast<int>(args.get(kStatusCode).get<double>());
570 std::unique_ptr<char[]> value{nullptr};
572 if (args.get(kData).is<picojson::array>()) {
573 auto value_octets = args.get(kData).get<picojson::array>();
574 value_size = value_octets.size();
575 value = std::make_unique<char[]>(value_size);
576 for (int i = 0; i < value_size; ++i) {
577 value[i] += static_cast<int>(value_octets[i].get<double>());
584 "Sending response: _id: %d, requestId: %d, requestType: %s, offset: %d, statusCode: %d, "
585 "value: [%p], value size: %d",
586 _id, request_id, request_type_str.c_str(), offset, status_code, value.get(), value_size);
588 auto ret = bt_gatt_server_send_response(request_id, request_type, offset, status_code,
589 value.get(), value_size);
590 if (BT_ERROR_NONE != ret) {
591 LoggerE("bt_gatt_server_send_response() failed: %d (%s)", ret, get_error_message(ret));
592 return BluetoothErrorToPlatformResult(ret, "Failed to send response");
594 LoggerD("bt_gatt_server_send_response(): SUCCESS");
596 return common::PlatformResult{};
599 struct NotificationUserData {
601 BluetoothGATTServerService* service;
604 void BluetoothGATTServerService::NotifyCallback(int result, const char* remote_address,
605 bt_gatt_server_h server, bt_gatt_h characteristic,
606 bool completed, void* user_data) {
607 ScopeLogger("Async callback of bt_gatt_server_notify_characteristic_changed_value()");
608 LoggerD("result: %d, remote_address: %s, completed: %d", result, remote_address, completed);
610 NotificationUserData* data = static_cast<NotificationUserData*>(user_data);
611 BluetoothGATTServerService* bt_service = data->service;
612 int notify_id = data->notify_id;
613 LoggerD("notify_id: %d", notify_id);
615 picojson::value response = picojson::value(picojson::object());
616 picojson::object& obj = response.get<picojson::object>();
618 if (remote_address != nullptr) {
619 obj.insert(std::make_pair(kClientAddress, remote_address));
621 obj.insert(std::make_pair(kClientAddress, picojson::value()));
623 obj.insert(std::make_pair(kNotifyId, static_cast<double>(notify_id)));
626 if (BT_ERROR_NONE != result) {
627 auto ret = util::GetBluetoothError(result, "Failed to notify client about change");
628 type = kOnNotificationFail;
629 common::tools::ReportError(ret, &obj);
631 type = kOnNotificationSuccess;
634 obj.insert(std::make_pair(kType, type));
636 LoggerD("Sending event: type: %s, notifyId: %d", type.c_str(), notify_id);
638 "BluetoothGATTServerCharacteristicNotifyCallback_" + std::to_string(notify_id);
639 bt_service->instance_.FireEvent(event, response);
642 obj[kType] = picojson::value(kOnNotificationFinish);
643 bt_service->instance_.FireEvent(event, response);
648 common::PlatformResult BluetoothGATTServerService::NotifyAboutValueChange(
649 const picojson::value& args) {
652 auto gatt_id = static_cast<int>(args.get(kId).get<double>());
653 auto gatt_iter = gatt_objects_.find(gatt_id);
654 if (gatt_iter == gatt_objects_.end()) {
655 LoggerE("Can't find gatt object with id: %d", gatt_id);
656 return common::PlatformResult{common::ErrorCode::ABORT_ERR, "Unknown error occurred"};
658 bt_gatt_h gatt_handle = gatt_iter->second;
659 LoggerD("Found proper gatt object");
661 const picojson::array& value_array = args.get(kValue).get<picojson::array>();
662 int value_size = value_array.size();
663 std::unique_ptr<char[]> value_data(new char[value_size]);
664 for (int i = 0; i < value_size; ++i) {
665 value_data[i] = static_cast<int>(value_array[i].get<double>());
667 int ret = bt_gatt_set_value(gatt_handle, value_data.get(), value_size);
668 if (BT_ERROR_NONE != ret) {
669 LoggerE("Failed to set value, error: %d, message: %s", ret, get_error_message(ret));
670 return common::PlatformResult{common::ErrorCode::ABORT_ERR, "Unknown error occurred"};
672 LoggerD("New value set in characteristic");
674 const char* address = args.get(kClient).is<picojson::null>()
676 : args.get(kClient).get<std::string>().c_str();
678 LoggerD("Client address to notify: [%s]", address);
680 auto notify_id = static_cast<int>(args.get(kNotifyId).get<double>());
681 NotificationUserData* user_data = new NotificationUserData{notify_id, this};
682 ret = bt_gatt_server_notify_characteristic_changed_value(gatt_handle, NotifyCallback, address,
684 if (BT_ERROR_NONE != ret) {
685 LoggerE("bt_gatt_server_notify_characteristic_changed_value() failed: %d", ret);
687 return common::PlatformResult{common::ErrorCode::ABORT_ERR, "Failed to notify"};
689 LoggerD("Sent notification about value changed");
690 return common::PlatformResult{};
693 void BluetoothGATTServerService::ClearGATTData() {
696 LoggerD("Removing %zu old GATT handles and %zu callback names",
697 gatt_objects_.size(), callback_names_.size());
698 gatt_objects_.clear();
699 callback_names_.clear();
702 } // namespace bluetooth
703 } // namespace extension