- Joined
- Dec 3, 2010
- Messages
- 460
- Motherboard
- Gigabyte GA-H55M-S2V
- CPU
- Intel i3-530
- Graphics
- HIS HD 6570
- Mac
- Mobile Phone
This is a quick command line tool which I think tests correctly for Handoff (Bluetooth Low Energy) support. So far I've only seen posts referring to the LMP version, which is unhelpful; the Link Manager Protocol version corresponds directly to the Bluetooth marketing version, and even then each version has plenty of optional features. This tool checks "CoreBluetooth"'s functionality, but instead of trying to correlate the CB*Manager states with BLE support, it queries some private methods of IOBluetoothHostController, including -lowEnergySupport. The manager routines are still run, since they test the functionality, but the device information should be enough to make a decision.
If you get an abnormal result, please post it below. As usual the source is open (link against IOBluetooth if you compile), binary is compiled for Mountain Lion and higher.
If you get an abnormal result, please post it below. As usual the source is open (link against IOBluetooth if you compile), binary is compiled for Mountain Lion and higher.
Code:
//
// main.m
// BluetoothLowEnergyCheck
//
// Created by PHPdev32 on 7/24/14.
// Licensed under GPLv3, full text at http://www.gnu.org/licenses/gpl-3.0.txt
//
#import <Foundation/Foundation.h>
#import <IOBluetooth/IOBluetooth.h>
#define info(x, ...) printf(x"\n", ##__VA_ARGS__)
#define err(x, ...) { info(x, ##__VA_ARGS__); return EXIT_FAILURE; }
@interface IOBluetoothHostController ()
@property (readonly) bool lowEnergySupported, isReady, powerChangeSupported;
@property (readonly) UInt16 USBProductID, USBVendorID;
-(IOReturn)BluetoothHCIReadLocalVersionInformation:(BluetoothLMPVersion *)hciVersion outHCIRevision:(BluetoothLMPSubversion *)hciRevision outLMPVersion:(BluetoothLMPVersion *)lmpVersion outManufacturerName:(BluetoothManufacturerName *)manufacturerName outLMPSubversion:(BluetoothLMPSubversion *)lmpSubVersion;
-(IOReturn)BluetoothHCIReadLocalSupportedFeatures:(struct BluetoothHCISupportedFeatures *)arg1;
-(IOReturn)enableRemoteWake:(bool)flag;
@end
@interface Delegate : NSObject <CBCentralManagerDelegate>
@end
#ifdef MAC_OS_X_VERSION_10_9
@interface Delegate () <CBPeripheralManagerDelegate>
@end
#endif
@implementation Delegate
-(void)printState:(NSUInteger)state {
const char *s;
switch (state) {
case CBCentralManagerStateUnknown: s = "Unknown"; break;
case CBCentralManagerStateUnsupported: s = "Unsupported"; break;
case CBCentralManagerStateUnauthorized: s = "Unauthorized"; break;
case CBCentralManagerStatePoweredOff: s = "Powered Off"; break;
case CBCentralManagerStatePoweredOn: s = "Powered On"; break;
case CBCentralManagerStateResetting: s = "Resetting"; break;
default: s = "Bad state"; break;
}
info("State is: %s", s);
}
-(void)centralManagerDidUpdateState:(CBCentralManager *)central {
[self printState:central.state];
[central stopScan];
dispatch_async(dispatch_get_main_queue(), ^{ exit(EXIT_SUCCESS); });
}
#ifdef MAC_OS_X_VERSION_10_9
-(void)peripheralManagerDidUpdateState:(CBPeripheralManager *)peripheral {
[self printState:peripheral.state];
[peripheral stopAdvertising];
dispatch_async(dispatch_get_main_queue(), ^{ exit(EXIT_SUCCESS); });
}
#endif
@end
int main(int argc, const char * argv[])
{
@autoreleasepool {
// insert code here...
close(STDERR_FILENO);
info("Built %s", __DATE__);
IOBluetoothHostController *controller = [IOBluetoothHostController defaultController];
BluetoothHCIVersionInfo i;
if (controller && [controller BluetoothHCIReadLocalVersionInformation:&i.hciVersion outHCIRevision:&i.hciRevision outLMPVersion:&i.lmpVersion outManufacturerName:&i.manufacturerName outLMPSubversion:&i.lmpSubVersion] == kIOReturnSuccess) {
info("Found (0x%hX%hX) named '%s', turned %s, %sready", controller.USBVendorID, controller.USBProductID, controller.nameAsString.UTF8String, controller.powerState ? "on" : "off", controller.isReady ? "" : "not ");
info("HCI %#x:%#hx, LMP %#x:%#x, MAC %s", i.hciVersion, i.hciRevision, i.lmpVersion, i.lmpSubVersion, controller.addressAsString.UTF8String);
info("Low Energy %ssupported, Power Change %ssupported", controller.lowEnergySupported ? "" : "un", controller.powerChangeSupported ? "" : "un");
}
else
err("No controller found")
id manager, delegate = [Delegate new];
#ifdef MAC_OS_X_VERSION_10_9
if (&CBPeripheralManagerOptionShowPowerAlertKey) {
info("Using Peripheral Manager, Mavericks or higher");
CBPeripheralManager *pm = manager = [[CBPeripheralManager alloc] initWithDelegate:delegate queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0) options:@{CBPeripheralManagerOptionShowPowerAlertKey:@YES}];
[pm startAdvertising:nil];
} else
#endif
if (&CBCentralManagerScanOptionAllowDuplicatesKey) {
info("Using Central Manager, Lion or Mountain Lion");
CBCentralManager *cm = manager = [[CBCentralManager alloc] initWithDelegate:delegate queue:dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)];
[cm scanForPeripheralsWithServices:nil options:nil];
}
else
err("No Bluetooth managers found");
dispatch_main();
}
return 0;
}