From a5f362af452555b5aaa4585be82053029e4b25c0 Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Wed, 14 Oct 2015 16:54:47 +0200 Subject: Bluetooth: Introduce API for LE advertising. And provide an implementation for BlueZ. Change-Id: I302aee7c43b77016d9e1e7a0d5bcbf00096abf76 Reviewed-by: Alex Blasche --- src/bluetooth/bluez/bluez_data_p.h | 32 ++++++++++++++++++++++++++ src/bluetooth/bluez/hcimanager.cpp | 46 +++++++++++++++++++++++++++++++++++++- src/bluetooth/bluez/hcimanager_p.h | 4 +++- 3 files changed, 80 insertions(+), 2 deletions(-) (limited to 'src/bluetooth/bluez') 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 +#include +#include #include #include #include #include +#include #include #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 ¶meters) +{ + qCDebug(QT_BT_BLUEZ) << "sending command; ogf:" << ogf << "ocf:" << ocf; + quint8 packetType = HCI_COMMAND_PKT; + hci_command_hdr command = { + opCodePack(ogf, ocf), + static_cast(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(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(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(sizeof *event)); + const quint8 status = data[sizeof *event]; + const auto additionalData = QByteArray(reinterpret_cast(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 ¶meters); 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(); -- cgit v1.2.3