);
}
+function _createWriteValueRequestCallback(
+ _id,
+ sendResponseSuccessCallback,
+ sendResponseErrorCallback
+) {
+ return _singleListenerBuilder(
+ 'WriteValueRequestCallback_' + _id,
+ /*
+ * _singleListenerBuilder requires 2 callbacks, the second of which
+ * is an error callback.
+ * Write value request events coming from the native layer
+ * are never errors.
+ * Hence, we don't use the second callback here.
+ */
+ function(event, writeValueRequestCallback, unusedErrorCallback) {
+ var clientAddress = event.clientAddress;
+ var value = event.value;
+ var offset = event.offset;
+ var replyRequired = event.replyRequired;
+
+ if (writeValueRequestCallback) {
+ var requestReply = writeValueRequestCallback(
+ clientAddress,
+ BluetoothManager_toByteArray(value),
+ offset,
+ replyRequired
+ );
+ var response = {
+ _id: _id,
+ requestId: event.requestId,
+ requestType: event.requestType,
+ value: null, // Responses to write requests don't contain value
+ offset: offset,
+ statusCode: requestReply.statusCode,
+ data: requestReply.data
+ };
+ 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 = {};
var _setReadValueRequestCallbackCommon = function() {
}
};
+var _setWriteValueRequestCallbackCommon = function() {
+ var args = AV.validateArgs(arguments, [
+ {
+ name: 'writeValueRequestCallback',
+ 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 entityId = this._id;
+
+ var callback = function(result) {
+ if (native.isFailure(result)) {
+ native.callIfPossible(args.errorCallback, native.getErrorObject(result));
+ } else {
+ var writeValueRequestCallback = _createWriteValueRequestCallback(
+ entityId,
+ args.sendResponseSuccessCallback,
+ args.sendResponseErrorCallback
+ );
+ writeValueRequestCallback.addListener(
+ args.writeValueRequestCallback,
+ function unusedErrorCallback() {
+ /* Intentionally no operation */
+ }
+ );
+ _BluetoothGATTServerReadWriteValueRequestCallbacks[
+ 'WriteValueCallback' + entityId
+ ] = writeValueRequestCallback;
+ native.callIfPossible(args.successCallback, native.getErrorObject(result));
+ }
+ };
+
+ var callArgs = { _id: this._id };
+ var result = native.call(
+ 'BluetoothGATTServerSetWriteValueRequestCallback',
+ callArgs,
+ callback
+ );
+
+ if (native.isFailure(result)) {
+ throw native.getErrorObject(result);
+ }
+};
+
BluetoothGATTServerCharacteristic.prototype.setReadValueRequestCallback = _setReadValueRequestCallbackCommon;
+BluetoothGATTServerCharacteristic.prototype.setWriteValueRequestCallback = _setWriteValueRequestCallbackCommon;
/**
* Creates a manager for specified listener event. Manager handles multiple
});
BluetoothGATTServerDescriptor.prototype.setReadValueRequestCallback = _setReadValueRequestCallbackCommon;
+BluetoothGATTServerDescriptor.prototype.setWriteValueRequestCallback = _setWriteValueRequestCallbackCommon;
// class BluetoothAdapter ///////////////////////////
var BluetoothAdapter = function() {
ReportSuccess(out);
}
+void BluetoothGATTServer::SetWriteValueRequestCallback(const picojson::value& args,
+ picojson::object& out) {
+ ScopeLogger();
+
+ auto result = service_.SetWriteValueRequestCallback(args);
+
+ if (result.IsError()) {
+ ReportError(result, &out);
+ return;
+ }
+
+ ReportSuccess(out);
+}
+
void BluetoothGATTServer::SendResponse(const picojson::value& args, picojson::object& out) {
ScopeLogger();
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 SetWriteValueRequestCallback(const picojson::value& args, picojson::object& out);
void SendResponse(const picojson::value& args, picojson::object& out);
bool IsRunning();
const std::string kIdsToRemoveFromNativeLayer = "idsToRemoveFromNativeLayer";
const std::string kClientAddress = "clientAddress";
const std::string kRequestId = "requestId";
+const std::string kValue = "value";
const std::string kOffset = "offset";
+const std::string kReplyRequired = "replyRequired";
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";
+const std::string kReadCallback = "readCallback";
+const std::string kWriteCallback = "writeCallback";
int GetPermissionsInt(const picojson::value& permissions) {
ScopeLogger("permissions: %s", permissions.serialize().c_str());
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);
+ callback_names_.erase(std::make_pair(handle_to_remove, kReadCallback));
+ callback_names_.erase(std::make_pair(handle_to_remove, kWriteCallback));
gatt_objects_.erase(id_to_remove);
}
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);
+ callback_names_[std::make_pair(gatt_handle, kReadCallback)] =
+ "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,
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];
+ const auto callback_name =
+ rw_callback_data->callback_names_map_[std::make_pair(gatt_handle, kReadCallback)];
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);
return common::PlatformResult{};
}
-PlatformResult BluetoothGATTServerService::SendResponse(const picojson::value& args) {
+PlatformResult BluetoothGATTServerService::SetWriteValueRequestCallback(
+ const picojson::value& args) {
ScopeLogger();
auto _id = static_cast<int>(args.get(kId).get<double>());
+ LoggerD("Setting write value request callback for a GATT entity with _id: %d", _id);
+
+ auto gatt_handle = gatt_objects_[_id];
+ callback_names_[std::make_pair(gatt_handle, kWriteCallback)] =
+ "WriteValueRequestCallback_" + std::to_string(_id);
+
+ auto write_value_request_callback = [](
+ const char* remote_address, int request_id, bt_gatt_server_h server, bt_gatt_h gatt_handle,
+ bool response_needed, int offset, const char* value, int len, void* user_data) -> void {
+ ScopeLogger(
+ "WriteValueRequestCallback called. remote_address: %s, request_id: %d, response_needed: "
+ "%d, offset: %d, value: %s, len: %d",
+ remote_address, request_id, response_needed, offset, value, len);
+ auto rw_callback_data = static_cast<ReadWriteRequestCallbackData*>(user_data);
+
+ // We create a copy of value and remote_address
+ 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] {
+ ScopeLogger("Async call: SetWriteValueRequestCallback");
+
+ auto write_value_request = picojson::value{picojson::object{}};
+ auto& write_value_request_obj = write_value_request.get<picojson::object>();
+ write_value_request_obj[kClientAddress] = picojson::value{remote_address_copy};
+ write_value_request_obj[kRequestId] = picojson::value{static_cast<double>(request_id)};
+ write_value_request_obj[kRequestType] = picojson::value{kWriteRequestType};
+ write_value_request_obj[kReplyRequired] = picojson::value{response_needed};
+ write_value_request_obj[kOffset] = picojson::value{static_cast<double>(offset)};
+
+ 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) {
+ value_byte_array.push_back(picojson::value{static_cast<double>(c)});
+ }
+ const auto callback_name =
+ rw_callback_data->callback_names_map_[std::make_pair(gatt_handle, kWriteCallback)];
+ LoggerD("Firing write value request event: %s: %s", callback_name.c_str(),
+ write_value_request.serialize().c_str());
+ rw_callback_data->instance_.FireEvent(callback_name, write_value_request);
+ });
+ };
+
+ auto ret = bt_gatt_server_set_write_value_requested_cb(gatt_handle, write_value_request_callback,
+ &rw_request_callback_data_);
+ if (BT_ERROR_NONE != ret) {
+ LoggerE("bt_gatt_server_set_write_value_requested_cb() failed: %d (%s)", ret,
+ get_error_message(ret));
+ return BluetoothErrorToPlatformResult(ret, "Failed to set write value request callback");
+ }
+
+ LoggerD("bt_gatt_server_set_write_value_requested_cb(): SUCCESS");
+ return common::PlatformResult{};
+}
+
+PlatformResult BluetoothGATTServerService::SendResponse(const picojson::value& args) {
+ ScopeLogger("Response: %s", args.serialize().c_str());
+
+ 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
LoggerD(
"Sending response: _id: %d, requestId: %d, requestType: %s, offset: %d, statusCode: %d, "
- "value: [%s], value size: %d",
+ "value: [%p], 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,
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 SetWriteValueRequestCallback(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_;
+ std::map<std::pair<bt_gatt_h, std::string>, std::string> callback_names_;
BluetoothInstance& instance_;
struct ReadWriteRequestCallbackData {
BluetoothInstance& instance_;
- std::map<bt_gatt_h, std::string>& callback_names_map_;
+ std::map<std::pair<bt_gatt_h, std::string>, std::string>& callback_names_map_;
} rw_request_callback_data_;
static bool DestroyService(int total, int index, bt_gatt_h handle, void* user_data);
REGISTER_METHOD(BluetoothGATTServerRegisterService);
REGISTER_METHOD(BluetoothGATTServerUnregisterService);
REGISTER_METHOD(BluetoothGATTServerSetReadValueRequestCallback);
+ REGISTER_METHOD(BluetoothGATTServerSetWriteValueRequestCallback);
REGISTER_METHOD(BluetoothGATTServerSendResponse);
#undef REGISTER_METHOD
ReportSuccess(out);
}
+void BluetoothInstance::BluetoothGATTServerSetWriteValueRequestCallback(const picojson::value& args,
+ picojson::object& out) {
+ ScopeLogger();
+ CHECK_PRIVILEGE_ACCESS(kPrivilegeBluetooth, &out);
+
+ worker.add_job([this, args] {
+ ScopeLogger("Async call: BluetoothGATTServerSetWriteValueRequestCallback");
+ 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_.SetWriteValueRequestCallback(args, async_out);
+ this->PostMessage(response.serialize().c_str());
+ });
+
+ ReportSuccess(out);
+}
+
void BluetoothInstance::BluetoothGATTServerSendResponse(const picojson::value& args,
picojson::object& out) {
ScopeLogger();
void BluetoothGATTServerUnregisterService(const picojson::value& args, picojson::object& out);
void BluetoothGATTServerSetReadValueRequestCallback(const picojson::value& args,
picojson::object& out);
+ void BluetoothGATTServerSetWriteValueRequestCallback(const picojson::value& args,
+ picojson::object& out);
void BluetoothGATTServerSendResponse(const picojson::value& args, picojson::object& out);
BluetoothAdapter bluetooth_adapter_;