11#include <QtCore/QLoggingCategory>
12#include <QtDBus/QDBusConnection>
16Q_DECLARE_LOGGING_CATEGORY(QT_BT_BLUEZ)
18using namespace Qt::StringLiterals;
19using namespace QtBluetoothPrivate;
37QtBluezPeripheralGattObject::QtBluezPeripheralGattObject(
const QString& objectPath,
38 const QString& uuid, QLowEnergyHandle handle, QObject* parent)
39 : QObject(parent), objectPath(objectPath), uuid(uuid), handle(handle),
40 propertiesAdaptor(
new OrgFreedesktopDBusPropertiesAdaptor(
this))
43QtBluezPeripheralGattObject::~QtBluezPeripheralGattObject()
48bool QtBluezPeripheralGattObject::registerObject()
53 if (QDBusConnection::systemBus().registerObject(objectPath,
this)) {
54 qCDebug(QT_BT_BLUEZ) <<
"Registered object on DBus:" << objectPath << uuid;
58 qCWarning(QT_BT_BLUEZ) <<
"Failed to register object on DBus:" << objectPath << uuid;
63void QtBluezPeripheralGattObject::unregisterObject()
67 QDBusConnection::systemBus().unregisterObject(objectPath);
68 qCDebug(QT_BT_BLUEZ) <<
"Unregistered object on DBus:" << objectPath << uuid;
72void QtBluezPeripheralGattObject::accessEvent(
const QVariantMap& options)
75 const auto remoteDevice = options.value(
"device"_L1).value<QDBusObjectPath>().path();
76 if (!remoteDevice.isEmpty())
77 emit remoteDeviceAccessEvent(remoteDevice, options.value(
"mtu"_L1).toUInt());
80QtBluezPeripheralDescriptor::QtBluezPeripheralDescriptor(
81 const QLowEnergyDescriptorData& descriptorData,
82 const QString& characteristicPath, quint16 ordinal,
83 QLowEnergyHandle handle, QLowEnergyHandle characteristicHandle,
85 : QtBluezPeripheralGattObject(descriptorPathTemplate.arg(characteristicPath).arg(ordinal),
86 descriptorData.uuid().toString(QUuid::WithoutBraces), handle, parent),
87 m_adaptor(
new OrgBluezGattDescriptor1Adaptor(
this)),
88 m_characteristicPath(characteristicPath),
89 m_characteristicHandle(characteristicHandle)
91 if (descriptorData.value().size() > maximumAttributeLength) {
92 qCWarning(QT_BT_BLUEZ) <<
"Descriptor value is too large, cropping it to"
93 << maximumAttributeLength;
94 m_value = descriptorData.value().sliced(0, maximumAttributeLength);
96 m_value = descriptorData.value();
98 initializeFlags(descriptorData);
101InterfaceList QtBluezPeripheralDescriptor::properties()
const
104 properties.insert(bluezDescriptorInterface,
107 {
"Characteristic"_L1, QDBusObjectPath(m_characteristicPath)},
108 {
"Flags"_L1, m_flags}
115QByteArray QtBluezPeripheralDescriptor::ReadValue(
const QVariantMap &options, QString& error)
117 accessEvent(options);
122 const quint16 offset = options.value(
"offset"_L1).toUInt();
123 const quint16 mtu = options.value(
"mtu"_L1).toUInt();
125 if (offset > m_value.length() - 1) {
126 qCWarning(QT_BT_BLUEZ) <<
"Invalid offset" << offset <<
", value len:" << m_value.length();
127 error = bluezErrorInvalidOffset;
132 return m_value.mid(offset, mtu);
139QString QtBluezPeripheralDescriptor::WriteValue(
const QByteArray &value,
140 const QVariantMap &options)
142 accessEvent(options);
144 if (options.value(
"prepare-authorize"_L1).toBool()) {
146 qCWarning(QT_BT_BLUEZ) <<
"Descriptor write requires authorization."
147 <<
"The client device needs to be trusted beforehand";
148 return bluezErrorNotAuthorized;
151 if (value.size() > maximumAttributeLength) {
152 qCWarning(QT_BT_BLUEZ) <<
"Descriptor value is too large:" << value.size();
153 return bluezErrorInvalidValueLength;
156 emit valueUpdatedByRemote(m_characteristicHandle, handle, value);
161bool QtBluezPeripheralDescriptor::localValueUpdate(
const QByteArray& value)
163 if (value.size() > maximumAttributeLength) {
164 qCWarning(QT_BT_BLUEZ) <<
"Descriptor value is too large:" << value.size();
171void QtBluezPeripheralDescriptor::initializeFlags(
const QLowEnergyDescriptorData& data)
174 if (data.isReadable())
175 m_flags.append(
"read"_L1);
176 if (data.readConstraints() & QBluetooth::AttAccessConstraint::AttEncryptionRequired)
177 m_flags.append(
"encrypt-read"_L1);
178 if (data.readConstraints() & QBluetooth::AttAccessConstraint::AttAuthenticationRequired)
179 m_flags.append(
"encrypt-authenticated-read"_L1);
181 if (data.isWritable())
182 m_flags.append(
"write"_L1);
183 if (data.writeConstraints() & QBluetooth::AttAccessConstraint::AttEncryptionRequired)
184 m_flags.append(
"encrypt-write"_L1);
185 if (data.writeConstraints() & QBluetooth::AttAccessConstraint::AttAuthenticationRequired)
186 m_flags.append(
"encrypt-authenticated-write"_L1);
188 if (data.readConstraints() & QBluetooth::AttAccessConstraint::AttAuthorizationRequired
189 || data.writeConstraints() & QBluetooth::AttAccessConstraint::AttAuthorizationRequired)
190 m_flags.append(
"authorize"_L1);
192 if (m_flags.isEmpty()) {
193 qCWarning(QT_BT_BLUEZ) <<
"Descriptor property flags not set" << uuid
194 <<
"Peripheral may fail to register";
198QtBluezPeripheralCharacteristic::QtBluezPeripheralCharacteristic(
199 const QLowEnergyCharacteristicData& characteristicData,
200 const QString& servicePath, quint16 ordinal,
201 QLowEnergyHandle handle, QObject* parent)
202 : QtBluezPeripheralGattObject(characteristicPathTemplate.arg(servicePath).arg(ordinal),
203 characteristicData.uuid().toString(QUuid::WithoutBraces), handle, parent),
204 m_adaptor(
new OrgBluezGattCharacteristic1Adaptor(
this)),
205 m_servicePath(servicePath),
206 m_minimumValueLength(std::min(characteristicData.minimumValueLength(),
207 maximumAttributeLength)),
208 m_maximumValueLength(std::min(characteristicData.maximumValueLength(),
209 maximumAttributeLength))
211 initializeFlags(characteristicData);
212 initializeValue(characteristicData.value());
215InterfaceList QtBluezPeripheralCharacteristic::properties()
const
218 properties.insert(bluezCharacteristicInterface,
221 {
"Service"_L1, QDBusObjectPath(m_servicePath)},
222 {
"Flags"_L1, m_flags}
229QByteArray QtBluezPeripheralCharacteristic::ReadValue(
const QVariantMap &options, QString& error)
231 accessEvent(options);
236 const quint16 offset = options.value(
"offset"_L1).toUInt();
237 const quint16 mtu = options.value(
"mtu"_L1).toUInt();
239 if (offset > m_value.length() - 1) {
240 qCWarning(QT_BT_BLUEZ) <<
"Invalid offset" << offset <<
", value len:" << m_value.length();
241 error = bluezErrorInvalidOffset;
246 return m_value.mid(offset, mtu);
253QString QtBluezPeripheralCharacteristic::WriteValue(
const QByteArray &value,
254 const QVariantMap &options)
256 accessEvent(options);
258 if (options.value(
"prepare-authorize"_L1).toBool()) {
260 qCWarning(QT_BT_BLUEZ) <<
"Characteristic write requires authorization."
261 <<
"The client device needs to be trusted beforehand";
262 return bluezErrorNotAuthorized;
265 if (value.size() < m_minimumValueLength || value.size() > m_maximumValueLength) {
266 qCWarning(QT_BT_BLUEZ) <<
"Characteristic value has invalid length" << value.size()
267 <<
"min:" << m_minimumValueLength
268 <<
"max:" << m_maximumValueLength;
269 return bluezErrorInvalidValueLength;
272 emit valueUpdatedByRemote(handle, value);
277bool QtBluezPeripheralCharacteristic::localValueUpdate(
const QByteArray& value)
279 if (value.size() < m_minimumValueLength || value.size() > m_maximumValueLength) {
280 qCWarning(QT_BT_BLUEZ) <<
"Characteristic value has invalid length" << value.size()
281 <<
"min:" << m_minimumValueLength
282 <<
"max:" << m_maximumValueLength;
287 emit propertiesAdaptor->PropertiesChanged(
288 bluezCharacteristicInterface, {{
"Value"_L1, m_value}}, {});
295void QtBluezPeripheralCharacteristic::StartNotify()
297 qCDebug(QT_BT_BLUEZ) <<
"NTF or IND enabled for characteristic" << uuid;
301void QtBluezPeripheralCharacteristic::StopNotify()
303 qCDebug(QT_BT_BLUEZ) <<
"NTF or IND disabled for characteristic" << uuid;
308void QtBluezPeripheralCharacteristic::initializeValue(
const QByteArray& value)
310 const auto valueSize = value.size();
311 if (valueSize < m_minimumValueLength || valueSize > m_maximumValueLength) {
312 qCWarning(QT_BT_BLUEZ) <<
"Characteristic value has invalid length" << valueSize
313 <<
"min:" << m_minimumValueLength
314 <<
"max:" << m_maximumValueLength;
315 m_value = QByteArray(m_minimumValueLength, 0);
321void QtBluezPeripheralCharacteristic::initializeFlags(
const QLowEnergyCharacteristicData& data)
324 if (data.properties() & QLowEnergyCharacteristic::PropertyType::Broadcasting)
325 m_flags.append(
"broadcast"_L1);
326 if (data.properties() & QLowEnergyCharacteristic::PropertyType::WriteNoResponse)
327 m_flags.append(
"write-without-response"_L1);
328 if (data.properties() & QLowEnergyCharacteristic::PropertyType::Read)
329 m_flags.append(
"read"_L1);
330 if (data.properties() & QLowEnergyCharacteristic::PropertyType::Write)
331 m_flags.append(
"write"_L1);
332 if (data.properties() & QLowEnergyCharacteristic::PropertyType::Notify)
333 m_flags.append(
"notify"_L1);
334 if (data.properties() & QLowEnergyCharacteristic::PropertyType::Indicate)
335 m_flags.append(
"indicate"_L1);
336 if (data.properties() & QLowEnergyCharacteristic::PropertyType::WriteSigned)
337 m_flags.append(
"authenticated-signed-writes"_L1);
338 if (data.properties() & QLowEnergyCharacteristic::PropertyType::ExtendedProperty) {
343 for (
const auto& descriptor : data.descriptors()) {
345 if (descriptor.uuid()
346 == QBluetoothUuid::DescriptorType::CharacteristicExtendedProperties
347 && descriptor.value().size() == 2) {
348 const auto properties = descriptor.value().at(0);
349 if (properties & 0x01)
350 m_flags.append(
"reliable-write"_L1);
351 if (properties & 0x02)
352 m_flags.append(
"writable-auxiliaries"_L1);
357 if (data.readConstraints() & QBluetooth::AttAccessConstraint::AttEncryptionRequired)
358 m_flags.append(
"encrypt-read"_L1);
359 if (data.readConstraints() & QBluetooth::AttAccessConstraint::AttAuthenticationRequired)
360 m_flags.append(
"encrypt-authenticated-read"_L1);
361 if (data.writeConstraints() & QBluetooth::AttAccessConstraint::AttEncryptionRequired)
362 m_flags.append(
"encrypt-write"_L1);
363 if (data.writeConstraints() & QBluetooth::AttAccessConstraint::AttAuthenticationRequired)
364 m_flags.append(
"encrypt-authenticated-write"_L1);
366 if (data.readConstraints() & QBluetooth::AttAccessConstraint::AttAuthorizationRequired
367 || data.writeConstraints() & QBluetooth::AttAccessConstraint::AttAuthorizationRequired)
368 m_flags.append(
"authorize"_L1);
370 if (m_flags.isEmpty()) {
371 qCWarning(QT_BT_BLUEZ) <<
"Characteristic property flags not set" << uuid
372 <<
"Peripheral may fail to register";
377QtBluezPeripheralService::QtBluezPeripheralService(
const QLowEnergyServiceData &serviceData,
378 const QString& applicationPath, quint16 ordinal,
379 QLowEnergyHandle handle, QObject* parent)
380 : QtBluezPeripheralGattObject(servicePathTemplate.arg(applicationPath).arg(ordinal),
381 serviceData.uuid().toString(QUuid::WithoutBraces), handle, parent),
382 m_isPrimary(serviceData.type() == QLowEnergyServiceData::ServiceTypePrimary),
383 m_adaptor(
new OrgBluezGattService1Adaptor(
this))
387void QtBluezPeripheralService::addIncludedService(
const QString& objectPath) {
388 qCDebug(QT_BT_BLUEZ) <<
"Adding included service" << objectPath <<
"for" << uuid;
389 m_includedServices.append(QDBusObjectPath(objectPath));
392InterfaceList QtBluezPeripheralService::properties()
const {
394 interfaces.insert(bluezServiceInterface,{
396 {
"Primary"_L1, m_isPrimary},
397 {
"Includes"_L1, QVariant::fromValue(m_includedServices)}
404#include "moc_bluezperipheralobjects_p.cpp"
QMap< QString, QVariantMap > InterfaceList
static constexpr auto bluezErrorInvalidOffset
static constexpr auto bluezErrorInvalidValueLength
static constexpr auto bluezServiceInterface
static constexpr auto bluezCharacteristicInterface
static constexpr auto bluezDescriptorInterface
static constexpr auto bluezErrorNotAuthorized
static constexpr auto characteristicPathTemplate
static constexpr auto descriptorPathTemplate
static constexpr auto servicePathTemplate
static constexpr int maximumAttributeLength