Я пытаюсь использовать Android в качестве периферийного устройства BLE (сервер gatt). Мне удалось получить его рекламу, и я могу получать приложения iOS для получения уведомлений при изменении определенных характеристик, но у меня возникают проблемы при выполнении простого writeValue.
На iOS у меня есть:
- (void)peripheral:(CBPeripheral *)peripheral didDiscoverCharacteristicsForService:(CBService *)service error:(NSError *)error {
if (!error) {
for(int i = 0; i < service.characteristics.count; i++) { //Show every one
CBCharacteristic *c = [service.characteristics objectAtIndex:i];
if ([[c.UUID UUIDString] rangeOfString:@"43FF0001"].location!=NSNotFound){
self.shot_detected_characteristic = c;
[peripheral setNotifyValue:YES forCharacteristic:self.shot_detected_characteristic];
}else if ([[c.UUID UUIDString] rangeOfString:@"43FF0002"].location!=NSNotFound){
self.display_characteristic = c;
[self writeValue:@"ABC" forCharacteristic:c onPeripheral:peripheral];
}
NSLog(@"characteristic uuid: %@", [c.UUID UUIDString]);
}
} else {
NSLog(@"Characteristic discovery unsuccessful");
}
}
-(IBAction*) sendData {
CBPeripheral *p = [peripherals lastObject];
[self writeValue:@"ABC" forCharacteristic:self.display_characteristic onPeripheral:p];
}
-(void) writeValue:(NSString*)value forCharacteristic:(CBCharacteristic*)c onPeripheral:(CBPeripheral *)p {
NSData *d = [value dataUsingEncoding:NSUTF8StringEncoding];
if (c.properties & CBCharacteristicPropertyWrite) {
NSLog(@"Write with response"); //I am getting this message
[p writeValue:d forCharacteristic:c type:CBCharacteristicWriteWithResponse];
}else{
NSLog(@"Unable to write");
}
}
А на стороне Android у меня есть:
private BluetoothManager bluetoothManager;
private BluetoothGattServer gattServer;
private BluetoothGattCharacteristic displayCharacteristic;
private BluetoothDevice connected_device;
private BluetoothLeAdvertiser advertiser;
private void setupBLEService() {
bluetoothManager = (android.bluetooth.BluetoothManager) this.getSystemService(Context.BLUETOOTH_SERVICE);
if( ContextCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
ActivityCompat.requestPermissions(this, new String[]{android.Manifest.permission.ACCESS_COARSE_LOCATION}, 1);
}
gattServer = bluetoothManager.openGattServer(this, gattServerCallback);
String uuid_string = "92D9D153-9BE6-43FF-9672-3E2904628B9D";
BluetoothGattService service = new BluetoothGattService(UUID.fromString(uuid_string), BluetoothGattService.SERVICE_TYPE_PRIMARY);
shotDetectedCharacteristic = new BluetoothGattCharacteristic(
UUID.fromString("43FF0001-9BE6-43FF-9672-3E2904628B9D"),
BluetoothGattCharacteristic.PROPERTY_BROADCAST | BluetoothGattCharacteristic.PROPERTY_NOTIFY | BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_WRITE,
BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_WRITE);
BluetoothGattDescriptor gD = new BluetoothGattDescriptor(UUID.fromString(NOTIFICATION_DESCRIPTOR), BluetoothGattDescriptor.PERMISSION_WRITE | BluetoothGattDescriptor.PERMISSION_READ);
shotDetectedCharacteristic.addDescriptor(gD);
service.addCharacteristic(shotDetectedCharacteristic);
displayCharacteristic = new BluetoothGattCharacteristic(
UUID.fromString("43FF0002-2BE5-46FE-9162-1D2905728B9B"),
BluetoothGattCharacteristic.PROPERTY_BROADCAST | BluetoothGattCharacteristic.PROPERTY_READ | BluetoothGattCharacteristic.PROPERTY_WRITE,
BluetoothGattCharacteristic.PERMISSION_READ | BluetoothGattCharacteristic.PERMISSION_WRITE);
service.addCharacteristic(displayCharacteristic);
gattServer.addService(service);
}
private BluetoothGattServerCallback gattServerCallback = new BluetoothGattServerCallback() {
@Override
public void onConnectionStateChange(BluetoothDevice device, int status, int newState) {
super.onConnectionStateChange(device, status, newState);
if (newState == 2){
connected_device = device;
advertiser.stopAdvertising(new AdvertiseCallback() {});
}
Log.i("chase", "Connection state changed: "+newState);
}
@Override
public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {
super.onCharacteristicReadRequest(device, requestId, offset, characteristic);
long millis = System.currentTimeMillis();
characteristic.setValue( ""+millis );
Log.i("chase", "reading: "+millis);
gattServer.sendResponse(device, requestId, 2, offset, characteristic.getValue());
}
@Override
public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {
Log.i("chase", "characteristic write request");
super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
characteristic.setValue(value);
gattServer.sendResponse(device, requestId, 2, offset, characteristic.getValue());
if (characteristic == displayCharacteristic){
//TODO: UPDATE DISPLAY
Log.i("chase", "display write request: "+value.toString());
}else
Log.i("chase", "char write request: "+value.toString());
}
...
}
Причина, по которой я думаю, что проблема на стороне iOS, заключается в том, что я скачал приложение nrf Connect и смог успешно записать в характеристику Android с помощью nrf connect. Или, по крайней мере, получить в журнале операторов в BluetoothGattServerCallback#onCharacteristicWriteRequest
.
Тем не менее, я также написал приложения, взаимодействующие с чипами BLE, и у меня никогда не было проблем с написанием NSData с [p writeValue:d forCharacteristic:c type:CBCharacteristicWriteWithResponse];
Заранее благодарен за любую помощь или идеи, как решить эту проблему.
Обновление:
Когда я говорю, что это не работает. Я не получаю никаких сообщений об ошибках вообще. [p writeValue:d forCharacteristic:c type:CBCharacteristicWriteWithResponse];
вызывается, и на стороне андроида нет вызова на BluetoothGattServerCallback#onCharacteristicWriteRequest
, а на стороне ios нет обратного вызова на -(void)peripheral:(CBPeripheral *)peripheral didWriteValueForCharacteristic:(CBCharacteristic *)characteristic error:(NSError *)error;
.
Однако я получил кое-что интересное. Если я закомментирую строку ios:
//[peripheral setNotifyValue:YES forCharacteristic:self.shot_detected_characteristic];
Затем я делаю получаю звонок на onCharacteristicWriteRequest
андроида и получаю обратный вызов на didWriteValueForCharacteristic
(я получаю сообщение об ошибке, что оно не может быть написано, но я думаю, что справлюсь с этим По крайней мере, я что-то получаю).
Я подписываюсь на уведомления по другой характеристике, но по той же службе и по какой-то причине, которая мешает мне записывать данные по этой другой характеристике.