BluetoothRadio (macOS): detect more info

This commit is contained in:
李通洲
2024-07-29 16:32:36 +08:00
parent c14ba32b82
commit 0929b940c8
5 changed files with 78 additions and 34 deletions
@@ -6,9 +6,9 @@ typedef struct FFBluetoothRadioResult
{
FFstrbuf name;
FFstrbuf address;
FFstrbuf vendor;
int32_t lmpVersion;
int32_t lmpSubversion;
const char* vendor;
bool enabled;
bool discoverable;
bool connectable;
@@ -1,27 +1,69 @@
#include "bluetoothradio.h"
#include "common/processing.h"
#import <IOBluetooth/IOBluetooth.h>
// For some reason the official declaration of IOBluetoothHostController don't include property `controllers`
@interface IOBluetoothHostController()
+ (id)controllers;
@end
const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothResult */)
{
IOBluetoothHostController* ctrl = IOBluetoothHostController.defaultController;
if(!ctrl)
return "IOBluetoothHostController.defaultController failed";
NSArray<IOBluetoothHostController*>* ctrls = IOBluetoothHostController.controllers;
if(!ctrls)
return "IOBluetoothHostController.controllers returns nil";
FFBluetoothRadioResult* device = ffListAdd(devices);
ffStrbufInitS(&device->name, ctrl.nameAsString.UTF8String);
ffStrbufInitS(&device->address, ctrl.addressAsString.UTF8String);
device->lmpVersion = -1;
device->lmpSubversion = -1;
device->enabled = ctrl.powerState == kBluetoothHCIPowerStateON;
device->discoverable = false;
device->connectable = true;
FF_STRBUF_AUTO_DESTROY buffer = ffStrbufCreate();
if (ffProcessAppendStdOut(&buffer, (char* const[]) {
"system_profiler",
"SPBluetoothDataType",
"-xml",
"-detailLevel",
"basic",
NULL
}) != NULL)
return "Starting `system_profiler SPBluetoothDataType -xml -detailLevel basic` failed";
#ifdef __aarch64__
device->vendor = "Apple";
#else
device->vendor = "Unknown"; // Hackintosh?
#endif
NSArray* arr = [NSPropertyListSerialization propertyListWithData:[NSData dataWithBytes:buffer.chars length:buffer.length]
options:NSPropertyListImmutable
format:nil
error:nil];
if (!arr || !arr.count)
return "system_profiler SPBluetoothDataType returned an empty array";
for (IOBluetoothHostController* ctrl in ctrls)
{
FFBluetoothRadioResult* device = ffListAdd(devices);
ffStrbufInitS(&device->name, ctrl.nameAsString.UTF8String);
ffStrbufInitS(&device->address, ctrl.addressAsString.UTF8String);
ffStrbufInitStatic(&device->vendor, "Apple");
device->lmpVersion = INT_MIN;
device->lmpSubversion = INT_MIN;
device->enabled = ctrl.powerState == kBluetoothHCIPowerStateON;
device->discoverable = false;
device->connectable = true;
for (NSDictionary* itemDict in arr[0][@"_items"])
{
NSDictionary* props = itemDict[@"controller_properties"];
if (!props) continue;
if (![ctrl.addressAsString isEqualToString:props[@"controller_address"]]) continue;
NSString* services = props[@"controller_supportedServices"];
if ([services containsString:@" LEA "])
device->lmpVersion = -11;
else if ([services containsString:@" GATT "])
device->lmpVersion = -6;
device->discoverable = ![props[@"controller_discoverable"] isEqualToString:@"attrib_off"];
ffStrbufSetS(&device->vendor, ((NSString*) props[@"controller_vendorID"]).UTF8String);
ffStrbufSubstrAfterFirstC(&device->vendor, '(');
ffStrbufTrimRight(&device->vendor, ')');
break;
}
}
return NULL;
}
@@ -65,9 +65,9 @@ static void detectBluetoothValue(FFDBusData* dbus, DBusMessageIter* iter, FFBlue
ffDBusGetString(dbus, &dictIter, &device->name);
else if(ffStrEquals(deviceProperty, "Manufacturer"))
{
uint16_t detection;
if (ffDBusGetUint16(dbus, &dictIter, &detection))
device->vendor = ffBluetoothRadioGetVendor(detection);
uint16_t vendorId;
if (ffDBusGetUint16(dbus, &dictIter, &vendorId))
ffStrbufSetStatic(&device->vendor, ffBluetoothRadioGetVendor(vendorId));
}
else if(ffStrEquals(deviceProperty, "Version"))
{
@@ -144,9 +144,9 @@ static void detectBluetoothObject(FFlist* devices, FFDBusData* dbus, DBusMessage
FFBluetoothRadioResult* device = ffListAdd(devices);
ffStrbufInit(&device->name);
ffStrbufInit(&device->address);
device->lmpVersion = -1;
device->lmpSubversion = -1;
device->vendor = "Unknown";
ffStrbufInitStatic(&device->vendor, "Unknown");
device->lmpVersion = INT_MIN;
device->lmpSubversion = INT_MIN;
device->enabled = false;
while(true)
@@ -93,7 +93,7 @@ const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothRadioResult */)
device->lmpVersion = blri.radioInfo.lmpVersion;
device->lmpSubversion = blri.radioInfo.lmpSubversion;
device->vendor = ffBluetoothRadioGetVendor(blri.radioInfo.mfg);
ffStrbufSetStatic(&device->vendor, ffBluetoothRadioGetVendor(blri.radioInfo.mfg));
device->enabled = true;
device->connectable = ffBluetoothIsConnectable(hRadio);
device->discoverable = ffBluetoothIsDiscoverable(hRadio);
+12 -10
View File
@@ -26,14 +26,14 @@ static void printDevice(FFBluetoothRadioOptions* options, const FFBluetoothRadio
const char* version = NULL;
switch (radio->lmpVersion)
switch (radio->lmpVersion < 0 ? -radio->lmpVersion : radio->lmpVersion)
{
case 0: version = "1.0b"; break;
case 1: version = "1.1"; break;
case 2: version = "1.2"; break;
case 3: version = "2.0 + EDR"; break;
case 4: version = "2.1 + EDR"; break;
case 5: version = "3.0 + HS"; break;
case 3: version = "2.0"; break;
case 4: version = "2.1"; break;
case 5: version = "3.0"; break;
case 6: version = "4.0"; break;
case 7: version = "4.1"; break;
case 8: version = "4.2"; break;
@@ -49,9 +49,9 @@ static void printDevice(FFBluetoothRadioOptions* options, const FFBluetoothRadio
ffPrintLogoAndKey(key.chars, index, &options->moduleArgs, FF_PRINT_TYPE_NO_CUSTOM_KEY);
if (version)
printf("Bluetooth %s (%s)\n", version, radio->vendor);
printf("Bluetooth %s%s (%s)\n", version, (radio->lmpVersion < 0 ? "+" : ""), radio->vendor.chars);
else
fputs(radio->vendor, stdout);
ffStrbufPutTo(&radio->vendor, stdout);
}
else
{
@@ -61,7 +61,7 @@ static void printDevice(FFBluetoothRadioOptions* options, const FFBluetoothRadio
{FF_FORMAT_ARG_TYPE_INT, &radio->lmpVersion, "lmp-version"},
{FF_FORMAT_ARG_TYPE_INT, &radio->lmpSubversion, "lmp-subversion"},
{FF_FORMAT_ARG_TYPE_STRING, version, "version"},
{FF_FORMAT_ARG_TYPE_STRING, radio->vendor, "vendor"},
{FF_FORMAT_ARG_TYPE_STRBUF, &radio->vendor, "vendor"},
{FF_FORMAT_ARG_TYPE_BOOL, &radio->discoverable, "discoverable"},
{FF_FORMAT_ARG_TYPE_BOOL, &radio->connectable, "connectable"},
}));
@@ -102,6 +102,7 @@ void ffPrintBluetoothRadio(FFBluetoothRadioOptions* options)
{
ffStrbufDestroy(&radio->name);
ffStrbufDestroy(&radio->address);
ffStrbufDestroy(&radio->vendor);
}
}
@@ -158,15 +159,15 @@ void ffGenerateBluetoothRadioJsonResult(FF_MAYBE_UNUSED FFBluetoothRadioOptions*
yyjson_mut_val* obj = yyjson_mut_arr_add_obj(doc, arr);
yyjson_mut_obj_add_strbuf(doc, obj, "name", &item->name);
yyjson_mut_obj_add_strbuf(doc, obj, "address", &item->address);
if (item->lmpVersion < 0)
if (item->lmpVersion == INT_MIN)
yyjson_mut_obj_add_null(doc, obj, "lmpVersion");
else
yyjson_mut_obj_add_int(doc, obj, "lmpVersion", item->lmpVersion);
if (item->lmpSubversion < 0)
if (item->lmpSubversion == INT_MIN)
yyjson_mut_obj_add_null(doc, obj, "lmpSubversion");
else
yyjson_mut_obj_add_int(doc, obj, "lmpSubversion", item->lmpSubversion);
yyjson_mut_obj_add_str(doc, obj, "vendor", item->vendor);
yyjson_mut_obj_add_strbuf(doc, obj, "vendor", &item->vendor);
yyjson_mut_obj_add_bool(doc, obj, "enabled", item->enabled);
yyjson_mut_obj_add_bool(doc, obj, "discoverable", item->discoverable);
yyjson_mut_obj_add_bool(doc, obj, "connectable", item->connectable);
@@ -176,6 +177,7 @@ void ffGenerateBluetoothRadioJsonResult(FF_MAYBE_UNUSED FFBluetoothRadioOptions*
{
ffStrbufDestroy(&radio->name);
ffStrbufDestroy(&radio->address);
ffStrbufDestroy(&radio->vendor);
}
}