This post is older than 2 years and might not be relevant anymore
More Info: Consider searching for newer posts

[iOS App development] Need delay after connection for sending via NUS?

  • Using SDK 7.2 and S110 7.1

  • IDE : IAR EWARM 7.1

  • Board : PCA10001 (Revision 2 MCU)

  • Service : Battery Service (BAS), Nordic UART Service (NUS)

- Using "experimental_ble_app_uart" example project

  • Smart Phone: iPhone 6, 6 Plus (iOS 8.2 ~ 9.2)

  • Using Objective C and Swift

/********************************************/

Hi, I'm prototyping something with the PCA10001.

Suppose my device (peripheral, the PCA10001) name was "Nordic_NUS".

This device was advertising and after connection (pairing) was established,

I send the phone's current time using NUS and UNIX time stamp.

My custom iOS App splits the time stamp value to several bytes and sends it via NUS.

However, without giving a delay after pairing with "Nordic_NUS",

the peripheral fails to receive the time stamp value.

In other words, a breakpoint is not triggered when it is placed like this. breakpoint

I changed the code. It simply echoes back the received data.

Whereas if I set a delay after pairing before sending the timestamp, the breakpoint is triggered.

/***********************************************/

Here is my code of my iOS App.

void
_device syncDeviceTime];

public func syncDeviceTime(){
     request(CommandTypes.RequestTimeSync)
}

func request(type: CommandTypes, parameter: NSData? = nil){
let cmdData = NSMutableData()
        cmdData.appendBytes([type.rawValue] as Array<Character>, length: 1) // Command
switch type{

    case .RequestTimeSync:
        // Encoding
        let dateSec = UInt32(NSDate().timeIntervalSince1970)
        var timeArray: [UInt8] = []
        for i: UInt32 in 0...3 {
            let value: UInt8 = UInt8((dateSec >> ((3 - i) * 8)) & 0xFF)
            timeArray.append(value)
        }
        cmdData.appendBytes(timeArray, length: 4)
    default:
        break
    }
    
    // Send Request.
    let characteristic = characterMap[keyUARTTx]
    if let char = characteristic {
        //NSLog("Write \(cmdData.bytes[0]) \(cmdData.bytes[1])")
        self.cbPeripheral?.writeValue(cmdData, forCharacteristic: char,
            type: CBCharacteristicWriteType.WithResponse)
    }
}

When I set a delay for 2 second after connection, the peripheral received the contents.

However, if I set a delay about 0.3 seconds, if fails; the breakpoint is not triggered.

/**************************************/

So my questions are,

  1. After connection (whether bonding or pairing), does it need a delay for sending something?

Compared to querying the battery percentage using BAS, this was queried fast.

  1. If needed, how much delay is it needed?

Also, is there a reason described for using that delay vaule?

  1. Lastly, is there a way to send a data after connection without casting a delay?

Regards, Mango

    1. no it doesn't
    2. no delay is needed so the answer is 0
    3. yes you discover characteristics on the iOS side and when you get the callback that they have been discovered, you can send immediately after that - it's unclear whether your code is doing that or not or are using some cached characteristic which isn't actually yet valid.

    connect then discover services then discover characteristics then send

  • Wow, thanks for the quick response.

    I coded the latter way (I used the cached characteristics). I should check the callbacks.

    P.S.) Merry Christmas RK :)

  • Merry merry, in fact it's late enough already it's time to stop coding, and start drinking, so no more posts today!

  • Hi RK, come to think of it, I wonder the cached characteristic are invalid.

    For instance, this example uses only one service; the NUS. I added BAS (Battery service) to this example.

    After multiple connection and disconnection, without adding extra service or

    changing the device name, I am curious whether the cached characteristics are invalid.

    To be sure, since I didn't fully uploaded my source code, we can't directly see the problem.

    So my question is, how do I know the cached characteristics are invalid?

  • They're invalid because the CoreBluetooth documentation tells you they are invalid. Actually invalid is too strong a word, they are valid, they know what handle on what device they refer to however until iOS goes through the entire process of connection and discovery, even if internally iOS has the information cached, and calls you back to tell you it's finished, using them doesn't do anything, data goes nowhere. That's why your 'delay' hack worked, by the time you'd delayed, iOS had finished connection.

    Caching them is pretty pointless - there's plenty of other cases, eg when bluetooth is completely reset, where they have a good chance of becoming entirely invalid, or if you change the client code and move handles around, you're going to write to the wrong ones. Just go through the discovery process, if it's slow then bond to the device and iOS will internally cache for you.

Related