2017-02-18 48 views
0

我正在開發一個Android應用程序,它以每秒8000字節的速度從BLE傳感器接收數據。Android - BLE連接參數和在SQLite數據庫中存儲BLE傳感器數據

我的應用中的連接邏輯基於Google的BluetoothLeGatt示例。有用。我沒有改變任何東西,也沒有明確設置任何連接參數,如連接事件之間的間隔(我不認爲Android 4.4 API支持)。

我正在測試兩款Android手機,均使用Android版本4.4.2,並使用TI BLE嗅探器來監控BLE流量。

一個電話協商一個7.5ms的間隔,並且每個連接事件交換三個20字節的數據包。另一部電話在連接事件之間協商48.75ms,並且每個事件交換19個20字節的數據包(每秒的有效數據傳輸速率大致相同)。

我的問題是,我試圖從BLE服務活動中記錄數據,因爲它涉及到SQLite數據庫。日誌記錄以7.5ms爲間隔工作。但是,該應用會以48.75ms的間隔鎖定手機。 (一般來說,該手機的連接性不太穩定)。我認爲這是因爲它正在處理19個數據包在彼此之上。

我的問題:
1.是否有無論如何,我可以使兩個手機(和任何未來的設備)使用7.5毫秒的間隔,因爲這似乎更好?有沒有辦法控制參數Minimum/Maximum_CE_Length

  1. 有沒有比直接從BLE服務活動記錄數據更好的方法? These SQLite Android Developer pages建議使用ASync任務,但由於數據不會進入UI線程,因此看起來並不合適。

我的代碼片段: 這是我的連接代碼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; 
}` 

我的日誌代碼是在broadcastUpdate功能:

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

這是[FAQ](http://www.sqlite.org/faq.html#q19);在一次交易中寫入多個條目。 –

回答

0

1)API lvl21 +,你可以嘗試bluetoothGatt.requestConnectionPriority(int connectionPriority)
但這就是你所能做的。

2) Android上的BTLE堆棧並不是最好的,我建議在沒有任何處理的情況下采集數據,並在收到所有數據後進行處理。 請注意 gatt回調發生在隨機線程上,而不是你的ui線程。兩個調用可能來自兩個不同的線程,如果一個寫入數據庫而另一個寫入並且開始寫入,那麼你會得到一個混亂。

我的建議:

在你複製byte[]陣列(如Android的可重用未來的數據給定的數組),並將其與Handler發送到主線程每接收事件。在主線程中,您收集列表或集合中的數組,並且一旦收集到一定數量的數據後,您將開始一個新線程,將其列入列表並讓它將數據輸入數據庫,同時主線程爲新建立一個新列表數據。

+0

感謝NikkyD。我同意你關於Android BTLE堆棧。我喜歡Handler的建議,並在下次有這麼多的數據時使用它(我們改變了設備接口以減少數據傳輸)。如果可以,我會+1。 – Excelsior1024