summaryrefslogtreecommitdiffstats
path: root/src/bluetooth/bluez
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@theqtcompany.com>2015-10-14 16:54:47 +0200
committerAlex Blasche <alexander.blasche@theqtcompany.com>2015-11-17 15:40:02 +0000
commita5f362af452555b5aaa4585be82053029e4b25c0 (patch)
treeeae7edea0537c8fe55226628fc3d5618741cf04f /src/bluetooth/bluez
parenteb59027d32c7904a129b16c786df1dc2097ab9c9 (diff)
Bluetooth: Introduce API for LE advertising.
And provide an implementation for BlueZ. Change-Id: I302aee7c43b77016d9e1e7a0d5bcbf00096abf76 Reviewed-by: Alex Blasche <alexander.blasche@theqtcompany.com>
Diffstat (limited to 'src/bluetooth/bluez')
-rw-r--r--src/bluetooth/bluez/bluez_data_p.h32
-rw-r--r--src/bluetooth/bluez/hcimanager.cpp46
-rw-r--r--src/bluetooth/bluez/hcimanager_p.h4
3 files changed, 80 insertions, 2 deletions
diff --git a/src/bluetooth/bluez/bluez_data_p.h b/src/bluetooth/bluez/bluez_data_p.h
index 5d6a90ef..456a9374 100644
--- a/src/bluetooth/bluez/bluez_data_p.h
+++ b/src/bluetooth/bluez/bluez_data_p.h
@@ -217,12 +217,14 @@ template<> inline void putBtData(quint128 src, void *dst)
#define HCI_FILTER 2
// HCI packet types
+#define HCI_COMMAND_PKT 0x01
#define HCI_EVENT_PKT 0x04
#define HCI_VENDOR_PKT 0xff
#define HCI_FLT_TYPE_BITS 31
#define HCI_FLT_EVENT_BITS 63
+
struct sockaddr_hci {
sa_family_t hci_family;
unsigned short hci_dev;
@@ -347,6 +349,36 @@ typedef struct {
} __attribute__ ((packed)) evt_encrypt_change;
#define EVT_ENCRYPT_CHANGE_SIZE 4
+#define EVT_CMD_COMPLETE 0x0E
+struct evt_cmd_complete {
+ quint8 ncmd;
+ quint16 opcode;
+} __attribute__ ((packed));
+
+struct hci_command_hdr {
+ quint16 opcode; /* OCF & OGF */
+ quint8 plen;
+} __attribute__ ((packed));
+
+enum OpCodeGroupField {
+ OgfLinkControl = 0x8,
+};
+
+enum OpCodeCommandField {
+ OcfLeSetAdvParams = 0x6,
+ OcfLeReadTxPowerLevel = 0x7,
+ OcfLeSetAdvData = 0x8,
+ OcfLeSetScanResponseData = 0x9,
+ OcfLeSetAdvEnable = 0xa,
+ OcfLeClearWhiteList = 0x10,
+ OcfLeAddToWhiteList = 0x11,
+};
+
+/* Command opcode pack/unpack */
+#define opCodePack(ogf, ocf) (quint16(((ocf) & 0x03ff)|((ogf) << 10)))
+#define ogfFromOpCode(op) ((op) >> 10)
+#define ocfFromOpCode(op) ((op) & 0x03ff)
+
QT_END_NAMESPACE
#endif // BLUEZ_DATA_P_H
diff --git a/src/bluetooth/bluez/hcimanager.cpp b/src/bluetooth/bluez/hcimanager.cpp
index 30511ae5..388f3e0c 100644
--- a/src/bluetooth/bluez/hcimanager.cpp
+++ b/src/bluetooth/bluez/hcimanager.cpp
@@ -36,12 +36,14 @@
#include "qbluetoothsocket_p.h"
-#include <QtCore/QLoggingCategory>
+#include <QtCore/qloggingcategory.h>
+#include <cstring>
#include <errno.h>
#include <sys/types.h>
#include <sys/socket.h>
#include <sys/ioctl.h>
+#include <sys/uio.h>
#include <unistd.h>
#define HCIGETCONNLIST _IOR('H', 212, int)
@@ -174,6 +176,36 @@ bool HciManager::monitorEvent(HciManager::HciEvent event)
return true;
}
+bool HciManager::sendCommand(OpCodeGroupField ogf, OpCodeCommandField ocf, const QByteArray &parameters)
+{
+ qCDebug(QT_BT_BLUEZ) << "sending command; ogf:" << ogf << "ocf:" << ocf;
+ quint8 packetType = HCI_COMMAND_PKT;
+ hci_command_hdr command = {
+ opCodePack(ogf, ocf),
+ static_cast<uint8_t>(parameters.count())
+ };
+ static_assert(sizeof command == 3, "unexpected struct size");
+ struct iovec iv[3];
+ iv[0].iov_base = &packetType;
+ iv[0].iov_len = 1;
+ iv[1].iov_base = &command;
+ iv[1].iov_len = sizeof command;
+ int ivn = 2;
+ if (!parameters.isEmpty()) {
+ iv[2].iov_base = const_cast<char *>(parameters.constData()); // const_cast is safe, since iov_base will not get modified.
+ iv[2].iov_len = parameters.count();
+ ++ivn;
+ }
+ while (writev(hciSocket, iv, ivn) < 0) {
+ if (errno == EAGAIN || errno == EINTR)
+ continue;
+ qCDebug(QT_BT_BLUEZ()) << "hci command failure:" << strerror(errno);
+ return false;
+ }
+ qCDebug(QT_BT_BLUEZ) << "command sent successfully";
+ return true;
+}
+
/*
* Unsubscribe from all events
*/
@@ -275,6 +307,18 @@ void HciManager::_q_readNotify()
emit encryptionChangedEvent(remoteDevice, event->status == 0);
}
break;
+ case EVT_CMD_COMPLETE: {
+ auto * const event = reinterpret_cast<const evt_cmd_complete *>(data);
+ static_assert(sizeof *event == 3, "unexpected struct size");
+
+ // There is always a status byte right after the generic structure.
+ Q_ASSERT(size > static_cast<int>(sizeof *event));
+ const quint8 status = data[sizeof *event];
+ const auto additionalData = QByteArray(reinterpret_cast<const char *>(data)
+ + sizeof *event + 1, size - sizeof *event - 1);
+ emit commandCompleted(event->opcode, status, additionalData);
+ }
+ break;
default:
break;
}
diff --git a/src/bluetooth/bluez/hcimanager_p.h b/src/bluetooth/bluez/hcimanager_p.h
index 9dd2ceee..c8f2fe56 100644
--- a/src/bluetooth/bluez/hcimanager_p.h
+++ b/src/bluetooth/bluez/hcimanager_p.h
@@ -59,6 +59,7 @@ class HciManager : public QObject
public:
enum HciEvent {
EncryptChangeEvent = EVT_ENCRYPT_CHANGE,
+ CommandCompleteEvent = EVT_CMD_COMPLETE,
};
explicit HciManager(const QBluetoothAddress &deviceAdapter, QObject *parent = 0);
@@ -66,12 +67,13 @@ public:
bool isValid() const;
bool monitorEvent(HciManager::HciEvent event);
+ bool sendCommand(OpCodeGroupField ogf, OpCodeCommandField ocf, const QByteArray &parameters);
void stopEvents();
QBluetoothAddress addressForConnectionHandle(quint16 handle) const;
-
signals:
void encryptionChangedEvent(const QBluetoothAddress &address, bool wasSuccess);
+ void commandCompleted(quint16 opCode, quint8 status, const QByteArray &data);
private slots:
void _q_readNotify();