2017-02-18 16 views
0

Я разрабатываю приложение для Android, которое получает данные от датчика BLE со скоростью около 8000 байт в секунду.Android - параметр подключения BLE и сохранение данных датчика BLE в базе данных SQLite

Логика подключения в моем приложении основана на примере Bluetooth BluetoothLeGatt. Оно работает. Я ничего не изменил и не устанавливал явно никаких параметров соединения, таких как интервал между событиями подключения (я не думаю, что API-интерфейсы Android 4.4 поддерживают это).

Я тестирую на двух телефонах Android, используя Android 4.4.2, и использую сниффер TI BLE для отслеживания трафика BLE.

Один телефон согласовывает интервал 7,5 мс и обменивает три 20-байтовых пакета на событие соединения. Другой телефон согласовывает 48.75ms между событиями соединения и обмена девятнадцатью 20-байтовыми пакетами на событие (эффективная скорость передачи данных в секунду примерно такая же).

Моя проблема заключается в том, что я пытаюсь зарегистрировать данные из службы службы BLE, поскольку она входит в базу данных SQLite. Ведение журнала работает для телефона с интервалом 7,5 мс. Однако, приложение блокируется для телефона с интервалом 48,75 мс. (В общем, соединение телефона намного менее стабильно). Я предполагаю, что это потому, что он обрабатывает 19 пакетов прямо друг над другом.

Мои вопросы:
1. Есть ли способ, чтобы оба телефона (и любые будущие устройства) использовали интервал 7,5 мс, поскольку, похоже, он работает лучше? Есть ли способ контролировать параметры Minimum/Maximum_CE_Length?

  1. Есть ли лучший способ для регистрации данных, чем непосредственно из службы обслуживания BLE? These SQLite Android Developer pages предлагают использовать задачу ASync, но это не кажется нужным, так как данные не идут в поток пользовательского интерфейса.

Мои фрагменты кода: Это мой код подключения 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) Стек BTLE на Android не самый лучший, я бы предложил взять данные без какой-либо обработки и выполнить обработку после того, как все данные были получены. Обратите внимание:, что обратные вызовы gatt происходят на случайном потоке, который НЕ является вашей ui-нитью. Два вызова могут происходить из двух разных потоков, и если один записывает в базу данных, а другой приходит и начинает писать, вы также получаете беспорядок.

Мое предложение:

На каждом принимающем случае вы копирования в byte[] массив (как Android может повторно использовать данный массив для будущих данных) и отправить его в основной поток с Handler. В основном потоке вы собираете массивы в списке или коллекции, и как только определенная сумма была собрана, вы запускаете новый поток, даете ему список и позволяете ему вводить данные в базу данных, в то время как основной поток создает новый список для новых данные.

+0

Спасибо NikkyD. Я согласен с вами в отношении стека Android BTLE. Мне нравится предложение Handler и будет использовать его в следующий раз, когда у меня будет много данных (мы изменили интерфейс устройства, чтобы отправлять меньше данных в качестве работы). Если бы я мог, я бы добавил +1. – Excelsior1024