Home > front end >  iOS Bluetooth Performing Write Long
iOS Bluetooth Performing Write Long

Time:08-19

I'm working on a project with an iPhone connecting to an ESP32 using BLE. I'm trying to write a 528 byte long blob to a characteristic. Since the blob is longer than the max 512 allowed per write I'm trying to do a Write Long.

I'ved tried a couple things

1 - If I just try to write the blob I see the first chunk go through with Prepare Write set but there are no subsequent writes.

Why is it stopping after the first chunk?

2 - If I try to chuck it manually based on the size returned from maximumWriteValueLengthForType I see all the data is sent correctly but Prepare Write is not set so they aren't handled correctly.

How do I specify Prepare Write / Execute Write requests?

Here's a code snippet covering the implementation #2

      NSData *blob = [request value];
      NSUInteger localLength = 0;
      NSUInteger totalLength = [blob length];
      NSUInteger chunkSize = [peripheral maximumWriteValueLengthForType:type];
      uint8_t localBytes[chunkSize];
      NSData *localData;

      do
      {
        if(totalLength > chunkSize) {
            NSLog(@"BIGGER THAN CHUNK!!!!!!!!!!!!!!!!!!!!!");
            NSLog(@"%tu", chunkSize);
            for ( int i = 0; i < chunkSize; i  ) {
                localBytes[i] = ((uint8_t *)blob.bytes)[localLength   i];
            }
            localData = [NSMutableData dataWithBytes:localBytes length:chunkSize];
            totalLength -= chunkSize;
            localLength  = chunkSize;
        }
        else {
            NSLog(@"Smaller than chunk");
            uint8_t lastBytes[totalLength];
            for (int i = 0 ; i < totalLength; i  ) {
                lastBytes[i] = ((uint8_t *)blob.bytes)[localLength   i];
            }
            localData = [NSMutableData dataWithBytes:lastBytes length:totalLength];
            totalLength = 0;
        }
        // Write to characteristic
        [peripheral writeValue: localData forCharacteristic:characteristic type:type];
      } while( totalLength > 0);

CodePudding user response:

Long writes are affected by the same limit of 512 bytes maximum for the characteristic value. Long writes are only useful when MTU is too short to write the full value in one packet. Maybe you're trying to write out of this allowed range or something.

Newer iOS versions communicating with BLE 5 devices use a large enough MTU to fit a characteristic value of 512 in one packet (if the remote device also supports such a big MTU).

If you want to write bigger values than 512 bytes, you will need to split it up into multiple writes, so that the second write "overwrites" the first value sent, rather than appending to it. You can also use L2CAP CoC instead which eliminates this arbitrary 512 byte limit.

CodePudding user response:

You have the right general approach but you can't just send the chunks sequentially. There is a limited buffer for sending Bluetooth data and your loop will write data into that buffer more quickly than the Bluetooth hardware can send it.

The exact approach you need to take depends on whether your characteristic supports write with response or write without response.

If your characteristic uses write with response, you should send a chunk and then wait until you get a call to the didWriteValueFor delegate method. You can then write the next chunk. The advantage of this approach is essentially guaranteed delivery of the data. The disadvantage is it is relatively slow.

If your characteristic uses write without response then you call write repeatedly until you get a call to didWriteValueFor with an error. At this point you have to wait until you get a call to peripheralIsReady. At this point you can start writing again, beginning with the last failed write.

With this approach there is the potential for lost data, but it is faster.

If you have to move large amounts of data, an L2Cap stream might be better, but you need to handle data framing.

  • Related