mirror of
https://github.com/kidfromjupiter/nearby.git
synced 2026-09-15 15:16:12 -04:00
245 lines
9.2 KiB
C++
245 lines
9.2 KiB
C++
// Copyright 2023 Google LLC
|
|
//
|
|
// 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
|
|
//
|
|
// https://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 <sdbus-c++/Error.h>
|
|
#include <sdbus-c++/MethodResult.h>
|
|
#include <sdbus-c++/Types.h>
|
|
|
|
#include "internal/platform/byte_array.h"
|
|
#include "internal/platform/implementation/ble.h"
|
|
#include "internal/platform/implementation/linux/bluez_gatt_characteristic_server.h"
|
|
#include "internal/platform/logging.h"
|
|
|
|
namespace nearby {
|
|
namespace linux {
|
|
namespace bluez {
|
|
void GattCharacteristicServer::Update(const nearby::ByteArray &value) {
|
|
std::vector<uint8_t> bytes(value.size());
|
|
const auto *buf = value.data();
|
|
for (auto i = 0; i < value.size(); i++) bytes[i] = buf[i];
|
|
|
|
absl::MutexLock static_value_lock(&static_value_mutex_);
|
|
static_value_ = std::move(bytes);
|
|
}
|
|
|
|
absl::Status GattCharacteristicServer::NotifyChanged(
|
|
bool confirm, const ByteArray &new_value) {
|
|
std::vector<uint8_t> bytes(new_value.size());
|
|
const auto *buf = new_value.data();
|
|
for (auto i = 0; i < new_value.size(); i++) bytes[i] = buf[i];
|
|
|
|
{
|
|
absl::MutexLock lock(&cached_value_mutex_);
|
|
cached_value_ = bytes;
|
|
}
|
|
|
|
if (confirm) {
|
|
auto confirmed = [&]() {
|
|
confirmed_mutex_.AssertReaderHeld();
|
|
return confirmed_;
|
|
};
|
|
{
|
|
absl::MutexLock lock(&confirmed_mutex_);
|
|
confirmed_ = false;
|
|
}
|
|
absl::ReaderMutexLock lock(&confirmed_mutex_, absl::Condition(&confirmed));
|
|
}
|
|
|
|
try {
|
|
emitPropertiesChangedSignal(sdbus::InterfaceName(GattCharacteristic1_adaptor::INTERFACE_NAME),
|
|
{sdbus::PropertyName("Value")});
|
|
return absl::OkStatus();
|
|
} catch (const sdbus::Error &e) {
|
|
LOG(ERROR) << __func__
|
|
<< ": Error emitting PropertiesChanged signal on "
|
|
<< getObject().getObjectPath() << " with name '"
|
|
<< e.getName() << "' and message '" << e.getMessage()
|
|
<< "'";
|
|
return absl::UnknownError(e.getMessage());
|
|
}
|
|
}
|
|
|
|
void GattCharacteristicServer::ReadValue(
|
|
sdbus::Result<std::vector<uint8_t>> &&result,
|
|
std::map<std::string, sdbus::Variant> options) {
|
|
{
|
|
absl::ReaderMutexLock static_value_lock(&static_value_mutex_);
|
|
if (static_value_.has_value()) {
|
|
result.returnResults(*static_value_);
|
|
|
|
absl::MutexLock cached_value_lock(&cached_value_mutex_);
|
|
cached_value_ = *static_value_;
|
|
return;
|
|
}
|
|
}
|
|
|
|
uint16_t offset = options["offset"].get<uint16_t>();
|
|
sdbus::ObjectPath device_path = options["device"].get<sdbus::ObjectPath>();
|
|
|
|
auto device = devices_->get_device_by_path(device_path);
|
|
if (device == nullptr) {
|
|
result.returnError(
|
|
sdbus::Error(sdbus::Error::Name("org.bluez.Error.NotAuthorized"), "device does not exist"));
|
|
return;
|
|
}
|
|
auto characteristic = characteristic_;
|
|
// TODO: enable the callback
|
|
// server_cb_->on_characteristic_read_cb(
|
|
// *device, characteristic, static_cast<int>(offset),
|
|
// [result = std::move(result),
|
|
// this](absl::StatusOr<absl::string_view> data) {
|
|
// const auto &status = data.status();
|
|
// if (status.ok()) {
|
|
// auto str = data.value();
|
|
// std::vector<uint8_t> bytes(str.size());
|
|
// for (auto i = 0; i < str.size(); i++) {
|
|
// bytes[i] = str[i];
|
|
// }
|
|
// result.returnResults(bytes);
|
|
//
|
|
// absl::MutexLock lock(&cached_value_mutex_);
|
|
// cached_value_ = bytes;
|
|
// } else if (absl::IsPermissionDenied(status)) {
|
|
// result.returnError(sdbus::Error("org.bluez.Error.NotPermitted",
|
|
// std::string(status.message())));
|
|
// } else if (absl::IsUnauthenticated(status)) {
|
|
// result.returnError(sdbus::Error("org.bluez.Error.NotAuthorized",
|
|
// std::string(status.message())));
|
|
// } else if (absl::IsOutOfRange(status)) {
|
|
// result.returnError(sdbus::Error("org.bluez.Error.InvalidOffset",
|
|
// std::string(status.message())));
|
|
// } else if (absl::IsUnimplemented(status)) {
|
|
// result.returnError(sdbus::Error("org.bluez.Error.NotSupported",
|
|
// std::string(status.message())));
|
|
// } else {
|
|
// result.returnError(sdbus::Error("org.bluez.Error.Failed",
|
|
// std::string(status.message())));
|
|
// }
|
|
// });
|
|
}
|
|
|
|
void GattCharacteristicServer::WriteValue(
|
|
sdbus::Result<> &&result, std::vector<uint8_t> value,
|
|
std::map<std::string, sdbus::Variant> options) {
|
|
uint16_t offset = options["offset"].get<uint16_t>();
|
|
sdbus::ObjectPath device_path = options["device"].get<sdbus::ObjectPath>();
|
|
|
|
auto device = devices_->get_device_by_path(device_path);
|
|
if (device == nullptr) {
|
|
result.returnError(
|
|
sdbus::Error(sdbus::Error::Name("org.bluez.Error.NotAuthorized"), "device does not exist"));
|
|
return;
|
|
}
|
|
std::string type = options["type"].get<std::string>();
|
|
|
|
std::string data(value.begin(), value.end());
|
|
auto characteristic = characteristic_;
|
|
|
|
// TODO: enable the callback
|
|
// TODO: Support writes without response.
|
|
// server_cb_->on_characteristic_write_cb(
|
|
// *device, characteristic, static_cast<int>(offset), data,
|
|
// [result = std::move(result)](absl::Status status) {
|
|
// if (status.ok()) {
|
|
// result.returnResults();
|
|
// } else if (absl::IsPermissionDenied(status)) {
|
|
// result.returnError(sdbus::Error("org.bluez.Error.NotPermitted",
|
|
// std::string(status.message())));
|
|
// } else if (absl::IsUnauthenticated(status)) {
|
|
// result.returnError(sdbus::Error("org.bluez.Error.NotAuthorized",
|
|
// std::string(status.message())));
|
|
// } else if (absl::IsOutOfRange(status)) {
|
|
// result.returnError(sdbus::Error("org.bluez.Error.InvalidOffset",
|
|
// std::string(status.message())));
|
|
// } else if (absl::IsUnimplemented(status)) {
|
|
// result.returnError(sdbus::Error("org.bluez.Error.NotSupported",
|
|
// std::string(status.message())));
|
|
// } else {
|
|
// result.returnError(sdbus::Error("org.bluez.Error.Failed",
|
|
// std::string(status.message())));
|
|
// }
|
|
// });
|
|
}
|
|
|
|
void GattCharacteristicServer::StartNotify() {
|
|
if ((characteristic_.property |
|
|
api::ble::GattCharacteristic::Property::kNotify) ==
|
|
api::ble::GattCharacteristic::Property::kNotify) {
|
|
if (notify_sessions_.fetch_add(1) == 0) {
|
|
if (server_cb_->characteristic_subscription_cb != nullptr) {
|
|
server_cb_->characteristic_subscription_cb(characteristic_);
|
|
}
|
|
notifying_ = true;
|
|
}
|
|
} else {
|
|
throw(sdbus::Error(sdbus::Error::Name("org.bluez.Error.NotSupported")));
|
|
}
|
|
}
|
|
|
|
void GattCharacteristicServer::StopNotify() {
|
|
if ((characteristic_.property |
|
|
api::ble::GattCharacteristic::Property::kNotify) ==
|
|
api::ble::GattCharacteristic::Property::kNotify) {
|
|
if (notify_sessions_.load() == 0) {
|
|
return;
|
|
}
|
|
if (notify_sessions_.fetch_sub(1) == 1) {
|
|
if (server_cb_->characteristic_unsubscription_cb != nullptr) {
|
|
server_cb_->characteristic_unsubscription_cb(characteristic_);
|
|
}
|
|
notifying_ = false;
|
|
}
|
|
} else {
|
|
throw(sdbus::Error(sdbus::Error::Name("org.bluez.Error.Failed")));
|
|
}
|
|
}
|
|
|
|
std::vector<std::string> GattCharacteristicServer::Flags() {
|
|
auto characteristic = characteristic_;
|
|
std::vector<std::string> flags;
|
|
|
|
if ((characteristic.permission &
|
|
api::ble::GattCharacteristic::Permission::kRead) ==
|
|
api::ble::GattCharacteristic::Permission::kRead ||
|
|
(characteristic.property &
|
|
api::ble::GattCharacteristic::Property::kRead) ==
|
|
api::ble::GattCharacteristic::Property::kRead)
|
|
flags.push_back("read");
|
|
|
|
if ((characteristic.permission &
|
|
api::ble::GattCharacteristic::Permission::kWrite) ==
|
|
api::ble::GattCharacteristic::Permission::kWrite ||
|
|
(characteristic.property &
|
|
api::ble::GattCharacteristic::Property::kWrite) ==
|
|
api::ble::GattCharacteristic::Property::kWrite) {
|
|
flags.push_back("write");
|
|
flags.push_back("write-without-response");
|
|
}
|
|
|
|
if ((characteristic.property &
|
|
api::ble::GattCharacteristic::Property::kIndicate) ==
|
|
api::ble::GattCharacteristic::Property::kIndicate)
|
|
flags.push_back("indicate");
|
|
|
|
if ((characteristic.property &
|
|
api::ble::GattCharacteristic::Property::kNotify) ==
|
|
api::ble::GattCharacteristic::Property::kNotify)
|
|
flags.push_back("notify");
|
|
|
|
return flags;
|
|
}
|
|
} // namespace bluez
|
|
} // namespace linux
|
|
} // namespace nearby
|