Giter Site home page Giter Site logo

troystribling / bluecap Goto Github PK

View Code? Open in Web Editor NEW
713.0 32.0 115.0 6.75 MB

iOS Bluetooth LE framework

License: MIT License

Swift 99.68% Ruby 0.24% Objective-C 0.08%
bluetooth-low-energy bluetooth-beacons swift-framework corebluetooth peripherals cocoapods carthage centralmanager peripheralmanager swift

bluecap's People

Contributors

cbowns avatar gableroux avatar jeffreybergier avatar jessepollak avatar soulphalanx avatar troystribling avatar xuyuanme avatar zittix avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

bluecap's Issues

Advice migrating code, using new examples

Previous Code: Swift 2, BlueCap 0.1.0
New Code: Swift 3, BlueCap 0.2
Example Referenced: https://github.com/troystribling/BlueCap/blob/master/Examples/CentralManager/CentralManager/ViewController.swift#L132

I am currently in the middle of a migration to Swift 3, and at the same time I am updating some of my old code, and I was wondering if I could get some advice.

In my previous code, when calling .connect() on the Peripheral, I would use the .onSuccess syntax to handle the code to be executed after its completion.

However, looking at your (new) examples, it seems you've adopted a preferred syntax of using .flatmap() to handle a chain of closures.

I really like this syntax, the only problem I've encountered with it is when calling .terminate() or .reconnect() on the Peripheral. Here is the code I will be referencing:

.flatMap { [unowned self] (peripheral, connectionEvent) -> Future<Peripheral> in
            switch connectionEvent {
            case .connect:
                return peripheral.discoverServices([self.deviceUUID_CB])
            case .timeout:
                print(err_msg + "Connection Timeout, reconnecting.")
                self.statusMessage(nil)
                peripheral.reconnect()
            case .disconnect:
                print(err_msg + "Got disconnected, reconnecting.")
                self.statusMessage(nil)
                peripheral.reconnect()
            case .forceDisconnect:
                print(err_msg + "Forced Disconnect, terminating.")
                self.statusMessage(nil)
            case .giveUp:
                print(err_msg + "Giving up, terminating.")
                self.statusMessage(nil)
                peripheral.terminate()
            }
        }

The following is obviously creating an error as not all the switch's cases either return or throw.

Now I should obviously throw when it gets to .giveUp. But is there a way to have this closure loop when using .reconnect() and not interrupt the closure chain by throwing or having it proceed with a return statement?

background

when i try and enable background it doesnt seem to be working, all the permissions are there and the code is going through and verifying everything in the library but the monitoring doesnt seem to be picking up the beacons.

if swap to events ranging that works perfectly, when i swap to All or region boundary the enter / Exit in onStateDidChange is not being called.

and in background, when the app is not in the foreground everything stops straight away.

Im i doing something worng

Peripheral Objects Never Deallocated

I haven't taken an in depth look into where the exact problem is, but it looks like the Peripheral objects that are being generated aren't being deallocated. I assume there is a strong reference cycle being created somewhere preventing them from deallocating (unless there is some buffer that stores all discovered peripherals that I'm unaware of). I created a deinit method inside both the Peripheral and Peripheral wrapper objects and neither are ever called.

I've talked with an Apple engineer about this and it's a big problem when CBPeripheral objects are never released (and Peripheral holds a strong reference to the CBPeripheral). To simplify the issue, if I just took an array and added every peripheral I discover to it, CoreBluetooth would eventually crash after discovering so many devices. I'm unsure of exactly why CoreBluetooth needs the memory released, but I've actually seen this happen in my tests.

Let me know if there's anything I can do to help.

Question about multiple writes in sequence

I was reviewing the code for characteristic writes, and it looks like the code may be fragile for multiple writes in quick succession (specifically when writeValue is called multiple times before the didWriteValueForCharacteristic is called back for the first write). It looks like the writing flag in CharacteristicImpl can be set to false even if a write may be pending. Mock example timeline:

  1. First writeData() call
  2. Second writeData() call
  3. First writeData completes succesfully, didWrite() is called, sets writing flag to false
  4. Second writeData fails, and times out. Since the writing flag is now already false, timeoutWrite will NOT call writePromise.failure()

Did I miss something? It looks like iOS internally handles sequencing of multiple writes, but doesn't provide a way for the client to know which write succeeded. See for example:

http://stackoverflow.com/questions/10977649/writing-multiple-bluetooth-low-energy-characteristic-values-with-response

Therefore, it looks like a CoreBluetooth wrapper will have to queue up write requests so that it can echo the data written in the response-- a feature that the iOS stack currently lacks.

I'm still a relative newbie, so am I missing something here? Thanks for sharing your code, and any pointers are appreciated.

CBMutableDescriptors can't be added to MutableCharacteristics

As far as I can tell there is no way to add a CDMutableDescriptor to BlueCap's MutableCharacteristic class. The underlying CBMutableCharacteristic is not exposed either so there is no way to add the descriptors directly to the characteristic itself.

Issue with request

Hi,
Thank you so mu much for this git !
I run the peripheral example project but it shows some issues about request value.
Value of tuple type '(CBATTRequestInjectable, CBCentralInjectable)' has no member 'value'

Any help would be appreciated

write command not return expected result

i tried to read temperature from foramed devices with command 0x26 i can pairing and read info (name ,version , manufacturer) but i cann't write command 0x26 to read result

// Scaning 4 seconds for peripherals
[[LGCentralManager sharedInstance] scanForPeripheralsByInterval:10
completion:^(NSArray *peripherals)
{
// If we found any peripherals sending to test
for (LGPeripheral *per in peripherals) {
if ([per.UUIDString isEqualToString:@"2FF2DAFC-D4D5-4929-8E80-4CA23C56EEF2"]) {

     const uint16_t bytes[] = {0x26};
     NSData *data = [NSData dataWithBytes:bytes length:sizeof(bytes)];
        
         [LGUtils writeData:data
                charactUUID:@"00001524-1212-efde-1523-785feabcd123"
                serviceUUID:@"00001523-1212-efde-1523-785feabcd123"
                 peripheral:per completion:^(NSError *error) {
                     NSLog(@"Error : %@", error);
                     
                     [LGUtils readDataFromCharactUUID:@"00001524-1212-efde-1523-785feabcd123"
                                          serviceUUID:@"00001523-1212-efde-1523-785feabcd123"
                                           peripheral:per
                                           completion:^(NSData *data, NSError *error) {
                                               NSLog(@"Data : %s Error : %@", (char *)[data bytes], error);
                                           }];
                 }];
     
         
 }
     NSLog(@"name:%@ UUID:%@",per.name,per.UUIDString);
 }

}];

Return richer error objects

As a boomerang/follow-up to troystribling/SimpleFutures#1:

BlueCap should return a richer error object type than a simple NSError. This richer object should contain more information about the failure's origin: was it a failed filter? propagation of an upstream future's failure? etc etc.

Sing in project and Podfile.lock & Manifest.lock error

Hello everyone,

I have a concern and I think is very primary, I just downloaded this project and I was trying to test one of those examples, (CentralManager), but I take an error message immediately :

Showing Recent Issues
diff: /../Podfile.lock: No such file or directory

Showing Recent Issues
diff: /Manifest.lock: No such file or directory

Showing Recent Issues
error: The sandbox is not in sync with the Podfile.lock. Run 'pod install' or update your CocoaPods installation.

I have to say in Targets>General>Sing in, I couldn't use my Personal Team for this project.
I just wanted to ask if it's possible to help me resurrect this concern.

not able to subscribe to characteristic with indicate property

Hi,
first of all, let me thank you for this great tool! I currently use BlueCap to test the implementation of a characteristic that has the properties Write and Indicate. I would expect that I'm able to enable Notifications for that characteristic, but I'm not. Is this a know limitation or bug? Is there an other way to write the indication bit to the client characteristic configuration descriptor?

kind regards,
Torsten

Peripheral Connection Status Updates

Hey!

Hopefully you can help...
I need to know when the connection status of a peripheral is changed (either connected/disconnected).

Normally you set CBCentralManager.delegate to receive updates when this happens, but the BlueCapKit.CentralManager is already the delegate and implements both:
public func centralManager(_ central: CBCentralManager, didConnect peripheral: CBPeripheral)
public func centralManager(_ central: CBCentralManager, didDisconnectPeripheral peripheral: CBPeripheral, error: Error?)

These methods both update properties on the individual peripheral object but the FutureStream for the connection status is fileprivate.

Is there any way for me to be able to be notified about a peripheral connection status change? I really don't want to poll Peripheral.state

Thanks in advance :)

Questions on MFI and Connectionless Slave Mode

I have some C code that communicates at a low level, using the BlueZ lib, with the Bluetooth HCI on the Raspberry Pi 3, allowing it to emulate a peripheral.

I'm wondering if either my iPhone 6 or iPad Pro 10.5 has the capability to do this too. There's two parts to this:

  1. It's still not clear to me if this would need MFI? So far as I can tell from Apple's docs, almost anything that works on Bluetooth LE is exempt, but I see contradictions to this in various posts.

  2. Whether iOS and underlying hardware allows some of the Bluetooth modes I need

Looking at your excellent docs, I do see PeripheralManager - however, this is at a higher abstraction than I'm used to. For instance, I have this piece of code:

bt_hci_send(BT_HCI_CMD_SET_EVENT_MASK_PAGE2);

Which sets the Raspberry Pi bluetooth module to something called connectionless slave broadcast, setting it up to listen for BT_HCI_EVT_CONN_REQUEST from the master device, and if so commence with the synchronization train.

I know that not even all third party Bluetooth 4 chips support this mode, so wondering if iOS/BlueCap supports this? I can't see anything like it in your code, and it doesn't help Apple have an undocumented proprietary Wifi/Bluetooth chip, so far as I can tell from iFixit teardowns.

CBCentralManagerInjectable protocol conformance error

I'm developing my app in Swift 3.0 and added BlueCapKit using CocoaPods.
I've updated the flag 'Use Legacy Swift Language Version' to 'Yes' for BlueCap.

However I'm getting this particular issue which says Type 'CBCentralManager' does not conform to protocol 'CBCentralManagerInjectable'

And this happens due to the 'state' variable.

Here's a screenshot of the error to help you. Can you please help solve this?

screen shot 2016-11-15 at 10 59 21 pm

Critical bug

There are wrong logic when called function loadRetrievedPeripheral().

  1. Call func loadRetrievedPeripheral(_ peripheral: CBPeripheralInjectable) -> Peripheral
  2. Created new instance of newBCPeripheral (line 262 CentralManager.swift) and it sets
    self.cbPeripheral.delegate = self (line 203 in Peripheral.swift)
  3. Replaced peripheral (line 262 CentralManager.swift) and
    self._discoveredPeripherals[peripheral.identifier] = newBCPeripheral
    and it removes old peripheral and calls deinit (line 208 in Peripheral.swift) BUT it also removes delegate for new peripheral
  4. As result it never calls any of peripheral delegate functions

Way to fix:
Peripheral.swift

  1. remove
    deinit {
    self.cbPeripheral.delegate = nil
    }
    2 ) and replace:
    var delegate: CBPeripheralDelegate? { get set }
    with:
    weak var delegate: CBPeripheralDelegate? { get set }

Bluetooth device with password

Hello, i have to connect to a bluetooth device that requires a password.
How can i add it programmatically or display an input field to the user?

Swift 3 compatibility

Hey, I'd love to see this lib available in Swift 3 so I can implement it in my project.

Thanks ๐Ÿ˜„

Alert support for iOS 7.1

Right now I struggle with backward compat, I must run on 7.1.
Your code uses alert messages this way:

self.presentViewController(UIAlertController.alertOnError(error), animated:true, completion:nil)
with an extension to the UIAlertController.
This function returns an UIAlertController.
It does not exist on iOS7

So, I get a dyld error: Symbol not found: OBJC_CLASS$_UIAlertAction

My solution would be:

var device : UIDevice = UIDevice.currentDevice()!;
var systemVersion = device.systemVersion;
var iosVerion : Float = systemVersion.bridgeToObjectiveC().floatValue;
if(iosVerion < 8.0) {
let alert = UIAlertView()
alert.title = "Error"
alert.message = error.localizedDescription
alert.addButtonWithTitle("OK")
alert.show()
}else{
var alert : UIAlertController = UIAlertController(title: "Error",
message: error.localizedDescription, preferredStyle: UIAlertControllerStyle.Alert)
alert.addAction(UIAlertAction(title: "OK", style:.Default, handler: nil))
self.presentViewController(alert, animated: true, completion: nil)
}

But I can't return a UIAlertView and a UIAlertController with the same methods you use
in your code.

Suggestion, I would change all your calls to
self.presentViewController(UIAlertController.alertOnError(error), animated:true, completion:nil)

to a central notification object or something.
Suggestions?

Support For Writes Without Responses

From this: https://github.com/troystribling/BlueCap/blob/master/BlueCapKit/Central/Characteristic.swift#L321

It looks like BlueCap is hardcoded to always write with response. I'd like to be able to write without response for my application.

There are some complications implementing write without responses and sending a large amount of data. Since there are no callbacks to let you know when the write is done, the writes have to be spaced out based on the CI. I don't know of a good way to do this right now, I actually just asked this question on SO (http://stackoverflow.com/questions/33442472/ios-bluetooth-le-proper-way-to-write-without-response).

It'd be nice to be able to just pass a large chunk of data in and have the library handle the timing, but since that's not readily defined, the best way to do it for this library is probably just to enable the functionality of WriteWithoutResponse which just passes the data straight into the writeValue method and leaves the timing/write frequency up to the user's application.

CBCharacteristicInjectable

(characteristic: CBCharacteristicInjectable, error: NSError?)

I have this issues from my BLE device !
Can you help ?

Discovered Services and Characteristics are removed on new search

Hey!

When I am reading/writing to characteristics on my BLE device, I configure the device and then start getting notified for updates to a particular characteristic (so that I can monitor a button press).

Alongside this I regularly poll the battery level and signal strength of the peripheral but whenever I try to discover new services/and or characteristics, the previous services and characteristics are removed and forgotten about. This means that when the button is pressed I see the log message come through from CoreBluetooth that a characteristic was updated, but it can't find which peripheral the characteristic belongs to.

I can see references to discoveredServices.removeAll() and discoveredCharacteristics.removeAll() in a few places.

Is there a reason that services and characteristics are removed from the Peripheral when you try to discover new ones? I'm happy to submit a PR to resolve this if desired but wanted to check beforehand.

Thanks!

Updates to the README

The podspec says the minimum target is 9.0 and the minimum Cocoapod version as 1.1.

https://github.com/troystribling/BlueCap#cocoapods
This example uses a target of 10.0, should probably be 9.0 to avoid confusion.
Also, the library now requires CocoaPods 1.1+.

https://github.com/troystribling/BlueCap#manual
The manual installation says 8.0, should definitely be 9.0 there.

Nothing really important here obviously, but thought I'd create a ticket so you notice it. Great library by the way.

tvOS Support

First thanks for this great library and example app!

I'd like to use this in a project where a tvOS-App connects to its counterpart iOS-App (which serves as a remote to the TV app). As far as I can tell this doesn't support tvOS though (Carthage couldn't find a scheme for tvOS) which is a pity. Do you plan to add tvOS support and do you think there are parts that won't work or make any sense on tvOS? If so, which ones are they?

I'm willing to help getting tvOS-support done, so if there's anything I should know just tell me. :)
Thank you for your help!

next_release example

Hi, I'm trying to test next_release branch but I'm new in Swift, what's the new syntaxis to create a new connection and when it's successful, it could probably be something like this? Could you give me a more complete example please?

manager.startScanning(forServiceUUIDs: [CBUUID]?).flatMap(mapping: (Peripheral) throws -> Future)

Thanks in advance

Disconnection when pushing new ViewController

Hi Troy,

When I connected a device and passing the peripheral to new controller,it works fine but If I push another view controller, it will disconnect. So here is the scenario, from view A discovered and connected -> pass to B able to send command -> from B to C , the peripheral is being passed but it will disconnect right away.

Is there's something that was missing that I need to pass? Like the discovery future? It worked for the first pass , but always disconnect from B to C.

Thanks.

"CenteralError.peripheralNotConnected" Does Not Exist

Here's an excerpt from the simple Central example:

let peripheralDiscoveredFuture = peripheralConnectFuture.flatmap {(peripheral, connectionEvent) -> Future<Peripheral> in
    if peripheral.state == .Connected {
        return peripheral.discoverPeripheralServices([serviceUUID])
    } else {
        let promise = Promise<Peripheral>()
        promise.failure(CenteralError.peripheralNotConnected)
        return promise.future
    }
}

Two things:

  1. CenteralError should be CentralError
  2. peripheralNotConnected is not a member of the CentralError enum. There is only one member, IsScanning.

Future previously completed.

I have this error message. Why? What it means exactly?
Terminating app due to uncaught exception 'Future complete error', reason: 'Future previously completed.'

Replacement For `WhenPowerOn` in next_release branch

Hello,

I am wondering what the correct replacement is for WhenPowerOn/WhenPowerOff in the next_release branch.

Previously, I had:
peripheralManager!.whenPowerOff().onComplete({ _ in
Should I have this now?

peripheralManager!.whenStateChanges().onComplete(completion: { (managerState) in
            if self.peripheralManager?.state == ManagerState.poweredOff {

And also, previously I had this, from the docs:

let scanningFuture = manager.whenPowerOn().flatmap {
    manager.startScanningForServiceUUIDs([serviceUUID])
}

What should I have now?

Thanks

CentralManager state reported as unsupported if already connected to a peripheral. Errors thrown are sometimes CoreBluetooth errors instead of PeripheralError.

If I connect to, discover services and characteristics, notify and receive notification updates with a peripheral and I use the same central to attempt to connect and do the same with another peripheral, the state of the CentralManager is unsupported, yet if I forgo the state checking and connect anyway, it works as intended.

I am running this on an iPhone 7 Plus 256GB running iOS 10.3.2 beta 4.

Here is my code for the connection, discovery, etc.:

func connect() {
        let dataUpdateFuture = self.central.whenStateChanges().flatMap { [unowned self] state -> FutureStream<Void> in
            
            switch state {
            case .poweredOn:
                return self.peripheral.connect(connectionTimeout: 10.0)
            case .poweredOff:
                throw BLEError.poweredOff
            case .unauthorized:
                throw BLEError.unauthorized
            case .unsupported:
                throw BLEError.unsupported
            case .resetting:
                throw BLEError.resetting
            case .unknown:
                throw BLEError.unknown
            }
 
            return self.peripheral.connect(connectionTimeout: 10.0)
            }.flatMap { [unowned self] () -> Future<Void> in
                //Update UI
                self.peripheral.startPollingRSSI(period: 0.25, capacity: 10).onSuccess { rssi in
                    BLE.sharedInstance.invoke(method: { $0.didUpdateRSSI?(rssi) })
                }
                BLE.sharedInstance.invoke(method: { $0.didGetPeripheralUUID?(self.peripheral.identifier.uuidString) })
                self.uuid = self.peripheral.identifier.uuidString

                print("Discovering services")
                return self.peripheral.discoverServices([s2UUID], timeout: 10.0)
            }.flatMap { [unowned self] () -> Future<Void> in
                guard let service = self.peripheral.services(withUUID: s2UUID)?.first else {
                    throw AppError.serviceNotFound
                }
                print("Discovering characteristics")
                return service.discoverCharacteristics([rawUUID], timeout: 10.0)
            }.flatMap { [unowned self] () -> Future<Void> in
                guard let service = self.peripheral.services(withUUID: s2UUID)?.first else {
                    throw BLEError.serviceNotFound
                }
                guard let rawCharacteristic = service.characteristics(withUUID: rawUUID)?.first else {
                    throw BLEError.rawDataCharacteristicNotFound
                }
                print("Start notifying raw characteristic")
                self.rawDataCharacteristic = rawCharacteristic
                return rawCharacteristic.startNotifying()
            }.flatMap { [unowned self] () -> FutureStream<Data?> in
                guard let rawCharacteristic = self.rawDataCharacteristic else {
                    throw BLEError.rawDataCharacteristicNotFound
                }
                print("Receiving raw characteristic notification update")
                return rawCharacteristic.receiveNotificationUpdates(capacity: 30)
        }

As for errors being thrown, I have to use CBErrors to catch some of them, like so:

dataUpdateFuture.onFailure { error in
            print("Data update error: \(error)")
            switch error {
            case BLEError.serviceNotFound:
                self.disconnect()
            case PeripheralError.disconnected, PeripheralError.connectionTimeout, CBError.connectionTimeout, CBError.connectionFailed:
                self.connect()
            default:
                break
            }
        }

Futures: `onFailure` blocks do not prevent failures from falling through to later `onFailure` blocks

I've got a question about BlueCap (or perhaps it's for SimpleFutures) and its handling of onFailure:

I've got a bunch of simple BT code strung together to discover, filter, and connect to a device. I've got onSuccess and onFailure blocks written for each of my calls.

Specifically, I'm scanning for all nearby devices, and using a withFilter: block to search for a peripheral with a specific name pattern. When I reject the devices by returning false, the onFailure block logs, "Filter failed", as I expected.

        peripheralConnectFuture.onFailure { (error) -> Void in
            print("Error connecting to the device. \(error.localizedDescription)")
        }

However! I'm seeing something frustrating in subsequent futures:

After my filter passes, I connect to the peripheral. I discover services in peripheralConnectFuture:

let peripheralServicesDiscoveredFuture = peripheralConnectFuture.withFilter { (peripheral, connectionEvent) -> Bool in
โ€ฆ

In its onFailure block,

         peripheralServicesDiscoveredFuture.onFailure { (error) -> Void in
            print("Error discovering services: \(error.localizedDescription)")
        }

I'm receiving a second failure callback, for devices I rejected with the withFilter block.

Is this by design, or is this a bug?

Notifications Fail To Properly Deliver Packets

I'm using BlueCap as a central to connect to a peripheral that has a notification characteristic. I subscribe to that characteristic and then set up notifications like so:

//Subscribe to the notification
if let service = peripheral.service(SERVICE_UUID), txCharacteristic = service.characteristic(TX_CHARACTERISTIC_UUID)
{
    //Set subscription
    txCharacteristic.setNotifyValue(true)

    ///Set up updates for the notification
    let updatesFuture = txCharacteristic.recieveNotificationUpdates()

    updatesFuture.onSuccess({
        characteristic in

        if characteristic.dataValue != nil
        {
            var data = [UInt8](count: characteristic.dataValue!.length, repeatedValue: 0)
            characteristic.dataValue!.getBytes(&data, length: data.count)

            var byteStr = ""
            for byte in data
            {
                byteStr += String(format: "%02X ", arguments: [byte])
            }
            print("updatesFuture: \(byteStr): \(String(UTF8String: dispatch_queue_get_label(DISPATCH_CURRENT_QUEUE_LABEL))!)")
        }
    })

    updatesFuture.onFailure({
        error in

        //Error
    })
}
else
{
    //Error
}

I also added a log similar to the one above here: https://github.com/troystribling/BlueCap/blob/master/BlueCapKit/Central/Peripheral.swift#L529

My peripheral sends more than 20 bytes of data across a set of packets. In this case, the data it was attempting to send was 5 packets, 72 bytes.

Here are the logs from the first attempt:

1a. didUpdateValueForCharacteristic: 7E 01 53 00 00 00 01 08 06 12 0C 50 94 BF 57 86 12 DA DD FC : com.gnos.us.central.main
2a. didUpdateValueForCharacteristic: 92 93 F9 1A 40 18 15 8A 78 D8 D3 1C 3A 66 30 E2 DC CB 66 53 : com.gnos.us.central.main
1b. updatesFuture:                   7E 01 53 00 00 00 01 08 06 12 0C 50 94 BF 57 86 12 DA DD FC : com.apple.main-thread
3a. didUpdateValueForCharacteristic: D4 BE 03 7A E3 AC 57 49 CE 62 C4 BD 01 82 E9 1D 2E 39 07 8F : com.gnos.us.central.main
2b. updatesFuture:                   D4 BE 03 7A E3 AC 57 49 CE 62 C4 BD 01 82 E9 1D 2E 39 07 8F : com.apple.main-thread
4a. didUpdateValueForCharacteristic: 29 00 2F A1 25 F2 AF AB C1 17 BE AC 9D C7 92 BD 65 7C 67 B1 : com.gnos.us.central.main
3b. updatesFuture:                   D4 BE 03 7A E3 AC 57 49 CE 62 C4 BD 01 82 E9 1D 2E 39 07 8F : com.apple.main-thread
4b. updatesFuture:                   29 00 2F A1 25 F2 AF AB C1 17 BE AC 9D C7 92 BD 65 7C 67 B1 : com.apple.main-thread
5a. didUpdateValueForCharacteristic: B3 B6 5A DA 91 B0 93 19 7A AF 3D 7F : com.gnos.us.central.main
5b. updatesFuture:                   B3 B6 5A DA 91 B0 93 19 7A AF 3D 7F : com.apple.main-thread

The data arrives correctly in the proper order, as logged by the didUpdateValueForCharacteristic logs. But when it is delivered to the future (as logged by the updateFuture logs), there is a packet missing. Packet 2a was never delivered and packet 3a was delivered twice (2b and 3b).

Here's another example of a retry of the same set of data:

1a. didUpdateValueForCharacteristic: 7E 01 53 00 00 00 01 08 06 12 0C 50 94 BF 57 86 12 DA DD FC : com.gnos.us.central.main
2a. didUpdateValueForCharacteristic: 92 93 F9 1A 40 18 15 8A 78 D8 D3 1C 3A 66 30 E2 DC CB 66 53 : com.gnos.us.central.main
3a. didUpdateValueForCharacteristic: D4 BE 03 7A E3 AC 57 49 CE 62 C4 BD 01 82 E9 1D 2E 39 07 8F : com.gnos.us.central.main
1b. updatesFuture:                   7E 01 53 00 00 00 01 08 06 12 0C 50 94 BF 57 86 12 DA DD FC : com.apple.main-thread
2b. updatesFuture:                   D4 BE 03 7A E3 AC 57 49 CE 62 C4 BD 01 82 E9 1D 2E 39 07 8F : com.apple.main-thread
3b. updatesFuture:                   D4 BE 03 7A E3 AC 57 49 CE 62 C4 BD 01 82 E9 1D 2E 39 07 8F : com.apple.main-thread
4a. didUpdateValueForCharacteristic: 29 00 2F A1 25 F2 AF AB C1 17 BE AC 9D C7 92 BD 65 7C 67 B1 : com.gnos.us.central.main
5a. didUpdateValueForCharacteristic: B3 B6 5A DA 91 B0 93 19 7A AF 3D 7F : com.gnos.us.central.main
4b. updatesFuture:                   29 00 2F A1 25 F2 AF AB C1 17 BE AC 9D C7 92 BD 65 7C 67 B1 : com.apple.main-thread
5b. updatesFuture:                   B3 B6 5A DA 91 B0 93 19 7A AF 3D 7F : com.apple.main-thread

I suspect there is some foul play going on with how the futures manage firing data in the queues. It looks like sequential promises being delivered to a futurestream are not guaranteed to be delivered back to the result in the same order.

I'll admit I'm not well versed in futures, so it's very possible I'm just not doing something right. If that's the case, would you mind advising the proper way to get notifications delivered in the order in which they're received?

support for cocoa pods

More of a request rather than an issue. Do you intend to add support for cocoa pods for BlueCap? It makes updates and new features / bug fixes much easier to incorporate than manually adding to projects.

Get CBPeripheral from BlueCapKit.Peripheral?

Anyway to get a CBPeripheral from BlueCapKit.Peripheral? I'm using a framework to upgrade the firmware OTA and it only accepts CBPeripherals and I would prefer to not have to rewrite it or write another central using CoreBluetooth calls.

Thanks for your time.

Crash when using BCCentralManager during application launch.

I ran into a repeatable crash when I open my app via a push notification, and the BCCentralManager is started in didFinishLaunchingWithOptions:. The Optional BCCentralManager.cbCentralManager is nil during the didUpdateState() callback. The problem is there is a race condition because the constructor sets the delegate to self before assigning to self.cbCentralManager, so if you get an event (like PoweredOn) during initialization, the didUpdateState() callback will happen before self.cbCentralManager is set, and you will get a crash.

I was able to fix it by passing in nil to the CBCentralManager delegate constructor, then explicitly setting the delegate after initialization, e.g.:

    self.centralQueue = Queue("us.gnos.blueCap.central-manager.main")
    super.init()
    self.cbCentralManager = CBCentralManager(delegate: nil, queue: self.centralQueue.queue)
    self.poweredOn = self.cbCentralManager.state == .PoweredOn
    self.startObserving()
    self.cbCentralManager.delegate = self

An alternative way to fix it would be to check the Optional cbCentralManager before using it.

Writing to characteristic not supported, but why?

I get the error mesage "Error Domain=BlueCap Code=5 "Characteristic write not supported" UserInfo={NSLocalizedDescription=Characteristic write not supported}" in the log and I don't get why.
I am not using a profile, but followed the Central (without profile) example and it seems like the writing property is not enabled.
But why is that?
How do I enable the property?
I tested this with pure CoreBluetooth before and writing to the same characteristic was not an issue.
I am talking to a UART emulation over BLE service using a Nordic nRF8001 and the library by RedBearLabs -> https://github.com/RedBearLab/nRF8001/.

// on power, start scanning. when peripheral is discovered connect and stop scanning
    let manager = CentralManager.sharedInstance
    let peripheralConnectFuture = manager.powerOn().flatmap {_ -> FutureStream<Peripheral> in
      manager.startScanningForServiceUUIDs([self.serviceUUID], capacity:10)
      }.flatmap {peripheral -> FutureStream<(Peripheral, ConnectionEvent)> in
        manager.stopScanning()
        return peripheral.connect(10, timeoutRetries:5, disconnectRetries:5)
    }

    // on .Timeout and .Disconnect try to reconnect on .Giveup terminate connection
    peripheralConnectFuture.onSuccess{(peripheral, connectionEvent) in
      switch connectionEvent {
      case .Connect:
        break
        // TODO
      case .Timeout:
        peripheral.reconnect()
      case .Disconnect:
        peripheral.reconnect()
      case .ForceDisconnect:
        break
        // TODO
      case .Failed:
        break
        // TODO
      case .GiveUp:
        peripheral.terminate()
      }
    }

    // discover services *and* characteristics
    let characteristicsDiscoveredFuture = peripheralConnectFuture.flatmap {(peripheral, connectionEvent) -> Future<Peripheral> in
      if peripheral.state == .Connected {
        return peripheral.discoverPeripheralServices([self.serviceUUID])
      } else {
        let promise = Promise<Peripheral>()
        promise.failure(CentralError.peripheralNotConnected)
        return promise.future
      }
    }

    let writeCharacteristicFuture = characteristicsDiscoveredFuture.flatmap {peripheral -> Future<Characteristic> in
      if let service = peripheral.service(self.serviceUUID), characteristic = service.characteristic(CBUUID(string:self.rxUUID)) {
        let message = WhisperParameterlessMessage(rawValue: WhisperMessageType.Nop.rawValue)
        return characteristic.write(message!, timeout:20.0)
      } else {
        let promise = Promise<Characteristic>()
        promise.failure(CentralError.rxCharacteristicsNotFound)
        return promise.future
      }
    }
    writeCharacteristicFuture.onSuccess {characteristic in
     // Log
    }
    writeCharacteristicFuture.onFailure {error in
      // Log
    }

    let writeCharacteristicFuture2 = writeCharacteristicFuture.flatmap { characteristic -> Future<Characteristic> in
     // Log
      let message = WhisperInteractiveChannelSetMessage(rawValue1: [0], rawValue2: self.kDefaultMessageParameters)
      return characteristic.write(message!, timeout:20.0)
    }

    writeCharacteristicFuture2.onSuccess {characteristic in
      // Log
    }
    writeCharacteristicFuture2.onFailure {error in
      //  Log
    }

Scanning services automatically filter out same UUID services?

Hi, the device we create has 2 same UUID services for battery from different sources. When I use bluecap service discovery, it automatically filter out the service. So when I use other BLE app, I will able to find lets say total 5 services, but bluecap only show 4 services due to same UUID? Is it possible to remove the filter option? If so , how can I do it?

Thank you.

Peripheral.connect retries even after a timeout

Hi,

I noted that the peripheral.connect tries to connect even after getting a timeout. Here is a scenario.

Maintain a peripheral connected to a central A
Run peripheral.connect(timeout: 10) on central B. B cannot connect since the connection is owned by 1.
onFailed is called after the timeout on central B
central A disconnects
Central B connects but it should not because we got a timeout

Is there a way to avoid this ?
Thanks,

Connection callbacks not called if scanning is not stopped

Unlike in the examples where stopScanning() is called before connect(), I'd like to keep scanning for other devices after making a connection.

In didConnectPeripheral(), connectionPromise? was nil because the Peripheral in _discoveredPeripherals[] was overwritten in didDiscoverPeripheral() which always creates a new Peripheral instance.

Is it possible to keep objects in _discoveredPeripherals[] stable? Update the properties instead of replacing the object.

This will allow holding references to the Peripheral object.

I'm happy to discuss more or even coding.

Cannot Run Examples

EDIT PART 2 - It was due to XCode 7. Example now runs for me. Perhaps call it out a bit more in the README. Will close this issue.

EDIT - Missed the XCode 7 Requirement. Will try that now.

Been at this for a solid 8 hours now trying to get any of the examples to run. Many issues with code-signing, then I found these instructions to get past this issue.

Since then I've tried a few different ways of running the examples, but none work. I've tried:

  • click the Xcode Project file from a fresh clone of the repo
  • copy all files from the Beacon example into a new folder, then copy all files from the BlueCapKit folder, add the .framework into my project
  • copy all files from Beacon example, then use Carthage to add BlueCap as a dependency
  • fastlane

Xcode 6.4
OSX 10.10.5

I admit that I'm not an iOS developer, but I also can run a C compiler and have built other iOS projects in the past. But this I just cannot make work. Not sure why. If there's something missing from the README, that would be helpful to add in even more detail there.

Is it possible to setNotifyValue for a Characteristic once you've discovered it?

I'm working with a library right now from my chipset manufacturer, and trying to rewrite this and wrap it with the BlueCap framework, but I'm having trouble with the BLE messaging because I need to be able to setNotifyValue for a characteristic once I've discovered it. For example, the manufacturer's library makes this call:

[self.connectedPeripheral.peripheral
 setNotifyValue:YES
 forCharacteristic:characteristic];

This call is made after the services and characteristics have been discovered, and is basically saying, "I've found this characteristic on my peripheral, and now I want to be notified of changes to it." However, the BlueCap library wraps setNotifyValue into a private internal function, so when the characteristic is discovered, the initializer casts it to a CBCharacteristicInjectable, and the internal cbCharacteristic.isNotifying value is set to NO, and there's no way to change this after the fact, as far as I can tell. Am I missing something simple? Is there something more complex, like me needing to create a profile for the characteristics on my device? Or do I need to figure out a way to fix this and send a PR? Thanks for your help, and thanks for this awesome framework.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.