Android Development-Bluetooth

Posted by docmattman on Thu, 11 Jul 2019 20:40:19 +0200

- Restore content to start

Preface

Lonely fragrant self-admiration, a package of fanghua;
Humanity is cold and warm, free in the heart;
Climbing high and looking far ahead;
Laugh and lie.
The last article introduced the basic use of Bluetooth, writing demo is not very perfect, I hope you gods can correct. In the past two weeks, due to the progress of the company's development and some personal reasons, I did not write this article in time to introduce the demo I wrote. This is a kind of irresponsibility to oneself. Over the past two weeks, boss asked me to refactor the code according to OCP principles, and changed it again and again. Later, boss gave me a demo reference and helped me refactor the code. For the three characteristics of object-oriented, six principles and twenty-three design patterns, I won't be ugly here until I finish reading the book.

text

1. Open Bluetooth and Scan Bluetooth Devices

private void initBluetoothAdapter() {
        if (null == mBluetoothManager) {
            mBluetoothManager = (BluetoothManager) getSystemService(BLUETOOTH_SERVICE);// Access to System Services
            if (null != mBluetoothManager) {
                mBluetoothAdapter = mBluetoothManager.getAdapter();//Get Bluetooth Adapter
            }
        }

        if (null == mBluetoothAdapter) {
            mBluetoothAdapter = BluetoothAdapter.getDefaultAdapter();//In case Manager is null, get Bluetooth adapter again
            if (null == mBluetoothAdapter) {
                Toast.makeText(this, R.string.noBluetooth, Toast.LENGTH_SHORT).show();
                return;
            }
        }
        //Check whether the mobile phone has Bluetooth on, if not, prompt the user to open Bluetooth.
        if (!mBluetoothAdapter.isEnabled()) {
            if (!mBluetoothAdapter.isEnabled()) {
                Intent enableBtIntent = new Intent(BluetoothAdapter.ACTION_REQUEST_ENABLE);
                startActivity(enableBtIntent);
            }
        }
    }

When Bluetooth is opened, it scans the Bluetooth device and finds Bluetooth.

if (null != mBluetoothAdapter)
   mBluetoothAdapter.startDiscovery();//Scanning Bluetooth

At this point, you need to register Receiver to receive information about Bluetooth discovery.

private void register() {
  IntentFilter intentFilter = new IntentFilter();
  intentFilter.addAction(BluetoothDevice.ACTION_FOUND);//action scanned to Bluetooth device registration
  intentFilter.addAction(BluetoothConstant.ACTION_DATA_AVAILABLE);//Monitor when Bluetooth starts and returns data
  intentFilter.addAction(BluetoothConstant.ACTION_DATA_COMPLETE);//When Bluetooth data is returned, the final data is returned
  registerReceiver(mBroadcastReceiver, intentFilter);
}
  • Processing the scanned Bluetooth, saving the name of Bluetooth and linking to Service, connecting Bluetooth in Service, writing some commands to Bluetooth, and processing Bluetooth callbacks into Service, reducing the cost of Activity page.

II. Linking Bluetooth Devices

Bluetooth Gatt is a very important class in Bluetooth. It is used to write Write command and Read command to Bluetooth. Its initialization is inseparable for Bluetooth links.
One of the methods encapsulated in Service is to link Bluetooth and initialize Bluetooth Gatt in this method.

/**
     * Link Bluetooth
     *
     * @param address Bluetooth address
     * @return Is the link successful?
     */
    public boolean connect(BluetoothAdapter bluetoothAdapter,String address) {
        this.mBluetoothAdapter = bluetoothAdapter;
        if (null == address || null == mBluetoothAdapter) {
            Log.e(TAG, "connect Bluetooth address or BluetoothAdapter is null that not initial");
            return false;
        }

        if (mDeviceAddress != null && address.equals(mDeviceAddress)
                && mBluetoothGatt != null) {
                //Linked Devices Link Again
            Log.i(TAG, "connect existing device");
            return mBluetoothGatt.connect();
        }
        BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
        if (null != device) {
            mBluetoothGatt = device.connectGatt(this, false, mGattCallback);//First link to Bluetooth and initialize Bluetooth Gatt
            mDeviceAddress = address;
            this.mDeviceName = device.getName();
        }else {
            Log.i(TAG,"device is null");
        }
        return true;
    }
  • In the link bluetooth, there is another pit. This pit does not appear every time, nor every day, but occasionally several times, that is, the linked bluetooth. When you disconnect the link again, it will not link, sometimes it will show that all Bluetooth devices can not be scanned. I do not have a good solution. The temporary solution is to close bluetooth. Bluetooth scan and link again.

III. Registration Channel

Some methods and callback processing of Bluetooth callback have been roughly described in the previous article, but they are not described in detail here.
When Bluetooth links succeed, you need to scan Bluetooth service channels.

mBluetoothGatt.discoverServices();

After scanning the Bluetooth service, traverse all channels in the service and select the channels you need to register.

/**
     * Get the eigenvalue (feature UUID) to be the only channel to communicate with Bluetooth
     *
     * @param gattServices BluetoothGattService
     */
    private void displayGattServices(List<BluetoothGattService> gattServices) {
        if (gattServices == null)
            return;
        String uuid;
        /**
         *Here, names, uuids, receiveUUIDs must correspond one by one (example below), if there is no need to use the device name to fill in gas, if the "program" may make a mistake, channel registration fails.
         */
        String[] names = BluetoothConstant.getInstance().getDeviceNames();
        String[] uuids = BluetoothConstant.getInstance().getNotificationUUIDs();
        String[] receiveUUIDs = BluetoothConstant.getInstance().getReceiveNotificationUUIDs();
       //From all services, find the effective service UUID that can communicate with Bluetooth
        for (BluetoothGattService gattService : gattServices) {
            List<BluetoothGattCharacteristic> gattCharacteristics = gattService.getCharacteristics();
            //Find your desired eigenvalue from the service Bluetooth GattCharacteristic
                for (BluetoothGattCharacteristic characteristic : gattCharacteristics) {
                    uuid = characteristic.getUuid().toString();
                    String device = mBluetoothGatt.getDevice().getName();
                    for (int i = 0; i < names.length; i++) {
                        if (uuid.contains(uuids[i]) && device.equals(names[i])) {
                        //Here is the eigenvalue needed.
                            Log.i(TAG,">>>><<<<< \n name ="+names[i]+"\n"+"uuid = "+uuid+"\n"+"receiveUUID = "+receiveUUIDs[i]);
                           if (!uuid.contains(receiveUUIDs[i])) {
                                this.mCharacteristic = characteristic;//Why add an if here, because some Bluetooth data return and write command is a channel; some data return is a channel, write command is another channel; when write command with return data channel, command is not written in. Therefore, when Bluetooth is not the channel to return data, the eigenvalues are globally integrated.
                            }
                            notification(characteristic);
                        }
                    }
                }
            }
    }
//Here's why. When we first registered the channel, we only wrote mBluetooth Gatt. setCharacteristicNotification (true). However, not every time we registered successfully, we found several methods on the Internet. Only this method is more useful, so that the channel will not register incorrectly. It's wrong.
    private void notification(BluetoothGattCharacteristic gattCharacteristic) {
        boolean success = mBluetoothGatt.setCharacteristicNotification(gattCharacteristic, true);

        Log.i(TAG,"notification characteristic permissions = "+gattCharacteristic.getPermissions()+"\n"
                +"characteristic properties = "+ gattCharacteristic.getProperties()+"\n"+
                "characteristic uuid = "+gattCharacteristic.getUuid());
        if (success) {
            for (BluetoothGattDescriptor dp : gattCharacteristic.getDescriptors()) {
                if (dp != null) {
                    if ((gattCharacteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_NOTIFY) != 0) {
                        dp.setValue(BluetoothGattDescriptor.ENABLE_NOTIFICATION_VALUE);
                    }
                    mBluetoothGatt.writeDescriptor(dp);
                    try {
                        Thread.sleep(200);//Why do we sleep 200 ms here? Because registration is too fast, not all channels can register successfully. It would be better to add a delay.
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }

Here are some basic Bluetooth settings, written in the Bluetooth Constant class, this class is mainly unified to write some Bluetooth-related things, such as name, registration channel, access to data, commands and so on.

//Name of device
    private final String[] deviceNames = new String[]{
            DEVICE_NAME_ONE,
            DEVICE_NAME_TWO,
            DEVICE_NAME_TWO,
            DEVICE_NAME_THREE
    };
    //Need to register Bluetooth Characteristic channel (read, write, notify)
    private final String[] notificationUUIDs = new String[]{
            "0001",
            "0002",
            "0003",
            "0004"
    };
    //Only receive data channels, do not read and write, not UUID is occupied, occupied can also be other characters channeling, as long as it is not "."
    private final String[] receiveNotificationUUIDs = new String[]{
            "DEVICE_NAME_ONE",
            "DEVICE_NAME_TWO",
            "0000fff4-0000-1000-8000-00805f9b34fb",
            "DEVICE_NAME_THREE"
    };

I am deeply sorry that it took so long to write this article. In Bluetooth development, the most hateful thing is that the Bluetooth provider gives the protocol, but there is no specific command, which requires us to spell the command ourselves. However, at the end of the command, there are parity checks, odd or odd checks, CRC8 checks, CRC16 checks. Here I provide benefits to you. Check and CRC8 Check Record:

/**
     * XOR Check Bit Computation
     * Get rid of the starting position and start with the second.
     */
    private void getXOR(int[] hexs){
        int xor = 0;
        for (int i = 0;i<hexs.length;i++){
            xor = xor^hexs[i];
            Log.i(TAG,"XOR ="+xor);
        }
        Log.i(TAG,"Hex XOR = "+xor);
    }

// CRC8 Check
private static byte[] crc8_tab = { (byte) 0, (byte) 94, (byte) 188, (byte) 226, (byte) 97, (byte) 63, (byte) 221, (byte) 131, (byte) 194, (byte) 156, (byte) 126, (byte) 32, (byte) 163, (byte) 253, (byte) 31, (byte) 65, (byte) 157, (byte) 195, (byte) 33, (byte) 127, (byte) 252, (byte) 162, (byte) 64, (byte) 30, (byte) 95, (byte) 1, (byte) 227, (byte) 189, (byte) 62, (byte) 96, (byte) 130, (byte) 220, (byte) 35, (byte) 125, (byte) 159, (byte) 193, (byte) 66, (byte) 28, (byte) 254, (byte) 160, (byte) 225, (byte) 191, (byte) 93, (byte) 3, (byte) 128, (byte) 222, (byte) 60, (byte) 98, (byte) 190, (byte) 224, (byte) 2, (byte) 92, (byte) 223, (byte) 129, (byte) 99, (byte) 61, (byte) 124, (byte) 34, (byte) 192, (byte) 158, (byte) 29, (byte) 67, (byte) 161, (byte) 255, (byte) 70, (byte) 24,
            (byte) 250, (byte) 164, (byte) 39, (byte) 121, (byte) 155, (byte) 197, (byte) 132, (byte) 218, (byte) 56, (byte) 102, (byte) 229, (byte) 187, (byte) 89, (byte) 7, (byte) 219, (byte) 133, (byte) 103, (byte) 57, (byte) 186, (byte) 228, (byte) 6, (byte) 88, (byte) 25, (byte) 71, (byte) 165, (byte) 251, (byte) 120, (byte) 38, (byte) 196, (byte) 154, (byte) 101, (byte) 59, (byte) 217, (byte) 135, (byte) 4, (byte) 90, (byte) 184, (byte) 230, (byte) 167, (byte) 249, (byte) 27, (byte) 69, (byte) 198, (byte) 152, (byte) 122, (byte) 36, (byte) 248, (byte) 166, (byte) 68, (byte) 26, (byte) 153, (byte) 199, (byte) 37, (byte) 123, (byte) 58, (byte) 100, (byte) 134, (byte) 216, (byte) 91, (byte) 5, (byte) 231, (byte) 185, (byte) 140, (byte) 210, (byte) 48, (byte) 110, (byte) 237,
            (byte) 179, (byte) 81, (byte) 15, (byte) 78, (byte) 16, (byte) 242, (byte) 172, (byte) 47, (byte) 113, (byte) 147, (byte) 205, (byte) 17, (byte) 79, (byte) 173, (byte) 243, (byte) 112, (byte) 46, (byte) 204, (byte) 146, (byte) 211, (byte) 141, (byte) 111, (byte) 49, (byte) 178, (byte) 236, (byte) 14, (byte) 80, (byte) 175, (byte) 241, (byte) 19, (byte) 77, (byte) 206, (byte) 144, (byte) 114, (byte) 44, (byte) 109, (byte) 51, (byte) 209, (byte) 143, (byte) 12, (byte) 82, (byte) 176, (byte) 238, (byte) 50, (byte) 108, (byte) 142, (byte) 208, (byte) 83, (byte) 13, (byte) 239, (byte) 177, (byte) 240, (byte) 174, (byte) 76, (byte) 18, (byte) 145, (byte) 207, (byte) 45, (byte) 115, (byte) 202, (byte) 148, (byte) 118, (byte) 40, (byte) 171, (byte) 245, (byte) 23, (byte) 73, (byte) 8,
            (byte) 86, (byte) 180, (byte) 234, (byte) 105, (byte) 55, (byte) 213, (byte) 139, (byte) 87, (byte) 9, (byte) 235, (byte) 181, (byte) 54, (byte) 104, (byte) 138, (byte) 212, (byte) 149, (byte) 203, (byte) 41, (byte) 119, (byte) 244, (byte) 170, (byte) 72, (byte) 22, (byte) 233, (byte) 183, (byte) 85, (byte) 11, (byte) 136, (byte) 214, (byte) 52, (byte) 106, (byte) 43, (byte) 117, (byte) 151, (byte) 201, (byte) 74, (byte) 20, (byte) 246, (byte) 168, (byte) 116, (byte) 42, (byte) 200, (byte) 150, (byte) 21, (byte) 75, (byte) 169, (byte) 247, (byte) 182, (byte) 232, (byte) 10, (byte) 84, (byte) 215, (byte) 137, (byte) 107, 53 };

    /**
     * Calculate the CRC8 check value of the array
     *
     * @param data
     *            Array to be computed
     * @return CRC8 Check Value
     */
    public static byte calcCrc8(byte[] data) {
        return calcCrc8(data, 0, data.length, (byte) 0);
    }

    /**
     * Calculating CRC8 Check Value
     *
     * @param data
     *            data
     * @param offset
     *            Starting position
     * @param len
     *            length
     * @param preval
     *            Previous check values
     * @return Check Value
     */
    public static byte calcCrc8(byte[] data, int offset, int len, byte preval) {
        byte ret = preval;
        for (int i = offset; i < (offset + len); ++i) {
            ret = crc8_tab[(0x00ff & (ret ^ data[i]))];
        }
        return ret;
    }

Some knowledge about Bluetooth development is basically introduced. If you have any questions, you can add QQ group: 177694195. We will discuss Bluetooth development together.

- Restore the end of the content.

Topics: Android Mobile