简体   繁体   English

Android-BLE连接参数和将BLE传感器数据存储在SQLite数据库中

[英]Android - BLE connection parameter and Storing BLE sensor data in SQLite Database

I am developing an Android app that receives data from a BLE sensor at a rate of about 8000 bytes per second. 我正在开发一个Android应用,该应用以大约8000字节/秒的速率从BLE传感器接收数据。

The connection logic in my app is based upon Google's BluetoothLeGatt sample. 我的应用程序中的连接逻辑基于Google的BluetoothLeGatt示例。 It works. 有用。 I haven't changed anything and don't explicitly set any connection parameters like interval between connection events (I don't think the Android 4.4 APIs support that). 我没有做任何更改,也没有明确设置任何连接参数,例如连接事件之间的间隔(我不认为Android 4.4 API支持该功能)。

I am testing on two Android phones, both using Android version 4.4.2 and am using the TI BLE sniffer to monitor BLE traffic. 我正在使用Android 4.4.2版和TI BLE嗅探器监视BLE流量的两部Android手机上进行测试。

One phone negotiates a 7.5ms interval and exchanges three 20-byte packets per connection event. 一部电话协商一个7.5ms的间隔,每个连接事件交换三个20字节的数据包。 The other phone negotiates 48.75ms between connection events and exchanges nineteen 20-byte packets per event (the effective data transfer rate per second is about the same). 另一部电话在连接事件之间协商48.75毫秒,并且每个事件交换19个20字节的数据包(每秒的有效数据传输速率大致相同)。

My problem is that I am trying to log the data from the BLE Service activity as it comes in to a SQLite database. 我的问题是,我试图记录来自BLE服务活动的数据,这些数据进入SQLite数据库。 The logging works for the phone with the 7.5ms interval. 记录适用于手机,间隔为7.5ms。 However, the app locks up for the phone with the 48.75ms interval. 但是,应用程序以48.75ms的时间间隔锁定手机。 (In general, that phone's connection is a lot less stable). (通常,该电话的连接不稳定得多)。 I assume that's because it is getting processing for 19 packets right on top of each other. 我认为这是因为它正在相互处理19个数据包。

My questions: 我的问题:
1. Is there anyway I can make both phones (and any future devices) use the 7.5ms interval since that seems to work better? 1.无论如何,我可以让两部手机(以及以后的任何设备)都使用7.5毫秒的间隔,因为这似乎效果更好? Is there a way to control the Minimum/Maximum_CE_Length parameters? 有没有办法控制Minimum / Maximum_CE_Length参数?

  1. Is there a better way to log the data than directly from the BLE service activity? 有没有比直接从BLE服务活动中记录数据更好的方法? These SQLite Android Developer pages suggest using an ASync task but that doesn't seem appropriate since the data isn't going to the UI thread. 这些SQLite Android Developer页面建议使用ASync任务,但这似乎不合适,因为数据不会进入UI线程。

My code snippets: This is my connection code directly from the BluetoothLeGatt sample 我的代码段:这是我的连接代码, 直接来自BluetoothLeGatt示例

  /**
 * 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;
}`

My logging code is in the broadcastUpdate function: 我的日志记录代码在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);
}

1) on API lvl21+ you can try bluetoothGatt.requestConnectionPriority(int connectionPriority) 1)在API lvl21 +上,您可以尝试bluetoothGatt.requestConnectionPriority(int connectionPriority)
But that is all you can do. 但这就是您所能做的。

2) The BTLE stack on Android is not the best, i would suggest taking the data without any processing and do the processing after all the data has been received. 2)Android上的BTLE堆栈不是最好的,我建议不做任何处理就获取数据,并在收到所有数据后进行处理。 Please note that the gatt callbacks happen on a random thread that is NOT your ui-thread. 请注意 ,gatt回调发生在不是您的ui线程的随机线程上。 Two calls can originate from two different threads and if one writes into a database and the other comes along and starts to write as well you get a mess. 两次调用可能来自两个不同的线程,如果一个调用写入数据库,而另一个调用同时出现并开始写,则您会陷入混乱。

My suggestion: 我的建议:

On every receiving event you copy the byte[] array (as Android may reuse the given array for future data) and send it to the main thread with a Handler . 在每个接收事件中,您都复制 byte[]数组(因为Android可能会将给定的数组重用于将来的数据),并使用Handler将其发送到主线程。 On the main thread you collect the arrays in a List or Collection and once a certain amount has been collected you start a new thread, give it the list and let it enter the data into a database while the main thread creates a new list for new data. 在主线程上,将数组收集在“列表”或“集合”中,并在收集到一定数量后启动一个新线程,为其提供列表,然后将其输入数据库中,同时主线程为新列表创建一个新列表数据。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM