BluetoothRadio (Linux): add support

This commit is contained in:
Carter Li
2024-07-28 10:55:07 +08:00
parent 2c7cd6df98
commit 96c58148f6
7 changed files with 325 additions and 65 deletions
+1 -1
View File
@@ -2,4 +2,4 @@
check-filenames =
builtin = clear,rare,usage,informal
skip = */.git,*/cmake-build-*,*/.idea,*/completions,*/presets,*/screenshots,*/tests,*/3rdparty,*/logo/ascii
ignore-words-list = iterm,compiletime,unknwn,pengwin,siduction,master,sur,doas,Conexant
ignore-words-list = iterm,compiletime,unknwn,pengwin,siduction,master,sur,doas,conexant
+3 -2
View File
@@ -294,6 +294,7 @@ set(LIBFASTFETCH_SRC
src/common/properties.c
src/common/settings.c
src/common/temps.c
src/detection/bluetoothradio/bluetoothradio.c
src/detection/bootmgr/bootmgr.c
src/detection/chassis/chassis.c
src/detection/cpu/cpu.c
@@ -422,7 +423,7 @@ if(LINUX)
src/detection/cpuusage/cpuusage_linux.c
src/detection/cursor/cursor_linux.c
src/detection/bluetooth/bluetooth_linux.c
src/detection/bluetoothradio/bluetoothradio_nosupport.c
src/detection/bluetoothradio/bluetoothradio_linux.c
src/detection/disk/disk_linux.c
src/detection/dns/dns_linux.c
src/detection/physicaldisk/physicaldisk_linux.c
@@ -553,7 +554,7 @@ elseif(BSD)
src/detection/battery/battery_bsd.c
src/detection/bios/bios_bsd.c
src/detection/bluetooth/bluetooth_linux.c
src/detection/bluetoothradio/bluetoothradio_nosupport.c
src/detection/bluetoothradio/bluetoothradio_linux.c
src/detection/board/board_bsd.c
src/detection/bootmgr/bootmgr_bsd.c
src/detection/brightness/brightness_bsd.c
@@ -0,0 +1,112 @@
#include "bluetoothradio.h"
// https://github.com/ziglang/zig/blob/a84951465b409495095a9598db0cae745f34fa7b/lib/libc/include/any-windows-any/bthdef.h#L187-L236
#define BTH_MFG_ERICSSON 0
#define BTH_MFG_NOKIA 1
#define BTH_MFG_INTEL 2
#define BTH_MFG_IBM 3
#define BTH_MFG_TOSHIBA 4
#define BTH_MFG_3COM 5
#define BTH_MFG_MICROSOFT 6
#define BTH_MFG_LUCENT 7
#define BTH_MFG_MOTOROLA 8
#define BTH_MFG_INFINEON 9
#define BTH_MFG_CSR 10
#define BTH_MFG_SILICONWAVE 11
#define BTH_MFG_DIGIANSWER 12
#define BTH_MFG_TI 13
#define BTH_MFG_PARTHUS 14
#define BTH_MFG_BROADCOM 15
#define BTH_MFG_MITEL 16
#define BTH_MFG_WIDCOMM 17
#define BTH_MFG_ZEEVO 18
#define BTH_MFG_ATMEL 19
#define BTH_MFG_MITSIBUSHI 20
#define BTH_MFG_RTX_TELECOM 21
#define BTH_MFG_KC_TECHNOLOGY 22
#define BTH_MFG_NEWLOGIC 23
#define BTH_MFG_TRANSILICA 24
#define BTH_MFG_ROHDE_SCHWARZ 25
#define BTH_MFG_TTPCOM 26
#define BTH_MFG_SIGNIA 27
#define BTH_MFG_CONEXANT 28
#define BTH_MFG_QUALCOMM 29
#define BTH_MFG_INVENTEL 30
#define BTH_MFG_AVM_BERLIN 31
#define BTH_MFG_BANDSPEED 32
#define BTH_MFG_MANSELLA 33
#define BTH_MFG_NEC 34
#define BTH_MFG_WAVEPLUS_TECHNOLOGY_CO 35
#define BTH_MFG_ALCATEL 36
#define BTH_MFG_PHILIPS_SEMICONDUCTOR 37
#define BTH_MFG_C_TECHNOLOGIES 38
#define BTH_MFG_OPEN_INTERFACE 39
#define BTH_MFG_RF_MICRO_DEVICES 40
#define BTH_MFG_HITACHI 41
#define BTH_MFG_SYMBOL_TECHNOLOGIES 42
#define BTH_MFG_TENOVIS 43
#define BTH_MFG_MACRONIX_INTERNATIONAL 44
#define BTH_MFG_MARVELL 72
#define BTH_MFG_APPLE 76
#define BTH_MFG_NORDIC_SEMICONDUCTORS_ASA 89
#define BTH_MFG_ARUBA_NETWORKS 283
#define BTH_MFG_INTERNAL_USE 65535
const char* ffBluetoothRadioGetVendor(uint32_t manufacturerId)
{
switch (manufacturerId)
{
case BTH_MFG_ERICSSON: return "Ericsson";
case BTH_MFG_NOKIA: return "Nokia";
case BTH_MFG_INTEL: return "Intel";
case BTH_MFG_IBM: return "IBM";
case BTH_MFG_TOSHIBA: return "Toshiba";
case BTH_MFG_3COM: return "3Com";
case BTH_MFG_MICROSOFT: return "Microsoft";
case BTH_MFG_LUCENT: return "Lucent";
case BTH_MFG_MOTOROLA: return "Motorola";
case BTH_MFG_INFINEON: return "Infineon";
case BTH_MFG_CSR: return "CSR";
case BTH_MFG_SILICONWAVE: return "Silicon-Wave";
case BTH_MFG_DIGIANSWER: return "Digi-Answer";
case BTH_MFG_TI: return "Ti";
case BTH_MFG_PARTHUS: return "Parthus";
case BTH_MFG_BROADCOM: return "Broadcom";
case BTH_MFG_MITEL: return "Mitel";
case BTH_MFG_WIDCOMM: return "Widcomm";
case BTH_MFG_ZEEVO: return "Zeevo";
case BTH_MFG_ATMEL: return "Atmel";
case BTH_MFG_MITSIBUSHI: return "Mitsubishi";
case BTH_MFG_RTX_TELECOM: return "RTX Telecom";
case BTH_MFG_KC_TECHNOLOGY: return "KC Technology";
case BTH_MFG_NEWLOGIC: return "Newlogic";
case BTH_MFG_TRANSILICA: return "Transilica";
case BTH_MFG_ROHDE_SCHWARZ: return "Rohde-Schwarz";
case BTH_MFG_TTPCOM: return "TTPCom";
case BTH_MFG_SIGNIA: return "Signia";
case BTH_MFG_CONEXANT: return "Conexant";
case BTH_MFG_QUALCOMM: return "Qualcomm";
case BTH_MFG_INVENTEL: return "Inventel";
case BTH_MFG_AVM_BERLIN: return "AVM Berlin";
case BTH_MFG_BANDSPEED: return "Bandspeed";
case BTH_MFG_MANSELLA: return "Mansella";
case BTH_MFG_NEC: return "NEC";
case BTH_MFG_WAVEPLUS_TECHNOLOGY_CO: return "Waveplus";
case BTH_MFG_ALCATEL: return "Alcatel";
case BTH_MFG_PHILIPS_SEMICONDUCTOR: return "Philips Semiconductors";
case BTH_MFG_C_TECHNOLOGIES: return "C Technologies";
case BTH_MFG_OPEN_INTERFACE: return "Open Interface";
case BTH_MFG_RF_MICRO_DEVICES: return "RF Micro Devices";
case BTH_MFG_HITACHI: return "Hitachi";
case BTH_MFG_SYMBOL_TECHNOLOGIES: return "Symbol Technologies";
case BTH_MFG_TENOVIS: return "Tenovis";
case BTH_MFG_MACRONIX_INTERNATIONAL: return "Macronix International";
case BTH_MFG_MARVELL: return "Marvell";
case BTH_MFG_APPLE: return "Apple";
case BTH_MFG_NORDIC_SEMICONDUCTORS_ASA: return "Nordic Semiconductor ASA";
case BTH_MFG_ARUBA_NETWORKS: return "Aruba Networks";
case BTH_MFG_INTERNAL_USE: return "Internal Use";
default: return "Unknown";
}
}
@@ -11,7 +11,7 @@ typedef struct FFBluetoothRadioResult
uint16_t lmpSubversion;
uint16_t hciRevision;
const char* vendor;
bool leSupported;
} FFBluetoothRadioResult;
const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothRadioResult */);
const char* ffBluetoothRadioGetVendor(uint32_t manufacturerId);
@@ -0,0 +1,205 @@
#include "bluetoothradio.h"
#include "util/stringUtils.h"
#ifdef FF_HAVE_DBUS
#include "common/dbus.h"
/* Example dbus reply, striped to only the relevant parts:
array [ //root
dict entry(
object path "/org/bluez/hci0"
array [
dict entry(
string "org.bluez.Adapter1"
array [
dict entry(
string "Address"
variant string "XX:XX:XX:XX:XX:XX"
)
dict entry(
string "Name"
variant string "xxxxxxxx"
)
dict entry(
string "Powered"
variant boolean true
)
dict entry(
string "PowerState"
variant string "on"
)
dict entry(
string "Manufacturer"
variant uint16 2
)
dict entry(
string "Version"
variant byte 12
)
]
)
]
)
]
*/
static void detectBluetoothValue(FFDBusData* dbus, DBusMessageIter* iter, FFBluetoothRadioResult* device)
{
if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY)
return;
DBusMessageIter dictIter;
dbus->lib->ffdbus_message_iter_recurse(iter, &dictIter);
// if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_STRING)
// return;
const char* deviceProperty;
dbus->lib->ffdbus_message_iter_get_basic(&dictIter, &deviceProperty);
dbus->lib->ffdbus_message_iter_next(&dictIter);
if(ffStrEquals(deviceProperty, "Address"))
ffDBusGetString(dbus, &dictIter, &device->address);
else if(ffStrEquals(deviceProperty, "Name"))
ffDBusGetString(dbus, &dictIter, &device->name);
else if(ffStrEquals(deviceProperty, "Manufacturer"))
{
uint16_t detection;
if (ffDBusGetUint16(dbus, &dictIter, &detection))
device->vendor = ffBluetoothRadioGetVendor(detection);
}
else if(ffStrEquals(deviceProperty, "Version"))
ffDBusGetByte(dbus, &dictIter, &device->lmpVersion);
}
static void detectBluetoothProperty(FFDBusData* dbus, DBusMessageIter* iter, FFBluetoothRadioResult* device)
{
if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY)
return;
DBusMessageIter dictIter;
dbus->lib->ffdbus_message_iter_recurse(iter, &dictIter);
if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_STRING)
return;
const char* propertyType;
dbus->lib->ffdbus_message_iter_get_basic(&dictIter, &propertyType);
if(!ffStrContains(propertyType, ".Adapter"))
return; //We don't care about other properties
dbus->lib->ffdbus_message_iter_next(&dictIter);
if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_ARRAY)
return;
DBusMessageIter arrayIter;
dbus->lib->ffdbus_message_iter_recurse(&dictIter, &arrayIter);
while(true)
{
detectBluetoothValue(dbus, &arrayIter, device);
FF_DBUS_ITER_CONTINUE(dbus, &arrayIter);
}
}
static void detectBluetoothObject(FFlist* devices, FFDBusData* dbus, DBusMessageIter* iter)
{
if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_DICT_ENTRY)
return;
DBusMessageIter dictIter;
dbus->lib->ffdbus_message_iter_recurse(iter, &dictIter);
if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_OBJECT_PATH)
return;
const char* objectPath;
dbus->lib->ffdbus_message_iter_get_basic(&dictIter, &objectPath);
//We want adapter objects
if(!ffStrStartsWith(objectPath, "/org/bluez/hci") || ffStrContains(objectPath, "/dev_"))
return;
dbus->lib->ffdbus_message_iter_next(&dictIter);
if(dbus->lib->ffdbus_message_iter_get_arg_type(&dictIter) != DBUS_TYPE_ARRAY)
return;
DBusMessageIter arrayIter;
dbus->lib->ffdbus_message_iter_recurse(&dictIter, &arrayIter);
FFBluetoothRadioResult* device = ffListAdd(devices);
ffStrbufInit(&device->name);
ffStrbufInit(&device->address);
device->lmpVersion = 0;
device->hciVersion = 0;
device->lmpSubversion = 0;
device->hciRevision = 0;
device->vendor = "Unknown";
while(true)
{
detectBluetoothProperty(dbus, &arrayIter, device);
FF_DBUS_ITER_CONTINUE(dbus, &arrayIter);
}
if(device->name.length == 0)
{
ffStrbufDestroy(&device->name);
ffStrbufDestroy(&device->address);
--devices->length;
}
}
static void detectBluetoothRoot(FFlist* devices, FFDBusData* dbus, DBusMessageIter* iter)
{
if(dbus->lib->ffdbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
return;
DBusMessageIter arrayIter;
dbus->lib->ffdbus_message_iter_recurse(iter, &arrayIter);
while(true)
{
detectBluetoothObject(devices, dbus, &arrayIter);
FF_DBUS_ITER_CONTINUE(dbus, &arrayIter);
}
}
static const char* detectBluetooth(FFlist* devices)
{
FFDBusData dbus;
const char* error = ffDBusLoadData(DBUS_BUS_SYSTEM, &dbus);
if(error)
return error;
DBusMessage* managedObjects = ffDBusGetMethodReply(&dbus, "org.bluez", "/", "org.freedesktop.DBus.ObjectManager", "GetManagedObjects");
if(!managedObjects)
return "Failed to call GetManagedObjects";
DBusMessageIter rootIter;
if(!dbus.lib->ffdbus_message_iter_init(managedObjects, &rootIter))
{
dbus.lib->ffdbus_message_unref(managedObjects);
return "Failed to get root iterator of GetManagedObjects";
}
detectBluetoothRoot(devices, &dbus, &rootIter);
dbus.lib->ffdbus_message_unref(managedObjects);
return NULL;
}
#endif
const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothRadioResult */)
{
#ifdef FF_HAVE_DBUS
return detectBluetooth(devices);
#else
return "Fastfetch was compiled without DBus support";
#endif
}
@@ -93,62 +93,7 @@ const char* ffDetectBluetoothRadio(FFlist* devices /* FFBluetoothRadioResult */)
device->lmpSubversion = blri.radioInfo.lmpSubversion;
device->hciVersion = blri.hciVersion;
device->hciRevision = blri.hciRevision;
device->leSupported = LMP_LE_SUPPORTED(blri.radioInfo.lmpSupportedFeatures);
switch (blri.radioInfo.mfg)
{
case BTH_MFG_ERICSSON: device->vendor = "Ericsson"; break;
case BTH_MFG_NOKIA: device->vendor = "Nokia"; break;
case BTH_MFG_INTEL: device->vendor = "Intel"; break;
case BTH_MFG_IBM: device->vendor = "IBM"; break;
case BTH_MFG_TOSHIBA: device->vendor = "Toshiba"; break;
case BTH_MFG_3COM: device->vendor = "3Com"; break;
case BTH_MFG_MICROSOFT: device->vendor = "Microsoft"; break;
case BTH_MFG_LUCENT: device->vendor = "Lucent"; break;
case BTH_MFG_MOTOROLA: device->vendor = "Motorola"; break;
case BTH_MFG_INFINEON: device->vendor = "Infineon"; break;
case BTH_MFG_CSR: device->vendor = "CSR"; break;
case BTH_MFG_SILICONWAVE: device->vendor = "Silicon-Wave"; break;
case BTH_MFG_DIGIANSWER: device->vendor = "Digi-Answer"; break;
case BTH_MFG_TI: device->vendor = "Ti"; break;
case BTH_MFG_PARTHUS: device->vendor = "Parthus"; break;
case BTH_MFG_BROADCOM: device->vendor = "Broadcom"; break;
case BTH_MFG_MITEL: device->vendor = "Mitel"; break;
case BTH_MFG_WIDCOMM: device->vendor = "Widcomm"; break;
case BTH_MFG_ZEEVO: device->vendor = "Zeevo"; break;
case BTH_MFG_ATMEL: device->vendor = "Atmel"; break;
case BTH_MFG_MITSIBUSHI: device->vendor = "Mitsubishi"; break;
case BTH_MFG_RTX_TELECOM: device->vendor = "RTX Telecom"; break;
case BTH_MFG_KC_TECHNOLOGY: device->vendor = "KC Technology"; break;
case BTH_MFG_NEWLOGIC: device->vendor = "Newlogic"; break;
case BTH_MFG_TRANSILICA: device->vendor = "Transilica"; break;
case BTH_MFG_ROHDE_SCHWARZ: device->vendor = "Rohde-Schwarz"; break;
case BTH_MFG_TTPCOM: device->vendor = "TTPCom"; break;
case BTH_MFG_SIGNIA: device->vendor = "Signia"; break;
case BTH_MFG_CONEXANT: device->vendor = "Conexant"; break;
case BTH_MFG_QUALCOMM: device->vendor = "Qualcomm"; break;
case BTH_MFG_INVENTEL: device->vendor = "Inventel"; break;
case BTH_MFG_AVM_BERLIN: device->vendor = "AVM Berlin"; break;
case BTH_MFG_BANDSPEED: device->vendor = "Bandspeed"; break;
case BTH_MFG_MANSELLA: device->vendor = "Mansella"; break;
case BTH_MFG_NEC: device->vendor = "NEC"; break;
case BTH_MFG_WAVEPLUS_TECHNOLOGY_CO: device->vendor = "Waveplus"; break;
case BTH_MFG_ALCATEL: device->vendor = "Alcatel"; break;
case BTH_MFG_PHILIPS_SEMICONDUCTOR: device->vendor = "Philips Semiconductors"; break;
case BTH_MFG_C_TECHNOLOGIES: device->vendor = "C Technologies"; break;
case BTH_MFG_OPEN_INTERFACE: device->vendor = "Open Interface"; break;
case BTH_MFG_RF_MICRO_DEVICES: device->vendor = "RF Micro Devices"; break;
case BTH_MFG_HITACHI: device->vendor = "Hitachi"; break;
case BTH_MFG_SYMBOL_TECHNOLOGIES: device->vendor = "Symbol Technologies"; break;
case BTH_MFG_TENOVIS: device->vendor = "Tenovis"; break;
case BTH_MFG_MACRONIX_INTERNATIONAL: device->vendor = "Macronix International"; break;
case BTH_MFG_MARVELL: device->vendor = "Marvell"; break;
case BTH_MFG_APPLE: device->vendor = "Apple"; break;
case BTH_MFG_NORDIC_SEMICONDUCTORS_ASA: device->vendor = "Nordic Semiconductor ASA"; break;
case BTH_MFG_ARUBA_NETWORKS: device->vendor = "Aruba Networks"; break;
case BTH_MFG_INTERNAL_USE: device->vendor = "Internal Use"; break;
default: device->vendor = "Unknown"; break;
}
device->vendor = ffBluetoothRadioGetVendor(blri.radioInfo.mfg);
} while (ffBluetoothFindNextRadio(hFind, &hRadio));
ffBluetoothFindRadioClose(hFind);
+2 -5
View File
@@ -5,7 +5,7 @@
#include "modules/bluetoothradio/bluetoothradio.h"
#include "util/stringUtils.h"
#define FF_BLUETOOTHRADIO_NUM_FORMAT_ARGS 7
#define FF_BLUETOOTHRADIO_NUM_FORMAT_ARGS 6
#define FF_BLUETOOTHRADIO_DISPLAY_NAME "Bluetooth Radio"
static void printDevice(FFBluetoothRadioOptions* options, const FFBluetoothRadioResult* radio, uint8_t index)
@@ -65,7 +65,6 @@ static void printDevice(FFBluetoothRadioOptions* options, const FFBluetoothRadio
{FF_FORMAT_ARG_TYPE_STRBUF, &hciVersion, "hci-version"},
{FF_FORMAT_ARG_TYPE_STRING, version, "version"},
{FF_FORMAT_ARG_TYPE_STRING, radio->vendor, "vendor"},
{FF_FORMAT_ARG_TYPE_BOOL, &radio->leSupported, "le-supported"},
}));
}
}
@@ -153,7 +152,6 @@ void ffGenerateBluetoothRadioJsonResult(FF_MAYBE_UNUSED FFBluetoothRadioOptions*
yyjson_mut_obj_add_uint(doc, obj, "hciVersion", item->hciVersion);
yyjson_mut_obj_add_uint(doc, obj, "hciRevision", item->hciRevision);
yyjson_mut_obj_add_str(doc, obj, "vendor", item->vendor);
yyjson_mut_obj_add_bool(doc, obj, "leSupported", item->leSupported);
}
FF_LIST_FOR_EACH(FFBluetoothRadioResult, radio, results)
@@ -165,14 +163,13 @@ void ffGenerateBluetoothRadioJsonResult(FF_MAYBE_UNUSED FFBluetoothRadioOptions*
void ffPrintBluetoothRadioHelpFormat(void)
{
FF_PRINT_MODULE_FORMAT_HELP_CHECKED(FF_BLUETOOTHRADIO_MODULE_NAME, "{1} ({4})", FF_BLUETOOTHRADIO_NUM_FORMAT_ARGS, ((const char* []) {
FF_PRINT_MODULE_FORMAT_HELP_CHECKED(FF_BLUETOOTHRADIO_MODULE_NAME, "Bluetooth {5} ({6})", FF_BLUETOOTHRADIO_NUM_FORMAT_ARGS, ((const char* []) {
"Radio name for discovering - name",
"Address - local radio address",
"LMP version - lmp-version",
"HCI version - hci-version",
"Bluetooth version - version",
"Vendor - vendor",
"Is Bluetooth Low Energy (LE) supported - le-supported"
}));
}