Question

I've been trying to read data from a device via Bluetooth 2.1 using an RN-42. The device pairs to an iPhone or iPad Mini, and data is streamed across briefly, but the iOS & BT module disconnect (unpair) within seconds (less than 10). The device is outputting data 5-10kB/s, so well within Bluetooth’s spec. Something that I’ve also noticed is that when I run the function NSInputStream, [NSInputStream read: maxLength:], the number of bytes returned is always 158 or less. The app and hardware don’t crash, but the Bluetooth just unpairs.

The device is still sending data to the RN42 even after the disconnect, which reduces the likelihood of a problem on the electronics side. This setup also works perfectly fine on Android devices. I can stream data without any disconnects or crashes.

Things I’ve tried...

  • followed the External Accessory example, EADemo, provided by Apple.
  • purely using the run-loop instead of polling.
  • putting the stream on a background thread as suggested in this post.
  • removing all NSLogs to help with performance.
  • compiled in debug and release modes.

One thing which sort of works is slowing down the data transfer (i.e. less than 5kB/s), as that allows the iOS and BT module to stay connected and transfer data longer before disconnecting.

#define EAD_INPUT_BUFFER_SIZE 1024

/**
 * Stream delegate
 */
- (void)stream:(NSStream *)aStream handleEvent:(NSStreamEvent)eventCode
{
    switch (eventCode) {
[... other cases ...]

        case NSStreamEventHasBytesAvailable:
        {            
            uint8_t buf[EAD_INPUT_BUFFER_SIZE];
            unsigned int len = 0;
            len = [(NSInputStream *)aStream read:buf maxLength:EAD_INPUT_BUFFER_SIZE];

            if(len) {
                // Read successful, process data
            } else {
                // Fail
            }     
            break;
        }
        default:
            break;
    }
}

/**
 * Stream delegate with polling (for better or worse)
 */
    [...]
        case NSStreamEventHasBytesAvailable:
        {            
            while ([[_session inputStream] hasBytesAvailable])
            {
                // Read the data
                NSInteger bytesRead = [[_session inputStream] read:_buf maxLength:EAD_INPUT_BUFFER_SIZE];

                if (bytesRead > 0) {
                    // Read successful, process data

                } else if (bytesRead == 0) {
                    // End of buffer reached
                    return;

                } else if (bytesRead == -1) {
                    // Failed to read
                    return;
                }
            }
            break;
    [...]
Was it helpful?

Solution

I've spoken with guys at Microchip (the company that bought Roving Networks, who were the original makers of the RN42) about this type of problem, and it seems that there is an unfortunate little "feature" that is not documented anywhere in the RN42 manuals.

When the RN42 is used to communicate with an iOS device, it cannot communicate faster than 2.5-3kB/s... If it's used to communicate with an Android or computer or anything else, it can transfer at 35kB/s (over SPP).

The reason for this is an under-powered chip in the RN42, which can't handle both the BT stack AND re-packaging bytes in the format an iOS device needs (iAP protocol).

They recommend the following options:

  1. Switch to using a WiFi module.
  2. Implement the iAP protocol on your microcontroller and use a vanilla RN42 to transfer data (which should theoretically be back at 35kB/s).
  3. Buffer data on your device, and send it back at the slower rate.
  4. Use a vanilla RN42, and one of their PIC devices which implements the iAP stack.

I have a polite 5th suggestion... Find a new Apple-supported Bluetooth module.

Additionally, using 4-wire UART communication should help with the crashes.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top