2017-02-18 2 views
0

Ich entwickle eine Android-App, die Daten von einem BLE-Sensor mit einer Rate von etwa 8000 Bytes pro Sekunde empfängt.Android - BLE-Verbindungsparameter und Speichern von BLE-Sensordaten in der SQLite-Datenbank

Die Verbindungslogik in meiner App basiert auf dem BluetoothLegatt-Beispiel von Google. Es klappt. Ich habe nichts geändert und setze keine Verbindungsparameter wie Intervall zwischen Verbindungsereignissen explizit (ich glaube nicht, dass die Android 4.4 APIs das unterstützen).

Ich teste auf zwei Android-Handys, beide mit Android-Version 4.4.2 und verwende den TI BLE-Sniffer, um BLE-Verkehr zu überwachen.

Ein Telefon verhandelt ein Intervall von 7,5 ms und tauscht drei 20-Byte-Pakete pro Verbindungsereignis aus. Das andere Telefon verhandelt 48,75 ms zwischen Verbindungsereignissen und tauscht neunzehn 20-Byte-Pakete pro Ereignis aus (die effektive Datenübertragungsrate pro Sekunde ist ungefähr die gleiche).

Mein Problem ist, dass ich versuche, die Daten aus der BLE-Service-Aktivität zu protokollieren, wie es in einer SQLite-Datenbank kommt. Die Protokollierung funktioniert für das Telefon mit dem Intervall von 7,5 ms. Jedoch, stürzt die App für das Telefon mit dem 48.75ms-Intervall ab. (Im Allgemeinen ist die Verbindung dieses Telefons viel weniger stabil). Ich nehme an, das liegt daran, dass die Verarbeitung von 19 Paketen direkt übereinander erfolgt.

Meine Fragen:
1. Gibt es auf jeden Fall kann ich beide Telefone (und alle zukünftigen Geräte) das 7,5ms-Intervall verwenden, da das scheint besser zu funktionieren? Gibt es eine Möglichkeit, die Minimum/Maximum_CE_Length Parameter zu steuern?

  1. Gibt es eine bessere Möglichkeit, die Daten als direkt von der BLE-Dienstaktivität zu protokollieren? These SQLite Android Developer pages schlägt vor, eine ASync-Aufgabe zu verwenden, die jedoch nicht geeignet erscheint, da die Daten nicht zum UI-Thread gesendet werden.

Mein Code-Schnipsel: Dies ist mein Verbindungscode directly from the BluetoothLeGatt sample

/** 
* Connects to the GATT server hosted on the Bluetooth LE device. 
* 
* @param address The device address of the destination device. 
* 
* @return Return true if the connection is initiated successfully. The connection result 
*   is reported asynchronously through the 
*   {@code BluetoothGattCallback#onConnectionStateChange(android.bluetooth.BluetoothGatt, int, int)} 
*   callback. 
*/ 
public boolean connect(final String address) { 
    if (mBluetoothAdapter == null || address == null) { 
     Log.w(TAG, "BluetoothAdapter not initialized or unspecified address."); 
     return false; 
    } 
    // Previously connected device. Try to reconnect. 
    if (mBluetoothDeviceAddress != null && address.equals(mBluetoothDeviceAddress) 
      && mBluetoothGatt != null) { 
     Log.d(TAG, "Trying to use an existing mBluetoothGatt for connection."); 
     if (mBluetoothGatt.connect()) { 
      mConnectionState = STATE_CONNECTING; 
      return true; 
     } else { 
      return false; 
     } 
    } 
    final BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address); 
    if (device == null) { 
     Log.w(TAG, "Device not found. Unable to connect."); 
     return false; 
    } 
    // We want to directly connect to the device, so we are setting the autoConnect 
    // parameter to false. 
    mBluetoothGatt = device.connectGatt(this, false, mGattCallback); 
    Log.d(TAG, "Trying to create a new connection."); 
    mBluetoothDeviceAddress = address; 
    mConnectionState = STATE_CONNECTING; 
    return true; 
}` 

ist mein Logging-Code in der broadcastUpdate Funktion:

private void broadcastUpdate(final String action, 
          final BluetoothGattCharacteristic characteristic) { 
    final Intent intent = new Intent(action); 
    StringBuilder stringBuilder = new StringBuilder(); 
    StringBuilder descStringBuilder = new StringBuilder(); 
    byte[] newData = characteristic.getValue(); 
    String dataString; 

    if (newData != null && newData.length > 0) { 
     if (UUID_SENSOR_FFF4.equals(characteristic.getUuid())) { 

      totalDataBytes += newData.length; 
      // https://stackoverflow.com/questions/8150155/java-gethours-getminutes-and-getseconds 
      estimatedTime = System.currentTimeMillis(); 
      Date timeDiff = new Date(estimatedTime - startTime - 19 * 3600000); 
      SimpleDateFormat timeFormat = new SimpleDateFormat("HH:mm:ss.SSS"); 
      descStringBuilder.append("CHAR_FFF4\n"); 
      descStringBuilder.append("Total Data: " + totalDataBytes + " Bytes\n"); 
      descStringBuilder.append("Elapsed Time: " + timeFormat.format(timeDiff) + "\n"); 

      for (int i = 0; i < newData.length; i++){ 
       byte[] tempArray = { newData[i+1], newData[i] }; 
       ByteBuffer wrapper = ByteBuffer.wrap(tempArray); 
       short tempShort = wrapper.getShort(); 
       i++; 
       stringBuilder.append(tempShort); 
       stringBuilder.append(", "); 
      } 
      dataString = stringBuilder.toString(); 

      values.put(NbmcContract.NmbcDeviceData.COLUMN_TIMESTAMP, estimatedTime); 
      values.put(NbmcContract.NmbcDeviceData.COLUMN_DATA_STRING, dataString); 

      long newRowId = db.insert(NbmcContract.NmbcDeviceData.TABLE_NAME, null, values); 
      descStringBuilder.append("Row ID: " + newRowId + "\n"); 


     } else { 
      descStringBuilder.append(getCharacteristicString(characteristic) + "\nDATA: "); 

      // We expect these characteristics to return ASCII strings 
      if ( DEVICE_NAME_CHAR.equals(characteristic.getUuid()) || 
        MODEL_NUM_CHAR.equals(characteristic.getUuid()) || 
        SERIAL_NUM_CHAR.equals(characteristic.getUuid()) || 
        FIRMWARE_REV_CHAR.equals(characteristic.getUuid()) || 
        HARDWARE_REV_CHAR.equals(characteristic.getUuid()) || 
        FIRMWARE_REV_CHAR.equals(characteristic.getUuid()) || 
        SOFTWARE_REV_CHAR.equals(characteristic.getUuid()) || 
        MANUF_NAME_STRING_CHAR.equals(characteristic.getUuid())) 
      { 
       for (byte byteChar : newData) { 
        stringBuilder.append(String.format("%c", byteChar)); 
       } 
      } 
      else { 
       for (byte byteChar : newData) { 
        stringBuilder.append(String.format("%02X", byteChar)); 
       } 
      } 
      dataString = stringBuilder.toString(); 
     } 
     String descString = descStringBuilder.toString(); 
     intent.putExtra("DESC_STRING", descString); 

     UUID uuid = characteristic.getUuid(); 
     String uuidString = uuid.toString(); 
     intent.putExtra("CHAR_UUID", uuidString); 
     intent.putExtra("EXTRA_DATA", dataString); 
    } 
    sendBroadcast(intent); 
} 
+0

Dies ist ein [FAQ] (http://www.sqlite.org/faq.html#q19); Schreiben Sie mehrere Einträge in einer einzigen Transaktion. –

Antwort

0

1) auf API lvl21 + Sie können bluetoothGatt.requestConnectionPriority(int connectionPriority)
versuchen Aber das ist alles, was Sie tun können.

2) Der BTLE-Stack auf Android ist nicht der beste, ich würde vorschlagen, die Daten ohne irgendeine Verarbeitung zu nehmen und die Verarbeitung zu machen, nachdem alle Daten empfangen worden sind. Bitte beachten Sie, dass die gatt Callbacks auf einem zufälligen Thread geschehen, der NICHT Ihr ui-Thread ist. Zwei Anrufe können von zwei verschiedenen Threads stammen, und wenn man in eine Datenbank schreibt und die andere kommt und beginnt zu schreiben, bekommt man ein Durcheinander.

Mein Vorschlag:

Auf jedem Empfangsereignis Sie kopieren die byte[] Array (wie Android die gegebene Array für zukünftige Wiederverwendung von Daten kann) und an den Haupt-Thread mit einem Handler senden. Auf dem Hauptthread sammeln Sie die Arrays in einer Liste oder Sammlung und sobald ein bestimmter Betrag gesammelt wurde, starten Sie einen neuen Thread, geben Sie ihm die Liste und lassen Sie die Daten in eine Datenbank eingeben, während der Hauptthread eine neue Liste für neue erstellt Daten.

+0

Danke NikkyD. Ich stimme dir mit dem Android BTLE-Stack zu. Ich mag den Handler-Vorschlag und werde ihn verwenden, wenn ich das nächste Mal so viele Daten habe (wir haben die Geräteschnittstelle geändert, um weniger Daten als Arbeit zu senden). Ich würde +1 geben, wenn ich könnte. – Excelsior1024

Verwandte Themen