6.0.0 (#74)
* 调整接口 * 临时提交 * 重构 Android 平台代码 * 临时提交 * 临时提交 * Android 6.0.0-dev.0 * 临时提交 * 实现 Windows 接口 * windows-6.0.0-dev.0 * Darwin 6.0.0-dev.0 * 临时提交 * 1 * 临时提交 * 调整接口 * windows-6.0.0-dev.1 * 临时提交 * interface-6.0.0-dev.7 * interface-6.0.0-dev.8 * 临时提交 * windows-6.0.0-dev.2 * 删除多余脚本 * interface-6.0.0-dev.9 * 临时提交 * 临时提交 * interface-6.0.0-dev.10 * android-6.0.0-dev.1 * windows-6.0.0-dev.3 * 临时提交 * interface-6.0.0-dev.11 * windows-6.0.0-dev.4 * 更新 pubspec.lock * 1 * interface-6.0.0-dev.12 * interface-6.0.0-dev.13 * interface-6.0.0-dev.14 * 临时提交 * interface-6.0.0-dev.15 * 临时提交 * interface-6.0.0-dev.16 * android-6.0.0-dev.2 * 临时提交 * windows-6.0.0-dev.5 * 临时提交 * 临时提交 * windows-6.0.0-dev.6 * 优化注释和代码样式 * 优化代码 * 临时提交 * 实现 Dart 接口 * darwin-6.0.0-dev.0 * linux-6.0.0-dev.0 * 修复已知问题 * 修复问题 * 6.0.0-dev.0 * 修改包名 * 更新版本 * 移除原生部分 * 临时提交 * 修复问题 * 更新 pigeon 19.0.0 * 更新 README,添加迁移文档 * linux-6.0.0-dev.1 * 解析扫描回复和扩展广播 * 修复 googletest 版本警告问题 * Use centralArgs instead of addressArgs * interface-6.0.0-dev.18 * android-6.0.0-dev.4 * linux-6.0.0-dev.2 * windows-6.0.0-dev.8 * darwin-6.0.0-dev.2 * 6.0.0-dev.1 * Update LICENSE * clang-format * Combine ADV_IND and SCAN_RES * TEMP commit: update exampe * Adjust advertisement combine logic * Implement `MyPeripheralMananger` on Windows * Added NuGet auto download and scan for names on peripheral (#67) * fetch nuget using other technique * move FetchContent to right location in CMakeLists.txt * also added hash for googletest --------- Co-authored-by: Kevin De Keyser <kevin@dekeyser.ch> * Fix errors. * Check BluetoothAdapter role supported state and implement PeripheralManager on Flutter side. * Sort code * Fix known errors * interface-6.0.0-dev.19 * windows-6.0.0-dev.9 * Optimize example * android-6.0.0-dev.5 * Optimize the Adverrtisement BottomSheet. * linux-6.0.0-dev.3 * Update dependency * Fix example errors. * Temp commit. * darwin-6.0.0-dev.3 * 6.0.0-dev.2 * Update README.md * 6.0.0 * darwin-6.0.0-dev.4 * android-6.0.0-dev.6 * 6.0.0-dev.3 * Update docs. * interface-6.0.0 * android-6.0.0 * darwin-6.0.0 * linux-6.0.0 * windows-6.0.0 * 6.0.0 * Update dependency --------- Co-authored-by: Kevin De Keyser <dekeyser.kevin97@gmail.com> Co-authored-by: Kevin De Keyser <kevin@dekeyser.ch>
This commit is contained in:
@ -3,9 +3,9 @@ import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_pla
|
||||
import 'src/my_central_manager.dart';
|
||||
import 'src/my_peripheral_manager.dart';
|
||||
|
||||
abstract class BluetoothLowEnergyDarwin {
|
||||
abstract class BluetoothLowEnergyDarwinPlugin {
|
||||
static void registerWith() {
|
||||
CentralManager.instance = MyCentralManager();
|
||||
PeripheralManager.instance = MyPeripheralManager();
|
||||
PlatformCentralManager.instance = MyCentralManager();
|
||||
PlatformPeripheralManager.instance = MyPeripheralManager();
|
||||
}
|
||||
}
|
||||
|
@ -3,13 +3,28 @@ import 'dart:typed_data';
|
||||
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
|
||||
|
||||
import 'my_api.g.dart';
|
||||
import 'my_gatt_characteristic2.dart';
|
||||
import 'my_gatt_descriptor2.dart';
|
||||
import 'my_gatt_service2.dart';
|
||||
|
||||
export 'my_api.g.dart';
|
||||
import 'my_gatt.dart';
|
||||
|
||||
// ToObject
|
||||
extension Uint8ListX on Uint8List {
|
||||
List<ManufacturerSpecificData> toManufacturerSpecificData() {
|
||||
if (length > 2) {
|
||||
return [
|
||||
ManufacturerSpecificData(
|
||||
id: ByteData.view(
|
||||
buffer,
|
||||
offsetInBytes,
|
||||
length,
|
||||
).getUint16(0, Endian.host),
|
||||
data: sublist(2),
|
||||
),
|
||||
];
|
||||
} else {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension MyBluetoothLowEnergyStateArgsX on MyBluetoothLowEnergyStateArgs {
|
||||
BluetoothLowEnergyState toState() {
|
||||
switch (this) {
|
||||
@ -28,211 +43,230 @@ extension MyBluetoothLowEnergyStateArgsX on MyBluetoothLowEnergyStateArgs {
|
||||
}
|
||||
}
|
||||
|
||||
extension MyGattCharacteristicPropertyArgsX
|
||||
on MyGattCharacteristicPropertyArgs {
|
||||
GattCharacteristicProperty toProperty() {
|
||||
return GattCharacteristicProperty.values[index];
|
||||
extension MyConnectionStateArgsX on MyConnectionStateArgs {
|
||||
ConnectionState toState() {
|
||||
return ConnectionState.values[index];
|
||||
}
|
||||
}
|
||||
|
||||
extension MyManufacturerSpecificDataArgsX on MyManufacturerSpecificDataArgs {
|
||||
ManufacturerSpecificData toManufacturerSpecificData() {
|
||||
final id = idArgs;
|
||||
final data = dataArgs;
|
||||
return ManufacturerSpecificData(
|
||||
id: id,
|
||||
data: data,
|
||||
);
|
||||
extension MyGATTCharacteristicPropertyArgsX
|
||||
on MyGATTCharacteristicPropertyArgs {
|
||||
GATTCharacteristicProperty toProperty() {
|
||||
return GATTCharacteristicProperty.values[index];
|
||||
}
|
||||
}
|
||||
|
||||
extension MyAdvertisementArgsX on MyAdvertisementArgs {
|
||||
Advertisement toAdvertisement() {
|
||||
final name = nameArgs;
|
||||
final serviceUUIDs =
|
||||
serviceUUIDsArgs.cast<String>().map((args) => args.toUUID()).toList();
|
||||
final serviceData = serviceDataArgs.cast<String, Uint8List>().map(
|
||||
(uuidArgs, dataArgs) {
|
||||
final uuid = uuidArgs.toUUID();
|
||||
final data = dataArgs;
|
||||
return MapEntry(uuid, data);
|
||||
},
|
||||
);
|
||||
final manufacturerSpecificData =
|
||||
manufacturerSpecificDataArgs?.toManufacturerSpecificData();
|
||||
return Advertisement(
|
||||
name: name,
|
||||
serviceUUIDs: serviceUUIDs,
|
||||
serviceData: serviceData,
|
||||
manufacturerSpecificData: manufacturerSpecificData,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension MyCentralArgsX on MyCentralArgs {
|
||||
MyCentral toCentral() {
|
||||
final uuid = uuidArgs.toUUID();
|
||||
return MyCentral(
|
||||
uuid: uuid,
|
||||
name: nameArgs,
|
||||
serviceUUIDs: serviceUUIDsArgs
|
||||
.cast<String>()
|
||||
.map((args) => UUID.fromString(args))
|
||||
.toList(),
|
||||
serviceData: serviceDataArgs.cast<String, Uint8List>().map(
|
||||
(uuidArgs, dataArgs) {
|
||||
final uuid = UUID.fromString(uuidArgs);
|
||||
return MapEntry(uuid, dataArgs);
|
||||
},
|
||||
),
|
||||
manufacturerSpecificData:
|
||||
manufacturerSpecificDataArgs?.toManufacturerSpecificData() ?? [],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension MyPeripheralArgsX on MyPeripheralArgs {
|
||||
MyPeripheral toPeripheral() {
|
||||
final uuid = uuidArgs.toUUID();
|
||||
return MyPeripheral(
|
||||
uuid: uuid,
|
||||
Peripheral toPeripheral() {
|
||||
return Peripheral(
|
||||
uuid: UUID.fromString(uuidArgs),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension MyGattDescriptorArgsX on MyGattDescriptorArgs {
|
||||
MyGattDescriptor2 toDescriptor2(MyPeripheral peripheral) {
|
||||
final hashCode = hashCodeArgs;
|
||||
final uuid = uuidArgs.toUUID();
|
||||
return MyGattDescriptor2(
|
||||
peripheral: peripheral,
|
||||
hashCode: hashCode,
|
||||
uuid: uuid,
|
||||
extension MyGATTDescriptorArgsX on MyGATTDescriptorArgs {
|
||||
MyGATTDescriptor toDescriptor() {
|
||||
return MyGATTDescriptor(
|
||||
hashCodeArgs: hashCodeArgs,
|
||||
uuid: UUID.fromString(uuidArgs),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension MyGattCharacteristicArgsX on MyGattCharacteristicArgs {
|
||||
MyGattCharacteristic2 toCharacteristic2(MyPeripheral peripheral) {
|
||||
final hashCode = hashCodeArgs;
|
||||
final uuid = uuidArgs.toUUID();
|
||||
final properties = propertyNumbersArgs.cast<int>().map(
|
||||
(args) {
|
||||
final propertyArgs = MyGattCharacteristicPropertyArgs.values[args];
|
||||
extension MyGATTCharacteristicArgsX on MyGATTCharacteristicArgs {
|
||||
MyGATTCharacteristic toCharacteristic() {
|
||||
return MyGATTCharacteristic(
|
||||
hashCodeArgs: hashCodeArgs,
|
||||
uuid: UUID.fromString(uuidArgs),
|
||||
properties: propertyNumbersArgs.cast<int>().map((args) {
|
||||
final propertyArgs = MyGATTCharacteristicPropertyArgs.values[args];
|
||||
return propertyArgs.toProperty();
|
||||
},
|
||||
).toList();
|
||||
final descriptors = descriptorsArgs
|
||||
.cast<MyGattDescriptorArgs>()
|
||||
.map((args) => args.toDescriptor2(peripheral))
|
||||
.toList();
|
||||
return MyGattCharacteristic2(
|
||||
peripheral: peripheral,
|
||||
hashCode: hashCode,
|
||||
uuid: uuid,
|
||||
properties: properties,
|
||||
descriptors: descriptors,
|
||||
}).toList(),
|
||||
descriptors: descriptorsArgs
|
||||
.cast<MyGATTDescriptorArgs>()
|
||||
.map((args) => args.toDescriptor())
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension MyGattServiceArgsX on MyGattServiceArgs {
|
||||
MyGattService2 toService2(MyPeripheral peripheral) {
|
||||
final hashCode = hashCodeArgs;
|
||||
final uuid = uuidArgs.toUUID();
|
||||
final characteristics = characteristicsArgs
|
||||
.cast<MyGattCharacteristicArgs>()
|
||||
.map((args) => args.toCharacteristic2(peripheral))
|
||||
.toList();
|
||||
return MyGattService2(
|
||||
peripheral: peripheral,
|
||||
hashCode: hashCode,
|
||||
uuid: uuid,
|
||||
characteristics: characteristics,
|
||||
extension MyGATTServiceArgsX on MyGATTServiceArgs {
|
||||
MyGATTService toService() {
|
||||
return MyGATTService(
|
||||
hashCodeArgs: hashCodeArgs,
|
||||
uuid: UUID.fromString(uuidArgs),
|
||||
isPrimary: isPrimaryArgs,
|
||||
includedServices: includedServicesArgs
|
||||
.cast<MyGATTServiceArgs>()
|
||||
.map((args) => args.toService())
|
||||
.toList(),
|
||||
characteristics: characteristicsArgs
|
||||
.cast<MyGATTCharacteristicArgs>()
|
||||
.map((args) => args.toCharacteristic())
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension MyUuidArgsX on String {
|
||||
UUID toUUID() {
|
||||
return UUID.fromString(this);
|
||||
extension MyCentralArgsX on MyCentralArgs {
|
||||
Central toCentral() {
|
||||
return Central(
|
||||
uuid: UUID.fromString(uuidArgs),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// ToArgs
|
||||
extension GattCharacteristicPropertyX on GattCharacteristicProperty {
|
||||
MyGattCharacteristicPropertyArgs toArgs() {
|
||||
return MyGattCharacteristicPropertyArgs.values[index];
|
||||
extension UUIDX on UUID {
|
||||
String toArgs() {
|
||||
return toString();
|
||||
}
|
||||
}
|
||||
|
||||
extension GattCharacteristicWriteTypeX on GattCharacteristicWriteType {
|
||||
MyGattCharacteristicWriteTypeArgs toArgs() {
|
||||
return MyGattCharacteristicWriteTypeArgs.values[index];
|
||||
extension GATTCharacteristicWriteTypeX on GATTCharacteristicWriteType {
|
||||
MyGATTCharacteristicWriteTypeArgs toArgs() {
|
||||
return MyGATTCharacteristicWriteTypeArgs.values[index];
|
||||
}
|
||||
}
|
||||
|
||||
extension ManufacturerSpecificDataX on ManufacturerSpecificData {
|
||||
MyManufacturerSpecificDataArgs toArgs() {
|
||||
final idArgs = id;
|
||||
final dataArgs = data;
|
||||
return MyManufacturerSpecificDataArgs(
|
||||
idArgs: idArgs,
|
||||
dataArgs: dataArgs,
|
||||
);
|
||||
extension GATTCharacteristicPropertyX on GATTCharacteristicProperty {
|
||||
MyGATTCharacteristicPropertyArgs toArgs() {
|
||||
return MyGATTCharacteristicPropertyArgs.values[index];
|
||||
}
|
||||
}
|
||||
|
||||
extension GATTCharacteristicPermissionX on GATTCharacteristicPermission {
|
||||
MyGATTCharacteristicPermissionArgs toArgs() {
|
||||
return MyGATTCharacteristicPermissionArgs.values[index];
|
||||
}
|
||||
}
|
||||
|
||||
extension GATTErrorX on GATTError {
|
||||
MyATTErrorArgs toArgs() {
|
||||
switch (this) {
|
||||
case GATTError.invalidHandle:
|
||||
return MyATTErrorArgs.invalidHandle;
|
||||
case GATTError.readNotPermitted:
|
||||
return MyATTErrorArgs.readNotPermitted;
|
||||
case GATTError.writeNotPermitted:
|
||||
return MyATTErrorArgs.writeNotPermitted;
|
||||
case GATTError.invalidPDU:
|
||||
return MyATTErrorArgs.invalidPDU;
|
||||
case GATTError.insufficientAuthentication:
|
||||
return MyATTErrorArgs.insufficientAuthentication;
|
||||
case GATTError.requestNotSupported:
|
||||
return MyATTErrorArgs.requestNotSupported;
|
||||
case GATTError.invalidOffset:
|
||||
return MyATTErrorArgs.invalidOffset;
|
||||
case GATTError.insufficientAuthorization:
|
||||
return MyATTErrorArgs.insufficientAuthorization;
|
||||
case GATTError.prepareQueueFull:
|
||||
return MyATTErrorArgs.prepareQueueFull;
|
||||
case GATTError.attributeNotFound:
|
||||
return MyATTErrorArgs.attributeNotFound;
|
||||
case GATTError.attributeNotLong:
|
||||
return MyATTErrorArgs.attributeNotLong;
|
||||
case GATTError.insufficientEncryptionKeySize:
|
||||
return MyATTErrorArgs.insufficientEncryptionKeySize;
|
||||
case GATTError.invalidAttributeValueLength:
|
||||
return MyATTErrorArgs.invalidAttributeValueLength;
|
||||
case GATTError.unlikelyError:
|
||||
return MyATTErrorArgs.unlikelyError;
|
||||
case GATTError.insufficientEncryption:
|
||||
return MyATTErrorArgs.insufficientEncryption;
|
||||
case GATTError.unsupportedGroupType:
|
||||
return MyATTErrorArgs.unsupportedGroupType;
|
||||
case GATTError.insufficientResources:
|
||||
return MyATTErrorArgs.insufficientResources;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
extension AdvertisementX on Advertisement {
|
||||
MyAdvertisementArgs toArgs() {
|
||||
final nameArgs = name;
|
||||
final serviceUUIDsArgs = serviceUUIDs.map((uuid) => uuid.toArgs()).toList();
|
||||
final serviceDataArgs = serviceData.map((uuid, data) {
|
||||
final uuidArgs = uuid.toArgs();
|
||||
final dataArgs = data;
|
||||
return MapEntry(uuidArgs, dataArgs);
|
||||
});
|
||||
final manufacturerSpecificDataArgs = manufacturerSpecificData?.toArgs();
|
||||
// CoreBluetooth only support `CBAdvertisementDataLocalNameKey` and `CBAdvertisementDataServiceUUIDsKey`
|
||||
// see https://developer.apple.com/documentation/corebluetooth/cbperipheralmanager/1393252-startadvertising
|
||||
if (serviceData.isNotEmpty || manufacturerSpecificData.isNotEmpty) {
|
||||
throw UnsupportedError(
|
||||
'serviceData and manufacturerSpecificData is not supported on Darwin.');
|
||||
}
|
||||
return MyAdvertisementArgs(
|
||||
nameArgs: nameArgs,
|
||||
serviceUUIDsArgs: serviceUUIDsArgs,
|
||||
serviceDataArgs: serviceDataArgs,
|
||||
manufacturerSpecificDataArgs: manufacturerSpecificDataArgs,
|
||||
nameArgs: name,
|
||||
serviceUUIDsArgs: serviceUUIDs.map((uuid) => uuid.toArgs()).toList(),
|
||||
serviceDataArgs: {},
|
||||
manufacturerSpecificDataArgs: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension MyGattDescriptorX on MyGattDescriptor {
|
||||
MyGattDescriptorArgs toArgs() {
|
||||
final hashCodeArgs = hashCode;
|
||||
final uuidArgs = uuid.toArgs();
|
||||
final valueArgs = value;
|
||||
return MyGattDescriptorArgs(
|
||||
hashCodeArgs: hashCodeArgs,
|
||||
uuidArgs: uuidArgs,
|
||||
valueArgs: valueArgs,
|
||||
extension MutableGATTDescriptorX on MutableGATTDescriptor {
|
||||
MyMutableGATTDescriptorArgs toArgs() {
|
||||
return MyMutableGATTDescriptorArgs(
|
||||
hashCodeArgs: hashCode,
|
||||
uuidArgs: uuid.toArgs(),
|
||||
valueArgs: this is ImmutableGATTDescriptor
|
||||
? (this as ImmutableGATTDescriptor).value
|
||||
: null,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension MyGattCharacteristicX on MyGattCharacteristic {
|
||||
MyGattCharacteristicArgs toArgs(List<MyGattDescriptorArgs> descriptorsArgs) {
|
||||
final hashCodeArgs = hashCode;
|
||||
final uuidArgs = uuid.toArgs();
|
||||
final propertyNumbersArgs = properties.map((property) {
|
||||
final propertyArgs = property.toArgs();
|
||||
return propertyArgs.index;
|
||||
}).toList();
|
||||
return MyGattCharacteristicArgs(
|
||||
hashCodeArgs: hashCodeArgs,
|
||||
uuidArgs: uuidArgs,
|
||||
propertyNumbersArgs: propertyNumbersArgs,
|
||||
descriptorsArgs: descriptorsArgs,
|
||||
extension MutableGATTCharacteristicX on MutableGATTCharacteristic {
|
||||
MyMutableGATTCharacteristicArgs toArgs() {
|
||||
return MyMutableGATTCharacteristicArgs(
|
||||
hashCodeArgs: hashCode,
|
||||
uuidArgs: uuid.toArgs(),
|
||||
propertyNumbersArgs: properties.map((property) {
|
||||
final propertyArgs = property.toArgs();
|
||||
return propertyArgs.index;
|
||||
}).toList(),
|
||||
permissionNumbersArgs: permissions.map((permission) {
|
||||
final permissionArgs = permission.toArgs();
|
||||
return permissionArgs.index;
|
||||
}).toList(),
|
||||
valueArgs: this is ImmutableGATTCharacteristic
|
||||
? (this as ImmutableGATTCharacteristic).value
|
||||
: null,
|
||||
descriptorsArgs: descriptors
|
||||
.cast<MutableGATTDescriptor>()
|
||||
.map((descriptor) => descriptor.toArgs())
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension MyGattServiceX on MyGattService {
|
||||
MyGattServiceArgs toArgs(List<MyGattCharacteristicArgs> characteristicsArgs) {
|
||||
final hashCodeArgs = hashCode;
|
||||
final uuidArgs = uuid.toArgs();
|
||||
return MyGattServiceArgs(
|
||||
hashCodeArgs: hashCodeArgs,
|
||||
uuidArgs: uuidArgs,
|
||||
characteristicsArgs: characteristicsArgs,
|
||||
extension GATTServiceX on GATTService {
|
||||
MyMutableGATTServiceArgs toArgs() {
|
||||
return MyMutableGATTServiceArgs(
|
||||
hashCodeArgs: hashCode,
|
||||
uuidArgs: uuid.toArgs(),
|
||||
isPrimaryArgs: isPrimary,
|
||||
includedServicesArgs:
|
||||
includedServices.map((service) => service.toArgs()).toList(),
|
||||
characteristicsArgs: characteristics
|
||||
.cast<MutableGATTCharacteristic>()
|
||||
.map((characteristic) => characteristic.toArgs())
|
||||
.toList(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
extension UuidX on UUID {
|
||||
String toArgs() {
|
||||
return toString().toLowerCase();
|
||||
}
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1,66 +1,81 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'my_api.dart';
|
||||
import 'my_gatt_characteristic2.dart';
|
||||
import 'my_gatt_descriptor2.dart';
|
||||
import 'my_api.g.dart';
|
||||
import 'my_gatt.dart';
|
||||
|
||||
class MyCentralManager extends CentralManager
|
||||
implements MyCentralManagerFlutterApi {
|
||||
final MyCentralManagerHostApi _api;
|
||||
final class MyCentralManager extends PlatformCentralManager
|
||||
implements MyCentralManagerFlutterAPI {
|
||||
final MyCentralManagerHostAPI _api;
|
||||
final StreamController<BluetoothLowEnergyStateChangedEventArgs>
|
||||
_stateChangedController;
|
||||
final StreamController<DiscoveredEventArgs> _discoveredController;
|
||||
final StreamController<ConnectionStateChangedEventArgs>
|
||||
final StreamController<PeripheralConnectionStateChangedEventArgs>
|
||||
_connectionStateChangedController;
|
||||
final StreamController<GattCharacteristicNotifiedEventArgs>
|
||||
final StreamController<GATTCharacteristicNotifiedEventArgs>
|
||||
_characteristicNotifiedController;
|
||||
final Map<String, MyPeripheral> _peripherals;
|
||||
final Map<String, Map<int, MyGattCharacteristic2>> _characteristics;
|
||||
|
||||
BluetoothLowEnergyState _state;
|
||||
|
||||
MyCentralManager()
|
||||
: _api = MyCentralManagerHostApi(),
|
||||
: _api = MyCentralManagerHostAPI(),
|
||||
_stateChangedController = StreamController.broadcast(),
|
||||
_discoveredController = StreamController.broadcast(),
|
||||
_connectionStateChangedController = StreamController.broadcast(),
|
||||
_characteristicNotifiedController = StreamController.broadcast(),
|
||||
_peripherals = {},
|
||||
_characteristics = {},
|
||||
_state = BluetoothLowEnergyState.unknown;
|
||||
|
||||
@override
|
||||
BluetoothLowEnergyState get state => _state;
|
||||
@override
|
||||
Stream<BluetoothLowEnergyStateChangedEventArgs> get stateChanged =>
|
||||
_stateChangedController.stream;
|
||||
@override
|
||||
Stream<DiscoveredEventArgs> get discovered => _discoveredController.stream;
|
||||
@override
|
||||
Stream<ConnectionStateChangedEventArgs> get connectionStateChanged =>
|
||||
_connectionStateChangedController.stream;
|
||||
Stream<PeripheralConnectionStateChangedEventArgs>
|
||||
get connectionStateChanged => _connectionStateChangedController.stream;
|
||||
@override
|
||||
Stream<GattCharacteristicNotifiedEventArgs> get characteristicNotified =>
|
||||
Stream<PeripheralMTUChangedEventArgs> get mtuChanged =>
|
||||
throw UnsupportedError('mtuChanged is not supported on Darwin.');
|
||||
@override
|
||||
Stream<GATTCharacteristicNotifiedEventArgs> get characteristicNotified =>
|
||||
_characteristicNotifiedController.stream;
|
||||
|
||||
@override
|
||||
Future<void> setUp() async {
|
||||
logger.info('setUp');
|
||||
await _api.setUp();
|
||||
MyCentralManagerFlutterApi.setup(this);
|
||||
void initialize() {
|
||||
MyCentralManagerFlutterAPI.setUp(this);
|
||||
_initialize();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<BluetoothLowEnergyState> getState() {
|
||||
logger.info('getState');
|
||||
return Future.value(_state);
|
||||
Future<bool> authorize() {
|
||||
throw UnsupportedError('authorize is not supported on Darwin.');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> startDiscovery() async {
|
||||
logger.info('startDiscovery');
|
||||
await _api.startDiscovery();
|
||||
Future<void> showAppSettings() async {
|
||||
if (Platform.isIOS) {
|
||||
logger.info('showAppSettings');
|
||||
await _api.showAppSettings();
|
||||
} else {
|
||||
throw UnsupportedError(
|
||||
'showAppSettings is not supported on ${Platform.operatingSystem}.');
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> startDiscovery({
|
||||
List<UUID>? serviceUUIDs,
|
||||
}) async {
|
||||
final serviceUUIDsArgs =
|
||||
serviceUUIDs?.map((uuid) => uuid.toArgs()).toList() ?? [];
|
||||
logger.info('startDiscovery: $serviceUUIDsArgs');
|
||||
await _api.startDiscovery(serviceUUIDsArgs);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -69,11 +84,19 @@ class MyCentralManager extends CentralManager
|
||||
await _api.stopDiscovery();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<Peripheral>> retrieveConnectedPeripherals() async {
|
||||
logger.info('retrieveConnectedPeripherals');
|
||||
final peripheralsArgs = await _api.retrieveConnectedPeripherals();
|
||||
final peripherals = peripheralsArgs
|
||||
.cast<MyPeripheralArgs>()
|
||||
.map((args) => args.toPeripheral())
|
||||
.toList();
|
||||
return peripherals;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> connect(Peripheral peripheral) async {
|
||||
if (peripheral is! MyPeripheral) {
|
||||
throw TypeError();
|
||||
}
|
||||
final uuidArgs = peripheral.uuid.toArgs();
|
||||
logger.info('connect: $uuidArgs');
|
||||
await _api.connect(uuidArgs);
|
||||
@ -81,19 +104,36 @@ class MyCentralManager extends CentralManager
|
||||
|
||||
@override
|
||||
Future<void> disconnect(Peripheral peripheral) async {
|
||||
if (peripheral is! MyPeripheral) {
|
||||
throw TypeError();
|
||||
}
|
||||
final uuidArgs = peripheral.uuid.toArgs();
|
||||
logger.info('disconnect: $uuidArgs');
|
||||
await _api.disconnect(uuidArgs);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> requestMTU(
|
||||
Peripheral peripheral, {
|
||||
required int mtu,
|
||||
}) {
|
||||
throw UnsupportedError('requestMTU is not supported on Darwin.');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> getMaximumWriteLength(
|
||||
Peripheral peripheral, {
|
||||
required GATTCharacteristicWriteType type,
|
||||
}) async {
|
||||
final uuidArgs = peripheral.uuid.toArgs();
|
||||
final typeArgs = type.toArgs();
|
||||
logger.info('getMaximumWriteLength: $uuidArgs - $typeArgs');
|
||||
final maximumWriteLength = await _api.getMaximumWriteLength(
|
||||
uuidArgs,
|
||||
typeArgs,
|
||||
);
|
||||
return maximumWriteLength;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<int> readRSSI(Peripheral peripheral) async {
|
||||
if (peripheral is! MyPeripheral) {
|
||||
throw TypeError();
|
||||
}
|
||||
final uuidArgs = peripheral.uuid.toArgs();
|
||||
logger.info('readRSSI: $uuidArgs');
|
||||
final rssi = await _api.readRSSI(uuidArgs);
|
||||
@ -101,53 +141,22 @@ class MyCentralManager extends CentralManager
|
||||
}
|
||||
|
||||
@override
|
||||
Future<List<GattService>> discoverGATT(Peripheral peripheral) async {
|
||||
if (peripheral is! MyPeripheral) {
|
||||
throw TypeError();
|
||||
}
|
||||
Future<List<GATTService>> discoverGATT(Peripheral peripheral) async {
|
||||
// 发现 GATT 服务
|
||||
final uuidArgs = peripheral.uuid.toArgs();
|
||||
logger.info('discoverServices: $uuidArgs');
|
||||
final servicesArgs = await _api
|
||||
.discoverServices(uuidArgs)
|
||||
.then((args) => args.cast<MyGattServiceArgs>());
|
||||
for (var serviceArgs in servicesArgs) {
|
||||
// 发现 GATT 特征值
|
||||
final hashCodeArgs = serviceArgs.hashCodeArgs;
|
||||
logger.info('discoverCharacteristics: $uuidArgs.$hashCodeArgs');
|
||||
final characteristicsArgs = await _api
|
||||
.discoverCharacteristics(uuidArgs, hashCodeArgs)
|
||||
.then((args) => args.cast<MyGattCharacteristicArgs>());
|
||||
for (var characteristicArgs in characteristicsArgs) {
|
||||
// 发现 GATT 描述值
|
||||
final hashCodeArgs = characteristicArgs.hashCodeArgs;
|
||||
logger.info('discoverDescriptors: $uuidArgs.$hashCodeArgs');
|
||||
final descriptorsArgs = await _api
|
||||
.discoverDescriptors(uuidArgs, hashCodeArgs)
|
||||
.then((args) => args.cast<MyGattDescriptorArgs>());
|
||||
characteristicArgs.descriptorsArgs = descriptorsArgs;
|
||||
}
|
||||
serviceArgs.characteristicsArgs = characteristicsArgs;
|
||||
}
|
||||
final services =
|
||||
servicesArgs.map((args) => args.toService2(peripheral)).toList();
|
||||
final characteristics =
|
||||
services.expand((service) => service.characteristics).toList();
|
||||
_characteristics[uuidArgs] = {
|
||||
for (var characteristic in characteristics)
|
||||
characteristic.hashCode: characteristic
|
||||
};
|
||||
final servicesArgs = await _discoverServices(uuidArgs);
|
||||
final services = servicesArgs.map((args) => args.toService()).toList();
|
||||
return services;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Uint8List> readCharacteristic(
|
||||
GattCharacteristic characteristic,
|
||||
Peripheral peripheral,
|
||||
GATTCharacteristic characteristic,
|
||||
) async {
|
||||
if (characteristic is! MyGattCharacteristic2) {
|
||||
if (characteristic is! MyGATTCharacteristic) {
|
||||
throw TypeError();
|
||||
}
|
||||
final peripheral = characteristic.peripheral;
|
||||
final uuidArgs = peripheral.uuid.toArgs();
|
||||
final hashCodeArgs = characteristic.hashCode;
|
||||
logger.info('readCharacteristic: $uuidArgs.$hashCodeArgs');
|
||||
@ -157,97 +166,73 @@ class MyCentralManager extends CentralManager
|
||||
|
||||
@override
|
||||
Future<void> writeCharacteristic(
|
||||
GattCharacteristic characteristic, {
|
||||
Peripheral peripheral,
|
||||
GATTCharacteristic characteristic, {
|
||||
required Uint8List value,
|
||||
required GattCharacteristicWriteType type,
|
||||
required GATTCharacteristicWriteType type,
|
||||
}) async {
|
||||
if (characteristic is! MyGattCharacteristic2) {
|
||||
if (characteristic is! MyGATTCharacteristic) {
|
||||
throw TypeError();
|
||||
}
|
||||
final peripheral = characteristic.peripheral;
|
||||
final uuidArgs = peripheral.uuid.toArgs();
|
||||
final hashCodeArgs = characteristic.hashCode;
|
||||
final trimmedValueArgs = value.trimGATT();
|
||||
final valueArgs = value;
|
||||
final typeArgs = type.toArgs();
|
||||
final typeNumberArgs = typeArgs.index;
|
||||
final fragmentSize = await _api.getMaximumWriteValueLength(
|
||||
uuidArgs,
|
||||
typeNumberArgs,
|
||||
);
|
||||
var start = 0;
|
||||
while (start < trimmedValueArgs.length) {
|
||||
final end = start + fragmentSize;
|
||||
final fragmentedValueArgs = end < trimmedValueArgs.length
|
||||
? trimmedValueArgs.sublist(start, end)
|
||||
: trimmedValueArgs.sublist(start);
|
||||
logger.info(
|
||||
'writeCharacteristic: $uuidArgs.$hashCodeArgs - $fragmentedValueArgs, $typeArgs');
|
||||
await _api.writeCharacteristic(
|
||||
uuidArgs,
|
||||
hashCodeArgs,
|
||||
fragmentedValueArgs,
|
||||
typeNumberArgs,
|
||||
);
|
||||
start = end;
|
||||
}
|
||||
logger.info(
|
||||
'writeCharacteristic: $uuidArgs.$hashCodeArgs - $valueArgs, $typeArgs');
|
||||
await _api.writeCharacteristic(uuidArgs, hashCodeArgs, valueArgs, typeArgs);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> setCharacteristicNotifyState(
|
||||
GattCharacteristic characteristic, {
|
||||
Peripheral peripheral,
|
||||
GATTCharacteristic characteristic, {
|
||||
required bool state,
|
||||
}) async {
|
||||
if (characteristic is! MyGattCharacteristic2) {
|
||||
if (characteristic is! MyGATTCharacteristic) {
|
||||
throw TypeError();
|
||||
}
|
||||
final peripheral = characteristic.peripheral;
|
||||
final uuidArgs = peripheral.uuid.toArgs();
|
||||
final hashCodeArgs = characteristic.hashCode;
|
||||
final stateArgs = state;
|
||||
logger.info(
|
||||
'setCharacteristicNotifyState: $uuidArgs.$hashCodeArgs - $stateArgs');
|
||||
await _api.setCharacteristicNotifyState(
|
||||
uuidArgs,
|
||||
hashCodeArgs,
|
||||
stateArgs,
|
||||
);
|
||||
await _api.setCharacteristicNotifyState(uuidArgs, hashCodeArgs, stateArgs);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Uint8List> readDescriptor(GattDescriptor descriptor) async {
|
||||
if (descriptor is! MyGattDescriptor2) {
|
||||
Future<Uint8List> readDescriptor(
|
||||
Peripheral peripheral,
|
||||
GATTDescriptor descriptor,
|
||||
) async {
|
||||
if (descriptor is! MyGATTDescriptor) {
|
||||
throw TypeError();
|
||||
}
|
||||
final peripheral = descriptor.peripheral;
|
||||
final uuidArgs = peripheral.uuid.toArgs();
|
||||
final hashCodeArgs = descriptor.hashCode;
|
||||
logger.info('readDescriptor: $uuidArgs.$hashCodeArgs');
|
||||
final value = await _api.readDescriptor(
|
||||
uuidArgs,
|
||||
hashCodeArgs,
|
||||
);
|
||||
final value = await _api.readDescriptor(uuidArgs, hashCodeArgs);
|
||||
return value;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> writeDescriptor(
|
||||
GattDescriptor descriptor, {
|
||||
Peripheral peripheral,
|
||||
GATTDescriptor descriptor, {
|
||||
required Uint8List value,
|
||||
}) async {
|
||||
if (descriptor is! MyGattDescriptor2) {
|
||||
if (descriptor is! MyGATTDescriptor) {
|
||||
throw TypeError();
|
||||
}
|
||||
final peripheral = descriptor.peripheral;
|
||||
final uuidArgs = peripheral.uuid.toArgs();
|
||||
final hashCodeArgs = descriptor.hashCode;
|
||||
final trimmedValueArgs = value.trimGATT();
|
||||
logger.info('writeDescriptor: $uuidArgs.$hashCodeArgs - $trimmedValueArgs');
|
||||
await _api.writeDescriptor(uuidArgs, hashCodeArgs, trimmedValueArgs);
|
||||
final valueArgs = value;
|
||||
logger.info('writeDescriptor: $uuidArgs.$hashCodeArgs - $valueArgs');
|
||||
await _api.writeDescriptor(uuidArgs, hashCodeArgs, valueArgs);
|
||||
}
|
||||
|
||||
@override
|
||||
void onStateChanged(int stateNumberArgs) {
|
||||
final stateArgs = MyBluetoothLowEnergyStateArgs.values[stateNumberArgs];
|
||||
void onStateChanged(MyBluetoothLowEnergyStateArgs stateArgs) {
|
||||
logger.info('onStateChanged: $stateArgs');
|
||||
final state = stateArgs.toState();
|
||||
if (_state == state) {
|
||||
@ -266,15 +251,11 @@ class MyCentralManager extends CentralManager
|
||||
) {
|
||||
final uuidArgs = peripheralArgs.uuidArgs;
|
||||
logger.info('onDiscovered: $uuidArgs - $rssiArgs, $advertisementArgs');
|
||||
final peripheral = _peripherals.putIfAbsent(
|
||||
peripheralArgs.uuidArgs,
|
||||
() => peripheralArgs.toPeripheral(),
|
||||
);
|
||||
final rssi = rssiArgs;
|
||||
final peripheral = peripheralArgs.toPeripheral();
|
||||
final advertisement = advertisementArgs.toAdvertisement();
|
||||
final eventArgs = DiscoveredEventArgs(
|
||||
peripheral,
|
||||
rssi,
|
||||
rssiArgs,
|
||||
advertisement,
|
||||
);
|
||||
_discoveredController.add(eventArgs);
|
||||
@ -282,50 +263,135 @@ class MyCentralManager extends CentralManager
|
||||
|
||||
@override
|
||||
void onConnectionStateChanged(
|
||||
String uuidArgs,
|
||||
bool stateArgs,
|
||||
MyPeripheralArgs peripheralArgs,
|
||||
MyConnectionStateArgs stateArgs,
|
||||
) {
|
||||
final uuidArgs = peripheralArgs.uuidArgs;
|
||||
logger.info('onConnectionStateChanged: $uuidArgs - $stateArgs');
|
||||
final peripheral = _peripherals[uuidArgs];
|
||||
if (peripheral == null) {
|
||||
return;
|
||||
}
|
||||
final state = stateArgs;
|
||||
final eventArgs = ConnectionStateChangedEventArgs(peripheral, state);
|
||||
final peripheral = peripheralArgs.toPeripheral();
|
||||
final state = stateArgs.toState();
|
||||
final eventArgs = PeripheralConnectionStateChangedEventArgs(
|
||||
peripheral,
|
||||
state,
|
||||
);
|
||||
_connectionStateChangedController.add(eventArgs);
|
||||
if (!state) {
|
||||
_characteristics.remove(uuidArgs);
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onCharacteristicNotified(
|
||||
String uuidArgs,
|
||||
int hashCodeArgs,
|
||||
MyPeripheralArgs peripheralArgs,
|
||||
MyGATTCharacteristicArgs characteristicArgs,
|
||||
Uint8List valueArgs,
|
||||
) {
|
||||
final uuidArgs = peripheralArgs.uuidArgs;
|
||||
final hashCodeArgs = characteristicArgs.hashCodeArgs;
|
||||
logger
|
||||
.info('onCharacteristicNotified: $uuidArgs.$hashCodeArgs - $valueArgs');
|
||||
final characteristic = _retrieveCharacteristic(uuidArgs, hashCodeArgs);
|
||||
if (characteristic == null) {
|
||||
return;
|
||||
}
|
||||
final value = valueArgs;
|
||||
final eventArgs = GattCharacteristicNotifiedEventArgs(
|
||||
final peripheral = peripheralArgs.toPeripheral();
|
||||
final characteristic = characteristicArgs.toCharacteristic();
|
||||
final eventArgs = GATTCharacteristicNotifiedEventArgs(
|
||||
peripheral,
|
||||
characteristic,
|
||||
value,
|
||||
valueArgs,
|
||||
);
|
||||
_characteristicNotifiedController.add(eventArgs);
|
||||
}
|
||||
|
||||
MyGattCharacteristic2? _retrieveCharacteristic(
|
||||
Future<void> _initialize() async {
|
||||
// Here we use `Future()` to make it possible to change the `logLevel` before `initialize()`.
|
||||
await Future(() async {
|
||||
try {
|
||||
logger.info('initialize');
|
||||
await _api.initialize();
|
||||
_getState();
|
||||
} catch (e) {
|
||||
logger.severe('initialize failed.', e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _getState() async {
|
||||
try {
|
||||
logger.info('getState');
|
||||
final stateArgs = await _api.getState();
|
||||
onStateChanged(stateArgs);
|
||||
} catch (e) {
|
||||
logger.severe('getState failed.', e);
|
||||
}
|
||||
}
|
||||
|
||||
Future<List<MyGATTServiceArgs>> _discoverServices(String uuidArgs) async {
|
||||
logger.info('discoverServices: $uuidArgs');
|
||||
final servicesArgs = await _api
|
||||
.discoverServices(uuidArgs)
|
||||
.then((args) => args.cast<MyGATTServiceArgs>());
|
||||
for (var serviceArgs in servicesArgs) {
|
||||
final hashCodeArgs = serviceArgs.hashCodeArgs;
|
||||
final includedServicesArgs = await _discoverIncludedServices(
|
||||
uuidArgs,
|
||||
hashCodeArgs,
|
||||
);
|
||||
serviceArgs.includedServicesArgs = includedServicesArgs;
|
||||
final characteristicsArgs = await _discoverCharacteristics(
|
||||
uuidArgs,
|
||||
hashCodeArgs,
|
||||
);
|
||||
serviceArgs.characteristicsArgs = characteristicsArgs;
|
||||
}
|
||||
return servicesArgs;
|
||||
}
|
||||
|
||||
Future<List<MyGATTServiceArgs>> _discoverIncludedServices(
|
||||
String uuidArgs,
|
||||
int hashCodeArgs,
|
||||
) {
|
||||
final characteristics = _characteristics[uuidArgs];
|
||||
if (characteristics == null) {
|
||||
return null;
|
||||
) async {
|
||||
logger.info('discoverIncludedServices: $uuidArgs.$hashCodeArgs');
|
||||
final servicesArgs = await _api
|
||||
.discoverIncludedServices(uuidArgs, hashCodeArgs)
|
||||
.then((args) => args.cast<MyGATTServiceArgs>());
|
||||
for (var serviceArgs in servicesArgs) {
|
||||
final hashCodeArgs = serviceArgs.hashCodeArgs;
|
||||
final includedServicesArgs = await _discoverIncludedServices(
|
||||
uuidArgs,
|
||||
hashCodeArgs,
|
||||
);
|
||||
serviceArgs.includedServicesArgs = includedServicesArgs;
|
||||
final characteristicsArgs = await _discoverCharacteristics(
|
||||
uuidArgs,
|
||||
hashCodeArgs,
|
||||
);
|
||||
serviceArgs.characteristicsArgs = characteristicsArgs;
|
||||
}
|
||||
return characteristics[hashCodeArgs];
|
||||
return servicesArgs;
|
||||
}
|
||||
|
||||
Future<List<MyGATTCharacteristicArgs>> _discoverCharacteristics(
|
||||
String uuidArgs,
|
||||
int hashCodeArgs,
|
||||
) async {
|
||||
logger.info('discoverCharacteristics: $uuidArgs.$hashCodeArgs');
|
||||
final characteristicsArgs = await _api
|
||||
.discoverCharacteristics(uuidArgs, hashCodeArgs)
|
||||
.then((args) => args.cast<MyGATTCharacteristicArgs>());
|
||||
for (var characteristicArgs in characteristicsArgs) {
|
||||
final hashCodeArgs = characteristicArgs.hashCodeArgs;
|
||||
final descriptorsArgs = await _discoverDescriptors(
|
||||
uuidArgs,
|
||||
hashCodeArgs,
|
||||
);
|
||||
characteristicArgs.descriptorsArgs = descriptorsArgs;
|
||||
}
|
||||
return characteristicsArgs;
|
||||
}
|
||||
|
||||
Future<List<MyGATTDescriptorArgs>> _discoverDescriptors(
|
||||
String uuidArgs,
|
||||
int hashCodeArgs,
|
||||
) async {
|
||||
logger.info('discoverDescriptors: $uuidArgs.$hashCodeArgs');
|
||||
final descriptorsArgs = await _api
|
||||
.discoverDescriptors(uuidArgs, hashCodeArgs)
|
||||
.then((args) => args.cast<MyGATTDescriptorArgs>());
|
||||
return descriptorsArgs;
|
||||
}
|
||||
}
|
||||
|
93
bluetooth_low_energy_darwin/lib/src/my_gatt.dart
Normal file
93
bluetooth_low_energy_darwin/lib/src/my_gatt.dart
Normal file
@ -0,0 +1,93 @@
|
||||
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
|
||||
|
||||
final class MyGATTDescriptor extends GATTDescriptor {
|
||||
final int hashCodeArgs;
|
||||
|
||||
MyGATTDescriptor({
|
||||
required this.hashCodeArgs,
|
||||
required super.uuid,
|
||||
});
|
||||
|
||||
@override
|
||||
int get hashCode => hashCodeArgs;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is MyGATTDescriptor && other.hashCodeArgs == hashCodeArgs;
|
||||
}
|
||||
}
|
||||
|
||||
final class MyGATTCharacteristic extends GATTCharacteristic {
|
||||
final int hashCodeArgs;
|
||||
|
||||
MyGATTCharacteristic({
|
||||
required this.hashCodeArgs,
|
||||
required super.uuid,
|
||||
required super.properties,
|
||||
required List<MyGATTDescriptor> descriptors,
|
||||
}) : super(
|
||||
descriptors: descriptors,
|
||||
);
|
||||
|
||||
@override
|
||||
List<MyGATTDescriptor> get descriptors =>
|
||||
super.descriptors.cast<MyGATTDescriptor>();
|
||||
|
||||
@override
|
||||
int get hashCode => hashCodeArgs;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is MyGATTCharacteristic && other.hashCodeArgs == hashCodeArgs;
|
||||
}
|
||||
}
|
||||
|
||||
final class MyGATTService extends GATTService {
|
||||
final int hashCodeArgs;
|
||||
|
||||
MyGATTService({
|
||||
required this.hashCodeArgs,
|
||||
required super.uuid,
|
||||
required super.isPrimary,
|
||||
required List<MyGATTService> includedServices,
|
||||
required List<MyGATTCharacteristic> characteristics,
|
||||
}) : super(
|
||||
includedServices: includedServices,
|
||||
characteristics: characteristics,
|
||||
);
|
||||
|
||||
@override
|
||||
List<MyGATTService> get includedServices =>
|
||||
super.includedServices.cast<MyGATTService>();
|
||||
|
||||
@override
|
||||
List<MyGATTCharacteristic> get characteristics =>
|
||||
super.characteristics.cast<MyGATTCharacteristic>();
|
||||
|
||||
@override
|
||||
int get hashCode => hashCodeArgs;
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is MyGATTService && other.hashCodeArgs == hashCodeArgs;
|
||||
}
|
||||
}
|
||||
|
||||
final class MyGATTReadRequest extends GATTReadRequest {
|
||||
final int hashCodeArgs;
|
||||
|
||||
MyGATTReadRequest({
|
||||
required this.hashCodeArgs,
|
||||
required super.offset,
|
||||
});
|
||||
}
|
||||
|
||||
final class MyGATTWriteRequest extends GATTWriteRequest {
|
||||
final int hashCodeArgs;
|
||||
|
||||
MyGATTWriteRequest({
|
||||
required this.hashCodeArgs,
|
||||
required super.offset,
|
||||
required super.value,
|
||||
});
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
|
||||
|
||||
import 'my_gatt_descriptor2.dart';
|
||||
|
||||
class MyGattCharacteristic2 extends MyGattCharacteristic {
|
||||
final MyPeripheral peripheral;
|
||||
@override
|
||||
final int hashCode;
|
||||
|
||||
MyGattCharacteristic2({
|
||||
required this.peripheral,
|
||||
required this.hashCode,
|
||||
required super.uuid,
|
||||
required super.properties,
|
||||
required List<MyGattDescriptor2> descriptors,
|
||||
}) : super(descriptors: descriptors);
|
||||
|
||||
@override
|
||||
List<MyGattDescriptor2> get descriptors =>
|
||||
super.descriptors.cast<MyGattDescriptor2>();
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is MyGattCharacteristic2 &&
|
||||
other.peripheral == peripheral &&
|
||||
other.hashCode == hashCode;
|
||||
}
|
||||
}
|
@ -1,20 +0,0 @@
|
||||
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
|
||||
|
||||
class MyGattDescriptor2 extends MyGattDescriptor {
|
||||
final MyPeripheral peripheral;
|
||||
@override
|
||||
final int hashCode;
|
||||
|
||||
MyGattDescriptor2({
|
||||
required this.peripheral,
|
||||
required this.hashCode,
|
||||
required super.uuid,
|
||||
});
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is MyGattDescriptor2 &&
|
||||
other.peripheral == peripheral &&
|
||||
other.hashCode == hashCode;
|
||||
}
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
|
||||
|
||||
import 'my_gatt_characteristic2.dart';
|
||||
|
||||
class MyGattService2 extends MyGattService {
|
||||
final MyPeripheral peripheral;
|
||||
@override
|
||||
final int hashCode;
|
||||
|
||||
MyGattService2({
|
||||
required this.peripheral,
|
||||
required this.hashCode,
|
||||
required super.uuid,
|
||||
required List<MyGattCharacteristic2> characteristics,
|
||||
}) : super(characteristics: characteristics);
|
||||
|
||||
@override
|
||||
List<MyGattCharacteristic2> get characteristics =>
|
||||
super.characteristics.cast<MyGattCharacteristic2>();
|
||||
|
||||
@override
|
||||
bool operator ==(Object other) {
|
||||
return other is MyGattService2 &&
|
||||
other.peripheral == peripheral &&
|
||||
other.hashCode == hashCode;
|
||||
}
|
||||
}
|
@ -1,100 +1,117 @@
|
||||
import 'dart:async';
|
||||
import 'dart:io';
|
||||
import 'dart:typed_data';
|
||||
|
||||
import 'package:bluetooth_low_energy_darwin/src/my_gatt.dart';
|
||||
import 'package:bluetooth_low_energy_platform_interface/bluetooth_low_energy_platform_interface.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
import 'my_api.dart';
|
||||
import 'my_api.g.dart';
|
||||
|
||||
class MyPeripheralManager extends PeripheralManager
|
||||
implements MyPeripheralManagerFlutterApi {
|
||||
final MyPeripheralManagerHostApi _api;
|
||||
final class MyPeripheralManager extends PlatformPeripheralManager
|
||||
implements MyPeripheralManagerFlutterAPI {
|
||||
final MyPeripheralManagerHostAPI _api;
|
||||
final StreamController<BluetoothLowEnergyStateChangedEventArgs>
|
||||
_stateChangedController;
|
||||
final StreamController<GattCharacteristicReadEventArgs>
|
||||
_characteristicReadController;
|
||||
final StreamController<GattCharacteristicWrittenEventArgs>
|
||||
_characteristicWrittenController;
|
||||
final StreamController<GattCharacteristicNotifyStateChangedEventArgs>
|
||||
final StreamController<GATTCharacteristicReadRequestedEventArgs>
|
||||
_characteristicReadRequestedController;
|
||||
final StreamController<GATTCharacteristicWriteRequestedEventArgs>
|
||||
_characteristicWriteRequestedController;
|
||||
final StreamController<GATTCharacteristicNotifyStateChangedEventArgs>
|
||||
_characteristicNotifyStateChangedController;
|
||||
final StreamController<EventArgs> _isReadyController;
|
||||
|
||||
final Map<int, Map<int, MyGattCharacteristic>> _characteristics;
|
||||
final Map<String, Map<int, bool>> _listeners;
|
||||
final Map<int, MutableGATTCharacteristic> _characteristics;
|
||||
|
||||
BluetoothLowEnergyState _state;
|
||||
|
||||
MyPeripheralManager()
|
||||
: _api = MyPeripheralManagerHostApi(),
|
||||
: _api = MyPeripheralManagerHostAPI(),
|
||||
_stateChangedController = StreamController.broadcast(),
|
||||
_characteristicReadController = StreamController.broadcast(),
|
||||
_characteristicWrittenController = StreamController.broadcast(),
|
||||
_characteristicReadRequestedController = StreamController.broadcast(),
|
||||
_characteristicWriteRequestedController = StreamController.broadcast(),
|
||||
_characteristicNotifyStateChangedController =
|
||||
StreamController.broadcast(),
|
||||
_isReadyController = StreamController.broadcast(),
|
||||
_characteristics = {},
|
||||
_listeners = {},
|
||||
_state = BluetoothLowEnergyState.unknown;
|
||||
|
||||
@override
|
||||
BluetoothLowEnergyState get state => _state;
|
||||
@override
|
||||
Stream<BluetoothLowEnergyStateChangedEventArgs> get stateChanged =>
|
||||
_stateChangedController.stream;
|
||||
@override
|
||||
Stream<GattCharacteristicReadEventArgs> get characteristicRead =>
|
||||
_characteristicReadController.stream;
|
||||
Stream<CentralConnectionStateChangedEventArgs> get connectionStateChanged =>
|
||||
throw UnsupportedError(
|
||||
'connectionStateChanged is not supported on Darwin.');
|
||||
@override
|
||||
Stream<GattCharacteristicWrittenEventArgs> get characteristicWritten =>
|
||||
_characteristicWrittenController.stream;
|
||||
Stream<CentralMTUChangedEventArgs> get mtuChanged =>
|
||||
throw UnsupportedError('mtuChanged is not supported on Darwin.');
|
||||
@override
|
||||
Stream<GattCharacteristicNotifyStateChangedEventArgs>
|
||||
Stream<GATTCharacteristicReadRequestedEventArgs>
|
||||
get characteristicReadRequested =>
|
||||
_characteristicReadRequestedController.stream;
|
||||
@override
|
||||
Stream<GATTCharacteristicWriteRequestedEventArgs>
|
||||
get characteristicWriteRequested =>
|
||||
_characteristicWriteRequestedController.stream;
|
||||
@override
|
||||
Stream<GATTCharacteristicNotifyStateChangedEventArgs>
|
||||
get characteristicNotifyStateChanged =>
|
||||
_characteristicNotifyStateChangedController.stream;
|
||||
@override
|
||||
Stream<GATTDescriptorReadRequestedEventArgs> get descriptorReadRequested =>
|
||||
throw UnsupportedError(
|
||||
'descriptorReadRequested is not supported on Darwin.');
|
||||
@override
|
||||
Stream<GATTDescriptorWriteRequestedEventArgs> get descriptorWriteRequested =>
|
||||
throw UnsupportedError(
|
||||
'descriptorWriteRequested is not supported on Darwin.');
|
||||
Stream<EventArgs> get _isReady => _isReadyController.stream;
|
||||
|
||||
@override
|
||||
Future<void> setUp() async {
|
||||
logger.info('setUp');
|
||||
await _api.setUp();
|
||||
MyPeripheralManagerFlutterApi.setup(this);
|
||||
void initialize() {
|
||||
MyPeripheralManagerFlutterAPI.setUp(this);
|
||||
_initialize();
|
||||
}
|
||||
|
||||
@override
|
||||
Future<BluetoothLowEnergyState> getState() {
|
||||
logger.info('getState');
|
||||
return Future.value(_state);
|
||||
Future<bool> authorize() {
|
||||
throw UnsupportedError('authorize is not supported on Darwin.');
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> addService(GattService service) async {
|
||||
if (service is! MyGattService) {
|
||||
throw TypeError();
|
||||
Future<void> showAppSettings() async {
|
||||
if (Platform.isIOS) {
|
||||
logger.info('showAppSettings');
|
||||
await _api.showAppSettings();
|
||||
} else {
|
||||
throw UnsupportedError(
|
||||
'showAppSettings is not supported on ${Platform.operatingSystem}.');
|
||||
}
|
||||
final characteristics = <int, MyGattCharacteristic>{};
|
||||
final characteristicsArgs = <MyGattCharacteristicArgs>[];
|
||||
for (var characteristic in service.characteristics) {
|
||||
final descriptorsArgs = <MyGattDescriptorArgs>[];
|
||||
for (var descriptor in characteristic.descriptors) {
|
||||
final descriptorArgs = descriptor.toArgs();
|
||||
descriptorsArgs.add(descriptorArgs);
|
||||
}
|
||||
final characteristicArgs = characteristic.toArgs(descriptorsArgs);
|
||||
characteristicsArgs.add(characteristicArgs);
|
||||
characteristics[characteristicArgs.hashCodeArgs] = characteristic;
|
||||
}
|
||||
final serviceArgs = service.toArgs(characteristicsArgs);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> addService(GATTService service) async {
|
||||
final serviceArgs = service.toArgs();
|
||||
logger.info('addService: $serviceArgs');
|
||||
await _api.addService(serviceArgs);
|
||||
_characteristics[serviceArgs.hashCodeArgs] = characteristics;
|
||||
_addService(service);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> removeService(GattService service) async {
|
||||
Future<void> removeService(GATTService service) async {
|
||||
final hashCodeArgs = service.hashCode;
|
||||
logger.info('removeService: $hashCodeArgs');
|
||||
await _api.removeService(hashCodeArgs);
|
||||
_characteristics.remove(hashCodeArgs);
|
||||
_removeService(service);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> clearServices() async {
|
||||
logger.info('clearServices');
|
||||
await _api.clearServices();
|
||||
Future<void> removeAllServices() async {
|
||||
logger.info('removeAllServices');
|
||||
await _api.removeAllServices();
|
||||
_characteristics.clear();
|
||||
}
|
||||
|
||||
@ -112,62 +129,112 @@ class MyPeripheralManager extends PeripheralManager
|
||||
}
|
||||
|
||||
@override
|
||||
Future<Uint8List> readCharacteristic(GattCharacteristic characteristic) {
|
||||
if (characteristic is! MyGattCharacteristic) {
|
||||
throw TypeError();
|
||||
}
|
||||
final hashCodeArgs = characteristic.hashCode;
|
||||
logger.info('readCharacteristic: $hashCodeArgs');
|
||||
final value = characteristic.value;
|
||||
return Future.value(value);
|
||||
Future<int> getMaximumNotifyLength(Central central) async {
|
||||
final uuidArgs = central.uuid.toArgs();
|
||||
logger.info('getMaximumNotifyLength: $uuidArgs');
|
||||
final maximumNotifyLength = await _api.getMaximumNotifyLength(uuidArgs);
|
||||
return maximumNotifyLength;
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> writeCharacteristic(
|
||||
GattCharacteristic characteristic, {
|
||||
Future<void> respondReadRequestWithValue(
|
||||
GATTReadRequest request, {
|
||||
required Uint8List value,
|
||||
Central? central,
|
||||
}) async {
|
||||
if (characteristic is! MyGattCharacteristic) {
|
||||
if (request is! MyGATTReadRequest) {
|
||||
throw TypeError();
|
||||
}
|
||||
characteristic.value = value;
|
||||
if (central == null) {
|
||||
return;
|
||||
}
|
||||
if (central is! MyCentral) {
|
||||
final hashCodeArgs = request.hashCodeArgs;
|
||||
final valueArgs = value;
|
||||
const errorArgs = MyATTErrorArgs.success;
|
||||
logger.info('respond: $hashCodeArgs - $valueArgs, $errorArgs');
|
||||
await _api.respond(
|
||||
hashCodeArgs,
|
||||
valueArgs,
|
||||
errorArgs,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> respondReadRequestWithError(
|
||||
GATTReadRequest request, {
|
||||
required GATTError error,
|
||||
}) async {
|
||||
if (request is! MyGATTReadRequest) {
|
||||
throw TypeError();
|
||||
}
|
||||
final uuidArgs = central.uuid.toArgs();
|
||||
final hashCodeArgs = request.hashCodeArgs;
|
||||
const valueArgs = null;
|
||||
final errorArgs = error.toArgs();
|
||||
logger.info('respond: $hashCodeArgs - $valueArgs, $errorArgs');
|
||||
await _api.respond(
|
||||
hashCodeArgs,
|
||||
valueArgs,
|
||||
errorArgs,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> respondWriteRequest(GATTWriteRequest request) async {
|
||||
if (request is! MyGATTWriteRequest) {
|
||||
throw TypeError();
|
||||
}
|
||||
final hashCodeArgs = request.hashCodeArgs;
|
||||
const valueArgs = null;
|
||||
const errorArgs = MyATTErrorArgs.success;
|
||||
logger.info('respond: $hashCodeArgs - $valueArgs, $errorArgs');
|
||||
await _api.respond(
|
||||
hashCodeArgs,
|
||||
valueArgs,
|
||||
errorArgs,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> respondWriteRequestWithError(
|
||||
GATTWriteRequest request, {
|
||||
required GATTError error,
|
||||
}) async {
|
||||
if (request is! MyGATTWriteRequest) {
|
||||
throw TypeError();
|
||||
}
|
||||
final hashCodeArgs = request.hashCodeArgs;
|
||||
const valueArgs = null;
|
||||
final errorArgs = error.toArgs();
|
||||
logger.info('respond: $hashCodeArgs - $valueArgs, $errorArgs');
|
||||
await _api.respond(
|
||||
hashCodeArgs,
|
||||
valueArgs,
|
||||
errorArgs,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> notifyCharacteristic(
|
||||
Central central,
|
||||
GATTCharacteristic characteristic, {
|
||||
required Uint8List value,
|
||||
}) async {
|
||||
final hashCodeArgs = characteristic.hashCode;
|
||||
final listener = _retrieveListener(uuidArgs, hashCodeArgs);
|
||||
if (listener == null) {
|
||||
logger.warning('The central is not listening.');
|
||||
return;
|
||||
}
|
||||
final valueArgs = value;
|
||||
final uuidArgs = central.uuid.toArgs();
|
||||
final uuidsArgs = [uuidArgs];
|
||||
final trimmedValueArgs = characteristic.value;
|
||||
final fragmentSize = await _api.getMaximumUpdateValueLength(uuidArgs);
|
||||
var start = 0;
|
||||
while (start < trimmedValueArgs.length) {
|
||||
final end = start + fragmentSize;
|
||||
final fragmentedValueArgs = end < trimmedValueArgs.length
|
||||
? trimmedValueArgs.sublist(start, end)
|
||||
: trimmedValueArgs.sublist(start);
|
||||
logger.info(
|
||||
'notifyCharacteristicChanged: $hashCodeArgs - $fragmentedValueArgs, $uuidsArgs');
|
||||
await _api.updateCharacteristic(
|
||||
while (true) {
|
||||
logger.info('updateValue: $hashCodeArgs - $valueArgs, $uuidsArgs');
|
||||
final updated = await _api.updateValue(
|
||||
hashCodeArgs,
|
||||
fragmentedValueArgs,
|
||||
valueArgs,
|
||||
uuidsArgs,
|
||||
);
|
||||
start = end;
|
||||
if (updated) {
|
||||
break;
|
||||
}
|
||||
await _isReady.first;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void onStateChanged(int stateNumberArgs) {
|
||||
final stateArgs = MyBluetoothLowEnergyStateArgs.values[stateNumberArgs];
|
||||
void onStateChanged(MyBluetoothLowEnergyStateArgs stateArgs) {
|
||||
logger.info('onStateChanged: $stateArgs');
|
||||
final state = stateArgs.toState();
|
||||
if (_state == state) {
|
||||
@ -179,54 +246,82 @@ class MyPeripheralManager extends PeripheralManager
|
||||
}
|
||||
|
||||
@override
|
||||
void onCharacteristicReadRequest(
|
||||
MyCentralArgs centralArgs,
|
||||
int hashCodeArgs,
|
||||
int idArgs,
|
||||
int offsetArgs,
|
||||
) async {
|
||||
final uuidArgs = centralArgs.uuidArgs;
|
||||
void didReceiveRead(MyATTRequestArgs requestArgs) async {
|
||||
final centralArgs = requestArgs.centralArgs;
|
||||
final hashCodeArgs = requestArgs.hashCodeArgs;
|
||||
final characteristicHashCodeArgs = requestArgs.characteristicHashCodeArgs;
|
||||
final offsetArgs = requestArgs.offsetArgs;
|
||||
final valueArgs = requestArgs.valueArgs;
|
||||
logger.info(
|
||||
'onCharacteristicReadRequest: $uuidArgs.$hashCodeArgs - $idArgs, $offsetArgs');
|
||||
'didReceiveRead: ${centralArgs.uuidArgs} - $hashCodeArgs, $characteristicHashCodeArgs, $offsetArgs, $valueArgs');
|
||||
final central = centralArgs.toCentral();
|
||||
final characteristic = _retrieveCharacteristic(hashCodeArgs);
|
||||
final characteristic = _characteristics[characteristicHashCodeArgs];
|
||||
if (characteristic == null) {
|
||||
return;
|
||||
await _respond(hashCodeArgs, null, MyATTErrorArgs.attributeNotFound);
|
||||
} else {
|
||||
final eventArgs = GATTCharacteristicReadRequestedEventArgs(
|
||||
central,
|
||||
characteristic,
|
||||
MyGATTReadRequest(
|
||||
hashCodeArgs: hashCodeArgs,
|
||||
offset: offsetArgs,
|
||||
),
|
||||
);
|
||||
_characteristicReadRequestedController.add(eventArgs);
|
||||
}
|
||||
const errorArgs = MyGattErrorArgs.success;
|
||||
final offset = offsetArgs;
|
||||
final valueArgs = _onCharacteristicRead(central, characteristic, offset);
|
||||
await _tryRespond(
|
||||
idArgs,
|
||||
errorArgs,
|
||||
valueArgs,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void onCharacteristicWriteRequest(
|
||||
MyCentralArgs centralArgs,
|
||||
int hashCodeArgs,
|
||||
int idArgs,
|
||||
int offsetArgs,
|
||||
Uint8List valueArgs,
|
||||
) async {
|
||||
final uuidArgs = centralArgs.uuidArgs;
|
||||
logger.info(
|
||||
'onCharacteristicWriteRequest: $uuidArgs.$hashCodeArgs - $idArgs, $offsetArgs, $valueArgs');
|
||||
final central = centralArgs.toCentral();
|
||||
final characteristic = _retrieveCharacteristic(hashCodeArgs);
|
||||
if (characteristic == null) {
|
||||
return;
|
||||
void didReceiveWrite(List<MyATTRequestArgs?> requestsArgs) async {
|
||||
// When you respond to a write request, note that the first parameter of the respond(to:with
|
||||
// Result:) method expects a single CBATTRequest object, even though you received an array of
|
||||
// them from the peripheralManager(_:didReceiveWrite:) method. To respond properly,
|
||||
// pass in the first request of the requests array.
|
||||
// see: https://developer.apple.com/documentation/corebluetooth/cbperipheralmanagerdelegate/1393315-peripheralmanager#discussion
|
||||
final requestArgs = requestsArgs.cast<MyATTRequestArgs>().first;
|
||||
final centralArgs = requestArgs.centralArgs;
|
||||
final hashCodeArgs = requestArgs.hashCodeArgs;
|
||||
final characteristicHashCodeArgs = requestArgs.characteristicHashCodeArgs;
|
||||
final offsetArgs = requestArgs.offsetArgs;
|
||||
final unsupported = requestsArgs.cast<MyATTRequestArgs>().any((args) =>
|
||||
args.centralArgs.uuidArgs != centralArgs.uuidArgs ||
|
||||
args.characteristicHashCodeArgs != characteristicHashCodeArgs);
|
||||
if (unsupported) {
|
||||
await _respond(hashCodeArgs, null, MyATTErrorArgs.unsupportedGroupType);
|
||||
} else {
|
||||
final central = centralArgs.toCentral();
|
||||
final characteristic = _characteristics[characteristicHashCodeArgs];
|
||||
if (characteristic == null) {
|
||||
await _respond(hashCodeArgs, null, MyATTErrorArgs.attributeNotFound);
|
||||
} else {
|
||||
final elements = requestsArgs.cast<MyATTRequestArgs>().fold(
|
||||
<int>[],
|
||||
(previousValue, args) {
|
||||
final valueArgs = args.valueArgs;
|
||||
if (valueArgs != null) {
|
||||
previousValue.insertAll(args.offsetArgs, valueArgs);
|
||||
}
|
||||
return previousValue;
|
||||
},
|
||||
);
|
||||
final eventArgs = GATTCharacteristicWriteRequestedEventArgs(
|
||||
central,
|
||||
characteristic,
|
||||
MyGATTWriteRequest(
|
||||
hashCodeArgs: hashCodeArgs,
|
||||
offset: offsetArgs,
|
||||
value: Uint8List.fromList(elements),
|
||||
),
|
||||
);
|
||||
_characteristicWriteRequestedController.add(eventArgs);
|
||||
}
|
||||
}
|
||||
const errorArgs = MyGattErrorArgs.success;
|
||||
final value = valueArgs;
|
||||
_onCharacteristicWritten(central, characteristic, value);
|
||||
await _tryRespond(
|
||||
idArgs,
|
||||
errorArgs,
|
||||
null,
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void isReady() {
|
||||
final eventArgs = EventArgs();
|
||||
_isReadyController.add(eventArgs);
|
||||
}
|
||||
|
||||
@override
|
||||
@ -237,88 +332,80 @@ class MyPeripheralManager extends PeripheralManager
|
||||
) {
|
||||
final uuidArgs = centralArgs.uuidArgs;
|
||||
logger.info(
|
||||
'onCharacteristicNotifyStateChanged: $uuidArgs.$hashCodeArgs - $stateArgs');
|
||||
'onCharacteristicNotifyStateChanged: $uuidArgs - $hashCodeArgs, $stateArgs');
|
||||
final central = centralArgs.toCentral();
|
||||
final characteristic = _retrieveCharacteristic(hashCodeArgs);
|
||||
final characteristic = _characteristics[hashCodeArgs];
|
||||
if (characteristic == null) {
|
||||
logger.warning('The characteristic[$hashCodeArgs] is null.');
|
||||
return;
|
||||
}
|
||||
final state = stateArgs;
|
||||
final listeners = _listeners.putIfAbsent(uuidArgs, () => {});
|
||||
if (state) {
|
||||
listeners[hashCodeArgs] = true;
|
||||
} else {
|
||||
listeners.remove(hashCodeArgs);
|
||||
}
|
||||
final eventArgs = GattCharacteristicNotifyStateChangedEventArgs(
|
||||
final eventArgs = GATTCharacteristicNotifyStateChangedEventArgs(
|
||||
central,
|
||||
characteristic,
|
||||
state,
|
||||
stateArgs,
|
||||
);
|
||||
_characteristicNotifyStateChangedController.add(eventArgs);
|
||||
}
|
||||
|
||||
MyGattCharacteristic? _retrieveCharacteristic(int hashCodeArgs) {
|
||||
final characteristics = _characteristics.values
|
||||
.reduce((value, element) => value..addAll(element));
|
||||
return characteristics[hashCodeArgs];
|
||||
}
|
||||
|
||||
bool? _retrieveListener(String uuidArgs, int hashCodeArgs) {
|
||||
final listeners = _listeners[uuidArgs];
|
||||
if (listeners == null) {
|
||||
return null;
|
||||
void _addService(GATTService service) {
|
||||
for (var includedService in service.includedServices) {
|
||||
_addService(includedService);
|
||||
}
|
||||
for (var characteristic in service.characteristics) {
|
||||
if (characteristic is! MutableGATTCharacteristic) {
|
||||
throw TypeError();
|
||||
}
|
||||
_characteristics[characteristic.hashCode] = characteristic;
|
||||
}
|
||||
return listeners[hashCodeArgs];
|
||||
}
|
||||
|
||||
Future<void> _tryRespond(
|
||||
int idArgs,
|
||||
MyGattErrorArgs errorArgs,
|
||||
Uint8List? valueArgs,
|
||||
) async {
|
||||
final errorNumberArgs = errorArgs.index;
|
||||
void _removeService(GATTService service) {
|
||||
for (var includedService in service.includedServices) {
|
||||
_removeService(includedService);
|
||||
}
|
||||
for (var characteristic in service.characteristics) {
|
||||
final hashCodeArgs = characteristic.hashCode;
|
||||
_characteristics.remove(hashCodeArgs);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _initialize() async {
|
||||
// Here we use `Future()` to make it possible to change the `logLevel` before `initialize()`.
|
||||
await Future(() async {
|
||||
try {
|
||||
logger.info('initialize');
|
||||
await _api.initialize();
|
||||
_getState();
|
||||
} catch (e) {
|
||||
logger.severe('initialize failed.', e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _getState() async {
|
||||
try {
|
||||
_api.respond(
|
||||
idArgs,
|
||||
errorNumberArgs,
|
||||
valueArgs,
|
||||
);
|
||||
} catch (e, stack) {
|
||||
logger.shout('Respond failed.', e, stack);
|
||||
logger.info('getState');
|
||||
final stateArgs = await _api.getState();
|
||||
onStateChanged(stateArgs);
|
||||
} catch (e) {
|
||||
logger.severe('getState failed.', e);
|
||||
}
|
||||
}
|
||||
|
||||
Uint8List _onCharacteristicRead(
|
||||
MyCentral central,
|
||||
MyGattCharacteristic characteristic,
|
||||
int offset,
|
||||
) {
|
||||
final value = characteristic.value;
|
||||
final trimmedValue = value.sublist(offset);
|
||||
if (offset == 0) {
|
||||
final eventArgs = GattCharacteristicReadEventArgs(
|
||||
central,
|
||||
characteristic,
|
||||
value,
|
||||
);
|
||||
_characteristicReadController.add(eventArgs);
|
||||
}
|
||||
return trimmedValue;
|
||||
}
|
||||
|
||||
void _onCharacteristicWritten(
|
||||
MyCentral central,
|
||||
MyGattCharacteristic characteristic,
|
||||
Uint8List value,
|
||||
Future<void> _respond(
|
||||
int hashCodeArgs,
|
||||
Uint8List? valueArgs,
|
||||
MyATTErrorArgs errorArgs,
|
||||
) async {
|
||||
characteristic.value = value;
|
||||
final trimmedValue = characteristic.value;
|
||||
final eventArgs = GattCharacteristicWrittenEventArgs(
|
||||
central,
|
||||
characteristic,
|
||||
trimmedValue,
|
||||
);
|
||||
_characteristicWrittenController.add(eventArgs);
|
||||
try {
|
||||
logger.info('respond: $hashCodeArgs - $valueArgs, $errorArgs');
|
||||
await _api.respond(
|
||||
hashCodeArgs,
|
||||
valueArgs,
|
||||
errorArgs,
|
||||
);
|
||||
} catch (e) {
|
||||
logger.severe('respond failed.', e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user