From b41e73a1565ff9edd45f814a4b535020c04b1b15 Mon Sep 17 00:00:00 2001 From: Javier Date: Wed, 17 Sep 2014 00:10:06 +0200 Subject: Bump version, add new GatoConnectionParameters class and ability to change connection parameters. --- gatoattclient.cpp | 21 +++++++++ gatoattclient.h | 6 +++ gatoconnectionparameters.cpp | 77 ++++++++++++++++++++++++++++++++ gatoconnectionparameters.h | 52 ++++++++++++++++++++++ gatoperipheral.cpp | 12 +++++ gatoperipheral.h | 4 ++ gatosocket.cpp | 103 +++++++++++++++++++++++++++++++++++++++++-- gatosocket.h | 4 ++ libgato.pro | 8 ++-- rpm/libgato.spec | 2 +- rpm/libgato.yaml | 2 +- 11 files changed, 283 insertions(+), 8 deletions(-) create mode 100644 gatoconnectionparameters.cpp create mode 100644 gatoconnectionparameters.h diff --git a/gatoattclient.cpp b/gatoattclient.cpp index 0bf5877..00dd9d0 100644 --- a/gatoattclient.cpp +++ b/gatoattclient.cpp @@ -103,6 +103,27 @@ void GatoAttClient::close() socket->close(); } +GatoSocket::SecurityLevel GatoAttClient::securityLevel() const +{ + return socket->securityLevel(); +} + +bool GatoAttClient::setSecurityLevel(GatoSocket::SecurityLevel level) +{ + required_sec = level; + return socket->setSecurityLevel(level); +} + +GatoConnectionParameters GatoAttClient::connectionParameters() const +{ + return socket->connectionParameters(); +} + +bool GatoAttClient::setConnectionParameters(const GatoConnectionParameters ¶ms) +{ + return socket->setConnectionParameters(params); +} + int GatoAttClient::mtu() const { return cur_mtu; diff --git a/gatoattclient.h b/gatoattclient.h index 64df313..764abdd 100644 --- a/gatoattclient.h +++ b/gatoattclient.h @@ -19,6 +19,12 @@ public: bool connectTo(const GatoAddress& addr, GatoSocket::SecurityLevel sec_level); void close(); + GatoSocket::SecurityLevel securityLevel() const; + bool setSecurityLevel(GatoSocket::SecurityLevel level); + + GatoConnectionParameters connectionParameters() const; + bool setConnectionParameters(const GatoConnectionParameters ¶ms); + struct InformationData { GatoHandle handle; diff --git a/gatoconnectionparameters.cpp b/gatoconnectionparameters.cpp new file mode 100644 index 0000000..29ec37b --- /dev/null +++ b/gatoconnectionparameters.cpp @@ -0,0 +1,77 @@ +#include "gatoconnectionparameters.h" +#include + +struct GatoConnectionParametersPrivate : public QSharedData +{ + int connIntervalMin; + int connIntervalMax; + int slaveLatency; + int supervisionTimeout; +}; + +GatoConnectionParameters::GatoConnectionParameters() + : d(new GatoConnectionParametersPrivate) +{ +} + +GatoConnectionParameters::GatoConnectionParameters(const GatoConnectionParameters &o) + : d(o.d) +{ +} + +GatoConnectionParameters::~GatoConnectionParameters() +{ +} + +int GatoConnectionParameters::connectionIntervalMin() const +{ + return d->connIntervalMin; +} + +void GatoConnectionParameters::setConnectionIntervalMin(int interval) +{ + d->connIntervalMin = interval; +} + +int GatoConnectionParameters::connectionIntervalMax() const +{ + return d->connIntervalMax; +} + +void GatoConnectionParameters::setConnectionIntervalMax(int interval) +{ + d->connIntervalMax = interval; +} + +void GatoConnectionParameters::setConnectionInterval(int min, int max) +{ + d->connIntervalMin = min; + d->connIntervalMax = max; +} + +int GatoConnectionParameters::slaveLatency() const +{ + return d->slaveLatency; +} + +void GatoConnectionParameters::setSlaveLatency(int latency) +{ + d->slaveLatency = latency; +} + +int GatoConnectionParameters::supervisionTimeout() const +{ + return d->supervisionTimeout; +} + +void GatoConnectionParameters::setSupervisionTimeout(int timeout) +{ + d->supervisionTimeout = timeout; +} + +GatoConnectionParameters &GatoConnectionParameters::operator=(const GatoConnectionParameters &o) +{ + if (this != &o) + d.operator=(o.d); + return *this; +} diff --git a/gatoconnectionparameters.h b/gatoconnectionparameters.h new file mode 100644 index 0000000..1441020 --- /dev/null +++ b/gatoconnectionparameters.h @@ -0,0 +1,52 @@ +#ifndef GATOCONNECTIONPARAMETERS_H +#define GATOCONNECTIONPARAMETERS_H + +#include +#include + +#include "libgato_global.h" + +class GatoConnectionParametersPrivate; + +/** These parameters determine the effective throughput of a Low Energy link, + * enabling custom balancing between power usage, bandwidth, and latency. */ + +class LIBGATO_EXPORT GatoConnectionParameters +{ + Q_GADGET + +public: + GatoConnectionParameters(); + GatoConnectionParameters(const GatoConnectionParameters &o); + ~GatoConnectionParameters(); + + // Units for all of this: milliseconds + // TODO Need to document + + // Connection interval: generally, lower connection interval increases throughput. + // Units: microseconds (µs!) + + int connectionIntervalMin() const; + void setConnectionIntervalMin(int interval); + + int connectionIntervalMax() const; + void setConnectionIntervalMax(int interval); + + void setConnectionInterval(int min, int max); + + // TODO Document + // Units: miliseconds (ms!) + int slaveLatency() const; + void setSlaveLatency(int latency); + + // Units: miliseconds + int supervisionTimeout() const; + void setSupervisionTimeout(int timeout); + + GatoConnectionParameters &operator=(const GatoConnectionParameters &o); + +private: + QSharedDataPointer d; +}; + +#endif // GATOCONNECTIONPARAMETERS_H diff --git a/gatoperipheral.cpp b/gatoperipheral.cpp index 160e302..d15bf99 100644 --- a/gatoperipheral.cpp +++ b/gatoperipheral.cpp @@ -97,6 +97,18 @@ QList GatoPeripheral::services() const return d->services.values(); } +GatoConnectionParameters GatoPeripheral::connectionParameters() const +{ + Q_D(const GatoPeripheral); + return d->att->connectionParameters(); +} + +bool GatoPeripheral::setConnectionParameters(const GatoConnectionParameters ¶ms) +{ + Q_D(const GatoPeripheral); + return d->att->setConnectionParameters(params); +} + void GatoPeripheral::parseEIR(quint8 data[], int len) { Q_D(GatoPeripheral); diff --git a/gatoperipheral.h b/gatoperipheral.h index c8c9023..6b7ab5b 100644 --- a/gatoperipheral.h +++ b/gatoperipheral.h @@ -5,6 +5,7 @@ #include "libgato_global.h" #include "gatouuid.h" #include "gatoaddress.h" +#include "gatoconnectionparameters.h" class GatoService; class GatoCharacteristic; @@ -46,6 +47,9 @@ public: QString name() const; QList services() const; + GatoConnectionParameters connectionParameters() const; + bool setConnectionParameters(const GatoConnectionParameters ¶ms); + void parseEIR(quint8 data[], int len); bool advertisesService(const GatoUUID &uuid) const; diff --git a/gatosocket.cpp b/gatosocket.cpp index 73567b5..19f11ff 100644 --- a/gatosocket.cpp +++ b/gatosocket.cpp @@ -28,6 +28,41 @@ #include #include "gatosocket.h" +#ifndef BT_LE_PARAMS +/* Too old kernel headers. */ +#define BT_LE_PARAMS 100 +#define BT_LE_SCAN_WINDOW_MIN 0x0004 +#define BT_LE_SCAN_WINDOW_MAX 0x4000 +#define BT_LE_SCAN_WINDOW_DEF 0x0004 +#define BT_LE_SCAN_INTERVAL_MIN 0x0004 +#define BT_LE_SCAN_INTERVAL_MAX 0x4000 +#define BT_LE_SCAN_INTERVAL_DEF 0x0008 +#define BT_LE_CONN_INTERVAL_MIN 0x0006 +#define BT_LE_CONN_INTERVAL_MAX 0x0C80 +#define BT_LE_CONN_INTERVAL_MIN_DEF 0x0008 +#define BT_LE_CONN_INTERVAL_MAX_DEF 0x0100 +#define BT_LE_LATENCY_MAX 0x01F4 +#define BT_LE_LATENCY_DEF 0x0000 +#define BT_LE_SUP_TO_MIN 0x000A +#define BT_LE_SUP_TO_MAX 0x0C80 +#define BT_LE_SUP_TO_DEFAULT 0X03E8 + +struct bt_le_params { + uint8_t prohibit_remote_chg; + uint8_t filter_policy; + uint16_t scan_interval; + uint16_t scan_window; + uint16_t interval_min; + uint16_t interval_max; + uint16_t latency; + uint16_t supervision_timeout; + uint16_t min_ce_len; + uint16_t max_ce_len; + uint16_t conn_timeout; +}; + +#endif + GatoSocket::GatoSocket(QObject *parent) : QObject(parent), s(StateDisconnected), fd(-1) { @@ -156,9 +191,11 @@ bool GatoSocket::setSecurityLevel(SecurityLevel level) if (s == StateDisconnected) { qWarning() << "Socket not connected"; - return SecurityNone; + return false; } + memset(&bt_sec, 0, len); + switch (level) { case SecurityNone: case SecurityLow: @@ -168,11 +205,9 @@ bool GatoSocket::setSecurityLevel(SecurityLevel level) bt_sec.level = BT_SECURITY_MEDIUM; break; case SecurityHigh: - // Will this even work in BT LE? bt_sec.level = BT_SECURITY_HIGH; break; } - bt_sec.key_size = 0; if (::setsockopt(fd, SOL_BLUETOOTH, BT_SECURITY, &bt_sec, len) == 0) { return true; @@ -182,6 +217,68 @@ bool GatoSocket::setSecurityLevel(SecurityLevel level) } } +GatoConnectionParameters GatoSocket::connectionParameters() const +{ + GatoConnectionParameters params; + bt_le_params bt_params; + socklen_t len = sizeof(bt_params); + + if (s == StateDisconnected) { + qWarning() << "Socket not connected"; + return params; + } + + if (::getsockopt(fd, SOL_BLUETOOTH, BT_LE_PARAMS, &bt_params, &len) == 0) { + if (bt_params.interval_min == 0 && bt_params.interval_max == 0) { + // Sometimes the kernel will give us this when no parameters have been set. + // I believe it is a bug, because in truth the kernel default parameters are in use. + qDebug() << "Filling in kernel defaults, since the kernel did not"; + bt_params.interval_min = BT_LE_CONN_INTERVAL_MIN_DEF; + bt_params.interval_max = BT_LE_CONN_INTERVAL_MAX_DEF; + bt_params.latency = BT_LE_LATENCY_DEF; + bt_params.supervision_timeout = BT_LE_SUP_TO_DEFAULT; + } + // Kernel uses "multiples of 1.25ms", we use µs, need to convert. + params.setConnectionInterval(bt_params.interval_min * 1250, bt_params.interval_max * 1250); + // Kernel units already in ms. + params.setSlaveLatency(bt_params.latency); + // Kernel uses "multiples of 10ms", need to convert + params.setSupervisionTimeout(bt_params.supervision_timeout * 10); + } else { + qErrnoWarning("Could not read connection parameters from L2 socket"); + } + + return params; +} + +bool GatoSocket::setConnectionParameters(const GatoConnectionParameters ¶ms) +{ + bt_le_params bt_params; + socklen_t len = sizeof(bt_params); + + if (s == StateDisconnected) { + qWarning() << "Socket not connected"; + return false; + } + + memset(&bt_params, 0, len); + + // Kernel uses "multiples of 1.25ms", we use µs, need to convert + bt_params.interval_min = params.connectionIntervalMin() / 1250; + bt_params.interval_max = params.connectionIntervalMax() / 1250; + // Kernel units already "ms". + bt_params.latency = params.slaveLatency(); + // Kernel uses "multiples of 10ms", need to convert + bt_params.supervision_timeout = params.supervisionTimeout() / 10; + + if (::setsockopt(fd, SOL_BLUETOOTH, BT_LE_PARAMS, &bt_params, len) == 0) { + return true; + } else { + qErrnoWarning("Could not set connection parameters in L2 socket"); + return false; + } +} + bool GatoSocket::transmit(const QByteArray &pkt) { int written = ::write(fd, pkt.constData(), pkt.size()); diff --git a/gatosocket.h b/gatosocket.h index 56760ee..28fd788 100644 --- a/gatosocket.h +++ b/gatosocket.h @@ -6,6 +6,7 @@ #include #include "gatoaddress.h" +#include "gatoconnectionparameters.h" /** This class encapsulates a message-oriented bluetooth L2CAP socket. */ class GatoSocket : public QObject @@ -49,6 +50,9 @@ public: SecurityLevel securityLevel() const; bool setSecurityLevel(SecurityLevel level); + GatoConnectionParameters connectionParameters() const; + bool setConnectionParameters(const GatoConnectionParameters ¶ms); + signals: void connected(); void disconnected(); diff --git a/libgato.pro b/libgato.pro index f13ebd3..a3397a4 100644 --- a/libgato.pro +++ b/libgato.pro @@ -19,7 +19,8 @@ SOURCES += \ gatoservice.cpp \ gatocharacteristic.cpp \ gatodescriptor.cpp \ - gatoattclient.cpp + gatoattclient.cpp \ + gatoconnectionparameters.cpp HEADERS += libgato_global.h gato.h \ gatocentralmanager.h \ @@ -33,7 +34,8 @@ HEADERS += libgato_global.h gato.h \ gatoservice.h \ gatocharacteristic.h \ gatodescriptor.h \ - gatoattclient.h + gatoattclient.h \ + gatoconnectionparameters.h target.path = /usr/lib INSTALLS += target @@ -41,7 +43,7 @@ INSTALLS += target publicheaders.files = libgato_global.h gato.h \ gatocentralmanager.h gatoperipheral.h \ gatoservice.h gatocharacteristic.h gatodescriptor.h \ - gatouuid.h gatoaddress.h + gatouuid.h gatoaddress.h gatoconnectionparameters.h publicheaders.path = /usr/include/gato INSTALLS += publicheaders diff --git a/rpm/libgato.spec b/rpm/libgato.spec index 7ca7e60..669579b 100644 --- a/rpm/libgato.spec +++ b/rpm/libgato.spec @@ -13,7 +13,7 @@ Name: libgato %{!?qtc_make:%define qtc_make make} %{?qtc_builddir:%define _builddir %qtc_builddir} Summary: A GATT library to connect with Bluetooth Smart devices -Version: 0.1.4 +Version: 0.1.6 Release: 1 Group: Qt/Qt License: GPL2 diff --git a/rpm/libgato.yaml b/rpm/libgato.yaml index 3f603da..3b13a5c 100644 --- a/rpm/libgato.yaml +++ b/rpm/libgato.yaml @@ -1,6 +1,6 @@ Name: libgato Summary: A GATT library to connect with Bluetooth Smart devices -Version: 0.1.4 +Version: 0.1.6 Release: 1 Group: Qt/Qt URL: https://gitorious.org/gato/ -- cgit v1.2.3