From: Pawel Wasowski Date: Wed, 12 Aug 2020 11:25:10 +0000 (+0200) Subject: [Bluetooth][gatt] Add registerService method X-Git-Tag: submit/tizen/20200831.125703~1 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=aeac9973ff098d3fafa07e8ca8e884bcc5194a7f;p=platform%2Fcore%2Fapi%2Fwebapi-plugins.git [Bluetooth][gatt] Add registerService method https://code.sec.samsung.net/jira/browse/TWDAPI-263 [Description] Added: + BluetoothGATTServer::RegisterService() + BluetoothGATTServer::services getter [Verification] tested on chrome console Change-Id: I9588d6c613293d3c5f139263c0e8703de8ab02c3 Signed-off-by: Dawid Juszczak Signed-off-by: Pawel Wasowski --- diff --git a/src/bluetooth/bluetooth.gyp b/src/bluetooth/bluetooth.gyp index f99eb6b7..560710d8 100644 --- a/src/bluetooth/bluetooth.gyp +++ b/src/bluetooth/bluetooth.gyp @@ -44,7 +44,9 @@ 'uuid.cc', 'uuid.h', 'bluetooth_gatt_server.cc', - 'bluetooth_gatt_server.h' + 'bluetooth_gatt_server.h', + 'bluetooth_gatt_server_service.cc', + 'bluetooth_gatt_server_service.h' ], 'includes': [ '../common/pkg-config.gypi', diff --git a/src/bluetooth/bluetooth_api.js b/src/bluetooth/bluetooth_api.js index 09677975..5cd60055 100755 --- a/src/bluetooth/bluetooth_api.js +++ b/src/bluetooth/bluetooth_api.js @@ -3219,20 +3219,83 @@ BluetoothAdapter.prototype.getBluetoothProfileHandler = function() { }; // class BluetoothGATTServer //////////////////////// +var _BluetoothGATTServerServices = []; + var BluetoothGATTServer = function() { - var services_ = []; - Object.defineProperties(this, { - services: { - get: function() { - return services_; - }, - set: function() {} - } - }); -} + Object.defineProperties(this, { + services: { + enumerable: true, + get: function() { + return _BluetoothGATTServerServices; + }, + set: function() {} + } + }); +}; var AbortError = new WebAPIException('AbortError', 'An unknown error occurred'); +var BluetoothGATTServer_valid_registerService_errors = [ + 'InvalidStateError', + 'NotSupportedError', + 'InvalidValuesError', + 'AbortError' +]; +var BluetoothGATTServer_valid_registerService_exceptions = [ + 'InvalidStateError', + 'TypeMismatchError', + 'SecurityError' +]; + +BluetoothGATTServer.prototype.registerService = function() { + var args = AV.validateArgs(arguments, [ + { + name: 'service', + type: AV.Types.DICTIONARY + }, + { + name: 'successCallback', + type: AV.Types.FUNCTION, + optional: true, + nullable: true + }, + { + name: 'errorCallback', + type: AV.Types.FUNCTION, + optional: true, + nullable: true + } + ]); + + var service = new BluetoothGATTServerService(args.service); + + var callback = function(result) { + if (native.isFailure(result)) { + native.callIfPossible( + args.errorCallback, + native.getErrorObjectAndValidate( + result, + BluetoothGATTServer_valid_registerService_errors, + AbortError + ) + ); + } else { + _BluetoothGATTServerServicesRegisteredInNativeLayer[service._id] = true; + _BluetoothGATTServerServices.push(service); + native.callIfPossible(args.successCallback); + } + }; + + var result = native.call('BluetoothGATTServerRegisterService', service, callback); + if (native.isFailure(result)) { + throw native.getErrorObjectAndValidate( + result, + BluetoothGATTServer_valid_registerService_exceptions, + AbortError + ); + } +}; + var BluetoothGATTServer_valid_start_errors = ['InvalidStateError', 'NotSupportedError', 'AbortError']; var BluetoothGATTServer_valid_start_exceptions = ['InvalidStateError', 'TypeMismatchError', 'SecurityError']; diff --git a/src/bluetooth/bluetooth_gatt_server.cc b/src/bluetooth/bluetooth_gatt_server.cc index b2273112..0d131a08 100644 --- a/src/bluetooth/bluetooth_gatt_server.cc +++ b/src/bluetooth/bluetooth_gatt_server.cc @@ -27,10 +27,14 @@ using namespace common::tools; namespace extension { namespace bluetooth { -BluetoothGATTServer::BluetoothGATTServer(const BluetoothInstance& instance) - : instance_{instance}, initialized_{false}, running_{false}, handle_{nullptr} { +BluetoothGATTServer::BluetoothGATTServer(const BluetoothInstance& instance, + BluetoothGATTServerService& service) + : instance_{instance}, + service_{service}, + initialized_{false}, + running_{false}, + handle_{nullptr} { ScopeLogger(); - /* * TODO: register a callback, that deinitializes a server, unregisters its * services, destroys handle_ and sets running_ to false @@ -129,6 +133,55 @@ void BluetoothGATTServer::GetConnectionMtu(const picojson::value& args, ReportSuccess(picojson::value{static_cast(mtu)}, out); } +void BluetoothGATTServer::RegisterService(const picojson::value& args, picojson::object& out) { + ScopeLogger(); + + bt_gatt_h service_handle = nullptr; + + /* + * Each successfully created GATT{Service, Characteristic, Descriptor} has a + * corresponding entry in service_.gatt_objects, mapping its _id field of its JS + * object to its bt_gatt_h handle. + * new_gatt_objects is a container for the entries, that are added to + * service_.gatt_objects if both CreateService() and RegisterService() + * succeed. + * Otherwise, the service is not registered and the map is not updated. + */ + std::vector> new_gatt_objects; + auto result = service_.CreateService(args, &service_handle, new_gatt_objects); + if (result.IsError()) { + ReportError(result, &out); + return; + } + + if (!initialized_) { + /* + * Server is initialized when its services are registered. + * However, the case when server is uninitialized until start is + * also valid. It happens, when user doesn't register any services + * and starts the server with the default ones. + */ + auto result = InitializeAndCreateHandle(); + if (!result) { + result.SetMessage("Couldn't register the service"); + ReportError(result, &out); + return; + } + } + + result = service_.RegisterService(service_handle, this->handle_, new_gatt_objects); + if (result.IsError()) { + ReportError(result, &out); + return; + } + + ReportSuccess(out); +} + +bool BluetoothGATTServer::IsRunning() { + return running_; +} + PlatformResult BluetoothGATTServer::Initialize() { ScopeLogger(); diff --git a/src/bluetooth/bluetooth_gatt_server.h b/src/bluetooth/bluetooth_gatt_server.h index e28789c8..82185f4f 100644 --- a/src/bluetooth/bluetooth_gatt_server.h +++ b/src/bluetooth/bluetooth_gatt_server.h @@ -19,6 +19,7 @@ #include +#include "bluetooth/bluetooth_gatt_server_service.h" #include "common/picojson.h" #include "common/platform_result.h" @@ -31,12 +32,14 @@ class BluetoothInstance; class BluetoothGATTServer { public: - BluetoothGATTServer(const BluetoothInstance&); + BluetoothGATTServer(const BluetoothInstance& instance, BluetoothGATTServerService& service); ~BluetoothGATTServer(); void Start(picojson::object& out); void Stop(picojson::object& out); void GetConnectionMtu(const picojson::value& args, picojson::object& out); + void RegisterService(const picojson::value& args, picojson::object& out); + bool IsRunning(); static bool DestroyService(int total, int index, bt_gatt_h handle, void* user_data); static bool DestroyCharacteristic(int total, int index, bt_gatt_h handle, void* user_data); @@ -44,6 +47,7 @@ class BluetoothGATTServer { private: const BluetoothInstance& instance_; + BluetoothGATTServerService& service_; bool initialized_; bool running_; bt_gatt_server_h handle_; diff --git a/src/bluetooth/bluetooth_gatt_server_service.cc b/src/bluetooth/bluetooth_gatt_server_service.cc new file mode 100644 index 00000000..dcf0e6d4 --- /dev/null +++ b/src/bluetooth/bluetooth_gatt_server_service.cc @@ -0,0 +1,406 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include + +#include "bluetooth/bluetooth_gatt_server.h" +#include "bluetooth/bluetooth_gatt_server_service.h" +#include "bluetooth/bluetooth_util.h" +#include "bluetooth/uuid.h" + +#include "common/logger.h" +#include "common/platform_result.h" +#include "common/tools.h" + +using namespace extension::bluetooth::util; +using common::PlatformResult; +using common::ErrorCode; + +namespace extension { +namespace bluetooth { + +namespace { +const std::string kUuid = "uuid"; +const std::string kServiceUuid = "serviceUuid"; +const std::string kIsPrimary = "isPrimary"; +const std::string kCharacteristics = "characteristics"; + +const std::string kServices = "services"; +const std::string kDescriptors = "descriptors"; +const std::string kIsBroadcast = "isBroadcast"; +const std::string kHasExtendedProperties = "hasExtendedProperties"; +const std::string kIsNotify = "isNotify"; +const std::string kIsIndication = "isIndication"; +const std::string kIsReadable = "isReadable"; +const std::string kIsSignedWrite = "isSignedWrite"; +const std::string kIsWritable = "isWritable"; +const std::string kIsWriteNoResponse = "isWriteNoResponse"; +const std::string kReadPermission = "readPermission"; +const std::string kWritePermission = "writePermission"; +const std::string kEncryptedReadPermission = "encryptedReadPermission"; +const std::string kEncryptedWritePermission = "encryptedWritePermission"; +const std::string kEncryptedSignedReadPermission = "encryptedSignedReadPermission"; +const std::string kEncryptedSignedWritePermission = "encryptedSignedWritePermission"; + +const std::string kId = "_id"; + +int GetPermissionsInt(const picojson::value& permissions) { + ScopeLogger("permissions: %s", permissions.serialize().c_str()); + + int ret = 0; + if (permissions.get(kReadPermission).get()) { + ret |= BT_GATT_PERMISSION_READ; + } + if (permissions.get(kWritePermission).get()) { + ret |= BT_GATT_PERMISSION_WRITE; + } + if (permissions.get(kEncryptedReadPermission).get()) { + ret |= BT_GATT_PERMISSION_ENCRYPT_READ; + } + if (permissions.get(kEncryptedWritePermission).get()) { + ret |= BT_GATT_PERMISSION_ENCRYPT_WRITE; + } + if (permissions.get(kEncryptedSignedReadPermission).get()) { + ret |= BT_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_READ; + } + if (permissions.get(kEncryptedSignedWritePermission).get()) { + ret |= BT_GATT_PERMISSION_ENCRYPT_AUTHENTICATED_WRITE; + } + + LoggerD("Permissions: %x", static_cast(ret)); + return ret; +} + +int GetPropertiesInt(const picojson::value& properties) { + ScopeLogger("properties: %s", properties.serialize().c_str()); + + int ret = 0; + if (properties.get(kIsBroadcast).get()) { + ret |= BT_GATT_PROPERTY_BROADCAST; + } + if (properties.get(kIsReadable).get()) { + ret |= BT_GATT_PROPERTY_READ; + } + if (properties.get(kIsWriteNoResponse).get()) { + ret |= BT_GATT_PROPERTY_WRITE_WITHOUT_RESPONSE; + } + if (properties.get(kIsWritable).get()) { + ret |= BT_GATT_PROPERTY_WRITE; + } + if (properties.get(kIsNotify).get()) { + ret |= BT_GATT_PROPERTY_NOTIFY; + } + if (properties.get(kIsIndication).get()) { + ret |= BT_GATT_PROPERTY_INDICATE; + } + if (properties.get(kIsSignedWrite).get()) { + ret |= BT_GATT_PROPERTY_AUTHENTICATED_SIGNED_WRITES; + } + if (properties.get(kHasExtendedProperties).get()) { + ret |= BT_GATT_PROPERTY_EXTENDED_PROPERTIES; + } + + LoggerD("Properties: %x", static_cast(ret)); + return ret; +} + +} // namespace + +bool BluetoothGATTServerService::DestroyService(int total, int index, bt_gatt_h handle, void* user_data) { + ScopeLogger("total: %d, index: %d, handle: %p", total, index, handle); + + /* + * Undocumented behavior of native Bluetooth API: + * bt_gatt_service_destroy() destroys not only the service, but also all + * its components (included services, characteristics, descriptors) + * recursively. + */ + auto ret = bt_gatt_service_destroy(handle); + if (BT_ERROR_NONE != ret) { + LoggerE("bt_gatt_service_destroy(): %d (%s)", ret, get_error_message(ret)); + } + LoggerD("bt_gatt_service_destroy(): success"); + + return true; +} + +bool BluetoothGATTServerService::DestroyCharacteristic(int total, int index, bt_gatt_h handle, + void* user_data) { + ScopeLogger("total: %d, index: %d, handle: %p", total, index, handle); + + auto ret = bt_gatt_characteristic_destroy(handle); + if (BT_ERROR_NONE != ret) { + LoggerE("bt_gatt_characteristic_destroy(): %d (%s)", ret, get_error_message(ret)); + } + LoggerD("bt_gatt_characteristic_destroy(): success"); + + return true; +} + +bool BluetoothGATTServerService::DestroyDescriptor(int total, int index, bt_gatt_h handle, + void* user_data) { + ScopeLogger("total: %d, index: %d, handle: %p", total, index, handle); + + auto ret = bt_gatt_descriptor_destroy(handle); + if (BT_ERROR_NONE != ret) { + LoggerE("bt_gatt_descriptor_destroy(): %d (%s)", ret, get_error_message(ret)); + } + LoggerD("bt_gatt_descriptor_destroy(): success"); + + return true; +} +BluetoothGATTServerService::BluetoothGATTServerService() { + ScopeLogger(); +} + +BluetoothGATTServerService::~BluetoothGATTServerService() { + ScopeLogger(); +} + +common::PlatformResult BluetoothGATTServerService::AddDescriptors( + const picojson::array& descriptors_init, bt_gatt_h characteristic_handle, + std::vector>& new_gatt_objects) { + ScopeLogger("descriptors_init length: %zu", descriptors_init.size()); + + /* + * This function expects valid input. + * If it gets descriptors missing any: uuid, permission, + * or with one of these with a wrong type, the application will crash. + */ + + for (const auto& descriptor_init_data : descriptors_init) { + const auto& uuid_str = descriptor_init_data.get(kUuid).get(); + /* + * Native APIs don't support 32-bit UUIDs. We convert any UUID to its 128-bit + * form to assure, it will be accepted by the native API. + * + * We assume, UUID::create() returns a valid object, because the input is valid. + */ + auto uuid = UUID::create(uuid_str); + int permissions = GetPermissionsInt(descriptor_init_data); + bt_gatt_h descriptor_handle = nullptr; + + int ret = bt_gatt_descriptor_create(uuid->uuid_128_bit.c_str(), permissions, nullptr, 0, + &descriptor_handle); + if (BT_ERROR_NONE != ret) { + LoggerE("bt_gatt_descriptor_create() failed: %d (%s)", ret, get_error_message(ret)); + return BluetoothErrorToPlatformResult(ret, "Failed to create a descriptor"); + } + LoggerD("bt_gatt_descriptor_create(): success"); + + ret = bt_gatt_characteristic_add_descriptor(characteristic_handle, descriptor_handle); + if (BT_ERROR_NONE != ret) { + LoggerE("bt_gatt_characteristic_add_descriptor() failed: %d (%s)", ret, + get_error_message(ret)); + DestroyDescriptor(0, 0, descriptor_handle, nullptr); + return BluetoothErrorToPlatformResult(ret, "Failed to add descriptor to characteristic"); + } + LoggerD("bt_gatt_characteristic_add_descriptor(): success"); + + const auto _id = static_cast(descriptor_init_data.get(kId).get()); + new_gatt_objects.push_back({_id, descriptor_handle}); + } + + return common::PlatformResult(); +} + +common::PlatformResult BluetoothGATTServerService::AddCharacteristics( + const picojson::array& characteristics_init, bt_gatt_h service_handle, + std::vector>& new_gatt_objects) { + ScopeLogger("characteristics_init length: %zu", characteristics_init.size()); + + /* + * This function expects valid input. + * If it gets characteristics missing any: uuid, permission, property, + * or with any of these with a wrong type, the application will crash. + */ + + for (const auto& characteristic_init_data : characteristics_init) { + const auto& uuid_str = characteristic_init_data.get(kUuid).get(); + /* + * Native APIs don't support 32-bit UUIDs. We convert any UUID to its 128-bit + * form to assure, it will be accepted by the native API. + * + * We assume, UUID::create() returns a valid object, because the input is valid. + */ + auto uuid = UUID::create(uuid_str); + + int permissions = GetPermissionsInt(characteristic_init_data); + int properties = GetPropertiesInt(characteristic_init_data); + bt_gatt_h characteristic_handle = nullptr; + + int ret = bt_gatt_characteristic_create(uuid->uuid_128_bit.c_str(), permissions, properties, + nullptr, 0, &characteristic_handle); + if (BT_ERROR_NONE != ret) { + LoggerE("bt_gatt_characteristic_create() failed: %d (%s)", ret, get_error_message(ret)); + return BluetoothErrorToPlatformResult(ret, "Failed to create a characteristic"); + } + LoggerD("bt_gatt_characteristic_create(): success"); + + if (characteristic_init_data.get(kDescriptors).is()) { + const auto& descriptors = characteristic_init_data.get(kDescriptors).get(); + auto result = AddDescriptors(descriptors, characteristic_handle, new_gatt_objects); + if (!result) { + DestroyCharacteristic(0, 0, characteristic_handle, nullptr); + return result; + } + } + + ret = bt_gatt_service_add_characteristic(service_handle, characteristic_handle); + if (BT_ERROR_NONE != ret) { + LoggerE("bt_gatt_service_add_characteristic() failed: %d (%s)", ret, get_error_message(ret)); + DestroyCharacteristic(0, 0, characteristic_handle, nullptr); + return BluetoothErrorToPlatformResult(ret, "Failed to add a characteristic to a service"); + } + LoggerD("bt_gatt_service_add_characteristic(): success"); + + const auto _id = static_cast(characteristic_init_data.get(kId).get()); + new_gatt_objects.push_back({_id, characteristic_handle}); + } + + return common::PlatformResult(); +} + +common::PlatformResult BluetoothGATTServerService::AddIncludedServices( + const picojson::array& included_services_init, bt_gatt_h parent_service_handle, + std::vector>& new_gatt_objects) { + ScopeLogger("included_services_init length: %zu", included_services_init.size()); + + /* + * This function expects valid input. + * If it gets included_services missing a uuid + * or with any of these with a wrong type, the application will crash. + */ + + for (const auto& service_init_data : included_services_init) { + bt_gatt_h included_service_handle = nullptr; + auto result = CreateService(service_init_data, &included_service_handle, new_gatt_objects); + if (!result) { + LoggerE("Failed to create included service"); + return result; + } + + int ret = bt_gatt_service_add_included_service(parent_service_handle, included_service_handle); + if (BT_ERROR_NONE != ret) { + LoggerE("bt_gatt_service_add_included_service() failed: %d (%s)", ret, + get_error_message(ret)); + DestroyService(0, 0, included_service_handle, nullptr); + return BluetoothErrorToPlatformResult(ret, "Failed to add included service"); + } + LoggerD("bt_gatt_service_add_included_service(): success"); + + const auto _id = static_cast(service_init_data.get(kId).get()); + new_gatt_objects.push_back({_id, parent_service_handle}); + } + + return common::PlatformResult(); +} + +common::PlatformResult BluetoothGATTServerService::CreateService( + const picojson::value& service_init, bt_gatt_h* new_service_handle, + std::vector>& new_gatt_objects) { + ScopeLogger("service_init: %s", service_init.serialize().c_str()); + /* + * This function expects valid input. + * If it gets service_init without any of the expected members or with a member of + * a wrong type, the application will crash. + */ + + const auto& uuid_str = service_init.get(kServiceUuid).get(); + /* + * Native APIs don't support 32-bit UUIDs. We convert any UUID to its 128-bit + * form to assure, it will be accepted by the native API. + * + * We assume, UUID::create() returns a valid object, because the input is valid. + */ + auto uuid = UUID::create(uuid_str); + bool primary = service_init.get(kIsPrimary).get(); + bt_gatt_service_type_e type = + primary ? BT_GATT_SERVICE_TYPE_PRIMARY : BT_GATT_SERVICE_TYPE_SECONDARY; + bt_gatt_h service_handle = nullptr; + + int err = bt_gatt_service_create(uuid->uuid_128_bit.c_str(), type, &service_handle); + if (BT_ERROR_NONE != err) { + LoggerE("bt_gatt_service_create error: %d (%s)", err, get_error_message(err)); + return BluetoothErrorToPlatformResult(err, "Failed to create GATT service"); + } + LoggerD("bt_gatt_service_create(): success"); + + if (service_init.get(kServices).is()) { + const auto& services = service_init.get(kServices).get(); + auto result = AddIncludedServices(services, service_handle, new_gatt_objects); + if (!result) { + DestroyService(0, 0, service_handle, nullptr); + return result; + } + } + + if (service_init.get(kCharacteristics).is()) { + const auto& characteristics = service_init.get(kCharacteristics).get(); + auto result = AddCharacteristics(characteristics, service_handle, new_gatt_objects); + if (!result) { + DestroyService(0, 0, service_handle, nullptr); + return result; + } + } + + const auto _id = static_cast(service_init.get(kId).get()); + new_gatt_objects.push_back({_id, service_handle}); + + *new_service_handle = service_handle; + + return common::PlatformResult(); +} + +common::PlatformResult BluetoothGATTServerService::RegisterService( + bt_gatt_h service_handle, bt_gatt_server_h server, + const std::vector>& new_gatt_objects) { + ScopeLogger(); + + int ret = bt_gatt_server_register_service(server, service_handle); + if (BT_ERROR_NONE != ret) { + LoggerE("bt_gatt_server_register_service() failed: %d (%s)", ret, get_error_message(ret)); + return BluetoothErrorToPlatformResult(ret, "Failed to register GATT service"); + } + + gatt_objects_.insert(new_gatt_objects.begin(), new_gatt_objects.end()); + + return common::PlatformResult(); +} + + +common::PlatformResult BluetoothGATTServerService::UnregisterService(const picojson::value& args, bt_gatt_server_h server) { + ScopeLogger(); + + auto _id = static_cast(args.get(kId).get()); + LoggerD("Unregistering service with _id: %d", _id); + + auto service_handle = gatt_objects_[_id]; + + auto ret = bt_gatt_server_unregister_service(server, service_handle); + if (BT_ERROR_NONE != ret) { + LoggerE("bt_gatt_server_unregister_service() failed: %d (%s)", ret, get_error_message(ret)); + return BluetoothErrorToPlatformResult(ret, "Failed to unregister GATT service"); + } + LoggerD("bt_gatt_server_unregister_service(): SUCCESS"); + + gatt_objects_.erase(_id); + return common::PlatformResult{}; + +} + +} // namespace bluetooth +} // namespace extension diff --git a/src/bluetooth/bluetooth_gatt_server_service.h b/src/bluetooth/bluetooth_gatt_server_service.h new file mode 100644 index 00000000..cecd9d2b --- /dev/null +++ b/src/bluetooth/bluetooth_gatt_server_service.h @@ -0,0 +1,66 @@ +/* + * Copyright (c) 2020 Samsung Electronics Co., Ltd All Rights Reserved + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef BLUETOOTH_BLUETOOTH_GATT_SERVER_SERVICE_H_ +#define BLUETOOTH_BLUETOOTH_GATT_SERVER_SERVICE_H_ + +#include +#include + +#include + +#include "common/platform_result.h" + +using common::PlatformResult; + +namespace extension { + +namespace bluetooth { + +class BluetoothInstance; + +class BluetoothGATTServerService { + public: + BluetoothGATTServerService(); + ~BluetoothGATTServerService(); + + PlatformResult CreateService(const picojson::value& args, bt_gatt_h* new_service_handle, + std::vector>& new_gatt_objects); + PlatformResult RegisterService(bt_gatt_h service_handle, bt_gatt_server_h server, + const std::vector>& new_gatt_objects); + PlatformResult UnregisterService(const picojson::value& args, bt_gatt_server_h server); + + private: + std::map gatt_objects_; + + static bool DestroyService(int total, int index, bt_gatt_h handle, void* user_data); + static bool DestroyCharacteristic(int total, int index, bt_gatt_h handle, void* user_data); + static bool DestroyDescriptor(int total, int index, bt_gatt_h handle, void* user_data); + + PlatformResult AddDescriptors(const picojson::array& descriptors, bt_gatt_h characteristic_handle, + std::vector>& new_gatt_objects); + PlatformResult AddCharacteristics(const picojson::array& characteristics, + bt_gatt_h service_handle, + std::vector>& new_gatt_objects); + PlatformResult AddIncludedServices(const picojson::array& included_services, + bt_gatt_h parent_service_handle, + std::vector>& new_gatt_objects); +}; + +} // bluetooth +} // extension + +#endif // BLUETOOTH_BLUETOOTH_GATT_SERVER_SERVICE_H_ diff --git a/src/bluetooth/bluetooth_instance.cc b/src/bluetooth/bluetooth_instance.cc index 2e72a9c3..a7575ea7 100644 --- a/src/bluetooth/bluetooth_instance.cc +++ b/src/bluetooth/bluetooth_instance.cc @@ -37,8 +37,9 @@ BluetoothInstance::BluetoothInstance() bluetooth_le_adapter_(*this), bluetooth_gatt_client_service_(*this), bluetooth_le_device_(*this, bluetooth_gatt_client_service_), + bluetooth_gatt_server_service_(), worker(), - bluetooth_gatt_server_(*this) { + bluetooth_gatt_server_(*this, bluetooth_gatt_server_service_) { ScopeLogger(); using std::placeholders::_1; using std::placeholders::_2; @@ -103,6 +104,7 @@ BluetoothInstance::BluetoothInstance() REGISTER_METHOD(BluetoothGATTServerStart); REGISTER_METHOD(BluetoothGATTServerStop); REGISTER_METHOD(BluetoothGATTServerGetConnectionMtu); + REGISTER_METHOD(BluetoothGATTServerRegisterService); #undef REGISTER_METHOD } @@ -500,5 +502,23 @@ void BluetoothInstance::BluetoothGATTServerGetConnectionMtu(const picojson::valu ReportSuccess(out); } +void BluetoothInstance::BluetoothGATTServerRegisterService(const picojson::value& args, + picojson::object& out) { + ScopeLogger(); + CHECK_PRIVILEGE_ACCESS(kPrivilegeBluetooth, &out); + + worker.add_job([this, args] { + ScopeLogger("Async call: BluetoothGATTServerRegisterService"); + picojson::value response = picojson::value(picojson::object()); + picojson::object& async_out = response.get(); + double callback_id = args.get("callbackId").get(); + async_out["callbackId"] = picojson::value(callback_id); + this->bluetooth_gatt_server_.RegisterService(args, async_out); + this->PostMessage(response.serialize().c_str()); + }); + + ReportSuccess(out); +} + } // namespace bluetooth } // namespace extension diff --git a/src/bluetooth/bluetooth_instance.h b/src/bluetooth/bluetooth_instance.h index 58f9b7c0..ed122272 100644 --- a/src/bluetooth/bluetooth_instance.h +++ b/src/bluetooth/bluetooth_instance.h @@ -23,6 +23,7 @@ #include "bluetooth/bluetooth_device.h" #include "bluetooth/bluetooth_gatt_server.h" #include "bluetooth/bluetooth_gatt_client_service.h" +#include "bluetooth/bluetooth_gatt_server_service.h" #include "bluetooth/bluetooth_health_application.h" #include "bluetooth/bluetooth_health_channel.h" #include "bluetooth/bluetooth_health_profile_handler.h" @@ -111,6 +112,7 @@ class BluetoothInstance : public common::ParsedInstance { void BluetoothGATTServerStart(const picojson::value& args, picojson::object& out); void BluetoothGATTServerStop(const picojson::value& args, picojson::object& out); void BluetoothGATTServerGetConnectionMtu(const picojson::value& args, picojson::object& out); + void BluetoothGATTServerRegisterService(const picojson::value& args, picojson::object& out); BluetoothAdapter bluetooth_adapter_; BluetoothDevice bluetooth_device_; @@ -122,6 +124,7 @@ class BluetoothInstance : public common::ParsedInstance { BluetoothLEAdapter bluetooth_le_adapter_; BluetoothGATTClientService bluetooth_gatt_client_service_; BluetoothLEDevice bluetooth_le_device_; + BluetoothGATTServerService bluetooth_gatt_server_service_; common::Worker worker; // If all operations on bluetooth_gatt_server_ will be done by the worker, // no mutex to prevent concurrent access of this object is needed