在Android中将数据写入蓝牙LE特性

abh*_*ICT 5 android bluetooth bluetooth-lowenergy

虽然已经提出了类似的问题,但它略有不同.我知道如何将数据传递给连接的BLE设备,但我认为我做错了什么我需要帮助.下面的代码包含我的类中扩展BroadcastReceiver的所有方法.

  1. 我扫描并连接到'PEN_ADDRESS`指定的设备.
  2. 在`onServicesDiscovered`方法中,我寻找一个'UUID`包含`abcd`的服务.
  3. 然后我循环遍历这些服务的特性,并在其"UUID"中查找具有特定字符串的三个特征.
  4. 第三个特性是一个可写特性,我试图通过调用方法`writeCharac(mGatt,writeChar1,123)来写数据;`上面传递的数据`123`只是一个伪数据.

我在尝试写入此特性时调试了我的代码,但是在writeCharac方法中放置了断点,我发现status值为false,表明写入不成功.我在这里错过了什么吗?请帮忙!

public class BackgroundReceiverFire extends BroadcastReceiver {
Context context;
private BluetoothAdapter mBluetoothAdapter;
private BluetoothGatt mGatt;
private BluetoothLeService mBluetoothLeService;
private boolean mScanning;
private final String TAG = "READING: ";
private BluetoothDevice mDevice;
private Handler mHandler;
private static final int REQUEST_ENABLE_BT = 1;
private final String PEN_ADDRESS = "FB:23:AF:42:5C:56";
// Stops scanning after 10 seconds.
private static final long SCAN_PERIOD = 10000;

    public void onReceive(Context context, Intent intent) {
        this.context = context;
        Toast.makeText(context, "Started Scanning", LENGTH_SHORT).show();
        initializeBluetooth();
        startScan();
    }

    private void initializeBluetooth() {
        mHandler = new Handler();

        // Use this check to determine whether BLE is supported on the device.  Then you can
        // selectively disable BLE-related features.
        // Initializes a Bluetooth adapter.  For API level 18 and above, get a reference to
        // BluetoothAdapter through BluetoothManager.
        final BluetoothManager bluetoothManager =
                (BluetoothManager) context.getSystemService(Context.BLUETOOTH_SERVICE);
        mBluetoothAdapter = bluetoothManager.getAdapter();

        // Checks if Bluetooth is supported on the device.
        if (mBluetoothAdapter == null) {
            Toast.makeText(this.context, "No Bluetooth", LENGTH_SHORT).show();
            return;
        }
    }

    private void startScan() {
        scanLeDevice(true);
    }

    private void stopScan() {
        scanLeDevice(false);
    }

    private void scanLeDevice(final boolean enable) {
        if (enable) {
            // Stops scanning after a pre-defined scan period.
            mHandler.postDelayed(new Runnable() {
                @Override
                public void run() {
                    mScanning = false;
                    mBluetoothAdapter.stopLeScan(mLeScanCallback);
                }
            }, SCAN_PERIOD);

            mScanning = true;
            //Scanning for the device
            mBluetoothAdapter.startLeScan(mLeScanCallback);
        } else {
            mScanning = false;
            mBluetoothAdapter.stopLeScan(mLeScanCallback);
        }
    }

    private BluetoothAdapter.LeScanCallback mLeScanCallback =
            new BluetoothAdapter.LeScanCallback() {
                @Override
                public void onLeScan(final BluetoothDevice device, int rssi, byte[] scanRecord) {
                    if (device.getAddress().matches(PEN_ADDRESS)) {
                        connectBluetooth(device);
                        Toast.makeText(context, "Device Found: " + device.getAddress(), Toast.LENGTH_LONG).show();

                    }
                }
            };

    private void connectBluetooth(BluetoothDevice insulinPen) {
        if (mGatt == null) {
            Log.d("connectToDevice", "connecting to device: " + insulinPen.toString());
            mDevice = insulinPen;
            mGatt = insulinPen.connectGatt(context, true, gattCallback);
            scanLeDevice(false);// will stop after first device detection
        }
    }

    private void enableBluetooth() {
        if (!mBluetoothAdapter.isEnabled()) {
            mBluetoothAdapter.enable();
        }
        scanLeDevice(true);
    }

    private void disableBluetooth() {
        if (mBluetoothAdapter.isEnabled()) {
            mBluetoothAdapter.disable();
        }
    }

    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:
                    gatt.discoverServices();
                    break;
                case BluetoothProfile.STATE_DISCONNECTED:
                    Log.e("gattCallback", "STATE_DISCONNECTED");
                    Log.i("gattCallback", "reconnecting...");
                    BluetoothDevice mDevice = gatt.getDevice();
                    mGatt = null;
                    connectBluetooth(mDevice);
                    break;
                default:
                    Log.e("gattCallback", "STATE_OTHER");
                    break;
            }

        }

        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            mGatt = gatt;
            List<BluetoothGattService> services = mGatt.getServices();
            Log.i("onServicesDiscovered", services.toString());
            Iterator<BluetoothGattService> serviceIterator = services.iterator();
            while(serviceIterator.hasNext()){
                BluetoothGattService bleService = serviceIterator.next();
                if(bleService.getUuid().toString().contains("abcd")){
                    //Toast.makeText(context,"Got the service",Toast.LENGTH_SHORT);
                    BluetoothGattCharacteristic readChar1 = bleService.getCharacteristics().get(0);
                    for (BluetoothGattDescriptor descriptor : readChar1.getDescriptors()) {
                        descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
                        mGatt.writeDescriptor(descriptor);
                        mGatt.setCharacteristicNotification(readChar1, true);
                    }
                    //mGatt.readCharacteristic(readChar1);

                    BluetoothGattCharacteristic readChar2 = bleService.getCharacteristics().get(1);
                    for (BluetoothGattDescriptor descriptor : readChar2.getDescriptors()) {
                        descriptor.setValue(BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
                        mGatt.writeDescriptor(descriptor);
                        mGatt.setCharacteristicNotification(readChar2, true);
                    }
                    //mGatt.readCharacteristic(readChar2);

                    BluetoothGattCharacteristic writeChar1 = bleService.getCharacteristics().get(2);
                    for (BluetoothGattDescriptor descriptor : writeChar1.getDescriptors()) {
                        descriptor.setValue( BluetoothGattDescriptor.ENABLE_INDICATION_VALUE);
                        mGatt.writeDescriptor(descriptor);
                        mGatt.setCharacteristicNotification(writeChar1, true);
                    }
                    writeCharac(mGatt,writeChar1,123);
                }
            }

            //gatt.readCharacteristic(therm_char);

        }
        public void writeCharac(BluetoothGatt gatt, BluetoothGattCharacteristic charac, int value ){
            if (mBluetoothAdapter == null || gatt == null) {
                Log.w(TAG, "BluetoothAdapter not initialized");
                return;
            }
/*
            BluetoothGattCharacteristic charac = gattService
                    .getCharacteristic(uuid);
*/
            if (charac == null) {
                Log.e(TAG, "char not found!");
            }

            int unixTime = value;
            String unixTimeString = Integer.toHexString(unixTime);
            byte[] byteArray = hexStringToByteArray(unixTimeString);
            charac.setValue(byteArray);
            boolean status = mGatt.writeCharacteristic(charac);
            if(status){
                Toast.makeText(context,"Written Successfully",Toast.LENGTH_SHORT).show();
            }else{
                Toast.makeText(context,"Error writing characteristic",Toast.LENGTH_SHORT).show();
            }
        }

        public byte[] hexStringToByteArray(String s) {
            int len = s.length();
            byte[] data = new byte[len/2];

            for(int i = 0; i < len; i+=2){
                data[i/2] = (byte) ((Character.digit(s.charAt(i), 16) << 4) + Character.digit(s.charAt(i+1), 16));
            }

            return data;
        }

        public void onCharacteristicRead(BluetoothGatt gatt,
                                         BluetoothGattCharacteristic
                                                 characteristic, int status) {
            Log.i("onCharacteristicRead", characteristic.toString());
            String characteristicValue = characteristic.getValue().toString();
            Log.d("CHARACTERISTIC VALUE: ", characteristicValue);
            gatt.disconnect();
        }

        public void onCharacteristicChanged(BluetoothGatt gatt,
                                            BluetoothGattCharacteristic
                                                    characteristic) {
            String value = characteristic.getValue().toString();
            Log.d(TAG,value);
        }

    };
Run Code Online (Sandbox Code Playgroud)

reT*_*eTs 5

尽管BLE API本质上是异步的,但实际的信号传输不可避免地是同步的.在开始任何连接/写入/读取操作之前,必须等待先前的连接/写入/读取调用回调.

在您的代码onServicesDiscovered(BluetoothGatt gatt, int status)函数中,您mGatt.writeDescriptor(descriptor)在尝试编写特征之前调用了两次.API将在忙于编写描述符时拒绝启动写入请求,并为您的mGatt.writeCharacteristic(charac)调用返回false .

所以只需等待writeDescriptor回调,然后再调用writeCharacteristic.这种性质没有很好的记录,但你可以在这里这里找到一些来源.