'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',
var address_ = address || data.address;
function servicesGetter() {
var services = [];
- var result = native.callSync('BluetoothGATTServiceGetServices', {
+ var result = native.callSync('BluetoothGATTClientServiceGetServices', {
handle: handle_,
address: address_
});
}
function characteristicsGetter() {
var characteristics = [];
- var result = native.callSync('BluetoothGATTServiceGetCharacteristics', {
+ var result = native.callSync('BluetoothGATTClientServiceGetCharacteristics', {
handle: handle_,
uuid: serviceUuid_,
address: 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);
address: address_
};
- var result = native.call('BluetoothGATTServiceWriteValue', callArgs, callback);
+ var result = native.call('BluetoothGATTClientServiceWriteValue', callArgs, callback);
if (native.isFailure(result)) {
throw native.getErrorObject(result);
function(listener, event) {
listener(event);
},
- 'BluetoothGATTServiceAddValueChangeListener',
- 'BluetoothGATTServiceRemoveValueChangeListener',
+ 'BluetoothGATTClientServiceAddValueChangeListener',
+ 'BluetoothGATTClientServiceRemoveValueChangeListener',
true
);
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);
address: address_
};
- var result = native.call('BluetoothGATTServiceWriteValue', callArgs, callback);
+ var result = native.call('BluetoothGATTClientServiceWriteValue', callArgs, callback);
if (native.isFailure(result)) {
throw native.getErrorObject(result);
--- /dev/null
+/*
+ * 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 <sstream>
+
+#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<long>(args.get("handle").get<double>());
+ const std::string& address = args.get("address").get<std::string>();
+
+ 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<picojson::object>();
+
+ 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<picojson::array*>(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<long>(args.get("handle").get<double>());
+
+ const std::string& address = args.get("address").get<std::string>();
+
+ 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*>(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<picojson::object>();
+
+ // 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<picojson::array>();
+ 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<picojson::array*>(data));
+
+ picojson::value desc = picojson::value(picojson::object());
+ picojson::object& desc_obj = desc.get<picojson::object>();
+
+ // 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<void*>(&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<void*>(&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<std::string>();
+ 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<long>(args.get("handle").get<double>());
+
+ auto read_value = [](int result, bt_gatt_h handle, void* user_data) -> void {
+ ScopeLogger("Entered into asynchronous function, read_value");
+ Data* data = static_cast<Data*>(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<picojson::array>();
+
+ 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<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+ if (plarform_res.IsSuccess()) {
+ ReportSuccess(byte_array, response->get<picojson::object>());
+ } else {
+ LogAndReportError(plarform_res, &response->get<picojson::object>());
+ }
+ TaskQueue::GetInstance().Async<picojson::value>(
+ [service, callback_handle](const std::shared_ptr<picojson::value>& 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<std::string>();
+ 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<picojson::array>();
+
+ int value_size = value_array.size();
+ std::unique_ptr<char[]> value_data(new char[value_size]);
+ for (int i = 0; i < value_size; ++i) {
+ value_data[i] = (int)value_array[i].get<double>();
+ }
+
+ struct Data {
+ double callback_handle;
+ BluetoothGATTClientService* service;
+ };
+
+ bt_gatt_h handle = (bt_gatt_h) static_cast<long>(args.get("handle").get<double>());
+
+ auto write_value = [](int result, bt_gatt_h handle, void* user_data) -> void {
+ ScopeLogger("Entered into asynchronous function, write_value");
+ Data* data = static_cast<Data*>(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<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+ if (ret.IsSuccess()) {
+ ReportSuccess(response->get<picojson::object>());
+ } else {
+ LogAndReportError(ret, &response->get<picojson::object>());
+ }
+ TaskQueue::GetInstance().Async<picojson::value>(
+ [service, callback_handle](const std::shared_ptr<picojson::value>& 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<picojson::value> response =
+ std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+ LogAndReportError(util::GetBluetoothError(ret, "Failed to set value"),
+ &response->get<picojson::object>(),
+ ("bt_gatt_set_value error: %d (%s)", ret, get_error_message(ret)));
+ TaskQueue::GetInstance().Async<picojson::value>(
+ [this, callback_handle](const std::shared_ptr<picojson::value>& 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<std::string>();
+ 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<long>(args.get(kHandle).get<double>());
+
+ 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<std::string>();
+ 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<long>(args.get(kHandle).get<double>());
+
+ 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<picojson::array*>(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<BluetoothGATTClientService*>(user_data);
+
+ if (!service) {
+ LoggerE("user_data is NULL");
+ return;
+ }
+
+ picojson::value result = picojson::value(picojson::object());
+ picojson::object& result_obj = result.get<picojson::object>();
+
+ 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<picojson::array>();
+
+ 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
--- /dev/null
+/*
+ * 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 <map>
+
+#include <bluetooth.h>
+
+#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<std::string, bt_gatt_client_h> gatt_clients_;
+ std::vector<bt_gatt_h> gatt_characteristic_;
+
+ BluetoothInstance& instance_;
+};
+
+} // namespace bluetooth
+} // namespace extension
+
+#endif // BLUETOOTH_BLUETOOTH_GATT_CLIENT_SERVICE_H_
+++ /dev/null
-/*
- * 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 <sstream>
-
-#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<long>(args.get("handle").get<double>());
- const std::string& address = args.get("address").get<std::string>();
-
- 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<picojson::object>();
-
- 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<picojson::array*>(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<long>(args.get("handle").get<double>());
-
- const std::string& address = args.get("address").get<std::string>();
-
- 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*>(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<picojson::object>();
-
- // 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<picojson::array>();
- 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<picojson::array*>(data));
-
- picojson::value desc = picojson::value(picojson::object());
- picojson::object& desc_obj = desc.get<picojson::object>();
-
- // 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<void*>(&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<void*>(&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<std::string>();
- 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<long>(args.get("handle").get<double>());
-
- auto read_value = [](int result, bt_gatt_h handle, void* user_data) -> void {
- ScopeLogger("Entered into asynchronous function, read_value");
- Data* data = static_cast<Data*>(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<picojson::array>();
-
- 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<picojson::value> response =
- std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
- if (plarform_res.IsSuccess()) {
- ReportSuccess(byte_array, response->get<picojson::object>());
- } else {
- LogAndReportError(plarform_res, &response->get<picojson::object>());
- }
- TaskQueue::GetInstance().Async<picojson::value>(
- [service, callback_handle](const std::shared_ptr<picojson::value>& 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<std::string>();
- 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<picojson::array>();
-
- int value_size = value_array.size();
- std::unique_ptr<char[]> value_data(new char[value_size]);
- for (int i = 0; i < value_size; ++i) {
- value_data[i] = (int)value_array[i].get<double>();
- }
-
- struct Data {
- double callback_handle;
- BluetoothGATTService* service;
- };
-
- bt_gatt_h handle = (bt_gatt_h) static_cast<long>(args.get("handle").get<double>());
-
- auto write_value = [](int result, bt_gatt_h handle, void* user_data) -> void {
- ScopeLogger("Entered into asynchronous function, write_value");
- Data* data = static_cast<Data*>(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<picojson::value> response =
- std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
- if (ret.IsSuccess()) {
- ReportSuccess(response->get<picojson::object>());
- } else {
- LogAndReportError(ret, &response->get<picojson::object>());
- }
- TaskQueue::GetInstance().Async<picojson::value>(
- [service, callback_handle](const std::shared_ptr<picojson::value>& 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<picojson::value> response =
- std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
- LogAndReportError(util::GetBluetoothError(ret, "Failed to set value"),
- &response->get<picojson::object>(),
- ("bt_gatt_set_value error: %d (%s)", ret, get_error_message(ret)));
- TaskQueue::GetInstance().Async<picojson::value>(
- [this, callback_handle](const std::shared_ptr<picojson::value>& 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<std::string>();
- 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<long>(args.get(kHandle).get<double>());
-
- 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<std::string>();
- 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<long>(args.get(kHandle).get<double>());
-
- 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<picojson::array*>(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<BluetoothGATTService*>(user_data);
-
- if (!service) {
- LoggerE("user_data is NULL");
- return;
- }
-
- picojson::value result = picojson::value(picojson::object());
- picojson::object& result_obj = result.get<picojson::object>();
-
- 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<picojson::array>();
-
- 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
+++ /dev/null
-/*
- * 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 <map>
-
-#include <bluetooth.h>
-
-#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<std::string, bt_gatt_client_h> gatt_clients_;
- std::vector<bt_gatt_h> gatt_characteristic_;
-
- BluetoothInstance& instance_;
-};
-
-} // namespace bluetooth
-} // namespace extension
-
-#endif // BLUETOOTH_BLUETOOTH_GATT_SERVICE_H_
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();
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);
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,
#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"
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);
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,
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);
picojson::value response = picojson::value(picojson::object());
picojson::object* data_obj = &response.get<picojson::object>();
- PlatformResult result = service_.GetSpecifiedGATTService(address, *uuid, data_obj);
+ PlatformResult result = service_.GetSpecifiedGATTClient(address, *uuid, data_obj);
if (result.IsError()) {
LogAndReportError(result, &out);
#include <set>
#include <unordered_map>
-#include "bluetooth/bluetooth_gatt_service.h"
+#include "bluetooth/bluetooth_gatt_client_service.h"
#include "bluetooth/uuid.h"
#include "common/picojson.h"
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);
void CleanClientInfo(const char* remote_address);
void TriggerConnectStateChangeListener(const char* remote_address, bool connected);
BluetoothInstance& instance_;
- BluetoothGATTService& service_;
+ BluetoothGATTClientService& service_;
std::unordered_map<std::string, double> connecting_;
bool is_listener_set_;
std::set<std::string> is_connected_;
* 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