From: Dawid Juszczak Date: Wed, 22 Jul 2020 16:11:06 +0000 (+0200) Subject: [Bluetooth] Rename BluetoothGATTService to BluetoothGATTClientService X-Git-Tag: submit/tizen/20200831.125703~4^2 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=5a25c241bbeb6df51cc268cc2e3f064d58c224e2;p=platform%2Fcore%2Fapi%2Fwebapi-plugins.git [Bluetooth] Rename BluetoothGATTService to BluetoothGATTClientService [Verification] Each method implemented by BluetoothGATTClientService was called in Chrome Dev Tools. All auto Bluetooth and manual BLE tests pass. Change-Id: I530e94aa40b294d43525aed50c9a19dde3c2a1c4 Signed-off-by: Dawid Juszczak Signed-off-by: Pawel Wasowski --- diff --git a/src/bluetooth/bluetooth.gyp b/src/bluetooth/bluetooth.gyp index 73df5d3f..f99eb6b7 100644 --- a/src/bluetooth/bluetooth.gyp +++ b/src/bluetooth/bluetooth.gyp @@ -33,8 +33,8 @@ 'bluetooth_le_adapter.h', 'bluetooth_service_handler.cc', 'bluetooth_service_handler.h', - 'bluetooth_gatt_service.cc', - 'bluetooth_gatt_service.h', + 'bluetooth_gatt_client_service.cc', + 'bluetooth_gatt_client_service.h', 'bluetooth_socket.cc', 'bluetooth_socket.h', 'bluetooth_util.cc', diff --git a/src/bluetooth/bluetooth_api.js b/src/bluetooth/bluetooth_api.js index 37799e00..df42559a 100755 --- a/src/bluetooth/bluetooth_api.js +++ b/src/bluetooth/bluetooth_api.js @@ -1621,7 +1621,7 @@ var BluetoothGATTService = function(data, address) { var address_ = address || data.address; function servicesGetter() { var services = []; - var result = native.callSync('BluetoothGATTServiceGetServices', { + var result = native.callSync('BluetoothGATTClientServiceGetServices', { handle: handle_, address: address_ }); @@ -1635,7 +1635,7 @@ var BluetoothGATTService = function(data, address) { } function characteristicsGetter() { var characteristics = []; - var result = native.callSync('BluetoothGATTServiceGetCharacteristics', { + var result = native.callSync('BluetoothGATTClientServiceGetCharacteristics', { handle: handle_, uuid: serviceUuid_, address: address_ @@ -1790,7 +1790,7 @@ var BluetoothGATTCharacteristic = function(data, address) { var callArgs = { handle: handle_, address: address_ }; - var result = native.call('BluetoothGATTServiceReadValue', callArgs, callback); + var result = native.call('BluetoothGATTClientServiceReadValue', callArgs, callback); if (native.isFailure(result)) { throw native.getErrorObject(result); @@ -1828,7 +1828,7 @@ var BluetoothGATTCharacteristic = function(data, address) { address: address_ }; - var result = native.call('BluetoothGATTServiceWriteValue', callArgs, callback); + var result = native.call('BluetoothGATTClientServiceWriteValue', callArgs, callback); if (native.isFailure(result)) { throw native.getErrorObject(result); @@ -1985,8 +1985,8 @@ var _bluetoothGATTCharacteristicListener = _multipleListenerBuilder( function(listener, event) { listener(event); }, - 'BluetoothGATTServiceAddValueChangeListener', - 'BluetoothGATTServiceRemoveValueChangeListener', + 'BluetoothGATTClientServiceAddValueChangeListener', + 'BluetoothGATTClientServiceRemoveValueChangeListener', true ); @@ -2032,7 +2032,7 @@ var BluetoothGATTDescriptor = function(data, address) { var callArgs = { handle: handle_, address: address_ }; - var result = native.call('BluetoothGATTServiceReadValue', callArgs, callback); + var result = native.call('BluetoothGATTClientServiceReadValue', callArgs, callback); if (native.isFailure(result)) { throw native.getErrorObject(result); @@ -2070,7 +2070,7 @@ var BluetoothGATTDescriptor = function(data, address) { address: address_ }; - var result = native.call('BluetoothGATTServiceWriteValue', callArgs, callback); + var result = native.call('BluetoothGATTClientServiceWriteValue', callArgs, callback); if (native.isFailure(result)) { throw native.getErrorObject(result); diff --git a/src/bluetooth/bluetooth_gatt_client_service.cc b/src/bluetooth/bluetooth_gatt_client_service.cc new file mode 100644 index 00000000..1be096c8 --- /dev/null +++ b/src/bluetooth/bluetooth_gatt_client_service.cc @@ -0,0 +1,638 @@ +/* + * Copyright (c) 2015 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 "bluetooth/bluetooth_gatt_client_service.h" + +#include + +#include "common/extension.h" +#include "common/logger.h" +#include "common/platform_result.h" +#include "common/task-queue.h" +#include "common/tools.h" + +#include "bluetooth/bluetooth_instance.h" +#include "bluetooth/bluetooth_privilege.h" +#include "bluetooth/bluetooth_util.h" + +namespace extension { +namespace bluetooth { + +using common::PlatformResult; +using common::ErrorCode; +using common::TaskQueue; +using namespace common::tools; + +namespace { +const std::string kUuid = "uuid"; +const std::string kServiceUuid = "serviceUuid"; +const std::string kHandle = "handle"; +const std::string kAddress = "address"; + +const std::string kDescriptors = "descriptors"; +const std::string kBroadcast = "isBroadcast"; +const std::string kExtendedProperties = "hasExtendedProperties"; +const std::string kNotify = "isNotify"; +const std::string kIndication = "isIndication"; +const std::string kReadable = "isReadable"; +const std::string kSignedWrite = "isSignedWrite"; +const std::string kWritable = "isWritable"; +const std::string kWriteNoResponse = "isWriteNoResponse"; + +const std::string kOnValueChanged = "BluetoothGATTCharacteristicValueChangeListener"; + +bool IsProperty(int propertyBits, bt_gatt_property_e property) { + return (propertyBits & property) != 0; +} +} + +BluetoothGATTClientService::BluetoothGATTClientService(BluetoothInstance& instance) : instance_(instance) { + ScopeLogger(); +} + +BluetoothGATTClientService::~BluetoothGATTClientService() { + ScopeLogger(); + + for (auto it : gatt_characteristic_) { + // unregister callback, ignore errors + bt_gatt_client_unset_characteristic_value_changed_cb(it); + } + + for (auto it : gatt_clients_) { + LoggerD("destroying client for address: %s", it.first.c_str()); + bt_gatt_client_destroy(it.second); + } +} + +bool BluetoothGATTClientService::IsStillConnected(const std::string& address) { + auto it = gatt_clients_.find(address); + return gatt_clients_.end() != it; +} + +bt_gatt_client_h BluetoothGATTClientService::GetGattClient(const std::string& address) { + ScopeLogger(); + + bt_gatt_client_h client = nullptr; + + const auto it = gatt_clients_.find(address); + + if (gatt_clients_.end() == it) { + int ret = bt_gatt_client_create(address.c_str(), &client); + if (BT_ERROR_NONE != ret) { + LoggerE("Failed to create GATT client, error: %d", ret); + } else { + gatt_clients_.insert(std::make_pair(address, client)); + } + } else { + LoggerD("Client already created"); + client = it->second; + } + + return client; +} + +// this method should be used to inform this object that some device was disconnected +void BluetoothGATTClientService::TryDestroyClient(const std::string& address) { + ScopeLogger(); + auto it = gatt_clients_.find(address); + if (gatt_clients_.end() != it) { + LoggerD("destroying client for address: %s", it->first.c_str()); + bt_gatt_client_destroy(it->second); + gatt_clients_.erase(it); + } else { + LoggerD("Client for address: %s does not exist, no need for deletion", address.c_str()); + } +} + +PlatformResult BluetoothGATTClientService::GetSpecifiedGATTClient(const std::string& address, + const UUID& uuid, + picojson::object* result) { + ScopeLogger(); + + bt_gatt_client_h client = GetGattClient(address); + + if (nullptr == client) { + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Failed to create the GATT client's handle"); + } + + bt_gatt_h service = nullptr; + int ret = bt_gatt_client_get_service(client, uuid.uuid_128_bit.c_str(), &service); + if (BT_ERROR_NONE != ret) { + LoggerE("bt_gatt_client_get_service() error: %d", ret); + switch (ret) { + case BT_ERROR_NO_DATA: + return LogAndCreateResult( + ErrorCode::NOT_FOUND_ERR, "Service not found", + ("bt_gatt_client_get_service error: %d (%s)", ret, get_error_message(ret))); + + case BT_ERROR_INVALID_PARAMETER: + return LogAndCreateResult( + ErrorCode::NOT_FOUND_ERR, "Service UUID is invalid", + ("bt_gatt_client_get_service error: %d (%s)", ret, get_error_message(ret))); + + default: + return LogAndCreateResult( + ErrorCode::UNKNOWN_ERR, "Failed to get a service's GATT handle", + ("bt_gatt_client_get_service error: %d (%s)", ret, get_error_message(ret))); + } + } + + /* + * BACKWARD COMPATIBILITY + * + * BluetoothGATTClientService::uuid has always been set to source format in this + * function. + */ + result->insert(std::make_pair(kUuid, picojson::value(uuid.uuid_in_source_format))); + result->insert(std::make_pair(kServiceUuid, picojson::value(uuid.uuid_in_source_format))); + // handle is passed to upper layer because there is no need to delete it + result->insert(std::make_pair(kHandle, picojson::value((double)(long)service))); + // address is necessary to later check if device is still connected + result->insert(std::make_pair(kAddress, picojson::value(address))); + return PlatformResult(ErrorCode::NO_ERROR); +} + +void BluetoothGATTClientService::GetServices(const picojson::value& args, picojson::object& out) { + ScopeLogger(); + + bt_gatt_h handle = (bt_gatt_h) static_cast(args.get("handle").get()); + const std::string& address = args.get("address").get(); + + picojson::array array; + PlatformResult ret = GetServicesHelper(handle, address, &array); + if (ret.IsError()) { + LogAndReportError(ret, &out, ("Error while getting services")); + } else { + ReportSuccess(picojson::value(array), out); + } +} + +PlatformResult BluetoothGATTClientService::GetServicesHelper(bt_gatt_h handle, const std::string& address, + picojson::array* array) { + ScopeLogger(); + + if (!IsStillConnected(address)) { + return LogAndCreateResult(ErrorCode::INVALID_STATE_ERR, "Device is not connected", + ("Device with address %s is no longer connected", address.c_str())); + } + + int ret = bt_gatt_service_foreach_included_services( + handle, + [](int total, int index, bt_gatt_h gatt_handle, void* data) { + ScopeLogger( + "Entered into asynchronous function, argument in " + "bt_gatt_service_foreach_included_services"); + + picojson::value result = picojson::value{picojson::object{}}; + picojson::object& result_obj = result.get(); + + const auto uuid = UUID::createFromGatt(gatt_handle); + if (uuid) { + /* + * BACKWARD COMPATIBILITY + * + * UUID has always been set to source format in this function. + */ + result_obj.insert(std::make_pair(kUuid, picojson::value{uuid->uuid_in_source_format})); + result_obj.insert(std::make_pair(kServiceUuid, picojson::value{uuid->uuid_in_source_format})); + } else { + result_obj.insert(std::make_pair(kUuid, picojson::value{"0xFFFF"})); + result_obj.insert(std::make_pair(kServiceUuid, picojson::value{})); + } + + // handle is passed to upper layer because there is no need of deletion + result_obj.insert(std::make_pair(kHandle, picojson::value{(double)(long)gatt_handle})); + static_cast(data)->push_back(result); + return true; + }, + array); + if (BT_ERROR_NONE != ret) { + LoggerE("Failed bt_gatt_service_foreach_included_services() (%d)", ret); + return util::GetBluetoothError(ret, "Failed to set a service's GATT callback"); + } + + return PlatformResult(ErrorCode::NO_ERROR); +} + +void BluetoothGATTClientService::GetCharacteristics(const picojson::value& args, picojson::object& out) { + ScopeLogger(); + + bt_gatt_h handle = (bt_gatt_h) static_cast(args.get("handle").get()); + + const std::string& address = args.get("address").get(); + + picojson::array array; + PlatformResult ret = GetCharacteristicsHelper(handle, address, &array); + if (ret.IsError()) { + LogAndReportError(ret, &out, ("Error while getting characteristics")); + } else { + ReportSuccess(picojson::value(array), out); + } +} + +PlatformResult BluetoothGATTClientService::GetCharacteristicsHelper(bt_gatt_h handle, + const std::string& address, + picojson::array* array) { + ScopeLogger(); + + if (!IsStillConnected(address)) { + return LogAndCreateResult(ErrorCode::INVALID_STATE_ERR, "Device is not connected", + ("Device with address %s is no longer connected", address.c_str())); + } + + struct Data { + picojson::array* array; + PlatformResult* platform_res; + }; + + PlatformResult platform_result = PlatformResult(ErrorCode::NO_ERROR); + Data user_data = {array, &platform_result}; + + int ret = bt_gatt_service_foreach_characteristics( + handle, + [](int total, int index, bt_gatt_h gatt_handle, void* data) { + ScopeLogger( + "Entered into asynchronous function, bt_gatt_service_foreach_characteristics;" + " index: %d", index); + Data* user_data = static_cast(data); + picojson::array* array = user_data->array; + PlatformResult* platform_result = user_data->platform_res; + + picojson::value result = picojson::value(picojson::object()); + picojson::object& result_obj = result.get(); + + // handle is passed to upper layer because there is no need of deletion + result_obj.insert(std::make_pair(kHandle, picojson::value((double)(long)gatt_handle))); + + // descriptors + picojson::array& desc_array = + result_obj.insert(std::make_pair("descriptors", picojson::value(picojson::array()))) + .first->second.get(); + int ret = bt_gatt_characteristic_foreach_descriptors( + gatt_handle, + [](int total, int index, bt_gatt_h desc_handle, void* data) { + ScopeLogger( + "Entered into asynchronous function, bt_gatt_characteristic_foreach_descriptors;" + " index: %d", index); + picojson::array& desc_array = *(static_cast(data)); + + picojson::value desc = picojson::value(picojson::object()); + picojson::object& desc_obj = desc.get(); + + // handle is passed to upper layer because there is no need of deletion + desc_obj.insert(std::make_pair(kHandle, picojson::value((double)(long)desc_handle))); + + auto uuid = UUID::createFromGatt(desc_handle); + if (uuid) { + desc_obj.insert(std::make_pair(kUuid, picojson::value{uuid->ShortestPossibleFormat()})); + } else { + desc_obj.insert(std::make_pair(kUuid, picojson::value{})); + } + + desc_array.push_back(desc); + return true; + }, + static_cast(&desc_array)); + if (BT_ERROR_NONE != ret) { + *platform_result = util::GetBluetoothError(ret, "Failed to get descriptors"); + LoggerE("Failed bt_gatt_characteristic_foreach_descriptors() (%d)", ret); + return false; + } + + // other properties + int property_bits = 0; + int err = bt_gatt_characteristic_get_properties(gatt_handle, &property_bits); + if (BT_ERROR_NONE != err) { + LoggerE("Properties of characteristic couldn't be acquired"); + } + result_obj.insert(std::make_pair( + kBroadcast, picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_BROADCAST)))); + result_obj.insert(std::make_pair( + kReadable, picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_READ)))); + result_obj.insert(std::make_pair( + kWriteNoResponse, + picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_WRITE_WITHOUT_RESPONSE)))); + result_obj.insert(std::make_pair( + kWritable, picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_WRITE)))); + result_obj.insert(std::make_pair( + kNotify, picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_NOTIFY)))); + result_obj.insert(std::make_pair( + kIndication, picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_INDICATE)))); + result_obj.insert(std::make_pair( + kSignedWrite, picojson::value(IsProperty( + property_bits, BT_GATT_PROPERTY_AUTHENTICATED_SIGNED_WRITES)))); + result_obj.insert(std::make_pair( + kExtendedProperties, + picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_EXTENDED_PROPERTIES)))); + + auto uuid = UUID::createFromGatt(gatt_handle); + if (uuid) { + result_obj.insert(std::make_pair(kUuid, picojson::value{uuid->ShortestPossibleFormat()})); + } else { + LoggerW("bt_gatt_get_uuid error: %d (%s)", err, get_error_message(err)); + result_obj.insert(std::make_pair(kUuid, picojson::value{})); + } + + array->push_back(result); + return true; + }, + static_cast(&user_data)); + if (platform_result.IsError()) { + return platform_result; + } + if (BT_ERROR_NONE != ret) { + LoggerE("Failed (%d)", ret); + return util::GetBluetoothError(ret, "Failed while getting characteristic"); + } + + return PlatformResult(ErrorCode::NO_ERROR); +} + +void BluetoothGATTClientService::ReadValue(const picojson::value& args, picojson::object& out) { + ScopeLogger(); + CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin, + &out); + + const std::string& address = args.get("address").get(); + if (!IsStillConnected(address)) { + LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Device is not connected"), &out, + ("Device with address %s is no longer connected", address.c_str())); + return; + } + + const double callback_handle = util::GetAsyncCallbackHandle(args); + struct Data { + double callback_handle; + BluetoothGATTClientService* service; + }; + + Data* user_data = new Data{callback_handle, this}; + bt_gatt_h handle = (bt_gatt_h) static_cast(args.get("handle").get()); + + auto read_value = [](int result, bt_gatt_h handle, void* user_data) -> void { + ScopeLogger("Entered into asynchronous function, read_value"); + Data* data = static_cast(user_data); + double callback_handle = data->callback_handle; + BluetoothGATTClientService* service = data->service; + delete data; + + PlatformResult plarform_res = PlatformResult(ErrorCode::NO_ERROR); + + picojson::value byte_array = picojson::value(picojson::array()); + picojson::array& byte_array_obj = byte_array.get(); + + if (BT_ERROR_NONE != result) { + plarform_res = util::GetBluetoothError(result, "Error while reading value"); + } else { + char* value = nullptr; + int length = 0; + int ret = bt_gatt_get_value(handle, &value, &length); + if (BT_ERROR_NONE != ret) { + plarform_res = util::GetBluetoothError(ret, "Error while getting value"); + } else { + for (int i = 0; i < length; i++) { + byte_array_obj.push_back(picojson::value(std::to_string(value[i]))); + } + } + if (value) { + free(value); + value = nullptr; + } + } + + std::shared_ptr response = + std::shared_ptr(new picojson::value(picojson::object())); + if (plarform_res.IsSuccess()) { + ReportSuccess(byte_array, response->get()); + } else { + LogAndReportError(plarform_res, &response->get()); + } + TaskQueue::GetInstance().Async( + [service, callback_handle](const std::shared_ptr& response) { + service->instance_.SyncResponse(callback_handle, response); + }, + response); + }; + int ret = bt_gatt_client_read_value(handle, read_value, (void*)user_data); + if (BT_ERROR_NONE != ret) { + delete user_data; + user_data = nullptr; + LoggerE("Couldn't register callback for read value %d (%s)", ret, get_error_message(ret)); + } + ReportSuccess(out); +} + +void BluetoothGATTClientService::WriteValue(const picojson::value& args, picojson::object& out) { + ScopeLogger(); + CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin, + &out); + + const std::string& address = args.get("address").get(); + if (!IsStillConnected(address)) { + LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Device is not connected"), &out, + ("Device with address %s is no longer connected", address.c_str())); + return; + } + + const double callback_handle = util::GetAsyncCallbackHandle(args); + const picojson::array& value_array = args.get("value").get(); + + int value_size = value_array.size(); + std::unique_ptr value_data(new char[value_size]); + for (int i = 0; i < value_size; ++i) { + value_data[i] = (int)value_array[i].get(); + } + + struct Data { + double callback_handle; + BluetoothGATTClientService* service; + }; + + bt_gatt_h handle = (bt_gatt_h) static_cast(args.get("handle").get()); + + auto write_value = [](int result, bt_gatt_h handle, void* user_data) -> void { + ScopeLogger("Entered into asynchronous function, write_value"); + Data* data = static_cast(user_data); + double callback_handle = data->callback_handle; + BluetoothGATTClientService* service = data->service; + delete data; + + PlatformResult ret = PlatformResult(ErrorCode::NO_ERROR); + if (BT_ERROR_NONE != result) { + ret = util::GetBluetoothError(result, "Error while getting value"); + } + + std::shared_ptr response = + std::shared_ptr(new picojson::value(picojson::object())); + if (ret.IsSuccess()) { + ReportSuccess(response->get()); + } else { + LogAndReportError(ret, &response->get()); + } + TaskQueue::GetInstance().Async( + [service, callback_handle](const std::shared_ptr& response) { + service->instance_.SyncResponse(callback_handle, response); + }, + response); + }; + + int ret = bt_gatt_set_value(handle, value_data.get(), value_size); + + if (BT_ERROR_NONE != ret) { + std::shared_ptr response = + std::shared_ptr(new picojson::value(picojson::object())); + LogAndReportError(util::GetBluetoothError(ret, "Failed to set value"), + &response->get(), + ("bt_gatt_set_value error: %d (%s)", ret, get_error_message(ret))); + TaskQueue::GetInstance().Async( + [this, callback_handle](const std::shared_ptr& response) { + instance_.SyncResponse(callback_handle, response); + }, + response); + } else { + Data* user_data = new Data{callback_handle, this}; + ret = bt_gatt_client_write_value(handle, write_value, user_data); + if (BT_ERROR_NONE != ret) { + delete user_data; + LoggerE("Couldn't register callback for write value %d (%s)", ret, get_error_message(ret)); + } + } + ReportSuccess(out); +} + +void BluetoothGATTClientService::AddValueChangeListener(const picojson::value& args, + picojson::object& out) { + ScopeLogger(); + const auto& address = args.get("address").get(); + if (!IsStillConnected(address)) { + LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Device is not connected"), &out, + ("Device with address %s is no longer connected", address.c_str())); + return; + } + + bt_gatt_h handle = (bt_gatt_h) static_cast(args.get(kHandle).get()); + + int ret = bt_gatt_client_set_characteristic_value_changed_cb(handle, OnCharacteristicValueChanged, + this); + if (BT_ERROR_NONE != ret) { + LogAndReportError(util::GetBluetoothError(ret, "Failed to register listener"), &out, + ("bt_gatt_client_set_characteristic_value_changed_cb() failed with: %d (%s)", + ret, get_error_message(ret))); + } else { + gatt_characteristic_.push_back(handle); + ReportSuccess(out); + } +} + +void BluetoothGATTClientService::RemoveValueChangeListener(const picojson::value& args, + picojson::object& out) { + ScopeLogger(); + const auto& address = args.get("address").get(); + if (!IsStillConnected(address)) { + LoggerW("Device with address %s is no longer connected", address.c_str()); + } else { + bt_gatt_h handle = (bt_gatt_h) static_cast(args.get(kHandle).get()); + + int ret = bt_gatt_client_unset_characteristic_value_changed_cb(handle); + + if (BT_ERROR_NONE != ret) { + LoggerW("bt_gatt_client_unset_characteristic_value_changed_cb() failed with: %d (%s)", ret, + get_error_message(ret)); + } else { + gatt_characteristic_.erase( + std::remove(gatt_characteristic_.begin(), gatt_characteristic_.end(), handle), + gatt_characteristic_.end()); + } + } + ReportSuccess(out); +} + +common::PlatformResult BluetoothGATTClientService::GetServiceAllUuids(const std::string& address, + picojson::array* array) { + ScopeLogger(); + + bt_gatt_client_h client = GetGattClient(address); + + if (nullptr == client) { + return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to create client"); + } + + auto foreach_callback = [](int total, int index, bt_gatt_h gatt_handle, void* user_data) -> bool { + ScopeLogger("Entered into asynchronous function, foreach_callback, total: %d, index: %d", total, + index); + + auto& uuids = *static_cast(user_data); + auto uuid = UUID::createFromGatt(gatt_handle); + if (uuid) { + /* + * BACKWARD COMPATIBILITY + * + * In the past, this function has always trimmed UUIDs retrieved + * from native API to 16 bit format. UUIDs that were not created + * from 16 bit UUID and BASE_UUID were converted to invalid values. + * + * We return UUIDs in shortest possible format to comply with past + * behaviour when possible. If the UUID is not convertible + * to 16 bit UUID, we return a longer form. + */ + uuids.push_back(picojson::value{uuid->ShortestPossibleFormat()}); + } else { + LoggerE("Couldn't get UUID from bt_gatt_h"); + } + + return true; + }; + + int ret = bt_gatt_client_foreach_services(client, foreach_callback, array); + + if (BT_ERROR_NONE == ret) { + return PlatformResult(ErrorCode::NO_ERROR); + } else { + return util::GetBluetoothError(ret, "Failed to get UUIDS"); + } +} + +void BluetoothGATTClientService::OnCharacteristicValueChanged(bt_gatt_h characteristic, char* value, + int length, void* user_data) { + ScopeLogger("characteristic: [%p], len: [%d], user_data: [%p]", characteristic, length, + user_data); + + auto service = static_cast(user_data); + + if (!service) { + LoggerE("user_data is NULL"); + return; + } + + picojson::value result = picojson::value(picojson::object()); + picojson::object& result_obj = result.get(); + + result_obj.insert(std::make_pair(kHandle, picojson::value((double)(long)characteristic))); + + picojson::value byte_array = picojson::value(picojson::array()); + picojson::array& byte_array_obj = byte_array.get(); + + for (int i = 0; i < length; ++i) { + byte_array_obj.push_back(picojson::value(std::to_string(value[i]))); + } + + ReportSuccess(byte_array, result_obj); + + service->instance_.FireEvent(kOnValueChanged, result); +} + +} // namespace bluetooth +} // namespace extension diff --git a/src/bluetooth/bluetooth_gatt_client_service.h b/src/bluetooth/bluetooth_gatt_client_service.h new file mode 100644 index 00000000..72328686 --- /dev/null +++ b/src/bluetooth/bluetooth_gatt_client_service.h @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2015 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_CLIENT_SERVICE_H_ +#define BLUETOOTH_BLUETOOTH_GATT_CLIENT_SERVICE_H_ + +#include + +#include + +#include "bluetooth/uuid.h" +#include "common/picojson.h" +#include "common/platform_result.h" + +namespace extension { +namespace bluetooth { + +class BluetoothInstance; + +class BluetoothGATTClientService { + public: + BluetoothGATTClientService(BluetoothInstance& instance); + ~BluetoothGATTClientService(); + + common::PlatformResult GetSpecifiedGATTClient(const std::string& address, const UUID& uuid, + picojson::object* result); + + void TryDestroyClient(const std::string& address); + void GetServices(const picojson::value& data, picojson::object& out); + void GetCharacteristics(const picojson::value& data, picojson::object& out); + void ReadValue(const picojson::value& args, picojson::object& out); + void WriteValue(const picojson::value& args, picojson::object& out); + void AddValueChangeListener(const picojson::value& args, picojson::object& out); + void RemoveValueChangeListener(const picojson::value& args, picojson::object& out); + + common::PlatformResult GetServiceAllUuids(const std::string& address, picojson::array* array); + + private: + bool IsStillConnected(const std::string& address); + + bt_gatt_client_h GetGattClient(const std::string& address); + + common::PlatformResult GetServicesHelper(bt_gatt_h handle, const std::string& address, + picojson::array* array); + common::PlatformResult GetCharacteristicsHelper(bt_gatt_h handle, const std::string& address, + picojson::array* array); + + static void OnCharacteristicValueChanged(bt_gatt_h characteristic, char* value, int len, + void* user_data); + + std::map gatt_clients_; + std::vector gatt_characteristic_; + + BluetoothInstance& instance_; +}; + +} // namespace bluetooth +} // namespace extension + +#endif // BLUETOOTH_BLUETOOTH_GATT_CLIENT_SERVICE_H_ diff --git a/src/bluetooth/bluetooth_gatt_service.cc b/src/bluetooth/bluetooth_gatt_service.cc deleted file mode 100644 index ca74a240..00000000 --- a/src/bluetooth/bluetooth_gatt_service.cc +++ /dev/null @@ -1,638 +0,0 @@ -/* - * Copyright (c) 2015 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 "bluetooth/bluetooth_gatt_service.h" - -#include - -#include "common/extension.h" -#include "common/logger.h" -#include "common/platform_result.h" -#include "common/task-queue.h" -#include "common/tools.h" - -#include "bluetooth/bluetooth_instance.h" -#include "bluetooth/bluetooth_privilege.h" -#include "bluetooth/bluetooth_util.h" - -namespace extension { -namespace bluetooth { - -using common::PlatformResult; -using common::ErrorCode; -using common::TaskQueue; -using namespace common::tools; - -namespace { -const std::string kUuid = "uuid"; -const std::string kServiceUuid = "serviceUuid"; -const std::string kHandle = "handle"; -const std::string kAddress = "address"; - -const std::string kDescriptors = "descriptors"; -const std::string kBroadcast = "isBroadcast"; -const std::string kExtendedProperties = "hasExtendedProperties"; -const std::string kNotify = "isNotify"; -const std::string kIndication = "isIndication"; -const std::string kReadable = "isReadable"; -const std::string kSignedWrite = "isSignedWrite"; -const std::string kWritable = "isWritable"; -const std::string kWriteNoResponse = "isWriteNoResponse"; - -const std::string kOnValueChanged = "BluetoothGATTCharacteristicValueChangeListener"; - -bool IsProperty(int propertyBits, bt_gatt_property_e property) { - return (propertyBits & property) != 0; -} -} - -BluetoothGATTService::BluetoothGATTService(BluetoothInstance& instance) : instance_(instance) { - ScopeLogger(); -} - -BluetoothGATTService::~BluetoothGATTService() { - ScopeLogger(); - - for (auto it : gatt_characteristic_) { - // unregister callback, ignore errors - bt_gatt_client_unset_characteristic_value_changed_cb(it); - } - - for (auto it : gatt_clients_) { - LoggerD("destroying client for address: %s", it.first.c_str()); - bt_gatt_client_destroy(it.second); - } -} - -bool BluetoothGATTService::IsStillConnected(const std::string& address) { - auto it = gatt_clients_.find(address); - return gatt_clients_.end() != it; -} - -bt_gatt_client_h BluetoothGATTService::GetGattClient(const std::string& address) { - ScopeLogger(); - - bt_gatt_client_h client = nullptr; - - const auto it = gatt_clients_.find(address); - - if (gatt_clients_.end() == it) { - int ret = bt_gatt_client_create(address.c_str(), &client); - if (BT_ERROR_NONE != ret) { - LoggerE("Failed to create GATT client, error: %d", ret); - } else { - gatt_clients_.insert(std::make_pair(address, client)); - } - } else { - LoggerD("Client already created"); - client = it->second; - } - - return client; -} - -// this method should be used to inform this object that some device was disconnected -void BluetoothGATTService::TryDestroyClient(const std::string& address) { - ScopeLogger(); - auto it = gatt_clients_.find(address); - if (gatt_clients_.end() != it) { - LoggerD("destroying client for address: %s", it->first.c_str()); - bt_gatt_client_destroy(it->second); - gatt_clients_.erase(it); - } else { - LoggerD("Client for address: %s does not exist, no need for deletion", address.c_str()); - } -} - -PlatformResult BluetoothGATTService::GetSpecifiedGATTService(const std::string& address, - const UUID& uuid, - picojson::object* result) { - ScopeLogger(); - - bt_gatt_client_h client = GetGattClient(address); - - if (nullptr == client) { - return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Failed to create the GATT client's handle"); - } - - bt_gatt_h service = nullptr; - int ret = bt_gatt_client_get_service(client, uuid.uuid_128_bit.c_str(), &service); - if (BT_ERROR_NONE != ret) { - LoggerE("bt_gatt_client_get_service() error: %d", ret); - switch (ret) { - case BT_ERROR_NO_DATA: - return LogAndCreateResult( - ErrorCode::NOT_FOUND_ERR, "Service not found", - ("bt_gatt_client_get_service error: %d (%s)", ret, get_error_message(ret))); - - case BT_ERROR_INVALID_PARAMETER: - return LogAndCreateResult( - ErrorCode::NOT_FOUND_ERR, "Service UUID is invalid", - ("bt_gatt_client_get_service error: %d (%s)", ret, get_error_message(ret))); - - default: - return LogAndCreateResult( - ErrorCode::UNKNOWN_ERR, "Failed to get a service's GATT handle", - ("bt_gatt_client_get_service error: %d (%s)", ret, get_error_message(ret))); - } - } - - /* - * BACKWARD COMPATIBILITY - * - * BluetoothGATTService::uuid has always been set to source format in this - * function. - */ - result->insert(std::make_pair(kUuid, picojson::value(uuid.uuid_in_source_format))); - result->insert(std::make_pair(kServiceUuid, picojson::value(uuid.uuid_in_source_format))); - // handle is passed to upper layer because there is no need to delete it - result->insert(std::make_pair(kHandle, picojson::value((double)(long)service))); - // address is necessary to later check if device is still connected - result->insert(std::make_pair(kAddress, picojson::value(address))); - return PlatformResult(ErrorCode::NO_ERROR); -} - -void BluetoothGATTService::GetServices(const picojson::value& args, picojson::object& out) { - ScopeLogger(); - - bt_gatt_h handle = (bt_gatt_h) static_cast(args.get("handle").get()); - const std::string& address = args.get("address").get(); - - picojson::array array; - PlatformResult ret = GetServicesHelper(handle, address, &array); - if (ret.IsError()) { - LogAndReportError(ret, &out, ("Error while getting services")); - } else { - ReportSuccess(picojson::value(array), out); - } -} - -PlatformResult BluetoothGATTService::GetServicesHelper(bt_gatt_h handle, const std::string& address, - picojson::array* array) { - ScopeLogger(); - - if (!IsStillConnected(address)) { - return LogAndCreateResult(ErrorCode::INVALID_STATE_ERR, "Device is not connected", - ("Device with address %s is no longer connected", address.c_str())); - } - - int ret = bt_gatt_service_foreach_included_services( - handle, - [](int total, int index, bt_gatt_h gatt_handle, void* data) { - ScopeLogger( - "Entered into asynchronous function, argument in " - "bt_gatt_service_foreach_included_services"); - - picojson::value result = picojson::value{picojson::object{}}; - picojson::object& result_obj = result.get(); - - const auto uuid = UUID::createFromGatt(gatt_handle); - if (uuid) { - /* - * BACKWARD COMPATIBILITY - * - * UUID has always been set to source format in this function. - */ - result_obj.insert(std::make_pair(kUuid, picojson::value{uuid->uuid_in_source_format})); - result_obj.insert(std::make_pair(kServiceUuid, picojson::value{uuid->uuid_in_source_format})); - } else { - result_obj.insert(std::make_pair(kUuid, picojson::value{"0xFFFF"})); - result_obj.insert(std::make_pair(kServiceUuid, picojson::value{})); - } - - // handle is passed to upper layer because there is no need of deletion - result_obj.insert(std::make_pair(kHandle, picojson::value{(double)(long)gatt_handle})); - static_cast(data)->push_back(result); - return true; - }, - array); - if (BT_ERROR_NONE != ret) { - LoggerE("Failed bt_gatt_service_foreach_included_services() (%d)", ret); - return util::GetBluetoothError(ret, "Failed to set a service's GATT callback"); - } - - return PlatformResult(ErrorCode::NO_ERROR); -} - -void BluetoothGATTService::GetCharacteristics(const picojson::value& args, picojson::object& out) { - ScopeLogger(); - - bt_gatt_h handle = (bt_gatt_h) static_cast(args.get("handle").get()); - - const std::string& address = args.get("address").get(); - - picojson::array array; - PlatformResult ret = GetCharacteristicsHelper(handle, address, &array); - if (ret.IsError()) { - LogAndReportError(ret, &out, ("Error while getting characteristics")); - } else { - ReportSuccess(picojson::value(array), out); - } -} - -PlatformResult BluetoothGATTService::GetCharacteristicsHelper(bt_gatt_h handle, - const std::string& address, - picojson::array* array) { - ScopeLogger(); - - if (!IsStillConnected(address)) { - return LogAndCreateResult(ErrorCode::INVALID_STATE_ERR, "Device is not connected", - ("Device with address %s is no longer connected", address.c_str())); - } - - struct Data { - picojson::array* array; - PlatformResult* platform_res; - }; - - PlatformResult platform_result = PlatformResult(ErrorCode::NO_ERROR); - Data user_data = {array, &platform_result}; - - int ret = bt_gatt_service_foreach_characteristics( - handle, - [](int total, int index, bt_gatt_h gatt_handle, void* data) { - ScopeLogger( - "Entered into asynchronous function, bt_gatt_service_foreach_characteristics;" - " index: %d", index); - Data* user_data = static_cast(data); - picojson::array* array = user_data->array; - PlatformResult* platform_result = user_data->platform_res; - - picojson::value result = picojson::value(picojson::object()); - picojson::object& result_obj = result.get(); - - // handle is passed to upper layer because there is no need of deletion - result_obj.insert(std::make_pair(kHandle, picojson::value((double)(long)gatt_handle))); - - // descriptors - picojson::array& desc_array = - result_obj.insert(std::make_pair("descriptors", picojson::value(picojson::array()))) - .first->second.get(); - int ret = bt_gatt_characteristic_foreach_descriptors( - gatt_handle, - [](int total, int index, bt_gatt_h desc_handle, void* data) { - ScopeLogger( - "Entered into asynchronous function, bt_gatt_characteristic_foreach_descriptors;" - " index: %d", index); - picojson::array& desc_array = *(static_cast(data)); - - picojson::value desc = picojson::value(picojson::object()); - picojson::object& desc_obj = desc.get(); - - // handle is passed to upper layer because there is no need of deletion - desc_obj.insert(std::make_pair(kHandle, picojson::value((double)(long)desc_handle))); - - auto uuid = UUID::createFromGatt(desc_handle); - if (uuid) { - desc_obj.insert(std::make_pair(kUuid, picojson::value{uuid->ShortestPossibleFormat()})); - } else { - desc_obj.insert(std::make_pair(kUuid, picojson::value{})); - } - - desc_array.push_back(desc); - return true; - }, - static_cast(&desc_array)); - if (BT_ERROR_NONE != ret) { - *platform_result = util::GetBluetoothError(ret, "Failed to get descriptors"); - LoggerE("Failed bt_gatt_characteristic_foreach_descriptors() (%d)", ret); - return false; - } - - // other properties - int property_bits = 0; - int err = bt_gatt_characteristic_get_properties(gatt_handle, &property_bits); - if (BT_ERROR_NONE != err) { - LoggerE("Properties of characteristic couldn't be acquired"); - } - result_obj.insert(std::make_pair( - kBroadcast, picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_BROADCAST)))); - result_obj.insert(std::make_pair( - kReadable, picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_READ)))); - result_obj.insert(std::make_pair( - kWriteNoResponse, - picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_WRITE_WITHOUT_RESPONSE)))); - result_obj.insert(std::make_pair( - kWritable, picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_WRITE)))); - result_obj.insert(std::make_pair( - kNotify, picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_NOTIFY)))); - result_obj.insert(std::make_pair( - kIndication, picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_INDICATE)))); - result_obj.insert(std::make_pair( - kSignedWrite, picojson::value(IsProperty( - property_bits, BT_GATT_PROPERTY_AUTHENTICATED_SIGNED_WRITES)))); - result_obj.insert(std::make_pair( - kExtendedProperties, - picojson::value(IsProperty(property_bits, BT_GATT_PROPERTY_EXTENDED_PROPERTIES)))); - - auto uuid = UUID::createFromGatt(gatt_handle); - if (uuid) { - result_obj.insert(std::make_pair(kUuid, picojson::value{uuid->ShortestPossibleFormat()})); - } else { - LoggerW("bt_gatt_get_uuid error: %d (%s)", err, get_error_message(err)); - result_obj.insert(std::make_pair(kUuid, picojson::value{})); - } - - array->push_back(result); - return true; - }, - static_cast(&user_data)); - if (platform_result.IsError()) { - return platform_result; - } - if (BT_ERROR_NONE != ret) { - LoggerE("Failed (%d)", ret); - return util::GetBluetoothError(ret, "Failed while getting characteristic"); - } - - return PlatformResult(ErrorCode::NO_ERROR); -} - -void BluetoothGATTService::ReadValue(const picojson::value& args, picojson::object& out) { - ScopeLogger(); - CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin, - &out); - - const std::string& address = args.get("address").get(); - if (!IsStillConnected(address)) { - LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Device is not connected"), &out, - ("Device with address %s is no longer connected", address.c_str())); - return; - } - - const double callback_handle = util::GetAsyncCallbackHandle(args); - struct Data { - double callback_handle; - BluetoothGATTService* service; - }; - - Data* user_data = new Data{callback_handle, this}; - bt_gatt_h handle = (bt_gatt_h) static_cast(args.get("handle").get()); - - auto read_value = [](int result, bt_gatt_h handle, void* user_data) -> void { - ScopeLogger("Entered into asynchronous function, read_value"); - Data* data = static_cast(user_data); - double callback_handle = data->callback_handle; - BluetoothGATTService* service = data->service; - delete data; - - PlatformResult plarform_res = PlatformResult(ErrorCode::NO_ERROR); - - picojson::value byte_array = picojson::value(picojson::array()); - picojson::array& byte_array_obj = byte_array.get(); - - if (BT_ERROR_NONE != result) { - plarform_res = util::GetBluetoothError(result, "Error while reading value"); - } else { - char* value = nullptr; - int length = 0; - int ret = bt_gatt_get_value(handle, &value, &length); - if (BT_ERROR_NONE != ret) { - plarform_res = util::GetBluetoothError(ret, "Error while getting value"); - } else { - for (int i = 0; i < length; i++) { - byte_array_obj.push_back(picojson::value(std::to_string(value[i]))); - } - } - if (value) { - free(value); - value = nullptr; - } - } - - std::shared_ptr response = - std::shared_ptr(new picojson::value(picojson::object())); - if (plarform_res.IsSuccess()) { - ReportSuccess(byte_array, response->get()); - } else { - LogAndReportError(plarform_res, &response->get()); - } - TaskQueue::GetInstance().Async( - [service, callback_handle](const std::shared_ptr& response) { - service->instance_.SyncResponse(callback_handle, response); - }, - response); - }; - int ret = bt_gatt_client_read_value(handle, read_value, (void*)user_data); - if (BT_ERROR_NONE != ret) { - delete user_data; - user_data = nullptr; - LoggerE("Couldn't register callback for read value %d (%s)", ret, get_error_message(ret)); - } - ReportSuccess(out); -} - -void BluetoothGATTService::WriteValue(const picojson::value& args, picojson::object& out) { - ScopeLogger(); - CHECK_BACKWARD_COMPABILITY_PRIVILEGE_ACCESS(Privilege::kBluetooth, Privilege::kBluetoothAdmin, - &out); - - const std::string& address = args.get("address").get(); - if (!IsStillConnected(address)) { - LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Device is not connected"), &out, - ("Device with address %s is no longer connected", address.c_str())); - return; - } - - const double callback_handle = util::GetAsyncCallbackHandle(args); - const picojson::array& value_array = args.get("value").get(); - - int value_size = value_array.size(); - std::unique_ptr value_data(new char[value_size]); - for (int i = 0; i < value_size; ++i) { - value_data[i] = (int)value_array[i].get(); - } - - struct Data { - double callback_handle; - BluetoothGATTService* service; - }; - - bt_gatt_h handle = (bt_gatt_h) static_cast(args.get("handle").get()); - - auto write_value = [](int result, bt_gatt_h handle, void* user_data) -> void { - ScopeLogger("Entered into asynchronous function, write_value"); - Data* data = static_cast(user_data); - double callback_handle = data->callback_handle; - BluetoothGATTService* service = data->service; - delete data; - - PlatformResult ret = PlatformResult(ErrorCode::NO_ERROR); - if (BT_ERROR_NONE != result) { - ret = util::GetBluetoothError(result, "Error while getting value"); - } - - std::shared_ptr response = - std::shared_ptr(new picojson::value(picojson::object())); - if (ret.IsSuccess()) { - ReportSuccess(response->get()); - } else { - LogAndReportError(ret, &response->get()); - } - TaskQueue::GetInstance().Async( - [service, callback_handle](const std::shared_ptr& response) { - service->instance_.SyncResponse(callback_handle, response); - }, - response); - }; - - int ret = bt_gatt_set_value(handle, value_data.get(), value_size); - - if (BT_ERROR_NONE != ret) { - std::shared_ptr response = - std::shared_ptr(new picojson::value(picojson::object())); - LogAndReportError(util::GetBluetoothError(ret, "Failed to set value"), - &response->get(), - ("bt_gatt_set_value error: %d (%s)", ret, get_error_message(ret))); - TaskQueue::GetInstance().Async( - [this, callback_handle](const std::shared_ptr& response) { - instance_.SyncResponse(callback_handle, response); - }, - response); - } else { - Data* user_data = new Data{callback_handle, this}; - ret = bt_gatt_client_write_value(handle, write_value, user_data); - if (BT_ERROR_NONE != ret) { - delete user_data; - LoggerE("Couldn't register callback for write value %d (%s)", ret, get_error_message(ret)); - } - } - ReportSuccess(out); -} - -void BluetoothGATTService::AddValueChangeListener(const picojson::value& args, - picojson::object& out) { - ScopeLogger(); - const auto& address = args.get("address").get(); - if (!IsStillConnected(address)) { - LogAndReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR, "Device is not connected"), &out, - ("Device with address %s is no longer connected", address.c_str())); - return; - } - - bt_gatt_h handle = (bt_gatt_h) static_cast(args.get(kHandle).get()); - - int ret = bt_gatt_client_set_characteristic_value_changed_cb(handle, OnCharacteristicValueChanged, - this); - if (BT_ERROR_NONE != ret) { - LogAndReportError(util::GetBluetoothError(ret, "Failed to register listener"), &out, - ("bt_gatt_client_set_characteristic_value_changed_cb() failed with: %d (%s)", - ret, get_error_message(ret))); - } else { - gatt_characteristic_.push_back(handle); - ReportSuccess(out); - } -} - -void BluetoothGATTService::RemoveValueChangeListener(const picojson::value& args, - picojson::object& out) { - ScopeLogger(); - const auto& address = args.get("address").get(); - if (!IsStillConnected(address)) { - LoggerW("Device with address %s is no longer connected", address.c_str()); - } else { - bt_gatt_h handle = (bt_gatt_h) static_cast(args.get(kHandle).get()); - - int ret = bt_gatt_client_unset_characteristic_value_changed_cb(handle); - - if (BT_ERROR_NONE != ret) { - LoggerW("bt_gatt_client_unset_characteristic_value_changed_cb() failed with: %d (%s)", ret, - get_error_message(ret)); - } else { - gatt_characteristic_.erase( - std::remove(gatt_characteristic_.begin(), gatt_characteristic_.end(), handle), - gatt_characteristic_.end()); - } - } - ReportSuccess(out); -} - -common::PlatformResult BluetoothGATTService::GetServiceAllUuids(const std::string& address, - picojson::array* array) { - ScopeLogger(); - - bt_gatt_client_h client = GetGattClient(address); - - if (nullptr == client) { - return LogAndCreateResult(ErrorCode::UNKNOWN_ERR, "Unable to create client"); - } - - auto foreach_callback = [](int total, int index, bt_gatt_h gatt_handle, void* user_data) -> bool { - ScopeLogger("Entered into asynchronous function, foreach_callback, total: %d, index: %d", total, - index); - - auto& uuids = *static_cast(user_data); - auto uuid = UUID::createFromGatt(gatt_handle); - if (uuid) { - /* - * BACKWARD COMPATIBILITY - * - * In the past, this function has always trimmed UUIDs retrieved - * from native API to 16 bit format. UUIDs that were not created - * from 16 bit UUID and BASE_UUID were converted to invalid values. - * - * We return UUIDs in shortest possible format to comply with past - * behaviour when possible. If the UUID is not convertible - * to 16 bit UUID, we return a longer form. - */ - uuids.push_back(picojson::value{uuid->ShortestPossibleFormat()}); - } else { - LoggerE("Couldn't get UUID from bt_gatt_h"); - } - - return true; - }; - - int ret = bt_gatt_client_foreach_services(client, foreach_callback, array); - - if (BT_ERROR_NONE == ret) { - return PlatformResult(ErrorCode::NO_ERROR); - } else { - return util::GetBluetoothError(ret, "Failed to get UUIDS"); - } -} - -void BluetoothGATTService::OnCharacteristicValueChanged(bt_gatt_h characteristic, char* value, - int length, void* user_data) { - ScopeLogger("characteristic: [%p], len: [%d], user_data: [%p]", characteristic, length, - user_data); - - auto service = static_cast(user_data); - - if (!service) { - LoggerE("user_data is NULL"); - return; - } - - picojson::value result = picojson::value(picojson::object()); - picojson::object& result_obj = result.get(); - - result_obj.insert(std::make_pair(kHandle, picojson::value((double)(long)characteristic))); - - picojson::value byte_array = picojson::value(picojson::array()); - picojson::array& byte_array_obj = byte_array.get(); - - for (int i = 0; i < length; ++i) { - byte_array_obj.push_back(picojson::value(std::to_string(value[i]))); - } - - ReportSuccess(byte_array, result_obj); - - service->instance_.FireEvent(kOnValueChanged, result); -} - -} // namespace bluetooth -} // namespace extension diff --git a/src/bluetooth/bluetooth_gatt_service.h b/src/bluetooth/bluetooth_gatt_service.h deleted file mode 100644 index d4e5446f..00000000 --- a/src/bluetooth/bluetooth_gatt_service.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - * Copyright (c) 2015 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_SERVICE_H_ -#define BLUETOOTH_BLUETOOTH_GATT_SERVICE_H_ - -#include - -#include - -#include "bluetooth/uuid.h" -#include "common/picojson.h" -#include "common/platform_result.h" - -namespace extension { -namespace bluetooth { - -class BluetoothInstance; - -class BluetoothGATTService { - public: - BluetoothGATTService(BluetoothInstance& instance); - ~BluetoothGATTService(); - - common::PlatformResult GetSpecifiedGATTService(const std::string& address, const UUID& uuid, - picojson::object* result); - - void TryDestroyClient(const std::string& address); - void GetServices(const picojson::value& data, picojson::object& out); - void GetCharacteristics(const picojson::value& data, picojson::object& out); - void ReadValue(const picojson::value& args, picojson::object& out); - void WriteValue(const picojson::value& args, picojson::object& out); - void AddValueChangeListener(const picojson::value& args, picojson::object& out); - void RemoveValueChangeListener(const picojson::value& args, picojson::object& out); - - common::PlatformResult GetServiceAllUuids(const std::string& address, picojson::array* array); - - private: - bool IsStillConnected(const std::string& address); - - bt_gatt_client_h GetGattClient(const std::string& address); - - common::PlatformResult GetServicesHelper(bt_gatt_h handle, const std::string& address, - picojson::array* array); - common::PlatformResult GetCharacteristicsHelper(bt_gatt_h handle, const std::string& address, - picojson::array* array); - - static void OnCharacteristicValueChanged(bt_gatt_h characteristic, char* value, int len, - void* user_data); - - std::map gatt_clients_; - std::vector gatt_characteristic_; - - BluetoothInstance& instance_; -}; - -} // namespace bluetooth -} // namespace extension - -#endif // BLUETOOTH_BLUETOOTH_GATT_SERVICE_H_ diff --git a/src/bluetooth/bluetooth_instance.cc b/src/bluetooth/bluetooth_instance.cc index 2ff079ea..91fb4885 100644 --- a/src/bluetooth/bluetooth_instance.cc +++ b/src/bluetooth/bluetooth_instance.cc @@ -35,8 +35,8 @@ BluetoothInstance::BluetoothInstance() bluetooth_service_handler_(bluetooth_adapter_), bluetooth_socket_(bluetooth_adapter_), bluetooth_le_adapter_(*this), - bluetooth_gatt_service_(*this), - bluetooth_le_device_(*this, bluetooth_gatt_service_), + bluetooth_gatt_client_service_(*this), + bluetooth_le_device_(*this, bluetooth_gatt_client_service_), worker(), bluetooth_gatt_server_(*this) { ScopeLogger(); @@ -93,12 +93,12 @@ BluetoothInstance::BluetoothInstance() REGISTER_METHOD(BluetoothLEDeviceRemoveConnectStateChangeListener); REGISTER_METHOD(BluetoothLEDeviceGetServiceAllUuids); - REGISTER_METHOD(BluetoothGATTServiceGetServices); - REGISTER_METHOD(BluetoothGATTServiceGetCharacteristics); - REGISTER_METHOD(BluetoothGATTServiceReadValue); - REGISTER_METHOD(BluetoothGATTServiceWriteValue); - REGISTER_METHOD(BluetoothGATTServiceAddValueChangeListener); - REGISTER_METHOD(BluetoothGATTServiceRemoveValueChangeListener); + REGISTER_METHOD(BluetoothGATTClientServiceGetServices); + REGISTER_METHOD(BluetoothGATTClientServiceGetCharacteristics); + REGISTER_METHOD(BluetoothGATTClientServiceReadValue); + REGISTER_METHOD(BluetoothGATTClientServiceWriteValue); + REGISTER_METHOD(BluetoothGATTClientServiceAddValueChangeListener); + REGISTER_METHOD(BluetoothGATTClientServiceRemoveValueChangeListener); REGISTER_METHOD(BluetoothGATTServerStart); REGISTER_METHOD(BluetoothGATTServerStop); @@ -406,40 +406,40 @@ void BluetoothInstance::BluetoothLEDeviceGetServiceAllUuids(const picojson::valu bluetooth_le_device_.GetServiceAllUuids(args, out); } -void BluetoothInstance::BluetoothGATTServiceGetServices(const picojson::value& args, +void BluetoothInstance::BluetoothGATTClientServiceGetServices(const picojson::value& args, picojson::object& out) { ScopeLogger(); - bluetooth_gatt_service_.GetServices(args, out); + bluetooth_gatt_client_service_.GetServices(args, out); } -void BluetoothInstance::BluetoothGATTServiceGetCharacteristics(const picojson::value& args, +void BluetoothInstance::BluetoothGATTClientServiceGetCharacteristics(const picojson::value& args, picojson::object& out) { ScopeLogger(); - bluetooth_gatt_service_.GetCharacteristics(args, out); + bluetooth_gatt_client_service_.GetCharacteristics(args, out); } -void BluetoothInstance::BluetoothGATTServiceReadValue(const picojson::value& args, +void BluetoothInstance::BluetoothGATTClientServiceReadValue(const picojson::value& args, picojson::object& out) { ScopeLogger(); - bluetooth_gatt_service_.ReadValue(args, out); + bluetooth_gatt_client_service_.ReadValue(args, out); } -void BluetoothInstance::BluetoothGATTServiceWriteValue(const picojson::value& args, +void BluetoothInstance::BluetoothGATTClientServiceWriteValue(const picojson::value& args, picojson::object& out) { ScopeLogger(); - bluetooth_gatt_service_.WriteValue(args, out); + bluetooth_gatt_client_service_.WriteValue(args, out); } -void BluetoothInstance::BluetoothGATTServiceAddValueChangeListener(const picojson::value& args, +void BluetoothInstance::BluetoothGATTClientServiceAddValueChangeListener(const picojson::value& args, picojson::object& out) { ScopeLogger(); - bluetooth_gatt_service_.AddValueChangeListener(args, out); + bluetooth_gatt_client_service_.AddValueChangeListener(args, out); } -void BluetoothInstance::BluetoothGATTServiceRemoveValueChangeListener(const picojson::value& args, +void BluetoothInstance::BluetoothGATTClientServiceRemoveValueChangeListener(const picojson::value& args, picojson::object& out) { ScopeLogger(); - bluetooth_gatt_service_.RemoveValueChangeListener(args, out); + bluetooth_gatt_client_service_.RemoveValueChangeListener(args, out); } void BluetoothInstance::BluetoothGATTServerStart(const picojson::value& args, diff --git a/src/bluetooth/bluetooth_instance.h b/src/bluetooth/bluetooth_instance.h index 0ee235df..48ac8d0a 100644 --- a/src/bluetooth/bluetooth_instance.h +++ b/src/bluetooth/bluetooth_instance.h @@ -22,7 +22,7 @@ #include "bluetooth/bluetooth_adapter.h" #include "bluetooth/bluetooth_device.h" #include "bluetooth/bluetooth_gatt_server.h" -#include "bluetooth/bluetooth_gatt_service.h" +#include "bluetooth/bluetooth_gatt_client_service.h" #include "bluetooth/bluetooth_health_application.h" #include "bluetooth/bluetooth_health_channel.h" #include "bluetooth/bluetooth_health_profile_handler.h" @@ -100,13 +100,13 @@ class BluetoothInstance : public common::ParsedInstance { picojson::object& out); void BluetoothLEDeviceGetServiceAllUuids(const picojson::value& args, picojson::object& out); - void BluetoothGATTServiceGetServices(const picojson::value& args, picojson::object& out); - void BluetoothGATTServiceGetCharacteristics(const picojson::value& args, picojson::object& out); - void BluetoothGATTServiceReadValue(const picojson::value& args, picojson::object& out); - void BluetoothGATTServiceWriteValue(const picojson::value& args, picojson::object& out); - void BluetoothGATTServiceAddValueChangeListener(const picojson::value& args, + void BluetoothGATTClientServiceGetServices(const picojson::value& args, picojson::object& out); + void BluetoothGATTClientServiceGetCharacteristics(const picojson::value& args, picojson::object& out); + void BluetoothGATTClientServiceReadValue(const picojson::value& args, picojson::object& out); + void BluetoothGATTClientServiceWriteValue(const picojson::value& args, picojson::object& out); + void BluetoothGATTClientServiceAddValueChangeListener(const picojson::value& args, picojson::object& out); - void BluetoothGATTServiceRemoveValueChangeListener(const picojson::value& args, + void BluetoothGATTClientServiceRemoveValueChangeListener(const picojson::value& args, picojson::object& out); void BluetoothGATTServerStart(const picojson::value& args, picojson::object& out); void BluetoothGATTServerStop(const picojson::value& args, picojson::object& out); @@ -119,7 +119,7 @@ class BluetoothInstance : public common::ParsedInstance { BluetoothServiceHandler bluetooth_service_handler_; BluetoothSocket bluetooth_socket_; BluetoothLEAdapter bluetooth_le_adapter_; - BluetoothGATTService bluetooth_gatt_service_; + BluetoothGATTClientService bluetooth_gatt_client_service_; BluetoothLEDevice bluetooth_le_device_; common::Worker worker; // If all operations on bluetooth_gatt_server_ will be done by the worker, diff --git a/src/bluetooth/bluetooth_le_device.cc b/src/bluetooth/bluetooth_le_device.cc index 413a3059..bbcf715f 100644 --- a/src/bluetooth/bluetooth_le_device.cc +++ b/src/bluetooth/bluetooth_le_device.cc @@ -55,7 +55,7 @@ const std::string kOnDisconnected = "ondisconnected"; const std::string kConnectChangeEvent = "BluetoothLEConnectChangeCallback"; } -BluetoothLEDevice::BluetoothLEDevice(BluetoothInstance& instance, BluetoothGATTService& service) +BluetoothLEDevice::BluetoothLEDevice(BluetoothInstance& instance, BluetoothGATTClientService& service) : instance_(instance), service_(service), is_listener_set_(false) { ScopeLogger(); int ret = bt_gatt_set_connection_state_changed_cb(GattConnectionState, this); @@ -393,7 +393,7 @@ void BluetoothLEDevice::GetService(const picojson::value& data, picojson::object picojson::value response = picojson::value(picojson::object()); picojson::object* data_obj = &response.get(); - PlatformResult result = service_.GetSpecifiedGATTService(address, *uuid, data_obj); + PlatformResult result = service_.GetSpecifiedGATTClient(address, *uuid, data_obj); if (result.IsError()) { LogAndReportError(result, &out); diff --git a/src/bluetooth/bluetooth_le_device.h b/src/bluetooth/bluetooth_le_device.h index 25d0f5fc..99f42aae 100644 --- a/src/bluetooth/bluetooth_le_device.h +++ b/src/bluetooth/bluetooth_le_device.h @@ -22,7 +22,7 @@ #include #include -#include "bluetooth/bluetooth_gatt_service.h" +#include "bluetooth/bluetooth_gatt_client_service.h" #include "bluetooth/uuid.h" #include "common/picojson.h" @@ -35,7 +35,7 @@ class BluetoothInstance; class BluetoothLEDevice { public: - explicit BluetoothLEDevice(BluetoothInstance& instance, BluetoothGATTService& service); + explicit BluetoothLEDevice(BluetoothInstance& instance, BluetoothGATTClientService& service); ~BluetoothLEDevice(); void Connect(const picojson::value& data, picojson::object& out); @@ -60,7 +60,7 @@ class BluetoothLEDevice { void CleanClientInfo(const char* remote_address); void TriggerConnectStateChangeListener(const char* remote_address, bool connected); BluetoothInstance& instance_; - BluetoothGATTService& service_; + BluetoothGATTClientService& service_; std::unordered_map connecting_; bool is_listener_set_; std::set is_connected_; diff --git a/src/bluetooth/uuid.h b/src/bluetooth/uuid.h index ac08c153..35f30d9b 100644 --- a/src/bluetooth/uuid.h +++ b/src/bluetooth/uuid.h @@ -90,7 +90,7 @@ struct UUID { * work in the following manner: * 1. the user passes them a UUID, in any acceptable format, e.g.: "aBcD" * 2. the function performs requested operations using the passed UUID - * 3. the function creates an object, e.g. BlueoothGATTService, with the UUID + * 3. the function creates an object, e.g. BluetoothGATTClientService, with the UUID * passed by the user. * * As user may expect an identical UUID in the created object, identical to