6

Sto usando il framework CoreBlueTooth per scrivere in una delle caratteristiche scrivibili di Peripheral. Sto implementando "didWriteValueForCharacteristic: error:" delegato in centrale che mi restituisce sempre sotto errore. Anche se ho ricevuto dati sulla mia periferica.CoreBlueTooth: ottenere errori anche se i dati sono scritti in caratteri scrivibili

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

Nel mio codice il mio self.data è un NSDictionary con 3 chiavi e valori.

// 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's more than one. 
    for (CBService *service in iPeripheral.services) { 
     [iPeripheral discoverCharacteristics:@[self.writeableCharactersticsUUID] forService:service]; 
    } 
} 


// Write the data into peripheral's 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); 
} 

risposta

9

L'ho capito. Il problema era con il tipo di caratteristiche. Invece di "CBCharacteristicWriteWithResponse" ho usato "CBCharacteristicWriteWithoutResponse" e ha funzionato.

ho fatto questo dopo aver letto questa:

writeValue forCharacteristic writeType, questa funzione è la funzione primaria per la scrittura di una caratteristica di un dispositivo. la proprietà writeType è impostata per scrivere senza risposta o scrivere con risposta. Quando si utilizza la scrittura con risposta, tutte le scritture sulla periferica vengono memorizzate nella cache mentre il dispositivo iOS è in attesa di ricevere la risposta ok e il callback. Quando si scrive non viene utilizzata alcuna risposta, i dati non verranno memorizzati nella cache. Questo è importante quando si usano cose che richiedono una bassa latenza, come un'automobile RC o un elicottero ecc. Quando si utilizza la scrittura con risposta, il dispositivo iOS può talvolta restare indietro, il che non produce una grande risposta ... Per ogni scrittura viene richiamato il callback DidWriteCharacteristic.

+0

Ho avuto questo stesso momento esatto numero e l'ora (con i requisiti firmware che cambiano). Ho bisogno di Google ogni volta :) – SJoshi

+0

Ho fatto lo stesso cambiamento, ma ancora non sto ricevendo alcuna chiamata su Peripheral End. Sto cercando qualsiasi aggiornamento nel metodo 'didReceiveWriteRequests' di PeripheralManager. ho ragione ? – Mrug

2

Lasciando questo qui per altre persone, ma la risposta dell'OP non è corretta.

L'errore che è stato fatto qui è che egli non ha aggiornato il suo caratteristico in questa funzione:

- (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); 
} 

Dal momento che nessuno caratteristica si trova ad essere aggiornato, il sistema operativo assume qualcosa è andato storto e genera un errore.

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

Questo codice è in realtà costituito per avere la caratteristica di scrivibile con una risposta, l'enum che specifica nessuna risposta è:

CBCharacteristicPropertyWriteWithoutResponse 

Spero che questo aiuta gli altri che inciampano su questo.

4

registrare questo per i posteri: si deve rispondere per impedire l'errore:

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

Non funziona. dati ancora disponibili Null –

+0

Funziona bene. Grazie! – flame3

Problemi correlati