#include "bluetooth_internal.h"
#include "common/converter.h"
+#include "common/extension.h"
#include "common/logger.h"
#include "common/platform_result.h"
-#include "common/extension.h"
#include "common/task-queue.h"
+#include "common/tools.h"
#include "bluetooth/bluetooth_class.h"
#include "bluetooth/bluetooth_device.h"
data_obj->insert(std::make_pair(kData, picojson::value(adapter->discovered_devices_)));
- //TODO Consider if all events during scanning shouldn't be called asynchronously
adapter->user_request_list_[DISCOVER_DEVICES] = false;
adapter->instance_.FireEvent(kAdapterDiscoverSuccessEvent, value);
}
is_powered_(false),
is_initialized_(false),
user_request_list_(),
+ user_request_callback_(),
+ requested_powered_(),
+ requested_visibility_(),
instance_(instance)
{
LoggerD("Entered");
}
if (ret.IsSuccess()) {
- const void* t_param[] = { this, &ret, &new_powered, &callback_handle };
+ struct UserData {
+ BluetoothAdapter* adapter;
+ double callback_handle;
+ };
+
+ UserData* user_data = new UserData{ this, callback_handle };
err = app_control_send_launch_request(service, [](
app_control_h request, app_control_h reply,
app_control_result_e r, void* user_data) {
+ LoggerD("app_control_send_launch_request() callback");
- BluetoothAdapter* self = static_cast<BluetoothAdapter*>(((void**) user_data)[0]);
- PlatformResult* p_ret = static_cast<PlatformResult*>(((void**) user_data)[1]);
- bool* p_new_powered = static_cast<bool*>(((void**) user_data)[2]);
- double* p_callback_handle = static_cast<double*>(((void**) user_data)[3]);
+ UserData* data = static_cast<UserData*>(user_data);
char* result = nullptr;
app_control_get_extra_data(reply, "result", &result);
- LoggerD("bt onoff: %s", result);
- if (strcmp(result, "success") == 0) {
- self->requested_powered_ = *p_new_powered;
- self->user_request_list_[SET_POWERED] = true;
- self->user_request_callback_[SET_POWERED] = *p_callback_handle;
+ if (result && strcmp(result, "success") == 0) {
+ LoggerD("bt onoff: %s", result);
+ free(result);
} else {
LoggerE("app control setPowered failed");
- *p_ret = PlatformResult(ErrorCode::UNKNOWN_ERR, "app control setPowered failed");
+ data->adapter->instance_.AsyncResponse(data->callback_handle, PlatformResult(ErrorCode::UNKNOWN_ERR, "app control setPowered failed"));
}
- }, t_param);
+
+ delete data;
+ }, user_data);
if (err != APP_CONTROL_ERROR_NONE) {
LoggerE("app control set launch request failed: %d", err);
ret = PlatformResult(ErrorCode::UNKNOWN_ERR, "app control set launch request failed");
+ } else {
+ this->requested_powered_ = new_powered;
+ this->user_request_list_[SET_POWERED] = true;
+ this->user_request_callback_[SET_POWERED] = callback_handle;
}
}
LoggerE("app control destroy failed: %d", err);
ret = PlatformResult(ErrorCode::UNKNOWN_ERR, "app control destroy failed");
}
+
+ if (!ret) {
+ instance_.AsyncResponse(callback_handle, ret);
+ }
#else
this->requested_powered_ = new_powered;
this->user_request_list_[SET_POWERED] = true;
} else {
bt_adapter_disable();
}
- return;
#endif
+ } else {
+ instance_.AsyncResponse(callback_handle, ret);
}
-
- instance_.AsyncResponse(callback_handle, ret);
}
void BluetoothAdapter::SetVisible(const picojson::value& data, picojson::object& out) {
instance_.SyncResponse(callback_handle, response);
};
+ auto queue_data = std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+
TaskQueue::GetInstance().Queue<picojson::value>(
get_known_devices,
get_known_devices_response,
- std::shared_ptr<picojson::value>(new picojson::value(picojson::object())));
+ queue_data);
ReportSuccess(out);
}
instance_.SyncResponse(callback_handle, response);
};
+ auto queue_data = std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+
TaskQueue::GetInstance().Queue<picojson::value>(
get_device,
get_device_response,
- std::shared_ptr<picojson::value>(new picojson::value(picojson::object())));
+ queue_data);
ReportSuccess(out);
}
instance_.SyncResponse(callback_handle, response);
};
+ auto queue_data = std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+
TaskQueue::GetInstance().Queue<picojson::value>(
rfcomm,
rfcomm_response,
- std::shared_ptr<picojson::value>(new picojson::value(picojson::object())));
+ queue_data);
ReportSuccess(out);
}
}
}
- if (registered_uuids_.size() == 0 &&
- connection_requests_.size() == 0 &&
- connected_sockets_.size() == 0) {
+ if (registered_uuids_.empty() &&
+ connection_requests_.empty() &&
+ connected_sockets_.empty()) {
bt_socket_unset_connection_state_changed_cb();
}
} else if (result.IsSuccess()){
return;
}
- if (object->connected_sockets_.size() == 0) {
+ if (object->connected_sockets_.empty()) {
bt_socket_unset_data_received_cb();
}
- if (object->registered_uuids_.size() == 0 &&
- object->connection_requests_.size() == 0 &&
- object->connected_sockets_.size() == 0) {
+ if (object->registered_uuids_.empty() &&
+ object->connection_requests_.empty() &&
+ object->connected_sockets_.empty()) {
bt_socket_unset_connection_state_changed_cb();
}
}
return serviceData_;
},
set: function(v) {
- if (T.isNull(v)) {
- serviceData_ = v;
- } else if (T.isArray(v)) {
- for (var i = 0; i < v.length; ++i) {
- if (!(v[i] instanceof tizen.BluetoothLEServiceData)) {
- return;
- }
- }
+ if (T.isNull(v) || (v instanceof tizen.BluetoothLEServiceData)) {
serviceData_ = v;
}
}
}
// serviceData
- if (T.isNull(dict.serviceData)) {
- o.serviceData = dict.serviceData;
- } else if (T.isArray(dict.serviceData)) {
- for (var i = 0; i < dict.serviceData.length; ++i) {
- if (!(dict.serviceData[i] instanceof tizen.BluetoothLEServiceData)) {
- return;
- }
- }
+ if (T.isNull(dict.serviceData) || dict.serviceData instanceof tizen.BluetoothLEServiceData) {
o.serviceData = dict.serviceData;
} else if (!T.isUndefined(dict.serviceData)) {
return;
//class BluetoothLEDevice ////////////////////////////////////////////////////
var BluetoothLEDevice = function(data) {
-
- var address = "", name = "", txpowerLevel = null, appearance = null, uuids = [],
- solicitationuuids = [], serviceData = [], manufacturerData = null;
+ var address = "", name = null, txpowerlevel = null, appearance = null, uuids = null,
+ solicitationuuids = null, serviceData = null, manufacturerData = null;
if (data) {
- address = data.address;
- name = data.name;
- txpowerLevel = data.txpowerLevel;
- appearance = data.appearance;
- uuids = data.uuids;
- solicitationuuids = data.solicitationuuids;
+ address = data.address;
+ name = data.name || null;
+ txpowerlevel = data.txpowerlevel || null;
+ appearance = data.appearance || null;
+ uuids = data.uuids || null;
+ solicitationuuids = data.solicitationuuids || null;
+ if (data.serviceData) {
data.serviceData.forEach(function(d) {
serviceData.push(new tizen.BluetoothLEServiceData(d));
});
+ }
+ if (data.manufacturerData) {
manufacturerData = new tizen.BluetoothLEManufacturerData(data.manufacturerData);
+ }
}
Object.defineProperties(this, {
address : {value: address, writable: false, enumerable: true},
name : {value: name, writable: false, enumerable: true},
- txpowerLevel : {value: txpowerLevel, writable: false, enumerable: true},
+ txpowerlevel : {value: txpowerlevel, writable: false, enumerable: true},
appearance : {value: appearance, writable: false, enumerable: true},
uuids : {
enumerable: true,
set : function(){},
- get : function(){ return uuids.slice(); }
+ get : function(){
+ var service_uuids = uuids ? uuids.slice() : null;
+ return service_uuids;
+ }
},
solicitationuuids : {
enumerable: true,
set : function(){},
- get : function(){ return solicitationuuids.slice(); }
+ get : function(){ return solicitationuuids ? solicitationuuids.slice() : null; }
},
serviceData : {
enumerable: true,
set : function(){},
- get : function(){ return serviceData.slice(); }
+ get : function(){ return serviceData ? serviceData.slice() : null; }
},
manufacturerData : {
value: manufacturerData,
native.callIfPossible(args.successCallback);
}
};
-
+ // Errors are handled by error callback
native.call('BluetoothLEDevice_connect', {address : this.address}, callback);
};
nullable : true
}
]);
- var callback = function(result) {
+ var callback = function(result) {
if (native.isFailure(result)) {
native.callIfPossible(args.errorCallback, native.getErrorObject(result));
} else {
}
};
- native.call('BluetoothLEDevice_disconnect', {address : this.address}, callback);
+ var result = native.call('BluetoothLEDevice_disconnect', {address : this.address}, callback);
+ if (native.isFailure(result)) {
+ throw native.getErrorObject(result);
+ }
};
BluetoothLEDevice.prototype.getService = function() {
if (native.isFailure(result)) {
throw native.getErrorObject(result);
} else {
- return BluetoothGATTService(native.getResultObject(result));
+ return new BluetoothGATTService(native.getResultObject(result));
}
};
}
};
- // native.call does not inform if call results in failure
- // TODO: what to do in this case?
+ // The native function BluetoothDevice_connectToServiceByUUID always returns success
+ // Errors are handled by error callback
native.call('BluetoothDevice_connectToServiceByUUID', callArgs, callback);
};
};
// native.call does not inform if call results in failure
- // TODO: what to do in this case?
+ // Errors are handled by error callback
native.call('BluetoothServiceHandler_unregister', callArgs, callback);
_bluetoothServiceListeners.removeListener(this.uuid);
};
// native.call does not inform if call results in failure
- // TODO: what to do in this case?
+ // Errors are handled by error callback
native.call('BluetoothHealthApplication_unregister', callArgs, callback);
_bluetoothHealthApplicationListeners.removeListener(this._id);
};
// native.call does not inform if call results in failure
- // TODO: what to do in this case?
+ // Errors are handled by error callback
native.call('BluetoothHealthProfileHandler_registerSinkApp', callArgs, callback);
};
};
// native.call does not inform if call results in failure
- // TODO: what to do in this case?
+ // Errors are handled by error callback
native.call('BluetoothHealthProfileHandler_connectToSource', callArgs, callback);
};
xwalk.utils.checkPrivilegeAccess4Ver("2.4", Privilege.BLUETOOTH, Privilege.BLUETOOTH_ADMIN);
- // TODO: when should we call _bleAdvertiseListener.removeListener()?
-
+ _bleAdvertiseListener.removeListener();
var result = native.callSync('BluetoothLEAdapter_stopAdvertise', {});
if (native.isFailure(result)) {
- _bleAdvertiseListener.removeListener();
throw native.getErrorObject(result);
}
};
function servicesGetter() {
var services = [];
var result = native.callSync('BluetoothGATTService_getServices',
- {handle: handle_, uuid: uuid_, address : address_});
+ {handle: handle_, address : address_});
if (native.isSuccess(result)) {
var resultObject = native.getResultObject(result);
resultObject.forEach(function(s) {
});
};
+var toByteArray = function(array) {
+ var d = [];
+
+ array.forEach(function(b) {
+ d.push(Converter.toOctet(b));
+ });
+ return d;
+};
+
//class BluetoothGATTCharacteristic ////////////////////////////////////////////////////
var BluetoothGATTCharacteristic = function(data, address) {
var handle_ = data.handle;
}
});
- var toByteArray = function(array) {
- var d = [];
-
- array.forEach(function(b) {
- d.push(Converter.toOctet(b));
- });
- return d;
- };
-
- BluetoothGATTCharacteristic.prototype.readValue = function() {
+ this.readValue = function() {
console.log('Entered BluetoothGATTCharacteristic.readValue()');
xwalk.utils.checkPrivilegeAccess4Ver("2.4", Privilege.BLUETOOTH, Privilege.BLUETOOTH_ADMIN);
}
};
- BluetoothGATTCharacteristic.prototype.writeValue = function() {
+ this.writeValue = function() {
console.log('Entered BluetoothGATTCharacteristic.writeValue()');
xwalk.utils.checkPrivilegeAccess4Ver("2.4", Privilege.BLUETOOTH, Privilege.BLUETOOTH_ADMIN);
}
};
- BluetoothGATTCharacteristic.prototype.addValueChangeListener = function() {
+ this.addValueChangeListener = function() {
console.log('Entered BluetoothGATTCharacteristic.addValueChangeListener()');
xwalk.utils.checkPrivilegeAccess4Ver("2.4", Privilege.BLUETOOTH, Privilege.BLUETOOTH_ADMIN);
return _bluetoothGATTCharacteristicListener.addListener(callback, callArgs);
};
- BluetoothGATTCharacteristic.prototype.removeValueChangeListener = function() {
+ this.removeValueChangeListener = function() {
console.log('Entered BluetoothGATTCharacteristic.removeValueChangeListener()');
var args = AV.validateMethod(arguments, [{
);
//class BluetoothGATTDescriptor ////////////////////////////////////////////////////
-var BluetoothGATTDescriptor = function(address) {
+var BluetoothGATTDescriptor = function(data, address) {
var handle_ = data.handle;
//address_ is needed to control if device is still connected
var address_ = address;
- BluetoothGATTDescriptor.prototype.readValue = function() {
+ this.readValue = function() {
console.log('Entered BluetoothGATTDescriptor.readValue()');
xwalk.utils.checkPrivilegeAccess4Ver("2.4", Privilege.BLUETOOTH, Privilege.BLUETOOTH_ADMIN);
}
};
- BluetoothGATTDescriptor.prototype.writeValue = function() {
+ this.writeValue = function() {
console.log('Entered BluetoothGATTDescriptor.writeValue()');
xwalk.utils.checkPrivilegeAccess4Ver("2.4", Privilege.BLUETOOTH, Privilege.BLUETOOTH_ADMIN);
};
// native.call does not inform if call results in failure
- // TODO: what to do in this case?
+ // Errors are handled by error callback
native.call('BluetoothAdapter_setName', callArgs, callback);
};
};
// native.call does not inform if call results in failure
- // TODO: what to do in this case?
+ // Errors are handled by error callback
native.call('BluetoothAdapter_setPowered', callArgs, callback);
};
};
// native.call does not inform if call results in failure
- // TODO: what to do in this case?
+ // Errors are handled by error callback
native.call('BluetoothAdapter_setVisible', callArgs, callback);
};
};
// native.call does not inform if call results in failure
- // TODO: what to do in this case?
+ // Errors are handled by error callback
native.call('BluetoothAdapter_stopDiscovery', {}, callback);
};
};
// native.call does not inform if call results in failure
- // TODO: what to do in this case?
+ // Errors are handled by error callback
native.call('BluetoothAdapter_getKnownDevices', {}, callback);
};
};
// native.call does not inform if call results in failure
- // TODO: what to do in this case?
+ // Errors are handled by error callback
native.call('BluetoothAdapter_getDevice', {address : args.address}, callback);
};
};
// native.call does not inform if call results in failure
- // TODO: what to do in this case?
+ // Errors are handled by error callback
native.call('BluetoothAdapter_createBonding', callArgs, callback);
};
};
// native.call does not inform if call results in failure
- // TODO: what to do in this case?
+ // Errors are handled by error callback
native.call('BluetoothAdapter_destroyBonding', callArgs, callback);
};
};
// native.call does not inform if call results in failure
- // TODO: what to do in this case?
+ // Errors are handled by error callback
native.call('BluetoothAdapter_registerRFCOMMServiceByUUID', callArgs, callback);
};
#include "bluetooth_device.h"
#include "common/converter.h"
-#include "common/logger.h"
#include "common/extension.h"
+#include "common/logger.h"
+#include "common/tools.h"
#include "bluetooth_adapter.h"
#include "bluetooth_class.h"
#include <sstream>
+#include "common/extension.h"
#include "common/logger.h"
#include "common/platform_result.h"
-#include "common/extension.h"
#include "common/task-queue.h"
+#include "common/tools.h"
#include "bluetooth/bluetooth_instance.h"
#include "bluetooth/bluetooth_util.h"
const std::string kOnValueChanged = "BluetoothGATTCharacteristicValueChangeListener";
bool IsProperty (int propertyBits, bt_gatt_property_e property) {
- return (propertyBits & property) == 0;
+ return (propertyBits & property) != 0;
}
}
BluetoothGATTService::~BluetoothGATTService() {
LoggerD("Entered");
- for (auto it : gatt_clients_) {
+ for (auto it : gatt_characteristic_) {
// unregister callback, ignore errors
- bt_gatt_client_unset_characteristic_value_changed_cb(it.second);
+ 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);
}
return gatt_clients_.end() != it;
}
+bt_gatt_client_h BluetoothGATTService::GetGattClient(const std::string& address) {
+ LoggerD("Entered");
+
+ 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) {
auto it = gatt_clients_.find(address);
picojson::object* result) {
LoggerD("Entered");
- bt_gatt_client_h client = nullptr;
- auto it = gatt_clients_.find(address);
- int ret = BT_ERROR_NONE;
- if (gatt_clients_.end() == it) {
- ret = bt_gatt_client_create(address.c_str(), &client);
- if (BT_ERROR_NONE != ret) {
- LoggerE("%d", ret);
- return util::GetBluetoothError(ret, "Failed to create the GATT client's handle");
- }
- gatt_clients_.insert(std::make_pair(address, client));
- } else {
- LoggerD("Client already created");
- client = it->second;
+ bt_gatt_client_h client = GetGattClient(address);
+
+ if (nullptr == client) {
+ return PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to create the GATT client's handle");
}
bt_gatt_h service = nullptr;
- ret = bt_gatt_client_get_service(client, uuid.c_str(), &service);
+ int ret = bt_gatt_client_get_service(client, uuid.c_str(), &service);
if (BT_ERROR_NONE != ret) {
- LoggerE("%d", ret);
- return util::GetBluetoothError(ret, "Failed to get a service's GATT handle");
+ LoggerE("bt_gatt_client_get_service() error: %d", ret);
+ switch (ret) {
+ case BT_ERROR_NO_DATA:
+ return PlatformResult(ErrorCode::NOT_FOUND_ERR, "Service not found");
+
+ case BT_ERROR_INVALID_PARAMETER:
+ return PlatformResult(ErrorCode::NOT_FOUND_ERR, "Service UUID is invalid");
+
+ default:
+ return PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to get a service's GATT handle");
+ }
}
//report BluetoothGattService
LoggerD("Entered");
bt_gatt_h handle = (bt_gatt_h) static_cast<long>(args.get("handle").get<double>());
- const std::string& uuid = args.get("uuid").get<std::string>();
const std::string& address = args.get("address").get<std::string>();
picojson::array array;
- PlatformResult ret = GetServicesHelper(handle, address, uuid, &array);
+ PlatformResult ret = GetServicesHelper(handle, address, &array);
if (ret.IsError()) {
LoggerE("Error while getting services");
ReportError(ret, &out);
PlatformResult BluetoothGATTService::GetServicesHelper(bt_gatt_h handle,
const std::string& address,
- const std::string& uuid,
picojson::array* array) {
LoggerD("Entered");
"Device is not connected");
}
- struct Data {
- const std::string& uuid;
- picojson::array* array;
- };
- Data user_data {uuid, array};
-
int ret = bt_gatt_service_foreach_included_services(
handle,
[](int total, int index, bt_gatt_h gatt_handle, void *data) {
LoggerD("Enter");
- Data user_data = *(static_cast<Data*>(data));
picojson::value result = picojson::value(picojson::object());
picojson::object& result_obj = result.get<picojson::object>();
- result_obj.insert(std::make_pair(kUuid, picojson::value(user_data.uuid)));
+ char* uuid = nullptr;
+
+ if (BT_ERROR_NONE == bt_gatt_get_uuid(gatt_handle, &uuid) && nullptr != uuid) {
+ result_obj.insert(std::make_pair(kUuid, picojson::value(uuid)));
+ free(uuid);
+ } else {
+ result_obj.insert(std::make_pair(kUuid, picojson::value("FFFF")));
+ }
+
//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)));
- user_data.array->push_back(result);
+ static_cast<picojson::array*>(data)->push_back(result);
return true;
- }, static_cast<void*>(&user_data));
+ }, 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");
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 {
- Data* data = (Data*) user_data;
+ Data* data = static_cast<Data*>(user_data);
double callback_handle = data->callback_handle;
BluetoothGATTService* service = data->service;
delete data;
LoggerE("bt_gatt_client_set_characteristic_value_changed_cb() failed with: %d", ret);
ReportError(util::GetBluetoothError(ret, "Failed to register listener"), &out);
} else {
+ gatt_characteristic_.push_back(handle);
ReportSuccess(out);
}
}
LoggerE("bt_gatt_client_unset_characteristic_value_changed_cb() failed with: %d", ret);
ReportError(util::GetBluetoothError(ret, "Failed to unregister listener"), &out);
} else {
+ gatt_characteristic_.erase(std::remove(gatt_characteristic_.begin(), gatt_characteristic_.end(), handle), gatt_characteristic_.end());
ReportSuccess(out);
}
}
+common::PlatformResult BluetoothGATTService::GetServiceUuids(
+ const std::string& address, picojson::array* array) {
+ LoggerD("Entered");
+
+ bt_gatt_client_h client = GetGattClient(address);
+
+ if (nullptr == client) {
+ return PlatformResult(ErrorCode::UNKNOWN_ERR, "Unable to create client");
+ }
+
+ auto foreach_callback = [](int total, int index, bt_gatt_h gatt_handle, void* user_data) -> bool {
+ LoggerD("Entered foreach_callback, total: %d, index: %d", total, index);
+
+ char* uuid = nullptr;
+ int ret = bt_gatt_get_uuid(gatt_handle, &uuid);
+
+ if (BT_ERROR_NONE != ret || nullptr == uuid) {
+ LoggerE("Failed to get UUID: %d", ret);
+ } else {
+ std::string u = std::string(uuid);
+ free(uuid);
+ if (u.length() > 4) { // 128-bit UUID, needs to be converted to 16-bit
+ u = u.substr(4, 4);
+ }
+ static_cast<picojson::array*>(user_data)->push_back(picojson::value(u));
+ }
+
+ return true;
+ };
+
+ int ret = bt_gatt_client_foreach_services(client, foreach_callback, array);
+
+ if (BT_ERROR_NONE == ret) {
+ return PlatformResult(ErrorCode::NO_ERROR);
+ } else {
+ LoggerE("Failed to get UUIDS: %d", ret);
+ return util::GetBluetoothError(ret, "Failed to get UUIDS");
+ }
+}
+
void BluetoothGATTService::OnCharacteristicValueChanged(
bt_gatt_h characteristic, char* value, int length, void* user_data) {
LoggerD("Entered, characteristic: [%p], len: [d], user_data: [%p]", characteristic, length, user_data);
void RemoveValueChangeListener(const picojson::value& args,
picojson::object& out);
+ common::PlatformResult GetServiceUuids(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,
- const std::string& uuid,
picojson::array* array);
common::PlatformResult GetCharacteristicsHelper(bt_gatt_h handle,
const std::string& address,
void* user_data);
std::map<std::string, bt_gatt_client_h> gatt_clients_;
+ std::vector<bt_gatt_h> gatt_characteristic_;
BluetoothInstance& instance_;
};
#include "bluetooth_health_application.h"
#include "common/converter.h"
-#include "common/logger.h"
#include "common/extension.h"
+#include "common/logger.h"
+#include "common/tools.h"
#include "bluetooth_health_profile_handler.h"
#include "bluetooth_util.h"
#include <memory>
#include "common/converter.h"
-#include "common/logger.h"
#include "common/extension.h"
+#include "common/logger.h"
+#include "common/tools.h"
#include "bluetooth_device.h"
#include "bluetooth_util.h"
#include "bluetooth_health_profile_handler.h"
#include "common/converter.h"
-#include "common/logger.h"
#include "common/extension.h"
+#include "common/logger.h"
#include "common/task-queue.h"
+#include "common/tools.h"
#include "bluetooth/bluetooth_adapter.h"
#include "bluetooth/bluetooth_instance.h"
instance_.SyncResponse(callback_handle, response);
};
+ auto queue_data = std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+
TaskQueue::GetInstance().Queue<picojson::value>(
register_app,
register_app_response,
- std::shared_ptr<picojson::value>(new picojson::value(picojson::object())));
+ queue_data);
ReportSuccess(out);
}
instance_.SyncResponse(callback_handle, response);
};
+ auto data = std::shared_ptr<picojson::value>(new picojson::value(picojson::object()));
+
TaskQueue::GetInstance().Queue<picojson::value>(
unregister_app,
unregister_app_response,
- std::shared_ptr<picojson::value>(new picojson::value(picojson::object())));
+ data);
}
} // namespace bluetooth
#include "common/converter.h"
#include "common/logger.h"
#include "common/task-queue.h"
+#include "common/tools.h"
namespace extension {
namespace bluetooth {
"BluetoothLEDevice_removeConnectStateChangeListener",
std::bind(&BluetoothLEDevice::RemoveConnectStateChangeListener,
&bluetooth_le_device_, _1, _2));
+ REGISTER_SYNC(
+ "BluetoothLEDevice_getServiceUuids",
+ std::bind(&BluetoothLEDevice::GetServiceUuids,
+ &bluetooth_le_device_, _1, _2));
// BluetoothGATTService
REGISTER_SYNC("BluetoothGATTService_getServices",
LoggerD("Entered");
auto& obj = response->get<picojson::object>();
obj[JSON_CALLBACK_ID] = picojson::value(callback_handle);
- PostMessage(response->serialize().c_str());
+ Instance::PostMessage(this, response->serialize().c_str());
}
void BluetoothInstance::FireEvent(const std::string& event, picojson::value& value) {
LoggerD("Entered");
auto& obj = value.get<picojson::object>();
obj[JSON_LISTENER_ID] = picojson::value(event);
- PostMessage(value.serialize().c_str());
+ Instance::PostMessage(this, value.serialize().c_str());
}
void BluetoothInstance::FireEvent(const std::string& event, const picojson::value& value) {
#include "bluetooth/bluetooth_le_adapter.h"
+#include "common/tools.h"
#include "common/logger.h"
#include "bluetooth/bluetooth_instance.h"
class BluetoothLEManufacturerData : public ParsedDataHolder {
public:
BluetoothLEManufacturerData()
- : ParsedDataHolder() {
+ : ParsedDataHolder(),
+ data_(nullptr),
+ data_length_(0) {
}
const std::string& id() const {
return id_;
}
- const std::string& data() const {
+ const unsigned char* const data() const {
return data_;
}
+ const int data_length() const {
+ return data_length_;
+ }
+
static bool Construct(const picojson::value& obj,
BluetoothLEManufacturerData* out) {
LoggerD("Entered");
return true;
}
+ ~BluetoothLEManufacturerData() {
+ if (data_) {
+ delete [] data_;
+ data_ = nullptr;
+ data_length_ = 0;
+ }
+ }
+
private:
static bool ParseId(const picojson::value& obj,
BluetoothLEManufacturerData* out) {
static bool ParseData(const picojson::value& obj,
BluetoothLEManufacturerData* out) {
LoggerD("Entered");
- const auto& data = obj.get("data");
- if (data.is<std::string>()) {
- out->data_ = data.get<std::string>();
+
+ const auto& val_data = obj.get("data");
+
+ if (val_data.is<std::string>()) {
+ const std::string& str_data = val_data.get<std::string>();
+ const char* p_data = str_data.c_str();
+ int size = str_data.length();
+ if (size > 2 && (str_data.find("0x", 0) == 0 || str_data.find("0X", 0) == 0)) {
+ p_data += 2;
+ size -= 2;
+ }
+ out->data_length_ = size / 2;
+ out->data_ = new unsigned char[out->data_length_];
+ common::tools::HexToBin(p_data, size, out->data_, out->data_length_);
+ return true;
} else {
return false;
}
-
- return true;
}
std::string id_;
- std::string data_;
+ unsigned char* data_;
+ int data_length_;
};
class BluetoothLEAdvertiseData : public ParsedDataHolder {
}
const auto& manufacturer_data = advertise_data.manufacturer_data();
- if (manufacturer_data.id().empty() && manufacturer_data.data().empty()) {
+ if (manufacturer_data.id().empty() && manufacturer_data.data() == nullptr) {
LoggerD("manufacturerData is empty");
} else {
- if (manufacturer_data.valid()) {
+ if (manufacturer_data.valid()) {
ret = bt_adapter_le_add_advertising_manufacturer_data(advertiser,
packet_type,
atoi(manufacturer_data.id().c_str()),
- manufacturer_data.data().c_str(),
- manufacturer_data.data().length());
+ (const char*)manufacturer_data.data(),
+ manufacturer_data.data_length());
if (BT_ERROR_NONE != ret) {
LoggerE("bt_adapter_le_add_advertising_manufacturer_data() failed with: %d", ret);
ReportError(util::GetBluetoothError(ret, "Failed to create advertiser"), &out);
ReportError(util::GetBluetoothError(result, "Error during scanning"), data_obj);
data_obj->insert(std::make_pair(kAction, picojson::value(kOnScanError)));
} else {
- // TODO: this is probably capi-network-bluetooth error: when scan is stopped info has 0x1 value
+ // this is probably capi-network-bluetooth error: when scan is stopped info has 0x1 value
if (nullptr != info && reinterpret_cast<void*>(0x1) != info) {
// device found
LoggerD("Device found");
#include "common/converter.h"
#include "common/logger.h"
+#include "common/tools.h"
using common::ErrorCode;
using common::PlatformResult;
using common::tools::ReportError;
using common::tools::ReportSuccess;
+using common::tools::BinToHex;
namespace extension {
namespace bluetooth {
//le_device
const std::string kDeviceName = "name";
const std::string kDeviceAddress = "address";
-const std::string kTxPowerLevel = "txpowerLevel";
+const std::string kTxPowerLevel = "txpowerlevel";
const std::string kAppearance = "appearance";
const std::string kDeviceUuids = "uuids";
const std::string kSolicitationUuids = "solicitationuuids";
}
}
-static void ManufacturerToJson(int manufacturer_id, char *manufacturer_data,
+static void ManufacturerToJson(int manufacturer_id,
+ char *manufacturer_data,
int manufacturer_count,
picojson::object* le_device) {
LoggerD("Entered");
picojson::value response = picojson::value(picojson::object());
picojson::object& response_obj = response.get<picojson::object>();
response_obj[kId] = picojson::value(std::to_string(manufacturer_id));
- response_obj[kData] = picojson::value(
- std::string(manufacturer_data, manufacturer_count));
+
+ const int hex_count = manufacturer_count * 2;
+ char* manuf_data_hex = new char[hex_count + 1];
+ BinToHex((const unsigned char*) manufacturer_data,
+ manufacturer_count,
+ manuf_data_hex,
+ hex_count);
+ manuf_data_hex[hex_count] = '\0';
+ response_obj[kData] = picojson::value(std::string(manuf_data_hex));
+ delete [] manuf_data_hex;
+ manuf_data_hex = nullptr;
+
+ le_device->insert(std::make_pair(kManufacturerData, response));
}
PlatformResult BluetoothLEDevice::ToJson(
g_free(device_name);
}
+
int power_level = 0;
found = false;
for (size_t i = 0; i < types.size() && !found; ++i) {
if (found) {
le_device->insert(
- std::make_pair(kTxPowerLevel,
- picojson::value(static_cast<double>(power_level))));
+ std::make_pair(kTxPowerLevel,
+ picojson::value(static_cast<double>(power_level))));
}
+
int appearance = 0;
found = false;
for (size_t i = 0; i < types.size() && !found; ++i) {
if (found) {
le_device->insert(
- std::make_pair(kAppearance,
- picojson::value(static_cast<double>(appearance))));
+ std::make_pair(kAppearance,
+ picojson::value(static_cast<double>(appearance))));
}
char **uuids = nullptr;
if (found) {
ServiceDataToJson(serviceDataList, service_data_list_count, le_device);
ret = bt_adapter_le_free_service_data_list(serviceDataList,
- service_data_list_count);
+ service_data_list_count);
if (BT_ERROR_NONE != ret) {
LoggerW("Failed to free service data list: %d", ret);
}
manufacturer_data_count, le_device);
g_free(manufacturer_data);
}
+
return PlatformResult(ErrorCode::NO_ERROR);
}
const auto& address = common::FromJson<std::string>(args, "address");
- int ret = bt_gatt_connect(address.c_str(), true);
+ bool connected = false;
+ int ret = bt_device_is_profile_connected(address.c_str(), BT_PROFILE_GATT, &connected);
if (BT_ERROR_NONE != ret) {
- instance_.AsyncResponse(
- callback_handle,
- PlatformResult(util::GetBluetoothError(ret, "Failed to connect.")));
+ instance_.AsyncResponse(callback_handle,
+ PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to disconnect."));
return;
}
- connecting_[address] = callback_handle;
+ if (connected) {
+ instance_.AsyncResponse(callback_handle,
+ PlatformResult(ErrorCode::NO_ERROR));
+ } else { // not connected yet
+ ret = bt_gatt_connect(address.c_str(), false);
+ if (BT_ERROR_NONE != ret) {
+ instance_.AsyncResponse(
+ callback_handle,
+ PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to connect."));
+ return;
+ }
+ connecting_[address] = callback_handle;
+ }
ReportSuccess(out);
}
const auto callback_handle = util::GetAsyncCallbackHandle(data);
const auto& args = util::GetArguments(data);
-
const auto& address = common::FromJson<std::string>(args, "address");
- int ret = bt_gatt_disconnect(address.c_str());
+ int ret = BT_ERROR_NONE;
+
+ bool connected = false;
+ ret = bt_device_is_profile_connected(address.c_str(), BT_PROFILE_GATT, &connected);
if (BT_ERROR_NONE != ret) {
instance_.AsyncResponse(
callback_handle,
- PlatformResult(util::GetBluetoothError(ret, "Failed to disconnect.")));
+ PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to disconnect."));
+ return;
+ }
+ if (!connected) {
+ ReportError(PlatformResult(ErrorCode::INVALID_STATE_ERR,
+ "Bluetooth low energy device is not connected"),
+ &out);
+ return;
+ }
+
+ ret = bt_gatt_disconnect(address.c_str());
+ if (BT_ERROR_NONE != ret) {
+ instance_.AsyncResponse(
+ callback_handle,
+ PlatformResult(ErrorCode::UNKNOWN_ERR, "Failed to disconnect."));
return;
}
ReportSuccess(out);
}
+void BluetoothLEDevice::GetServiceUuids(const picojson::value& data,
+ picojson::object& out) {
+ LoggerD("Entered");
+
+ const auto& args = util::GetArguments(data);
+ const auto& address = common::FromJson<std::string>(args, "address");
+
+ picojson::value response = picojson::value(picojson::array());
+ picojson::array *data_obj = &response.get<picojson::array>();
+
+ PlatformResult result = service_.GetServiceUuids(address, data_obj);
+
+ if (result) {
+ ReportSuccess(response, out);
+ } else {
+ ReportError(result, &out);
+ }
+}
+
void BluetoothLEDevice::GattConnectionState(int result, bool connected,
const char* remote_address,
void* user_data) {
void RemoveConnectStateChangeListener(const picojson::value& data,
picojson::object& out);
+ void GetServiceUuids(const picojson::value& data, picojson::object& out);
+
static common::PlatformResult ToJson(
bt_adapter_le_device_scan_result_info_s* info,
picojson::object* le_device);
#include "bluetooth_service_handler.h"
#include "common/converter.h"
-#include "common/logger.h"
#include "common/extension.h"
+#include "common/logger.h"
+#include "common/tools.h"
#include "bluetooth_adapter.h"
#include "bluetooth_util.h"
#include <memory>
#include "common/converter.h"
-#include "common/logger.h"
#include "common/extension.h"
+#include "common/logger.h"
+#include "common/tools.h"
#include "bluetooth_adapter.h"
#include "bluetooth_device.h"
common::PlatformResult GetBluetoothError(int error_code, const std::string& hint);
std::string GetBluetoothErrorMessage(int error_code);
-} // namespace util
-} // namespace bluetooth
-} // namespace extension
+} // util
+} // bluetooth
+} // extension
#endif // BLUETOOTH_BLUETOOTH_UTIL_H_
return msg;
}
+
+int HexToInt(char c) {
+ if (c >= '0' && c <= '9') {
+ return c - '0';
+ } else if (c >= 'A' && c <= 'Z') {
+ return c - 'A';
+ } else {
+ return c - 'a';
+ }
+}
+
+unsigned char* HexToBin(const char* hex, int size, unsigned char* bin, int bin_size) {
+ for (int i = 0; i < size - 1 && i / 2 < bin_size; i += 2) {
+ bin[i * 2] = HexToInt(hex[i]) << 4;
+ bin[i * 2] += HexToInt(hex[i + 1]);
+ }
+ return bin;
+}
+
+char* BinToHex(const unsigned char* bin, int size, char* hex, int hex_size) {
+ static const char * const digits = "0123456789ABCDEF";
+ for (int i = 0; i < size && i < hex_size / 2; i++) {
+ hex[i * 2] = digits[bin[i] >> 4];
+ hex[i * 2 + 1] = digits[bin[i] & 15];
+ }
+ return hex;
+}
+
} // namespace tools
} // namespace common
*/
std::string GetErrorString(int error_code);
+int HexToInt(char c);
+unsigned char* HexToBin(const char* hex, int size, unsigned char* bin, int bin_size);
+char* BinToHex(const unsigned char* bin, int size, char* hex, int hex_size);
+
} // namespace tools
} // namespace common