CoreBlueTooth: getting an error even when data is being written to the recorded characteristics

I use the CoreBlueTooth environment to record into one of the recorded properties of Peripheral. I implement the delegate didWriteValueForCharacteristic: error: "delegate in central, which always returns me below the error. Although I received data about my periphery.

Error Domain=CBErrorDomain Code=0 "Unknown error." UserInfo=0x166762e0 {NSLocalizedDescription=Unknown error.} 

In my code, my self.data is an NSDictionary with 3 keys and values.

 // Central - (void)centralManagerDidUpdateState:(CBCentralManager *)iCentral { if (iCentral.state != CBCentralManagerStatePoweredOn) { return; } [self.centralManager scanForPeripheralsWithServices:self.peripheralServices options:@{ CBCentralManagerScanOptionAllowDuplicatesKey : @YES}]; } - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)iPeripheral advertisementData:(NSDictionary *)iAdvertisementData RSSI:(NSNumber *)iRSSI { if (self.discoveredPeripheral != iPeripheral) { // Save a local copy of the peripheral, so CoreBluetooth doesn't get rid of it self.discoveredPeripheral = iPeripheral; // Connect to the discovered peripheral [self.centralManager connectPeripheral:iPeripheral options:nil]; } } - (void)centralManager:(CBCentralManager *)central didDiscoverPeripheral:(CBPeripheral *)iPeripheral advertisementData:(NSDictionary *)iAdvertisementData RSSI:(NSNumber *)iRSSI { if (self.discoveredPeripheral != iPeripheral) { // Save a local copy of the peripheral, so CoreBluetooth doesn't get rid of it self.discoveredPeripheral = iPeripheral; // Connect to the discovered peripheral [self.centralManager connectPeripheral:iPeripheral options:nil]; } } // We've connected to the peripheral, now we need to discover the services and characteristics to find the 'writeable' characteristic. - (void)centralManager:(CBCentralManager *)iCentral didConnectPeripheral:(CBPeripheral *)iPeripheral { // Stop scanning [self.centralManager stopScan]; // Make sure we get the discovery callbacks iPeripheral.delegate = self; // Search only for services that match our UUID [iPeripheral discoverServices:self.peripheralServices]; } - (void)peripheral:(CBPeripheral *)iPeripheral didDiscoverServices:(NSError *)iError { if (iError) { [self cleanup]; return; } // Loop through the newly filled peripheral.services array, just in case there more than one. for (CBService *service in iPeripheral.services) { [iPeripheral discoverCharacteristics:@[self.writeableCharactersticsUUID] forService:service]; } } // Write the data into peripheral characterstics - (void)peripheral:(CBPeripheral *)iPeripheral didDiscoverCharacteristicsForService:(CBService *)iService error:(NSError *)iError { if (iError) { [self cleanup]; return; } // Find out the writable characterstics for (CBCharacteristic *characteristic in iService.characteristics) { if ([characteristic.UUID isEqual:self.writeableCharactersticsUUID]) { NSData *dataToWrite = [NSJSONSerialization dataWithJSONObject:self.data options:0 error:nil]; NSInteger dataSize = [[NSByteCountFormatter stringFromByteCount:dataToWrite.length countStyle:NSByteCountFormatterCountStyleFile] integerValue]; if (dataSize > 130) { NSLog(@"Cannot send more than 130 bytes"); return; } [self.discoveredPeripheral writeValue:dataToWrite forCharacteristic:self.centralWriteableCharacteristic type:CBCharacteristicWriteWithResponse]; break; } } } - (void)peripheral:(CBPeripheral *)iPeripheral didWriteValueForCharacteristic:(CBCharacteristic *)iCharacteristic error:(NSError *)iError { NSLog(@"Error = %@", iError); } - (void)cleanup { // Don't do anything if we're not connected if (self.discoveredPeripheral.state != CBPeripheralStateConnected) { return; } // If we've got this far, we're connected, but we're not subscribed, so we just disconnect [self.centralManager cancelPeripheralConnection:self.discoveredPeripheral]; } // Peripheral - (void)peripheralManagerDidUpdateState:(CBPeripheralManager *)iPeripheral { if (iPeripheral.state != CBPeripheralManagerStatePoweredOn) { return; } CBMutableCharacteristic *characteristic = [[CBMutableCharacteristic alloc] initWithType:iCID properties:CBCharacteristicPropertyWrite value:nil permissions:CBAttributePermissionsWriteable]; CBMutableService *writableService = [[CBMutableService alloc] initWithType:iServiceId primary:YES]; writableService.characteristics = @[characteristic]; //[self.peripheralManager removeAllServices]; [self.peripheralManager addService:writableService]; [self.peripheralManager startAdvertising:@{ CBAdvertisementDataServiceUUIDsKey : @[iServiceId]}]; } - (void)peripheralManager:(CBPeripheralManager *)iPeripheral didReceiveWriteRequests:(NSArray *)iRequests { CBATTRequest *aRequest = iRequests[0]; NSData *aData = aRequest.value; NSDictionary *aResponse = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:aData options:NSJSONReadingMutableContainers error:nil]; NSLog(@"Received Data = %@", aResponse); } 
+6
source share
3 answers

I get it. The problem was the type of characteristics. Instead of "CBCharacteristicWriteWithResponse" I used "CBCharacteristicWriteWithoutResponse" and it worked.

I did this after reading this:

writeValue forCharacteristic writeType, this function is the main function for writing to a characteristic on the device. The writeType property is either configured to write without a response, or with a response to a write. When a response record is used, all records in peripheral devices are cached while the iOS device is waiting for an ok response and callback. When writing an answer is not used, the data will not be cached. This is important when using things that require low latency, such as an RC car or helicopter, etc. When using a response record, the iOS device may sometimes lag, which does not give a big response ... For each record, the didWriteCharacteristic callback is called.

+9
source

Recording this for posterity: you MUST respond to prevent the error:

 - (void)peripheralManager:(CBPeripheralManager *)peripheral didReceiveWriteRequests:(NSArray *)requests { // respond! [peripheral respondToRequest:[requests objectAtIndex:0] withResult:CBATTErrorSuccess]; 
+4
source

Leaving this here for other people, but the OP answer is wrong.

The error that was made here is that he did not update his attribute in this function:

 - (void)peripheralManager:(CBPeripheralManager *)iPeripheral didReceiveWriteRequests:(NSArray *)iRequests { CBATTRequest *aRequest = iRequests[0]; NSData *aData = aRequest.value; NSDictionary *aResponse = (NSDictionary *)[NSJSONSerialization JSONObjectWithData:aData options:NSJSONReadingMutableContainers error:nil]; NSLog(@"Received Data = %@", aResponse); } 

Since no sign is updated, the OS assumes that something went wrong and generates an error.

 CBMutableCharacteristic *characteristic = [[CBMutableCharacteristic alloc] initWithType:iCID properties:CBCharacteristicPropertyWrite value:nil permissions:CBAttributePermissionsWriteable]; 

This code is actually configured to have a characteristic written with the answer, an enumeration that does not define the answer:

 CBCharacteristicPropertyWriteWithoutResponse 

Hope this helps others who stumble upon this.

+2
source

Source: https://habr.com/ru/post/950213/


All Articles