Я пишу приложение Xamarin.Android, но этот вопрос применим к родным Android и BLE в целом. У меня есть характеристика записи, в которую я могу писать, и она работает до тех пор, пока я не отправляю более 600 символов. Все более 600 символов усекается. Глядя на мои журналы, я вижу, что текст разбивается на пакеты по 20 символов, и OnCharacteristicWriteRequest
вызывается для каждого пакета, но перестает вызываться после 600 символов. Я тестирую с 2 планшетами Android. Мой код для записи в характеристику:
public override void OnServicesDiscovered(BluetoothGatt gatt, [GeneratedEnum] GattStatus status)
{
base.OnServicesDiscovered(gatt, status);
try
{
if (status != GattStatus.Success)
{
Log?.Invoke("discover services failed");
return;
}
Log?.Invoke("services discovered");
if(RequestForAddressExists(gatt.Device.Address))
{
lock (_requestsLocker)
{
Java.Util.UUID serviceUuid = GetRequestedServiceUuid(gatt.Device.Address);
Java.Util.UUID characteristicUuid = GetRequestedCharacteristicUuid(gatt.Device.Address);
BluetoothGattCharacteristic characteristic = gatt.GetService(serviceUuid).GetCharacteristic(characteristicUuid);
Log?.Invoke("characterisitic found");
var request = _requests.FirstOrDefault(r => r.DeviceAddress == gatt.Device.Address);
if (characteristic.Properties.HasFlag(GattProperty.Write))
{
Log?.Invoke("writing characteristic...");
string data = ((WriteCharacteristicRequest)request).Data;
characteristic.SetValue($"{data}{Constants.WriteCharacteristicEndDelimiter}");
characteristic.WriteType = GattWriteType.Default;
gatt.WriteCharacteristic(characteristic);
}
else
{
Log?.Invoke("GattProperty not supported");
_requests.Remove(request);
}
}
}
}
catch (Exception e)
{
Log?.Invoke(e.Message);
}
}
public override void OnCharacteristicWrite(BluetoothGatt gatt, BluetoothGattCharacteristic characteristic, [GeneratedEnum] GattStatus status)
{
base.OnCharacteristicWrite(gatt, characteristic, status);
if (status != GattStatus.Success)
{
Log?.Invoke($"OnCharacteristicWrite status not success: {status}");
}
else
{
Log?.Invoke("OnCharacteristicWrite success");
}
gatt.Disconnect();
gatt.Close();
lock (_requestsLocker)
{
var r = _requests.FirstOrDefault(x => x.DeviceAddress == gatt.Device.Address);
if (r != null)
{
_requests.Remove(r);
}
}
}
Мой код для принятия запроса на запись:
public override void OnCharacteristicWriteRequest(BluetoothDevice device, int requestId, BluetoothGattCharacteristic characteristic, bool preparedWrite, bool responseNeeded, int offset, byte[] value)
{
base.OnCharacteristicWriteRequest(device, requestId, characteristic, preparedWrite, responseNeeded, offset, value);
Log?.Invoke("OnCharacteristicWriteRequest");
string data = System.Text.Encoding.UTF8.GetString(value);
Log?.Invoke(data);
string characteristicId = new Guid(characteristic.Uuid.ToString()).ToString().ToUpperInvariant();
var record = _writeCharacteristicsReceived.FirstOrDefault(c => c.DeviceAddress == device.Address && c.CharacteristicId.ToUpperInvariant() == characteristicId);
if(record != null)
{
record.Data += data;
}
else
{
record = new CharacteristicWriteReceived()
{
CharacteristicId = characteristicId,
DeviceAddress = device.Address,
Data = data
};
_writeCharacteristicsReceived.Add(record);
}
if (record.Data.EndsWith(Constants.WriteCharacteristicEndDelimiter) == true)
{
Log?.Invoke("end found");
_writeCharacteristicsReceived.Remove(record);
record.Data = record.Data.Substring(0, record.Data.Length - Constants.WriteCharacteristicEndDelimiter.Length); // remove the end delimeter
Log?.Invoke(record.Data);
OnCharacteristicWriteReceived?.Invoke(record);
}
if (responseNeeded)
{
BluetoothGattServer.SendResponse(device, requestId, GattStatus.Success, 0, value);
}
}
public override void OnExecuteWrite(BluetoothDevice device, int requestId, bool execute)
{
// need to override OnExecuteWrite and call SendResponse here as well,
// since the execute packet corresponds to the last ATT packet that the client sends as a "finish" marker,
// and the client expects a response to know that the server accepted the writes
base.OnExecuteWrite(device, requestId, execute);
BluetoothGattServer.SendResponse(device, requestId, GattStatus.Success, 0, new byte[0]);
}
Самое смешное, что даже когда текст обрезан, я все равно получаю status == GattStatus.Success
в моем OnCharacteristicWrite
. Почему оно усекается? Максимальное количество пакетов, которое можно отправить?
Оба устройства непрерывно рекламируют и сканируют на BLE во время записи этой характеристики ... может ли это вызвать проблемы?