if (T.isNull(v)) {
servicesData_ = v;
} else if (T.isArray(v)) {
- var tmpArray = []
+ var tmpArray = [];
for (var i = 0; i < v.length; ++i) {
if (v[i] instanceof tizen.BluetoothLEServiceData) {
tmpArray.push(v[i]);
this.removeValueChangeListener = function() {
/* Intended no operation */
};
+
+ this.notifyAboutValueChange = function(
+ value,
+ clientAddress,
+ notificationCB,
+ errorCB
+ ) {
+ var args = AV.validateArgs(
+ Array.prototype.slice.call(arguments, 1),
+ [
+ {
+ name: 'clientAddress',
+ type: AV.Types.STRING,
+ optional: true,
+ nullable: true
+ },
+ {
+ name: 'notificationCB',
+ type: AV.Types.LISTENER,
+ values: [
+ 'onnotificationsuccess',
+ 'onnotificationfail',
+ 'onnotificationfinish'
+ ],
+ optional: true,
+ nullable: true
+ },
+ {
+ name: 'errorCB',
+ type: AV.Types.FUNCTION,
+ optional: true,
+ nullable: true
+ }
+ ]
+ );
+
+ var callArgs = {
+ value: BluetoothManager_toByteArray(value),
+ client: args.clientAddress || null,
+ _id: this._id,
+ notifyId: _BluetoothGATTServerCharacteristicNotifyId++
+ };
+
+ var callback = function(result) {
+ if (native.isFailure(result)) {
+ native.callIfPossible(args.errorCB, native.getErrorObject(result));
+ }
+ };
+
+ var result = native.call(
+ 'BluetoothGATTServerCharacteristicNotifyAboutValueChange',
+ callArgs,
+ callback
+ );
+
+ if (native.isFailure(result)) {
+ throw native.getErrorObject(result);
+ }
+
+ native.addListener(
+ 'BluetoothGATTServerCharacteristicNotifyCallback_' + callArgs.notifyId,
+ _BluetoothGATTServerCharacteristicNotifyCallback
+ );
+
+ _BluetoothGATTServerCharacteristicNotifyListeners[callArgs.notifyId] =
+ args.notificationCB;
+ };
};
BluetoothGATTServerCharacteristic.prototype = Object.create(
}
);
_BluetoothGATTServerReadWriteValueRequestCallbacks[
- "ReadValueCallback" + entityId
+ 'ReadValueCallback' + entityId
] = readValueRequestCallback;
native.callIfPossible(args.successCallback, native.getErrorObject(result));
}
BluetoothGATTServerCharacteristic.prototype.setReadValueRequestCallback = _setReadValueRequestCallbackCommon;
BluetoothGATTServerCharacteristic.prototype.setWriteValueRequestCallback = _setWriteValueRequestCallbackCommon;
+var _BluetoothGATTServerCharacteristicNotifyId = 0;
+var _BluetoothGATTServerCharacteristicNotifyListeners = {};
+var _BluetoothGATTServerCharacteristicNotifyCallback = function(event) {
+ privUtils_.log('Got notification about characteristic\'s value change');
+ if (
+ T.isNullOrUndefined(
+ _BluetoothGATTServerCharacteristicNotifyListeners[event.notifyId]
+ )
+ ) {
+ privUtils_.log('Notification callback is not set, skipping');
+ return;
+ }
+
+ var callback = _BluetoothGATTServerCharacteristicNotifyListeners[event.notifyId];
+
+ if (event.type === 'onnotificationsuccess') {
+ native.callIfPossible(callback.onnotificationsuccess, event.clientAddress);
+ return;
+ }
+
+ if (event.type === 'onnotificationfail') {
+ native.callIfPossible(
+ callback.onnotificationfail,
+ event.clientAddress,
+ native.getErrorObject(event)
+ );
+ return;
+ }
+
+ if (event.type === 'onnotificationfinish') {
+ native.callIfPossible(callback.onnotificationfinish, event.clientAddress);
+ }
+
+ native.removeListener(
+ 'BluetoothGATTServerCharacteristicNotifyCallback_' + event.notifyId
+ );
+};
+
/**
* Creates a manager for specified listener event. Manager handles multiple
* registered listeners
return running_;
}
+void BluetoothGATTServer::NotifyAboutValueChange(const picojson::value& args,
+ picojson::object& out) {
+ ScopeLogger();
+
+ if (!initialized_) {
+ LoggerE("Server not started");
+ ReportError(common::PlatformResult{common::ErrorCode::ABORT_ERR, "Server not started"}, &out);
+ return;
+ }
+
+ auto result = service_.NotifyAboutValueChange(args);
+ if (result.IsError()) {
+ ReportError(result, &out);
+ return;
+ }
+
+ ReportSuccess(out);
+}
+
PlatformResult BluetoothGATTServer::Initialize() {
ScopeLogger();
void SetWriteValueRequestCallback(const picojson::value& args, picojson::object& out);
void SendResponse(const picojson::value& args, picojson::object& out);
bool IsRunning();
+ void NotifyAboutValueChange(const picojson::value& args, picojson::object& out);
static bool DestroyService(int total, int index, bt_gatt_h handle, void* user_data);
static bool DestroyCharacteristic(int total, int index, bt_gatt_h handle, void* user_data);
const std::string kData = "data";
const std::string kReadCallback = "readCallback";
const std::string kWriteCallback = "writeCallback";
+const std::string kNotifyId = "notifyId";
+const std::string kOnNotificationFail = "onnotificationfail";
+const std::string kOnNotificationFinish = "onnotificationfinish";
+const std::string kOnNotificationSuccess = "onnotificationsuccess";
+const std::string kType = "type";
+const std::string kClient = "client";
int GetPermissionsInt(const picojson::value& permissions) {
ScopeLogger("permissions: %s", permissions.serialize().c_str());
auto remote_address_copy = std::string{remote_address};
auto value_copy = std::string{value};
rw_callback_data->instance_.GetWorker().add_job([remote_address_copy, request_id, server,
- gatt_handle, response_needed, offset, value_copy,
- rw_callback_data] {
+ gatt_handle, response_needed, offset,
+ value_copy, rw_callback_data] {
ScopeLogger("Async call: SetWriteValueRequestCallback");
auto write_value_request = picojson::value{picojson::object{}};
write_value_request_obj[kValue] = picojson::value{picojson::array{}};
auto& value_byte_array = write_value_request_obj[kValue].get<picojson::array>();
- for (auto c: value_copy) {
+ for (auto c : value_copy) {
value_byte_array.push_back(picojson::value{static_cast<double>(c)});
}
const auto callback_name =
return common::PlatformResult{};
}
+struct NotificationUserData {
+ int notify_id;
+ BluetoothGATTServerService* service;
+};
+
+void BluetoothGATTServerService::NotifyCallback(int result, const char* remote_address,
+ bt_gatt_server_h server, bt_gatt_h characteristic,
+ bool completed, void* user_data) {
+ ScopeLogger("Async callback of bt_gatt_server_notify_characteristic_changed_value()");
+ LoggerD("result: %d, remote_address: %s, completed: %d", result, remote_address, completed);
+
+ NotificationUserData* data = static_cast<NotificationUserData*>(user_data);
+ BluetoothGATTServerService* bt_service = data->service;
+ int notify_id = data->notify_id;
+ LoggerD("notify_id: %d", notify_id);
+
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& obj = response.get<picojson::object>();
+
+ if (remote_address != nullptr) {
+ obj.insert(std::make_pair(kClientAddress, remote_address));
+ } else {
+ obj.insert(std::make_pair(kClientAddress, picojson::value()));
+ }
+ obj.insert(std::make_pair(kNotifyId, static_cast<double>(notify_id)));
+
+ std::string type;
+ if (BT_ERROR_NONE != result) {
+ auto ret = util::GetBluetoothError(result, "Failed to notify client about change");
+ type = kOnNotificationFail;
+ common::tools::ReportError(ret, &obj);
+ } else {
+ type = kOnNotificationSuccess;
+ }
+
+ obj.insert(std::make_pair(kType, type));
+
+ LoggerD("Sending event: type: %s, notifyId: %d", type.c_str(), notify_id);
+ std::string event =
+ "BluetoothGATTServerCharacteristicNotifyCallback_" + std::to_string(notify_id);
+ bt_service->instance_.FireEvent(event, response);
+
+ if (completed) {
+ obj[kType] = picojson::value(kOnNotificationFinish);
+ bt_service->instance_.FireEvent(event, response);
+ delete data;
+ }
+};
+
+common::PlatformResult BluetoothGATTServerService::NotifyAboutValueChange(
+ const picojson::value& args) {
+ ScopeLogger();
+
+ auto gatt_id = static_cast<int>(args.get(kId).get<double>());
+ auto gatt_iter = gatt_objects_.find(gatt_id);
+ if (gatt_iter == gatt_objects_.end()) {
+ LoggerE("Can't find gatt object with id: %d", gatt_id);
+ return common::PlatformResult{common::ErrorCode::ABORT_ERR, "Unknown error occurred"};
+ }
+ bt_gatt_h gatt_handle = gatt_iter->second;
+ LoggerD("Found proper gatt object");
+
+ const picojson::array& value_array = args.get(kValue).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] = static_cast<int>(value_array[i].get<double>());
+ }
+ int ret = bt_gatt_set_value(gatt_handle, value_data.get(), value_size);
+ if (BT_ERROR_NONE != ret) {
+ LoggerE("Failed to set value, error: %d, message: %s", ret, get_error_message(ret));
+ return common::PlatformResult{common::ErrorCode::ABORT_ERR, "Unknown error occurred"};
+ }
+ LoggerD("New value set in characteristic");
+
+ const char* address = args.get(kClient).is<picojson::null>()
+ ? nullptr
+ : args.get(kClient).get<std::string>().c_str();
+
+ LoggerD("Client address to notify: [%s]", address);
+
+ auto notify_id = static_cast<int>(args.get(kNotifyId).get<double>());
+ NotificationUserData* user_data = new NotificationUserData{notify_id, this};
+ ret = bt_gatt_server_notify_characteristic_changed_value(gatt_handle, NotifyCallback, address,
+ user_data);
+ if (BT_ERROR_NONE != ret) {
+ LoggerE("bt_gatt_server_notify_characteristic_changed_value() failed: %d", ret);
+ delete user_data;
+ return common::PlatformResult{common::ErrorCode::ABORT_ERR, "Failed to notify"};
+ }
+ LoggerD("Sent notification about value changed");
+ return common::PlatformResult{};
+}
+
} // namespace bluetooth
} // namespace extension
PlatformResult SetReadValueRequestCallback(const picojson::value& args);
PlatformResult SetWriteValueRequestCallback(const picojson::value& args);
PlatformResult SendResponse(const picojson::value& args);
+ PlatformResult NotifyAboutValueChange(const picojson::value& args);
private:
+ BluetoothInstance& instance_;
std::map<int, bt_gatt_h> gatt_objects_;
std::map<std::pair<bt_gatt_h, std::string>, std::string> callback_names_;
- BluetoothInstance& instance_;
-
struct ReadWriteRequestCallbackData {
BluetoothInstance& instance_;
std::map<std::pair<bt_gatt_h, std::string>, std::string>& callback_names_map_;
static bool DestroyService(int total, int index, bt_gatt_h handle, void* user_data);
static bool DestroyCharacteristic(int total, int index, bt_gatt_h handle, void* user_data);
static bool DestroyDescriptor(int total, int index, bt_gatt_h handle, void* user_data);
+ static void NotifyCallback(int result, const char* remote_address, bt_gatt_server_h server,
+ bt_gatt_h characteristic, bool completed, void* user_data);
PlatformResult AddDescriptors(const picojson::array& descriptors, bt_gatt_h characteristic_handle,
std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects);
REGISTER_METHOD(BluetoothGATTServerSetReadValueRequestCallback);
REGISTER_METHOD(BluetoothGATTServerSetWriteValueRequestCallback);
REGISTER_METHOD(BluetoothGATTServerSendResponse);
+ REGISTER_METHOD(BluetoothGATTServerCharacteristicNotifyAboutValueChange);
#undef REGISTER_METHOD
}
ReportSuccess(out);
}
+void BluetoothInstance::BluetoothGATTServerCharacteristicNotifyAboutValueChange(
+ const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeBluetooth, &out);
+
+ worker.add_job([this, args] {
+ ScopeLogger("Async call: BluetoothGATTServerCharacteristicNotifyAboutValueChange");
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& async_out = response.get<picojson::object>();
+ double callback_id = args.get(JSON_CALLBACK_ID).get<double>();
+ async_out[JSON_CALLBACK_ID] = picojson::value(callback_id);
+ this->bluetooth_gatt_server_.NotifyAboutValueChange(args, async_out);
+ this->PostMessage(response.serialize().c_str());
+ });
+
+ ReportSuccess(out);
+}
+
} // namespace bluetooth
} // namespace extension
void BluetoothGATTServerSetWriteValueRequestCallback(const picojson::value& args,
picojson::object& out);
void BluetoothGATTServerSendResponse(const picojson::value& args, picojson::object& out);
+ void BluetoothGATTServerCharacteristicNotifyAboutValueChange(const picojson::value& args,
+ picojson::object& out);
BluetoothAdapter bluetooth_adapter_;
BluetoothDevice bluetooth_device_;