Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ abstract class ConnectedDeviceOperation {
required List<int> value,
});

Future<void> writeCharacteristicWithoutResponseBatch(
CharacteristicInstance characteristic, {
required List<int> value,
int? packetSize,
});

Stream<List<int>> subscribeToCharacteristic(
CharacteristicInstance characteristic,
Future<void> isDisconnected,
Expand Down Expand Up @@ -76,6 +82,20 @@ class ConnectedDeviceOperationImpl implements ConnectedDeviceOperation {
.writeCharacteristicWithoutResponse(characteristic, value)
.then((info) => info.result.dematerialize());

@override
Future<void> writeCharacteristicWithoutResponseBatch(
CharacteristicInstance characteristic, {
required List<int> value,
int? packetSize,
}) async =>
_blePlatform
.writeCharacteristicWithoutResponseBatch(
characteristic,
value,
packetSize: packetSize,
)
.then((info) => info.result.dematerialize());

@override
Stream<List<int>> subscribeToCharacteristic(
CharacteristicInstance characteristic,
Expand Down
47 changes: 47 additions & 0 deletions packages/flutter_reactive_ble/lib/src/reactive_ble.dart
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,53 @@ class FlutterReactiveBle {
await (await resolveSingle(characteristic)).write(value, withResponse: false);
}

/// Writes [value] without response as a sequence of packets, sent back to
/// back by the platform without returning to the dart layer between packets.
///
/// This reduces per-write overhead for bulk transfers such as firmware
/// updates: every packet is filled up to the maximum size and the
/// dart <-> platform round trip per write is removed, which awaiting
/// [writeCharacteristicWithoutResponse] per packet would incur. The BLE stack
/// may still send only one packet per connection event.
///
/// By default packets are (MTU - 3) bytes. Set [packetSize] when the
/// peripheral expects a fixed frame per ATT write; the value is split into
/// packets of that many bytes (the last one may be shorter). It must be
/// positive and must not exceed (MTU - 3): iOS and macOS clamp it to
/// `maximumWriteValueLength`, Android does not check it. Protocols with a
/// frame below (MTU - 3) only gain the saved round trips. A null [packetSize]
/// uses the platform default.
///
/// Packets are sent in order. The returned future completes when the last
/// packet has been accepted by the platform BLE stack (not when the device has
/// processed it), or with an error on the first failure; in that case, packets
/// before the failure may already have been sent.
///
/// Negotiate the MTU with [requestMtu] first. Keep [value] no larger than
/// what the device can buffer, and confirm reception between batches
/// (e.g. via a notification) as write-without-response has no acknowledgement.
///
/// Throws an [ArgumentError] if [packetSize] is not positive.
Future<void> writeCharacteristicWithoutResponseBatch(
QualifiedCharacteristic characteristic, {
required List<int> value,
int? packetSize,
}) async {
if (packetSize != null && packetSize <= 0) {
throw ArgumentError.value(
packetSize, 'packetSize', 'must be greater than 0');
}
if (value.isEmpty) return;
await initialize();
final resolved = await resolveSingle(characteristic);
resolved._assertValidity();
await _connectedDeviceOperator.writeCharacteristicWithoutResponseBatch(
resolved._ids,
value: value,
packetSize: packetSize,
);
}

/// Request a specific MTU for a connected device.
///
/// Returns the actual MTU negotiated.
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
// Mocks generated by Mockito 5.4.0 from annotations
// Mocks generated by Mockito 5.4.4 from annotations
// in flutter_reactive_ble/test/connected_device_operation_test.dart.
// Do not manually edit this file.

Expand All @@ -14,6 +14,8 @@ import 'package:reactive_ble_platform_interface/src/reactive_ble_platform_interf
// ignore_for_file: avoid_redundant_argument_values
// ignore_for_file: avoid_setters_without_getters
// ignore_for_file: comment_references
// ignore_for_file: deprecated_member_use
// ignore_for_file: deprecated_member_use_from_same_package
// ignore_for_file: implementation_imports
// ignore_for_file: invalid_use_of_visible_for_testing_member
// ignore_for_file: prefer_const_constructors
Expand Down Expand Up @@ -68,23 +70,27 @@ class MockReactiveBlePlatform extends _i1.Mock
Invocation.getter(#scanStream),
returnValue: _i4.Stream<_i2.ScanResult>.empty(),
) as _i4.Stream<_i2.ScanResult>);

@override
_i4.Stream<_i2.BleStatus> get bleStatusStream => (super.noSuchMethod(
Invocation.getter(#bleStatusStream),
returnValue: _i4.Stream<_i2.BleStatus>.empty(),
) as _i4.Stream<_i2.BleStatus>);

@override
_i4.Stream<_i2.ConnectionStateUpdate> get connectionUpdateStream =>
(super.noSuchMethod(
Invocation.getter(#connectionUpdateStream),
returnValue: _i4.Stream<_i2.ConnectionStateUpdate>.empty(),
) as _i4.Stream<_i2.ConnectionStateUpdate>);

@override
_i4.Stream<_i2.CharacteristicValue> get charValueUpdateStream =>
(super.noSuchMethod(
Invocation.getter(#charValueUpdateStream),
returnValue: _i4.Stream<_i2.CharacteristicValue>.empty(),
) as _i4.Stream<_i2.CharacteristicValue>);

@override
_i4.Future<void> initialize() => (super.noSuchMethod(
Invocation.method(
Expand All @@ -94,6 +100,7 @@ class MockReactiveBlePlatform extends _i1.Mock
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);

@override
_i4.Future<void> deinitialize() => (super.noSuchMethod(
Invocation.method(
Expand All @@ -103,6 +110,7 @@ class MockReactiveBlePlatform extends _i1.Mock
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);

@override
_i4.Stream<void> scanForDevices({
required List<_i2.Uuid>? withServices,
Expand All @@ -121,6 +129,7 @@ class MockReactiveBlePlatform extends _i1.Mock
),
returnValue: _i4.Stream<void>.empty(),
) as _i4.Stream<void>);

@override
_i4.Future<_i2.Result<_i2.Unit, _i2.GenericFailure<_i2.ClearGattCacheError>?>>
clearGattCache(String? deviceId) => (super.noSuchMethod(
Expand All @@ -140,8 +149,9 @@ class MockReactiveBlePlatform extends _i1.Mock
),
)),
) as _i4.Future<
_i2.Result<_i2.Unit,
_i2.GenericFailure<_i2.ClearGattCacheError>?>>);
_i2
.Result<_i2.Unit, _i2.GenericFailure<_i2.ClearGattCacheError>?>>);

@override
_i4.Future<int> readRssi(String? deviceId) => (super.noSuchMethod(
Invocation.method(
Expand All @@ -150,6 +160,7 @@ class MockReactiveBlePlatform extends _i1.Mock
),
returnValue: _i4.Future<int>.value(0),
) as _i4.Future<int>);

@override
_i4.Stream<void> connectToDevice(
String? id,
Expand All @@ -167,6 +178,7 @@ class MockReactiveBlePlatform extends _i1.Mock
),
returnValue: _i4.Stream<void>.empty(),
) as _i4.Stream<void>);

@override
_i4.Future<void> disconnectDevice(String? deviceId) => (super.noSuchMethod(
Invocation.method(
Expand All @@ -176,6 +188,7 @@ class MockReactiveBlePlatform extends _i1.Mock
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);

@override
_i4.Future<List<_i2.DiscoveredService>> discoverServices(String? deviceId) =>
(super.noSuchMethod(
Expand All @@ -186,6 +199,7 @@ class MockReactiveBlePlatform extends _i1.Mock
returnValue: _i4.Future<List<_i2.DiscoveredService>>.value(
<_i2.DiscoveredService>[]),
) as _i4.Future<List<_i2.DiscoveredService>>);

@override
_i4.Future<List<_i2.DiscoveredService>> getDiscoverServices(
String? deviceId) =>
Expand All @@ -197,6 +211,7 @@ class MockReactiveBlePlatform extends _i1.Mock
returnValue: _i4.Future<List<_i2.DiscoveredService>>.value(
<_i2.DiscoveredService>[]),
) as _i4.Future<List<_i2.DiscoveredService>>);

@override
_i4.Stream<void> readCharacteristic(
_i2.CharacteristicInstance? characteristic) =>
Expand All @@ -207,6 +222,7 @@ class MockReactiveBlePlatform extends _i1.Mock
),
returnValue: _i4.Stream<void>.empty(),
) as _i4.Stream<void>);

@override
_i4.Future<_i2.WriteCharacteristicInfo> writeCharacteristicWithResponse(
_i2.CharacteristicInstance? characteristic,
Expand All @@ -232,6 +248,7 @@ class MockReactiveBlePlatform extends _i1.Mock
),
)),
) as _i4.Future<_i2.WriteCharacteristicInfo>);

@override
_i4.Future<_i2.WriteCharacteristicInfo> writeCharacteristicWithoutResponse(
_i2.CharacteristicInstance? characteristic,
Expand All @@ -257,6 +274,37 @@ class MockReactiveBlePlatform extends _i1.Mock
),
)),
) as _i4.Future<_i2.WriteCharacteristicInfo>);

@override
_i4.Future<_i2.WriteCharacteristicInfo>
writeCharacteristicWithoutResponseBatch(
_i2.CharacteristicInstance? characteristic,
List<int>? value, {
int? packetSize,
}) =>
(super.noSuchMethod(
Invocation.method(
#writeCharacteristicWithoutResponseBatch,
[
characteristic,
value,
],
{#packetSize: packetSize},
),
returnValue: _i4.Future<_i2.WriteCharacteristicInfo>.value(
_FakeWriteCharacteristicInfo_1(
this,
Invocation.method(
#writeCharacteristicWithoutResponseBatch,
[
characteristic,
value,
],
{#packetSize: packetSize},
),
)),
) as _i4.Future<_i2.WriteCharacteristicInfo>);

@override
_i4.Stream<void> subscribeToNotifications(
_i2.CharacteristicInstance? characteristic) =>
Expand All @@ -267,6 +315,7 @@ class MockReactiveBlePlatform extends _i1.Mock
),
returnValue: _i4.Stream<void>.empty(),
) as _i4.Stream<void>);

@override
_i4.Future<void> stopSubscribingToNotifications(
_i2.CharacteristicInstance? characteristic) =>
Expand All @@ -278,6 +327,7 @@ class MockReactiveBlePlatform extends _i1.Mock
returnValue: _i4.Future<void>.value(),
returnValueForMissingStub: _i4.Future<void>.value(),
) as _i4.Future<void>);

@override
_i4.Future<int> requestMtuSize(
String? deviceId,
Expand All @@ -293,6 +343,7 @@ class MockReactiveBlePlatform extends _i1.Mock
),
returnValue: _i4.Future<int>.value(0),
) as _i4.Future<int>);

@override
_i4.Future<_i2.ConnectionPriorityInfo> requestConnectionPriority(
String? deviceId,
Expand Down
Loading