I’m trying to write a simple application that:
1. Scans for available BTLE devices, and
2. Places them in a drop down menu for the user to see.
So far, I’ve imported the IOBluetooth framework and I have one IBOutlet to an NSPopUpButton (where I'd like to display the results) and two IBActions for the buttons called startScan and stopScan.
I've been at it for a while and I need to ask for help. I've look at other posts on this wonderful forum but I'm relatively new to Objective-C programming and I would be very grateful for your help.
Here is my interface:
#import <Cocoa/Cocoa.h>
#import <IOBluetooth/IOBluetooth.h>
@interface AppDelegate : NSObject <NSApplicationDelegate, CBCentralManagerDelegate, CBPeripheralDelegate> {
CBCentralManager * central; // these properties are for the CBCentralManager
CBPeripheral * peripheral;
NSMutableDictionary * dictionary;
NSNumber * number;
}
@property (assign) IBOutlet NSWindow *window;
@property (weak) IBOutlet NSPopUpButton *deviceList;
@property NSMutableArray * list; // this is the array to fill up the deviceList NSPopUpButton
- (IBAction)startScan:(id)sender;
- (IBAction)stopScan:(id)sender;
@end
Here is my implementation:
@implementation AppDelegate
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
// Insert code here to initialize your application
CBCentralManager * central = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:nil];
NSLog(@"Central Manager's state is: %li", central.state);
}
- (IBAction)startScan:(id)sender {
// start scanning button
NSLog(@"Started scan. Discovering peripherals.");
NSArray * list;
}
- (IBAction)stopScan:(id)sender {
// stop scanning button
}
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
// I'm not sure how to make this work
}
- (void)centralManagerDidUpdateState:(CBCentralManager *)central {
NSLog(@"Central manager's state is updated to: %@", central);
}
- (void)retrievePeripherals:(NSArray *)peripheralUUIDs{
}
@end
Like I said, I would be very grateful for your help. I LOVE programming, but I'm frustrated with this, and I'm sure that one of you will take one look at this and know exactly what's going on.
Thanks, David
Okay quick overview on what you need to do to get started:
1.) Before you can scan for anything, you need to allocate your CentralManager, adopt its delegate, and wait to get the delegate callback:
-Allocate the central you declared in your header
central = [[CBCentralManager alloc] initWithDelegate:self queue:nil options:nil];
-Then wait for the delegate callback
- (void)centralManagerDidUpdateState:(CBCentralManager *)central
{
if(central.state == CBCentralManagerStatePoweredOn)
{
//okay your good to go and can now scan
}
else
{
//Unable to use CentralManager methods so print out the central.state and find out why
}
}
2.) If your wanting to use an IBAction to control scanning, you need to check the state each time as well.
- (IBAction)startScan:(id)sender
{
if(central.state == CBCentralManagerStatePoweredOn)
{
//nil scans for all peripherals. Change to an array of service UUID's if you're looking for specific devices. Change NO to YES if you want to allow duplicates
[central scanForPeripheralsWithServices:nil options:[NSDictionary dictionaryWithObjectsAndKeys:@NO, CBCentralManagerScanOptionAllowDuplicatesKey, nil];
}
}
3.) Now since you've already setup your delegate and your scanning for devices, just wait for the didDiscoverPeripheral callback:
- (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)peripheral advertisementData:(NSDictionary *)advertisementData RSSI:(NSNumber *)RSSI {
//you've found a peripheral so add it to your table
}
4.) Store your discovered CBPeripherals
inside an array or just the peripheral names (depending on your use case). Feed this into the data of your table and call reloadData on each new peripheral discovery. You can go ahead and allow duplicates if you want to keep track of which ones are currently nearby and you can remove/add depending on time found/advertisement rssi.
Note: The Central would ideally be setup inside a Singleton class, in which you adopt it's delegate methods inside your view controller. (But you can get your feet wet this way).
Hope it helps!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With