Android: отправка данных> 20 байт по BLE
Я могу отправлять данные размером до 20 байт, подключаясь к внешнему устройству BLE. Как мне отправить данные размером более 20 байт. Я читал, что мы должны либо фрагментировать данные, либо разбивать характеристику на требуемые части. Если я предположу, что мои данные составляют 32 байта, не могли бы вы сказать мне, какие изменения мне нужно внести в свой код, чтобы это заработало? Ниже приведены необходимые фрагменты из моего кода:
public boolean send(byte[] data) {
if (mBluetoothGatt == null || mBluetoothGattService == null) {
Log.w(TAG, "BluetoothGatt not initialized");
return false;
}
BluetoothGattCharacteristic characteristic =
mBluetoothGattService.getCharacteristic(UUID_SEND);
if (characteristic == null) {
Log.w(TAG, "Send characteristic not found");
return false;
}
characteristic.setValue(data);
characteristic.setWriteType(BluetoothGattCharacteristic.WRITE_TYPE_NO_RESPONSE);
return mBluetoothGatt.writeCharacteristic(characteristic);
}
Это код, который я использовал для отправки данных. Функция "отправить" используется в следующем событии onclick .
sendValueButton = (Button) findViewById(R.id.sendValue);
sendValueButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String text = dataEdit.getText().toString();
yableeService.send(text.getBytes());
}
});
Когда значение String text
превышает 20 байт, принимаются только первые 20 байт. Как это исправить?
Чтобы протестировать отправку нескольких характеристик, я попробовал это:
sendValueButton = (Button) findViewById(R.id.sendValue);
sendValueButton.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
String text = "Test1";
yableeService.send(text.getBytes());
text = "Test2";
yableeService.send(text.getBytes());
text = "Test3";
yableeService.send(text.getBytes());
}
});
Но я получил только "Test3", то есть последнюю характеристику. Какую ошибку я совершил? Я новичок в BLE, поэтому, пожалуйста, игнорируйте любую наивность
Редактировать:
После принятия ответа для всех, кто просмотрит это позже.
Для этого есть два способа. 1. Разделите свои данные и запишите в цикле, как это делает выбранный ответ. 2. Разделите ваши данные и напишите с помощью обратного вызова, т.е. onCharacterisitcWrite()
. Это избавит вас от ошибок, если таковые имели место во время записи.
Но самое важное между операциями записи используйте a Thread.sleep(200)
, если вы только записываете, а не ждете ответа от прошивки. Это гарантирует, что все ваши данные дойдут. Без sleep
я всегда получал последний пакет. Если вы заметили принятый ответ, который он также использовал sleep
между ними.
Переведено автоматически
Ответ 1
ОБНОВЛЕНИЕ: Пожалуйста, ознакомьтесь с дополнительным ответом, чтобы узнать, что есть другой способ достичь ваших ожиданий.
В 2014 году BLE позволял передавать максимум 20 байт.
Если вы хотите отправить более 20 байт, вы должны определить массив, который byte[]
будет содержать столько пакетов, сколько вы хотите.
Следующий пример отлично сработал, если вы хотите отправить менее 160 символов (160 байт).
p / s : Давайте отредактируем следующее так, как вы хотите. Не совсем меня понимаете.
На самом деле, когда мы используем BLE, мобильной стороне и стороне прошивки необходимо настроить ключ (например. 0x03
...) для определения шлюза подключения между обеими сторонами.
Идея в том, :
Когда мы продолжаем передавать пакеты, not является последним. Шлюз - это
byte[1] = 0x01
.Если мы отправим последнее, то шлюз будет
byte[1] = 0x00
.
Структура данных (20 байт):
1 - Byte 1
- Определите Gate ID
: например, идентификатор шлюза сообщений byte[0] = 0x03
.
2 - Byte 2
- Определите recognization
: Это последний пакет 0x00
или продолжайте отправлять пакеты 0x01
.
3 - Byte 3
(Должно быть 18 байт после удаления Byte 1
& Byte 2
) - Прикрепите содержимое сообщения сюда.
пожалуйста, поймите мою логику, прежде чем читать приведенный ниже код.
Ниже приведен пример отправки сообщения с большим количеством пакетов, каждый пакет представляет собой массив размером 20 байт.
private void sendMessage(BluetoothGattCharacteristic characteristic, String CHARACTERS){
byte[] initial_packet = new byte[3];
/**
* Indicate byte
*/
initial_packet[0] = BLE.INITIAL_MESSAGE_PACKET;
if (Long.valueOf(
String.valueOf(CHARACTERS.length() + initial_packet.length))
> BLE.DEFAULT_BYTES_VIA_BLE) {
sendingContinuePacket(characteristic, initial_packet, CHARACTERS);
} else {
sendingLastPacket(characteristic, initial_packet, CHARACTERS);
}
}
private void sendingContinuePacket(BluetoothGattCharacteristic characteristic,
byte[] initial_packet, String CHARACTERS){
/**
* TODO If data length > Default data can sent via BLE : 20 bytes
*/
// Check the data length is large how many times with Default Data (BLE)
int times = Byte.valueOf(String.valueOf(
CHARACTERS.length() / BLE.DEFAULT_BYTES_IN_CONTINUE_PACKET));
Log.i(TAG, "CHARACTERS.length() " + CHARACTERS.length());
Log.i(TAG, "times " + times);
// TODO
// 100 : Success
// 101 : Error
byte[] sending_continue_hex = new byte[BLE.DEFAULT_BYTES_IN_CONTINUE_PACKET];
for (int time = 0; time <= times; time++) {
/**
* Wait second before sending continue packet
*/
try {
Thread.sleep(200);
} catch (InterruptedException e) {
e.printStackTrace();
}
if (time == times) {
Log.i(TAG, "LAST PACKET ");
/**
* If you do not have enough characters to send continue packet,
* This is the last packet that will be sent to the band
*/
/**
* Packet length byte :
*/
/**
* Length of last packet
*/
int character_length = CHARACTERS.length()
- BLE.DEFAULT_BYTES_IN_CONTINUE_PACKET*times;
initial_packet[1] = Byte.valueOf(String.valueOf(character_length
+ BLE.INITIAL_MESSAGE_PACKET_LENGTH));
initial_packet[2] = BLE.SENDING_LAST_PACKET;
Log.i(TAG, "character_length " + character_length);
/**
* Message
*/
// Hex file
byte[] sending_last_hex = new byte[character_length];
// Hex file : Get next bytes
for (int i = 0; i < sending_last_hex.length; i++) {
sending_last_hex[i] =
CHARACTERS.getBytes()[sending_continue_hex.length*time + i];
}
// Merge byte[]
byte[] last_packet =
new byte[character_length + BLE.INITIAL_MESSAGE_PACKET_LENGTH];
System.arraycopy(initial_packet, 0, last_packet,
0, initial_packet.length);
System.arraycopy(sending_last_hex, 0, last_packet,
initial_packet.length, sending_last_hex.length);
// Set value for characteristic
characteristic.setValue(last_packet);
} else {
Log.i(TAG, "CONTINUE PACKET ");
/**
* If you have enough characters to send continue packet,
* This is the continue packet that will be sent to the band
*/
/**
* Packet length byte
*/
int character_length = sending_continue_hex.length;
/**
* TODO Default Length : 20 Bytes
*/
initial_packet[1] = Byte.valueOf(String.valueOf(
character_length + BLE.INITIAL_MESSAGE_PACKET_LENGTH));
/**
* If sent data length > 20 bytes (Default : BLE allow send 20 bytes one time)
* -> set 01 : continue sending next packet
* else or if after sent until data length < 20 bytes
* -> set 00 : last packet
*/
initial_packet[2] = BLE.SENDING_CONTINUE_PACKET;
/**
* Message
*/
// Hex file : Get first 17 bytes
for (int i = 0; i < sending_continue_hex.length; i++) {
Log.i(TAG, "Send stt : "
+ (sending_continue_hex.length*time + i));
// Get next bytes
sending_continue_hex[i] =
CHARACTERS.getBytes()[sending_continue_hex.length*time + i];
}
// Merge byte[]
byte[] sending_continue_packet =
new byte[character_length + BLE.INITIAL_MESSAGE_PACKET_LENGTH];
System.arraycopy(initial_packet, 0, sending_continue_packet,
0, initial_packet.length);
System.arraycopy(sending_continue_hex, 0, sending_continue_packet,
initial_packet.length, sending_continue_hex.length);
// Set value for characteristic
characteristic.setValue(sending_continue_packet);
}
// Write characteristic via BLE
mBluetoothGatt.writeCharacteristic(characteristic);
}
}
public boolean writeCharacteristic(BluetoothGattCharacteristic characteristic,
String data) {
if (mBluetoothAdapter == null || mBluetoothGatt == null) {
Log.w(TAG, "BluetoothAdapter not initialized");
return false;
}
if (ActivityBLEController.IS_FIRST_TIME) {
/**
* In the first time,
* should send the Title
*/
byte[] merge_title = sendTitle(data);
// Set value for characteristic
characteristic.setValue(merge_title);
// Write characteristic via BLE
mBluetoothGatt.writeCharacteristic(characteristic);
// Reset
ActivityBLEController.IS_FIRST_TIME = false;
return true;
} else {
/**
* In the second time,
* should send the Message
*/
if (data.length() <= BLE.LIMIT_CHARACTERS) {
sendMessage(characteristic, data);
// Reset
ActivityBLEController.IS_FIRST_TIME = true;
return true;
} else {
// Typed character
typed_character = data.length();
return false;
}
}
}
Ответ 2
На Lollipop вы можете отправлять до 512 байт. Вам нужно использовать BluetoothGatt.requestMtu()
со значением 512. Кроме того, как упоминал @Devunwired, вам нужно дождаться завершения любой предыдущей операции, прежде чем вызывать это.
Ответ 3
Здесь много ошибок.
BLE способен отправлять гораздо больше, чем 20 байт, и это можно легко сделать в Android.
Что вам нужно изменить, так это MTU ссылки, для которого по умолчанию установлено значение 23 (только 20 из них могут быть использованы для установки значения). Android предоставляет механизм фрагментации, если данный отправляемый пакет больше, чем текущий MTU канала (это назначение параметра offset в onCharacteristicRead(...)
API).
Таким образом, вы можете увеличить MTU в качестве запроса от центра, используя: requestMtu(...)
API. Последнее вызовет обратный вызов onMtuChanged
на периферийной стороне, которая сообщит ему о новом MTU. После выполнения этого действия вы сможете отправлять пакеты большего размера, не задействуя механизм фрагментации Android.
Альтернативой является создание собственного механизма фрагментации и отказ от отправки пакетов, размер которых превышает MTU. Или положиться на механизм Android и работать с ним, используя параметр 'offset'.
Ответ 4
Вам необходимо запросить обновление MTU. Это максимальная единица передачи. На данный момент BLE принимает до 512 байт в одном пакете. Однако без запроса этого обновления MTU ваше устройство не будет отправлять пакет размером более 23 байт (в настоящее время).
Использование вызова объекта BluetoothGatt requestMtu()
Вот ссылка на страницу разработчика
BluetoothGattCallback получит событие onMtuChanged(), как показано ниже. После успешного обновления MTU вы можете отправить данные одним пакетом. Вот ссылка на эту страницу разработчика.
Обычно я вызываю requestMtu() после подключения к характеристике, на которую я хочу записать. Удачи.