bluetooth.dart 55 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589
  1. import 'dart:async';
  2. import 'dart:collection';
  3. import 'dart:convert';
  4. import 'dart:core';
  5. import 'dart:io';
  6. import 'dart:math';
  7. import 'dart:typed_data';
  8. import 'package:broadcast/broadcast.dart';
  9. import 'package:buffer/buffer.dart';
  10. import 'package:device_info/device_info.dart';
  11. import 'package:flutter/material.dart';
  12. import 'package:flutter_reactive_ble/flutter_reactive_ble.dart';
  13. import 'package:get_it/get_it.dart';
  14. import 'package:package_info/package_info.dart';
  15. import 'package:path_provider/path_provider.dart';
  16. import 'package:permission_handler/permission_handler.dart';
  17. import 'package:shared_preferences/shared_preferences.dart';
  18. import 'package:sport/application.dart';
  19. import 'package:sport/bean/hardware.dart';
  20. import 'package:sport/db/bluetooth_db.dart';
  21. import 'package:sport/db/step_db.dart';
  22. import 'package:sport/pages/my/dfu_update_page.dart';
  23. import 'package:sport/services/Converter.dart';
  24. import 'package:sport/services/api/inject_api.dart';
  25. import 'package:sport/services/api/rest_client.dart';
  26. import 'package:sport/utils/toast.dart';
  27. import 'package:sport/utils/version.dart';
  28. import 'package:sport/widgets/dialog/alert_dialog.dart';
  29. const BLE_CODE_0 = 0x00;
  30. const BLE_CODE_1 = 0x01;
  31. class BLE {
  32. BLE._();
  33. static const BLE_Client_T_MOTION = 0x04;
  34. static const BLE_Client_T_UPDATE = 0xA1;
  35. static const BLE_Client_T_GAMEMODE = 0xA2;
  36. static const BLE_Client_T_CONNET_R = 0xA3;
  37. static const BLE_Client_T_SHOCK = 0xA4;
  38. static const BLE_Client_T_REALTIMESTEP = 0xA5;
  39. static const BLE_Client_T_DFU = 0xA6;
  40. static const BLE_Client_T_CHARGE = 0xA7;
  41. static const BLE_Client_T_LIGHTING = 0xAC;
  42. static const BLE_Client_T_ERR = 0xAD;
  43. }
  44. class BLE_UPDATE {
  45. BLE_UPDATE._();
  46. static const BASIC = 0x00;
  47. static const DATA = 0x01;
  48. static const STEP = 0x02;
  49. static const STEP_DELETE = 0x03;
  50. }
  51. const BLE_UUID = "6e400001-b5a3-f393-e0a9-e50e24dcca9e";
  52. class Bluetooth with ChangeNotifier, InjectApi {
  53. static final String PREF_KEY = "SHOES";
  54. factory Bluetooth() => _getInstance();
  55. static Bluetooth? _instance;
  56. // 获取对象
  57. static Bluetooth _getInstance() {
  58. if (_instance == null) {
  59. // 使用私有的构造方法来创建对象
  60. _instance = Bluetooth._internal();
  61. }
  62. return _instance!;
  63. }
  64. Bluetooth._internal() {
  65. //初始化(设置一些默认的)...
  66. }
  67. final List<StreamSubscription<dynamic>> _streamSubscriptions = <StreamSubscription<dynamic>>[];
  68. void addSubscription(StreamSubscription<dynamic> streamSubscription) {
  69. _streamSubscriptions.add(streamSubscription);
  70. }
  71. void disposeSubscription() {
  72. for (StreamSubscription<dynamic> subscription in _streamSubscriptions) {
  73. subscription.cancel();
  74. }
  75. _streamSubscriptions.clear();
  76. characteristicNotify?.cancel();
  77. }
  78. // ignore: close_sinks
  79. final StreamController<bool> _queryController = StreamController.broadcast();
  80. Stream<bool> get queryStream => _queryController.stream;
  81. // ignore: close_sinks
  82. final StreamController<bool> _stateController = StreamController.broadcast();
  83. Stream<bool> get stateStream => _stateController.stream;
  84. // ignore: close_sinks
  85. final StreamController<Uint8List> _dataController = StreamController.broadcast();
  86. Stream<Uint8List> get dataStream => _dataController.stream;
  87. // ignore: close_sinks
  88. final StreamController<int> _connectRightController = StreamController.broadcast();
  89. Stream<int> get connectRightStream => _connectRightController.stream;
  90. final ValueNotifier<DiscoveredDevice?> deviceNotifier = ValueNotifier(null);
  91. final ValueNotifier<Map> infoNotifier = ValueNotifier<Map>({});
  92. final ValueNotifier<String> versionNotifier = ValueNotifier<String>("");
  93. final ValueNotifier<Map> dataNotifier = ValueNotifier<Map>({});
  94. final ValueNotifier<int> electricityNotifier = ValueNotifier<int>(0);
  95. final ValueNotifier<int> stepNotifier = ValueNotifier<int>(0);
  96. final ValueNotifier<int> stepTotalNotifier = ValueNotifier<int>(0);
  97. final ValueNotifier<int> stepTotalTestNotifier = ValueNotifier<int>(0);
  98. final ValueNotifier<int> actionNotifier = ValueNotifier<int>(0);
  99. final ValueNotifier<List<int>> byteNotifier = ValueNotifier<List<int>>([]);
  100. final ValueNotifier<int> vibrateNotifier = ValueNotifier<int>(400);
  101. final ValueNotifier<int> stepRealtimeNotifier = ValueNotifier<int>(-1);
  102. final ValueNotifier<bool> stepRealtimePageNotifier = ValueNotifier<bool>(false);
  103. final ValueNotifier<Hardware?> verNotifier = ValueNotifier(null);
  104. final ValueNotifier<Map<int, int>> stateNotifier = ValueNotifier({1: 0, 0: 0});
  105. final ValueNotifier<bool> h5gameRNotifier = ValueNotifier<bool>(false);
  106. final ValueNotifier<bool> deviceWriteNotifier = ValueNotifier<bool>(false);
  107. final ValueNotifier<bool> deviceReadNotifier = ValueNotifier<bool>(false);
  108. final ValueNotifier<bool> deviceReadNotifyNotifier = ValueNotifier<bool>(false);
  109. final ValueNotifier<int> rssiNotifier = ValueNotifier<int>(0);
  110. final ValueNotifier<Map<String, int>> timeUseNotifier = ValueNotifier<Map<String, int>>({});
  111. DiscoveredDevice? _connectingDevice, _connectedDevice;
  112. bool _listen = false;
  113. bool _online = false;
  114. bool _uploadLoged = false;
  115. String? _deviceId;
  116. PartInfo? _partInfo;
  117. Completer<bool>? _completerStep;
  118. Completer<bool>? _completerStepDel;
  119. Completer<bool>? _completerSetupDeviceVer;
  120. StreamSubscription? scanStreamSubscription;
  121. QualifiedCharacteristic? characteristicWrite;
  122. StreamSubscription? characteristicNotify;
  123. late FlutterReactiveBle flutterReactiveBle;
  124. Timer? stepRealTimeTimer;
  125. Timer? gameModeTimer;
  126. Timer? timerConnected;
  127. Timer? rssiTimer;
  128. Timer? disconnectTimer;
  129. int disconnectTimes = 0;
  130. DateTime? startTime;
  131. List<int> timeUse = [];
  132. int testDfu = 0;
  133. int _isRightError = 0;
  134. bool get isConnected => _online;
  135. bool get isNotReady => isDebugShoe ? false : !(_online == true && electricityNotifier.value > 0);
  136. bool get isRightError => _isRightError != 1;
  137. late BuildContext _context;
  138. bool _showChargeDialog = false;
  139. DateTime? electricityTime;
  140. resetData() {
  141. stepNotifier.value = 0;
  142. stepTotalNotifier.value = 0;
  143. actionNotifier.value = 0;
  144. }
  145. DiscoveredDevice? get device => _connectedDevice;
  146. set device(DiscoveredDevice? device) {
  147. _connectedDevice = device;
  148. notifyListeners();
  149. }
  150. bool _dfu = false;
  151. set dfu(bool dfu) {
  152. _dfu = dfu;
  153. }
  154. Future<String> _saveDevice(DiscoveredDevice device) async {
  155. var id = device.id.toString();
  156. var prefs = await SharedPreferences.getInstance();
  157. prefs.setString(PREF_KEY, id);
  158. return id;
  159. }
  160. clearDevice({bool deleteStep = false}) async {
  161. var prefs = await SharedPreferences.getInstance();
  162. prefs.remove(PREF_KEY);
  163. if (deleteStep == true) {
  164. var db = StepDB();
  165. db.deleteAll();
  166. }
  167. startTime = null;
  168. await disconnectDevice("清空设备");
  169. this.device = _connectedDevice = null;
  170. }
  171. Future<String?> getHistoryDevice() async {
  172. var prefs = await SharedPreferences.getInstance();
  173. return prefs.getString(PREF_KEY);
  174. }
  175. init(BuildContext context) async {
  176. this._context = context;
  177. this._listen = true;
  178. if (Platform.isAndroid) {
  179. DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
  180. AndroidDeviceInfo info = await deviceInfo.androidInfo;
  181. if (info.version.sdkInt < 31) {
  182. if (await Permission.locationWhenInUse.status.isGranted != true) return;
  183. } else {
  184. Map<Permission, PermissionStatus> statuses = await [
  185. Permission.bluetoothScan,
  186. Permission.bluetoothConnect,
  187. ].request();
  188. if (statuses.isNotEmpty == true && statuses.values.any((element) => element.isGranted) != true) {
  189. return;
  190. }
  191. }
  192. }
  193. flutterReactiveBle = FlutterReactiveBle();
  194. flutterReactiveBle.statusStream.listen((state) {
  195. print("bluetooth -- instance state $state");
  196. if (state == BleStatus.ready) {
  197. connectDevice();
  198. } else if (state == BleStatus.unknown) {
  199. } else if (state == BleStatus.poweredOff) {
  200. disconnectDevice("蓝牙状态不可用");
  201. ToastUtil.show("蓝牙服务已关闭");
  202. } else {}
  203. });
  204. flutterReactiveBle.connectedDeviceStream.listen((event) {
  205. print("bluetooth -- state $event!");
  206. if (event.connectionState == DeviceConnectionState.connected) {
  207. if (_deviceId == event.deviceId) {
  208. final deviceId = _deviceId!;
  209. notifyConnectTime("C");
  210. discoverServices(flutterReactiveBle, deviceId).then((value) {
  211. notifyConnectTime("D$value");
  212. if (value == 2) {
  213. setupGameMode(h5gameRNotifier.value);
  214. queryDeviceRight();
  215. timerConnected = Timer(Duration(seconds: 30), () {
  216. if (isRightError) clearDevice();
  217. });
  218. } else {}
  219. });
  220. }
  221. } else if (event.connectionState == DeviceConnectionState.disconnected) {
  222. if (event.failure?.code == ConnectionError.failedToConnect) {
  223. disconnectDevice("${event.failure?.message}");
  224. if (event.failure?.message?.contains("133") == true) {
  225. Future.microtask(() {
  226. connectDevice(id: event.deviceId);
  227. });
  228. }
  229. }
  230. }
  231. });
  232. versionNotifier.addListener(() {
  233. if (versionNotifier.value.isNotEmpty) {
  234. checkUpdate();
  235. }
  236. });
  237. connectRightStream.listen((event) {
  238. print("bluetooth -- connect right ${_connectingDevice?.name} ${event}!");
  239. if (event == 1 && _isRightError != event) {
  240. notifyConnectTime("R");
  241. timerConnected?.cancel();
  242. dataNotifier.value = {};
  243. infoNotifier.value = {};
  244. verNotifier.value = null;
  245. if (_connectingDevice != null) {
  246. _saveDevice(_connectingDevice!);
  247. _connected(_connectingDevice!);
  248. _query();
  249. }
  250. }
  251. _isRightError = event;
  252. });
  253. }
  254. Future listen(BuildContext context, {bool init = false}) async {
  255. this._context = context;
  256. this._listen = true;
  257. print("bluetooth -- listen");
  258. Broadcast.broadcast("SHOE.SDK.BLUE_DISCONNECT");
  259. var prefs = await SharedPreferences.getInstance();
  260. if (!prefs.containsKey("token")) {
  261. return;
  262. }
  263. disconnectTimer?.cancel();
  264. disconnectTimes = 0;
  265. if (_dfu == true) return;
  266. if (!isConnected) {
  267. connectDevice();
  268. }
  269. }
  270. void runTimer() {
  271. addSubscription(Stream.periodic(Duration(seconds: 60)).listen((event) async {
  272. if (device == null) return;
  273. if (!_online) return;
  274. await queryDeviceData();
  275. await queryDeviceStep();
  276. }));
  277. }
  278. Future background(BuildContext context) async {
  279. this._listen = false;
  280. if (_showChargeDialog == true) {
  281. Navigator.maybePop(context);
  282. }
  283. disconnectTimer?.cancel();
  284. disconnectTimer = Timer.periodic(Duration(seconds: 5), (t) {
  285. disconnectTimes++;
  286. if (disconnectTimes >= 20) {
  287. disconnectDevice("后台时断开连接");
  288. t.cancel();
  289. }
  290. });
  291. }
  292. Future disposeBluetooth(BuildContext context) async {
  293. if (_dfu == true) return;
  294. // // 实时计步中不主动断开
  295. if (stepRealtimePageNotifier.value == true) return;
  296. gameModeTimer?.cancel();
  297. this._listen = false;
  298. if (_showChargeDialog == true) {
  299. Navigator.maybePop(context);
  300. }
  301. // if (Platform.isIOS) {
  302. await disconnectDevice("app退后台");
  303. // }
  304. }
  305. resetNotifierData() {
  306. dataNotifier.value = {};
  307. infoNotifier.value = {};
  308. verNotifier.value = null;
  309. electricityNotifier.value = -1;
  310. _connectRightController.add(0);
  311. stateNotifier.value = {0: 0, 1: 0};
  312. deviceWriteNotifier.value = false;
  313. deviceReadNotifier.value = false;
  314. deviceReadNotifyNotifier.value = false;
  315. _online = false;
  316. _stateController.add(false);
  317. }
  318. Future disconnectDevice(String msg) async {
  319. print("bluetooth -- disconnect $msg $device");
  320. _deviceId = null;
  321. disposeSubscription();
  322. deviceNotifier.value = null;
  323. timerConnected?.cancel();
  324. resetNotifierData();
  325. disconnectTimes = 0;
  326. _uploadLoged = false;
  327. device = _connectedDevice = _connectingDevice = null;
  328. errQueue.clear();
  329. }
  330. Future connectDevice({DiscoveredDevice? device, String? id, bool again = false}) async {
  331. await disconnectDevice("主动连接");
  332. if (again != true) {
  333. timeUse = [];
  334. timeUseNotifier.value = {};
  335. }
  336. if (device != null) {
  337. startTime = null;
  338. BluetoothDB().insert(device);
  339. }
  340. notifyConnectTime("F");
  341. String? deviceId = id;
  342. if (device == null) {
  343. if (deviceId == null) {
  344. deviceId = await getHistoryDevice();
  345. }
  346. print("bluetooth -- connect from $deviceId $device");
  347. if (deviceId == null || deviceId.isEmpty) {
  348. return null;
  349. }
  350. try {
  351. device = await discoverDevice(deviceId: deviceId);
  352. } catch (e) {
  353. print(e);
  354. return;
  355. }
  356. }
  357. if (device == null) return;
  358. _deviceId = deviceId = device.id;
  359. print("bluetooth -- connect $deviceId!");
  360. notifyConnectTime("S");
  361. addSubscription(flutterReactiveBle
  362. .connectToDevice(
  363. id: deviceId,
  364. connectionTimeout: const Duration(seconds: 8),
  365. )
  366. .listen((update) {
  367. _connectingDevice = device!;
  368. // print("bluetooth -- connect state $deviceId $update!");
  369. }, onError: (Object e) {
  370. print("bluetooth -- connect error $deviceId $e!");
  371. _connectingDevice = null;
  372. }));
  373. }
  374. Future<DiscoveredDevice?> discoverDevice({String? deviceId, String? deviceName}) async {
  375. // 2022-04-26 11:10:53.285 17454-17479/com.ouj.sdk.test I/System.out: 00001800-0000-1000-8000-00805f9b34fb
  376. // 2022-04-26 11:10:53.285 17454-17479/com.ouj.sdk.test I/System.out: 00002a00-0000-1000-8000-00805f9b34fb
  377. // 2022-04-26 11:10:53.285 17454-17479/com.ouj.sdk.test I/System.out: 00002a01-0000-1000-8000-00805f9b34fb
  378. // 2022-04-26 11:10:53.285 17454-17479/com.ouj.sdk.test I/System.out: 00002a04-0000-1000-8000-00805f9b34fb
  379. // 2022-04-26 11:10:53.285 17454-17479/com.ouj.sdk.test I/System.out: 00002aa6-0000-1000-8000-00805f9b34fb
  380. // 2022-04-26 11:10:53.285 17454-17479/com.ouj.sdk.test I/System.out: 00001801-0000-1000-8000-00805f9b34fb
  381. // 2022-04-26 11:10:53.285 17454-17479/com.ouj.sdk.test I/System.out: 6e400001-b5a3-f393-e0a9-e50e24dcca9e
  382. // 2022-04-26 11:10:53.285 17454-17479/com.ouj.sdk.test I/System.out: 6e400002-b5a3-f393-e0a9-e50e24dcca9e
  383. // 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
  384. // 2022-04-26 11:10:53.285 17454-17479/com.ouj.sdk.test I/System.out: 6e400003-b5a3-f393-e0a9-e50e24dcca9e
  385. // 2022-04-26 11:10:53.285 17454-17479/com.ouj.sdk.test D/BluetoothGatt: setCharacteristicNotification() - uuid: 6e400003-b5a3-f393-e0a9-e50e24dcca9e enable: true
  386. // 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
  387. // 2022-04-26 11:10:53.286 17454-17479/com.ouj.sdk.test I/System.out: 0000fe59-0000-1000-8000-00805f9b34fb
  388. // 2022-04-26 11:10:53.286 17454-17479/com.ouj.sdk.test I/System.out: 8ec90003-f315-4f60-9fb8-838830daea50
  389. scanStreamSubscription?.cancel();
  390. final completer = Completer<DiscoveredDevice?>();
  391. Timer timeout = Timer(Duration(seconds: 20), () {
  392. completer.completeError("timeout");
  393. });
  394. scanStreamSubscription = flutterReactiveBle.scanForDevices(withServices: [Uuid.parse(BLE_UUID)]).listen((event) {
  395. print('bluetooth -- scan device : ${event.id} ${event.name}');
  396. if (event.id == deviceId || event.name == deviceName || (deviceName != null && event.name.contains(deviceName))) {
  397. if (completer.isCompleted != true) completer.complete(event);
  398. }
  399. });
  400. var device;
  401. try {
  402. device = await completer.future.catchError((error, stackTrace) => throw error);
  403. timeout.cancel();
  404. } catch (e) {
  405. print("bluetooth -- shoe right fail $e");
  406. print(e);
  407. } finally {
  408. scanStreamSubscription?.cancel();
  409. }
  410. print('bluetooth -- found: ${device?.id} ${device?.name}');
  411. return device;
  412. }
  413. Future<int> discoverServices(FlutterReactiveBle flutterReactiveBle, String deviceId) async {
  414. int result = 0;
  415. characteristicNotify?.cancel();
  416. for (var i = 0; i < 3; i++) {
  417. bool findWrite = false;
  418. bool findRead = false;
  419. try {
  420. var services = await flutterReactiveBle.discoverServices(deviceId);
  421. for (DiscoveredService service in services) {
  422. for (var characteristic in service.characteristics) {
  423. if (characteristic.isWritableWithoutResponse) {
  424. characteristicWrite = QualifiedCharacteristic(serviceId: service.serviceId, characteristicId: characteristic.characteristicId, deviceId: deviceId);
  425. findWrite = true;
  426. deviceWriteNotifier.value = true;
  427. }
  428. if (characteristic.isNotifiable) {
  429. deviceReadNotifier.value = true;
  430. findRead = true;
  431. final qualifiedCharacteristic = QualifiedCharacteristic(serviceId: service.serviceId, characteristicId: characteristic.characteristicId, deviceId: deviceId);
  432. characteristicNotify = flutterReactiveBle.subscribeToCharacteristic(qualifiedCharacteristic).listen((event) {
  433. deviceReadNotifyNotifier.value = true;
  434. if (this._listen == true) {
  435. byteNotifier.value = event;
  436. parse(event);
  437. }
  438. });
  439. }
  440. }
  441. }
  442. } catch (e) {
  443. print(e);
  444. print("bluetooth -- service error $e");
  445. characteristicNotify?.cancel();
  446. }
  447. if (findWrite && findRead) {
  448. print("bluetooth -- service write: $findWrite, read: $findRead");
  449. result = 2;
  450. break;
  451. } else {
  452. await Future.delayed(Duration(seconds: 2));
  453. }
  454. }
  455. return result;
  456. }
  457. _query() async {
  458. queryDeviceInfo();
  459. queryDeviceRight();
  460. queryDeviceStep();
  461. queryDeviceCharge();
  462. queryDeviceData();
  463. }
  464. _connected(DiscoveredDevice newDevice) async {
  465. _stateController.add(true);
  466. _online = true;
  467. deviceNotifier.value = newDevice;
  468. this.device = newDevice;
  469. if (isDebugShoe) {
  470. ToastUtil.show("${newDevice.name} 已连接");
  471. }
  472. if ((startTime?.difference(DateTime.now()).inHours ?? 1) > 0) {
  473. notifyConnected();
  474. startTime = DateTime.now();
  475. }
  476. runTimer();
  477. flutterReactiveBle.connectedDeviceStream.toList().then((value) {
  478. value.forEach((element) {
  479. if (element.deviceId != newDevice.id) flutterReactiveBle.clearGattCache(element.deviceId);
  480. });
  481. });
  482. }
  483. notifyConnectTime(String tag) {
  484. int now = DateTime.now().millisecondsSinceEpoch;
  485. Map<String, int> result = timeUseNotifier.value;
  486. // print("111111111111111111 ${now} ${timeUse}");
  487. result[tag] = now - (timeUse.isNotEmpty ? timeUse.last : now);
  488. timeUseNotifier.value = result;
  489. timeUse.add(now);
  490. }
  491. notifyConnected() {
  492. this.vibrate(200);
  493. this.lighting(10000);
  494. }
  495. checkUpdate() async {
  496. var info = infoNotifier.value;
  497. print("bluetooth -- checkUpdate ${info}");
  498. if (info.isEmpty == true) return;
  499. String softwareVer = info['softwareVer'];
  500. String hardwareVer = info['hardwareVer'];
  501. List<String> device = info['device'];
  502. PackageInfo packageInfo = await PackageInfo.fromPlatform();
  503. String appVer = packageInfo.version;
  504. Hardware? updateInfo = (await GetIt.I<RestClient>().checkHardwareUpdate(hardwareVer, appVer)).data;
  505. if (updateInfo != null) {
  506. // PackageInfo packageInfo = await PackageInfo.fromPlatform();
  507. // if (updateInfo.min_app_ver?.isNotEmpty == true && versionCompare(packageInfo.version, updateInfo.min_app_ver ?? "0") < 0) {
  508. // debugPrint("bluetooth -- dfu update app ver ${packageInfo.version} min ${updateInfo.min_app_ver}");
  509. // return;
  510. // }
  511. // if (updateInfo.max_app_ver?.isNotEmpty == true && versionCompare(packageInfo.version, updateInfo.max_app_ver ?? "0") > 0) {
  512. // debugPrint("bluetooth -- dfu update app ver ${packageInfo.version} max ${updateInfo.max_app_ver}");
  513. // return;
  514. // }
  515. //
  516. // if (updateInfo.min_hardware_ver?.isNotEmpty == true && versionCompare(hardwareVer, updateInfo.min_hardware_ver ?? "0") < 0) {
  517. // debugPrint("bluetooth -- dfu update hardware ver ${hardwareVer} min ${updateInfo.min_hardware_ver}");
  518. // return;
  519. // }
  520. //
  521. // if (updateInfo.max_hardware_ver?.isNotEmpty == true && versionCompare(hardwareVer, updateInfo.max_hardware_ver ?? "0") > 0) {
  522. // debugPrint("bluetooth -- dfu update hardware ver ${hardwareVer} max ${updateInfo.max_hardware_ver}");
  523. // return;
  524. // }
  525. updateInfo.devices = [];
  526. updateInfo.localVer = softwareVer;
  527. print("bluetooth -- dfu versionCompare ${versionCompare(softwareVer, updateInfo.ver ?? "0.0")}");
  528. bool cancelable = this.testDfu >= 5
  529. ? true
  530. : Platform.isAndroid
  531. ? !inProduction
  532. : false;
  533. if (cancelable == false) {
  534. if (versionCompare(softwareVer, updateInfo.ver ?? "0.0") >= 0) {
  535. return;
  536. }
  537. }
  538. for (var i = device.length - 1; i >= 0; i--) {
  539. updateInfo.devices!.add(device[i]);
  540. }
  541. verNotifier.value = updateInfo;
  542. if (isDebugShoe) {
  543. var context = _context;
  544. var value = updateInfo;
  545. var closeable = 0;
  546. var result = await showDialog(
  547. context: context,
  548. barrierDismissible: false,
  549. builder: (context) => CustomAlertDialog(
  550. title: '发现新的鞋子固件',
  551. child: WillPopScope(
  552. onWillPop: () async {
  553. return false;
  554. },
  555. child: GestureDetector(
  556. behavior: HitTestBehavior.opaque,
  557. onTap: () {
  558. closeable++;
  559. if (closeable >= 5) {
  560. Navigator.of(context).pop(false);
  561. }
  562. },
  563. child: Container(
  564. width: double.infinity,
  565. padding: const EdgeInsets.symmetric(horizontal: 24.0),
  566. child: Text(
  567. "${value.name}\n${value.localVer} -> ${value.ver}\n${value.msg}",
  568. style: TextStyle(fontSize: 14, color: Color(0xff333333), height: 1.8),
  569. )),
  570. ),
  571. ),
  572. textOk: '立即升级',
  573. cancelable: cancelable,
  574. ok: () => Navigator.of(context).pop(true)),
  575. );
  576. if (result != true) return;
  577. result = await showDialog(
  578. context: context,
  579. barrierDismissible: false,
  580. builder: (context) => SimpleDialog(
  581. children: <Widget>[
  582. DfuUpdatePage(
  583. hardware: value,
  584. )
  585. ],
  586. ));
  587. }
  588. }
  589. }
  590. void parse(List<int> event) {
  591. if (event.isEmpty == true) return;
  592. if (!_listen) return;
  593. ByteDataReader reader = ByteDataReader();
  594. reader.add(event);
  595. int flagAA = reader.readUint8();
  596. // int flagBB = reader.readUint8();
  597. // int flagCC = reader.readUint8();
  598. int len = reader.readUint8();
  599. int len1 = 0xFF - reader.readUint8();
  600. // int index = reader.readUint8();
  601. int cmd = reader.readUint8();
  602. // print(" change --> ${flagAA} ${len} ${~len} ${cmd}");
  603. // print(" change --> ${len} ${~len} ${len1}");
  604. // print(" change --> ${index} ${cmd}");
  605. if (!(flagAA == 0xAA)) return;
  606. if (len != len1) return;
  607. Uint8List byteArray = reader.read(event.length - 5);
  608. int ver = 0;
  609. for (int i = 0; i < event.length - 1; i++) {
  610. ver += event[i];
  611. }
  612. if (ver.toUnsigned(8) != event[event.length - 1]) return;
  613. parseCmd(cmd, byteArray);
  614. }
  615. void parseCmd(int cmd, Uint8List byteArray) {
  616. // if (isDebugShoe) print(" cmd $cmd data --> $byteArray");
  617. switch (cmd) {
  618. case 0x01:
  619. _parseAction(byteArray);
  620. break;
  621. case BLE.BLE_Client_T_MOTION:
  622. disconnectTimes = 0;
  623. _dataController.add(byteArray);
  624. break;
  625. case 0xA0:
  626. break;
  627. case BLE.BLE_Client_T_UPDATE:
  628. _parseQuery(byteArray);
  629. break;
  630. case BLE.BLE_Client_T_CONNET_R:
  631. _connectRightController.add(byteArray.first);
  632. break;
  633. case BLE.BLE_Client_T_REALTIMESTEP:
  634. _parseStepRealtime(byteArray);
  635. break;
  636. case BLE.BLE_Client_T_DFU:
  637. if (_completerSetupDeviceVer?.isCompleted != true) _completerSetupDeviceVer?.complete(true);
  638. break;
  639. case BLE.BLE_Client_T_CHARGE: //充电
  640. _parseCharge(byteArray);
  641. break;
  642. case BLE.BLE_Client_T_ERR: //异常
  643. _parseErr(byteArray);
  644. break;
  645. case BLE.BLE_Client_T_GAMEMODE:
  646. break;
  647. }
  648. }
  649. void _parseAction(Uint8List byteArray) {
  650. ByteDataReader reader = ByteDataReader();
  651. reader.add(byteArray);
  652. int action = reader.readUint8();
  653. int t = reader.readUint16();
  654. print("action: $action ");
  655. actionNotifier.value = action;
  656. }
  657. void _parseQuery(Uint8List byteArray) {
  658. ByteDataReader reader = ByteDataReader();
  659. reader.add(byteArray);
  660. int cmd = reader.readUint8();
  661. switch (cmd) {
  662. case BLE_UPDATE.BASIC: // 设备基本信息
  663. Map<String, dynamic> info = {};
  664. List<int> name = [];
  665. for (var i = 0; i < 64; i++) {
  666. name.add(reader.readUint8());
  667. }
  668. info['name'] = String.fromCharCodes(name).replaceAll("\u0000", "");
  669. List<int> softwareVer = [];
  670. List<int> hardwareVer = [];
  671. List<String> device = [];
  672. for (var i = 0; i < 2; i++) {
  673. List<String> macList = [];
  674. for (var j = 0; j < 6; j++) {
  675. macList.add(reader.readUint8().toRadixString(16).padLeft(2, "0"));
  676. }
  677. var mac = macList.join(":").toUpperCase();
  678. print("mac $i = $mac");
  679. for (var k = 0; k < 4; k++) {
  680. hardwareVer.add(reader.readUint8());
  681. }
  682. softwareVer.add(reader.readUint8());
  683. device.add(mac);
  684. }
  685. print("bluetooth dfu info $hardwareVer $softwareVer");
  686. if (hardwareVer.length != 8 || softwareVer.length != 2) return;
  687. String leftHardware = hardwareVer.sublist(1, 4).join(".");
  688. String rightHardware = hardwareVer.sublist(4 + 1, hardwareVer.length).join(".");
  689. int compareHardware = versionCompare(leftHardware, rightHardware);
  690. String minHardwareVersion = compareHardware < 0 ? leftHardware : rightHardware;
  691. print("bluetooth hardwareVer $leftHardware $rightHardware $compareHardware $minHardwareVersion");
  692. String leftSoftware = hardwareVer.sublist(1, 3).join(".") + ".${softwareVer[0]}";
  693. String rightSoftware = hardwareVer.sublist(4 + 1, 4 + 1 + 2).join(".") + ".${softwareVer[0]}";
  694. int compareSoftware = versionCompare(leftSoftware, rightSoftware);
  695. String minSoftwareVersion = compareSoftware < 0 ? leftSoftware : rightSoftware;
  696. print("bluetooth softwareVer $leftSoftware $rightSoftware $compareSoftware $minSoftwareVersion");
  697. shoeVersion = "$minHardwareVersion";
  698. info['softwareVer'] = minSoftwareVersion;
  699. info['hardwareVer'] = minHardwareVersion;
  700. info['mac'] = device.length > 1 ? device.first : "";
  701. info['device'] = device;
  702. infoNotifier.value = info;
  703. if (versionNotifier.value != minSoftwareVersion) versionNotifier.value = minSoftwareVersion;
  704. _uploadErr();
  705. if (_uploadLoged != true) {
  706. _uploadLog();
  707. }
  708. break;
  709. case BLE_UPDATE.DATA: // 设备数据(左鞋,右鞋)
  710. Map<String, dynamic> info = {};
  711. for (var i = 0; i < 2; i++) {
  712. info['${i}_electricity'] = reader.readUint8();
  713. info['${i}_temperature'] = reader.readUint8();
  714. info['${i}_pressure'] = reader.readUint(4);
  715. reader.readUint(4);
  716. }
  717. if (reader.remainingLength >= 4) {
  718. info['0_adc'] = reader.readUint16();
  719. info['1_adc'] = reader.readUint16();
  720. }
  721. // [170, 187, 204, 23, 232, 0, 161, 1, 50, 0, 33, 0, 0, 156, 41, 51, 0, 34, 0, 0, 150, 19, 232]
  722. dataNotifier.value = info;
  723. int electricity = min(info['0_electricity'] ?? 0, info['1_electricity'] ?? 0);
  724. electricityNotifier.value = electricity;
  725. if (electricity < 10) {
  726. if (electricityTime == null || (electricityTime?.difference(DateTime.now()).inMinutes.abs() ?? 0) >= 60) {
  727. if (_showChargeDialog != true) {
  728. ToastUtil.show("鞋子电量不足,请及时充电!");
  729. electricityTime = DateTime.now();
  730. }
  731. }
  732. }
  733. if (isDebugShoe) {
  734. _testElectricity(info);
  735. }
  736. break;
  737. case BLE_UPDATE.STEP: // 查询步数
  738. print("bluetooth -- step part ${_partInfo?.ready}");
  739. if (_partInfo == null) return;
  740. if (_partInfo?.ready == true) return;
  741. if (isDebugShoe) {
  742. _testStep(byteArray.toList().join(","));
  743. }
  744. int start = reader.readUint64();
  745. int serialCount = reader.readUint16();
  746. int serial = reader.readUint16();
  747. // if(serialCount == 0){
  748. // _completerStep?.complete(false);
  749. // return;
  750. // }
  751. List<int> data = [];
  752. while (reader.remainingLength > 0) {
  753. data.add(reader.readUint32());
  754. }
  755. if (serial == 0 && data.isNotEmpty) {
  756. stepTotalNotifier.value = data.last;
  757. }
  758. _partInfo!.start = start;
  759. _partInfo!.serialCount = serialCount + 1;
  760. _partInfo!.data[serial] = data;
  761. print("bluetooth -- step start $start read ($serial,$serialCount) --> $data");
  762. if (_partInfo!.data.length == _partInfo!.serialCount) {
  763. _partInfo!.ready = true;
  764. var partResult = _partInfo!;
  765. Future.microtask(() async {
  766. await partResult.prepare();
  767. print("bluetooth -- step end ... ");
  768. await _saveInfo(partResult);
  769. });
  770. if (_completerStep?.isCompleted != true) _completerStep?.complete(true);
  771. }
  772. break;
  773. case BLE_UPDATE.STEP_DELETE: // 步数回调
  774. if (_completerStepDel != null) _completerStepDel!.complete(true);
  775. break;
  776. }
  777. }
  778. void _parseStepRealtime(Uint8List byteArray) {
  779. ByteDataReader reader = ByteDataReader();
  780. reader.add(byteArray);
  781. int cmd = reader.readUint8();
  782. if (cmd == 0) {
  783. } else if (cmd == 1) {
  784. int left = 0;
  785. int right = 0;
  786. if (reader.remainingLength > 4) {
  787. left = reader.readUint32();
  788. right = reader.readUint32();
  789. } else {
  790. left = reader.readUint16();
  791. right = reader.readUint16();
  792. }
  793. int step = left + right;
  794. // print("left: ${left}, right: ${ right} = ${step}");
  795. stepRealtimeNotifier.value = step;
  796. // 已经不是在实时计步页面,但还收到数据,关了!
  797. if (stepRealtimePageNotifier.value == false) {
  798. write(BLE.BLE_Client_T_REALTIMESTEP, Uint8List.fromList([BLE_CODE_0]));
  799. }
  800. }
  801. }
  802. void _parseCharge(Uint8List byteArray) async {
  803. ByteDataReader reader = ByteDataReader();
  804. reader.add(byteArray);
  805. int cmd = reader.readUint8();
  806. int state = reader.readUint8();
  807. Map<int, int> _state = Map.from(stateNotifier.value);
  808. _state.update(cmd, (value) => state);
  809. stateNotifier.value = _state;
  810. // print("111111111111111111111111 $_state");
  811. if (_state[0]! <= 1 && _state[1]! <= 1) {
  812. if (_showChargeDialog == true) {
  813. Navigator.maybePop(_context);
  814. }
  815. return;
  816. }
  817. if (_state[0] == 3 && _state[1] == 3) {
  818. queryDeviceData();
  819. }
  820. final String _name = "dialog_charge";
  821. if (_showChargeDialog == true) return;
  822. _showChargeDialog = true;
  823. showDialog(
  824. context: _context,
  825. barrierColor: Colors.transparent,
  826. builder: (context) => GestureDetector(
  827. behavior: HitTestBehavior.opaque,
  828. onTap: () {
  829. Navigator.maybePop(context);
  830. },
  831. child: Scaffold(
  832. backgroundColor: Colors.transparent,
  833. body: Center(
  834. child: Container(
  835. constraints: BoxConstraints(maxWidth: 180.0),
  836. decoration: BoxDecoration(
  837. borderRadius: BorderRadius.all(Radius.circular(10.0)),
  838. color: Colors.black.withOpacity(.75),
  839. ),
  840. child: Column(
  841. mainAxisSize: MainAxisSize.min,
  842. children: [
  843. Align(
  844. child: GestureDetector(
  845. child: Padding(
  846. padding: const EdgeInsets.all(10.0),
  847. child: Image.asset(
  848. "lib/assets/img/btn_close_white.png",
  849. width: 18,
  850. ),
  851. ),
  852. onTap: () {
  853. Navigator.maybePop(context);
  854. },
  855. behavior: HitTestBehavior.opaque,
  856. ),
  857. alignment: Alignment.topRight,
  858. ),
  859. Padding(
  860. padding: const EdgeInsets.fromLTRB(20.0, 5, 20.0, 16.0),
  861. child: ValueListenableBuilder<Map<int, int>>(
  862. valueListenable: stateNotifier,
  863. builder: (context, val, __) {
  864. int totalState = (val[0]! + val[1]!) ~/ 2;
  865. List<int> keys = val.keys.toList();
  866. keys.sort();
  867. return Column(
  868. children: [
  869. Center(
  870. child: Row(
  871. children: keys.map((key) {
  872. int state = val[key]!;
  873. String label = key == 0 ? "left" : "right";
  874. return Padding(
  875. padding: EdgeInsets.symmetric(horizontal: 10),
  876. child: Image.asset(
  877. state == 3
  878. ? "lib/assets/img/pop_icon_${label}full.png"
  879. : state == 2
  880. ? "lib/assets/img/pop_icon_${label}charge.png"
  881. : "lib/assets/img/pop_icon_${label}fault.png",
  882. ),
  883. );
  884. }).toList(),
  885. mainAxisSize: MainAxisSize.min,
  886. ),
  887. ),
  888. const SizedBox(
  889. height: 15,
  890. ),
  891. ValueListenableBuilder(
  892. valueListenable: electricityNotifier,
  893. builder: (BuildContext context, int value, Widget? child) {
  894. int _power = max(0, (val[0]! > 1 && val[1]! > 1) ? value : 0);
  895. return Column(
  896. children: [
  897. Text(
  898. (_power > 1) ? "$_power%" : "",
  899. style: TextStyle(fontSize: 8.0, color: Colors.white),
  900. ),
  901. const SizedBox(
  902. height: 7,
  903. ),
  904. ClipRRect(
  905. child: SizedBox(
  906. height: 2,
  907. child: LinearProgressIndicator(
  908. backgroundColor: Color(0xff656565),
  909. valueColor: AlwaysStoppedAnimation(Color(0xff00DC42)),
  910. value: _power / 100,
  911. ),
  912. ),
  913. borderRadius: BorderRadius.circular(5),
  914. )
  915. ],
  916. );
  917. },
  918. ),
  919. const SizedBox(
  920. height: 11,
  921. ),
  922. Text(
  923. (val[0] == 3 && val[1] == 3)
  924. ? "智能鞋充电已完成"
  925. : (val[0]! > 1 && val[1]! > 1)
  926. ? "智能鞋充电中..."
  927. : (val[0]! <= 1 && val[1]! <= 1)
  928. ? "智能鞋连接异常"
  929. : val[0]! <= 1
  930. ? "左鞋充电连接异常"
  931. : val[1]! <= 1
  932. ? "右鞋充电连接异常"
  933. : "连接异常",
  934. style: TextStyle(fontSize: 12.0, color: Colors.white),
  935. ),
  936. ],
  937. );
  938. }),
  939. ),
  940. ],
  941. )),
  942. ),
  943. ),
  944. ),
  945. routeSettings: RouteSettings(name: _name))
  946. .then((value) => _showChargeDialog = false);
  947. await Future.delayed(Duration(seconds: 5));
  948. if (_showChargeDialog == true) {
  949. Map<int, int> val = stateNotifier.value;
  950. print("_parseCharge $val");
  951. if (val[0]! > 1 && val[1]! > 1) {
  952. Navigator.maybePop(_context);
  953. }
  954. }
  955. }
  956. Queue<Map<String, String>> errQueue = Queue();
  957. /**
  958. * 错误处理
  959. */
  960. void _parseErr(Uint8List byteArray) async {
  961. ByteDataReader r = ByteDataReader();
  962. r.add(byteArray);
  963. int leftOrRight = r.readUint8();
  964. int code = r.readUint8();
  965. List<int> msgData = r.read(r.remainingLength);
  966. String msg = String.fromCharCodes(msgData);
  967. print("bluetooth - _parseErr $leftOrRight $code $msg");
  968. var err = {"code": "$code", "msg": "${leftOrRight == 0 ? "左鞋" : "右鞋"}:$msg"};
  969. if (errQueue.where((element) => element["code"] == "$code").isEmpty) errQueue.addLast(err);
  970. if (isDebugShoe) {
  971. await _testErrLog();
  972. }
  973. _uploadErr();
  974. }
  975. void _uploadErr() async {
  976. if (infoNotifier.value.isEmpty) return;
  977. if (errQueue.isEmpty) return;
  978. var info = infoNotifier.value;
  979. PackageInfo packageInfo = await PackageInfo.fromPlatform();
  980. String mac = "${info['mac']}";
  981. String firmware = "${info['softwareVer']}";
  982. String hardware = "${info['hardwareVer']}";
  983. String app_ver = "${packageInfo.version}";
  984. while (errQueue.isNotEmpty) {
  985. var first = errQueue.removeFirst();
  986. var err_code = first['code'] as String;
  987. var err_msg = first['msg'] as String;
  988. var resp = await api.logHardwareErr(mac, firmware, hardware, app_ver, err_code, err_msg, "");
  989. if (resp.code != 0) {
  990. errQueue.addLast(first);
  991. await Future.delayed(Duration(seconds: 5));
  992. }
  993. }
  994. }
  995. Future _saveInfo(PartInfo? partInfo) async {
  996. if (partInfo == null) return;
  997. print("bluetooth -- step save $partInfo ${partInfo.items.length}");
  998. if (partInfo.items.isEmpty == true) return;
  999. List<PartItem> _items = [];
  1000. for (var item in partInfo.items) {
  1001. if (item.step == 0 && item.distance == 0) continue;
  1002. _items.add(item);
  1003. print("bluetooth -- step save ${item.time} ${item.step}");
  1004. }
  1005. await StepDB().insertAll(_items);
  1006. _queryController.add(true);
  1007. }
  1008. Future<int> _uploadInfo(int startTime) async {
  1009. var list = await StepDB().find(startTime);
  1010. print("bluetooth -- step upload $startTime $list");
  1011. if (list.isEmpty) return 0;
  1012. List<List<int>> data = [];
  1013. int step = 0;
  1014. for (var item in list) {
  1015. data.add([item['st'], item['di'], (item['time'] as int) ~/ 1000]);
  1016. step += Converter.toInt(item['st']);
  1017. }
  1018. if (step > 5) {
  1019. var resp = await api.addDaily(data: json.encode(data));
  1020. if (resp.code == 0) {
  1021. // await StepDB().delete(last);
  1022. return 0;
  1023. }
  1024. }
  1025. return -1;
  1026. // Directory appDocDir = await getApplicationDocumentsDirectory();
  1027. // String appDocPath = appDocDir.path;
  1028. // Directory saveDir = Directory("$appDocPath/step");
  1029. // var files = saveDir.listSync();
  1030. // for(var file in files){
  1031. // var f= new File(file.path);
  1032. // var content = f.readAsStringSync();
  1033. // await api.addDaily(data: content);
  1034. // file.delete();
  1035. // }
  1036. }
  1037. // 查询 设备基本信息
  1038. Future queryDeviceCharge() async {
  1039. await write(BLE.BLE_Client_T_CHARGE, Uint8List(0));
  1040. }
  1041. // 查询 设备右鞋
  1042. Future queryDeviceRight() async {
  1043. await write(BLE.BLE_Client_T_CONNET_R, Uint8List.fromList([]));
  1044. }
  1045. // 查询 设备基本信息
  1046. Future queryDeviceInfo() async {
  1047. await write(BLE.BLE_Client_T_UPDATE, Uint8List.fromList([BLE_CODE_0]));
  1048. }
  1049. // 查询 设备数据
  1050. Future queryDeviceData() async {
  1051. await write(BLE.BLE_Client_T_UPDATE, Uint8List.fromList([BLE_CODE_1]));
  1052. }
  1053. // 查询 查询步数
  1054. Future queryDeviceStep({bool test = false}) async {
  1055. if (!isConnected) return;
  1056. // await Future.delayed(Duration(seconds: 3));
  1057. // _queryController.add(true);
  1058. if (test != true) if (stepTotalTestNotifier.value == 1) return;
  1059. if (_partInfo != null) {
  1060. print("bluetooth -- step _partInfo.now ${_partInfo!.now.difference(DateTime.now()).inSeconds}");
  1061. if ((_partInfo!.now.difference(DateTime.now()).inSeconds) > -60) {
  1062. return;
  1063. }
  1064. }
  1065. print("bluetooth -- step init");
  1066. _partInfo = PartInfo(0, 0);
  1067. if (test == true) stepTotalNotifier.value = -1;
  1068. // await write(0xA1, createTime(0x02));
  1069. await write(BLE.BLE_Client_T_UPDATE, Uint8List.fromList([BLE_UPDATE.STEP, BLE_CODE_0, BLE_CODE_0]));
  1070. if (_completerStep != null && _completerStep?.isCompleted != true) _completerStep?.complete(false);
  1071. if (_completerStepDel != null && _completerStepDel?.isCompleted != true) _completerStepDel?.complete(false);
  1072. _completerStep = Completer();
  1073. _completerStepDel = Completer();
  1074. var timer = Timer.periodic(Duration(seconds: 1), (timer) {
  1075. if (_partInfo == null) return;
  1076. Iterable<int> keys = _partInfo!.data.keys;
  1077. if (keys.isEmpty) return;
  1078. for (var i = 1; i < _partInfo!.serialCount; i++) {
  1079. if (!keys.contains(i)) {
  1080. print("bluetooth -- step request package $i");
  1081. // 请求缺包
  1082. ByteDataWriter writer = ByteDataWriter();
  1083. writer.writeUint8(BLE_UPDATE.STEP);
  1084. writer.writeUint16(i);
  1085. write(BLE.BLE_Client_T_UPDATE, writer.toBytes());
  1086. }
  1087. }
  1088. });
  1089. Timer timeout = Timer(Duration(seconds: 20), () {
  1090. if (_completerStep?.isCompleted != true) _completerStep?.complete(false);
  1091. });
  1092. var result = await _completerStep!.future;
  1093. timeout.cancel();
  1094. timer.cancel();
  1095. int stepTotal = 0;
  1096. if (result == true) {
  1097. await _saveInfo(_partInfo);
  1098. int code = await _uploadInfo(_partInfo!.start);
  1099. if (isDebugShoe) {
  1100. var now = DateTime.now();
  1101. _partInfo?.items.forEach((element) {
  1102. var info = {"t": element.time, "s": element.step, "total": element.absolute};
  1103. _testStep("${now.hour},${now.minute},${now.second},${info['t']},${info['s']},${info['total']}");
  1104. });
  1105. }
  1106. if (test == true) {
  1107. if (_partInfo?.items.isNotEmpty == true) {
  1108. stepTotal = _partInfo?.items.map((e) => e.step).reduce((value, element) => value + element) ?? 0;
  1109. } else {
  1110. stepTotal = 0;
  1111. }
  1112. }
  1113. if (code == 0) {
  1114. var timer = Timer.periodic(Duration(milliseconds: 1000), (timer) {
  1115. write(BLE.BLE_Client_T_UPDATE, createTime(BLE_UPDATE.STEP_DELETE));
  1116. });
  1117. Timer timeout = Timer(Duration(seconds: 60), () {
  1118. if (_completerStepDel?.isCompleted != true) _completerStepDel?.complete(false);
  1119. });
  1120. await _completerStepDel!.future;
  1121. timer.cancel();
  1122. timeout.cancel();
  1123. }
  1124. _completerStepDel = null;
  1125. }
  1126. _partInfo = null;
  1127. print("bluetooth -- step reset");
  1128. stepNotifier.value = stepTotal;
  1129. }
  1130. // 固件升级
  1131. Future<bool> setupDeviceVer(int type) async {
  1132. _completerSetupDeviceVer = Completer();
  1133. try {
  1134. write(BLE.BLE_Client_T_DFU, Uint8List.fromList([type]));
  1135. } catch (e) {
  1136. print(e);
  1137. }
  1138. Timer timeout = Timer(Duration(seconds: 10), () {
  1139. if (_completerSetupDeviceVer?.isCompleted != true) _completerSetupDeviceVer?.complete(false);
  1140. });
  1141. var result = (await _completerSetupDeviceVer?.future) ?? false;
  1142. timeout.cancel();
  1143. return result;
  1144. }
  1145. // 游戏模式
  1146. Future setupGameMode(bool mode) async {
  1147. if (mode == false && h5gameRNotifier.value == true) {
  1148. return;
  1149. }
  1150. gameModeTimer?.cancel();
  1151. if (mode) {
  1152. gameModeTimer = Timer.periodic(Duration(seconds: 60), (timer) {
  1153. if (this._listen == true) write(BLE.BLE_Client_T_GAMEMODE, Uint8List.fromList([BLE_CODE_1]));
  1154. });
  1155. }
  1156. await write(BLE.BLE_Client_T_GAMEMODE, mode ? Uint8List.fromList([BLE_CODE_1]) : Uint8List.fromList([BLE_CODE_0]));
  1157. }
  1158. Future setupGameMode4h5(bool mode) async {
  1159. h5gameRNotifier.value = mode;
  1160. setupGameMode(mode);
  1161. }
  1162. Future setupDataDebug(bool mode) async {
  1163. await write(BLE.BLE_Client_T_GAMEMODE, mode ? Uint8List.fromList([BLE_CODE_1 + 1]) : Uint8List.fromList([BLE_CODE_0]));
  1164. //
  1165. // device?.rssi.listen((event) {
  1166. // rssiNotifier.value = event;
  1167. // });
  1168. //
  1169. // rssiTimer?.cancel();
  1170. // if (mode == true) {
  1171. // rssiTimer = Timer.periodic(Duration(seconds: 1), (timer) {
  1172. // device?.requestRssi();
  1173. // });
  1174. // }
  1175. }
  1176. Future vibrate(int vibrate, {int leftOrRight = 0}) async {
  1177. int duration = min(1000, max(100, vibrate));
  1178. ByteDataWriter writer = ByteDataWriter();
  1179. writer.writeUint16(duration);
  1180. writer.writeUint8(leftOrRight);
  1181. await write(BLE.BLE_Client_T_SHOCK, writer.toBytes());
  1182. }
  1183. Future lighting(int time) async {
  1184. int duration = min(10000, max(100, time));
  1185. ByteDataWriter writer = ByteDataWriter();
  1186. writer.writeUint16(duration);
  1187. await write(BLE.BLE_Client_T_LIGHTING, writer.toBytes());
  1188. }
  1189. Future stepRealTime(bool mode) async {
  1190. stepRealtimeNotifier.value = -1;
  1191. stepRealtimePageNotifier.value = mode;
  1192. await write(BLE.BLE_Client_T_REALTIMESTEP, mode ? Uint8List.fromList([BLE_CODE_1]) : Uint8List.fromList([BLE_CODE_0]));
  1193. stepRealTimeTimer?.cancel();
  1194. if (mode == true) {
  1195. stepRealTimeTimer = Timer.periodic(Duration(seconds: 10), (timer) {
  1196. write(BLE.BLE_Client_T_REALTIMESTEP, Uint8List.fromList([BLE_CODE_1]));
  1197. });
  1198. }
  1199. }
  1200. Uint8List createTime(int cmd) {
  1201. DateTime now = DateTime.now();
  1202. DateTime offset = DateTime(now.year, now.month, now.day, now.hour);
  1203. print("create now .. $now - $offset ($offset.millisecondsSinceEpoch)");
  1204. ByteDataWriter writer = ByteDataWriter();
  1205. writer.writeUint8(cmd);
  1206. writer.writeUint64(offset.millisecondsSinceEpoch);
  1207. writer.writeUint8(max(0, min(60, now.minute - offset.minute)));
  1208. return writer.toBytes();
  1209. }
  1210. Future write(int cmd, Uint8List data) async {
  1211. if (characteristicWrite == null) return;
  1212. int length = data.length + 5;
  1213. ByteDataWriter writer = ByteDataWriter();
  1214. writer.writeUint8(0xAA);
  1215. // writer.writeUint8(0xBB);
  1216. // writer.writeUint8(0xCC);
  1217. writer.writeUint8(length);
  1218. writer.writeUint8(0xFF - length);
  1219. // writer.writeUint8(0x00);
  1220. writer.writeUint8(cmd);
  1221. if (data.isNotEmpty) writer.write(data);
  1222. int ver = writer.toBytes().reduce((value, element) => value + element);
  1223. writer.writeUint8(ver);
  1224. Uint8List out = writer.toBytes();
  1225. print("out $out");
  1226. // print("out ${out.map((e) => e.toRadixString(16)).join(",")}");
  1227. for (var i = 0; i < 10; i++) {
  1228. try {
  1229. await flutterReactiveBle.writeCharacteristicWithoutResponse(characteristicWrite!, value: out);
  1230. break;
  1231. } catch (e) {
  1232. print(e);
  1233. await Future.delayed(Duration(milliseconds: 100));
  1234. }
  1235. }
  1236. }
  1237. Future writeUintList(Uint8List data) async {
  1238. if (characteristicWrite == null) return;
  1239. int length = data.length + 4;
  1240. ByteDataWriter writer = ByteDataWriter();
  1241. writer.writeUint8(0xAA);
  1242. // writer.writeUint8(0xBB);
  1243. // writer.writeUint8(0xCC);
  1244. writer.writeUint8(length);
  1245. writer.writeUint8(0xFF - length);
  1246. // writer.writeUint8(0x00);
  1247. if (data.isNotEmpty) writer.write(data);
  1248. int ver = writer.toBytes().reduce((value, element) => value + element);
  1249. writer.writeUint8(ver);
  1250. Uint8List out = writer.toBytes();
  1251. print("out $out");
  1252. for (var i = 0; i < 10; i++) {
  1253. try {
  1254. await flutterReactiveBle.writeCharacteristicWithoutResponse(characteristicWrite!, value: out);
  1255. break;
  1256. } catch (e) {
  1257. print(e);
  1258. await Future.delayed(Duration(milliseconds: 10));
  1259. }
  1260. }
  1261. }
  1262. _uploadLog() async {
  1263. DiscoveredDevice? device = this.device;
  1264. if (device == null) return;
  1265. var info = infoNotifier.value;
  1266. if (info.isEmpty == true) return;
  1267. final api = GetIt.I<RestClient>();
  1268. PackageInfo packageInfo = await PackageInfo.fromPlatform();
  1269. DeviceInfoPlugin deviceInfo = DeviceInfoPlugin();
  1270. String os_name = Platform.operatingSystem;
  1271. String os_ver = Platform.operatingSystemVersion;
  1272. String phone_brand = "";
  1273. String phone_model = "";
  1274. if (Platform.isAndroid) {
  1275. AndroidDeviceInfo androidDeviceInfo = await deviceInfo.androidInfo;
  1276. phone_brand = androidDeviceInfo.brand;
  1277. phone_model = androidDeviceInfo.model;
  1278. } else if (Platform.isIOS) {
  1279. IosDeviceInfo iosDeviceInfo = await deviceInfo.iosInfo;
  1280. phone_brand = iosDeviceInfo.name;
  1281. phone_model = iosDeviceInfo.model;
  1282. }
  1283. api.onConnBt("${info['mac']}", "${info['softwareVer']}", "${info['hardwareVer']}", "${packageInfo.version}", os_name, os_ver, "${locale?.languageCode}", phone_brand, phone_model).then((value) => _uploadLoged = true);
  1284. }
  1285. _testErrLog() async {
  1286. Directory? dir = Platform.isAndroid ? await getExternalStorageDirectory() : await getTemporaryDirectory();
  1287. if (dir != null) {
  1288. var now = DateTime.now();
  1289. File file = File("${dir.path}/shoe/err_${now.year}_${now.month}_${now.day}.csv");
  1290. print("log file: $file $errQueue");
  1291. if (!file.parent.existsSync()) {
  1292. file.parent.createSync();
  1293. }
  1294. errQueue.forEach((element) {
  1295. file.writeAsStringSync("$element\n", mode: FileMode.append, flush: true);
  1296. });
  1297. }
  1298. }
  1299. void _testElectricity(Map<String, dynamic> info) async {
  1300. Directory? dir = Platform.isAndroid ? await getExternalStorageDirectory() : await getTemporaryDirectory();
  1301. if (dir != null) {
  1302. var now = DateTime.now();
  1303. File file = File("${dir.path}/shoe/electricity_${now.year}_${now.month}_${now.day}.csv");
  1304. print("log file: $file");
  1305. if (!file.parent.existsSync()) {
  1306. file.parent.createSync();
  1307. }
  1308. file.writeAsStringSync("${now.hour},${now.minute},${now.second},${info['0_electricity']},${info['1_electricity']},${info['0_adc']},${info['1_adc']}\n", mode: FileMode.append, flush: true);
  1309. }
  1310. }
  1311. void _testStep(String line) async {
  1312. Directory? dir = Platform.isAndroid ? await getExternalStorageDirectory() : await getTemporaryDirectory();
  1313. if (dir != null) {
  1314. var now = DateTime.now();
  1315. File file = File("${dir.path}/shoe/step_${now.year}_${now.month}_${now.day}.csv");
  1316. print("log file: $file");
  1317. if (!file.parent.existsSync()) {
  1318. file.parent.createSync();
  1319. }
  1320. file.writeAsStringSync("$line\n", mode: FileMode.append, flush: true);
  1321. }
  1322. }
  1323. }
  1324. class PartItem {
  1325. int step;
  1326. int distance;
  1327. int absolute;
  1328. int time;
  1329. PartItem(this.step, this.absolute, this.distance, this.time);
  1330. Map<String, dynamic> toJson() {
  1331. final Map<String, dynamic> data = new Map<String, dynamic>();
  1332. data['step'] = this.step;
  1333. data['absolute'] = this.absolute;
  1334. data['distance'] = this.distance;
  1335. data['time'] = this.time;
  1336. return data;
  1337. }
  1338. }
  1339. class PartInfo {
  1340. int start;
  1341. int serial = 0;
  1342. int serialCount;
  1343. List<PartItem> items = [];
  1344. late DateTime now;
  1345. late DateTime maxTime;
  1346. late Map<int, List<int>> data;
  1347. bool ready = false;
  1348. PartInfo(this.start, this.serialCount) {
  1349. now = DateTime.now();
  1350. maxTime = DateTime(now.year, now.month, now.day, now.hour);
  1351. data = {};
  1352. }
  1353. final int offset = 60 * 60 * 1000;
  1354. prepare() async {
  1355. print("bluetooth -- step prepare ... ");
  1356. if (data.isEmpty) return;
  1357. if (start == 0) return;
  1358. var current = data[0] ?? [];
  1359. if (current.isEmpty) return;
  1360. int currentStep = current.first;
  1361. print("bluetooth -- step current ... $currentStep");
  1362. var db = StepDB();
  1363. var history = await db.findHistory(start);
  1364. print("bluetooth -- step history ... $start $history");
  1365. int startStep = 0;
  1366. var p = PartItem(0, currentStep, 0, start - offset);
  1367. if (history.isNotEmpty == true) {
  1368. startStep = history.first['st'];
  1369. if (startStep > currentStep) {
  1370. await db.deleteAll();
  1371. print("bluetooth -- history ... clear");
  1372. startStep = currentStep;
  1373. await db.insert(p);
  1374. print("bluetooth -- step add history ... ${p.toJson()}");
  1375. }
  1376. } else {
  1377. startStep = currentStep;
  1378. await db.insert(p);
  1379. print("bluetooth -- step add history ... ${p.toJson()}");
  1380. }
  1381. data[data.length] = current;
  1382. for (var i = 1; i < data.length; i++) {
  1383. var list = data[i] ?? [];
  1384. for (int e in list) {
  1385. int time = start + items.length * offset;
  1386. int step = max(0, e - startStep);
  1387. print("bluetooth -- step add $time $e s:$startStep step:$step");
  1388. items.add(PartItem(step, e, 0, min(time, maxTime.millisecondsSinceEpoch)));
  1389. startStep = e;
  1390. }
  1391. }
  1392. }
  1393. }