首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >Android通知数据包丢失

Android通知数据包丢失
EN

Stack Overflow用户
提问于 2015-08-03 03:08:16
回答 1查看 6.1K关注 0票数 10

我正在开发一个硬件设备,它通过BLE向Android应用程序发送连续数据流。android应用程序将这些数据作为GATT通知接收,然后处理这些数据并将其保存到数据库中。

该项目的配置细节如下:

  1. 手机- Moto E第一代
  2. Android版本-Android5.1-Lollipop
  3. iOS - iPhone 4和5,在iOS 7和8上测试
  4. 硬件- CC2541
  5. Connection_Interval : 40 ms (在硬件固件中设置)。
  6. 每个连接间隔发送的数据包:4(在硬件的固件中设置)。

问题

当数据从硬件设备发送到运行在Android手机上的BLE数据捕获应用程序时,所有的数据包都不会被接收。它只接收大约35-45个数据包,而预期的数据包数量是50个.

更令人惊讶的是,当我们使用BLE数据包嗅探器时,Android手机监听和显示的数据(这是不完整/不正确的数据)之间有一个完美的匹配。这让我相信,当连接到Android手机而不是发送所有数据时,硬件的表现是不同的。

当我们在iOS BLE数据捕获应用程序中使用相同的硬件时,数据将被正确地接收。

对于Android中BLE数据捕获的这种行为,我感到困惑和无知。iOS设备上的应用程序如何能够正确捕获所有数据,而安卓手机上的应用程序却根本无法正确捕获数据?

在Android上使用BLE应用程序时,是否有人遇到过数据包丢失/数据错误的问题?任何输入都是受欢迎的。非常感谢您的提前帮助。

android应用程序使用标准的BLE代码通过BLE连接到设备。下面显示了我使用的Android代码:

代码语言:javascript
复制
import android.annotation.TargetApi;
import android.app.Activity;
import android.bluetooth.BluetoothAdapter;
import android.bluetooth.BluetoothDevice;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCallback;
import android.bluetooth.BluetoothGattCharacteristic;
import android.bluetooth.BluetoothGattDescriptor;
import android.bluetooth.BluetoothGattService;
import android.bluetooth.BluetoothManager;
import android.bluetooth.BluetoothProfile;
import android.bluetooth.le.BluetoothLeScanner;
import android.bluetooth.le.ScanCallback;
import android.bluetooth.le.ScanFilter;
import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.nfc.Tag;
import android.os.Build;
import android.os.Bundle;
import android.os.Handler;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.widget.Toast;

import java.util.ArrayList;
import java.util.List;

@TargetApi(21)
public class BLETestActivity extends Activity {
    private BluetoothAdapter mBluetoothAdapter;
    private int REQUEST_ENABLE_BT = 1;
    private Handler mHandler;
    private static final long SCAN_PERIOD = 10000;
    private BluetoothLeScanner mLEScanner;
    private ScanSettings settings;
    private List<ScanFilter> filters;
    private BluetoothGatt mGatt;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_bletest);
        mHandler = new Handler();
        if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_BLUETOOTH_LE)) {
            Toast.makeText(this, "BLE Not Supported",
                    Toast.LENGTH_SHORT).show();
            finish();
        }
        final BluetoothManager bluetoothManager =
                (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = bluetoothManager.getAdapter();

    }

    @Override
    protected void onResume() {
        super.onResume();
        if (mBluetoothAdapter == null || !mBluetoothAdapter.isEnabled()) {
            Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
            startActivityForResult(enableBtIntent, REQUEST_ENABLE_BT);
        } else {
            if (Build.VERSION.SDK_INT >= 21) {
                Log.i("innnnn","spinnnn - " + Build.VERSION.SDK_INT);
                mLEScanner = mBluetoothAdapter.getBluetoothLeScanner();
                settings = new ScanSettings.Builder()
                        .setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY)
                        .build();
                filters = new ArrayList<ScanFilter>();
            }
            scanLeDevice(true);
        }
    }

    @Override
    protected void onPause() {
        super.onPause();
        if (mBluetoothAdapter != null && mBluetoothAdapter.isEnabled()) {
            scanLeDevice(false);
        }
    }

    @Override
    protected void onDestroy() {
        if (mGatt == null) {
            return;
        }
        mGatt.close();
        mGatt = null;
        super.onDestroy();
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        if (requestCode == REQUEST_ENABLE_BT) {
            if (resultCode == Activity.RESULT_CANCELED) {
                //Bluetooth not enabled.
                finish();
                return;
            }
        }
        super.onActivityResult(requestCode, resultCode, data);
    }

    private void scanLeDevice(final boolean enable) {
        if (enable) {
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    if (Build.VERSION.SDK_INT < 21) {
                        mBluetoothAdapter.stopLeScan(mLeScanCallback);
                    } else {
                        mLEScanner.stopScan(mScanCallback);

                    }
                }
            }, SCAN_PERIOD);
            if (Build.VERSION.SDK_INT < 21) {
                mBluetoothAdapter.startLeScan(mLeScanCallback);
            } else {
                mLEScanner.startScan(filters, settings, mScanCallback);
            }
        } else {
            if (Build.VERSION.SDK_INT < 21) {
                mBluetoothAdapter.stopLeScan(mLeScanCallback);
            } else {
                mLEScanner.stopScan(mScanCallback);
            }
        }
    }


    private ScanCallback mScanCallback = null;/* new ScanCallback() {
        @Override
        public void onScanResult(int callbackType, ScanResult result) {
            Log.i("callbackType", String.valueOf(callbackType));
            Log.i("result", result.toString());
            BluetoothDevice btDevice = result.getDevice();
            connectToDevice(btDevice);
        }

        @Override
        public void onBatchScanResults(List<ScanResult> results) {
            for (ScanResult sr : results) {
                Log.i("ScanResult - Results", sr.toString());
            }
        }

        @Override
        public void onScanFailed(int errorCode) {
            Log.e("Scan Failed", "Error Code: " + errorCode);
        }
    };*/

    private BluetoothAdapter.LeScanCallback mLeScanCallback =
            new BluetoothAdapter.LeScanCallback() {
                @Override
                public void onLeScan(final BluetoothDevice device, int rssi,
                                     byte[] scanRecord) {
                    runOnUiThread(new Runnable() {
                        @Override
                        public void run() {
                            Log.i("onLeScan", device.toString());
                            connectToDevice(device);
                        }
                    });
                }
            };

    public void connectToDevice(BluetoothDevice device) {
        if (mGatt == null) {
            mGatt = device.connectGatt(this, false, gattCallback);
            scanLeDevice(false);// will stop after first device detection
        }
    }

    private final BluetoothGattCallback gattCallback = new BluetoothGattCallback() {
        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {
            Log.i("onConnectionStateChange", "Status: " + status);
            switch (newState) {
                case BluetoothProfile.STATE_CONNECTED:
                    Log.i("gattCallback", "STATE_CONNECTED");
                    gatt.discoverServices();
                    break;
                case BluetoothProfile.STATE_DISCONNECTED:
                    Log.e("gattCallback", "STATE_DISCONNECTED");
                    break;
                default:
                    Log.e("gattCallback", "STATE_OTHER");
            }

        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            List<BluetoothGattService> services = gatt.getServices();
           // Log.i("onServicesDiscovered", services.toString());

            for(int i=0;i<services.size();i++) {
                List<BluetoothGattCharacteristic> charList = services.get(i).getCharacteristics();
                for (int j = 0; j < charList.size();j++) {
                    BluetoothGattCharacteristic characteristic = charList.get(j);
                    if (characteristic.getUuid().compareTo(Constants.HEART_DATA_UUID) == 0) {
                        Log.i(BLETestActivity.class.getSimpleName(), "Characteristic UUID is " + characteristic.getUuid());
                        mGatt.setCharacteristicNotification(characteristic, true);
                        BluetoothGattDescriptor descriptor = characteristic.getDescriptor(Constants.HEART_DATA_DESCRIPTOR_UUID);
                        descriptor.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                        mGatt.writeDescriptor(descriptor);
                    }
                }
            }
        }

        public void onCharacteristicChanged(BluetoothGatt gatt,
                                            BluetoothGattCharacteristic characteristic) {
            // Retrieve the byte values
            // Convert them to hex values
            byte[] data = characteristic.getValue();

            // The following array contains data in the follwing form:
            // 0-1 - running counter counts
            // 2-4, 5-7, 8-10  - Sample 1 data for channel 1, channel2 and channel 3
            // 11-13, 14-16, 17-19 - Sample 2 data for channel 1, channel 2 and channel 3

//            Log.i(TAG," ------ " + Thread.currentThread().getId());
            String heartBeatDataInHex = bytesToHex(data);


            // An error packet is received after every 17 samples.
            // Checking to make sure that this is not an error packet

            if (!(heartBeatDataInHex.substring(4, 10).equalsIgnoreCase("FFFFFF") && heartBeatDataInHex.substring(26, 40).equalsIgnoreCase("FFFFFFFFFFFFFF"))) {
                Log.i("testdata", heartBeatDataInHex + " ---- " + Thread.currentThread().getId());
            }
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt,
                                         BluetoothGattCharacteristic
                                                 characteristic, int status) {
            Log.i("onCharacteristicRead", characteristic.toString());
            gatt.disconnect();
        }

    };

    private String bytesToHex(byte[] bytes) {
        final char[] hexArray = "0123456789ABCDEF".toCharArray();
        char[] hexChars = new char[bytes.length * 2];
        for ( int j = 0; j < bytes.length; j++ ) {
            int v = bytes[j] & 0xFF;
            hexChars[j * 2] = hexArray[v >>> 4];
            hexChars[j * 2 + 1] = hexArray[v & 0x0F];
        }
        return new String(hexChars);
    }
}
EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-08-03 14:46:18

我也有过类似的问题!我做了一些测试,并确定与android级别18 (GalaxyAndroid4.3上BLE的连接间隔)的最小连接间隔为48 is。

可点式解决方案:

  1. 使连接间隔变慢(小于48 Make )。
  2. 从api 21级到上层,您可以更改CONNECTION_PRIORITY android开发者来修改间隔连接,但这意味着更多的能源消耗。
票数 4
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/31778872

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档