1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876 |
- import 'dart:async';
- import 'dart:convert';
- import 'dart:core';
- import 'dart:io';
- import 'dart:math';
- import 'dart:typed_data';
- import 'package:broadcast/broadcast.dart';
- import 'package:buffer/buffer.dart';
- import 'package:device_info/device_info.dart';
- import 'package:flutter/material.dart';
- import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
- import 'package:get_it/get_it.dart';
- import 'package:package_info/package_info.dart';
- import 'package:path_provider/path_provider.dart';
- import 'package:shared_preferences/shared_preferences.dart';
- import 'package:sport/application.dart';
- import 'package:sport/bean/hardware.dart';
- import 'package:sport/db/bluetooth_db.dart';
- import 'package:sport/db/step_db.dart';
- import 'package:sport/game/sdk_parse.dart';
- import 'package:sport/pages/my/dfu_update_page.dart';
- import 'package:sport/pages/web/game_log.dart';
- import 'package:sport/services/Converter.dart';
- import 'package:sport/services/api/inject_api.dart';
- import 'package:sport/services/api/rest_client.dart';
- import 'package:sport/utils/toast.dart';
- import 'package:sport/utils/version.dart';
- import 'package:sport/widgets/dialog/alert_dialog.dart';
- const BLE_CODE_0 = 0x00;
- const BLE_CODE_1 = 0x01;
- class BLE {
- BLE._();
- static const BLE_Client_T_MOTION = 0x04;
- static const BLE_Client_T_UPDATE = 0xA1;
- static const BLE_Client_T_GAMEMODE = 0xA2;
- static const BLE_Client_T_CONNET_R = 0xA3;
- static const BLE_Client_T_SHOCK = 0xA4;
- static const BLE_Client_T_REALTIMESTEP = 0xA5;
- static const BLE_Client_T_DFU = 0xA6;
- static const BLE_Client_T_CHARGE = 0xA7;
- static const BLE_Client_T_LIGHTING = 0xAC;
- static const BLE_Client_T_ERR = 0xAD;
- static const BLE_Client_T_CONNECT_CONFIRM = 0xB0;
- }
- class BLE_UPDATE {
- BLE_UPDATE._();
- static const BASIC = 0x00;
- static const DATA = 0x01;
- static const STEP = 0x02;
- static const STEP_DELETE = 0x03;
- }
- const BLE_UUID = "6e400001-b5a3-f393-e0a9-e50e24dcca9e";
- class Bluetooth with InjectApi, GameLog {
- static final String PREF_KEY = "SHOES";
- static final String PREF_KEY_NAME = "SHOES_NAME";
- factory Bluetooth() => _getInstance();
- static Bluetooth? _instance;
- // 获取对象
- static Bluetooth _getInstance() {
- if (_instance == null) {
- // 使用私有的构造方法来创建对象
- _instance = Bluetooth._internal();
- }
- return _instance!;
- }
- Bluetooth._internal() {
- //初始化(设置一些默认的)...
- }
- final List<StreamSubscription<dynamic>> _streamSubscriptions = <StreamSubscription<dynamic>>[];
- void addSubscription(StreamSubscription<dynamic> streamSubscription) {
- _streamSubscriptions.add(streamSubscription);
- }
- disposeSubscription() async {
- timerConnected?.cancel();
- characteristicWrite = null;
- characteristicNotify = null;
- if(_streamSubscriptions.isNotEmpty) {
- try {
- for (StreamSubscription<dynamic> subscription in _streamSubscriptions) {
- await subscription.cancel();
- }
- } catch (e) {
- print(e);
- }
- }
- _streamSubscriptions.clear();
- }
- // ignore: close_sinks
- final StreamController<bool> _queryController = StreamController.broadcast();
- Stream<bool> get queryStream => _queryController.stream;
- // ignore: close_sinks
- final StreamController<Uint8List> _dataController = StreamController.broadcast();
- Stream<Uint8List> get dataStream => _dataController.stream;
- // ignore: close_sinks
- final StreamController<int> _connectRightController = StreamController.broadcast();
- Stream<int> get connectRightStream => _connectRightController.stream;
- // ignore: close_sinks
- final StreamController<bool> _dfuController = StreamController.broadcast();
- Stream<bool> get dfuStream => _dfuController.stream;
- // ignore: close_sinks
- final StreamController<int> _sdkCmdController = StreamController.broadcast();
- Stream<int> get sdkCmdStream => _sdkCmdController.stream;
- // ignore: close_sinks
- final StreamController<List<int>> _sdkMotionController = StreamController.broadcast();
- Stream<List<int>> get sdkMotionStream => _sdkMotionController.stream;
- // ignore: close_sinks
- final StreamController<String> _sdkMotionDataController = StreamController.broadcast();
- Stream<String> get sdkMotionDataStream => _sdkMotionDataController.stream;
- final ValueNotifier<DiscoveredDevice?> deviceNotifier = ValueNotifier<DiscoveredDevice?>(null);
- final ValueNotifier<String> deviceNameNotifier = ValueNotifier<String>("");
- final ValueNotifier<Map> infoNotifier = ValueNotifier<Map>({});
- final ValueNotifier<String> versionNotifier = ValueNotifier<String>("");
- final ValueNotifier<Map> dataNotifier = ValueNotifier<Map>({});
- final ValueNotifier<int> electricityNotifier = ValueNotifier<int>(0);
- final ValueNotifier<int> stepNotifier = ValueNotifier<int>(0);
- final ValueNotifier<int> stepTotalNotifier = ValueNotifier<int>(0);
- final ValueNotifier<int> stepTotalTestNotifier = ValueNotifier<int>(0);
- final ValueNotifier<int> actionNotifier = ValueNotifier<int>(0);
- final ValueNotifier<List<int>> byteNotifier = ValueNotifier<List<int>>([]);
- final ValueNotifier<int> vibrateNotifier = ValueNotifier<int>(400);
- final ValueNotifier<List<int>> stepRealtimeNotifier = ValueNotifier<List<int>>([]);
- final ValueNotifier<bool> stepRealtimePageNotifier = ValueNotifier<bool>(false);
- final ValueNotifier<Hardware?> verNotifier = ValueNotifier(null);
- final ValueNotifier<Map<int, int>> stateNotifier = ValueNotifier({1: 0, 0: 0});
- final ValueNotifier<bool> h5gameRNotifier = ValueNotifier<bool>(false);
- final ValueNotifier<bool> deviceWriteNotifier = ValueNotifier<bool>(false);
- final ValueNotifier<bool> deviceReadNotifier = ValueNotifier<bool>(false);
- final ValueNotifier<bool> deviceReadNotifyNotifier = ValueNotifier<bool>(false);
- final ValueNotifier<int> rssiNotifier = ValueNotifier<int>(0);
- final ValueNotifier<Map<String, int>> timeUseNotifier = ValueNotifier<Map<String, int>>({});
- DiscoveredDevice? _connectingDevice;
- bool _listen = false;
- bool _online = false;
- bool _uploadLoged = false;
- bool _connecting = false;
- bool _scanning = false;
- String? _deviceId;
- int heartbeat = 0;
- PartInfo? _partInfo;
- Completer<bool>? _completerStep;
- Completer<bool>? _completerStepDel;
- Completer<bool>? _completerSetupDeviceVer;
- Completer<bool>? _completerConnected;
- QualifiedCharacteristic? characteristicWrite, characteristicNotify;
- StreamSubscription? statusStream, connectRight;
- late FlutterReactiveBle flutterReactiveBle;
- Timer? stepRealTimeTimer;
- Timer? gameModeTimer;
- Timer? timerConnected;
- Timer? rssiTimer;
- Timer? disconnectTimer;
- Timer? tryConnectTimer;
- int disconnectTimes = 0;
- DateTime? startTime;
- List<int> timeUse = [];
- int testDfu = 0;
- int _isRightError = 0;
- bool get isConnected => _online;
- bool get isNotReady => isDebugShoe ? false : !(_online == true && electricityNotifier.value > 0);
- bool get isRightError => _isRightError != 1;
- String? get deviceId => _deviceId;
- DiscoveredDevice? get device => _connectingDevice;
- late BuildContext _context;
- bool _showChargeDialog = false;
- DateTime? electricityTime;
- late SDKApi sdk;
- resetData() {
- stepNotifier.value = 0;
- stepTotalNotifier.value = 0;
- actionNotifier.value = 0;
- }
- bool _dfu = false;
- set dfu(bool dfu) {
- _dfu = dfu;
- }
- Future<String> _saveDevice(DiscoveredDevice device) async {
- var prefs = await SharedPreferences.getInstance();
- prefs.setString(PREF_KEY, device.id);
- prefs.setString(PREF_KEY_NAME, device.name);
- return device.id;
- }
- clearDevice({bool deleteStep = false}) async {
- var prefs = await SharedPreferences.getInstance();
- prefs.remove(PREF_KEY);
- prefs.remove(PREF_KEY_NAME);
- // if (deleteStep == true) {
- // var db = StepDB();
- // db.deleteAll();
- // }
- startTime = null;
- await disconnectDevice("清空设备", clearGatt: true, click: true);
- }
- Future<String?> getHistoryDevice() async {
- var prefs = await SharedPreferences.getInstance();
- return prefs.getString(PREF_KEY);
- }
- init(BuildContext context) async {
- this._connecting = false;
- statusStream?.cancel();
- connectRight?.cancel();
- flutterReactiveBle = FlutterReactiveBle();
- flutterReactiveBle.logLevel = inProduction ? LogLevel.none : LogLevel.verbose;
- statusStream = flutterReactiveBle.statusStream.listen((state) {
- print("bluetooth -- instance state $state");
- if (state == BleStatus.ready) {
- autoConnect();
- } else if (state == BleStatus.unknown) {
- } else if (state == BleStatus.poweredOff) {
- // clearDevice(deleteStep: false);
- // ToastUtil.show("蓝牙服务已关闭");
- } else {}
- });
- // flutterReactiveBle.connectedDeviceStream.listen((event) {
- // print("bluetooth -- device state $event");
- // if (event.connectionState == DeviceConnectionState.disconnected) {
- // _online = false;
- // tryCount--;
- // if (event.failure?.code == ConnectionError.failedToConnect) {
- // notifyConnectTime("[$tryCount]E${RegExp(r"([0-9]+)").firstMatch("${event.failure?.message}")?.group(0)}");
- // // addErr("0", "${event.failure?.code}", "${event.failure?.message}");
- // } else {
- // notifyConnectTime("[$tryCount]E0");
- // }
- // disposeSubscription();
- //
- // if (event.failure == null) {
- // try {
- // _completerConnected?.complete(true);
- // } catch (e) {}
- // }
- // }
- // });
- connectRight = connectRightStream.listen((event) {
- print("bluetooth -- connect right ${_connectingDevice?.name} ${event}!");
- if (event == 1 && _isRightError != event) {
- notifyConnectTime("R");
- timerConnected?.cancel();
- dataNotifier.value = {};
- verNotifier.value = null;
- // 左右鞋连接状态就绪,正常连接
- final device = _connectingDevice;
- if (device != null) {
- _newConnect(checkDfuUpdate: false);
- _connected(device);
- _query();
- }
- }
- _isRightError = event;
- });
- deviceNotifier.addListener(() {
- if (deviceNotifier.value != null) {
- DiscoveredDevice device = deviceNotifier.value!;
- deviceNameNotifier.value = device.name;
- BluetoothDB().find().then((history) {
- if (history.isNotEmpty == true) {
- try {
- var item = history.firstWhere((element) => element[BluetoothDB.C_ID] == device.id);
- deviceNameNotifier.value = item[BluetoothDB.C_MARK] ?? device.name ?? "";
- } catch (e) {}
- }
- });
- } else {
- deviceNameNotifier.value = "";
- }
- });
- Broadcast.eventStream.listen((event) {
- disconnectDevice("iOS 进入游戏");
- });
- sdk = SDKApi();
- this.listen(context, init: true);
- }
- gameInit(int gameType) {
- sdk.gameInit(gameType);
- }
- SDKApi gameSDK() {
- return sdk;
- }
- createGameLog(String? name) async {
- super.createLog("${name}_${sdk.getVersion()}", device?.name ?? deviceId);
- }
- uploadGameLog() {
- uploadLog();
- }
- _newConnect({bool checkDfuUpdate = true}) {
- final device = _connectingDevice;
- if (device != null) {
- _saveDevice(device);
- // if (isDebugShoe) {
- // ToastUtil.show("${device.name} 已连接");
- // }
- BluetoothDB().insert(device);
- if (checkDfuUpdate == true) checkUpdate();
- }
- }
- Future<bool> _hasConnected() async {
- final device = _connectingDevice;
- if (device != null) {
- return (await BluetoothDB().findById(device.id)).isNotEmpty;
- }
- return false;
- }
- Future listen(BuildContext context, {bool init = false}) async {
- this._context = context;
- this._listen = true;
- print("bluetooth -- listen");
- Broadcast.broadcast("SHOE.SDK.BLUE_DISCONNECT");
- var prefs = await SharedPreferences.getInstance();
- if (!prefs.containsKey("token")) {
- return;
- }
- disconnectTimer?.cancel();
- disconnectTimes = 0;
- if (_dfu == true) return;
- if (init != true) {
- if (isConnected) {
- setupGameMode4h5(h5gameRNotifier.value);
- } else {
- autoConnect();
- }
- }
- }
- void runTimer() {
- heartbeat = 0;
- addSubscription(Stream.periodic(Duration(seconds: 60)).listen((event) async {
- if (!isConnected) return;
- heartbeat++;
- if (heartbeat > 3) {
- disconnectDevice("心跳异常");
- return;
- }
- await queryDeviceData();
- await queryDeviceStep();
- }));
- }
- autoConnect() {
- getHistoryDevice().then((value) {
- if (this._connecting == true) return;
- if (value != null) connectDevice(id: value);
- });
- }
- Future background(BuildContext context) async {
- this._listen = false;
- if (_showChargeDialog == true) {
- Navigator.maybePop(context);
- }
- disconnectTimer?.cancel();
- disconnectTimer = Timer.periodic(Duration(seconds: 10), (t) {
- disconnectTimes++;
- if (disconnectTimes >= 720) {
- disconnectDevice("后台时断开连接");
- t.cancel();
- }
- });
- }
- Future disposeBluetooth(BuildContext context) async {
- if (_dfu == true) return;
- // // 实时计步中不主动断开
- if (stepRealtimePageNotifier.value == true) return;
- gameModeTimer?.cancel();
- this._listen = false;
- if (_showChargeDialog == true) {
- Navigator.maybePop(context);
- }
- // if (Platform.isIOS) {
- await disconnectDevice("app退后台");
- // }
- }
- resetNotifierData() {
- dataNotifier.value = {};
- verNotifier.value = null;
- versionNotifier.value = "";
- electricityNotifier.value = -1;
- _connectRightController.add(0);
- stateNotifier.value = {0: 0, 1: 0};
- notifyConnectTime("dis");
- deviceWriteNotifier.value = false;
- deviceReadNotifier.value = false;
- deviceReadNotifyNotifier.value = false;
- _online = false;
- }
- Future disconnectDevice(String msg, {bool clearGatt = false, bool click = false}) async {
- print("bluetooth -- disconnect $msg ${_connectingDevice?.id}");
- _scanning = false;
- _deviceId = null;
- await disposeSubscription();
- try {
- _completerConnected?.complete(true);
- } catch (e) {}
- if (click == true) Broadcast.broadcast("SHOE.SDK.BLUE_DISCONNECT");
- resetNotifierData();
- _isRightError = 0;
- disconnectTimes = 0;
- _uploadLoged = false;
- _connectingDevice = null;
- deviceNotifier.value = null;
- errQueue.clear();
- }
- connect({DiscoveredDevice? device}) async {
- await connectDevice(discoveredDevice: device);
- }
- Future connectDevice({DiscoveredDevice? discoveredDevice, String? id, bool again = false}) async {
- await disconnectDevice("主动连接");
- this._connecting = true;
- // await _connectDeviceInner(discoveredDevice: discoveredDevice, id: id, again: again);
- timeUse = [];
- timeUseNotifier.value = {};
- if (discoveredDevice != null) {
- startTime = null;
- }
- notifyConnectTime("F");
- DiscoveredDevice? device = discoveredDevice;
- if (device == null) {
- device = await discoverDevice(deviceId: id);
- if (device == null) {
- await disconnectDevice("没有找到设备");
- return;
- }
- notifyConnectTime("FF");
- // 1秒可能会提高连接成功率
- await Future.delayed(Duration(seconds: 1));
- }
- _connectingDevice = device;
- await _connectDeviceInner(device);
- }
- Future _connectDeviceInner(DiscoveredDevice device) async {
- int tryCount = 3;
- while (tryCount > 0) {
- print("bluetooth -- connect id: ${device.id} (test=$tryCount) !");
- if (!_connecting) break;
- if (device.id != _connectingDevice?.id) break;
- String deviceId = _deviceId = device.id;
- try {
- if (Platform.isIOS && tryCount != 3) {
- DiscoveredDevice? device = await discoverDevice(deviceId: deviceId);
- if (device == null) {
- tryCount--;
- continue;
- }
- deviceId = device.id;
- notifyConnectTime("FF");
- // 1秒可能会提高连接成功率
- await Future.delayed(Duration(seconds: 1));
- }
- addSubscription(flutterReactiveBle.connectToDevice(id: deviceId, connectionTimeout: const Duration(seconds: 10)).listen((state) async {
- print("bluetooth -- connect state $state $_connecting ");
- if (state.connectionState == DeviceConnectionState.connected) {
- notifyConnectTime("[$tryCount]C");
- // bindConnectedDevice(id: deviceId);
- int result = await discoverServices(flutterReactiveBle, deviceId);
- notifyConnectTime("[$tryCount]D$result");
- print("bluetooth -- connect discover services $result");
- if (result != 3) {
- try {
- _completerConnected?.complete(true);
- } catch (e) {}
- return;
- }
- if (characteristicNotify != null) {
- print("bluetooth -- subscribe notify $characteristicNotify");
- addSubscription(flutterReactiveBle.subscribeToCharacteristic(characteristicNotify!).listen((event) {
- // print("bluetooth -- subscribe notify $event");
- deviceReadNotifyNotifier.value = true;
- byteNotifier.value = event;
- heartbeat = 0;
- parse(event);
- })
- ..onError((e) {
- print("bluetooth -- subscribe notify e -> $e");
- disconnectDevice("订阅服务失败");
- }));
- }
- Stream.periodic(const Duration(seconds: 1)).take(10).forEach((element) {
- write(BLE.BLE_Client_T_CONNECT_CONFIRM, Uint8List.fromList([BLE_CODE_1]), test: 10);
- });
- int timeout = 10;
- timerConnected = Timer.periodic(Duration(seconds: 1), (t) {
- queryDeviceInfo();
- queryDeviceRight();
- if (--timeout < 0) {
- if (isRightError) {
- clearDevice();
- }
- t.cancel();
- }
- });
- tryCount = 3;
- } else if (state.connectionState == DeviceConnectionState.disconnected) {
- tryCount--;
- notifyConnectTime("[$tryCount]E${RegExp(r"([0-9]+)").firstMatch("${state.failure?.message}")?.group(0) ?? "0"}");
- try {
- _completerConnected?.complete(!(state.failure?.code == ConnectionError.failedToConnect));
- } catch (e) {}
- }
- })
- ..onError((e) {}));
- if (_connecting) {
- var result = await (_completerConnected = Completer()).future;
- // true是主动断开
- _connecting = result != true;
- await disposeSubscription();
- if (!_connecting) break;
- }
- } catch (e) {
- print("bluetooth -- connect error: $e");
- print(e);
- break;
- }
- await Future.delayed(Duration(seconds: 3));
- }
- if(_connecting) {
- await disconnectDevice("断开蓝牙连接 $_connecting");
- }
- //
- // notifyConnectTime("F");
- //
- // if (discoveredDevice == null) {
- // DiscoveredDevice? d = await discoverDevice(deviceId: id);
- // if (d != null) {
- // discoveredDevice = d;
- // notifyConnectTime("FF");
- // } else {
- // disconnectDevice("搜索不到设备", clearGatt: true);
- // return;
- // }
- // }
- //
- // String deviceId = _deviceId = discoveredDevice.id;
- // _connectingDevice = discoveredDevice;
- //
- // print("bluetooth -- connect $deviceId $again!");
- //
- // final stream = flutterReactiveBle.connectToDevice(id: deviceId, connectionTimeout: const Duration(seconds: 10));
- // addSubscription(stream.listen(_connectState, onError: (Object e) {
- // disconnectDevice("连接服务异常", clearGatt: true);
- // }));
- }
- Future<DiscoveredDevice?> discoverDevice({String? deviceId, String? deviceName}) async {
- // 2022-04-26 11:10:53.285 17454-17479/com.ouj.sdk.test I/System.out: 00001800-0000-1000-8000-00805f9b34fb
- // 2022-04-26 11:10:53.285 17454-17479/com.ouj.sdk.test I/System.out: 00002a00-0000-1000-8000-00805f9b34fb
- // 2022-04-26 11:10:53.285 17454-17479/com.ouj.sdk.test I/System.out: 00002a01-0000-1000-8000-00805f9b34fb
- // 2022-04-26 11:10:53.285 17454-17479/com.ouj.sdk.test I/System.out: 00002a04-0000-1000-8000-00805f9b34fb
- // 2022-04-26 11:10:53.285 17454-17479/com.ouj.sdk.test I/System.out: 00002aa6-0000-1000-8000-00805f9b34fb
- // 2022-04-26 11:10:53.285 17454-17479/com.ouj.sdk.test I/System.out: 00001801-0000-1000-8000-00805f9b34fb
- // 2022-04-26 11:10:53.285 17454-17479/com.ouj.sdk.test I/System.out: 6e400001-b5a3-f393-e0a9-e50e24dcca9e
- // 2022-04-26 11:10:53.285 17454-17479/com.ouj.sdk.test I/System.out: 6e400002-b5a3-f393-e0a9-e50e24dcca9e
- // 2022-04-26 11:10:53.285 17454-17479/com.ouj.sdk.test D/BluetoothController: discovered characteristic write android.bluetooth.BluetoothGatt@28bbf97 android.bluetooth.BluetoothGattCharacteristic@81cd69e
- // 2022-04-26 11:10:53.285 17454-17479/com.ouj.sdk.test I/System.out: 6e400003-b5a3-f393-e0a9-e50e24dcca9e
- // 2022-04-26 11:10:53.285 17454-17479/com.ouj.sdk.test D/BluetoothGatt: setCharacteristicNotification() - uuid: 6e400003-b5a3-f393-e0a9-e50e24dcca9e enable: true
- // 2022-04-26 11:10:53.286 17454-17479/com.ouj.sdk.test D/BluetoothController: discovered characteristic notify android.bluetooth.BluetoothGatt@28bbf97 android.bluetooth.BluetoothGattCharacteristic@9dfb57f
- // 2022-04-26 11:10:53.286 17454-17479/com.ouj.sdk.test I/System.out: 0000fe59-0000-1000-8000-00805f9b34fb
- // 2022-04-26 11:10:53.286 17454-17479/com.ouj.sdk.test I/System.out: 8ec90003-f315-4f60-9fb8-838830daea50
- _scanning = true;
- Timer timeout = Timer(Duration(seconds: 10), () {
- _scanning = false;
- });
- var stream = flutterReactiveBle.scanForDevices(withServices: [Uuid.parse(BLE_UUID)], scanMode: ScanMode.lowPower);
- DiscoveredDevice? device;
- await for (var event in stream) {
- print('bluetooth -- scan device : ${event.id} ${event.name}');
- if (_scanning != true) {
- break;
- }
- if (event.id == deviceId || event.name == deviceName || (deviceName != null && event.name.contains(deviceName))) {
- device = event;
- break;
- }
- }
- timeout.cancel();
- print('bluetooth -- found: ${device?.id} ${device?.name}');
- return device;
- }
- Future<int> discoverServices(FlutterReactiveBle flutterReactiveBle, String deviceId) async {
- int result = 0;
- for (var i = 0; i < 3; i++) {
- bool findWrite = false;
- bool findRead = false;
- try {
- var services = await flutterReactiveBle.discoverServices(deviceId);
- for (DiscoveredService service in services) {
- for (var characteristic in service.characteristics) {
- if (characteristic.isWritableWithoutResponse) {
- characteristicWrite = QualifiedCharacteristic(serviceId: service.serviceId, characteristicId: characteristic.characteristicId, deviceId: deviceId);
- findWrite = true;
- }
- if (characteristic.isNotifiable) {
- characteristicNotify = QualifiedCharacteristic(serviceId: service.serviceId, characteristicId: characteristic.characteristicId, deviceId: deviceId);
- findRead = true;
- }
- }
- }
- } catch (e) {
- print(e);
- print("bluetooth -- service error $e");
- }
- deviceWriteNotifier.value = findWrite;
- deviceReadNotifier.value = findRead;
- if (findWrite && findRead) {
- print("bluetooth -- service write: $findWrite, read: $findRead");
- result = 3;
- break;
- } else {
- await Future.delayed(Duration(seconds: 2));
- if (findWrite) {
- result = 1;
- } else if (findRead) {
- result = 2;
- }
- }
- }
- return result;
- }
- _query() async {
- queryDeviceInfo();
- queryDeviceStep();
- queryDeviceCharge();
- queryDeviceData();
- }
- _connected(DiscoveredDevice newDevice) async {
- print("bluetooth -- connected: $newDevice");
- deviceNotifier.value = newDevice;
- _dfuController.add(false);
- _online = true;
- _partInfo = null;
- if ((startTime?.difference(DateTime.now()).inHours ?? 1) > 0) {
- notifyConnected();
- startTime = DateTime.now();
- }
- setupGameMode4h5(h5gameRNotifier.value);
- runTimer();
- }
- notifyConnectTime(String tag) {
- int now = DateTime.now().millisecondsSinceEpoch;
- Map<String, int> result = Map.from(timeUseNotifier.value);
- // print("111111111111111111 ${now} ${timeUse}");
- result[tag] = now - (timeUse.isNotEmpty ? timeUse.last : now);
- timeUseNotifier.value = result;
- timeUse.add(now);
- }
- notifyConnected() {
- this.vibrate(200);
- this.lighting(10000);
- }
- checkUpdate() async {
- var info = infoNotifier.value;
- print("bluetooth -- checkUpdate ${info}");
- if (info.isEmpty == true) return;
- if (h5gameRNotifier.value == true) return;
- String softwareVer = info['softwareVer'];
- String hardwareVer = info['hardwareVer'];
- List<String> device = info['device'];
- PackageInfo packageInfo = await PackageInfo.fromPlatform();
- String appVer = packageInfo.version;
- Hardware? updateInfo = (await GetIt.I<RestClient>().checkHardwareUpdate(hardwareVer, appVer)).data;
- if (updateInfo != null) {
- // PackageInfo packageInfo = await PackageInfo.fromPlatform();
- // if (updateInfo.min_app_ver?.isNotEmpty == true && versionCompare(packageInfo.version, updateInfo.min_app_ver ?? "0") < 0) {
- // debugPrint("bluetooth -- dfu update app ver ${packageInfo.version} min ${updateInfo.min_app_ver}");
- // return;
- // }
- // if (updateInfo.max_app_ver?.isNotEmpty == true && versionCompare(packageInfo.version, updateInfo.max_app_ver ?? "0") > 0) {
- // debugPrint("bluetooth -- dfu update app ver ${packageInfo.version} max ${updateInfo.max_app_ver}");
- // return;
- // }
- //
- // if (updateInfo.min_hardware_ver?.isNotEmpty == true && versionCompare(hardwareVer, updateInfo.min_hardware_ver ?? "0") < 0) {
- // debugPrint("bluetooth -- dfu update hardware ver ${hardwareVer} min ${updateInfo.min_hardware_ver}");
- // return;
- // }
- //
- // if (updateInfo.max_hardware_ver?.isNotEmpty == true && versionCompare(hardwareVer, updateInfo.max_hardware_ver ?? "0") > 0) {
- // debugPrint("bluetooth -- dfu update hardware ver ${hardwareVer} max ${updateInfo.max_hardware_ver}");
- // return;
- // }
- updateInfo.devices = [];
- updateInfo.localVer = softwareVer;
- print("bluetooth -- dfu versionCompare ${versionCompare(softwareVer, updateInfo.ver ?? "0.0")}");
- bool cancelable = this.testDfu >= 5 ? true : !isDebugShoe;
- if (this.testDfu >= 5) {
- } else {
- final testVersion = "梁剑波<font color=\"red\">DEBUG专用</font>";
- bool willTest = updateInfo.name == testVersion;
- if (willTest) {
- if (versionCompare(softwareVer, updateInfo.ver ?? "0.0") == 0) return;
- } else {
- if (versionCompare(softwareVer, updateInfo.ver ?? "0.0") >= 0) {
- return;
- }
- }
- }
- for (var i = device.length - 1; i >= 0; i--) {
- updateInfo.devices!.add(device[i]);
- }
- verNotifier.value = updateInfo;
- if (h5gameRNotifier.value == true) return;
- var context = _context;
- var value = updateInfo;
- var closeable = 0;
- var result = await showDialog(
- context: context,
- barrierDismissible: false,
- builder: (context) => CustomAlertDialog(
- title: '发现新的鞋子固件',
- child: WillPopScope(
- onWillPop: () async {
- return false;
- },
- child: GestureDetector(
- behavior: HitTestBehavior.opaque,
- onTap: () {
- closeable++;
- if (closeable >= 5) {
- Navigator.of(context).pop(false);
- }
- },
- child: Container(
- width: double.infinity,
- padding: const EdgeInsets.symmetric(horizontal: 24.0),
- child: Text(
- "${value.name}\n${value.localVer} -> ${value.ver}\n${value.msg}",
- style: TextStyle(fontSize: 14, color: Color(0xff333333), height: 1.8),
- )),
- ),
- ),
- textOk: '立即升级',
- cancelable: cancelable,
- ok: () => Navigator.of(context).pop(true)),
- );
- if (result != true) return;
- _dfuController.add(true);
- await Future.delayed(Duration(seconds: 1));
- result = await showDialog(
- context: context,
- barrierDismissible: false,
- builder: (context) => SimpleDialog(
- children: <Widget>[
- DfuUpdatePage(
- hardware: value,
- version: "${value.ver}",
- )
- ],
- ));
- }
- }
- void parse(List<int> event) {
- if (event.isEmpty == true) return;
- if (!_listen) return;
- ByteDataReader reader = ByteDataReader();
- reader.add(event);
- int flagAA = reader.readUint8();
- // int flagBB = reader.readUint8();
- // int flagCC = reader.readUint8();
- int len = reader.readUint8();
- int len1 = 0xFF - reader.readUint8();
- // int index = reader.readUint8();
- int cmd = reader.readUint8();
- // print(" change --> ${flagAA} ${len} ${~len} ${cmd}");
- // print(" change --> ${len} ${~len} ${len1}");
- // print(" change --> ${index} ${cmd}");
- if (!(flagAA == 0xAA)) return;
- if (len != len1) return;
- Uint8List byteArray = reader.read(event.length - 5);
- int ver = 0;
- for (int i = 0; i < event.length - 1; i++) {
- ver += event[i];
- }
- if (ver.toUnsigned(8) != event[event.length - 1]) return;
- parseCmd(cmd, byteArray);
- }
- void parseCmd(int cmd, Uint8List byteArray) {
- // if (isDebugShoe) print(" cmd $cmd data --> $byteArray");
- switch (cmd) {
- case 0x01:
- _parseAction(byteArray);
- break;
- case BLE.BLE_Client_T_MOTION:
- disconnectTimes = 0;
- if (appLifecycleState == AppLifecycleState.resumed) {
- sdk.gameProcess(byteArray);
- int cmd = sdk.getInteractionCMD();
- if (cmd > -1) {
- _sdkCmdController.add(cmd);
- }
- String gameData = sdk.getGameDataStr();
- _sdkMotionDataController.add(gameData);
- if (isDebugShoe) {
- // print("gameDate $gameData");
- writeLog(gameData);
- }
- List<int> result = sdk.getMotion();
- if (result.any((element) => element > 0)) {
- if (isDebugShoe) print("sdk -- motion $result");
- _sdkMotionController.add(result);
- }
- _dataController.add(byteArray);
- }
- break;
- case 0xA0:
- break;
- case BLE.BLE_Client_T_UPDATE:
- _parseQuery(byteArray);
- break;
- case BLE.BLE_Client_T_CONNET_R:
- _connectRightController.add(byteArray.first);
- break;
- case BLE.BLE_Client_T_REALTIMESTEP:
- _parseStepRealtime(byteArray);
- break;
- case BLE.BLE_Client_T_DFU:
- if (_completerSetupDeviceVer?.isCompleted != true) _completerSetupDeviceVer?.complete(true);
- break;
- case BLE.BLE_Client_T_CHARGE: //充电
- _parseCharge(byteArray);
- break;
- case BLE.BLE_Client_T_ERR: //异常
- _parseErr(byteArray);
- break;
- case BLE.BLE_Client_T_GAMEMODE:
- break;
- case BLE.BLE_Client_T_CONNECT_CONFIRM:
- _parseConnectConfirm(byteArray);
- break;
- }
- }
- void _parseConnectConfirm(Uint8List byteArray) {
- ByteDataReader reader = ByteDataReader();
- reader.add(byteArray);
- int state = reader.readUint8();
- }
- void _parseAction(Uint8List byteArray) {
- ByteDataReader reader = ByteDataReader();
- reader.add(byteArray);
- int action = reader.readUint8();
- int t = reader.readUint16();
- print("action: $action ");
- actionNotifier.value = action;
- }
- void _parseQuery(Uint8List byteArray) {
- ByteDataReader reader = ByteDataReader();
- reader.add(byteArray);
- int cmd = reader.readUint8();
- if (cmd != BLE_UPDATE.BASIC) {
- // 右鞋没连上,不处理下面的流程
- if (_isRightError != 1) return;
- }
- switch (cmd) {
- case BLE_UPDATE.BASIC: // 设备基本信息
- Map<String, dynamic> info = {};
- List<int> name = [];
- for (var i = 0; i < 64; i++) {
- name.add(reader.readUint8());
- }
- info['name'] = String.fromCharCodes(name).replaceAll("\u0000", "");
- List<int> softwareVer = [];
- List<int> hardwareVer = [];
- List<String> device = [];
- for (var i = 0; i < 2; i++) {
- List<String> macList = [];
- for (var j = 0; j < 6; j++) {
- macList.add(reader.readUint8().toRadixString(16).padLeft(2, "0"));
- }
- var mac = macList.join(":").toUpperCase();
- print("mac $i = $mac");
- for (var k = 0; k < 4; k++) {
- hardwareVer.add(reader.readUint8());
- }
- softwareVer.add(reader.readUint16());
- device.add(mac);
- }
- print("bluetooth dfu info $hardwareVer $softwareVer");
- if (hardwareVer.length != 8 || softwareVer.length != 2) return;
- String leftHardware = hardwareVer.sublist(1, 4).join(".");
- String rightHardware = hardwareVer.sublist(4 + 1, hardwareVer.length).join(".");
- int compareHardware = versionCompare(leftHardware, rightHardware);
- String minHardwareVersion = compareHardware < 0 ? leftHardware : rightHardware;
- print("bluetooth hardwareVer $leftHardware $rightHardware $compareHardware $minHardwareVersion");
- String leftSoftware = hardwareVer.sublist(1, 3).join(".") + ".${softwareVer[0]}";
- String rightSoftware = hardwareVer.sublist(4 + 1, 4 + 1 + 2).join(".") + ".${softwareVer[1]}";
- int compareSoftware = versionCompare(leftSoftware, rightSoftware);
- String minSoftwareVersion = compareSoftware < 0 ? leftSoftware : rightSoftware;
- print("bluetooth softwareVer $leftSoftware $rightSoftware $compareSoftware $minSoftwareVersion");
- shoeVersion = "$minSoftwareVersion";
- info['softwareVer'] = minSoftwareVersion;
- info['hardwareVer'] = minHardwareVersion;
- info['mac'] = device.length > 1 ? device.first : "";
- info['device'] = device;
- infoNotifier.value = info;
- if (versionNotifier.value != minSoftwareVersion) {
- versionNotifier.value = minSoftwareVersion;
- checkUpdate();
- }
- if (_uploadLoged != true) {
- _uploadLoged = true;
- _uploadLog();
- _uploadErr();
- }
- break;
- case BLE_UPDATE.DATA: // 设备数据(左鞋,右鞋)
- Map<String, dynamic> info = {};
- for (var i = 0; i < 2; i++) {
- info['${i}_electricity'] = reader.readUint8();
- info['${i}_temperature'] = reader.readUint8();
- info['${i}_pressure'] = reader.readUint(4);
- reader.readUint(4);
- }
- if (reader.remainingLength >= 4) {
- info['0_adc'] = reader.readUint16();
- info['1_adc'] = reader.readUint16();
- }
- // [170, 187, 204, 23, 232, 0, 161, 1, 50, 0, 33, 0, 0, 156, 41, 51, 0, 34, 0, 0, 150, 19, 232]
- dataNotifier.value = info;
- int electricity = min(info['0_electricity'] ?? 0, info['1_electricity'] ?? 0);
- electricityNotifier.value = electricity;
- if (electricity <= 10) {
- if (electricityTime == null || (electricityTime?.difference(DateTime.now()).inMinutes.abs() ?? 0) >= 60) {
- if (stateNotifier.value.values.every((element) => element > 1) != true) {
- ToastUtil.show("鞋子电量不足,请及时充电!");
- electricityTime = DateTime.now();
- }
- }
- }
- if (isDebugShoe) {
- _testElectricity(info);
- }
- break;
- case BLE_UPDATE.STEP: // 查询步数
- print("bluetooth -- step part ${_partInfo?.ready}");
- if (_partInfo == null) return;
- if (_partInfo?.ready == true) return;
- if (isDebugShoe) {
- _testStep(byteArray.toList().join(","));
- print("bluetooth -- step data ${byteArray.toList().join(",")}");
- }
- int start = reader.readUint64();
- int serialCount = reader.readUint16();
- int serial = reader.readUint16();
- // if(serialCount == 0){
- // _completerStep?.complete(false);
- // return;
- // }
- List<int> data = [];
- while (reader.remainingLength > 0) {
- data.add(reader.readUint32());
- }
- if (serial == 0 && data.isNotEmpty) {
- stepTotalNotifier.value = data.last;
- }
- _partInfo!.start = start;
- _partInfo!.serialCount = serialCount + 1;
- _partInfo!.data[serial] = data;
- if (isDebugShoe) print("bluetooth -- step start $start ${DateTime.fromMillisecondsSinceEpoch(start)} read ($serial,$serialCount) --> $data");
- if (_partInfo!.data.length == _partInfo!.serialCount) {
- _partInfo!.ready = true;
- var partResult = _partInfo!;
- Future.microtask(() async {
- await partResult.prepare();
- print("bluetooth -- step end ... ");
- if (_completerStep?.isCompleted != true) _completerStep?.complete(true);
- });
- }
- break;
- case BLE_UPDATE.STEP_DELETE: // 步数回调
- if (_completerStepDel != null) _completerStepDel!.complete(true);
- break;
- }
- }
- void _parseStepRealtime(Uint8List byteArray) {
- ByteDataReader reader = ByteDataReader();
- reader.add(byteArray);
- int cmd = reader.readUint8();
- if (cmd == 0) {
- } else if (cmd == 1) {
- int left = 0;
- int right = 0;
- if (reader.remainingLength > 4) {
- left = reader.readUint32();
- right = reader.readUint32();
- } else {
- left = reader.readUint16();
- right = reader.readUint16();
- }
- // print("left: ${left}, right: ${ right} = ${step}");
- stepRealtimeNotifier.value = [left, right];
- // 已经不是在实时计步页面,但还收到数据,关了!
- if (stepRealtimePageNotifier.value == false) {
- write(BLE.BLE_Client_T_REALTIMESTEP, Uint8List.fromList([BLE_CODE_0]));
- }
- }
- }
- void _parseCharge(Uint8List byteArray) async {
- ByteDataReader reader = ByteDataReader();
- reader.add(byteArray);
- int cmd = reader.readUint8();
- int state = reader.readUint8();
- Map<int, int> _state = Map.from(stateNotifier.value);
- _state.update(cmd, (value) => state);
- stateNotifier.value = _state;
- // print("111111111111111111111111 $_state");
- if (_state[0]! <= 1 || _state[1]! <= 1) {
- if (_showChargeDialog == true) {
- Navigator.maybePop(_context);
- }
- return;
- }
- if (_state[0] == 3 && _state[1] == 3) {
- queryDeviceData();
- }
- if (_state[0]! > 1 && _state[1]! > 1 && _showChargeDialog != true) {
- _showChargeDialog = true;
- showDialog(
- context: _context,
- barrierColor: Colors.transparent,
- builder: (context) => SimpleDialog(
- backgroundColor: Colors.transparent,
- elevation: 0,
- children: [
- Center(
- child: Container(
- constraints: BoxConstraints(maxWidth: 180.0),
- decoration: BoxDecoration(
- borderRadius: BorderRadius.all(Radius.circular(10.0)),
- color: Colors.black.withOpacity(.75),
- ),
- child: Column(
- mainAxisSize: MainAxisSize.min,
- children: [
- Align(
- child: GestureDetector(
- child: Padding(
- padding: const EdgeInsets.all(10.0),
- child: Image.asset(
- "lib/assets/img/btn_close_white.png",
- width: 18,
- ),
- ),
- onTap: () {
- Navigator.maybePop(context);
- },
- behavior: HitTestBehavior.opaque,
- ),
- alignment: Alignment.topRight,
- ),
- Padding(
- padding: const EdgeInsets.fromLTRB(20.0, 5, 20.0, 16.0),
- child: ValueListenableBuilder<Map<int, int>>(
- valueListenable: stateNotifier,
- builder: (context, val, __) {
- int totalState = (val[0]! + val[1]!) ~/ 2;
- List<int> keys = val.keys.toList();
- keys.sort();
- return Column(
- children: [
- Center(
- child: Row(
- children: keys.map((key) {
- int state = val[key]!;
- String label = key == 0 ? "left" : "right";
- return Padding(
- padding: EdgeInsets.symmetric(horizontal: 10),
- child: Image.asset(
- state == 3
- ? "lib/assets/img/pop_icon_${label}full.png"
- : state == 2
- ? "lib/assets/img/pop_icon_${label}charge.png"
- : "lib/assets/img/pop_icon_${label}fault.png",
- ),
- );
- }).toList(),
- mainAxisSize: MainAxisSize.min,
- ),
- ),
- const SizedBox(
- height: 15,
- ),
- ValueListenableBuilder(
- valueListenable: electricityNotifier,
- builder: (BuildContext context, int value, Widget? child) {
- int _power = max(0, (val[0]! > 1 && val[1]! > 1) ? value : 0);
- return Column(
- children: [
- Text(
- (_power > 1) ? "$_power%" : "",
- style: TextStyle(fontSize: 8.0, color: Colors.white),
- ),
- const SizedBox(
- height: 7,
- ),
- ClipRRect(
- child: SizedBox(
- height: 2,
- child: LinearProgressIndicator(
- backgroundColor: Color(0xff656565),
- valueColor: AlwaysStoppedAnimation(Color(0xff00DC42)),
- value: _power / 100,
- ),
- ),
- borderRadius: BorderRadius.circular(5),
- )
- ],
- );
- },
- ),
- const SizedBox(
- height: 11,
- ),
- Text(
- (val[0] == 3 && val[1] == 3)
- ? "智能鞋充电已完成"
- : (val[0]! > 1 && val[1]! > 1)
- ? "智能鞋充电中..."
- : (val[0]! <= 1 && val[1]! <= 1)
- ? "智能鞋连接异常"
- : val[0]! <= 1
- ? "左鞋充电连接异常"
- : val[1]! <= 1
- ? "右鞋充电连接异常"
- : "连接异常",
- style: TextStyle(fontSize: 12.0, color: Colors.white),
- ),
- ],
- );
- }),
- ),
- ],
- )),
- )
- ],
- )).then((value) => _showChargeDialog = false);
- }
- Future.delayed(Duration(seconds: 5)).then((value) {
- if (_showChargeDialog == true) {
- Map<int, int> val = stateNotifier.value;
- print("_parseCharge $val");
- if (val[0]! > 1 && val[1]! > 1) {
- Navigator.pop(_context);
- }
- }
- });
- }
- Map<String, Map<String, String?>> errQueue = {};
- /// 错误处理
- void _parseErr(Uint8List byteArray) async {
- ByteDataReader r = ByteDataReader();
- r.add(byteArray);
- int leftOrRight = r.readUint8();
- int code = r.readUint8();
- List<int> msgData = r.read(r.remainingLength);
- String msg = String.fromCharCodes(msgData);
- String err = "${leftOrRight == 0 ? "左鞋" : "右鞋"}:$msg";
- addErr("$code", err, "");
- }
- void _uploadErr() async {
- // if (infoNotifier.value.isEmpty) return;
- if (errQueue.isEmpty) return;
- var info = infoNotifier.value;
- // if (info.isEmpty) return;
- PackageInfo packageInfo = await PackageInfo.fromPlatform();
- String mac = info['mac']?.toString() ?? _connectingDevice?.id ?? _deviceId ?? "00:00:00:00:00:00";
- String firmware = "${info['softwareVer']}";
- String hardware = "${info['hardwareVer']}";
- String app_ver = "${packageInfo.version}";
- List<String> keys = errQueue.keys.toList();
- for (var i = 0; i < keys.length; i++) {
- String code = keys[i];
- Map<String, String?> err = errQueue[code] as Map<String, String?>;
- String? message = err["message"];
- String? detail = err["detail"];
- if (isDebugShoe) {
- await _testErrLog();
- }
- var resp = await api.logHardwareErr(mac, firmware, hardware, app_ver, code, "$message", "$detail ${await Application.getDeviceInfo()}");
- if (resp.code != 0) {
- await Future.delayed(Duration(seconds: 2));
- }
- }
- }
- addErr(String code, String? message, String? detail) {
- if (isDebugShoe) {
- print("bluetooth -- err $code $message $detail");
- }
- if (!errQueue.containsKey(code)) {
- errQueue[code] = {"code": code, "message": message, "detail": detail};
- _uploadErr();
- }
- }
- Future _saveInfo(PartInfo? partInfo) async {
- if (partInfo == null) return;
- print("bluetooth -- step save ${partInfo.start} ${partInfo.serialCount} ${partInfo.items.length}");
- if (partInfo.items.isEmpty == true) return;
- List<PartItem> _items = [];
- for (var item in partInfo.items) {
- _items.add(item);
- print("bluetooth -- step save ${item.time} ${item.step}");
- }
- await StepDB().insertAll(_items);
- _queryController.add(true);
- }
- Future<int> _uploadInfo(int startTime) async {
- final now = DateTime.fromMillisecondsSinceEpoch(startTime);
- final offset = DateTime(now.year, now.month, now.day, now.hour);
- var list = await StepDB().find(offset.millisecondsSinceEpoch, _deviceId ?? "0");
- if (list.isEmpty) return 0;
- List<List<int>> data = [];
- int step = 0;
- for (var item in list) {
- int _step = Converter.toInt(item['st']);
- if (_step > 0 && _step < 10000000) {
- data.add([_step, item['di'], (item['time'] as int) ~/ 1000]);
- }
- step += Converter.toInt(_step);
- }
- print("bluetooth -- step upload ${offset.millisecondsSinceEpoch} $startTime $data");
- if (step > 5) {
- var resp = await api.addDaily(data: json.encode(data));
- if (resp.code == 0) {
- // await StepDB().delete(last);
- return 0;
- }
- }
- return step == 0 ? 0 : -1;
- // Directory appDocDir = await getApplicationDocumentsDirectory();
- // String appDocPath = appDocDir.path;
- // Directory saveDir = Directory("$appDocPath/step");
- // var files = saveDir.listSync();
- // for(var file in files){
- // var f= new File(file.path);
- // var content = f.readAsStringSync();
- // await api.addDaily(data: content);
- // file.delete();
- // }
- }
- // 查询 设备基本信息
- Future queryDeviceCharge() async {
- await write(BLE.BLE_Client_T_CHARGE, Uint8List(0));
- }
- // 查询 设备右鞋
- Future queryDeviceRight() async {
- await write(BLE.BLE_Client_T_CONNET_R, Uint8List.fromList([]));
- }
- // 查询 设备基本信息
- Future queryDeviceInfo() async {
- await write(BLE.BLE_Client_T_UPDATE, Uint8List.fromList([BLE_CODE_0]));
- }
- // 查询 设备数据
- Future queryDeviceData() async {
- await write(BLE.BLE_Client_T_UPDATE, Uint8List.fromList([BLE_CODE_1]));
- }
- // 查询 查询步数
- Future queryDeviceStep({bool test = false}) async {
- if (!isConnected) return;
- // await Future.delayed(Duration(seconds: 3));
- // _queryController.add(true);
- if (test != true) if (stepTotalTestNotifier.value == 1) return;
- if (_partInfo != null) {
- print("bluetooth -- step _partInfo.now ${_partInfo!.now.difference(DateTime.now()).inSeconds}");
- if ((_partInfo!.now.difference(DateTime.now()).inSeconds) > -60) {
- return;
- }
- }
- print("bluetooth -- step init");
- _partInfo = PartInfo(_deviceId ?? "0", 0, 0);
- if (test == true) stepTotalNotifier.value = -1;
- // await write(BLE.BLE_Client_T_UPDATE, createTime(BLE_UPDATE.STEP));
- DateTime now = DateTime.now();
- DateTime offset = DateTime(now.year, now.month, now.day, now.hour);
- print("bluetooth -- create now .. $now - $offset (${offset.millisecondsSinceEpoch})");
- ByteDataWriter writer = ByteDataWriter();
- writer.writeUint8(BLE_UPDATE.STEP);
- writer.writeUint16(BLE_CODE_0);
- writer.writeUint64(now.millisecondsSinceEpoch);
- await write(BLE.BLE_Client_T_UPDATE, writer.toBytes());
- if (_completerStep != null && _completerStep?.isCompleted != true) _completerStep?.complete(false);
- if (_completerStepDel != null && _completerStepDel?.isCompleted != true) _completerStepDel?.complete(false);
- _completerStep = Completer();
- _completerStepDel = Completer();
- var timer = Timer.periodic(Duration(seconds: 1), (timer) {
- if (_partInfo == null) return;
- Iterable<int> keys = _partInfo!.data.keys;
- if (keys.isEmpty) return;
- for (var i = 1; i < _partInfo!.serialCount; i++) {
- if (!keys.contains(i)) {
- print("bluetooth -- step request package $i");
- // 请求缺包
- ByteDataWriter writer = ByteDataWriter();
- writer.writeUint8(BLE_UPDATE.STEP);
- writer.writeUint16(i);
- writer.writeUint64(now.millisecondsSinceEpoch);
- write(BLE.BLE_Client_T_UPDATE, writer.toBytes());
- }
- }
- });
- Timer timeout = Timer(Duration(seconds: 20), () {
- if (_completerStep?.isCompleted != true) _completerStep?.complete(false);
- });
- var result = await _completerStep!.future;
- timeout.cancel();
- timer.cancel();
- int stepTotal = 0;
- if (result == true) {
- await _saveInfo(_partInfo);
- int code = await _uploadInfo(_partInfo!.start);
- if (code != 0) {
- code = _partInfo!.items.length;
- }
- if (isDebugShoe) {
- var now = DateTime.now();
- _partInfo?.items.forEach((element) {
- var info = {"t": element.time, "s": element.step, "total": element.absolute};
- _testStep("$_deviceId,${now.hour},${now.minute},${now.second},${info['t']},${info['s']},${info['total']}");
- });
- }
- if (test == true) {
- if (_partInfo?.items.isNotEmpty == true) {
- stepTotal = _partInfo?.items.map((e) => e.step).reduce((value, element) => value + element) ?? 0;
- } else {
- stepTotal = 0;
- }
- }
- if (code == 0) {
- var timer = Timer.periodic(Duration(milliseconds: 1000), (timer) {
- write(BLE.BLE_Client_T_UPDATE, createTime(BLE_UPDATE.STEP_DELETE));
- if (_isRightError != 1) {
- timer.cancel();
- if (_completerStepDel?.isCompleted != true) _completerStepDel?.complete(false);
- }
- });
- Timer timeout = Timer(Duration(seconds: 60), () {
- if (_completerStepDel?.isCompleted != true) _completerStepDel?.complete(false);
- });
- await _completerStepDel!.future;
- timer.cancel();
- timeout.cancel();
- }
- _completerStepDel = null;
- }
- _partInfo = null;
- print("bluetooth -- step reset");
- stepNotifier.value = stepTotal;
- }
- // 固件升级
- Future<bool> setupDeviceVer(int type) async {
- _completerSetupDeviceVer = Completer();
- int time = 10;
- Timer timeout = Timer.periodic(Duration(seconds: 1), (t) {
- try {
- write(BLE.BLE_Client_T_DFU, Uint8List.fromList([type]));
- } catch (e) {
- print(e);
- }
- time--;
- if (time < 0) {
- if (_completerSetupDeviceVer?.isCompleted != true) _completerSetupDeviceVer?.complete(false);
- t.cancel();
- }
- });
- var result = (await _completerSetupDeviceVer?.future) ?? false;
- timeout.cancel();
- return result;
- }
- // 游戏模式
- Future setupGameMode(bool mode) async {
- if (mode == false && h5gameRNotifier.value == true) {
- return;
- }
- print("=================================setupGameMode $mode=================================");
- gameModeTimer?.cancel();
- if (mode) {
- gameModeTimer = Timer.periodic(Duration(seconds: 30), (timer) {
- if (this._listen == true) write(BLE.BLE_Client_T_GAMEMODE, Uint8List.fromList([BLE_CODE_1]));
- });
- }
- await write(BLE.BLE_Client_T_GAMEMODE, mode ? Uint8List.fromList([BLE_CODE_1]) : Uint8List.fromList([BLE_CODE_0]));
- }
- Future setupGameMode4h5(bool mode) async {
- h5gameRNotifier.value = mode;
- setupGameMode(mode);
- }
- Future setupDataDebug(bool mode) async {
- await write(BLE.BLE_Client_T_GAMEMODE, mode ? Uint8List.fromList([BLE_CODE_1 + 1]) : Uint8List.fromList([BLE_CODE_0]));
- //
- // device?.rssi.listen((event) {
- // rssiNotifier.value = event;
- // });
- //
- // rssiTimer?.cancel();
- // if (mode == true) {
- // rssiTimer = Timer.periodic(Duration(seconds: 1), (timer) {
- // device?.requestRssi();
- // });
- // }
- }
- Future vibrate(int vibrate, {int leftOrRight = 0}) async {
- int duration = min(1000, max(100, vibrate));
- ByteDataWriter writer = ByteDataWriter();
- writer.writeUint16(duration);
- writer.writeUint8(leftOrRight);
- await write(BLE.BLE_Client_T_SHOCK, writer.toBytes());
- }
- Future lighting(int time) async {
- int duration = min(10000, max(100, time));
- ByteDataWriter writer = ByteDataWriter();
- writer.writeUint16(duration);
- await write(BLE.BLE_Client_T_LIGHTING, writer.toBytes());
- }
- Future stepRealTime(bool mode) async {
- stepRealtimeNotifier.value = [];
- stepRealtimePageNotifier.value = mode;
- await write(BLE.BLE_Client_T_REALTIMESTEP, mode ? Uint8List.fromList([BLE_CODE_1]) : Uint8List.fromList([BLE_CODE_0]));
- stepRealTimeTimer?.cancel();
- if (mode == true) {
- stepRealTimeTimer = Timer.periodic(Duration(seconds: 10), (timer) {
- write(BLE.BLE_Client_T_REALTIMESTEP, Uint8List.fromList([BLE_CODE_1]));
- });
- }
- }
- Uint8List createTime(int cmd) {
- DateTime now = DateTime.now();
- DateTime offset = DateTime(now.year, now.month, now.day, now.hour);
- print("bluetooth -- create now .. $now - $offset (${offset.millisecondsSinceEpoch})");
- ByteDataWriter writer = ByteDataWriter();
- writer.writeUint8(cmd);
- writer.writeUint64(offset.millisecondsSinceEpoch);
- writer.writeUint8(max(0, min(60, now.minute - offset.minute)));
- return writer.toBytes();
- }
- Future write(int cmd, Uint8List data, {int test = 5}) async {
- if (characteristicWrite == null) return;
- int length = data.length + 5;
- ByteDataWriter writer = ByteDataWriter();
- writer.writeUint8(0xAA);
- // writer.writeUint8(0xBB);
- // writer.writeUint8(0xCC);
- writer.writeUint8(length);
- writer.writeUint8(0xFF - length);
- // writer.writeUint8(0x00);
- writer.writeUint8(cmd);
- if (data.isNotEmpty) writer.write(data);
- int ver = writer.toBytes().reduce((value, element) => value + element);
- writer.writeUint8(ver);
- Uint8List out = writer.toBytes();
- if (isDebugShoe) {
- print("bluetooth -- out ${cmd.toRadixString(16).padLeft(2, "0")} ${out.map((e) => e.toRadixString(16).padLeft(2, "0")).join(" ").toUpperCase()}");
- }
- // print("out ${out.map((e) => e.toRadixString(16)).join(",")}");
- for (var i = 0; i < test; i++) {
- try {
- await flutterReactiveBle.writeCharacteristicWithoutResponse(characteristicWrite!, value: out);
- break;
- } catch (e) {
- print(e);
- await Future.delayed(Duration(milliseconds: 100));
- }
- }
- }
- Future writeUintList(Uint8List data) async {
- if (characteristicWrite == null) return;
- int length = data.length + 4;
- ByteDataWriter writer = ByteDataWriter();
- writer.writeUint8(0xAA);
- // writer.writeUint8(0xBB);
- // writer.writeUint8(0xCC);
- writer.writeUint8(length);
- writer.writeUint8(0xFF - length);
- // writer.writeUint8(0x00);
- if (data.isNotEmpty) writer.write(data);
- int ver = writer.toBytes().reduce((value, element) => value + element);
- writer.writeUint8(ver);
- Uint8List out = writer.toBytes();
- if (isDebugShoe) {
- print("bluetooth -- out ${out.map((e) => e.toRadixString(16).padLeft(2, "0")).join(" ").toUpperCase()}");
- }
- for (var i = 0; i < 5; i++) {
- try {
- await flutterReactiveBle.writeCharacteristicWithoutResponse(characteristicWrite!, value: out);
- break;
- } catch (e) {
- print(e);
- await Future.delayed(Duration(milliseconds: 100));
- }
- }
- }
- _uploadLog() async {
- var info = infoNotifier.value;
- if (info.isEmpty == true) return;
- final api = GetIt.I<RestClient>();
- PackageInfo packageInfo = await PackageInfo.fromPlatform();
- String os_name = Platform.operatingSystem;
- String os_ver = Platform.operatingSystemVersion;
- String phone_brand = "";
- String phone_model = "";
- try {
- DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
- if (Platform.isAndroid) {
- AndroidDeviceInfo androidDeviceInfo = await deviceInfo.androidInfo;
- phone_brand = androidDeviceInfo.brand;
- phone_model = androidDeviceInfo.model;
- } else if (Platform.isIOS) {
- IosDeviceInfo iosDeviceInfo = await deviceInfo.iosInfo;
- phone_brand = iosDeviceInfo.model;
- phone_model = iosDeviceInfo.utsname.machine;
- }
- } catch (e) {
- print(e);
- }
- api.onConnBt("${info['mac']}", "${info['softwareVer']}", "${info['hardwareVer']}", "${packageInfo.version}+${packageInfo.buildNumber}", os_name, os_ver, "${locale?.languageCode}", phone_brand, phone_model).then((value) => _uploadLoged = true);
- }
- _testErrLog() async {
- Directory? dir = Platform.isAndroid ? await getExternalStorageDirectory() : await getTemporaryDirectory();
- if (dir != null) {
- var now = DateTime.now();
- File file = File("${dir.path}/shoe/err_${now.year}_${now.month}_${now.day}.csv");
- print("log file: $file $errQueue");
- if (!file.parent.existsSync()) {
- file.parent.createSync();
- }
- errQueue.forEach((k, v) {
- file.writeAsStringSync("$k, $v\n", mode: FileMode.append, flush: true);
- });
- }
- }
- void _testElectricity(Map<String, dynamic> info) async {
- Directory? dir = Platform.isAndroid ? await getExternalStorageDirectory() : await getTemporaryDirectory();
- if (dir != null) {
- var now = DateTime.now();
- File file = File("${dir.path}/shoe/electricity_${now.year}_${now.month}_${now.day}.csv");
- print("log file: $file");
- if (!file.parent.existsSync()) {
- file.parent.createSync();
- }
- file.writeAsStringSync("${now.hour},${now.minute},${now.second},${info['0_electricity']},${info['1_electricity']},${info['0_adc']},${info['1_adc']},${_connectingDevice?.name ?? deviceId}\n", mode: FileMode.append, flush: true);
- }
- }
- void _testStep(String line) async {
- Directory? dir = Platform.isAndroid ? await getExternalStorageDirectory() : await getTemporaryDirectory();
- if (dir != null) {
- var now = DateTime.now();
- File file = File("${dir.path}/shoe/step_${now.year}_${now.month}_${now.day}.csv");
- print("log file: $file");
- if (!file.parent.existsSync()) {
- file.parent.createSync();
- }
- file.writeAsStringSync("$line\n", mode: FileMode.append, flush: true);
- }
- }
- void updateName(String name) {
- DiscoveredDevice? device = deviceNotifier.value;
- if (device != null) {
- String newName = name.isNotEmpty ? name : device.name;
- BluetoothDB().insert(device, mark: newName).then((value) {
- deviceNameNotifier.value = newName;
- });
- }
- }
- }
- class PartItem {
- String shoe;
- int step;
- int distance;
- int absolute;
- int time;
- PartItem(this.shoe, this.step, this.absolute, this.distance, this.time);
- Map<String, dynamic> toJson() {
- final Map<String, dynamic> data = new Map<String, dynamic>();
- data['shoe'] = this.shoe;
- data['step'] = this.step;
- data['absolute'] = this.absolute;
- data['distance'] = this.distance;
- data['time'] = this.time;
- return data;
- }
- }
- class PartInfo {
- String shoeId;
- int start;
- int serial = 0;
- int serialCount;
- List<PartItem> items = [];
- late DateTime now;
- late DateTime maxTime;
- late Map<int, List<int>> data;
- bool ready = false;
- PartInfo(this.shoeId, this.start, this.serialCount) {
- now = DateTime.now();
- maxTime = DateTime(now.year, now.month, now.day, now.hour);
- data = {};
- }
- final int offset = 60 * 60 * 1000;
- prepare() async {
- print("bluetooth -- step prepare ... ");
- if (data.isEmpty) return;
- if (start == 0) return;
- var current = data[0] ?? [];
- if (current.isEmpty) return;
- int currentStep = current.first;
- print("bluetooth -- step current ... $currentStep");
- if (currentStep >= 2147483647) {
- if (data.values.where((element) => element.first >= 2147483647).length <= 1) {
- return;
- }
- }
- var db = StepDB();
- var history = await db.findHistory(start, shoeId);
- print("bluetooth -- step history ... $start $history");
- int startStep = 0;
- var p = PartItem(shoeId, 0, currentStep, 0, start - offset);
- if (history.isNotEmpty == true) {
- startStep = history.first['st'];
- if (startStep > currentStep) {
- await db.deleteAll();
- print("bluetooth -- history ... clear");
- startStep = currentStep;
- await db.insert(p);
- print("bluetooth -- step add history ... ${p.toJson()}");
- }
- } else {
- startStep = currentStep;
- await db.insert(p);
- print("bluetooth -- step add history ... ${p.toJson()}");
- }
- data[data.length] = current;
- for (var i = 1; i < data.length; i++) {
- var list = data[i] ?? [];
- for (int e in list) {
- int time = start + items.length * offset;
- int step = max(0, e - startStep);
- print("bluetooth -- step add $time $e s:$startStep step:$step");
- items.add(PartItem(shoeId, step, e, 0, min(time, maxTime.millisecondsSinceEpoch)));
- startStep = e;
- }
- }
- }
- }
|