Я начинаю использовать 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 ...)
Спасибо за потраченное время!