Отправка данных (периферийные и центральные роли) - PullRequest
0 голосов
/ 08 апреля 2020

Я начинаю использовать BLE, и у меня много проблем:

1: я пытаюсь отправить данные с центрального на периферийное устройство, ничего не происходит

2: я могу ' мое устройство может получить более одного байта от периферийного устройства до центрального * sh

Ниже приведена часть приложения:

        public static final String EXTRAS_DEVICE_NAME = "DEVICE_NAME";
        public static final String EXTRAS_DEVICE_ADDRESS = "DEVICE_ADDRESS";
        private static final String LIST_NAME = "NAME";
        private static final String LIST_UUID = "UUID";


        private CentralService mBluetoothLeService;
        private ArrayList<ArrayList<BluetoothGattCharacteristic>> mDeviceServices;
        private BluetoothGattCharacteristic mCharacteristic;

        private String mDeviceName;
        private String mDeviceAddress;

        private TextView mConnectionStatus;
        private TextView mConnectedDeviceName;
        private TextView mTestConnected;
        private ImageView mServerCharacteristic;
        private Button mRequestReadCharacteristic;


        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_device_connect);

            mDeviceServices = new ArrayList<>();
            mCharacteristic = null;

            Intent intent = getIntent();
            if (intent != null) {
                mDeviceName = intent.getStringExtra(EXTRAS_DEVICE_NAME);
                mDeviceAddress = intent.getStringExtra(EXTRAS_DEVICE_ADDRESS);
            }


            mConnectionStatus = (TextView) findViewById(R.id.connection_status);
            mConnectedDeviceName = (TextView) findViewById(R.id.connected_device_name);
            mServerCharacteristic = (ImageView) findViewById(R.id.server_characteristic_value);
            mRequestReadCharacteristic = (Button) findViewById(R.id.request_read_characteristic);
            mTestConnected = (TextView) findViewById(R.id.TestConnected);
            mRequestReadCharacteristic.setOnClickListener(this);


            if (TextUtils.isEmpty(mDeviceName)) {
                mConnectedDeviceName.setText("");
            } else {
                mConnectedDeviceName.setText(mDeviceName);
            }


            Intent gattServiceIntent = new Intent(this, CentralService.class);
            bindService(gattServiceIntent, mServiceConnection, BIND_AUTO_CREATE);

        }


        @Override
        public void onClick(View view) {

            switch (view.getId()) {

                case R.id.request_read_characteristic:
                    requestReadCharacteristic();
                    break;

            }
        }


        private void requestReadCharacteristic() {
            if (mBluetoothLeService != null && mCharacteristic != null) {
                mBluetoothLeService.readCharacteristic(mCharacteristic);
            }
        }


        private final ServiceConnection mServiceConnection = new ServiceConnection() {

            @Override
            public void onServiceConnected(ComponentName componentName, IBinder service) {

                mBluetoothLeService = ((CentralService.LocalBinder) service).getService();

                if (!mBluetoothLeService.initialize()) {
                    Log.e(MainActivity.TAG, "Unable to initialize Bluetooth");
                    finish();
                }

                // Automatically connects to the device upon successful start-up initialization.
                mBluetoothLeService.connect(mDeviceAddress);
            }

            @Override
            public void onServiceDisconnected(ComponentName componentName) {
                mBluetoothLeService = null;
            }
        };

        private final BroadcastReceiver mGattUpdateReceiver = new BroadcastReceiver() {
            @Override
            public void onReceive(Context context, Intent intent) {

                String action = intent.getAction();

                if (action == null) {
                    return;
                }

                switch (intent.getAction()) {

                    case CentralService.ACTION_GATT_CONNECTED:
                        updateConnectionState(R.string.connected);
                        mRequestReadCharacteristic.setEnabled(true);
                        break;

                    case CentralService.ACTION_GATT_DISCONNECTED:
                        updateConnectionState(R.string.disconnected);
                        mRequestReadCharacteristic.setEnabled(false);
                        break;


                    case CentralService.ACTION_GATT_SERVICES_DISCOVERED:
                        setGattServices(mBluetoothLeService.getSupportedGattServices());
                        registerCharacteristic();
                        break;

                    case CentralService.ACTION_DATA_AVAILABLE:
                        /* //--> method for an integer
                        int msg = intent.getIntExtra(CentralService.EXTRA_DATA, -1);
                        if(msg == 1){
                            mServerCharacteristic.setBackgroundColor(Color.parseColor("#AD1457"));
                        } else if(msg == 2){
                            mServerCharacteristic.setBackgroundColor(Color.parseColor("#6A1B9A"));
                        }
                        else {
                            mServerCharacteristic.setBackgroundColor(Color.parseColor("#000000"));
                        }
                        */
                        int bmsg = intent.getIntExtra(CentralService.EXTRA_DATA, -1);
                        mServerCharacteristic.setBackgroundColor(Color.parseColor("#000000"));
                        //Crash when i use getIntArrayExtra and Integer.toString[0]
                        String msg = Integer.toString(bmsg);

                       if(msg != null && !msg.isEmpty()){
                           mTestConnected.setText(msg);
                       }
                       else {
                           mTestConnected.setText("error");
                       }


                }
            }
        };

        private void registerCharacteristic() {

            BluetoothGattCharacteristic characteristic = null;

            if (mDeviceServices != null) {

                for (ArrayList<BluetoothGattCharacteristic> service : mDeviceServices) {

                    for (BluetoothGattCharacteristic serviceCharacteristic : service) {

                        if (serviceCharacteristic.getService().getUuid().equals(Constants.HEART_RATE_SERVICE_UUID)) {

                            if (serviceCharacteristic.getUuid().equals(Constants.BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID)) {
                                characteristic = serviceCharacteristic;
                                mCharacteristic = characteristic;
                            }
                        }
                    }
                }

                if (characteristic != null) {
                    mBluetoothLeService.readCharacteristic(characteristic);
                    mBluetoothLeService.setCharacteristicNotification(characteristic, true);
                }
            }
        }

        private void setGattServices(List<BluetoothGattService> gattServices) {

            if (gattServices == null) {
                return;
            }

            mDeviceServices = new ArrayList<>();

            for (BluetoothGattService gattService : gattServices) {
                ArrayList<BluetoothGattCharacteristic> characteristic = new ArrayList<>();
                characteristic.addAll(gattService.getCharacteristics());
                mDeviceServices.add(characteristic);
            }

        }


        private void updateConnectionState(final int resourceId) {
            runOnUiThread(new Runnable() {
                @Override
                public void run() {
                    mConnectionStatus.setText(resourceId);
                }
            });
        }


        private static IntentFilter makeGattUpdateIntentFilter() {
            final IntentFilter intentFilter = new IntentFilter();
            intentFilter.addAction(CentralService.ACTION_GATT_CONNECTED);
            intentFilter.addAction(CentralService.ACTION_GATT_DISCONNECTED);
            intentFilter.addAction(CentralService.ACTION_GATT_SERVICES_DISCOVERED);
            intentFilter.addAction(CentralService.ACTION_DATA_AVAILABLE);
            return intentFilter;
        }

//------------------------------------------------------------------
//------------------------------------------------------------------
//------------------------------------------------------------------

    private static final int STATE_DISCONNECTED = 0;
    private static final int STATE_CONNECTING = 1;
    private static final int STATE_CONNECTED = 2;

    public final static String ACTION_GATT_CONNECTED = "ACTION_GATT_CONNECTED";
    public final static String ACTION_GATT_DISCONNECTED = "ACTION_GATT_DISCONNECTED";
    public final static String ACTION_GATT_SERVICES_DISCOVERED = "ACTION_GATT_SERVICES_DISCOVERED";
    public final static String ACTION_DATA_AVAILABLE = "ACTION_DATA_AVAILABLE";
    public final static String EXTRA_DATA = "EXTRA_DATA";


    private BluetoothManager mBluetoothManager;
    private BluetoothAdapter mBluetoothAdapter;
    private String mBluetoothDeviceAddress;
    private BluetoothGatt mBluetoothGatt;

    private final IBinder mBinder = new LocalBinder();
    private int mConnectionState = STATE_DISCONNECTED;

    private final BluetoothGattCallback mGattCallback = new BluetoothGattCallback() {

        @Override
        public void onConnectionStateChange(BluetoothGatt gatt, int status, int newState) {

            String intentAction;

            if (newState == BluetoothProfile.STATE_CONNECTED) {
                intentAction = ACTION_GATT_CONNECTED;
                mConnectionState = STATE_CONNECTED;
                broadcastUpdate(intentAction);
                Log.i(MainActivity.TAG, "Connected to GATT server.");
                Log.i(MainActivity.TAG, "Attempting to start service discovery:" + mBluetoothGatt.discoverServices());

            } else if (newState == BluetoothProfile.STATE_DISCONNECTED) {
                intentAction = ACTION_GATT_DISCONNECTED;
                mConnectionState = STATE_DISCONNECTED;
                Log.i(MainActivity.TAG, "Disconnected from GATT server.");
                broadcastUpdate(intentAction);
            }
        }

        @Override
        public void onServicesDiscovered(BluetoothGatt gatt, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                broadcastUpdate(ACTION_GATT_SERVICES_DISCOVERED);
            } else {
                Log.w(MainActivity.TAG, "onServicesDiscovered received: " + status);
            }
        }

        @Override
        public void onCharacteristicRead(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, int status) {
            if (status == BluetoothGatt.GATT_SUCCESS) {
                broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
            } else {
                Log.w(MainActivity.TAG, "onCharacteristicRead GATT_FAILURE");
            }
        }

        @Override
        public void onCharacteristicChanged(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic) {
            broadcastUpdate(ACTION_DATA_AVAILABLE, characteristic);
        }
    };


    private void broadcastUpdate(final String action) {
        final Intent intent = new Intent(action);
        sendBroadcast(intent);
    }


    private void broadcastUpdate(final String action, final BluetoothGattCharacteristic characteristic) {

        Intent intent = new Intent(action);
        if (Constants.BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID.equals(characteristic.getUuid())) {

            int flag = characteristic.getProperties();
            int format = -1;

            if ((flag & 0x01) != 0) {
                format = BluetoothGattCharacteristic.FORMAT_UINT16;
                Log.d(MainActivity.TAG, "data format UINT16.");
            } else {
                format = BluetoothGattCharacteristic.FORMAT_UINT8;
                Log.d(MainActivity.TAG, "data format UINT16.");
            }

            int msg = characteristic.getIntValue(format, 0);
            Log.d(MainActivity.TAG, String.format("message: %d", msg));
            intent.putExtra(EXTRA_DATA, msg);

        } else {

            final byte[] data = characteristic.getValue();

            if (data != null && data.length > 0) {
                final StringBuilder stringBuilder = new StringBuilder(data.length);
                for (byte byteChar : data) {
                    stringBuilder.append(String.format("%02X ", byteChar));
                }

                Log.w(MainActivity.TAG, "broadcastUpdate. general profile");
                intent.putExtra(EXTRA_DATA, -1);
            }
        }


        sendBroadcast(intent);
    }



    public boolean initialize() {

        // For API level 18 and above, get a reference to BluetoothAdapter through BluetoothManager.
        if (mBluetoothManager == null) {

            mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

            if (mBluetoothManager == null) {
                Log.e(MainActivity.TAG, "Unable to initialize BluetoothManager.");
                return false;
            }
        }

        mBluetoothAdapter = mBluetoothManager.getAdapter();

        if (mBluetoothAdapter == null) {
            Log.e(MainActivity.TAG, "Unable to obtain a BluetoothAdapter.");
            return false;
        }

        return true;
    }

    public boolean connect(final String address) {

        if (mBluetoothAdapter == null || address == null) {
            Log.w(MainActivity.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(MainActivity.TAG, "Trying to use an existing mBluetoothGatt for connection.");
            if (mBluetoothGatt.connect()) {
                mConnectionState = STATE_CONNECTING;
                return true;
            } else {
                return false;
            }
        }

        BluetoothDevice device = mBluetoothAdapter.getRemoteDevice(address);
        if (device == null) {
            Log.w(MainActivity.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);
        mBluetoothDeviceAddress = address;
        mConnectionState = STATE_CONNECTING;

        Log.d(MainActivity.TAG, "Trying to create a new connection.");

        return true;
    }

   



    public void readCharacteristic(BluetoothGattCharacteristic characteristic) {

        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(MainActivity.TAG, "BluetoothAdapter not initialized");
            return;
        }
        characteristic.setValue(100, BluetoothGattCharacteristic.FORMAT_UINT8, 0);
        mBluetoothGatt.writeCharacteristic(characteristic);
    }

    public void setCharacteristicNotification(BluetoothGattCharacteristic characteristic, boolean enabled) {

        if (mBluetoothAdapter == null || mBluetoothGatt == null) {
            Log.w(MainActivity.TAG, "BluetoothAdapter not initialized");
            return;
        }

        mBluetoothGatt.setCharacteristicNotification(characteristic, enabled);

    }

    public List<BluetoothGattService> getSupportedGattServices() {
        if (mBluetoothGatt == null) {
            return null;
        }

        return mBluetoothGatt.getServices();
    }
//-----------------------------peripheral :
//-----------------------------
//-----------------------------
//-----------------------------



       private BluetoothGattService mSampleService;
        private BluetoothGattCharacteristic mSampleCharacteristic;

        private BluetoothManager mBluetoothManager;
        private BluetoothGattServer mGattServer;
        private HashSet<BluetoothDevice> mBluetoothDevices;

        private Button mNotifyButton;
        private Switch mEnableAdvertisementSwitch;
        private RadioGroup mCharacteristicValueSwitch;

        public static final String TAG = "BluetoothLE";



        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);

            mNotifyButton = (Button) findViewById(R.id.button_notify);
            mEnableAdvertisementSwitch = (Switch) findViewById(R.id.advertise_switch);
            mCharacteristicValueSwitch = (RadioGroup) findViewById(R.id.color_switch);


            mNotifyButton.setOnClickListener(this);
            mEnableAdvertisementSwitch.setOnClickListener(this);
            mCharacteristicValueSwitch.setOnCheckedChangeListener(new RadioGroup.OnCheckedChangeListener() {
                @Override
                public void onCheckedChanged(RadioGroup group, int checkedId) {
                    setCharacteristic(checkedId);
                }
            });

            setGattServer();
            setBluetoothService();
        }



        @Override
        public void onClick(View view) {

            switch(view.getId()) {

                case R.id.advertise_switch:
                    Switch switchToggle = (Switch) view;
                    if (switchToggle.isChecked()) {
                        startAdvertising();
                    } else {
                        stopAdvertising();
                    }
                    break;


                case R.id.button_notify:
                    notifyCharacteristicChanged();
                    break;

            }
        }



        //Starts BLE Advertising by starting
        private void startAdvertising() {
            startService(getServiceIntent(this));
        }



        private void setGattServer() {

            mBluetoothDevices = new HashSet<>();
            mBluetoothManager = (BluetoothManager) getSystemService(Context.BLUETOOTH_SERVICE);

            if (mBluetoothManager != null) {
                mGattServer = mBluetoothManager.openGattServer(this, mGattServerCallback);
            } else {
                showMsgText(R.string.error_unknown);
            }
        }

        private void setBluetoothService() {

            // create the Service
            mSampleService = new BluetoothGattService(HEART_RATE_SERVICE_UUID, BluetoothGattService.SERVICE_TYPE_PRIMARY);

            /*
            create the Characteristic.
            we need to grant to the Client permission to read (for when the user clicks the "Request Characteristic" button).
            no need for notify permission as this is an action the Server initiate.

            https://developer.android.com/reference/android/bluetooth/BluetoothGattCharacteristic
             */
            mSampleCharacteristic = new BluetoothGattCharacteristic(BODY_SENSOR_LOCATION_CHARACTERISTIC_UUID, BluetoothGattCharacteristic.PROPERTY_NOTIFY | BluetoothGattCharacteristic.PROPERTY_READ, BluetoothGattCharacteristic.PERMISSION_READ);
            setCharacteristic(R.id.color_option_1);

            // add the Characteristic to the Service
            mSampleService.addCharacteristic(mSampleCharacteristic);

            // add the Service to the Server/Peripheral
            if (mGattServer != null) {
                mGattServer.addService(mSampleService);
            }
        }


        private void setCharacteristic(int checkedId) {
            int value = checkedId == R.id.color_option_1 ? SERVER_MSG_FIRST_STATE : SERVER_MSG_SECOND_STATE;
            //mSampleCharacteristic.setValue(new byte[]{0x08, 0x01, 0x03, 0x04, 0x52, 0x00, 0x02, 0x62});
            mSampleCharacteristic.setValue(getValue(value));
        }

        private byte[] getValue(int value) {
            return new byte[]{(byte) value};
        }

        /*
        send to the client the value of the Characteristic,
        as the user requested to notify.
         */
        private void notifyCharacteristicChanged() {
            /*
            done when the user clicks the notify button in the app.
            indicate - true for indication (acknowledge) and false for notification (un-acknowledge).
             */
            boolean indicate = (mSampleCharacteristic.getProperties() & BluetoothGattCharacteristic.PROPERTY_INDICATE) == BluetoothGattCharacteristic.PROPERTY_INDICATE;

            for (BluetoothDevice device : mBluetoothDevices) {
                if (mGattServer != null) {
                    mGattServer.notifyCharacteristicChanged(device, mSampleCharacteristic, indicate);
                }
            }
        }


        private Intent getServiceIntent(Context context) {
            return new Intent(context, PeripheralAdvertiseService.class);
        }


        private final BluetoothGattServerCallback mGattServerCallback = new BluetoothGattServerCallback() {

            @Override
            public void onConnectionStateChange(BluetoothDevice device, final int status, int newState) {

                super.onConnectionStateChange(device, status, newState);

                String msg;

                if (status == BluetoothGatt.GATT_SUCCESS) {

                    if (newState == BluetoothGatt.STATE_CONNECTED) {

                        mBluetoothDevices.add(device);

                        msg = "Connected to device: " + device.getAddress();
                        Log.v(PeripheralRoleActivity.TAG, msg);
                        showMsgText(msg);

                    } else if (newState == BluetoothGatt.STATE_DISCONNECTED) {

                        mBluetoothDevices.remove(device);

                        msg = "Disconnected from device";
                        Log.v(PeripheralRoleActivity.TAG, msg);
                        showMsgText(msg);
                    }

                } else {
                    mBluetoothDevices.remove(device);

                    msg = getString(R.string.status_error_when_connecting) + ": " + status;
                    Log.e(PeripheralRoleActivity.TAG, msg);
                    showMsgText(msg);

                }
            }


            @Override
            public void onNotificationSent(BluetoothDevice device, int status) {
                super.onNotificationSent(device, status);
                Log.v(PeripheralRoleActivity.TAG, "Notification sent. Status: " + status);
            }


            @Override
            public void onCharacteristicReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattCharacteristic characteristic) {

                super.onCharacteristicReadRequest(device, requestId, offset, characteristic);

                if (mGattServer == null) {
                    return;
                }


                //showMsgText("Value: " + characteristic.getIntValue(BluetoothGattCharacteristic.FORMAT_UINT8, 0));

                mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, characteristic.getValue());
            }


            @Override
            public void onCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, boolean preparedWrite, boolean responseNeeded, int offset, byte[] value) {

                super.onCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);

                //Log.v(PeripheralRoleActivity.TAG, "Characteristic Write request: " + Arrays.toString(value));
                showMsgText("Value: " + value);


                if (responseNeeded) {
                    mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, 0, value);
                }

            }

            @Override
            public void onDescriptorReadRequest(BluetoothDevice device, int requestId, int offset, BluetoothGattDescriptor descriptor) {

                super.onDescriptorReadRequest(device, requestId, offset, descriptor);

                if (mGattServer == null) {
                    return;
                }

                Log.d(PeripheralRoleActivity.TAG, "Device tried to read descriptor: " + descriptor.getUuid());
                Log.d(PeripheralRoleActivity.TAG, "Value: " + Arrays.toString(descriptor.getValue()));
                showMsgText("onDescriptorReadRequest: ");

                mGattServer.sendResponse(device, requestId, BluetoothGatt.GATT_SUCCESS, offset, descriptor.getValue());
            }

            @Override
            public void onDescriptorWriteRequest(BluetoothDevice device, int requestId,
                                                 BluetoothGattDescriptor descriptor, boolean preparedWrite, boolean responseNeeded,
                                                 int offset,
                                                 byte[] value) {

                super.onDescriptorWriteRequest(device, requestId, descriptor, preparedWrite, responseNeeded, offset, value);

                Log.v(PeripheralRoleActivity.TAG, "Descriptor Write Request " + descriptor.getUuid() + " " + Arrays.toString(value));
                showMsgText("onDescriptorWriteRequest: ");

            }
        };

(я удалил какую-то бесполезную часть, например, отключить / остановить BLE ...)

Спасибо за потраченное время!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...