writable: true
});
+tizen.GATTRequestReply = function(statusCode, data) {
+ AV.isConstructorCall(this, tizen.GATTRequestReply);
+
+ var statusCode_ = Converter.toLong(statusCode);
+ var data_ = T.isNullOrUndefined(data) ? null : BluetoothManager_toByteArray(data);
+
+ Object.defineProperties(this, {
+ statusCode: {
+ enumerable: true,
+ get: function() {
+ return statusCode_;
+ },
+ set: function(v) {
+ statusCode_ = Converter.toLong(v);
+ }
+ },
+ data: {
+ enumerable: true,
+ get: function() {
+ return data_;
+ },
+ set: function(v) {
+ data_ = T.isNullOrUndefined(v) ? null : numberArrayToByteArray(v);
+ }
+ }
+ });
+};
+
+function _createReadValueRequestCallback(
+ _id,
+ sendResponseSuccessCallback,
+ sendResponseErrorCallback
+) {
+ return _singleListenerBuilder(
+ 'ReadValueRequestCallback_' + _id,
+ /*
+ * _singleListenerBuilder requires 2 callbacks, the second of which
+ * is an error callback.
+ * Read value request events coming from the native layer
+ * are never errors.
+ * Hence, we don't use the second callback here.
+ */
+ function(event, readValueRequestCallback, unusedErrorCallback) {
+ var clientAddress = event.clientAddress;
+ var offset = event.offset;
+ privUtils_.warn('event: ' + JSON.stringify(event));
+
+ if (readValueRequestCallback) {
+ var requestReply = readValueRequestCallback(clientAddress, offset);
+ var response = {
+ _id: _id,
+ requestId: event.requestId,
+ requestType: event.requestType,
+ offset: offset,
+ statusCode: requestReply.statusCode,
+ data: requestReply.data
+ };
+ privUtils_.warn('event: ' + JSON.stringify(response));
+ var callback = function(result) {
+ if (native.isFailure(result)) {
+ native.callIfPossible(
+ sendResponseErrorCallback,
+ native.getErrorObject(result)
+ );
+ } else {
+ native.callIfPossible(sendResponseSuccessCallback);
+ }
+ };
+ var result = native.call(
+ 'BluetoothGATTServerSendResponse',
+ response,
+ callback
+ );
+ }
+ return true;
+ }
+ );
+}
+
+var _BluetoothGATTServerReadWriteValueRequestCallbacks = {};
+
+BluetoothGATTServerCharacteristic.prototype.setReadValueRequestCallback = function() {
+ var args = AV.validateArgs(arguments, [
+ {
+ name: 'readValueRequestCallback',
+ type: AV.Types.FUNCTION
+ },
+ {
+ name: 'successCallback',
+ type: AV.Types.FUNCTION,
+ optional: true,
+ nullable: true
+ },
+ {
+ name: 'errorCallback',
+ type: AV.Types.FUNCTION,
+ optional: true,
+ nullable: true
+ },
+ {
+ name: 'sendResponseSuccessCallback',
+ type: AV.Types.FUNCTION,
+ optional: true,
+ nullable: true
+ },
+ {
+ name: 'sendResponseErrorCallback',
+ type: AV.Types.FUNCTION,
+ optional: true,
+ nullable: true
+ }
+ ]);
+
+ var characteristicId = this._id;
+
+ var callback = function(result) {
+ if (native.isFailure(result)) {
+ native.callIfPossible(args.errorCallback, native.getErrorObject(result));
+ } else {
+ var readValueRequestCallback = _createReadValueRequestCallback(
+ characteristicId,
+ args.sendResponseSuccessCallback,
+ args.sendResponseErrorCallback
+ );
+ readValueRequestCallback.addListener(
+ args.readValueRequestCallback,
+ function unusedErrorCallback() {
+ /* Intentionally no operation */
+ }
+ );
+ _BluetoothGATTServerReadWriteValueRequestCallbacks[
+ "ReadValueCallback" + characteristicId
+ ] = readValueRequestCallback;
+ native.callIfPossible(args.successCallback, native.getErrorObject(result));
+ }
+ };
+
+ var callArgs = { _id: this._id };
+ var result = native.call(
+ 'BluetoothGATTServerSetReadValueRequestCallback',
+ callArgs,
+ callback
+ );
+
+ if (native.isFailure(result)) {
+ throw native.getErrorObject(result);
+ }
+};
+
/**
* Creates a manager for specified listener event. Manager handles multiple
* registered listeners
throw native.getErrorObjectAndValidate(result, BluetoothGATTServer_valid_getConnectionMtu_exceptions,
UnknownError);
}
-}
+};
var GATTServer = new BluetoothGATTServer();
}
}
-BluetoothGATTClientService::BluetoothGATTClientService(BluetoothInstance& instance) : instance_(instance) {
+BluetoothGATTClientService::BluetoothGATTClientService(BluetoothInstance& instance)
+ : instance_(instance) {
ScopeLogger();
}
}
PlatformResult BluetoothGATTClientService::GetSpecifiedGATTClient(const std::string& address,
- const UUID& uuid,
- picojson::object* result) {
+ const UUID& uuid,
+ picojson::object* result) {
ScopeLogger();
bt_gatt_client_h client = GetGattClient(address);
}
}
-PlatformResult BluetoothGATTClientService::GetServicesHelper(bt_gatt_h handle, const std::string& address,
- picojson::array* array) {
+PlatformResult BluetoothGATTClientService::GetServicesHelper(bt_gatt_h handle,
+ const std::string& address,
+ picojson::array* array) {
ScopeLogger();
if (!IsStillConnected(address)) {
return PlatformResult(ErrorCode::NO_ERROR);
}
-void BluetoothGATTClientService::GetCharacteristics(const picojson::value& args, picojson::object& out) {
+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>());
}
PlatformResult BluetoothGATTClientService::GetCharacteristicsHelper(bt_gatt_h handle,
- const std::string& address,
- picojson::array* array) {
+ const std::string& address,
+ picojson::array* array) {
ScopeLogger();
if (!IsStillConnected(address)) {
}
void BluetoothGATTClientService::AddValueChangeListener(const picojson::value& args,
- picojson::object& out) {
+ picojson::object& out) {
ScopeLogger();
const auto& address = args.get("address").get<std::string>();
if (!IsStillConnected(address)) {
}
void BluetoothGATTClientService::RemoveValueChangeListener(const picojson::value& args,
- picojson::object& out) {
+ picojson::object& out) {
ScopeLogger();
const auto& address = args.get("address").get<std::string>();
if (!IsStillConnected(address)) {
}
common::PlatformResult BluetoothGATTClientService::GetServiceAllUuids(const std::string& address,
- picojson::array* array) {
+ picojson::array* array) {
ScopeLogger();
bt_gatt_client_h client = GetGattClient(address);
}
void BluetoothGATTClientService::OnCharacteristicValueChanged(bt_gatt_h characteristic, char* value,
- int length, void* user_data) {
+ int length, void* user_data) {
ScopeLogger("characteristic: [%p], len: [%d], user_data: [%p]", characteristic, length,
user_data);
~BluetoothGATTClientService();
common::PlatformResult GetSpecifiedGATTClient(const std::string& address, const UUID& uuid,
- picojson::object* result);
+ picojson::object* result);
void TryDestroyClient(const std::string& address);
void GetServices(const picojson::value& data, picojson::object& out);
ReportSuccess(out);
}
+void BluetoothGATTServer::SetReadValueRequestCallback(const picojson::value& args,
+ picojson::object& out) {
+ ScopeLogger();
+
+ auto result = service_.SetReadValueRequestCallback(args);
+
+ if (result.IsError()) {
+ ReportError(result, &out);
+ return;
+ }
+
+ ReportSuccess(out);
+}
+
+void BluetoothGATTServer::SendResponse(const picojson::value& args, picojson::object& out) {
+ ScopeLogger();
+
+ auto result = service_.SendResponse(args);
+
+ if (result.IsError()) {
+ ReportError(result, &out);
+ return;
+ }
+
+ ReportSuccess(out);
+}
+
bool BluetoothGATTServer::IsRunning() {
return running_;
}
void GetConnectionMtu(const picojson::value& args, picojson::object& out);
void RegisterService(const picojson::value& args, picojson::object& out);
void UnregisterService(const picojson::value& args, picojson::object& out);
+ void SetReadValueRequestCallback(const picojson::value& args, picojson::object& out);
+ void SendResponse(const picojson::value& args, picojson::object& out);
bool IsRunning();
static bool DestroyService(int total, int index, bt_gatt_h handle, void* user_data);
#include "bluetooth/bluetooth_gatt_server.h"
#include "bluetooth/bluetooth_gatt_server_service.h"
+#include "bluetooth/bluetooth_instance.h"
#include "bluetooth/bluetooth_util.h"
#include "bluetooth/uuid.h"
const std::string kId = "_id";
const std::string kIdsToRemoveFromNativeLayer = "idsToRemoveFromNativeLayer";
+const std::string kClientAddress = "clientAddress";
+const std::string kRequestId = "requestId";
+const std::string kOffset = "offset";
+const std::string kRequestType = "requestType";
+const std::string kReadRequestType = "readRequestType";
+const std::string kWriteRequestType = "writeRequestType";
+const std::string kStatusCode = "statusCode";
+const std::string kData = "data";
int GetPermissionsInt(const picojson::value& permissions) {
ScopeLogger("permissions: %s", permissions.serialize().c_str());
return true;
}
-BluetoothGATTServerService::BluetoothGATTServerService() {
+
+BluetoothGATTServerService::BluetoothGATTServerService(BluetoothInstance& instance)
+ : instance_{instance}, rw_request_callback_data_{instance, callback_names_} {
ScopeLogger();
}
auto ids_to_remove = args.get(kIdsToRemoveFromNativeLayer).get<picojson::array>();
for (const auto& to_remove : ids_to_remove) {
- int id_to_remove = static_cast<int>(to_remove.get<double>());
+ const auto id_to_remove = static_cast<int>(to_remove.get<double>());
+
+ auto handle_to_remove = gatt_objects_[id_to_remove];
LoggerD("Erasing gatt object with _id: %d", id_to_remove);
+ callback_names_.erase(handle_to_remove);
gatt_objects_.erase(id_to_remove);
}
return common::PlatformResult{};
}
+PlatformResult BluetoothGATTServerService::SetReadValueRequestCallback(
+ const picojson::value& args) {
+ ScopeLogger();
+
+ auto _id = static_cast<int>(args.get(kId).get<double>());
+ LoggerD("Setting read value request callback for a GATT entity with _id: %d", _id);
+
+ auto gatt_handle = gatt_objects_[_id];
+ callback_names_[gatt_handle] = "ReadValueRequestCallback_" + std::to_string(_id);
+
+ auto read_value_request_callback = [](const char* remote_address, int request_id,
+ bt_gatt_server_h server, bt_gatt_h gatt_handle, int offset,
+ void* user_data) -> void {
+ ScopeLogger("ReadValueRequestCallback called. remote_address: %s, request_id: %d, offset: %d",
+ remote_address, request_id, offset);
+ auto rw_callback_data = static_cast<ReadWriteRequestCallbackData*>(user_data);
+
+ rw_callback_data->instance_.GetWorker().add_job(
+ [remote_address, request_id, server, gatt_handle, offset, rw_callback_data] {
+ ScopeLogger("Async call: SetReadValueRequestCallback");
+
+ auto read_value_request = picojson::value{picojson::object{}};
+ auto& read_value_request_obj = read_value_request.get<picojson::object>();
+ read_value_request_obj[kClientAddress] = picojson::value{remote_address};
+ read_value_request_obj[kRequestId] = picojson::value{static_cast<double>(request_id)};
+ read_value_request_obj[kRequestType] = picojson::value{kReadRequestType};
+ read_value_request_obj[kOffset] = picojson::value{static_cast<double>(offset)};
+ const auto callback_name = rw_callback_data->callback_names_map_[gatt_handle];
+ LoggerD("Firing read value request event: %s: %s", callback_name.c_str(),
+ read_value_request.serialize().c_str());
+ rw_callback_data->instance_.FireEvent(callback_name, read_value_request);
+ });
+ };
+
+ auto ret = bt_gatt_server_set_read_value_requested_cb(gatt_handle, read_value_request_callback,
+ &rw_request_callback_data_);
+ if (BT_ERROR_NONE != ret) {
+ LoggerE("bt_gatt_server_set_read_value_requested_cb() failed: %d (%s)", ret,
+ get_error_message(ret));
+ return BluetoothErrorToPlatformResult(ret, "Failed to set read value request callback");
+ }
+
+ LoggerD("bt_gatt_server_set_read_value_requested_cb(): SUCCESS");
+ return common::PlatformResult{};
+}
+
+PlatformResult BluetoothGATTServerService::SendResponse(const picojson::value& args) {
+ ScopeLogger();
+
+ auto _id = static_cast<int>(args.get(kId).get<double>());
+ auto request_id = static_cast<int>(args.get(kRequestId).get<double>());
+ auto request_type_str = args.get(kRequestType).get<std::string>();
+ auto request_type = (request_type_str == kReadRequestType) ? BT_GATT_REQUEST_TYPE_READ
+ : BT_GATT_REQUEST_TYPE_WRITE;
+ auto offset = static_cast<int>(args.get(kOffset).get<double>());
+ auto status_code = static_cast<int>(args.get(kStatusCode).get<double>());
+
+ std::unique_ptr<char[]> value{nullptr};
+ int value_size = 0;
+ if (args.get(kData).is<picojson::array>()) {
+ auto value_octets = args.get(kData).get<picojson::array>();
+ value_size = value_octets.size();
+ value = std::make_unique<char[]>(value_size);
+ for (int i = 0; i < value_size; ++i) {
+ value[i] += static_cast<int>(value_octets[i].get<double>());
+ }
+ } else {
+ LoggerD("No data!");
+ }
+
+ LoggerD(
+ "Sending response: _id: %d, requestId: %d, requestType: %s, offset: %d, statusCode: %d, "
+ "value: [%s], value size: %d",
+ _id, request_id, request_type_str.c_str(), offset, status_code, value.get(), value_size);
+
+ auto ret = bt_gatt_server_send_response(request_id, request_type, offset, status_code,
+ value.get(), value_size);
+ if (BT_ERROR_NONE != ret) {
+ LoggerE("bt_gatt_server_send_response() failed: %d (%s)", ret, get_error_message(ret));
+ return BluetoothErrorToPlatformResult(ret, "Failed to send response");
+ }
+ LoggerD("bt_gatt_server_send_response(): SUCCESS");
+
+ return common::PlatformResult{};
+}
+
} // namespace bluetooth
} // namespace extension
#define BLUETOOTH_BLUETOOTH_GATT_SERVER_SERVICE_H_
#include <map>
+#include <string>
#include <vector>
#include <bluetooth.h>
class BluetoothGATTServerService {
public:
- BluetoothGATTServerService();
+ BluetoothGATTServerService(BluetoothInstance& instance);
~BluetoothGATTServerService();
PlatformResult CreateService(const picojson::value& args, bt_gatt_h* new_service_handle,
PlatformResult RegisterService(bt_gatt_h service_handle, bt_gatt_server_h server,
const std::vector<std::pair<int, bt_gatt_h>>& new_gatt_objects);
PlatformResult UnregisterService(const picojson::value& args, bt_gatt_server_h server);
+ PlatformResult SetReadValueRequestCallback(const picojson::value& args);
+ PlatformResult SendResponse(const picojson::value& args);
private:
std::map<int, bt_gatt_h> gatt_objects_;
+ std::map<bt_gatt_h, std::string> callback_names_;
+
+ BluetoothInstance& instance_;
+
+ struct ReadWriteRequestCallbackData {
+ BluetoothInstance& instance_;
+ std::map<bt_gatt_h, std::string>& callback_names_map_;
+ } rw_request_callback_data_;
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);
bluetooth_le_adapter_(*this),
bluetooth_gatt_client_service_(*this),
bluetooth_le_device_(*this, bluetooth_gatt_client_service_),
- bluetooth_gatt_server_service_(),
+ bluetooth_gatt_server_service_(*this),
worker(),
bluetooth_gatt_server_(*this, bluetooth_gatt_server_service_) {
ScopeLogger();
REGISTER_METHOD(BluetoothGATTServerGetConnectionMtu);
REGISTER_METHOD(BluetoothGATTServerRegisterService);
REGISTER_METHOD(BluetoothGATTServerUnregisterService);
+ REGISTER_METHOD(BluetoothGATTServerSetReadValueRequestCallback);
+ REGISTER_METHOD(BluetoothGATTServerSendResponse);
#undef REGISTER_METHOD
}
FireEvent(event, *value.get());
}
+common::Worker& BluetoothInstance::GetWorker() {
+ return worker;
+}
+
void BluetoothInstance::BluetoothAdapterSetName(const picojson::value& args,
picojson::object& out) {
ScopeLogger();
ReportSuccess(out);
}
+void BluetoothInstance::BluetoothGATTServerSetReadValueRequestCallback(const picojson::value& args,
+ picojson::object& out) {
+ ScopeLogger();
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeBluetooth, &out);
+
+ worker.add_job([this, args] {
+ ScopeLogger("Async call: BluetoothGATTServerSetReadValueRequestCallback");
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& async_out = response.get<picojson::object>();
+ double callback_id = args.get("callbackId").get<double>();
+ async_out["callbackId"] = picojson::value(callback_id);
+ this->bluetooth_gatt_server_.SetReadValueRequestCallback(args, async_out);
+ this->PostMessage(response.serialize().c_str());
+ });
+
+ ReportSuccess(out);
+}
+
+void BluetoothInstance::BluetoothGATTServerSendResponse(const picojson::value& args,
+ picojson::object& out) {
+ ScopeLogger();
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeBluetooth, &out);
+
+ worker.add_job([this, args] {
+ ScopeLogger("Async call: BluetoothGATTServerSendSyncResponse");
+ picojson::value response = picojson::value(picojson::object());
+ picojson::object& async_out = response.get<picojson::object>();
+ double callback_id = args.get("callbackId").get<double>();
+ async_out["callbackId"] = picojson::value(callback_id);
+ this->bluetooth_gatt_server_.SendResponse(args, async_out);
+ this->PostMessage(response.serialize().c_str());
+ });
+
+ ReportSuccess(out);
+}
+
} // namespace bluetooth
} // namespace extension
void FireEvent(const std::string& event, const picojson::value& value);
void FireEvent(const std::string& event, const std::shared_ptr<picojson::value>& value);
+ common::Worker& GetWorker();
+
private:
void BluetoothAdapterSetName(const picojson::value& args, picojson::object& out);
void BluetoothAdapterSetPowered(const picojson::value& args, picojson::object& out);
void BluetoothGATTServerGetConnectionMtu(const picojson::value& args, picojson::object& out);
void BluetoothGATTServerRegisterService(const picojson::value& args, picojson::object& out);
void BluetoothGATTServerUnregisterService(const picojson::value& args, picojson::object& out);
+ void BluetoothGATTServerSetReadValueRequestCallback(const picojson::value& args,
+ picojson::object& out);
+ void BluetoothGATTServerSendResponse(const picojson::value& args, picojson::object& out);
BluetoothAdapter bluetooth_adapter_;
BluetoothDevice bluetooth_device_;
const char* kAddress = "address";
}
-BluetoothLEDevice::BluetoothLEDevice(BluetoothInstance& instance, BluetoothGATTClientService& 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);