BLE & problems while learning

I've just started playing with the BLE code, and come across a couple of things which have caused me problems so far. I thought I'd mention them here in case I'm doing something wrong, or they shouldn't happen or maybe it will help someone else:

  •  I thought I'd start off with the easiest uuid (or so I thought haha!) - so I set out to use the generic access, and get the device name ...
    • So service uuid = 00001800-0000-1000-8000-00805f9b34fb
    • Characteristic uuid = 00002a00-0000-1000-8000-00805f9b34fb
  • Running this in the simulator works fine to register the profile, but as soon as I try on my watch it crashes. No stack trace or anything. Just "Error: System Error" and "Details: Profile Registration Unhandled Error". Eventually I get around to trying a different (random-ish) uuid and of course that works fine ... So I'm guessing it is just the generic access one that doesn't work - maybe because the system code is using it itself in some way? (as device name is returned in scan results?)
  • A second problem that didn't help, is that in the simulator when I call BluetoothLowEnergy.registerProfile() then onProfileRegister() in the delegate is not called, making it hard to check the code. Again it turns out that running on my watch it works differently, and onProfileRegister() is actually called correctly.
  • What actual device are you trying to connect to?  If you start with the nordicthingy52 sample, and in the delegate, have "contains" always return true, you build up a list if scan results for every BLE device in range.

    when are you registering the profiles?

  • Is the simulator set up to test BLE with the nRF52-dk or the nordic dongle? (see the programmer's guide)

  • Nope, I don't have any of the Nordic BLE hardware attached - I was just using the simulator to verify my code path and check for errors before actually running it on my watch.

    To start with I'd just like to connect to anything and read some values Slight smile Just trying to see what is possible. I'll try a scan with my phone next to get some real uuids other than the generic ones, and see if I can connect to something.

    I'm not sure what you mean by "contains" in the delegate - I can't find any mention of that in the API doc.

    I tried registering the profiles in various places as I wasn't sure why things weren't working. I tried in the application.GetInitialView(), onLayout() of the view, and currently in compute() of the (datafield) view. I thought maybe I was registering the profiles (and starting scanning) too soon after setting the ble delegate. But now I think that it doesn't matter so I'll move it all back to the same place in the code.

  • Use nRF Connect on the phone.

    "contains" is a function in the BLE delegate in the nordic sample if you just have the first line "return true", you'll get a list of all BLE devices that are advertising in the sample.  It doesn't need to be a thingy52.

  • Aha that was a useful tip! I'm not using the sample, but I can see now that the scanning returns everything (and not just things that match the profile you have registered as I first thought).

    I'm getting various things showing up with different signal strengths which is good Slight smile Although not getting any names from the scan result (whereas the phone app is showing names). So I'll need to find a way to work out what is what.

    I'll see if I can read some data Slight smile

  • Well I'm able to read some values from an e-bike now, so that feels cool!

    But a couple of odd things I noticed today in the BLE code:

    When I pair to a new device then onConnectedStateChanged() does not always get called in the delegate. I'd expect the state to always change to connected after pairing. But sometimes I was waiting for the state to change but it never would. I've added a check for whether the device .isConnected() immediately after calling pairDevice() and if it is then I don't wait for onConnectedStateChanged() to be called and that seems to avoid waiting forever. I think this state could occur when exiting the datafield and then starting it again - presumably the device and watch stay connected over bluetooth even though the app was exited briefly, which is why it doesn't report a change of state.

    I'm not sure if there is a limit to how many times you can call Characteristic.requestRead() without waiting for onCharacteristicRead() to be called in the delegate each time? I was getting some weird crashes when turning off the e-bike while it was paired to my watch, and every time it has been on the line with requestRead(). I was either getting an exception or symbol not found error - and it just doesn't make sense on that line of code. And I was always checking that the device was connected before requesting the read. However I then started initiating a new read only after the previous read had finished and that seemed to stop the crashes. I'm slightly worried though that I may still get a crash in the future if requesting a read happens to line up on the wrong time with disconnecting a device.

  • I'm not sure if there is a limit to how many times you can call Characteristic.requestRead() without waiting for onCharacteristicRead() to be called in the delegate each time

    You want to queue requests.

    do a read, wait for a response, do the next read, etc.

    if the characteristic supports notify, you can enable that, and then you'll see the data in onCharacteristicChanged() without doing a read loop (more efficient).  You'll want to do a queue of the notify requests to get things rolling.

  • if you look at piGD in the blog I did

    https://forums.garmin.com/developer/connect-iq/b/news-announcements/posts/would-you-like-some-raspberry-pi-with-your-connect-iq

    there's a file called commqueue.mc that's a simple queuing, where you add something to the queue with something like

    queue.add(self,[char,queue.C_READ,null],door);

    where self is the view, char is the characteristic, queue.C_READ is the operation, "null" here is data to be written if writing, and "door" is the UUID of the characteristic and is for debugging.

    at the end of onCharacterristicRead() you'll see I do a queue.run() to handle the next thing in the queue.

    setNotifity() in the main view turns notifications on or off for a given characteristic.

    There's a bug in the queuing code (something you can avoid) where I set a timeout when something is added, and if you keep adding things faster than the timeout, the timeout gets reset so you won't see a timeout if it occurs.

  • Thanks, that sounds like a good technique Slight smile I'll check it out!

  • Hi, didn't played with BLE integration yet, but have one question before I start. Can I connect to multiple BLE sensors in the same time from one CIQ app (datafiled)? Thanks