2015-08-21 185 views
0

我目前正在從藍牙LE LE開始從android到android交換小值的項目。 我使用nexus9作爲android周邊設備,Moto G作爲中心。完美的中央掃描外圍設備和外圍設備的服務正在被添加,現在我需要在外設上寫入特徵,然後外設將確認它到中央,但外圍設備發送特定字節到中央而不是讀取中央特徵,即使這個中央工作正常外設。 這裏是我的Android中央安卓android安卓通過ble通信

private void startScanning() { 
     if ((btAdapter != null) && (!isScanning)) { 
      if (scanner == null) { 
       Log.d(TAG, "scanner was null"); 
       scanner = btAdapter.getBluetoothLeScanner(); 
      } 
      if (scanCallback == null) 
       setScanCallback(null); 

      scanner.startScan(createScanFilters(), createScanSettings(), scanCallback); 
      isScanning = true; 
      Log.d(TAG, "in startScanning"); 
      //Toast.makeText(context, context.getString(R.string.scan_started), Toast.LENGTH_SHORT).show(); 
     } 
    } 


public void setScanCallback(final ScanCallback callback) { 

    scanCallback = new ScanCallback() { 
     @Override 
     public void onScanResult(int callbackType, ScanResult scanResult) { 
      super.onScanResult(callbackType, scanResult); 
      Log.d(TAG, scanResult.getDevice().getName() + " "); 

      deviceNames.add(scanResult.getDevice().getName()); 
      deviceRSSIs.add(String.valueOf(scanResult.getRssi())); 
      adapter.notifyDataSetChanged(); 

      scanResult.getDevice().connectGatt(context, false, new BluetoothGattCallback() { 


       @Override 
       public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) { 
        super.onConnectionStateChange(gatt, status, newState); 


        Set<BluetoothGattCharacteristic> characteristicSet; 

        switch (newState) { 
         case BluetoothProfile.STATE_DISCONNECTING: 

          break; 

         case BluetoothProfile.STATE_DISCONNECTED: 
          Log.d(TAG, gatt.getDevice().getName() + " is disconnected"); 
          //gatt.close(); 

          break; 

         case BluetoothProfile.STATE_CONNECTED: 
          Log.d(TAG, gatt.getDevice().getName() + " is connected"); 
          gatt.discoverServices(); 

          break; 

        } 
       } 

       @Override 
       public void onServicesDiscovered(BluetoothGatt gatt, int status) { 
        if (status == BluetoothGatt.GATT_SUCCESS) { 
         Log.d(TAG, "Discovered services central"); 
         // TODO: Keep this here to examine characteristics 
         // eventually we should get rid of the discoverServices step 
         boolean foundService = false; 
         try { 
          List<BluetoothGattService> serviceList = gatt.getServices(); 
          for (BluetoothGattService service : serviceList) { 
           if (service.getUuid().equals(serviceUUID)) { 

            foundService = true; 
            HashSet<BluetoothGattCharacteristic> characteristicSet = new HashSet<>(); 
            characteristicSet.addAll(service.getCharacteristics()); 
            discoveredCharacteristics.put(gatt.getDevice().getAddress(), characteristicSet); 

            for (BluetoothGattCharacteristic characteristic : characteristicSet) { 
             if (characteristic.getUuid().equals(characteristicUUID)) { 
              characteristic.setValue(dataToSend.getBytes()); 
              boolean chr = gatt.writeCharacteristic(characteristic); 
              characteristic = gatt.getService(serviceUUID).getCharacteristic(characteristicUUID); 
              gatt.setCharacteristicNotification(characteristic, true); 
              BluetoothGattDescriptor descriptor = characteristic.getDescriptor(CLIENT_CHARACTERISTIC_CONFIG); 
              descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); 
              boolean desc = gatt.writeDescriptor(descriptor); 
              // setIndictaionSubscription(gatt, characteristic, true); 
             } 

            } 
           } 
          } 


         } catch (Exception e) { 
          Log.d(TAG, "Exception analyzing discovered services " + e.getLocalizedMessage()); 
          e.printStackTrace(); 
         } 
         if (!foundService) 
          Log.d(TAG, "Could not discover chat service!"); 
        } else 
         Log.d(TAG, "Discovered services appears unsuccessful with code " + status); 
        super.onServicesDiscovered(gatt, status); 
       } 

       @Override 
       public void onDescriptorWrite(BluetoothGatt gatt, BluetoothGattDescriptor descriptor, int status) { 
        Log.d(TAG, "onDescriptorWrite"); 
       } 


       @Override 
       public void onCharacteristicChanged(final BluetoothGatt gatt, final BluetoothGattCharacteristic characteristic) { 
        Log.d(TAG, "onCharacteristicChanged"); 
        if (!characteristic.getValue().toString().isEmpty()) { 
         MainActivity.this.runOnUiThread(new Runnable() { 

          public void run() { 
           Toast.makeText(getBaseContext(), new String(characteristic.getValue()), Toast.LENGTH_LONG).show(); 
           gatt.readRemoteRssi(); 

          } 
         }); 
        } 

        super.onCharacteristicChanged(gatt, characteristic); 
       } 
       @Override 
       public void onCharacteristicWrite(BluetoothGatt gatt, 
                BluetoothGattCharacteristic characteristic, int status) { 

        Log.d(TAG, "onCharacteristicWrite"); 
        Exception exception = null; 
        if (status != BluetoothGatt.GATT_SUCCESS) { 

         String msg = "Write was not successful with code " + status; 
         Log.d(TAG, msg); 
         exception = new UnknownServiceException(msg); 

        } 
       } 


       @Override 
       public void onReadRemoteRssi(BluetoothGatt gatt, int rssi, int status) { 
        Log.i("RSSIValue", gatt.getDevice().getName() + " " + String.valueOf(rssi) + " " + String.valueOf(status)); 
        super.onReadRemoteRssi(gatt, rssi, status); 
       } 

      }); 


     } 

    }; 

} 

代碼在這裏是我的外設代碼。

private AdvertiseCallback mAdvCallback = new AdvertiseCallback() { 
     @Override 
     public void onStartSuccess(AdvertiseSettings settingsInEffect) { 
      if (settingsInEffect != null) { 
       Log.d(TAG, "Advertise success TxPowerLv=" 
         + settingsInEffect.getTxPowerLevel() 
         + " mode=" + settingsInEffect.getMode()); 
      } else { 
       Log.d(TAG, "Advertise success"); 
      } 
     } 

     @Override 
     public void onStartFailure(int errorCode) { 
      Log.d(TAG, "Advertising failed with code " + errorCode); 
     } 
    }; 


    private AdvertiseData createAdvData() { 
     AdvertiseData.Builder dataBuilder = new AdvertiseData.Builder(); 
     dataBuilder.addServiceUuid(new ParcelUuid(serviceUUID)); 
     dataBuilder.setIncludeTxPowerLevel(false); 
     dataBuilder.setIncludeDeviceName(true); 
//  builder.setManufacturerData(0x1234578, manufacturerData); 
     return dataBuilder.build(); 
    } 

    private AdvertiseSettings createAdvSettings() { 
     AdvertiseSettings.Builder builder = new AdvertiseSettings.Builder(); 
     builder.setTxPowerLevel(AdvertiseSettings.ADVERTISE_TX_POWER_HIGH); 
     builder.setAdvertiseMode(AdvertiseSettings.ADVERTISE_MODE_BALANCED); 
     builder.setConnectable(false); 
     return builder.build(); 
    } 

    private void stopAdvertising() { 
     if (isAdvertising) { 
      gattServer.close(); 
      advertiser.stopAdvertising(mAdvCallback); 
      isAdvertising = false; 
     } 
    } 


    public void createMessage() { 

     // Chop Message! You can only advertise 20 bytes at a time through ble 
     byte[] message = ("my text need to send").getBytes(); 
     mDataToSend = new ArrayList<>(); 
     dataToSendIndex = 0; 

     for(int i=0;i<Math.ceil((float)message.length/(float)20);i++) { 

      byte[] slice = new byte[20]; 

      for(int ii=0;ii<slice.length && i*20 + ii < message.length;ii++) { 
       slice[ii] = message[i*20 + ii]; 
      } 

      mDataToSend.add(slice); 

     } 

     // Start sending the message 
     sendMessage(); 
    } 

    public void sendMessage() { 

     if(dataToSendIndex >= mDataToSend.size()) { // If we have incremented through the message, the message is sent 
      Log.d("auto", "PeripheralActivity > sendMessage() > Message Sent"); 
      // Done Sending! 
      return; 
     } 

     // Set the value of the characteristic to the next data to send 
     mCharacteristic.setValue(mDataToSend.get(dataToSendIndex)); 
     // Notify the subscriber you have changed the value 
     gattServer.notifyCharacteristicChanged(btClient, mCharacteristic, true); 

     // Increment index 
     dataToSendIndex ++; 
    } 

    BluetoothGattServerCallback gattCallback = new BluetoothGattServerCallback() { 
     @Override 
     public void onConnectionStateChange(BluetoothDevice device, int status, int newState) { 
      super.onConnectionStateChange(device, status, newState); 
     } 

//  @Override 
//  public void onServiceAdded(int status, BluetoothGattService service) { 
//   super.onServiceAdded(status, service); 
//  } 

     @Override 
     public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) { 
      super.onCharacteristicReadRequest(device, requestId, offset, characteristic); 
      Log.d(TAG, characteristic.toString()); 
     } 

     @Override 
     public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { 
      super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value); 
      btClient = device; 

      gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, value); 
      createMessage(); 

     } 

     @Override 
     public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) { 
      super.onDescriptorReadRequest(device, requestId, offset, descriptor); 
     } 

     @Override 
     public void onDescriptorWriteRequest(BluetoothDevice device, int requestId, BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) { 
      super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value); 

      btClient = device; 

      gattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, BluetoothGattDescriptor.ENABLE_INDICATION_VALUE); 
      createMessage(); 
     } 

//  @Override 
//  public void onExecuteWrite(BluetoothDevice device, int requestId, boolean execute) { 
//   super.onExecuteWrite(device, requestId, execute); 
//  } 

     @Override 
     public void onNotificationSent(BluetoothDevice device, int status) { 
      super.onNotificationSent(device, status); 
      sendMessage(); 
     } 

//  @Override 
//  public void onMtuChanged(BluetoothDevice device, int mtu) { 
//   super.onMtuChanged(device, mtu); 
//  } 
    }; 
    private void startGattServer() { 
     // Create GATT Service 
     service = new BluetoothGattService(serviceUUID , BluetoothGattService.SERVICE_TYPE_PRIMARY); 


     // Create Config Descriptor 
     BluetoothGattDescriptor dataDescriptor = new BluetoothGattDescriptor(CLIENT_CHARACTERISTIC_CONFIG, BluetoothGattDescriptor.PERMISSION_WRITE | BluetoothGattDescriptor.PERMISSION_READ); 


     // Add Descriptor 
     mCharacteristic.addDescriptor(dataDescriptor); 
         BluetoothGattDescriptor.PERMISSION_WRITE | BluetoothGattCharacteristic.PERMISSION_READ); 

     // Add Characteristic 
     service.addCharacteristic(mCharacteristic); 

     gattServer = manager.openGattServer(this, gattCallback); 
     gattServer.addService(service); 


    } 

PS:可能有一個基本的錯誤,我可能無法檢測它,任何幫助將是非常可觀的:)

回答

0

我知道這是一個很「老」的問題,但也許這答案可以幫助其他人:

當您與GATT服務器通信時,儘量不要堆疊查詢,但總是讀/寫一次並等待答案,否則服務器可能會忽略您發送給它的所有內容。

所以你的情況這將是

boolean chr = gatt.writeCharacteristic(characteristic); 

- >等待onCharacteristicWrite()

然後做

descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE); 
boolean desc = gatt.writeDescriptor(descriptor); 
gatt.setCharacteristicNotification(characteristic, true);` 

- >等待onDescriptorWrite()

這是一個有點繁瑣的事情,但它會發送更多的可靠性,發送多個隊列里斯。 希望有所幫助。