0

I'm new to apple development and have been tackling the issue of Bluetooth. I trying to write a basic OSX application that will scan for nearby devices and populate a PopupList with a list of discovered devices.

Just to set the scene a little.. I have a button 'startStopScanBut' which will kickoff 'startStopScan' I also have two logs. Conn log for connection info. stateLog for phone state info.

ViewController.h

//  ViewController.h
//  F4STestHarness
//
//  Created by Nicholas Hayward on 26/06/2015.
//  Copyright (c) 2015 Nicholas Hayward. All rights reserved.
//
#import <Cocoa/Cocoa.h>
#import <CoreBluetooth/CoreBluetooth.h>

@interface ViewController : NSViewController
<CBCentralManagerDelegate,
 CBPeripheralDelegate>
@end

ViewController.m

//  ViewController.m
//  F4STestHarness
//
//  Created by Nicholas Hayward on 26/06/2015.
//  Copyright (c) 2015 Nicholas Hayward. All rights reserved.
//

#import "ViewController.h"

@interface ViewController ()

@property (nonatomic) IBOutlet NSTextView *stateLogTextView;
@property (nonatomic) IBOutlet NSTextView *bluetoothLogTextView;
@property BOOL bluetoothOn;

@property BOOL isScanning;
@property (nonatomic) IBOutlet NSButton *startStopScanBut;
@property (strong, nonatomic) CBCentralManager *centralManager;
@property (nonatomic) IBOutlet CBPeripheral *foundPeripheral;
@property (nonatomic) IBOutlet NSPopUpButton *foundPeripheralsPop;


/*@property BOOL isAdvertising;
@property BOOL isAdvertisingInitialised;
@property (nonatomic) IBOutlet NSButton *startStopAdvertisingButton;
@property (strong, nonatomic) CBPeripheralManager *peripheralManager;
@property (strong, nonatomic) CBMutableCharacteristic *myCharacteristic;
@property (strong, nonatomic) NSDictionary *advertisingData;*/

#define SERVICE_UUID        @ "1f9f7e9d-7a83-4053-87f9-2c328b8f315a"
#define CHARACTERISTIC_UUID @ "FFF3"

@end

@implementation ViewController

//Write to log function
-(void)conLog:(NSString *)msg
{
    self.bluetoothLogTextView.string = [@"\r\n" stringByAppendingString:self.bluetoothLogTextView.string];
    self.bluetoothLogTextView.string = [msg stringByAppendingString:self.bluetoothLogTextView.string];
}
-(void)stateLog:(NSString *)msg
{
    self.stateLogTextView.string = [@"\r\n" stringByAppendingString:self.stateLogTextView.string];
    self.stateLogTextView.string = [msg stringByAppendingString:self.stateLogTextView.string];
}

//form events

//form load
- (void)viewDidLoad {
    [super viewDidLoad];

    //Initialise flags
    self.bluetoothOn = NO;
    self.isScanning = NO;
    //self.isAdvertising = NO;
    //self.isAdvertisingInitialised = NO;

    //initialise bluetooth central  manager
    self.centralManager = [[CBCentralManager alloc] initWithDelegate:self queue:Nil];

    //initialise bluetooth perihperl manager
    //self.peripheralManager = [[CBPeripheralManager alloc] initWithDelegate:self queue:Nil];

}

- (void)setRepresentedObject:(id)representedObject {
    [super setRepresentedObject:representedObject];

    // Update the view, if already loaded.
}



//Bluetooth Central events
- (IBAction)startStopScan:(id)sender
{
    //check bluetooth
    if (!self.bluetoothOn){
        [self conLog:@"Bluetooth is OFF, Cannot start scan"];
        return;
    }

    //Do we need to start or stop the scan?
    if (!self.isScanning)
    {
        //We are not scanning, but we are starting a new scan
        //empty the foundPeripheralsPop
        [_foundPeripheralsPop removeAllItems];

        //Start the scan. (we scan for the service uuid used when advertising services)
        [self.centralManager scanForPeripheralsWithServices: Nil
                                                options: @{ CBCentralManagerScanOptionAllowDuplicatesKey : @NO }];

        //update flag
        self.isScanning = YES;

        //change button text to say stop Scanning
        [self.startStopScanBut setTitle:@"Stop Scanning"];

        //update log
        [self conLog:@"Starting scan for Peripherals"];
    }
    else
    {
        //We are scanning, Stop the scan
        [self.centralManager stopScan];

        //update flag
        self.isScanning = NO;

        //change button text to say start Scanning
        [self.startStopScanBut setTitle:@"Get Advertising Peripherals"];

        //update log
        [self conLog:@"Stopped scan for peripherals"];
    }
}

//the state of the adapter has changedA(su1 enabled or disabled bluetooth
-(void)centralManagerDidUpdateState:(CBCentralManager *)central
{
    if (central.state != CBCentralManagerStatePoweredOn)
    {
        [self stateLog:@"Bluetooth OFF"];
        self.bluetoothOn = NO;
    }
    else
    {
        [self stateLog:@"Bluetooth ON"];
        self.bluetoothOn = YES;
    }
}

//We have found a peripheral device while scanning.
-(void) centralManager:(CBCentralManager *)central
 didDiscoverPeripheral:(CBPeripheral *)peripheral
     advertisementData:(NSDictionary *)advertisementData
                  RSSI:(NSNumber *)RSSI
{
    NSString *deviceName = [advertisementData objectForKey:@"kCBAdvDataLocalName"];
    if (deviceName == nil || [deviceName  isEqual: @""]) deviceName = @"No Name";

    //log what device we discovered
    [self conLog:[NSString stringWithFormat:@"Discovered %@, RSSI: %@\n", deviceName, RSSI]];

    //Add device to select list
    [_foundPeripheralsPop addItemWithTitle:deviceName];


    self.foundPeripheral = peripheral;
    //[self.centralManager connectPeripheral:peripheral options:nil];
}

The issue I am having is that this OSX app will constantly find the same peripheral over and over kicking off the didFindPeripheral Function constantly. I have created a separate IOS project based on this code above and it does not find duplicates.

The peripherals I'm trying to find to is...
1. the Lynda.com peripheral examples running on my plugged in ios device.
2. Fitbit fitness tracker. (http://www.fitbit.com)

Is there anything I'm missing in OSX to stop these duplicates coming through?? Anyone got any ideas why its finding these devices over and over??

1 Answers1

0

Are you really only retaining a single discovered peripheral? Shouldn't that be storing it in an array?

If that isn't the problem, then it might be a buggy device, buggy Bluetooth firmware in the Mac, or it might simply be just at the edge of range, and the computer might be giving up on it and then re-detecting it. (I assume you've also implemented the - centralManager:didDisconnectPeripheral:error: delegate method, right?) Or you might be stopping the scan and restarting it on the Mac, but not doing that on iOS, because of differences elsewhere in the app.

Assuming that the bug is not in your code, my suggestion would be to try to recognize the redundant devices by comparing the identifier property on the CBPeripheral, and then update that item in your UI with the latest information for the device when the computer rediscovers it rather than adding a new item. (I'm assuming these devices have properly unique UUIDs, of course.)

dgatwood
  • 9,879
  • 1
  • 26
  • 49