Core Bluetooth замедляется при отправке пакетов

У меня возникла проблема, когда время между записью значения в характеристику с помощью

[peripheral writeValue:dataPacket forCharacteristic:writeChar type:CBCharacteristicWithResponse]

а устройство iOS, фактически физически отправляющее пакет Bluetooth, постепенно увеличивается дольше.

Это можно проиллюстрировать на следующем выходе отладчика:

2013-10-23 14:12:17.510 Test App iOS[1561:60b] Packet sent
2013-10-23 14:12:17.595 Test App iOS[1561:60b] Packet sent confirmation, error = (null)
2013-10-23 14:12:17.598 Test App iOS[1561:60b] Packet response received

2013-10-23 14:12:17.611 Test App iOS[1561:60b] Packet sent
2013-10-23 14:12:17.656 Test App iOS[1561:60b] Packet sent confirmation, error = (null)
2013-10-23 14:12:17.657 Test App iOS[1561:60b] Packet response received

2013-10-23 14:12:22.601 Test App iOS[1561:60b] Packet sent
2013-10-23 14:12:23.123 Test App iOS[1561:60b] Packet sent confirmation, error = (null)
2013-10-23 14:12:23.125 Test App iOS[1561:60b] Packet response received

2013-10-23 14:12:27.601 Test App iOS[1561:60b] Packet sent
2013-10-23 14:12:28.111 Test App iOS[1561:60b] Packet sent confirmation, error = (null)
2013-10-23 14:12:28.113 Test App iOS[1561:60b] Packet response received

2013-10-23 14:12:32.611 Test App iOS[1561:60b] Packet sent
2013-10-23 14:12:34.595 Test App iOS[1561:60b] Packet sent confirmation, error = (null)
2013-10-23 14:12:34.597 Test App iOS[1561:60b] Packet response received


2013-10-23 14:12:37.611 Test App iOS[1561:60b] Packet sent
2013-10-23 14:12:39.582 Test App iOS[1561:60b] Packet sent confirmation, error = (null)
2013-10-23 14:12:39.585 Test App iOS[1561:60b] Packet response received

2013-10-23 14:12:42.611 Test App iOS[1561:60b] Packet sent
2013-10-23 14:12:44.570 Test App iOS[1561:60b] Packet sent confirmation, error = (null)
2013-10-23 14:12:44.573 Test App iOS[1561:60b] Packet response received

2013-10-23 14:12:47.611 Test App iOS[1561:60b] Packet sent
2013-10-23 14:12:49.558 Test App iOS[1561:60b] Packet sent confirmation, error = (null)
2013-10-23 14:12:49.560 Test App iOS[1561:60b] Packet response received

// Several packets omitted...

2013-10-23 14:13:07.610 Test App iOS[1561:60b] Packet sent
2013-10-23 14:13:09.508 Test App iOS[1561:60b] Packet sent confirmation, error = (null)
2013-10-23 14:13:09.511 Test App iOS[1561:60b] Packet response received

2013-10-23 14:13:12.610 Test App iOS[1561:60b] Packet sent
2013-10-23 14:13:14.496 Test App iOS[1561:60b] Packet sent confirmation, error = (null)
2013-10-23 14:13:14.498 Test App iOS[1561:60b] Packet response received

//И так далее...

Сообщение отправленного пакета выводится в строке сразу после команды writeValue для записи пакета данных в характеристику.

Подтверждение отправки пакета выводится в первой строке в методе делегата didWriteValueForCharacteristic.

Полученное сообщение с ответом на пакет выводится в файле didUpdateValueForCharacteristic, который вызывается, когда устройство BTLE отправляет ответный пакет (через вторичный атрибут уведомления) для подтверждения получения моего отправленного пакета.

Как видно изначально, время между моим вызовом метода writeValue forCharacteristic и обратным вызовом для подтверждения пакета было отправлено в didWriteValueForCharacteristic, изначально 85 мс (который уже медленный, но переносимый). Я посылаю эти пакеты примерно каждые 5 секунд, и после того, как небольшое количество отправленных пакетов увеличивается, это увеличивается до ~ 2 секунд, после чего кажется, что оно постоянно статично в 2 секунды. Ответный пакет, отправленный обратно с устройства BTLE, всегда равен ~ 2 мс после подтверждения отправленного пакета.

Я не понимаю, почему я получаю эту задержку в библиотеках CoreBluetooth между вызовом writeValue и обратным вызовом подтверждения didWriteValueForCharacteristic.

Во всех других отношениях код работает отлично (устройство BTLE делает именно то, что ему поручено делать, и ни один из пакетов не пропадает).

У меня есть пример приложения, которое предоставляется изготовителем модуля BT4.0 (включая источник), который не испытывает этой растущей задержки. К сожалению, приложение-образец предназначено для решения большого числа вариантов реализации модуля, а не только наша конкретная реализация и поэтому массово сложна, содержащая много кода, который просто не имеет отношения к нашей реализации. Я поставил точки останова в каждой функции в образце и вручную перешел, чтобы точно определить, какие команды они выдают, и я считаю, что копирую их отлично (но, очевидно, нет).

Я не вижу ничего, что они делают, чего я не делаю, и наоборот. Единственное различие, которое я могу обнаружить между этими двумя проектами, заключается в том, что моя использует ARC, а их использует ручной подсчет ссылок.

Дополнительная информация: Все работает на основном потоке (как и в примере с образцом для образцов модулей) Я создаю Центральный диспетчер, используя основную очередь (аналогично в примере приложения для производителей модулей) Загрузка процессора на устройстве iOS составляет всего 3%, пока мое приложение работает, и ничто не задерживается из-за загрузки ЦП и т.д.

Я срываю волосы с этим, и если кто-нибудь может предложить любые возможные причины или решения этой проблемы, я буду вечно благодарен!

Спасибо, Рич

Ответ 1

Я сделал некоторый прогресс в этом, и новости не очень хорошие. Оказывается, мое первоначальное описание проблемы неверно. Я предположил (всегда плохо), что пример приложения, созданного поставщиком модуля, будет правильным, однако данные о времени, которые он сообщает, ошибочны - когда они сообщают о 3 мс, чтобы отправить пакет и получить ответ, это только время из -didWriteValueForCharacteristic и не включают время между вызовом writeValueForCharacteristic и didWriteValueForCharacteristic - как только я включил это время, их приложение ведет себя так же медленно, как и мое.

После дальнейшего исследования выяснилось, что библиотеки iOS CoreBluetooth вызывают задержку между запросом на отправку пакета и отправкой на самом деле - эти произвольные задержки могут быть в пределах от 80 мс до 2секунд. Кто-нибудь знает, почему библиотеки iOS настолько медленны при отправке фактического пакета? Наш эквивалентный код, работающий под Android, более или менее мгновенен.

Если бы у меня была моя циничная шляпа, я бы сказал, что Apple намеренно делает это, чтобы предотвратить приложения, требующие быстрого ответа от разработки с использованием BTLE, и тем самым заставить разработчиков оборудования использовать Bluetooth 3, который требует чипа безопасности Apple и тем самым эффективно стоимость лицензирования яблока на изготовленные единицы...

Ответ 2

Прежде всего, проверьте, что вы получаете:

-(void) peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic
 error:(NSError *)error {

}

если код ошибки равен 0, это означает, что вы отправляете значение в периферийное устройство БЕЗ подтверждения. Проверьте, реализует ли ваш перигерон этот метод:

//assuming 
@property (strong, nonatomic) CBPeripheralManager       *peripheralManager;

- (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests
{
    NSLog(@"WRITE REQUEST!!! %lu",(unsigned long)requests.count);
    //check if there are data

   for (CBATTRequest * req in requests) {
   //send reposnse to Central that you recivied write value and eg / accept / reject the write request
    [self.peripheralManager respondToRequest:req
                                          withResult:CBATTErrorSuccess];
   }


}