bluetooth: Implement EIR parsing for HCI_EVENT_EXTENDED_INQUIRY_EVENT
This parses only EIR_NAME_SHORT and EIR_NAME_COMPLETE, others are not yet usefull, adds a way to fetch the cached friendly name and adds a friendlyName field to RemoteDevice. Refactors DeviceListItem to work on RemoteDevice as it's only being used for that.Also adds a check if the cached name is complete or not. If not ask for the complete name. Change-Id: I7e37fb9cf44cb5598ef348fdd4d781c5ae04e24e Reviewed-on: https://review.haiku-os.org/c/haiku/+/10489 Reviewed-by: waddlesplash <[email protected]> Tested-by: Commit checker robot <[email protected]>
This commit is contained in:
committed by
waddlesplash
parent
ee10ca4b42
commit
e7eb60f1a7
@@ -162,7 +162,7 @@ SYSTEM_SERVERS += [ FFilterByBuildFeatures
|
|||||||
|
|
||||||
# Bluetooth stack + drivers
|
# Bluetooth stack + drivers
|
||||||
SYSTEM_NETWORK_PROTOCOLS +=
|
SYSTEM_NETWORK_PROTOCOLS +=
|
||||||
# l2cap
|
l2cap
|
||||||
;
|
;
|
||||||
SYSTEM_BT_STACK =
|
SYSTEM_BT_STACK =
|
||||||
hci
|
hci
|
||||||
|
|||||||
@@ -276,6 +276,7 @@ struct hci_ev_sychronous_connection_changed {
|
|||||||
|
|
||||||
// TODO: Define remaining Bluetooth 2.1 events structures
|
// TODO: Define remaining Bluetooth 2.1 events structures
|
||||||
#define HCI_EVENT_EXTENDED_INQUIRY_RESULT 0x2F
|
#define HCI_EVENT_EXTENDED_INQUIRY_RESULT 0x2F
|
||||||
|
#define HCI_MAX_EIR_LENGTH 240
|
||||||
struct hci_ev_extended_inquiry_info {
|
struct hci_ev_extended_inquiry_info {
|
||||||
bdaddr_t bdaddr;
|
bdaddr_t bdaddr;
|
||||||
uint8 page_repetition_mode;
|
uint8 page_repetition_mode;
|
||||||
@@ -283,8 +284,10 @@ struct hci_ev_extended_inquiry_info {
|
|||||||
uint8 dev_class[3];
|
uint8 dev_class[3];
|
||||||
uint16 clock_offset;
|
uint16 clock_offset;
|
||||||
int8 rssi;
|
int8 rssi;
|
||||||
uint8 eir[240];
|
uint8 eir[HCI_MAX_EIR_LENGTH];
|
||||||
} __attribute__((packed));
|
} __attribute__((packed));
|
||||||
|
#define EIR_NAME_SHORT 0x08
|
||||||
|
#define EIR_NAME_COMPLETE 0x09
|
||||||
|
|
||||||
#define HCI_EVENT_ENCRYPTION_KEY_REFRESH_COMPLETE 0x30
|
#define HCI_EVENT_ENCRYPTION_KEY_REFRESH_COMPLETE 0x30
|
||||||
|
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ public:
|
|||||||
bool IsTrustedDevice();
|
bool IsTrustedDevice();
|
||||||
BString GetFriendlyName(bool alwaysAsk); /* Throwing */
|
BString GetFriendlyName(bool alwaysAsk); /* Throwing */
|
||||||
BString GetFriendlyName(void); /* Throwing */
|
BString GetFriendlyName(void); /* Throwing */
|
||||||
|
BString GetCachedFriendlyName();
|
||||||
bdaddr_t GetBluetoothAddress();
|
bdaddr_t GetBluetoothAddress();
|
||||||
DeviceClass GetDeviceClass();
|
DeviceClass GetDeviceClass();
|
||||||
|
|
||||||
@@ -69,6 +70,8 @@ private:
|
|||||||
uint8 fScanMode;
|
uint8 fScanMode;
|
||||||
uint16 fClockOffset;
|
uint16 fClockOffset;
|
||||||
int8 fRSSI;
|
int8 fRSSI;
|
||||||
|
BString fFriendlyName;
|
||||||
|
bool fFriendlyNameIsComplete;
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -88,6 +88,9 @@ DiscoveryListener::MessageReceived(BMessage* message)
|
|||||||
uint8 scanMode = 0;
|
uint8 scanMode = 0;
|
||||||
uint16 clockOffset = 0;
|
uint16 clockOffset = 0;
|
||||||
int8 rssi = HCI_RSSI_INVALID;
|
int8 rssi = HCI_RSSI_INVALID;
|
||||||
|
BString friendlyName;
|
||||||
|
bool friendlyNameIsComplete = false;
|
||||||
|
|
||||||
|
|
||||||
if (message->FindData("bdaddr", B_ANY_TYPE, i, (const void**)&bdaddr, &size) != B_OK
|
if (message->FindData("bdaddr", B_ANY_TYPE, i, (const void**)&bdaddr, &size) != B_OK
|
||||||
|| message->FindData("dev_class", B_ANY_TYPE, i, (const void**)&devClass, &size)
|
|| message->FindData("dev_class", B_ANY_TYPE, i, (const void**)&devClass, &size)
|
||||||
@@ -102,6 +105,9 @@ DiscoveryListener::MessageReceived(BMessage* message)
|
|||||||
message->FindUInt8("scan_mode", i, &scanMode);
|
message->FindUInt8("scan_mode", i, &scanMode);
|
||||||
message->FindUInt16("clock_offset", i, &clockOffset);
|
message->FindUInt16("clock_offset", i, &clockOffset);
|
||||||
message->FindInt8("rssi", i, &rssi);
|
message->FindInt8("rssi", i, &rssi);
|
||||||
|
message->FindBool("friendly_name_is_complete", &friendlyNameIsComplete);
|
||||||
|
|
||||||
|
message->FindString("friendly_name", i, &friendlyName);
|
||||||
|
|
||||||
// Skip duplicated replies
|
// Skip duplicated replies
|
||||||
bool duplicatedFound = false;
|
bool duplicatedFound = false;
|
||||||
@@ -115,6 +121,10 @@ DiscoveryListener::MessageReceived(BMessage* message)
|
|||||||
existingDevice->fScanMode = scanMode;
|
existingDevice->fScanMode = scanMode;
|
||||||
existingDevice->fClockOffset = clockOffset;
|
existingDevice->fClockOffset = clockOffset;
|
||||||
existingDevice->fRSSI = rssi;
|
existingDevice->fRSSI = rssi;
|
||||||
|
if (!existingDevice->fFriendlyNameIsComplete && !friendlyName.IsEmpty()) {
|
||||||
|
existingDevice->fFriendlyNameIsComplete = friendlyNameIsComplete;
|
||||||
|
existingDevice->fFriendlyName = friendlyName;
|
||||||
|
}
|
||||||
duplicatedFound = true;
|
duplicatedFound = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -130,6 +140,8 @@ DiscoveryListener::MessageReceived(BMessage* message)
|
|||||||
rd->fScanMode = scanMode;
|
rd->fScanMode = scanMode;
|
||||||
rd->fClockOffset = clockOffset;
|
rd->fClockOffset = clockOffset;
|
||||||
rd->fRSSI = rssi;
|
rd->fRSSI = rssi;
|
||||||
|
rd->fFriendlyNameIsComplete = friendlyNameIsComplete;
|
||||||
|
rd->fFriendlyName = friendlyName;
|
||||||
DeviceDiscovered(rd, rd->GetDeviceClass());
|
DeviceDiscovered(rd, rd->GetDeviceClass());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -50,9 +50,8 @@ RemoteDevice::GetFriendlyName(bool alwaysAsk)
|
|||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
if (!alwaysAsk) {
|
if (!alwaysAsk) {
|
||||||
// Check if the name is already retrieved
|
if (!fFriendlyName.IsEmpty() && fFriendlyNameIsComplete)
|
||||||
// TODO: Check if It is known from a KnownDevicesList
|
return fFriendlyName;
|
||||||
return BString(B_TRANSLATE("Not implemented"));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (fDiscovererLocalDevice == NULL)
|
if (fDiscovererLocalDevice == NULL)
|
||||||
@@ -90,6 +89,8 @@ RemoteDevice::GetFriendlyName(bool alwaysAsk)
|
|||||||
if ((reply.FindInt8("status", &status) == B_OK) && (status == BT_OK)) {
|
if ((reply.FindInt8("status", &status) == B_OK) && (status == BT_OK)) {
|
||||||
|
|
||||||
if ((reply.FindString("friendlyname", &name) == B_OK )) {
|
if ((reply.FindString("friendlyname", &name) == B_OK )) {
|
||||||
|
fFriendlyName = name;
|
||||||
|
fFriendlyNameIsComplete = true;
|
||||||
return name;
|
return name;
|
||||||
} else {
|
} else {
|
||||||
return BString(""); // should not happen
|
return BString(""); // should not happen
|
||||||
@@ -97,6 +98,9 @@ RemoteDevice::GetFriendlyName(bool alwaysAsk)
|
|||||||
|
|
||||||
} else {
|
} else {
|
||||||
// seems we got a negative event
|
// seems we got a negative event
|
||||||
|
if (!fFriendlyName.IsEmpty())
|
||||||
|
return fFriendlyName;
|
||||||
|
|
||||||
return BString(B_TRANSLATE("#CommandFailed#Not Valid name"));
|
return BString(B_TRANSLATE("#CommandFailed#Not Valid name"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,7 +113,15 @@ BString
|
|||||||
RemoteDevice::GetFriendlyName()
|
RemoteDevice::GetFriendlyName()
|
||||||
{
|
{
|
||||||
CALLED();
|
CALLED();
|
||||||
return GetFriendlyName(true);
|
return GetFriendlyName(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
BString
|
||||||
|
RemoteDevice::GetCachedFriendlyName()
|
||||||
|
{
|
||||||
|
CALLED();
|
||||||
|
return fFriendlyName;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -16,19 +16,24 @@
|
|||||||
|
|
||||||
namespace Bluetooth {
|
namespace Bluetooth {
|
||||||
|
|
||||||
DeviceListItem::DeviceListItem(BluetoothDevice* bDevice)
|
|
||||||
|
DeviceListItem::DeviceListItem(RemoteDevice* bDevice)
|
||||||
:
|
:
|
||||||
BListItem(),
|
BListItem(),
|
||||||
fDevice(bDevice),
|
fDevice(bDevice)
|
||||||
fName("unknown")
|
|
||||||
{
|
{
|
||||||
fAddress = bDevice->GetBluetoothAddress();
|
fAddress = bDevice->GetBluetoothAddress();
|
||||||
fClass = bDevice->GetDeviceClass();
|
fClass = bDevice->GetDeviceClass();
|
||||||
|
// we always use the cached name here as we dont want to fire a query in the middle of an
|
||||||
|
// INQUIRY
|
||||||
|
fName = bDevice->GetCachedFriendlyName();
|
||||||
|
if (fName.IsEmpty())
|
||||||
|
fName = "unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
DeviceListItem::SetDevice(BluetoothDevice* bDevice)
|
DeviceListItem::SetDevice(RemoteDevice* bDevice)
|
||||||
{
|
{
|
||||||
fAddress = bDevice->GetBluetoothAddress();
|
fAddress = bDevice->GetBluetoothAddress();
|
||||||
fClass = bDevice->GetDeviceClass();
|
fClass = bDevice->GetDeviceClass();
|
||||||
@@ -146,7 +151,7 @@ DeviceListItem::Compare(const void *firstArg, const void *secondArg)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
BluetoothDevice*
|
RemoteDevice*
|
||||||
DeviceListItem::Device() const
|
DeviceListItem::Device() const
|
||||||
{
|
{
|
||||||
return fDevice;
|
return fDevice;
|
||||||
|
|||||||
@@ -8,15 +8,14 @@
|
|||||||
#include <ListItem.h>
|
#include <ListItem.h>
|
||||||
#include <String.h>
|
#include <String.h>
|
||||||
|
|
||||||
#include <bluetooth/bluetooth.h>
|
#include "bluetooth/RemoteDevice.h"
|
||||||
#include <bluetooth/DeviceClass.h>
|
|
||||||
|
|
||||||
namespace Bluetooth {
|
namespace Bluetooth {
|
||||||
|
|
||||||
class DeviceListItem : public BListItem
|
class DeviceListItem : public BListItem
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
DeviceListItem(BluetoothDevice* bDevice);
|
DeviceListItem(RemoteDevice* bDevice);
|
||||||
|
|
||||||
~DeviceListItem();
|
~DeviceListItem();
|
||||||
|
|
||||||
@@ -24,11 +23,11 @@ class DeviceListItem : public BListItem
|
|||||||
void Update(BView* owner, const BFont* font);
|
void Update(BView* owner, const BFont* font);
|
||||||
|
|
||||||
static int Compare(const void* firstArg, const void* secondArg);
|
static int Compare(const void* firstArg, const void* secondArg);
|
||||||
void SetDevice(BluetoothDevice* bDevice);
|
void SetDevice(RemoteDevice* bDevice);
|
||||||
BluetoothDevice* Device() const;
|
RemoteDevice* Device() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
BluetoothDevice* fDevice;
|
RemoteDevice* fDevice;
|
||||||
bdaddr_t fAddress;
|
bdaddr_t fAddress;
|
||||||
DeviceClass fClass;
|
DeviceClass fClass;
|
||||||
BString fName;
|
BString fName;
|
||||||
|
|||||||
@@ -283,8 +283,7 @@ InquiryPanel::MessageReceived(BMessage* message)
|
|||||||
// Really erally expensive operation should be done in a separate thread
|
// Really erally expensive operation should be done in a separate thread
|
||||||
// once Haiku gets a BarberPole in API replacing the progress bar
|
// once Haiku gets a BarberPole in API replacing the progress bar
|
||||||
((DeviceListItem*)fRemoteList->ItemAt(retrievalIndex))
|
((DeviceListItem*)fRemoteList->ItemAt(retrievalIndex))
|
||||||
->SetDevice((BluetoothDevice*) fDiscoveryAgent
|
->SetDevice(fDiscoveryAgent->RetrieveDevices(0).ItemAt(retrievalIndex));
|
||||||
->RetrieveDevices(0).ItemAt(retrievalIndex));
|
|
||||||
fRemoteList->InvalidateItem(retrievalIndex);
|
fRemoteList->InvalidateItem(retrievalIndex);
|
||||||
|
|
||||||
retrievalIndex++;
|
retrievalIndex++;
|
||||||
|
|||||||
@@ -57,13 +57,14 @@ RemoteDevicesView::RemoteDevicesView(const char* name, uint32 flags)
|
|||||||
|
|
||||||
disconnectButton = new BButton("disconnect", B_TRANSLATE("Disconnect"),
|
disconnectButton = new BButton("disconnect", B_TRANSLATE("Disconnect"),
|
||||||
new BMessage(kMsgDisconnectDevice));
|
new BMessage(kMsgDisconnectDevice));
|
||||||
/*
|
/*
|
||||||
blockButton = new BButton("block", B_TRANSLATE("As blocked"),
|
blockButton = new BButton("block", B_TRANSLATE("As blocked"),
|
||||||
new BMessage(kMsgBlockDevice));
|
new BMessage(kMsgBlockDevice));
|
||||||
|
|
||||||
availButton = new BButton("check", B_TRANSLATE("Refresh" B_UTF8_ELLIPSIS),
|
//TODO:Here use GetFriendlyName(true)
|
||||||
new BMessage(kMsgRefreshDevices));
|
availButton = new BButton("check", B_TRANSLATE("Refresh" B_UTF8_ELLIPSIS),
|
||||||
*/
|
new BMessage(kMsgRefreshDevices));
|
||||||
|
*/
|
||||||
// Set up device list
|
// Set up device list
|
||||||
fDeviceList = new BListView("DeviceList", B_SINGLE_SELECTION_LIST);
|
fDeviceList = new BListView("DeviceList", B_SINGLE_SELECTION_LIST);
|
||||||
|
|
||||||
|
|||||||
@@ -890,7 +890,8 @@ LocalDeviceImpl::ExtendedInquiryResult(uint8* numberOfResponses, BMessage* reque
|
|||||||
reply.AddUInt16("clock_offset", info->clock_offset);
|
reply.AddUInt16("clock_offset", info->clock_offset);
|
||||||
reply.AddInt8("rssi", info->rssi);
|
reply.AddInt8("rssi", info->rssi);
|
||||||
|
|
||||||
// need to implement eir parsing
|
ParseEIR(info->eir, reply);
|
||||||
|
|
||||||
printf("%s: Sending reply...\n", __func__);
|
printf("%s: Sending reply...\n", __func__);
|
||||||
status_t status = request->SendReply(&reply);
|
status_t status = request->SendReply(&reply);
|
||||||
if (status < B_OK)
|
if (status < B_OK)
|
||||||
@@ -898,6 +899,60 @@ LocalDeviceImpl::ExtendedInquiryResult(uint8* numberOfResponses, BMessage* reque
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void
|
||||||
|
LocalDeviceImpl::ParseEIR(const uint8* eir, BMessage& reply)
|
||||||
|
{
|
||||||
|
if (eir == NULL)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int offset = 0;
|
||||||
|
BString completeName;
|
||||||
|
BString shortName;
|
||||||
|
|
||||||
|
while (offset < HCI_MAX_EIR_LENGTH) {
|
||||||
|
uint8 length = eir[offset];
|
||||||
|
|
||||||
|
// break either when finished reading buffer or when next data value is zero
|
||||||
|
if (length == 0 || offset + length >= HCI_MAX_EIR_LENGTH)
|
||||||
|
break;
|
||||||
|
|
||||||
|
uint8 type = eir[offset + 1];
|
||||||
|
const uint8* data = &eir[offset + 2];
|
||||||
|
uint8 dataLen = length - 1;
|
||||||
|
|
||||||
|
// TODO:Implement other EIR datatypes
|
||||||
|
switch (type) {
|
||||||
|
case EIR_NAME_SHORT:
|
||||||
|
if (shortName.Length() == 0) {
|
||||||
|
shortName.SetTo((const char*)data, dataLen);
|
||||||
|
TRACE_BT("LocalDeviceImpl: Parsed EIR Short Name: '%s'\n", shortName.String());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case EIR_NAME_COMPLETE:
|
||||||
|
if (completeName.Length() == 0) {
|
||||||
|
completeName.SetTo((const char*)data, dataLen);
|
||||||
|
TRACE_BT("LocalDeviceImpl: Parsed EIR Complete Name: '%s'\n",
|
||||||
|
completeName.String());
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
TRACE_BT("LocalDeviceImpl: Ignored EIR Type: 0x%02X (Length: %d)\n", type, dataLen);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += length + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (completeName.Length() > 0) {
|
||||||
|
reply.AddString("friendly_name", completeName.String());
|
||||||
|
reply.AddBool("friendly_name_is_complete", true);
|
||||||
|
} else if (shortName.Length() > 0) {
|
||||||
|
reply.AddString("friendly_name", shortName.String());
|
||||||
|
reply.AddBool("friendly_name_is_complete", false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
LocalDeviceImpl::InquiryComplete(uint8* status, BMessage* request)
|
LocalDeviceImpl::InquiryComplete(uint8* status, BMessage* request)
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -50,6 +50,7 @@ private:
|
|||||||
void InquiryResult(uint8* numberOfResponses, BMessage* request);
|
void InquiryResult(uint8* numberOfResponses, BMessage* request);
|
||||||
void InquiryResultWithRSSI(uint8* numberOfResponses, BMessage* request);
|
void InquiryResultWithRSSI(uint8* numberOfResponses, BMessage* request);
|
||||||
void ExtendedInquiryResult(uint8* numberOfResponses, BMessage* request);
|
void ExtendedInquiryResult(uint8* numberOfResponses, BMessage* request);
|
||||||
|
void ParseEIR(const uint8* eir, BMessage& reply);
|
||||||
void InquiryComplete(uint8* status, BMessage* request);
|
void InquiryComplete(uint8* status, BMessage* request);
|
||||||
void RemoteNameRequestComplete(struct hci_ev_remote_name_request_complete_reply*
|
void RemoteNameRequestComplete(struct hci_ev_remote_name_request_complete_reply*
|
||||||
remotename, BMessage* request);
|
remotename, BMessage* request);
|
||||||
|
|||||||
Reference in New Issue
Block a user