123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220 |
- import 'dart:async';
- import 'package:flutter_blue_plus/flutter_blue_plus.dart';
- import 'package:flutter_vr/tools/YSTools.dart';
- class ConnectManager {
- final Guid SET_MODE_SERVICE_UUID = Guid("0000180f-0000-1000-8000-00805f9b34fb"); //设置模式-服务UUID
- final Guid SET_MODE_CHARACTERISTIC_UUID = Guid("00002a19-0000-1000-8000-00805f9b34fb"); //设置模式-特征值UUID
- final Guid SET_MODE_DESCRIPTOR_UUID = Guid("00002902-0000-1000-8000-00805f9b34fb"); //设置模式-特征值描述UUID(固定不变)
- final Guid WRITE_DATA_SERVICE_UUID = Guid("01ff0100-ba5e-f4ee-5ca1-eb1e5e4b1ce1"); //写数据-服务UUID
- final Guid WRITE_DATA_CHARACTERISTIC_UUID = Guid("01ff0101-ba5e-f4ee-5ca1-eb1e5e4b1ce1"); //写数据-特征值UUID
- final List<int> ENABLE_NOTIFICATION_VALUE = [0x01, 0x00]; //启用Notification模式
- final List<int> DISABLE_NOTIFICATION_VALUE = [0x00, 0x00]; //停用Notification模式
- final List<int> ENABLE_INDICATION_VALUE = [0x02, 0x00]; //启用Indication模式
- static const int CON_TIMEOUT = 10000;
- final GattCallback _gattCallback;
- BluetoothCharacteristic? _writeCharacteristic;
- ScanDevice? _scanDevice;
- DeviceBean? _device;
- bool isConnecting = false;
- ConnectManager(this._gattCallback);
- //1.扫描
- Future<void> start(String deviceName, {int timeout = ScanDevice.SCAN_TIMEOUT}) async {
- _scanDevice ??= ScanDevice(ScanCallback(
- onFind: (DeviceBean device) { //扫描到设备
- if(isConnecting) {
- _scanDevice?.stopScan(); //停止扫描
- return;
- }
- if(device.device.platformName == deviceName){
- _device = device;
- _scanDevice?.stopScan(); //停止扫描
- connect(device.device); //转 - 2.连接
- }
- },
- onStop: () { //停止扫描
- if(_device == null){
- LogUtil.d("没找到设备 >>>>>>");
- _gattCallback.onDeviceNotFind(); //没扫描到设备时, 回调外部
- }
- }
- ));
- _scanDevice?.startScan(timeout: timeout);
- isConnecting = false;
- }
- //2.连接
- Future<void> connect(BluetoothDevice device) async {
- isConnecting = true;
- LogUtil.d("2.开始连接 >>>>>>name: ${device.platformName}");
- await device.connect(timeout: const Duration(milliseconds: CON_TIMEOUT), autoConnect: false);
- LogUtil.d("连接成功 >>>>>>name: ${device.platformName}");
- _discoverServices(device);
- }
- //3.发现服务
- Future<void> _discoverServices(BluetoothDevice device) async {
- LogUtil.d("3.开始发现服务 >>>>>>name: ${device.platformName}");
- List<BluetoothService> services = await device.discoverServices();
- LogUtil.d("发现服务成功 >>>>>>name: ${device.platformName}");
- _handlerServices(device, services); //遍历服务列表,找出指定服务
- isConnecting = false;
- }
- //3.1遍历服务列表,找出指定服务
- void _handlerServices(BluetoothDevice device, List<BluetoothService> services){
- for (var sItem in services) {
- String sUuid = sItem.uuid.toString();
- if(sUuid == SET_MODE_SERVICE_UUID.toString()){ //找到设置模式的服务
- LogUtil.d("4.找到设置模式的服务 >>>>>>name: ${device.platformName} serviceGuid: ${SET_MODE_SERVICE_UUID.toString()}");
- _readCharacteristics(device, sItem); //读取特征值
- } else if(sUuid == WRITE_DATA_SERVICE_UUID.toString()){ //找到写数据的服务
- LogUtil.d("4.找到写数据的服务 >>>>>>name: ${device.platformName} serviceGuid: ${WRITE_DATA_SERVICE_UUID.toString()}");
- _readCharacteristics(device, sItem); //读取特征值
- }
- }
- }
- //4.读取特征值(读出设置模式与写数据的特征值)
- Future<void> _readCharacteristics(BluetoothDevice device, BluetoothService service) async {
- var characteristics = service.characteristics;
- for(BluetoothCharacteristic cItem in characteristics) {
- String cUuid = cItem.uuid.toString();
- if(cUuid == SET_MODE_CHARACTERISTIC_UUID.toString()){ //找到设置模式的特征值
- LogUtil.d("4.0.找到设置模式的特征值 >>>>>>name: ${device.platformName} characteristicUUID: ${SET_MODE_CHARACTERISTIC_UUID.toString()}");
- _requestMtu(device); //设置MTU
- _setNotificationMode(device, cItem); //设置为Notification模式(设备主动给手机发数据)
- } else if(cUuid == WRITE_DATA_CHARACTERISTIC_UUID.toString()){ //找到写数据的特征值
- LogUtil.d("4.0.找到写数据的特征值 >>>>>>name: ${device.platformName} characteristicUUID: ${WRITE_DATA_CHARACTERISTIC_UUID.toString()}");
- _writeCharacteristic = cItem; //保存写数据的征值
- }
- }
- }
- //4.1.设置MTU
- Future<void> _requestMtu(BluetoothDevice device) async {
- final mtu = await device.mtu.first;
- LogUtil.d("4.1.当前mtu: $mtu 请求设置mtu为512 >>>>>>name: ${device.platformName}");
- await device.requestMtu(512);
- }
- //4.2.设置为Notification模式(设备主动给手机发数据),Indication模式需要手机读设备的数据
- Future<void> _setNotificationMode(BluetoothDevice device, BluetoothCharacteristic cItem) async {
- LogUtil.d("4.2.设置为通知模式 >>>>>>name: ${device.platformName}");
- await cItem.setNotifyValue(true); //为指定特征的值设置通知
- cItem.lastValueStream.listen((value) {
- if (value.isEmpty) return;
- LogUtil.d("接收数据 >>>>>>name: ${device.platformName} value: $value");
- MessageData data = MessageData();
- //...省略解析设备数据的逻辑
- _gattCallback.onRead(data); //回调外部,返回设备发送的数据
- });
- var descriptors = cItem.descriptors;
- for (BluetoothDescriptor dItem in descriptors) {
- if (dItem.uuid.toString() == SET_MODE_DESCRIPTOR_UUID.toString()) {//找到设置模式的descriptor
- LogUtil.d("发送Notification模式给设备 >>>>>>name: ${device.platformName}");
- dItem.write(ENABLE_NOTIFICATION_VALUE); //发送Notification模式给设备
- return;
- }
- }
- }
- //发送指令到设备
- Future<void> writeCommand(List<int> data) async {
- LogUtil.d("发送指令给设备 >>>>>>name: ${_device?.device.platformName} data: $data");
- await _writeCharacteristic?.write(data);
- }
- //断开连接
- void disconnect(BluetoothDevice device) {
- LogUtil.d("断开连接 >>>>>>name: ${device.platformName}");
- device.disconnect(); //关闭连接
- _gattCallback.onDisconnect(); //连接失败回调
- }
- }
- class MessageData {
- }
- class ScanDevice {
- static const int SCAN_TIMEOUT = 10000;
- final String NAME_PREFIX = "T";
- final String NAME_PREFIX_2 = "HLW";
- final ScanCallback _callback; //回调接口
- var _isScanning = false;
- Timer? _timer;
- ScanDevice(this._callback);
- //开始扫描
- void startScan({int timeout = SCAN_TIMEOUT}) {
- LogUtil.d("1.开始扫描设备 >>>>>>");
- if (_isScanning) return;
- _isScanning = true;
- FlutterBluePlus.scanResults.listen((results) {
- if(results.isNotEmpty){
- LogUtil.d(">>>>>>$results");
- }
- for (ScanResult item in results) {
- _handlerScanResult(item);
- }
- });
- FlutterBluePlus.startScan(timeout: Duration(seconds: timeout));
- startTimer();
- }
- //N秒后停止扫描, 并回调通知外部
- void startTimer(){
- cancelTimer();
- _timer = Timer(const Duration(milliseconds: SCAN_TIMEOUT), () {
- stopScan(); //停止扫描
- _callback.onStop(); //回调通知外部
- });
- }
- void cancelTimer(){
- _timer?.cancel();
- _timer = null;
- }
- //是否扫描中
- bool isScan() {
- return _isScanning;
- }
- //停止扫描
- void stopScan() {
- LogUtil.d("停止扫描设备 >>>>>>");
- cancelTimer();
- if (!_isScanning) return;
- _isScanning = false;
- FlutterBluePlus.stopScan();
- }
- //处理扫描结果
- void _handlerScanResult(ScanResult result) {
- if (!result.device.platformName.startsWith(NAME_PREFIX) && !result.device.platformName.startsWith(NAME_PREFIX_2)) return; //过滤掉非本公司的蓝牙设备
- LogUtil.d('扫到设备, name: ${result.device.platformName}');
- if (result.device.platformName.startsWith(NAME_PREFIX_2)) { //针对定制过的蓝牙设备,需要从广播中获取真正的设备名称
- // var realName = getRealName(result); //从广播中获取真实的设备名称
- // if (realName != null && realName.startsWith("T")){
- // //...
- // }
- _callback.onFind(DeviceBean(result.device)); //回调到外部
- return;
- }
- _callback.onFind(DeviceBean(result.device)); //回调到外部
- }
- }
- typedef OnFind = void Function(DeviceBean device);
- typedef OnStop = void Function();
- class ScanCallback {
- ScanCallback ({required this.onFind, required this.onStop});
- OnFind onFind;
- OnStop onStop;
- }
- class DeviceBean {
- BluetoothDevice device; //设备
- DeviceBean(this.device);
- }
- typedef OnDeviceNotFind = void Function();
- typedef OnConnected = void Function();
- typedef OnDisconnect = void Function();
- typedef OnRead = void Function(MessageData data);
- class GattCallback {
- GattCallback ({required this.onDeviceNotFind, required this.onConnected, required this.onDisconnect, required this.onRead});
- OnDeviceNotFind onDeviceNotFind;
- OnConnected onConnected;
- OnDisconnect onDisconnect;
- OnRead onRead;
- }
|