Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to make a drop down list of available bluetooth devices in Objective-C?

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

like image 911
user2728981 Avatar asked Sep 09 '13 19:09

user2728981


1 Answers

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!

like image 91
Tommy Devoy Avatar answered Oct 14 '22 17:10

Tommy Devoy