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
|
||||
SYSTEM_NETWORK_PROTOCOLS +=
|
||||
# l2cap
|
||||
l2cap
|
||||
;
|
||||
SYSTEM_BT_STACK =
|
||||
hci
|
||||
|
||||
@@ -276,6 +276,7 @@ struct hci_ev_sychronous_connection_changed {
|
||||
|
||||
// TODO: Define remaining Bluetooth 2.1 events structures
|
||||
#define HCI_EVENT_EXTENDED_INQUIRY_RESULT 0x2F
|
||||
#define HCI_MAX_EIR_LENGTH 240
|
||||
struct hci_ev_extended_inquiry_info {
|
||||
bdaddr_t bdaddr;
|
||||
uint8 page_repetition_mode;
|
||||
@@ -283,8 +284,10 @@ struct hci_ev_extended_inquiry_info {
|
||||
uint8 dev_class[3];
|
||||
uint16 clock_offset;
|
||||
int8 rssi;
|
||||
uint8 eir[240];
|
||||
uint8 eir[HCI_MAX_EIR_LENGTH];
|
||||
} __attribute__((packed));
|
||||
#define EIR_NAME_SHORT 0x08
|
||||
#define EIR_NAME_COMPLETE 0x09
|
||||
|
||||
#define HCI_EVENT_ENCRYPTION_KEY_REFRESH_COMPLETE 0x30
|
||||
|
||||
|
||||
@@ -31,6 +31,7 @@ public:
|
||||
bool IsTrustedDevice();
|
||||
BString GetFriendlyName(bool alwaysAsk); /* Throwing */
|
||||
BString GetFriendlyName(void); /* Throwing */
|
||||
BString GetCachedFriendlyName();
|
||||
bdaddr_t GetBluetoothAddress();
|
||||
DeviceClass GetDeviceClass();
|
||||
|
||||
@@ -69,6 +70,8 @@ private:
|
||||
uint8 fScanMode;
|
||||
uint16 fClockOffset;
|
||||
int8 fRSSI;
|
||||
BString fFriendlyName;
|
||||
bool fFriendlyNameIsComplete;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
@@ -88,6 +88,9 @@ DiscoveryListener::MessageReceived(BMessage* message)
|
||||
uint8 scanMode = 0;
|
||||
uint16 clockOffset = 0;
|
||||
int8 rssi = HCI_RSSI_INVALID;
|
||||
BString friendlyName;
|
||||
bool friendlyNameIsComplete = false;
|
||||
|
||||
|
||||
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)
|
||||
@@ -102,6 +105,9 @@ DiscoveryListener::MessageReceived(BMessage* message)
|
||||
message->FindUInt8("scan_mode", i, &scanMode);
|
||||
message->FindUInt16("clock_offset", i, &clockOffset);
|
||||
message->FindInt8("rssi", i, &rssi);
|
||||
message->FindBool("friendly_name_is_complete", &friendlyNameIsComplete);
|
||||
|
||||
message->FindString("friendly_name", i, &friendlyName);
|
||||
|
||||
// Skip duplicated replies
|
||||
bool duplicatedFound = false;
|
||||
@@ -115,6 +121,10 @@ DiscoveryListener::MessageReceived(BMessage* message)
|
||||
existingDevice->fScanMode = scanMode;
|
||||
existingDevice->fClockOffset = clockOffset;
|
||||
existingDevice->fRSSI = rssi;
|
||||
if (!existingDevice->fFriendlyNameIsComplete && !friendlyName.IsEmpty()) {
|
||||
existingDevice->fFriendlyNameIsComplete = friendlyNameIsComplete;
|
||||
existingDevice->fFriendlyName = friendlyName;
|
||||
}
|
||||
duplicatedFound = true;
|
||||
break;
|
||||
}
|
||||
@@ -130,6 +140,8 @@ DiscoveryListener::MessageReceived(BMessage* message)
|
||||
rd->fScanMode = scanMode;
|
||||
rd->fClockOffset = clockOffset;
|
||||
rd->fRSSI = rssi;
|
||||
rd->fFriendlyNameIsComplete = friendlyNameIsComplete;
|
||||
rd->fFriendlyName = friendlyName;
|
||||
DeviceDiscovered(rd, rd->GetDeviceClass());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,9 +50,8 @@ RemoteDevice::GetFriendlyName(bool alwaysAsk)
|
||||
{
|
||||
CALLED();
|
||||
if (!alwaysAsk) {
|
||||
// Check if the name is already retrieved
|
||||
// TODO: Check if It is known from a KnownDevicesList
|
||||
return BString(B_TRANSLATE("Not implemented"));
|
||||
if (!fFriendlyName.IsEmpty() && fFriendlyNameIsComplete)
|
||||
return fFriendlyName;
|
||||
}
|
||||
|
||||
if (fDiscovererLocalDevice == NULL)
|
||||
@@ -90,6 +89,8 @@ RemoteDevice::GetFriendlyName(bool alwaysAsk)
|
||||
if ((reply.FindInt8("status", &status) == B_OK) && (status == BT_OK)) {
|
||||
|
||||
if ((reply.FindString("friendlyname", &name) == B_OK )) {
|
||||
fFriendlyName = name;
|
||||
fFriendlyNameIsComplete = true;
|
||||
return name;
|
||||
} else {
|
||||
return BString(""); // should not happen
|
||||
@@ -97,6 +98,9 @@ RemoteDevice::GetFriendlyName(bool alwaysAsk)
|
||||
|
||||
} else {
|
||||
// seems we got a negative event
|
||||
if (!fFriendlyName.IsEmpty())
|
||||
return fFriendlyName;
|
||||
|
||||
return BString(B_TRANSLATE("#CommandFailed#Not Valid name"));
|
||||
}
|
||||
}
|
||||
@@ -109,7 +113,15 @@ BString
|
||||
RemoteDevice::GetFriendlyName()
|
||||
{
|
||||
CALLED();
|
||||
return GetFriendlyName(true);
|
||||
return GetFriendlyName(false);
|
||||
}
|
||||
|
||||
|
||||
BString
|
||||
RemoteDevice::GetCachedFriendlyName()
|
||||
{
|
||||
CALLED();
|
||||
return fFriendlyName;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -16,19 +16,24 @@
|
||||
|
||||
namespace Bluetooth {
|
||||
|
||||
DeviceListItem::DeviceListItem(BluetoothDevice* bDevice)
|
||||
|
||||
DeviceListItem::DeviceListItem(RemoteDevice* bDevice)
|
||||
:
|
||||
BListItem(),
|
||||
fDevice(bDevice),
|
||||
fName("unknown")
|
||||
fDevice(bDevice)
|
||||
{
|
||||
fAddress = bDevice->GetBluetoothAddress();
|
||||
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
|
||||
DeviceListItem::SetDevice(BluetoothDevice* bDevice)
|
||||
DeviceListItem::SetDevice(RemoteDevice* bDevice)
|
||||
{
|
||||
fAddress = bDevice->GetBluetoothAddress();
|
||||
fClass = bDevice->GetDeviceClass();
|
||||
@@ -146,7 +151,7 @@ DeviceListItem::Compare(const void *firstArg, const void *secondArg)
|
||||
}
|
||||
|
||||
|
||||
BluetoothDevice*
|
||||
RemoteDevice*
|
||||
DeviceListItem::Device() const
|
||||
{
|
||||
return fDevice;
|
||||
|
||||
@@ -8,15 +8,14 @@
|
||||
#include <ListItem.h>
|
||||
#include <String.h>
|
||||
|
||||
#include <bluetooth/bluetooth.h>
|
||||
#include <bluetooth/DeviceClass.h>
|
||||
#include "bluetooth/RemoteDevice.h"
|
||||
|
||||
namespace Bluetooth {
|
||||
|
||||
class DeviceListItem : public BListItem
|
||||
{
|
||||
public:
|
||||
DeviceListItem(BluetoothDevice* bDevice);
|
||||
DeviceListItem(RemoteDevice* bDevice);
|
||||
|
||||
~DeviceListItem();
|
||||
|
||||
@@ -24,11 +23,11 @@ class DeviceListItem : public BListItem
|
||||
void Update(BView* owner, const BFont* font);
|
||||
|
||||
static int Compare(const void* firstArg, const void* secondArg);
|
||||
void SetDevice(BluetoothDevice* bDevice);
|
||||
BluetoothDevice* Device() const;
|
||||
void SetDevice(RemoteDevice* bDevice);
|
||||
RemoteDevice* Device() const;
|
||||
|
||||
private:
|
||||
BluetoothDevice* fDevice;
|
||||
RemoteDevice* fDevice;
|
||||
bdaddr_t fAddress;
|
||||
DeviceClass fClass;
|
||||
BString fName;
|
||||
|
||||
@@ -283,8 +283,7 @@ InquiryPanel::MessageReceived(BMessage* message)
|
||||
// Really erally expensive operation should be done in a separate thread
|
||||
// once Haiku gets a BarberPole in API replacing the progress bar
|
||||
((DeviceListItem*)fRemoteList->ItemAt(retrievalIndex))
|
||||
->SetDevice((BluetoothDevice*) fDiscoveryAgent
|
||||
->RetrieveDevices(0).ItemAt(retrievalIndex));
|
||||
->SetDevice(fDiscoveryAgent->RetrieveDevices(0).ItemAt(retrievalIndex));
|
||||
fRemoteList->InvalidateItem(retrievalIndex);
|
||||
|
||||
retrievalIndex++;
|
||||
|
||||
@@ -61,6 +61,7 @@ RemoteDevicesView::RemoteDevicesView(const char* name, uint32 flags)
|
||||
blockButton = new BButton("block", B_TRANSLATE("As blocked"),
|
||||
new BMessage(kMsgBlockDevice));
|
||||
|
||||
//TODO:Here use GetFriendlyName(true)
|
||||
availButton = new BButton("check", B_TRANSLATE("Refresh" B_UTF8_ELLIPSIS),
|
||||
new BMessage(kMsgRefreshDevices));
|
||||
*/
|
||||
|
||||
@@ -890,7 +890,8 @@ LocalDeviceImpl::ExtendedInquiryResult(uint8* numberOfResponses, BMessage* reque
|
||||
reply.AddUInt16("clock_offset", info->clock_offset);
|
||||
reply.AddInt8("rssi", info->rssi);
|
||||
|
||||
// need to implement eir parsing
|
||||
ParseEIR(info->eir, reply);
|
||||
|
||||
printf("%s: Sending reply...\n", __func__);
|
||||
status_t status = request->SendReply(&reply);
|
||||
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
|
||||
LocalDeviceImpl::InquiryComplete(uint8* status, BMessage* request)
|
||||
{
|
||||
|
||||
@@ -50,6 +50,7 @@ private:
|
||||
void InquiryResult(uint8* numberOfResponses, BMessage* request);
|
||||
void InquiryResultWithRSSI(uint8* numberOfResponses, BMessage* request);
|
||||
void ExtendedInquiryResult(uint8* numberOfResponses, BMessage* request);
|
||||
void ParseEIR(const uint8* eir, BMessage& reply);
|
||||
void InquiryComplete(uint8* status, BMessage* request);
|
||||
void RemoteNameRequestComplete(struct hci_ev_remote_name_request_complete_reply*
|
||||
remotename, BMessage* request);
|
||||
|
||||
Reference in New Issue
Block a user