将数据写入 Android 中的蓝牙 LE 特性 [英] Writing data to Bluetooth LE characteristic in Android

查看:14
本文介绍了将数据写入 Android 中的蓝牙 LE 特性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

Although similar questions have been asked but it's slightly different. I know how to pass data to a connected BLE device but I think I'm doing something wrong for which I need help. The code below contains all the methods from my class that is extending BroadcastReceiver.

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

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

I debugged my code while trying writing to this characteristic but on putting breakpoints inside the writeCharac method, I found that the status value is false, indicating that the write was not successful. Am I missing something here? Please do help!

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);
        }

    };

推荐答案

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

Although the BLE API is asynchronous in nature, the actual signal transmission is inevitably synchronous. You have to wait for the previous connect/write/read call to callback before starting any connecting/writing/reading operation.

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

In your code onServicesDiscovered(BluetoothGatt gatt, int status) function, you called mGatt.writeDescriptor(descriptor) twice before trying to write the characteristic. The API will refuse to start your write request as it is being busy writing the descriptor, and return false for your mGatt.writeCharacteristic(charac) call.

所以在调用 writeCharacteristic 之前只需等待 writeDescriptor 回调.这种性质没有得到很好的记录,但您可以找到一些来源 此处此处.

So just wait for the writeDescriptor to callback before calling writeCharacteristic. This nature is not well documented but you can find some source here and here.

这篇关于将数据写入 Android 中的蓝牙 LE 特性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆